2012-03-05 60 views
1

手动设置折叠时,如果可以以上下文敏感的方式设置commentstring,将会很方便。考虑语言使用BCPL样式注释标记的情况(即,注释以//开始并以换行符终止),视觉块的第一行包含注释,而最后一行不包含注释。目前,如果commentstring设置为//%s,则在使用zf创建折叠时,冗余//字符将附加到第一行。评论字符串中的上下文敏感度

是否可以设置commentstring以便仅在//字符尚未出现在行上才能添加//字符?

回答

1

根据:help fold-create-marker,自动折叠标记插入 不能正常工作时:

  • 线已包含具有一个电平数字的标记。然后Vim不知道该怎么做。
  • 附近的折叠在他们的标记中使用了一个级别号码。
  • 该行在注释中,commentstring不为空且嵌套 注释不起作用。例如对于C:在 内部添加/* {{{ */,评论将截断现有评论。

因此,就不可能通过修改 commentstring设置来改变默认zf行为。

但是,可以创建zf命令的定制版本, 将考虑折叠的开始或结束(或两个)行可能有意见。例如,考虑以下映射,一个用于通过视觉选择标记折叠的 ,另一个用于与运动 命令一起使用。

nnoremap <silent> <leader>zf :set opfunc=CreateMarkerFold<cr>[email protected] 
vnoremap <silent> <leader>zf :<c-u>call CreateMarkerFold(visualmode(), 1)<cr> 
function! CreateMarkerFold(vt, ...) 
    let range = map(['[<', ']>'], 'line("''".v:val[a:0])') 
    let mark = split(&foldmarker, ',') 
    let pat = escape(&commentstring, '\') 
    let pat = '\V' . substitute(pat, '\\\@<!%s', '\\zs\\ze\\.\\{-}', '') 
    for i in [1, 0] 
     let line = getline(range[i]) 
     if line =~ pat 
      let line = substitute(line, pat, escape(mark[i], '\'), '') 
     else 
      let line .= printf(&commentstring, mark[i]) 
     endif 
     call setline(range[i], line) 
    endfor 
endfunction 

映射的两者都遵循相同的程序。在添加开始和结束折叠标记之前,它会分别检查要折叠的块的第一个和最后一个 行是否匹配commentstring模式。对于两个匹配的 中的每一个,它都在第一个发现的 评论中的相应标记内插入文本的开头。否则,标记为 ,根据commentstring模板进行装饰,并在 的末尾添加该行。

如果在后一种情况下,最好在自己的行上分隔标记, 可以更改for循环,如下所示。

for i in [1, 0] 
     let line = getline(range[i]) 
     if line =~ pat 
      let line = substitute(line, pat, escape(mark[i], '\'), '') 
      call setline(range[i], line) 
     else 
      call append(range[i] - !i, printf(&commentstring, mark[i])) 
     endif 
    endfor 

不像以前的版本的循环,处理这两个 行的顺序是很重要的:将结束标记线应先加入,如果 必要的,因为插入线为开头标记将移 以下行改变了他们的号码。

+0

非常好。我改变的唯一的事情就是使用setline而不是在else子句中追加来将标记保持在同一行上。 – 2012-03-10 13:28:35

+0

@WilliamPursell:我认为,你是对的:将自定义'zf'命令设为默认行为是个好主意,因为它符合内置'zf'的行为。答案会相应更新。 – 2012-03-10 14:47:51

相关问题