diff options
Diffstat (limited to 'autoload')
| -rw-r--r-- | autoload/markdown.vim | 532 | 
1 files changed, 532 insertions, 0 deletions
| diff --git a/autoload/markdown.vim b/autoload/markdown.vim new file mode 100644 index 00000000..3db667e1 --- /dev/null +++ b/autoload/markdown.vim @@ -0,0 +1,532 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'markdown') == -1 + + +" {{{ FOLDING + +function! markdown#FoldLevelOfLine(lnum) +  let currentline = getline(a:lnum) +  let nextline = getline(a:lnum + 1) + +  " an empty line is not going to change the indentation level +  if match(currentline, '^\s*$') >= 0 +    return '=' +  endif + +  " folding lists +  if s:SyntaxGroupOfLineIs(a:lnum, '^markdownListItem') +    if s:SyntaxGroupOfLineIs(a:lnum - 1, '^markdownListItem') +      return 'a1' +    endif +    if s:SyntaxGroupOfLineIs(a:lnum + 1, '^markdownListItem') +      return 's1' +    endif +    return '=' +  endif + +  " we are not going to fold things inside list items, too hairy +  let is_inside_a_list_item = s:SyntaxGroupOfLineIs(a:lnum, '^markdownListItem') +  if is_inside_a_list_item +    return '=' +  endif + +  " folding atx headers +  if match(currentline, '^#\{1,6}\s') >= 0 +    let header_level = strlen(substitute(currentline, '^\(#\{1,6}\).*', '\1', '')) +    return '>' . header_level +  endif + +  " folding fenced code blocks +  let next_line_syntax_group = synIDattr(synID(a:lnum + 1, 1, 1), 'name') +  if match(currentline, '^\s*```') >= 0 +    if next_line_syntax_group ==# 'markdownFencedCodeBlock' +      return 'a1' +    endif +    return 's1' +  endif + +  " folding code blocks +  let current_line_syntax_group = synIDattr(synID(a:lnum, 1, 1), 'name') +  let prev_line_syntax_group = synIDattr(synID(a:lnum - 1, 1, 1), 'name') +  if match(currentline, '^\s\{4,}') >= 0 +    if current_line_syntax_group ==# 'markdownCodeBlock' +      if prev_line_syntax_group !=# 'markdownCodeBlock' +        return 'a1' +      endif +      if next_line_syntax_group !=# 'markdownCodeBlock' +        return 's1' +      endif +    endif +    return '=' +  endif + +  " folding setex headers +  if (match(currentline, '^.*$') >= 0) +    if (match(nextline, '^=\+$') >= 0) +      return '>1' +    endif +    if (match(nextline, '^-\+$') >= 0) +      return '>2' +    endif +  endif + +  return '=' +endfunction + +function! s:SyntaxGroupOfLineIs(lnum, pattern) +  let stack = synstack(a:lnum, a:cnum) +  if len(stack) > 0 +    return synIDattr(stack[0], 'name') =~# a:pattern +  endif +  return 0 +endfunction + +" }}} + +" {{{ EDIT + +function! markdown#EditBlock() range abort +  if exists('b:markdown_temporary_buffer') && b:markdown_temporary_buffer +    echo 'Sorry, you cannot edit a code block inside a temporary buffer' +    return +  endif +  " Github fenced code blocks like ```ruby +  let code_block = s:LocateFencedCodeBlock(a:firstline, +    \ '^\s*`\{3,}\(\w\+\)\%(\s.*$\|$\)', +    \ '^\s*`\{3,}\s*$' +    \ ) +  if code_block['from'] == 0 || code_block['to'] == 0 +    " Github fenced code blocks with metadata like ```{ruby, <WHATEVER>} +    let code_block = s:LocateFencedCodeBlock(a:firstline, +      \ '^\s*`\{3,}{\(\w\+\),[^}]\+}\%(\s.*$\|$\)', +      \ '^\s*`\{3,}\s*$' +      \ ) +  endif +  if code_block['from'] == 0 || code_block['to'] == 0 +    " Github fenced code blocks alternate style like ~~~ruby +    let code_block = s:LocateFencedCodeBlock(a:firstline, +      \ '^\s*\~\{3,}\(\w\+\)\%(\s.*$\|$\)', +      \ '^\s*\~\{3,}\s*$' +      \ ) +  endif +  if code_block['from'] == 0 || code_block['to'] == 0 +    " Liquid fenced code blocks {% highlight ruby %} +    " (since we support some liquid/jekyll tags, why not?) +    let code_block = s:LocateFencedCodeBlock(a:firstline, +      \ '^\s*{%\s*highlight\s\+\(\w\+\)\s*%}\%(\s.*$\|$\)', +      \ '^\s*{%\s*endhighlight\s*%}\%(\s.*$\|$\)' +      \ ) +  endif +  if code_block['from'] == 0 || code_block['to'] == 0 +    let code_block = s:LocateRangeBlock(a:firstline, a:lastline) +  endif +  if code_block['from'] == 0 || code_block['to'] == 0 +    echo 'Sorry, I did not find any suitable code block to edit or create' +    return +  endif + +  let code_block['file_extension'] = '.' . code_block['language'] +  if has_key(s:known_file_extensions, code_block['language']) +    let code_block['file_extension'] = s:known_file_extensions[code_block['language']] +  endif +  let code_block['file_path'] = tempname() . code_block['file_extension'] +  let code_block['content'] = getline(code_block['from'], code_block['to']) +  let code_block['content'] = s:UnindentBlock(code_block['content'], code_block['indentation']) + +  call writefile(code_block['content'], code_block['file_path']) +  augroup MarkdownReplaceEditedBlock +    autocmd BufEnter <buffer> call s:ReplaceEditedBlock() +  augroup END + +  let b:code_block = code_block +  execute 'split ' . code_block['file_path'] +  let b:markdown_temporary_buffer = 1 +  autocmd BufLeave <buffer> wq +endfunction + +function! s:ReplaceEditedBlock() +  augroup MarkdownReplaceEditedBlock +    autocmd! +  augroup END +  augroup! MarkdownReplaceEditedBlock + +  if b:code_block['to'] - b:code_block['from'] >= 0 +    execute b:code_block['from'] . ',' b:code_block['to'] . ' delete _' +  endif +  let content = readfile(b:code_block['file_path']) +  let content = s:IndentBlock(l:content, b:code_block['indentation']) +  let content = s:SurroundWithFencedCodeBlock(l:content, b:code_block) +  call append(b:code_block['from']-1, content) +  call setpos('.', b:code_block['back_to_position']) + +  execute 'silent bwipeout! ' . b:code_block['file_path'] +  call delete(b:code_block['file_path']) +  unlet! b:code_block +endfunction + +function! s:UnindentBlock(content, indentation) +  return map(a:content, 'substitute(v:val, ''^' . a:indentation . ''', '''', ''g'')') +endfunction + +function! s:IndentBlock(content, indentation) +  return map(a:content, 'substitute(v:val, ''^'', ''' . a:indentation . ''', ''g'')') +endfunction + +function! s:SurroundWithFencedCodeBlock(code, editing) +  if !a:editing['surround'] | return a:code | endif +  if a:editing['language'] =~# 'markdown' | return a:code | endif +  let before = +    \ (a:editing['make_room_before'] ? [''] : []) + +    \ [a:editing['indentation'] . '```' . a:editing['language']] +  let after = +    \ [a:editing['indentation'] . '```'] + +    \ (a:editing['make_room_after'] ? [''] : []) +  return l:before + a:code + l:after +endfunction + +function! s:LocateRangeBlock(from, to) +  " TODO: extract initialize_code_block +  let code_block = {'from': 0, 'to': 0, 'language': 'txt', 'indentation': '', 'surround': 0} +  if a:to >= a:from +    let code_block['from'] = a:from +    let code_block['to'] = a:to +    let code_block['back_to_position'] = getpos('.') +    let code_block['language'] = 'markdown' + +    if a:from == a:to && getline(a:from) =~ '^\s*$' +      let code_block['surround'] = 1 +      let code_block['make_room_before'] = getline(a:from - 1) !~ '^\s*$' +      let code_block['make_room_after'] = getline(a:to + 1) !~ '^\s*$' +      let code_block['language'] = input('filetype? (default: markdown) ', '', 'filetype') +      if code_block['language'] =~ '^\s*$' +        let code_block['language'] = 'markdown' +      endif +    endif +  endif +  return code_block +endfunction + +function! s:LocateFencedCodeBlock(starting_from, upper_delimiter, lower_delimiter) +  " TODO: extract initialize_code_block +  let code_block = {'from': 0, 'to': 0, 'language': 'txt', 'indentation': '', 'surround': 0} +  let initial_position = getpos('.') +  let search_position = copy(initial_position) +  let search_position[1] = a:starting_from +  let search_position[2] = 0 +  cal setpos('.', search_position) + +  let start_code_block_backward = search(a:upper_delimiter, 'cbnW') +  let end_code_block_backward = search(a:lower_delimiter, 'cbnW') +  let end_code_block_forward = search(a:lower_delimiter, 'cnW') + +  let found_code_block = +        \ start_code_block_backward > 0 && +        \ end_code_block_forward > 0 +  let between_two_code_blocks = +        \ start_code_block_backward < end_code_block_backward && +        \ end_code_block_backward <= a:starting_from +  let starting_inside_code_block = +        \ found_code_block && +        \ !between_two_code_blocks && +        \ start_code_block_backward <= a:starting_from && +        \ end_code_block_forward >= a:starting_from + +  if starting_inside_code_block +    let code_block['language'] = s:ExtractLanguage(start_code_block_backward, a:upper_delimiter) +    let code_block['indentation'] = s:ExtractIndentation(start_code_block_backward) +    let code_block['back_to_position'] = initial_position +    let code_block['back_to_position'][1] = start_code_block_backward +    let code_block['back_to_position'][2] = 0 +    let code_block['from'] = start_code_block_backward + 1 +    let code_block['to'] = end_code_block_forward - 1 +  endif +  return code_block +endfunction + +function! s:ExtractLanguage(start_at, upper_delimiter) +  return substitute(getline(a:start_at), a:upper_delimiter, '\1', '') +endfunction + +function! s:ExtractIndentation(start_at) +  return substitute(getline(a:start_at), '\(^\s*\).\+$', '\1', '') +endfunction + +let s:known_file_extensions = { +  \ 'abap': '.abap', +  \ 'antlr': '.g4', +  \ 'asp': '.asp', +  \ 'ats': '.dats', +  \ 'actionscript': '.as', +  \ 'ada': '.adb', +  \ 'agda': '.agda', +  \ 'apacheconf': '.apacheconf', +  \ 'apex': '.cls', +  \ 'applescript': '.applescript', +  \ 'arc': '.arc', +  \ 'arduino': '.ino', +  \ 'asciidoc': '.asciidoc', +  \ 'assembly': '.asm', +  \ 'augeas': '.aug', +  \ 'autohotkey': '.ahk', +  \ 'autoit': '.au3', +  \ 'awk': '.awk', +  \ 'batchfile': '.bat', +  \ 'befunge': '.befunge', +  \ 'blitzbasic': '.bb', +  \ 'blitzmax': '.bmx', +  \ 'bluespec': '.bsv', +  \ 'boo': '.boo', +  \ 'brainfuck': '.b', +  \ 'brightscript': '.brs', +  \ 'bro': '.bro', +  \ 'c': '.c', +  \ 'c++': '.cpp', +  \ 'cpp': '.cpp', +  \ 'clips': '.clp', +  \ 'cmake': '.cmake', +  \ 'cobol': '.cob', +  \ 'css': '.css', +  \ 'ceylon': '.ceylon', +  \ 'chuck': '.ck', +  \ 'cirru': '.cirru', +  \ 'clean': '.icl', +  \ 'clojure': '.clj', +  \ 'coffeescript': '.coffee', +  \ 'coldfusion': '.cfm', +  \ 'coq': '.coq', +  \ 'creole': '.creole', +  \ 'crystal': '.cr', +  \ 'cucumber': '.feature', +  \ 'cuda': '.cu', +  \ 'cython': '.pyx', +  \ 'd': '.d', +  \ 'dm': '.dm', +  \ 'dot': '.dot', +  \ 'dart': '.dart', +  \ 'diff': '.diff', +  \ 'dylan': '.dylan', +  \ 'ecl': '.ecl', +  \ 'eiffel': '.e', +  \ 'elixir': '.ex', +  \ 'elm': '.elm', +  \ 'erlang': '.erl', +  \ 'flux': '.fx', +  \ 'fortran': '.f90', +  \ 'factor': '.factor', +  \ 'fancy': '.fy', +  \ 'fantom': '.fan', +  \ 'forth': '.fth', +  \ 'gas': '.s', +  \ 'glsl': '.glsl', +  \ 'genshi': '.kid', +  \ 'glyph': '.glf', +  \ 'go': '.go', +  \ 'gosu': '.gs', +  \ 'groff': '.man', +  \ 'groovy': '.groovy', +  \ 'html': '.html', +  \ 'http': '.http', +  \ 'haml': '.haml', +  \ 'handlebars': '.handlebars', +  \ 'harbour': '.hb', +  \ 'haskell': '.hs', +  \ 'haxe': '.hx', +  \ 'hy': '.hy', +  \ 'idl': '.pro', +  \ 'ini': '.ini', +  \ 'idris': '.idr', +  \ 'io': '.io', +  \ 'ioke': '.ik', +  \ 'j': '.ijs', +  \ 'json': '.json', +  \ 'json5': '.json5', +  \ 'jsonld': '.jsonld', +  \ 'jade': '.jade', +  \ 'java': '.java', +  \ 'javascript': '.js', +  \ 'julia': '.jl', +  \ 'krl': '.krl', +  \ 'kotlin': '.kt', +  \ 'lfe': '.lfe', +  \ 'llvm': '.ll', +  \ 'lasso': '.lasso', +  \ 'less': '.less', +  \ 'lilypond': '.ly', +  \ 'livescript': '.ls', +  \ 'logos': '.xm', +  \ 'logtalk': '.lgt', +  \ 'lua': '.lua', +  \ 'm': '.mumps', +  \ 'makefile': '.mak', +  \ 'mako': '.mako', +  \ 'markdown': '.md', +  \ 'mask': '.mask', +  \ 'matlab': '.matlab', +  \ 'max': '.maxpat', +  \ 'mediawiki': '.mediawiki', +  \ 'mirah': '.druby', +  \ 'monkey': '.monkey', +  \ 'moocode': '.moo', +  \ 'moonscript': '.moon', +  \ 'myghty': '.myt', +  \ 'nsis': '.nsi', +  \ 'nemerle': '.n', +  \ 'netlogo': '.nlogo', +  \ 'nginx': '.nginxconf', +  \ 'nimrod': '.nim', +  \ 'nu': '.nu', +  \ 'numpy': '.numpy', +  \ 'ocaml': '.ml', +  \ 'objdump': '.objdump', +  \ 'omgrofl': '.omgrofl', +  \ 'opa': '.opa', +  \ 'opencl': '.cl', +  \ 'org': '.org', +  \ 'oxygene': '.oxygene', +  \ 'pawn': '.pwn', +  \ 'php': '.php', +  \ 'parrot': '.parrot', +  \ 'pascal': '.pas', +  \ 'perl': '.pl', +  \ 'perl6': '.p6', +  \ 'pike': '.pike', +  \ 'pod': '.pod', +  \ 'pogoscript': '.pogo', +  \ 'postscript': '.ps', +  \ 'powershell': '.ps1', +  \ 'processing': '.pde', +  \ 'prolog': '.prolog', +  \ 'puppet': '.pp', +  \ 'python': '.py', +  \ 'qml': '.qml', +  \ 'r': '.r', +  \ 'rdoc': '.rdoc', +  \ 'realbasic': '.rbbas', +  \ 'rhtml': '.rhtml', +  \ 'rmarkdown': '.rmd', +  \ 'racket': '.rkt', +  \ 'rebol': '.rebol', +  \ 'redcode': '.cw', +  \ 'robotframework': '.robot', +  \ 'rouge': '.rg', +  \ 'ruby': '.rb', +  \ 'rust': '.rs', +  \ 'scss': '.scss', +  \ 'sql': '.sql', +  \ 'sage': '.sage', +  \ 'sass': '.sass', +  \ 'scala': '.scala', +  \ 'scaml': '.scaml', +  \ 'scheme': '.scm', +  \ 'scilab': '.sci', +  \ 'self': '.self', +  \ 'shell': '.sh', +  \ 'shen': '.shen', +  \ 'slash': '.sl', +  \ 'smalltalk': '.st', +  \ 'smarty': '.tpl', +  \ 'squirrel': '.nut', +  \ 'stylus': '.styl', +  \ 'supercollider': '.scd', +  \ 'toml': '.toml', +  \ 'txl': '.txl', +  \ 'tcl': '.tcl', +  \ 'tcsh': '.tcsh', +  \ 'tex': '.tex', +  \ 'tea': '.tea', +  \ 'textile': '.textile', +  \ 'turing': '.t', +  \ 'twig': '.twig', +  \ 'typescript': '.ts', +  \ 'unrealscript': '.uc', +  \ 'vhdl': '.vhdl', +  \ 'vala': '.vala', +  \ 'verilog': '.v', +  \ 'viml': '.vim', +  \ 'volt': '.volt', +  \ 'xc': '.xc', +  \ 'xml': '.xml', +  \ 'xproc': '.xpl', +  \ 'xquery': '.xquery', +  \ 'xs': '.xs', +  \ 'xslt': '.xslt', +  \ 'xtend': '.xtend', +  \ 'yaml': '.yml', +  \ 'ec': '.ec', +  \ 'edn': '.edn', +  \ 'fish': '.fish', +  \ 'mupad': '.mu', +  \ 'nesc': '.nc', +  \ 'ooc': '.ooc', +  \ 'restructuredtext': '.rst', +  \ 'wisp': '.wisp', +  \ 'xbase': '.prg', +\ } + +" }}} + +" {{{ FORMAT +function! markdown#FormatTable() +  let p = '^\s*|\s.*\s|\s*$' +  if exists(':Tabularize') && getline('.') =~# '^\s*|' && (getline(line('.')-1) =~# p || getline(line('.')+1) =~# p) +    let column = strlen(substitute(getline('.')[0:col('.')],'[^|]','','g')) +    let position = strlen(matchstr(getline('.')[0:col('.')],'.*|\s*\zs.*')) +    let separator_line_number = search('^\s*|\s*-\{3,}', 'cbnW') + +    call s:ShrinkTableHeaderSeparator(separator_line_number) +    Tabularize/|/l1 +    call s:ExpandTableHeaderSeparator(separator_line_number) +    normal! 0 + +    call search(repeat('[^|]*|',column).'\s\{-\}'.repeat('.',position),'ce',line('.')) +  endif +endfunction + +function! s:ShrinkTableHeaderSeparator(separator_line_number) +  if a:separator_line_number > 0 +    let separator_line = getline(a:separator_line_number) +    let separator_line = substitute(separator_line, '-\+', '---', 'g') +    call setline(a:separator_line_number, separator_line) +  endif +endfunction + +function! s:ExpandTableHeaderSeparator(separator_line_number) +  if a:separator_line_number > 0 +    let separator_line = getline(a:separator_line_number) +    let separator_line = substitute( +      \ separator_line, +      \ '|\([^|]*\)', +      \ '\="| " . repeat("-", strlen(submatch(1)) - 2) . " "', +      \ 'g') +    let separator_line = substitute(separator_line, '\s*$', '', '') +    call setline(a:separator_line_number, separator_line) +  endif +endfunction +" }}} + +" {{{ SWITCH STATUS +function! markdown#SwitchStatus() +  let current_line = getline('.') +  if match(current_line, '^\s*[*\-+] \[ \]') >= 0 +    call setline('.', substitute(current_line, '^\(\s*[*\-+]\) \[ \]', '\1 [x]', '')) +    return +  endif +  if match(current_line, '^\s*[*\-+] \[x\]') >= 0 +    call setline('.', substitute(current_line, '^\(\s*[*\-+]\) \[x\]', '\1', '')) +    return +  endif +  if match(current_line, '^\s*[*\-+] \(\[[x ]\]\)\@!') >= 0 +    call setline('.', substitute(current_line, '^\(\s*[*\-+]\)', '\1 [ ]', '')) +    return +  endif +  if match(current_line, '^\s*#\{1,5}\s') >= 0 +    call setline('.', substitute(current_line, '^\(\s*#\{1,5}\) \(.*$\)', '\1# \2', '')) +    return +  endif +  if match(current_line, '^\s*#\{6}\s') >= 0 +    call setline('.', substitute(current_line, '^\(\s*\)#\{6} \(.*$\)', '\1# \2', '')) +    return +  endif +endfunction +" }}} + +endif | 
