2017-02-24 56 views
2

我经常将文本行转换为数组。例如,这样的:Vim:创建需要移动的自定义命令

Monday 
Tuesday 
Wednesday 

变为:

[ 
    'Monday', 
    'Tuesday', 
    'Wednesday', 
] 

我可以使地图改变所述线中的一个(例如Monday'Monday',)像这样:

:nnoremap gsa ^i'<Esc>A,

我想要做的是让该命令采取移动或文本对象,以便我可以执行它,如gsaipgsip3j

我该如何做到这一点?

回答

1

您可以使用'operatorfunc'[email protected]来制作带有 议案的地图。该帮助给出了关于 :map-operator主题下的完整说明和示例。基本上你可以在地图上设置你想要的功能 ,然后使用[email protected]。 Vim将等待一个动作,然后设置 标记'[']并调用你的函数。

在你的功能里面你可以发挥创意,在这里我只是简单地提出了一个例子,说明如何将这个原理应用到你需要的东西上。

:nnoremap <silent> gsa :set opfunc=TransformToArray<cr>[email protected] 

function! TransformToArray(type) 
    if a:type == 'line' 
    let s=line("'[") " saving beginning mark 
    ']s/\(\s*\).*\zs/\r\1] 
    exec s ",']-1s/\\s*\\zs.*/ '&'," 
    exec s 's/\(\s*\)\zs\ze /[\r\1' 
    elseif a:type == 'char' 
    " ... 
    endif 
endfunction 
+0

为什么不改变'“转到\ ]”'去''去]''? –

+1

@ Meninx-メネンックス对我来说是需要的,因为缩进设置。由于前一行缩进2,因此在插入右大括号之前,先用bs将其删除。这只是一个快速的解决方案,需要更多的思想来提高:) – sidyll

+0

@ Meninx-メネンックス我改变了它,现在看起来更加紧凑和更少冗余。 – sidyll

0

准确地说,您似乎想要将映射应用于运动或文本对象所覆盖的每条线。 vipv2j

可以经由视觉模式建立这样范围。然后,您可以使用:normal gsa(键入;如果从可视模式进入命令行模式,Vim将自动插入选定范围(:'<,'>))将自定义映射应用于每一行(光标位于每个行的第一列行,根据:help :normal-range)。

1

将这个到您的.vimrc文件:

vnoremap <silent> gsa :call Brackets()<CR> 

function! Brackets() 
    execute "normal! I'" 
    if line(".") == a:lastline 
     execute "normal! A'\<cr>]" 
     execute a:firstline."s:^:[\r:" 
    else 
     execute "normal! A'," 
    endif 
endfunction 

选择您想例如vip的视线块,然后按gsa

0

如果你真的想在最后一项后面添加一个逗号,我会这样做,以保持寄存器不变。

function! s:to_list() range abort 
    let words = getline(a:firstline, a:lastline) 
    exe a:firstline.','.a:lastline.'d _' " remove the "_" to fill the unnamed register 
    let lines = ['['] + map(words, '" ".string(v:val).","') + [']'] 
    call append(a:firstline-1, lines) 
endfunction 

command! -nargs=0 -range=% ToList <line1>,<line2>call s:to_list() 

为了摆脱最后两行的,我已经编辑的map()结果的最后一个项目或玩join()

let lines = "[\n" . join(map(words, '" ".string(v:val)'), ",\n") . "\n]" 
    put!=lines