多个光标位于所需位置


14

我正在使用vim-multiple-cursors插件。

我想将光标恰好放在我想要的位置。例如([x]是光标位置):

Lorem ipsum dolor sit amet[1], consectetur adipiscing elit, 
sed do eiusmod tempor incididunt ut labore et dolore magna[2]
aliqua.

Sublime Text中,我通常会放置第一个光标,然后使用箭头键转到下一个位置并放置第二个光标。

VIM中有类似的东西吗? 与此插件或另一个。

编辑

以下评论,我的兴趣这样做试图写的时候出现
\section[My first section in this book]{My first section in this book}
在一个.tex文件中。我的第一反应是写\section[]{},然后把两个光标为了写里面的同样的事情[]{}

其他示例是_someStuff在几个不同的变量名称之后添加。例如,将其打开:

variable1 = 2
my_variable2 = 12
var3 = 14

到这个:

variable1_someStuff = 2
my_variable2_someStuff = 12
var3_someStuff = 14

使用多个游标,我可以通过选择一个列游标,然后转到单词的末尾,然后进行插入等操作。但是我想我很容易选择准确的游标位置。



1
我认为要问的一个重要问题是,为什么要这样做?你想做什么?使用多个游标并不是真正的“遵循Vim方式”,可能存在另一种使用内置功能来完成所需功能的方法,至少同样有效。
statox

@statox。参见编辑。我举了两个例子。我可以使用vim-multiple-cursors插件完成第二个任务,但至少不能以简单的方式完成第一个任务。
tomasyany

@ Nobe4。谢谢,第二个脚本成功了。
tomasyany

Answers:


30

使用多个光标不是Vimmer的事情

正如我在使用多光标(甚至带有插件)的注释中所说的,并不是真正的“遵循Vim方式”,我完全理解它对Sublime-Text的用户很有吸引力,但是您经常可以找到至少是借助Vim内置功能提高了效率。

当然,找到这些替代解决方案并不总是那么容易,有时会花费一些时间,但是随着您在Vim上的经验,它将变得更加容易,并且您会发现,随着时间的流逝,多个游标对您似乎完全没有用。

太酷了,但是我如何找到替代方法呢?

没有通用的答案,因为它在很大程度上取决于您要尝试做的事情,我将尝试就尝试的第一件事给出一些提示:


点命令 .

点命令可能是Vim中功能最强大的工具之一,它只允许我们重复上一次更改。我无法比德鲁•尼尔(Drew Neil)在他的“ 实用Vim”中更好地解释它。我认为每个Vimmer应该考虑阅读这本书。

该命令的优势在于,最后的更改可以是对字符,行或整个文件进行的操作。例如,更改可以由您进入插入模式的那一刻和您回到普通模式的那一刻来界定。

考虑到这一点,使用多光标可以轻松完成您想做的事情:

  • 首先让我们建立环境:让我们按照您的建议编写

    \section[]{}

  • 然后进行可重复的更改 。光标现在位于上},单击F[可回到[字符上。然后使用进入插入模式i并使用键入My first section in this book并返回到普通模式ESC

    \section[My first section in this book]{}

  • 接下来是神奇的部分:让我们键入f{将光标放在{角色上,然后按一下.以重复上一次更改:

    \section[My first section in this book]{My first section in this book}

dot命令的所有挑战是学习如何进行可重复的更改:它与grokking Vim一起提供,但基本的目的是了解如何以可重复的方式进行更改。

例如,要在行尾插入半冒号,您更喜欢使用 A;而不是$a;。为什么?

因为A;创建了原子动作,所以当您.在另一行上使用时,无论您在行中的什么位置,都将在末尾插入分号。而使用时$a;,将更改分为两部分,$a并插入,;所以如果使用.它将在光标的当前位置插入分号。

注意 Vim中的魔术公式为n.。一个非常酷的工作流程是:

  • 搜索您要进行编辑的地方 /pattern
  • 进行可重复的编辑
  • 用于n转到下一个地方进行编辑
  • 用于.重复编辑
  • 重复最后两个步骤:您是世界之王(或至少是编辑之王)

巨集

宏是Vim中另一个非常重要的工具,因为它可以让您记录一系列击键并重复进行,就像您再次键入一样。

我以您的第二个用例为例:

variable1 = 2
my_variable2 = 12
var3 = 14

再次重要的是学习如何提高宏的效率(我将在后面给出一个反例):

  • 将光标放在单词上,variable1然后使用开始记录宏 qq。这意味着“开始将我以后所有的击键记录在名为q” 的寄存器中。

  • 开始输入编辑内容:

    • 0 在行的开头
    • e 在第一个单词的结尾
    • a 在光标后追加
    • .someStuff 追加通缉文本
    • <Esc> 停止插入
    • j 下一行
    • q 停止录制宏
  • 你会得到:

variable1.someStuff = 2
my_variable2 = 12
var3 = 14
  • 现在,您可以使用宏重复进行编辑。当您在右边进行编辑时,只需使用即可执行宏@q。由于我们要执行两次,因此您可以使用它,2@q并且您将获得以下结果:
variable1.someStuff = 2
my_variable2.someStuff = 12
var3.someStuff = 14

注1:您可能已经注意到,0ea在宏的开头使用确实非常重要。确实,如果在记录宏并再次执行它之前将光标放在第一个单词的末尾,则结果将是:

variable1.someStuff = 2
my_variable2 = 12.someStuff
var3 = 14.someStuff

作为您的光标,文本将在更改行后插入到光标的位置(在这种情况下,即行的结尾)

注意2:宏非常强大,您甚至可以在不熟悉时创建递归宏。这里的宏可能是:

`0ea.someStuff<Esc>j@q`

最终版本@q会自己调用宏而不是使用2@q;您将使用@q完,所有工作都将完成。


视觉障碍

这是另一个技巧,它并不直接适用于您的用例,但是对于同时编辑大量行非常有用。让我们提取一下CSS代码:

li.one   a{ background-image: url('/images/sprite.png'); }
li.two   a{ background-image: url('/images/sprite.png'); }
li.three a{ background-image: url('/images/sprite.png'); }

如果将精灵从images移到components怎么办?

好了,您可以将光标放在上iimages然后按<C-v>。这将启动可视块模式,该模式允许选择块。现在,您可以键入t/ 以选择要更改的单词,并2j选择所有出现的单词。

之后,您只需键入c以更改单词,然后输入components。当您退出插入模式时,您会看到:

li.one   a{ background-image: url('/components/sprite.png'); }
li.two   a{ background-image: url('/components/sprite.png'); }
li.three a{ background-image: url('/components/sprite.png'); }

全局命令

全局命令是一种工具,它允许在与模式匹配的行上应用ex模式命令,这再次是将相同的更改应用于不同位置而无需多个光标的好方法。

语法如下:

:[range] g / pattern / command

有关[range]参数的更多详细信息,请参见:h :range。我在这里不做详细说明,我只想提醒一下,它%代表整个文件,'<,'> 代表最后选择,并1,5代表文件的第1至5行。

此参数定义将由全局命令处理的行。如果未指定范围,则%默认情况下将使用全局命令。

[pattern]参数是用于搜索引擎的搜索模式。由于它集成了搜索历史记录,因此您可以将该字段保留为空白,然后全局命令将使用搜索历史记录中的最后一个搜索模式。

最后,[command]参数是您可能习惯使用的ex命令。

现在,全局命令的行为非常简单:

  • 遍历[range]参数中定义的所有行
  • 如果当前行与定义的模式匹配,则应用命令

由于[command]参数是ex命令,因此您可以做很多事情。让我们采用以下不太有趣的伪代码,其中包含许多调试消息:

var myList  = null
var i       = 0

myList = new List()
echo "List instantiated"

for (i=0; i<10; i++)
    myList.Add(i)
    echo i . " added to the list"

echo "end of for loop"

现在,我们确定您确定此代码有效,并且想要删除这些无用的echo语句:

  • 您可以在整个文件上应用全局命令,因此必须在命令前添加%(或不添加任何内容,因为这%是默认范围)。

  • 您知道要删除的行都与模式匹配 echo

  • 您要删除这些行,因此必须使用命令:delete ,该命令也可以缩写为d

因此,您只需使用以下功能:

:%global/echo/delete

也可以缩写为

:g/echo/d

需要注意的是%消失了,global简称gdelete作为d。您可能会想到结果是:

var myList  = null
var i       = 0

myList = new List()

for (i=0; i<10; i++)
    myList.Add(i)

注意1:我花了一些时间认识到的重要一点是,该 normal命令是ex命令,这意味着您可以将其与global命令一起使用。这可能非常强大:假设我想复制所有包含echo的行,不需要宏,甚至不需要魔术公式n.。我可以简单地使用

:g/echo/normal YP

和瞧:

var myList  = null
var i       = 0

myList = new List()
echo "List instantiated"
echo "List instantiated"

for (i=0; i<10; i++)
    myList.Add(i)
    echo i . " added to the list"
    echo i . " added to the list"

echo "end of for loop"
echo "end of for loop"

注2: “如果我想在与特定模式不匹配的行上使用命令怎么办?”

global有一个与之相反的vglobal缩写命令vglobal除了命令将应用于与[pattern]参数不匹配的行外,该命令的用法与之完全相同。如果我们申请的话

:v/echo/d

在前面的示例中,我们得到:

echo "List instantiated"
    echo i . " added to the list"
echo "end of for loop"

delete命令已应用于未包含的行echo


在这里,我希望这些提示能给您一些想法,以帮助您摆脱多光标插件并以Vim的方式使用Vim ;-)

如您所见,这些示例非常简单,并且仅用来说明按照Vim的方法,您实际上很少需要多个游标。我的建议是,当您遇到认为有用的情况时,写下来,然后花一些时间来找到更好的解决方案。您最终有99%的时间会找到一种更快/更有效的方法。

另外,我会再重复一遍,但我真的鼓励您阅读 Drew Neil的《实用Vim》,因为这本书不是关于“如何在Vim中做到这一点”,而是关于“如何学习以Vim的方式思考”。这将使您以良好的方式为将来的问题构建自己的解决方案。


PS特别感谢@Alex Stragies的编辑工作以及他对这一长篇文章所做的更正。


非常完整的答案。实际上,我确实知道所有这些命令,但从未想过像那样使用它们……我想我需要更多的练习。但是,我必须说,有时'vim-way'所花的时间比仅使用某些插件要长(例如,使用我提到的插件可以更快地完成CSS示例),有时所需的时间要短得多(实际上,如果使用得当,vim通常比任何文本编辑器都快。
tomasyany

顺便说一句,我想你的答案已经很完整了。我会接受的,但是如果您想添加更多详细信息,请这样做,我们很高兴阅读它们。
tomasyany

1
@tomasyany:确实确实有时使用“ vim方式”可能看起来更长(我无法计算出创建工作宏所花的时间比手动完成更改要花费多少时间),但随着实践的发展,它最终会变得更快。我使用Vim仅仅一年了,我(非常)还不是专家,但是我可以感觉到,随着我的练习,我的编辑工作会不断提高。
statox

1
可能还应该提到gn文本对象。它解决了多个游标的一些用例。用搜索/,然后用dgncgn,然后用重复.
贾斯汀·凯斯

@Justin我不太熟悉,gn我会尝试一下然后添加它。谢谢你的抬头!
statox

5

给我的给定用例听起来像想知道.key命令(重复最后一个Editing命令)

  • 转到第一位,按i,插入您的文字,<ESC>
  • 移至位置2,按.(点)==>插入相同文本
  • 要在此处向下移动一行并再次插入(在插入连续行时),请按 <ALT>-j.

您为我的tex示例通过以下方式解决:

I\section[]{}<ESC>hhiMy first Sec...<ESC>lll.


这是一个非常不错的解决方案。我完全知道.关键命令,但从未想过以这种方式使用它。我同意这是一个好方法。但是您的答案实际上并未涉及真正的问题,因此我认为接受它是不合适的。
tomasyany 2015年

1
好吧,您的问题(在添加了所需的用例之后)使我想起“我非常喜欢我的剪刀,想用它们拧紧螺丝。告诉我如何做”。我指着您想起螺丝刀的妙用;)(我补充说,因为我不知道如何在评论中格式化)
Alex Stragies

4

更多Vim方式。

第一项任务:

\section[foobar baz]{foobar baz}

工作流程:

\section[]{}
hh
ifoobar baz<Esc>
$.

第二项任务:

variable1 = 2
my_variable2 = 12
var3 = 14

命令:

3:norm ea_somestuff

结果:

variable1_somestuff = 2
my_variable2_somestuff = 12
var3_somestuff = 14
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.