From cea0d08a062478503814e51aa21c6486a0dd1b21 Mon Sep 17 00:00:00 2001 From: Adam Stankiewicz Date: Thu, 12 Dec 2019 16:43:09 +0100 Subject: Replace markdown plugin for faster one --- README.md | 2 +- after/ftplugin/markdown.vim | 205 -------- autoload/markdown.vim | 532 +++++++++++++++++++++ build | 2 +- config.vim | 12 + ftdetect/polyglot.vim | 23 +- ftplugin/markdown.vim | 903 +++++++---------------------------- indent/markdown.vim | 79 ---- syntax/markdown.vim | 1085 ++++++++++++++++++++++++++++++++++++------- syntax/markdown_jekyll.vim | 34 ++ 10 files changed, 1671 insertions(+), 1206 deletions(-) delete mode 100644 after/ftplugin/markdown.vim create mode 100644 autoload/markdown.vim delete mode 100644 indent/markdown.vim create mode 100644 syntax/markdown_jekyll.vim diff --git a/README.md b/README.md index 52e2776b..e41ef2ad 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ If you need full functionality of any plugin, please use it directly with your p - [log](https://github.com/MTDL9/vim-log-highlighting) (syntax) - [lua](https://github.com/tbastos/vim-lua) (syntax, indent) - [mako](https://github.com/sophacles/vim-bundle-mako) (syntax, indent, ftplugin) -- [markdown](https://github.com/plasticboy/vim-markdown) (syntax, indent, ftplugin) +- [markdown](https://github.com/gabrielelana/vim-markdown) (syntax, autoload, ftplugin) - [mathematica](https://github.com/voldikss/vim-mma) (syntax, ftplugin) - [mdx](https://github.com/jxnblk/vim-mdx-js) (syntax) - [meson](https://github.com/mesonbuild/meson) (syntax, indent, ftplugin) diff --git a/after/ftplugin/markdown.vim b/after/ftplugin/markdown.vim deleted file mode 100644 index 1d1e410c..00000000 --- a/after/ftplugin/markdown.vim +++ /dev/null @@ -1,205 +0,0 @@ -if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'markdown') == -1 - -" vim: ts=4 sw=4: -" folding for Markdown headers, both styles (atx- and setex-) -" http://daringfireball.net/projects/markdown/syntax#header -" -" this code can be placed in file -" $HOME/.vim/after/ftplugin/markdown.vim -" -" original version from Steve Losh's gist: https://gist.github.com/1038710 - -function! s:is_mkdCode(lnum) - let name = synIDattr(synID(a:lnum, 1, 0), 'name') - return (name =~ '^mkd\%(Code$\|Snippet\)' || name != '' && name !~ '^\%(mkd\|html\)') -endfunction - -if get(g:, "vim_markdown_folding_style_pythonic", 0) - function! Foldexpr_markdown(lnum) - let l1 = getline(a:lnum) - "~~~~~ keep track of fenced code blocks ~~~~~ - "If we hit a code block fence - if l1 =~ '````*' || l1 =~ '\~\~\~\~*' - " toggle the variable that says if we're in a code block - if b:fenced_block == 0 - let b:fenced_block = 1 - elseif b:fenced_block == 1 - let b:fenced_block = 0 - endif - " else, if we're caring about front matter - elseif g:vim_markdown_frontmatter == 1 - " if we're in front matter and not on line 1 - if b:front_matter == 1 && a:lnum > 2 - let l0 = getline(a:lnum-1) - " if the previous line fenced front matter - if l0 == '---' - " we must not be in front matter - let b:front_matter = 0 - endif - " else, if we're on line one - elseif a:lnum == 1 - " if we hit a front matter fence - if l1 == '---' - " we're in the front matter - let b:front_matter = 1 - endif - endif - endif - - " if we're in a code block or front matter - if b:fenced_block == 1 || b:front_matter == 1 - if a:lnum == 1 - " fold any 'preamble' - return '>1' - else - " keep previous foldlevel - return '=' - endif - endif - - let l2 = getline(a:lnum+1) - " if the next line starts with two or more '=' - " and is not code - if l2 =~ '^==\+\s*' && !s:is_mkdCode(a:lnum+1) - " next line is underlined (level 1) - return '>0' - " else, if the nex line starts with two or more '-' - " and is not code - elseif l2 =~ '^--\+\s*' && !s:is_mkdCode(a:lnum+1) - " next line is underlined (level 2) - return '>1' - endif - - "if we're on a non-code line starting with a pound sign - if l1 =~ '^#' && !s:is_mkdCode(a:lnum) - " set the fold level to the number of hashes -1 - " return '>'.(matchend(l1, '^#\+') - 1) - " set the fold level to the number of hashes - return '>'.(matchend(l1, '^#\+')) - " else, if we're on line 1 - elseif a:lnum == 1 - " fold any 'preamble' - return '>1' - else - " keep previous foldlevel - return '=' - endif - endfunction - - function! Foldtext_markdown() - let line = getline(v:foldstart) - let has_numbers = &number || &relativenumber - let nucolwidth = &fdc + has_numbers * &numberwidth - let windowwidth = winwidth(0) - nucolwidth - 6 - let foldedlinecount = v:foldend - v:foldstart - let line = strpart(line, 0, windowwidth - 2 -len(foldedlinecount)) - let line = substitute(line, '\%("""\|''''''\)', '', '') - let fillcharcount = windowwidth - len(line) - len(foldedlinecount) + 1 - return line . ' ' . repeat("-", fillcharcount) . ' ' . foldedlinecount - endfunction -else " vim_markdown_folding_style_pythonic == 0 - function! Foldexpr_markdown(lnum) - if (a:lnum == 1) - let l0 = '' - else - let l0 = getline(a:lnum-1) - endif - - " keep track of fenced code blocks - if l0 =~ '````*' || l0 =~ '\~\~\~\~*' - if b:fenced_block == 0 - let b:fenced_block = 1 - elseif b:fenced_block == 1 - let b:fenced_block = 0 - endif - elseif g:vim_markdown_frontmatter == 1 - if b:front_matter == 1 - if l0 == '---' - let b:front_matter = 0 - endif - elseif a:lnum == 2 - if l0 == '---' - let b:front_matter = 1 - endif - endif - endif - - if b:fenced_block == 1 || b:front_matter == 1 - " keep previous foldlevel - return '=' - endif - - let l2 = getline(a:lnum+1) - if l2 =~ '^==\+\s*' && !s:is_mkdCode(a:lnum+1) - " next line is underlined (level 1) - return '>1' - elseif l2 =~ '^--\+\s*' && !s:is_mkdCode(a:lnum+1) - " next line is underlined (level 2) - if s:vim_markdown_folding_level >= 2 - return '>1' - else - return '>2' - endif - endif - - let l1 = getline(a:lnum) - if l1 =~ '^#' && !s:is_mkdCode(a:lnum) - " fold level according to option - if s:vim_markdown_folding_level == 1 || matchend(l1, '^#\+') > s:vim_markdown_folding_level - if a:lnum == line('$') - return matchend(l1, '^#\+') - 1 - else - return -1 - endif - else - " headers are not folded - return 0 - endif - endif - - if l0 =~ '^#' && !s:is_mkdCode(a:lnum-1) - " previous line starts with hashes - return '>'.matchend(l0, '^#\+') - else - " keep previous foldlevel - return '=' - endif - endfunction -endif - - -let b:fenced_block = 0 -let b:front_matter = 0 -let s:vim_markdown_folding_level = get(g:, "vim_markdown_folding_level", 1) - -function! s:MarkdownSetupFolding() - if !get(g:, "vim_markdown_folding_disabled", 0) - if get(g:, "vim_markdown_folding_style_pythonic", 0) - if get(g:, "vim_markdown_override_foldtext", 1) - setlocal foldtext=Foldtext_markdown() - endif - endif - setlocal foldexpr=Foldexpr_markdown(v:lnum) - setlocal foldmethod=expr - endif -endfunction - -function! s:MarkdownSetupFoldLevel() - if get(g:, "vim_markdown_folding_style_pythonic", 0) - " set default foldlevel - execute "setlocal foldlevel=".s:vim_markdown_folding_level - endif -endfunction - -call s:MarkdownSetupFoldLevel() -call s:MarkdownSetupFolding() - -augroup Mkd - " These autocmds need to be kept in sync with the autocmds calling - " s:MarkdownRefreshSyntax in ftplugin/markdown.vim. - autocmd BufWinEnter,BufWritePost call s:MarkdownSetupFolding() - autocmd InsertEnter,InsertLeave call s:MarkdownSetupFolding() - autocmd CursorHold,CursorHoldI call s:MarkdownSetupFolding() -augroup END - -endif 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, } + 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 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 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 diff --git a/build b/build index 7e4b5221..67ad3c50 100755 --- a/build +++ b/build @@ -233,7 +233,7 @@ PACKS=" log:MTDL9/vim-log-highlighting lua:tbastos/vim-lua mako:sophacles/vim-bundle-mako - markdown:plasticboy/vim-markdown + markdown:gabrielelana/vim-markdown mathematica:voldikss/vim-mma mdx:jxnblk/vim-mdx-js meson:mesonbuild/meson:_ALL:/data/syntax-highlighting/vim/ diff --git a/config.vim b/config.vim index 1565a7ec..86db52a9 100644 --- a/config.vim +++ b/config.vim @@ -1,3 +1,15 @@ +if !exists('g:markdown_enable_spell_checking') + let g:markdown_enable_spell_checking = 0 +end + +if !exists('g:markdown_enable_input_abbreviations') + let g:markdown_enable_input_abbreviations = 0 +end + +if !exists('g:markdown_enable_mappings') + let g:markdown_enable_mappings = 0 +end + " Enable jsx syntax by default if !exists('g:jsx_ext_required') let g:jsx_ext_required = 0 diff --git a/ftdetect/polyglot.vim b/ftdetect/polyglot.vim index 5ab23e80..480ea023 100644 --- a/ftdetect/polyglot.vim +++ b/ftdetect/polyglot.vim @@ -1,3 +1,15 @@ +if !exists('g:markdown_enable_spell_checking') + let g:markdown_enable_spell_checking = 0 +end + +if !exists('g:markdown_enable_input_abbreviations') + let g:markdown_enable_input_abbreviations = 0 +end + +if !exists('g:markdown_enable_mappings') + let g:markdown_enable_mappings = 0 +end + " Enable jsx syntax by default if !exists('g:jsx_ext_required') let g:jsx_ext_required = 0 @@ -781,15 +793,8 @@ endif if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'markdown') == -1 augroup filetypedetect - " markdown, from markdown.vim in plasticboy/vim-markdown -if !has('patch-7.4.480') - " Before this patch, vim used modula2 for .md. - au! filetypedetect BufRead,BufNewFile *.md -endif - -" markdown filetype file -au BufRead,BufNewFile *.{md,mdown,mkd,mkdn,markdown,mdwn} setfiletype markdown -au BufRead,BufNewFile *.{md,mdown,mkd,mkdn,markdown,mdwn}.{des3,des,bf,bfa,aes,idea,cast,rc2,rc4,rc5,desx} setfiletype markdown + " markdown, from markdown.vim in gabrielelana/vim-markdown +au BufRead,BufNewFile *.{md,mdown,mkd,mkdn,markdown,mdwn} set filetype=markdown augroup end endif diff --git a/ftplugin/markdown.vim b/ftplugin/markdown.vim index 43c9773a..8d327f61 100644 --- a/ftplugin/markdown.vim +++ b/ftplugin/markdown.vim @@ -1,795 +1,202 @@ if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'markdown') == -1 -"TODO print messages when on visual mode. I only see VISUAL, not the messages. - -" Function interface phylosophy: -" -" - functions take arbitrary line numbers as parameters. -" Current cursor line is only a suitable default parameter. -" -" - only functions that bind directly to user actions: -" -" - print error messages. -" All intermediate functions limit themselves return `0` to indicate an error. -" -" - move the cursor. All other functions do not move the cursor. -" -" This is how you should view headers for the header mappings: -" -" |BUFFER -" | -" |Outside any header -" | -" a-+# a -" | -" |Inside a -" | -" a-+ -" b-+## b -" | -" |inside b -" | -" b-+ -" c-+### c -" | -" |Inside c -" | -" c-+ -" d-|# d -" | -" |Inside d -" | -" d-+ -" e-|e -" |==== -" | -" |Inside e -" | -" e-+ - -" For each level, contains the regexp that matches at that level only. -" -let s:levelRegexpDict = { - \ 1: '\v^(#[^#]@=|.+\n\=+$)', - \ 2: '\v^(##[^#]@=|.+\n-+$)', - \ 3: '\v^###[^#]@=', - \ 4: '\v^####[^#]@=', - \ 5: '\v^#####[^#]@=', - \ 6: '\v^######[^#]@=' -\ } - -" Maches any header level of any type. -" -" This could be deduced from `s:levelRegexpDict`, but it is more -" efficient to have a single regexp for this. -" -let s:headersRegexp = '\v^(#|.+\n(\=+|-+)$)' - -" Returns the line number of the first header before `line`, called the -" current header. -" -" If there is no current header, return `0`. -" -" @param a:1 The line to look the header of. Default value: `getpos('.')`. -" -function! s:GetHeaderLineNum(...) - if a:0 == 0 - let l:l = line('.') - else - let l:l = a:1 - endif - while(l:l > 0) - if join(getline(l:l, l:l + 1), "\n") =~ s:headersRegexp - return l:l - endif - let l:l -= 1 - endwhile - return 0 -endfunction +if exists('b:did_ftplugin') | finish | endif -" - if inside a header goes to it. -" Return its line number. -" -" - if on top level outside any headers, -" print a warning -" Return `0`. -" -function! s:MoveToCurHeader() - let l:lineNum = s:GetHeaderLineNum() - if l:lineNum != 0 - call cursor(l:lineNum, 1) - else - echo 'outside any header' - "normal! gg - endif - return l:lineNum -endfunction +" {{{ CONFIGURATION -" Move cursor to next header of any level. -" -" If there are no more headers, print a warning. -" -function! s:MoveToNextHeader() - if search(s:headersRegexp, 'W') == 0 - "normal! G - echo 'no next header' - endif -endfunction +if !exists('g:markdown_flavor') + let g:markdown_flavor = 'github' +endif -" Move cursor to previous header (before current) of any level. -" -" If it does not exist, print a warning. -" -function! s:MoveToPreviousHeader() - let l:curHeaderLineNumber = s:GetHeaderLineNum() - let l:noPreviousHeader = 0 - if l:curHeaderLineNumber <= 1 - let l:noPreviousHeader = 1 - else - let l:previousHeaderLineNumber = s:GetHeaderLineNum(l:curHeaderLineNumber - 1) - if l:previousHeaderLineNumber == 0 - let l:noPreviousHeader = 1 - else - call cursor(l:previousHeaderLineNumber, 1) - endif - endif - if l:noPreviousHeader - echo 'no previous header' - endif -endfunction +if !exists('g:markdown_enable_folding') + let g:markdown_enable_folding = 0 +endif -" - if line is inside a header, return the header level (h1 -> 1, h2 -> 2, etc.). -" -" - if line is at top level outside any headers, return `0`. -" -function! s:GetHeaderLevel(...) - if a:0 == 0 - let l:line = line('.') - else - let l:line = a:1 - endif - let l:linenum = s:GetHeaderLineNum(l:line) - if l:linenum != 0 - return s:GetLevelOfHeaderAtLine(l:linenum) - else - return 0 - endif -endfunction +if !exists('g:markdown_enable_mappings') + " make it compatible with previous configuration value + if exists('g:markdown_include_default_mappings') + let g:markdown_enable_mappings = g:markdown_include_default_mappings + else + let g:markdown_enable_mappings = 1 + endif +endif -" Returns the level of the header at the given line. -" -" If there is no header at the given line, returns `0`. -" -function! s:GetLevelOfHeaderAtLine(linenum) - let l:lines = join(getline(a:linenum, a:linenum + 1), "\n") - for l:key in keys(s:levelRegexpDict) - if l:lines =~ get(s:levelRegexpDict, l:key) - return l:key - endif - endfor - return 0 -endfunction +if !exists('g:markdown_enable_insert_mode_mappings') + " make it compatible with previous configuration value + if exists('g:markdown_include_insert_mode_default_mappings') + let g:markdown_enable_insert_mode_mappings = g:markdown_include_insert_mode_default_mappings + else + let g:markdown_enable_insert_mode_mappings = 1 + endif +endif -" Move cursor to parent header of the current header. -" -" If it does not exit, print a warning and do nothing. -" -function! s:MoveToParentHeader() - let l:linenum = s:GetParentHeaderLineNumber() - if l:linenum != 0 - call cursor(l:linenum, 1) - else - echo 'no parent header' - endif -endfunction +if !exists('g:markdown_enable_insert_mode_leader_mappings') + let g:markdown_enable_insert_mode_leader_mappings = 0 +endif -" Return the line number of the parent header of line `line`. -" -" If it has no parent, return `0`. -" -function! s:GetParentHeaderLineNumber(...) - if a:0 == 0 - let l:line = line('.') - else - let l:line = a:1 - endif - let l:level = s:GetHeaderLevel(l:line) - if l:level > 1 - let l:linenum = s:GetPreviousHeaderLineNumberAtLevel(l:level - 1, l:line) - return l:linenum - endif - return 0 -endfunction +if !exists('g:markdown_drop_empty_blockquotes') + let g:markdown_drop_empty_blockquotes = 0 +endif -" Return the line number of the previous header of given level. -" in relation to line `a:1`. If not given, `a:1 = getline()` -" -" `a:1` line is included, and this may return the current header. -" -" If none return 0. -" -function! s:GetNextHeaderLineNumberAtLevel(level, ...) - if a:0 < 1 - let l:line = line('.') - else - let l:line = a:1 - endif - let l:l = l:line - while(l:l <= line('$')) - if join(getline(l:l, l:l + 1), "\n") =~ get(s:levelRegexpDict, a:level) - return l:l - endif - let l:l += 1 - endwhile - return 0 -endfunction +if !exists('g:markdown_mapping_switch_status') + let g:markdown_mapping_switch_status = '' +endif -" Return the line number of the previous header of given level. -" in relation to line `a:1`. If not given, `a:1 = getline()` -" -" `a:1` line is included, and this may return the current header. -" -" If none return 0. -" -function! s:GetPreviousHeaderLineNumberAtLevel(level, ...) - if a:0 == 0 - let l:line = line('.') - else - let l:line = a:1 - endif - let l:l = l:line - while(l:l > 0) - if join(getline(l:l, l:l + 1), "\n") =~ get(s:levelRegexpDict, a:level) - return l:l - endif - let l:l -= 1 - endwhile - return 0 -endfunction +if !exists('g:markdown_enable_spell_checking') + let g:markdown_enable_spell_checking = 1 +endif -" Move cursor to next sibling header. -" -" If there is no next siblings, print a warning and don't move. -" -function! s:MoveToNextSiblingHeader() - let l:curHeaderLineNumber = s:GetHeaderLineNum() - let l:curHeaderLevel = s:GetLevelOfHeaderAtLine(l:curHeaderLineNumber) - let l:curHeaderParentLineNumber = s:GetParentHeaderLineNumber() - let l:nextHeaderSameLevelLineNumber = s:GetNextHeaderLineNumberAtLevel(l:curHeaderLevel, l:curHeaderLineNumber + 1) - let l:noNextSibling = 0 - if l:nextHeaderSameLevelLineNumber == 0 - let l:noNextSibling = 1 - else - let l:nextHeaderSameLevelParentLineNumber = s:GetParentHeaderLineNumber(l:nextHeaderSameLevelLineNumber) - if l:curHeaderParentLineNumber == l:nextHeaderSameLevelParentLineNumber - call cursor(l:nextHeaderSameLevelLineNumber, 1) - else - let l:noNextSibling = 1 - endif - endif - if l:noNextSibling - echo 'no next sibling header' - endif -endfunction +if !exists('g:markdown_enable_input_abbreviations') + let g:markdown_enable_input_abbreviations = 1 +endif -" Move cursor to previous sibling header. -" -" If there is no previous siblings, print a warning and do nothing. -" -function! s:MoveToPreviousSiblingHeader() - let l:curHeaderLineNumber = s:GetHeaderLineNum() - let l:curHeaderLevel = s:GetLevelOfHeaderAtLine(l:curHeaderLineNumber) - let l:curHeaderParentLineNumber = s:GetParentHeaderLineNumber() - let l:previousHeaderSameLevelLineNumber = s:GetPreviousHeaderLineNumberAtLevel(l:curHeaderLevel, l:curHeaderLineNumber - 1) - let l:noPreviousSibling = 0 - if l:previousHeaderSameLevelLineNumber == 0 - let l:noPreviousSibling = 1 - else - let l:previousHeaderSameLevelParentLineNumber = s:GetParentHeaderLineNumber(l:previousHeaderSameLevelLineNumber) - if l:curHeaderParentLineNumber == l:previousHeaderSameLevelParentLineNumber - call cursor(l:previousHeaderSameLevelLineNumber, 1) - else - let l:noPreviousSibling = 1 - endif - endif - if l:noPreviousSibling - echo 'no previous sibling header' - endif -endfunction +" }}} -function! s:Toc(...) - if a:0 > 0 - let l:window_type = a:1 - else - let l:window_type = 'vertical' - endif +" {{{ OPTIONS - let l:bufnr = bufnr('%') - let l:cursor_line = line('.') - let l:cursor_header = 0 - let l:fenced_block = 0 - let l:front_matter = 0 - let l:header_list = [] - let l:header_max_len = 0 - let l:vim_markdown_toc_autofit = get(g:, "vim_markdown_toc_autofit", 0) - let l:vim_markdown_frontmatter = get(g:, "vim_markdown_frontmatter", 0) - for i in range(1, line('$')) - let l:lineraw = getline(i) - let l:l1 = getline(i+1) - let l:line = substitute(l:lineraw, "#", "\\\#", "g") - if l:line =~ '````*' || l:line =~ '\~\~\~\~*' - if l:fenced_block == 0 - let l:fenced_block = 1 - elseif l:fenced_block == 1 - let l:fenced_block = 0 - endif - elseif l:vim_markdown_frontmatter == 1 - if l:front_matter == 1 - if l:line == '---' - let l:front_matter = 0 - endif - elseif i == 1 - if l:line == '---' - let l:front_matter = 1 - endif - endif - endif - if l:line =~ '^#\+' || (l:l1 =~ '^=\+\s*$' || l:l1 =~ '^-\+\s*$') && l:line =~ '^\S' - let l:is_header = 1 - else - let l:is_header = 0 - endif - if l:is_header == 1 && l:fenced_block == 0 && l:front_matter == 0 - " append line to location list - let l:item = {'lnum': i, 'text': l:line, 'valid': 1, 'bufnr': l:bufnr, 'col': 1} - let l:header_list = l:header_list + [l:item] - " set header number of the cursor position - if l:cursor_header == 0 - if i == l:cursor_line - let l:cursor_header = len(l:header_list) - elseif i > l:cursor_line - let l:cursor_header = len(l:header_list) - 1 - endif - endif - " keep track of the longest header size (heading level + title) - let l:total_len = stridx(l:line, ' ') + strdisplaywidth(l:line) - if l:total_len > l:header_max_len - let l:header_max_len = l:total_len - endif - endif - endfor - call setloclist(0, l:header_list) - if len(l:header_list) == 0 - echom "Toc: No headers." - return - endif +setlocal textwidth=0 +setlocal ts=2 sw=2 expandtab smarttab +setlocal comments=b:*,b:-,b:+,n:>,se:``` commentstring=>\ %s +setlocal formatoptions=tron +setlocal formatlistpat=^\\s*\\d\\+\\.\\s\\+\\\\|^\\s*[+-\\*]\\s\\+ +setlocal nolisp +setlocal autoindent + +" Enable spelling and completion based on dictionary words +if &spelllang !~# '^\s*$' && g:markdown_enable_spell_checking + setlocal spell +endif + +" Custom dictionary for emoji +execute 'setlocal dictionary+=' . shellescape(expand(':p:h:h')) . '/dict/emoticons.dict' +setlocal iskeyword+=:,+,- +setlocal complete+=k + +if g:markdown_enable_input_abbreviations + " Replace common ascii emoticons with supported emoji + iabbrev :-) :smile: + iabbrev :-D :laughing: + iabbrev :-( :disappointed: + + " Replace common punctuation + iabbrev ... … + iabbrev << « + iabbrev >> » +endif + +" Folding +if g:markdown_enable_folding + setlocal foldmethod=expr + setlocal foldexpr=markdown#FoldLevelOfLine(v:lnum) +endif + +" }}} - if l:window_type ==# 'horizontal' - lopen - elseif l:window_type ==# 'vertical' - vertical lopen - " auto-fit toc window when possible to shrink it - if (&columns/2) > l:header_max_len && l:vim_markdown_toc_autofit == 1 - execute 'vertical resize ' . (l:header_max_len + 1) - else - execute 'vertical resize ' . (&columns/2) - endif - elseif l:window_type ==# 'tab' - tab lopen - else - lopen - endif - setlocal modifiable - for i in range(1, line('$')) - " this is the location-list data for the current item - let d = getloclist(0)[i-1] - " atx headers - if match(d.text, "^#") > -1 - let l:level = len(matchstr(d.text, '#*', 'g'))-1 - let d.text = substitute(d.text, '\v^#*[ ]*', '', '') - let d.text = substitute(d.text, '\v[ ]*#*$', '', '') - " setex headers - else - let l:next_line = getbufline(d.bufnr, d.lnum+1) - if match(l:next_line, "=") > -1 - let l:level = 0 - elseif match(l:next_line, "-") > -1 - let l:level = 1 - endif - endif - call setline(i, repeat(' ', l:level). d.text) - endfor - setlocal nomodified - setlocal nomodifiable - execute 'normal! ' . l:cursor_header . 'G' -endfunction -" Convert Setex headers in range `line1 .. line2` to Atx. -" -" Return the number of conversions. -" -function! s:SetexToAtx(line1, line2) - let l:originalNumLines = line('$') - execute 'silent! ' . a:line1 . ',' . a:line2 . 'substitute/\v(.*\S.*)\n\=+$/# \1/' - execute 'silent! ' . a:line1 . ',' . a:line2 . 'substitute/\v(.*\S.*)\n-+$/## \1/' - return l:originalNumLines - line('$') +" {{{ FUNCTIONS + +function! s:JumpToHeader(forward, visual) + let cnt = v:count1 + let save = @/ + let pattern = '\v^#{1,6}.*$|^.+\n%(\-+|\=+)$' + if a:visual + normal! gv + endif + if a:forward + let motion = '/' . pattern + else + let motion = '?' . pattern + endif + while cnt > 0 + silent! execute motion + let cnt = cnt - 1 + endwhile + call histdel('/', -1) + let @/ = save endfunction -" If `a:1` is 0, decrease the level of all headers in range `line1 .. line2`. -" -" Otherwise, increase the level. `a:1` defaults to `0`. -" -function! s:HeaderDecrease(line1, line2, ...) - if a:0 > 0 - let l:increase = a:1 +function! s:Indent(indent) + if getline('.') =~ '\v^\s*%([-*+]|\d\.)\s*$' + if a:indent + normal >> else - let l:increase = 0 + normal << endif - if l:increase - let l:forbiddenLevel = 6 - let l:replaceLevels = [5, 1] - let l:levelDelta = 1 + call setline('.', substitute(getline('.'), '\([-*+]\|\d\.\)\s*$', '\1 ', '')) + normal $ + elseif getline('.') =~ '\v^\s*(\s?\>)+\s*$' + if a:indent + call setline('.', substitute(getline('.'), '>\s*$', '>> ', '')) else - let l:forbiddenLevel = 1 - let l:replaceLevels = [2, 6] - let l:levelDelta = -1 + call setline('.', substitute(getline('.'), '\s*>\s*$', ' ', '')) + call setline('.', substitute(getline('.'), '^\s\+$', '', '')) endif - for l:line in range(a:line1, a:line2) - if join(getline(l:line, l:line + 1), "\n") =~ s:levelRegexpDict[l:forbiddenLevel] - echomsg 'There is an h' . l:forbiddenLevel . ' at line ' . l:line . '. Aborting.' - return - endif - endfor - let l:numSubstitutions = s:SetexToAtx(a:line1, a:line2) - let l:flags = (&gdefault ? '' : 'g') - for l:level in range(replaceLevels[0], replaceLevels[1], -l:levelDelta) - execute 'silent! ' . a:line1 . ',' . (a:line2 - l:numSubstitutions) . 'substitute/' . s:levelRegexpDict[l:level] . '/' . repeat('#', l:level + l:levelDelta) . '/' . l:flags - endfor -endfunction - -" Format table under cursor. -" -" Depends on Tabularize. -" -function! s:TableFormat() - let l:pos = getpos('.') - normal! { - " Search instead of `normal! j` because of the table at beginning of file edge case. - call search('|') - normal! j - " Remove everything that is not a pipe, colon or hyphen next to a colon othewise - " well formated tables would grow because of addition of 2 spaces on the separator - " line by Tabularize /|. - let l:flags = (&gdefault ? '' : 'g') - execute 's/\(:\@ ' . a:rhs . ' :call ' . a:lhs . '()' - execute 'vn ' . a:rhs . ' :call VisMove(''' . a:lhs . ''')' +function! s:IsAnEmptyQuote() + return getline('.') =~ '\v^\s*(\s?\>)+\s*$' endfunction -" Parameters: -" -" - step +1 for right, -1 for left -" -" TODO: multiple lines. -" -function! s:FindCornerOfSyntax(lnum, col, step) - let l:col = a:col - let l:syn = synIDattr(synID(a:lnum, l:col, 1), 'name') - while synIDattr(synID(a:lnum, l:col, 1), 'name') ==# l:syn - let l:col += a:step - endwhile - return l:col - a:step -endfunction - -" Return the next position of the given syntax name, -" inclusive on the given position. -" -" TODO: multiple lines -" -function! s:FindNextSyntax(lnum, col, name) - let l:col = a:col - let l:step = 1 - while synIDattr(synID(a:lnum, l:col, 1), 'name') !=# a:name - let l:col += l:step - endwhile - return [a:lnum, l:col] -endfunction +" }}} -function! s:FindCornersOfSyntax(lnum, col) - return [FindLeftOfSyntax(a:lnum, a:col), FindRightOfSyntax(a:lnum, a:col)] -endfunction -function! s:FindRightOfSyntax(lnum, col) - return FindCornerOfSyntax(a:lnum, a:col, 1) -endfunction +" {{{ MAPPINGS -function! s:FindLeftOfSyntax(lnum, col) - return FindCornerOfSyntax(a:lnum, a:col, -1) -endfunction +" Commands +command! -nargs=0 -range MarkdownEditBlock :,call markdown#EditBlock() -" Returns: -" -" - a string with the the URL for the link under the cursor -" - an empty string if the cursor is not on a link -" -" TODO -" -" - multiline support -" - give an error if the separator does is not on a link -" -function! s:Markdown_GetUrlForPosition(lnum, col) - let l:lnum = a:lnum - let l:col = a:col - let l:syn = synIDattr(synID(l:lnum, l:col, 1), 'name') - - if l:syn ==# 'mkdInlineURL' || l:syn ==# 'mkdURL' || l:syn ==# 'mkdLinkDefTarget' - " Do nothing. - elseif l:syn ==# 'mkdLink' - let [l:lnum, l:col] = FindNextSyntax(l:lnum, l:col, 'mkdURL') - let l:syn = 'mkdURL' - elseif l:syn ==# 'mkdDelimiter' - let l:line = getline(l:lnum) - let l:char = l:line[col - 1] - if l:char ==# '<' - let l:col += 1 - elseif l:char ==# '>' || l:char ==# ')' - let l:col -= 1 - elseif l:char ==# '[' || l:char ==# ']' || l:char ==# '(' - let [l:lnum, l:col] = FindNextSyntax(l:lnum, l:col, 'mkdURL') - else - return '' - endif - else - return '' - endif +if g:markdown_enable_mappings + " Jumping around + noremap