如何在 Vim 中为命令创建别名?

Posted

技术标签:

【中文标题】如何在 Vim 中为命令创建别名?【英文标题】:How to create an alias for a command in Vim? 【发布时间】:2011-04-22 04:15:37 【问题描述】:

Vim 是我编程时首选的文本编辑器,因此我总是遇到一个特别烦人的问题。

通常,当我需要快速保存缓冲区并继续执行其他杂项任务时,我会做典型的

:w

但是,我总是——似乎超过 50% 的时间——设法利用:w。很自然,Vim 会对我大喊大叫,因为 W 是一个无效命令:

E492: Not an editor command: W

我的问题是如何在 Vim 中为冒号命令别名。特别是,您能否举例说明如何将W 别名为w

我知道将键映射到某些命令的过程,但这不是我想要的。

【问题讨论】:

Can I (re-) map commands in vim?的可能重复 为了避免:W,您可以映射一个键来执行保存。如果你习惯了一些使用 Ctrl-s 保存的程序,那么 $VIM/mswin.vim 中有这些映射:" Use CTRL-S for saving, also in Insert modenoremap <C-S> :update<CR>vnoremap <C-S> <C-C>:update<CR>inoremap <C-S> <C-O>:update<CR> 关于 Vi Stack 交换的类似问题:vi.stackexchange.com/q/2665/7244 【参考方案1】:

要保持完成不变,请尝试使用

cnoreabbrev W w

它将在命令行中将W 替换为w,但前提是它既不跟也不以单词字符开头,因此:W<CR> 将替换为:w<CR>,但:Write 不会。 (请注意,这会影响任何匹配的命令,包括您可能没想到的命令。例如,命令 :saveas W Z 将被 :saveas w Z 替换,因此请注意这一点。)

更新

这是我现在的写法

cnoreabbrev <expr> W ((getcmdtype() is# ':' && getcmdline() is# 'W')?('w'):('W'))

作为一个函数:

fun! SetupCommandAlias(from, to)
  exec 'cnoreabbrev <expr> '.a:from
        \ .' ((getcmdtype() is# ":" && getcmdline() is# "'.a:from.'")'
        \ .'? ("'.a:to.'") : ("'.a:from.'"))'
endfun
call SetupCommandAlias("W","w")

这会检查命令类型是:,命令是W,所以它比cnoreabbrev W w更安全。

【讨论】:

这个答案对我来说是最安全最可靠的。 如果您使用推荐的解决方案,请注意以下两个命令都将作为较低的命令工作,根据实际缓冲区内容和 VIM 设置可能会出现意外结果::%s/W/foo/g&lt;CR&gt; :%s/w/foo/g&lt;CR&gt; 实际上,这意味着 W 将被替换 anywhere 在命令栏中,包括例如在搜索中,因此 s/W foo/bar/g 将被替换进入 s/w foo/bar/g。这会很快变得烦人。请参阅我的答案以获得全面的解决方案。 绝对的;这是一个可怕的想法。您应该永远永远永远这样做。 :cnoreabbrev &lt;expr&gt; W getcmdtype()==':'&amp;&amp;getcmdline()=~#'^W'?'w':'W'【参考方案2】:

通过补充搜索,我发现有人问的question和我几乎一样。

:command <AliasName> <string of command to be aliased>

会成功的。

请注意,正如Richo 指出的那样,用户命令必须以大写字母开头。

【讨论】:

使用 :command 是很好的解决方案。 :cnoreabbrev 不理解 cmd1|cmd2,:command 可以。 一个不那么容易混淆的写法是:command AliasName string of command to be aliased 这不会处理/转发任何command 参数,例如-nargs-complete 等。 :Q!:W! 怎么样? 直言不讳:将:command W w 放入.vimrc 文件中。【参考方案3】:

我发现将; 键映射到: 会是一个更好的解决方案,并且可以提高您键入其他命令的效率。

nnoremap ; :
vnoremap ; :

【讨论】:

这是 vim 的最佳技巧。我现在已经习惯了,每次遇到正常行为时,我都需要尝试几次才能重新训练自己的思想。 这不是问题的答案。 @Flimm 不,但它使 OP 的问题消失了。 当使用tf 时,通常可以使用; 转到下一个匹配项。即使您将分号映射到冒号,也可以安全地映射另一种方式。不会有别名循环。 nnoremap : ;【参考方案4】:

最好的解决方案是使用writing a custom function 处理仅出现在命令栏开头的缩写。

为此,请在您的 vimrc 文件或其他任何地方添加以下内容。

" cabs - less stupidity                                                      
fu! Single_quote(str)
  return "'" . substitute(copy(a:str), "'", "''", 'g') . "'"
endfu
fu! Cabbrev(key, value)
  exe printf('cabbrev <expr> %s (getcmdtype() == ":" && getcmdpos() <= %d) ? %s : %s',
    \ a:key, 1+len(a:key), Single_quote(a:value), Single_quote(a:key))
endfu
"

 

" use this custom function for cabbrevations. This makes sure that they only
" apply in the beginning of a command. Else we might end up with stuff like
"   :%s/\vfoo/\v/\vbar/
" if we happen to move backwards in the pattern.

" For example:
call Cabbrev('W', 'w')

一些useful abbreviations from the source material 我在哪里找到了这些东西:

call Cabbrev('/',   '/\v')
call Cabbrev('?',   '?\v')

call Cabbrev('s/',  's/\v')
call Cabbrev('%s/', '%s/\v')

call Cabbrev('s#',  's#\v')
call Cabbrev('%s#', '%s#\v')

call Cabbrev('s@',  's@\v')
call Cabbrev('%s@', '%s@\v')

call Cabbrev('s!',  's!\v')
call Cabbrev('%s!', '%s!\v')

call Cabbrev('s%',  's%\v')
call Cabbrev('%s%', '%s%\v')

call Cabbrev("'<,'>s/", "'<,'>s/\v")
call Cabbrev("'<,'>s#", "'<,'>s#\v")
call Cabbrev("'<,'>s@", "'<,'>s@\v")
call Cabbrev("'<,'>s!", "'<,'>s!\v")

【讨论】:

有一个内置函数 string() 和你的 Single_quote() 做同样的事情。【参考方案5】:

假设你想在 gvim 中为 tabnew 命令添加别名。您只需在 .vimrc 文件中键入以下命令(如果不在主文件夹中,则创建一个)

cabbrev t tabnew

【讨论】:

这将导致:saveas t example之类的命令被:saveas tabnew example替换【参考方案6】:

也许您想将您的一个功能键 (F1..F12) 映射到 :w ?然后把它放到你的 .vimrc 中:

noremap  <f1> :w<return>
inoremap <f1> <c-o>:w<return>

(插入模式下的 ctrl-o 暂时切换到普通模式)。

【讨论】:

【参考方案7】:

最安全和最简单的是插件,例如cmdalias.vim 或我最近更新的vim-alias 考虑到

前面的空格或修饰符,例如:sil(ent)(!):redi(r), 用于当前视觉选择的范围修饰符,例如 '&lt;,'&gt;, 转义特殊字符,例如引号和 检查所选别名是否为有效的命令行缩写。

【讨论】:

【参考方案8】:

我认为@ZyX 的回答很棒,但是如果您使用的是新版本的 neovim (0.5+),您可能希望使用 lua 来定义函数。这是您可以做到的一种方法:

function _G.abbreviate_or_noop(input, output)
  local cmdtype = vim.fn.getcmdtype()
  local cmdline = vim.fn.getcmdline()

  if (cmdtype == ":" and cmdline == input) then 
    return output
  else
    return input
  end
end

function SetupCommandAlias(input, output)
  vim.api.nvim_command("cabbrev <expr> " .. input .. " " .. "v:lua.abbreviate_or_noop('" .. input .. "', '" .. output .. "')")
end

然后,您可以从 call SetupCommandAlias("pg", "postgres://") 中删除 call 并使用如下函数:SetupCommandAlias("pg", "postgres://")

n.b.如果从.vim 文件而不是.lua 文件中使用它,则需要在函数调用前加上lua,即lua SetupCommandAlias("pg", "postgres://")

【讨论】:

以上是关于如何在 Vim 中为命令创建别名?的主要内容,如果未能解决你的问题,请参考以下文章

在python中为打印设置命令别名?

如何在css或sass中为类名起别名

在 pipenv 项目中为 python 文件创建命令行别名

如何分别创建多个 Flutter 版本别名以在 Windows PC 的命令提示符中使用 [关闭]

如何在 C# 中为类名起别名,而不必向使用该类的每个文件添加一行代码?

在 Windows 7 中为 composer 创建一个工作别名