【问题标题】:How to do something in a function based on the character under the cursor in Vim?如何根据 Vim 中光标下的字符在函数中做某事?
【发布时间】:2011-11-25 12:44:14
【问题描述】:

我正在编写一个在 LaTeX 中编辑特定环境的函数。

环境基本是这样的:

\begin{quicktikz}
    ...some stuff...
\end{quicktikz}

或者像这样:

\begin*{quicktikz}
    ...some stuff...
\end{quicktikz}

我想编写一个在从环境中调用时在两者之间切换的函数。由于我的 Vim 知识还不是全部,我想出了一个简单的解决方案:

  1. 使用let save_cursor=getpos(".")获取光标位置。
  2. 使用?\\begin{quicktikz}\|\\begin\*{quicktikz} 向后搜索\begin{quicktikz}
  3. 搜索{ 并使用:normal 0f{h 向左移动。
  4. 检查光标下的项目是否等于*
    • 如果有,请执行normal x
    • 如果没有,请执行normal a*<esc>
  5. 使用 call setpos('.',save_cursor)恢复光标位置。

除了第 3 步之外,我知道如何执行所有这些操作。如何检查光标下的字符是否等于 *

如果您知道更好的方法,欢迎分享。

【问题讨论】:

    标签: vim text-cursor


    【解决方案1】:

    我认为检索光标下字符的最简单方法是:

    getline(".")[col(".")-1]
    

    或者,您也可以使用strpart()

    strpart(getline("."), col(".")-1, 1)
    

    第一个表达式首先调用函数getline()传递"."为 参数,这意味着将返回光标所在的行。 然后我们使用所谓的 expr8expr-[](参见help)来检索一个 单个字符。传递的数字来自另一个函数,col() 它返回当前游标列。由于索引从 0 开始,因此减去 1。

    你可以像这样使用它

    if getline(".")[col(".")-1] == '*'
            ...
    

    【讨论】:

    • 另外,您能否对语法的每个部分进行一些解释?我正在努力学习 vim!
    • 对不起@romeovs,我刚刚编辑了答案。第二个表达式很容易用一点 :h :-) 破译,但如果您有任何问题,请告诉我。
    • @sidyll:strpart() 函数的有趣用法!顺便说一句,您是否知道一种从 Unicode 字符串中通过索引(以字符而不是字节索引)提取字符的简单方法? substitute(s, '^.\{7}\(.\).*$', '\1', '') 之类的东西?
    • @sidyll:关于更好的方法,我尝试解决的不是将字符置于光标下的问题,而是解决整体问题。结果,我遇到了一个有趣的 Vim 功能组合来解决这个问题。
    • @ib。 (抱歉回复延迟,我在另一个远离计算机的城市 :-) expr8 的帮助确实说它不适用于多字节字符串,但指向另一个名为 @987654334 的有用函数@。看看这两个,这个功能可能是解决方案。
    【解决方案2】:

    让我提出您描述的技术的替代实现。

    :?\\begin\>\zs\*\=?s//\='*'[submatch(0)!='']/|norm!``
    

    上面的命令由两个单独的命令组成,它们用| 链接(参见 :help :bar) 在一行中。第一个是替换(见:help :s) 对指定范围内的每一行执行,

    ?\\begin\>\zs\*\=?
    

    根据范围语法(请参阅:help :range),此范围指定 只有一行,即\\begin\>\zs\*\= 模式所在的前一行 匹配单词 begin 前面有一个反斜杠,后面是可选的 星号。1 模式各部分之间的 \zs 原子 匹配\begin*,在那里设置匹配的开始。所以,比赛 整个模式要么是空的,要么包含单个星号。这 不需要指定范围内的行,它对于重用很有用 稍后在:substitute 命令中使用相同的模式,其中只有那个星号 字符或其空白处应被替换。有关详细信息 模式的语法见:help /\>:help /\=:help /\zs

    替换本身,

    s//\='*'[submatch(0)!='']/
    

    替换最后一个搜索模式的第一次出现(由 在范围内向后搜索)与表达式的字符串 '*'[submatch(0)!=''] 评估(请参阅:help sub-replace-\=)。作为图案 仅匹配空字符串或星号,子表达式 如果\begin 之后没有星号,submatch(0)!='' 的计算结果为零,或者 一个否则。字符串 '*' 的零下标导致子字符串 包含该单字符字符串的第一个字符。索引一是 等于字符串的长度,因此下标结果为空 细绳。因此,当\begin 后面有一个星号时,它会被替换为 空字符串,当星不存在时,紧随其后的零宽度间隔 \begin 替换为 *

    第二条命令,

    :norm!``
    

    利用:substitute 命令存储当前 在实际开始替换之前的光标位置。 `` 运动 命令跳回到最近一次跳转之前的位置(发生在 上述替换命令)恢复的位置 光标。2


    1 小心搜索,因为在范围内,像往常一样,它会换行 在文件末尾附近,当启用wrapscan 选项时(它已打开 默认)。

    2 不要将``'' 命令混淆 光标到该位置之前的行中的第一个非空白字符 最近的跳跃。

    【讨论】:

    • submatch(0)=="*"?"":"*" 只长了两个字符,但 +1 表示这个想法。不过,为什么要使用:exe
    • @Benoit:实际上,我已经将用表达式替换的部分缩短了一个字符。 :-) 反正你是对的,这个表达也是有道理的。
    • @Benoit::exe 在先前版本的答案中的命令中的使用是由于在执行 :global 命令后需要恢复精确的光标位置引起的。如果没有:exe,光标会跳转到其先前位置的行的第一个非空白字符,而不是实际的列位置。原来:global这个命令是多余的,没有它就不再需要:exe调用了。
    • 我看到你喜欢高尔夫,我喜欢解读你的新发现。这个比上一个可读性更强,甚至更短,如果可能的话,我会再加一个 +1。
    • @Benoit:顺便说一句,同样,今天我找到了一个improvement,为另一个最近的问题“Inserting indentation for columns in Vim”提供了解决方案。看看第一种解决问题的方法有多复杂可能会很有趣。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-09
    相关资源
    最近更新 更多