9

Is it possible to reuse the range of ex commands in VIM?

As an example, I can write (copy) lines 4 to 10 from my current file to a new file using the following command:

:4,10w foo/bar.txt

But what I really want to do is move the lines to a new file. I can do this like so:

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

But it's a bit annoying to have to type 4,10 both times.

So I have two questions:

  1. Generally, Is there a way to reference the previously used range in ex commands?
  2. Specifically, if there is not a way to do (1), is there any easier way to cut and paste a number of lines from one file into a new one.
4

8 回答 8

5

我通常使用 cat 来执行此操作:

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

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

于 2012-06-13T17:54:22.887 回答
4

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

4GV10G
:w foo/bar.txt
gvd

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

但是你可以把问题转过来,然后尝试:

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

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

于 2012-06-13T09:35:13.240 回答
3

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

如果我更频繁地使用这种移动线组合,我会为它编写一个自定义命令:

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

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

您也可以为其他组合编写类似的内容。主要挑战是指定所有命令属性(bang、范围、完成),然后记住自定义命令名称。

于 2012-06-13T09:39:59.533 回答
2

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

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

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

当然,您可以使用任何字母a作为z标记;我通常使用be但你可以使用你喜欢的。

我将如何移动线条:

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

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

以上假设您已将autowrite选项设置为 on。使用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 中有效;只是你不需要它。

于 2012-06-13T09:32:59.113 回答
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>

作为插件

我的CmdlineSpecialEdits 插件(在许多其他插件中)也有这个映射。

于 2012-06-13T10:57:22.737 回答
1

您也可以这样做将匿名寄存器的内容写入 file2.txt

 :4,10d | :call writefile(split(@@, "\n", 1), 'file2.txt')
于 2012-06-13T11:17:31.173 回答
0

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

于 2012-06-13T09:36:46.023 回答
0

In Vim 8 and NVIM 0.3.7 as of writing, you can actually edit your command list and hit enter to execute.

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

q: is to enter interactive ex command

Once you open the interactive command list, you can then edit it and press enter to execute.

I love moopet's answer though, it's efficient.

于 2019-06-01T09:30:07.277 回答