在VIM中重用ex命令中的先前范围

时间:2012-06-13 08:51:11

标签: vim

是否可以在VIM中重用ex命令的范围?

例如,我可以使用以下命令将当前文件中的第4到第10行写入(复制)到新文件中:

:4,10w foo/bar.txt

但我真正想做的是将线条移动到新文件。我可以这样做:

:4,10w foo/bar.txt
:4,10d

但是两次输入4,10都有点烦人。

所以我有两个问题:

  1. 一般,有没有办法在ex命令中引用以前使用的范围?
  2. 具体,如果没有办法(1),是否有更简单的方法可以将一行文件中的多行剪切并粘贴到新文件中。

8 个答案:

答案 0 :(得分:5)

我通常用猫来做这件事:

:4,10!cat > foo/bar.txt

这是有效的,因为你通过cat管道线并用结果输出替换它们,这没什么。当然,您可以通过执行>>追加到现有文件的末尾。而不是>。

答案 1 :(得分:4)

我不知道(1)的答案,但回答(2),有许多不同的方法,不需要手动重新选择线。在可视模式下,这将起作用:

4GV10G
:w foo/bar.txt
gvd

因为gv重新选择了之前的选择,这几乎是你想要的,而不使用ex范围。

但你可以把问题放在首位,然后尝试:

:4,10d
:sp foo/bar.txt
pZZ

剪切,然后粘贴到新文件中,然后关闭它。

答案 2 :(得分:3)

除了使用Vim历史记录( Cursor Up q:)并删除上一个命令以便只保留范围之外,没有办法重复使用最后一个范围,没有魔法变量。

如果我经常使用此移动线组合,我会为它编写一个自定义命令:

command! -bang -range -nargs=1 -complete=file MoveWrite <line1>,<line2>write<bang> <args> | <line1>,<line2>delete _

您只需指定一次范围并保存输入。

你也可以为其他组合写这样的东西。主要挑战是指定所有命令属性(爆炸,范围,完成),以及稍后记住自定义命令名称。

答案 3 :(得分:2)

这是一个实现此目的的命令行映射。我将它绑定到CTRL-G CTRL-U,因为它执行与CTRL-U类似的操作。 (但你当然可以改变它!)

" c_CTRL-G_CTRL-U   Remove all characters between the cursor position and
"           the closest previous |:range| given to a command. When
"           directly after a range, remove it.
"           Useful to repeat a recalled command line with the same
"           range, but a different command.
let s:singleRangeExpr = '\%(\d\+\|[.$%]\|''\S\|\\[/?&]\|/[^/]*/\|?[^?]*?\)\%([+-]\d*\)\?'
let s:rangeExpr = s:singleRangeExpr.'\%([,;]'.s:singleRangeExpr.'\)\?'
let s:upToRangeExpr = '^\%(.*\\\@<!|\)\?\s*' . s:rangeExpr . '\ze\s*\h'
" Note: I didn't take over the handling of command prefixes (:verbose, :silent,
" etc.) to avoid making this overly complex.
function! s:RemoveAllButRange()
    let l:cmdlineBeforeCursor = strpart(getcmdline(), 0, getcmdpos() - 1)
    let l:cmdlineAfterCursor = strpart(getcmdline(), getcmdpos() - 1)

    let l:upToRange = matchstr(l:cmdlineBeforeCursor, s:upToRangeExpr)
    if empty(l:upToRange)
        return getcmdline()
    else
        call setcmdpos(strlen(l:upToRange) + 1)
        return l:upToRange . l:cmdlineAfterCursor
    endif
endfunction
cnoremap <C-g><C-u> <C-\>e(<SID>RemoveAllButRange())<CR>

答案 4 :(得分:1)

通常,我要做的是从一个文件中删除行,切换到另一个文件,然后粘贴。

另外,我通常使用标记。我没有输入实际数字,而是点击mb标记开始行,然后转到结束行并点击d'b以删除标记为b的行。但您可以使用mb标记开始行,使用me标记结束行,然后运行ex命令:

:'b,'e w somefile.txt<Enter>

当然,您可以使用az中的任何字母作为标记;我通常使用be,但您可以使用自己喜欢的内容。

我如何移动线条:

m'b
<navigate to end line>
d'b
:n somefile.txt<Enter>
p
Ctrl+^

Ctrl + ^从当前打开的文件切换到上一个打开的文件。 (如果您愿意,也可以打开一个窗格并切换窗格。窗格不能在普通的vi中工作,但在vim中工作。)

以上假设您已设置autowrite选项。使用autowrite:n命令和Ctrl + ^都只是编写当前文件然后切换文件,而不是抱怨文件已更改而不保存。您也可以执行上述操作,只需在使用:n或Ctrl + ^。

之前显式写入文件

顺便说一下,我使用Ctrl + ^,以至于我把它映射到K。打字比较容易,但很久以前我养成了这种习惯,以前我常常不得不使用一个无法输入Ctrl + ^的哑终端。

顺便说一下,当你删除行时,它们会进入“未命名的缓冲区”。在vim中,切换文件时会保留未命名的缓冲区。在原始vi中,清除未命名的缓冲区。所以上面的内容不适用于旧的vi。您可以通过删除命名缓冲区,然后从命名缓冲区粘贴来使其工作;适用于任何版本的vi。

m'b
<navigate to end line>
"ad'b
:n somefile.txt<Enter>
"ap
Ctrl+^

上面删除了名为a的缓冲区,然后从a粘贴到另一个文件中。这当然适用于vim;只是你不需要它。

答案 5 :(得分:1)

您也可以这样做,将匿名注册的内容写入file2.txt

 :4,10d | :call writefile(split(@@, "\n", 1), 'file2.txt')

答案 6 :(得分:0)

您可以先删除,然后打开新标签并粘贴内容 - 所以:4,10d,然后是:tabe foo/bar.txt,然后是p ...听起来会更好吗?

答案 7 :(得分:0)

在撰写本文时,在Vim 8和NVIM 0.3.7中,您实际上可以编辑命令列表,然后按Enter键来执行。

:4,10w foo/bar.txt
q:

q:是输入交互式ex命令

打开交互式命令列表后,您可以对其进行编辑并按Enter键来执行。

尽管我爱moopet's answer,但效率很高。