使用变量commentstring在vim中插入结束foldmarker

时间:2013-03-20 17:09:21

标签: vim folding

我定义了两个用于在Vim中快速插入foldmarkers的宏:

nnoremap <leader>mb A {{{<Esc>0
nnoremap <leader>me o# }}}<Esc>0zc

但很快就发现它们对于不使用#作为注释字符串的所有内容感到相当不满意。

所以我想出了这个动态,但它不起作用:

nnoremap <leader>mb A {{{<Esc>0
nnoremap <leader>me :call s:InsertFoldEnding()

…

function! s:InsertFoldEnding()
  l:line=call line('.')
  l:str=&commentstring + '}}}'
  call append(l:line, l:str)
endfunction

错误讯息:

E81: Using <SID> not in a script context

有什么问题?是否有更好的方法来插入这些折叠?

澄清:

我希望折叠最终看起来像这样:

" Caption {{{
Content
" }}}

1 个答案:

答案 0 :(得分:4)

你有很多错误。

  1. “使用&lt; SID&gt;不在脚本上下文中“是用于调用s:函数。您需要将s:替换为<SID>,并确保在定义该函数的同一文件中定义映射。 (或者手动展开<SID>“,但这很棘手。)
  2. l:line=…是一个错误的赋值表达式。使用:let分配和删除l:前缀(在函数上下文中,它是默认值)。
  3. &commentstring+'}}}'可能会导致0+始终是数字加法,使用.来连接字符串。
  4. append()函数没有缩进。因此,您需要在行前加matchstr(getline('.'), '^\s*')或做更聪明的事情。
  5. &commentstring看起来像/*%s*/。您无需连接,您需要使用printf(&cms, '}}}')substitute()
  6. 标记是可配置的。使用split(&foldmarker, ',')[0]代替'{{{'split(&foldmarker, ',')[1]代替'}}}'

  7. 我个人使用这个(直接你需要的东西,至少没有一些编辑):

    function InsertBlock(foldlevel, ...)
        let line=getline('.')
        if !empty(a:000)
            let text=a:000[0]
        else
            let text=matchstr(line, '\S.*\S\@<=')
        endif
        if empty(line)
            normal! "_cc_"
            let indent=getline('.')[:-3]
        else
            let indent=matchstr(line, '^\s*')
        endif
        let cmsl=split(&commentstring, '%s', 1)
        let [startmarker, endmarker]=split(&foldmarker, ',')
        let left=(indent).get(cmsl, 0, '').startmarker
        if a:foldlevel>0
            let left.=a:foldlevel
        elseif a:foldlevel==0
            let left.='1'
        endif
        let left.=' '.text
        let right=''
        if !empty(get(cmsl, 1, ''))
            let right=' '.cmsl[1]
        endif
        call setline('.', left)
        normal! $
        if !empty(right)
            call setline('.', left.right)
            normal! l
        endif
        if a:foldlevel==-1
            call append('.', (indent).get(cmsl, 0, '').endmarker)
        endif
    endfunction
    function CloseBlock(foldlevel)
        if a:foldlevel==0
            return
        endif
        let [startmarker, endmarker]=split(&foldmarker, ',')
        let foldstart=search('\V'.escape(startmarker, '\').a:foldlevel, 'bnW')
        let cmsl=split(&commentstring, '%s', 1)
        if foldstart
            let indent=matchstr(getline(foldstart), '^\s*')
        else
            normal! "_cc_"
            let indent=getline('.')[:-3]
        endif
        call setline('.', (indent).get(cmsl, 0, '').endmarker.a:foldlevel.
                    \              get(cmsl, 1, ''))
    endfunction
    nnoremap ,{          o<C-o>:call InsertBlock(foldlevel('.'))<CR><Esc>
    nnoremap ,}          o<C-o>:call InsertBlock(foldlevel('.')+1)<CR><Esc>
    nnoremap ,[          o<C-o>:call InsertBlock(foldlevel('.')-1)<CR><Esc>
    nnoremap ,-          o<C-o>:call CloseBlock(foldlevel('.'))<CR><Esc>
    
    inoremap ,{           <C-o>:call InsertBlock(foldlevel('.'))<CR>
    inoremap ,}           <C-o>:call InsertBlock(foldlevel('.')+1)<CR>
    inoremap ,[           <C-o>:call InsertBlock(foldlevel('.')-1)<CR>
    inoremap ,-           <C-o>:call CloseBlock(foldlevel('.'))<CR>
    inoremap ,+           <C-o>:call InsertBlock(foldlevel('.')+1)<CR><CR><C-o>:call CloseBlock(foldlevel('.'))<CR>
    

    。请注意,这a)将非空行转换为标记,标题看起来像"▶3 Caption{{{太胖而无法使用)。结束标记的使用更为罕见,它们看起来像"▲3。具有水平的标记自动结束具有更大或相同水平的所有折叠,因此大多数时间不需要结束标记。