自定义Markdown链接文本对象在Vim脚本/命令模式下无法执行操作
自定义Markdown文本对象在脚本/命令模式失效的问题解决
我为Markdown链接创建了自定义文本对象il,正常模式下手动执行yil/dil等操作能正确选中并操作链接,但在函数脚本里调用normal! yil,或者通过映射执行时完全失效。
原自定义文本对象代码
function! markdown#InLink() let l:magic = &magic set magic let l:currentLineNumber = line('.') " markdown link regex pattern let l:pattern = '\[[^\]]\+\]([^)]\+)' " move cursor to end of the markdown link if (!search(l:pattern, 'ce', l:currentLineNumber)) " if it fails, there was not match on the line, so return prematurely return endif " start visually selecting from end of the markdown link normal! v " move cursor to beginning of the markdown link call search(l:pattern, 'cb', l:currentLineNumber) " restore magic let &magic = l:magic endfunction xnoremap <silent> il :<c-u>call markdown#InLink()<cr> onoremap <silent> il :<c-u>call markdown#InLink()<cr>
原复制链接函数代码
function! markdown#YankLink() normal! yil endfunction nnoremap <buffer> <Leader>yl :call markdown#YankLink()<CR>
问题原因
原函数依赖search()命令的光标移动和交互模式下的视觉选中同步,在脚本/命令模式执行时,search()的位置变更无法和normal! v的选中操作正确同步,导致选中范围失效。另外,onoremap的操作符等待模式在非交互环境下,原逻辑没有处理光标位置的正确绑定。
解决方案
修改markdown#InLink()函数,改用直接匹配行内文本的方式定位链接范围,并区分操作符等待模式和视觉模式的处理逻辑:
function! markdown#InLink() let l:magic = &magic set magic let l:current_line = getline('.') let l:link_pattern = '\[[^\]]\+\]([^)]\+)' let l:match_start = match(l:current_line, l:link_pattern) " 当前行无匹配链接则退出 if l:match_start == -1 let &magic = l:magic return 0 endif let l:match_end = matchend(l:current_line, l:link_pattern) let l:current_row = line('.') " 区分操作符等待模式(如y/d之后调用il)和视觉模式 if !empty(v:operator) " 操作符模式下:先定位到链接起始,再选中到结束 call setpos('.', [0, l:current_row, l:match_start + 1, 0]) normal! v call setpos('.', [0, l:current_row, l:match_end, 0]) else " 视觉模式下:先定位到链接结束,再反向选中到起始 call setpos('.', [0, l:current_row, l:match_end, 0]) normal! v call setpos('.', [0, l:current_row, l:match_start + 1, 0]) endif let &magic = l:magic return 1 endfunction xnoremap <silent> il :<c-u>call markdown#InLink()<cr> onoremap <silent> il :<c-u>call markdown#InLink()<cr>
修改说明
- 用
match()和matchend()替代search(),直接在当前行内查找链接的起始和结束位置,避免跨搜索的光标同步问题 - 通过
v:operator变量判断当前是否处于操作符等待模式(比如执行y后等待文本对象),分别处理光标定位逻辑 - 用
setpos()直接设置光标位置,确保在脚本执行时也能准确定位并选中链接范围
修改后,执行<Leader>yl或者:execute 'normal! yil'即可正常复制Markdown链接。
内容的提问来源于stack exchange,提问作者ankur
相关产品推荐
相关产品推荐

