色情、禅宗和.vimrc

2020-10-17 06:41:44

Karolis Koncevičius Vim是一个高度可定制的文本编辑器,专为编写代码而设计。但是,开放式配置的可能性往往会诱使用户浪费时间,同时追求工作效率上的微小收益。本文描述了我的Vim之旅,从大量的个人定制开始,以对默认设置的重新热爱告终。

一般来说,新用户在使用了几个基本命令后,就开始沉迷于Vim配置色情。这类色情有各种不同的风格。有一种“表现狂”,它包括在状态栏、配色方案和字体装饰上修饰Vim,以给别人留下深刻印象。这通常会导致Vim被显示在视频上,或者不祥地出现在“Vim-Porn”屏幕截图上。还有一种“集成”类别,人们插入和扩展他们的Vim,直到它像IDE一样。Git集成、自动补全、语言服务器、重构和调试是这个版本中的交易工具。此外,还有更多的变体,如Git集成、自动补全、语言服务器、重构和调试。此外,还有更多的变体,如Git集成、自动补全、语言服务器、重构和调试,这些都是这个版本中的交易工具。此外,还有更多的变种,如Git集成、自动补全、语言服务器、重构和调试。包括“模糊”、“打包”、“方便地重新映射”,我相信任何人都能想出一些自己的。

我的特殊风格是“一致性”--我希望我的Vim是直观和可预测的。在工作时,我会经常注意Vim行为中的离题之处,然后花时间试图调整它们。在我的幻想中,Vim必须感觉直观和流畅,所以我试图纠正每一个小细节。尽管“一致性”色情是相当普通的,我还是设法构建了一个超过1000行代码的vimrc文件。

分享整个收藏是没有意义的,但这里有几个说明性的例子及其背后的原理。如果你喜欢的话,可以自由地尝试一下。

众所周知,Y与其他大写命令不一致。它复制整行,而D和C从光标位置操作到行尾。简单的重新映射解决了这个问题。

让相同的字符总是朝着同一个方向会容易得多,所以这个映射使得n总是前进,N总是后退。对于;和,0也是如此。

";使n始终向前搜索,向后N向后nnoremap<;expr>;n';nn';[v:searchward]nnoremap<;N';nn';[v:搜索向前]";make;始终;查找";向前和向后nnoremap<;expr>;;getcharsearch().向前?';;';:';,';nnoremap<;expr>;,getcharsearch().转发?';,';:';;';

我不喜欢将向前和向后的f重复放在不同的字符下:;和,.这组重新映射将它们放在相同的键下,并将冒号命令移到反号。原来的反号行为被转换为单引号。

";make;和,位于同一keynnoremap:,nnoremap`:nnoremap';`。

这组映射使j、k、h和l键在各种情况下执行一致的方向相关操作:滚动、更改和创建窗口、跨段落移动。

";使J、K、L和H移动光标。nnoremap J}nnoremap K{nnoremap L g_nnoremap H^";make<;c-j>;、<;c-k>;、<;c-l>;和<;c-h>;滚动屏幕。nnoremap<;c-j>;<;c-e>;nnoremap<;c-k>;c-y>;c-l>;滚动屏幕。Zlnnoremap<;c-h>;zh";make<;a-j>;、<;a-k>;、<;a-l>;和<;a-h>;移动到窗口。nnoremap<;a-j>;<;c-w>;jnnoremap<;a-k>;<;c-w>;nnoremap<;a-l>;c-w>;a-h>;<;c-w>;h";make<;a-J>;、<;a-K>;、<;a-L>;和<;a-H>;创建窗口。nnoremap<;a-J>;<;c-w>;s<;c-w>;nnoremap<;a-K>;<;c-w>;snnoremap<;a-H>;<;c-w>;Vnnoremap<;a-L>;<;c-w>;v<;c-w>;h。

如果你思考Vim是如何在句子和单词之间移动的,你会注意到它没有把光标放在它们之间的空白处,而是放在了第一个和最后一个字符上。类似地,这个坏男孩让J和K命令将光标放在最外面的一行上,同时从一个段落移动到另一个段落。

";移到段落边缘。函数!S:如果a:isInVisual Normal,则Move(isup,isInVisual)!GV end let curpos=getcurpos()let Firstline=';\(^\s*\n\)\zs\s*\S\&39;let Lastline=';\s*\S\\ze\n\s*$#39;let flag=';wn';。(a:isup?';b';:';b';)";移动到段落的第一行或最后一行,或者移动到文件的开头/结尾,让pat=';\(';.firstline.';\|';.lastline.';\)\|\%^\|\%$';&34;确保光标移动,搜索不会停留在当前线路呼叫光标(LINE(';.';),a:isup?1:COL(';$&39;))如果目标&>0字母curpos[1]=目标字母curpos[2]=curpos[4]结束调用设置(';.';,curpos)endfu";H K L J用于移动到段落edgennoremap<;静默>;J:<;c-u&>;call<;cr>;nnoremap<;移动(0,0)<;cr>;nnoremap<;K:<;c-u>;调用<;则让target=搜索(<;c-u&>;调用<;sid&>;移动(0,0)<;cr>;nnoremap<;K:<;C-u>;call<;sid>;move(1,0)<;cr>;vnoremap<;静默>;J:<;c-u>;call<;sid>;call<;sid>;cr>;vnoremap<;move(0,1)<;cr>;vnoremap<;静默>;K:<;c-u>;call<;sid>;move(1,1)<;cr>;onoremap J V:call<;sid>;move(0,0)<;cr>;onoremap J V:call<;sid>;cr>;onoremap J V:call<;sid>;cr>;Onoremap K V:调用<;sid>;move(1,0)<;cr>;

光标位置命令Result---word1 word2 de wo word2^dw word2word1字2 db word1 rd2^dge word2。

请注意,dge在两个方面不一致:第一,与db不同,它删除光标下的字符;第二,与dw不同,它删除移动到的单词的最后一个字符。

";使具有ge的命令与b一致,并获得映射ge:EXECUTE";NORMAL!";。V:倒数1。";ge<;space>;&34;<;cr>;

我有更多的例子,但你现在可能已经明白了。简单的事实是,我的1000行vimrc文件并没有给我任何安慰。当我打开它的时候,我的感觉最好被描述为一种焦虑。我经常感觉到一种奇怪的推动,想要改进它,更好地组织它,使它更一致。直到有一天我吃够了,按了DELETE键。

一开始,我确实感觉很邋遢,但我很快就找到了一种新的出行方式。

高度自定义的配置文件的一些问题是众所周知的。您必须使用插件来管理插件;必须跨不同的服务器传输点文件;失去在没有配置文件的情况下在计算机上工作的能力;如果不先禁用您的安装程序,其他人将无法使用您的计算机。删除繁重的配置消除了这些缺点。但是,我注意到下面列出的一些额外的较少讨论的好处。

当我的vimrc增长时,记住其中的所有映射和重映射变得更加困难。因此,在调整配置时,有时我会覆盖以前的映射,而另一些时候,我会以两种略微不同的方式应用相同的“一致性修复”两次,最终将两个不同的键重新映射到相同的操作。通常,更改内容或阅读和搜索帮助页面变得很麻烦。

即使是最简单的例子:使cw与dw保持一致,也比你想象的要难。可能有些人没有注意到,但在Vim CW中,它的行为类似于ce:它将文本更改到当前单词的末尾,而不是下一个单词的开头。它看起来很容易更改,但最著名的实现是近20行vimscript 0,不能保证它是完美的。您总是必须跟踪各种边缘情况,并针对不同的模式、空行、文件结尾情况添加检查。如果没有如此仔细的处理,修复本身就会不一致。

此外,一些一致性绷带本身在其他地方引入了不一致。以冒号和逗号之间的重新映射为例。请记住-我重新映射冒号使其与分号保持一致,并将原来的命令行操作转换为反标记。但是这个g;和g,未调整,您猜对了,仍然不一致。即使我们调整它们,";:register仍然在那里。所以,要重做最后一个命令行操作,我仍然必须调用@:,即使我的命令行操作本身现在在反标记下。这些不一致永远不会结束。

我逐渐习惯了我的简化映射,并且慢慢但肯定地失去了控制更复杂命令的能力。一个很好的例子就是我的领导者&>R映射(<;Leader>;R map):

它在当前窗口下面打开了一个:终端缓冲区,将其高度设置为20行,并在其中启动了R。不错的小命令,对吧?是的。但它只允许我在固定大小的窗口中打开R。不知何故,它剥夺了我在任何位置、任何大小打开窗口以及在其中运行任何命令的知识。我已经习惯了这种简单性,所以如果不首先检查vimrc中R重映射的语法,我就无法在30行高的窗口中打开Python。

使用寄存器是另一个很好的例子。我有一个将文本复制到系统剪贴板中的映射<;Leader>;y。简单、方便、快捷。当它不再存在时,我被迫发出完整的命令,即";+。它可能稍微不太方便,但是查看和使用这个语法可以清楚地知道发生了什么,它自然会鼓励使用不同的寄存器。当我养成了将文本拖入+寄存器的习惯后,我使用自定义寄存器的频率就变得更高了,这是一个副作用。Vim的一个新的方面,以前由我的自定义重新映射分层,现在开放和扩展了。

类似的事情也发生在拖拽文本并用它替换另一段文本的过程中。这是一个很常见的过程,所以我求助于插件。使用插件0很方便。它非常方便,我不需要考虑它,只需拖动文本,发出操作符,定义一个动作,然后砰地一声-替换就发生了。在我删除这个插件后,我不得不寻找Vim可以实现同样任务的方法。而在这里,我不得不再次使用寄存器。所以像cw<;c-r>;这样的命令。0将用yank寄存器中的内容替换该单词,这反过来又使我习惯于粘贴来自各种不同寄存器的文本。

将上面描述的两个注册操作组合在一起:拖入注册和从注册粘贴,您将看到原来的方法是多么灵活。我的重映射太方便了,因此它们使我无法熟悉更通用的默认Vim命令的行为。

如果你阅读上面的代码片段,你会注意到我非常关注j、k、h和l键。这些键让我在Vim初学者的日子里四处走动。所以我早期的配置尝试自然地开始增强它们。当然,如果j下降一行,为什么J不应该一段一段地下降呢?我重新映射了这些键,它们成为了我在Vim中导航的方式。我一直使用j、k、h、l和它们的组合。需要向下滚动屏幕吗?我重新映射了这些键,它们成了我在Vim中导航的方式。我一直使用j、k、h、l和它们的组合。需要向下滚动屏幕吗?我只能用J键跳过几个段落,需要把光标放在段落的某个位置吗?跨几个段落跳几次,然后用小写j,l进行几次调整,我就到了。但是,当您检查默认的Vim动作时,这四个字母似乎只是一个事后的想法。它们并不像初学者想象的那样重要。人们应该使用其他方法来解决问题,例如搜索、跳过方法和按标记导航。我将j、k、l和h放在Vim体验的中心,但没有任何理由,除了我对Vim中应该如何操作的错误初始假设。

最重要的是,我感觉到的一些不一致之处是想象出来的。起初,在我删除了我的整个配置后,我仍然试图保留几个“经过深思熟虑”的调整。其中一个方向修正是,n总是在搜索之后前进,N总是后退。试图保留这张地图也让我在这次经历中有了一个更大的“顿悟”时刻。在这一点上,我不再有运动重映射的星座,所以我试图更多地使用搜索。在特定的情况下,我想到达光标上方几段的单词,所以我按了?开始键入单词,然后按Return。但是,在光标和目标之间出现了另一个相同的单词,所以我的搜索就落在了那里。当看着我的目标,看到光标卡在中间,甚至没有想过它时,我按了n键。而且,由于n重映射仍然在适当的位置,我的光标从我想要的位置向后移动。发生了什么!?在这一点上,我已经使用调整后的n和N多年了,但是当我开始使用Vim而没有配置的时候,最初的默认行为立即变得更直观了。我只是看着我的目标,试图转到那里,这是怎么回事!?在这一点上,我已经使用调整后的n和N多年了,但是当我开始使用Vim而没有配置的时候,最初的默认行为立即变得更直观了。我只是看着我的目标,试图转到那里,这是不够的,n键是一个自然的“向我需要的方向移动”的命令,不用说它让我放弃了重映射和它的映射;而且,等同于。

最后,我的一些配置是由于对某些命令背后的真正目的的轻微误解造成的。例如,我使用*和#在光标下搜索单词。在这样的上下文中,我的重新映射使得光标最初在按下*和#后不会移动,而是突出显示该单词的所有匹配项。然后,我将像通常使用n和N一样导航搜索。但是,在丢失所有这些映射之后,我开始以不同的方式查看相同的键。*执行的操作真的应该被视为跳到单词的下一个实例。这在编写代码时特别有意义:您考虑调整某个变量,并希望查看它的下一个影响位置。同一过程的其他扩展有gd,[<;C-i&>;和]<;c-i>;。通过改变*和#的行为,我使t

首先,如果您从行首开始编辑,您将不会被包含和独占运动之间的区别所困扰。也就是说-光标所在的字符将始终包含在运动中。当您试图向后应用运动时情况并非如此。只需比较上面两个场景中两个看似等效的删除到词尾的命令:第一个是de,第二个是db。您注意到db是如何保持e字符不受影响的吗?这是因为运动是独占的,它不包括缓冲区中出现得更远的字符。在本例中是这样的。您可以记住这一点,然后使用DVB进行更正,但要点仍然存在-它更麻烦。

其次,向前移动的键通常放在更方便的位置。转到下一个单词的开头-w,到最后-。这两个字符靠得很近。与它们相比,类似的向后移动是不合适的:B和Ge。向前移动也经常映射到小写字母,这意味着更少的按键。当光标位于行首时,转到第一个引号吗?F";,从行尾开始做同样的事情吗?F";餐厅。

第三,当光标位于行首时,您将获得许多其他情况下不适用的便捷操作。在第一个引号内进行更改吗?-无需先移动光标即可执行此操作。在第二个示例中不能执行同样的操作。更改FULLNAME变量的值?F(第一个示例中的D,第一个示例中的F)dv0或T)d0。所有方便的快捷方式(如大写C和D、I";、%等)。只有当光标向前移动时才真正适用。

第四,说到方便性,如果我们考虑一下方向,Vim中的一些不一致开始变得更有意义。默认情况下Y复制整行是有原因的。想想编写代码-我们真正需要将一段代码从行的中间复制到末尾的频率是多少?与我们想要更改相同部分的时间相比,不是那么频繁。因此,Vi的作者可能认为让Y命令与C保持一致将是浪费一个键。此外,考虑一下';一种命令,不会跳到标记的确切位置,而只跳到标记所在的行的开头。如果已经存在一个更精确的替代选项,即反号,为什么会有这个键呢?如果您愿意,其目的可能是为您提供一种从行的开始处开始工作的方法。

第五,记住上一次创建宏是什么时候。如果打算在多行中重复,您可能要注意确保光标放在记录开始后的行首。原因是一样的,这样做给您带来的麻烦更少,并使宏更通用。

第六,有一组Vim命令不会超出线的边界。F和t是最明显的示例,但它们并不是唯一的例子。您可以查看:help WHITH WRAPH以查看更多内容。所有这些命令的目的都是将编辑内容包含在一行中。Vim似乎认为这是一项功能。

还有很多其他类似的细节,不胜枚举,其中包括“line undo”命令:通过始终将光标放在开头来跨行移动的U、+和-mobile命令,按两次键将在整行上执行的约定等等。所有这些内容加在一起,给我的印象是Vim希望我们逐行执行操作,并鼓励我们从一行的开头开始编辑。

那么,在经历了这么多麻烦之后,我是否后悔删除了我创建的1000行代码呢?没有。简单的事实是,无论我在自定义配置上投入了多少精力,构建和设计Vim的人都比我更了解它。它像冷水澡一样打击着我:实现的默认设置和设计是有原因的。我感觉到的一些不一致是我有限理解的结果。我对某个命令应该做什么,应该何时使用,以及如何使用做出了假设。但这些假设并不总是有根据的。

有一段时间,我甚至走到了相反的方向,试图让我的vimrc尽可能简约。这是一种禁欲主义的练习,它产生了类似的负面影响,除了在另一个方向之外。我仍然太在乎我的vimrc,只是这一次,我没有让它更一致,而是努力让它尽可能地轻。在一些禅宗修行中也会出现类似的悖论,比如一个弟子被告知不应该依附于事物,开始依附于不依恋。正确的态度,至少在Vim的情况下是这样。我学会了信任创造Vim的人的选择,不去干涉他们的设计。从长远来看,这种态度使我免于与Vim结构之间的艰苦斗争。从长远来看,它帮助我不再浪费时间。

现在,经过所有的努力,我的vimrc大约有50行代码,它只包含一些简单且常用的命令,比如这个映射到togg。

.