在Vim中重构


98

当然,对于许多人而言,可以在IDE上进行重构的事实是无价的,我在编码时几乎不会这样做,但是在编辑其他人的源代码时可能会尝试这样做。如何在Vim中的多个文件中完成如此琐碎的任务?

我找到了用于重构Ruby的插件,但是“任何”语言怎么样?


2
重构是非常特定于语言的。您需要为自己感兴趣的每种语言查找特定的加载项。大概会找到某些(而不是其他)加载项。如果您想要找到一种找不到的东西,那么如果您感到野心勃勃,则可以尝试使用现有的另一种类似语言的加载项来编写一个。
史蒂夫·乔根森

2
VIM旨在编辑单个文件,甚至可以编辑目录下的文件,而不是project。许多受IDE支持的重构都会影响整个项目中的文件(例如,重命名一个类)。我认为用(g)VI(m)这样的编辑器来实现“正确”是很难的,以至于我认为公司或大型项目都必须采用它。他们基本上必须解析每种语言,以避免进行简单的字符串替换,并容易出错(ctags提供了其中的一些错误)以及相应的项目类型(以了解要编辑的文件)。
Merlyn Morgan-Graham

1
感谢您的评论,我认为这是开始变得棘手的地方,尝试将VIM转换为IDE并不是一种仅使用一个程序来编辑多种语言的优雅解决方案。由于IDE上提供了一些“高级”功能,因此我真的不想放弃VIM。
Helmut Granda

@ MerlynMorgan-Graham-有些人只是将他们的代码保存在几个(可能很大)文件中。完全避免此问题。
Rook 2012年

7
@ldigas:可以解决此问题。但这与某些语言(例如Java)的推荐做法完全相反。从根本上来说,代码弯曲可以满足工具的需求,而实际上应该是相反的。
Merlyn Morgan-Graham

Answers:


76

我同意“ Vim不是IDE”范式。但是有时候没有IDE。在这些情况下,我将使用以下方法:

:grep,:vimgrep,:Ag,:Ggrep

重构与常规替换有更多关系,我通常在项目树上使用:grep,然后记录一个宏进行重构-:g和:s毫不费力。通常,它可以让我毫不费力地快速修改大量文件。老实说,我比其他任何人都使用这种方法。

根据您的工作流程,内置命令可能会很慢/不便。如果您使用git,那么您将要使用出色的Fugitive插件及其:Ggrep命令来仅搜索签入git的文件。我也喜欢Silver Searcher的快速性。

:argdo,:cdo和:bufdo

:cdo:argdo可以方便地在一组文件上执行vim命令。

命令行

当更难通过:vimgrep我确定需要更改的文件列表时,请使用命令行grep / find命令来更紧密地整理我需要重构的文件列表。将列表保存到文本文件并使用:e和宏录制的混搭来进行我需要进行的更改。

我发现保持宏录制技能的生锈程度越小,发现Vim重构就越有用:可以轻松地从寄存器保存/恢复,递增/递减寄存器计数器变量,清理/保存宏记录以备以后使用等。


更新资料

自从为我描述的方法编写了更多的视频广播以来,已经在vimcasts.org上发布了(我鼓励您观看所有的Vimcasts!)。要进行重构,请注意以下内容:

Vimgolf也是练习的好方法。

自从我写了这个答案以来,语言服务器协议服务器的普及还为Vim(和其他编辑器)带来了一些重构能力。IMO,它们与您在专用IDE中看到的重构功能(要使用重构功能,我确实会使用它们,并且更喜欢使用coc和ALE)相提并论。有关更多信息,请参见此问题的其他答案!


12
重构远不止是模式匹配,这就是为什么需要IDE以安全的方式自动进行重构的原因。显然,您可以手动执行此操作,但是考虑到可用的选项,并且在大多数情况下手动执行此操作更安全,为什么还要考虑其他任何选项?
Cutberto Ocampo 2015年

1
@CutbertoOcampo我在某种程度上同意您的意见:根据项目的各个方面(结构,语言,员工技能和资源,仅举几例),可能会有一个适用于您问题的出色重构工具。我的答案适用于不正确的情况,而您想解决Vim中的问题。
dsummersl

2
很好,我了解人们可能会使用他们长期使用的首选工具来做事更舒适,并且有些骇客的性能确实非常好,可能比那里的任何IDE都要好,但是对于盒解决方案我想说一个实际的IDE对于大多数用户来说会更好。我会考虑80%到20%的情况(甚至更多,其余的都支持IDE)。
Cutberto Ocampo 2015年

1
几乎每种语言都有一个想法。试图用vim或regex进行重构听起来绝对是疯狂的。你为什么还要尝试?

1
@rolls具有足够的能力,可以随心所欲地抓住随机需要的同事使用的机器,或者仅能与之共存的cfg并留下良好的印象(不是“正当印象”,而是声誉和未来地位)。
血腥

23

语言服务器协议 (LSP)

语言服务器协议包含用于在项目中智能重命名符号的功能:

https://microsoft.github.io//language-server-protocol/specifications/specification-3-14/#textDocument_rename

例如,以下语言服务器对此提供支持:

您可以在https://langserver.org/下找到更多语言服务器。

Vim

要在vim中使用它们,必须有一个vim编辑器客户端。存在以下选项:

  1. LanguageClient-neovim(需要防锈)建议映射:

    nnoremap <silent> <F2> :call LanguageClient_textDocument_rename()<CR>
    
  2. coc.nvim(需要node.js)建议映射:

    " Remap for rename current word
    nmap <leader>rn <Plug>(coc-rename)
    
  3. 啤酒

    nnoremap <silent> <Plug>(ale_rename) :ALERename<Return>
    

    Ale没有定义任何键绑定。这必须由用户完成。

  4. vim-lsp提供以下命令

    :LspRename
    

    与Ale相似,不建议任何映射。但是,您当然可以定义如下

    nmap <leader>r <plug>(lsp-rename)
    

    <leader>r将由您选择;我不知道大多数插件都同意)

  5. vim-lsc具有默认映射:

    'Rename': 'gR'
    

另请参见YouCompleteMe,它也促进LSP。

新病毒

自2000年以来,Neovim已初步支持lsp。 二○一九年十一月一十三日

有关LSP的常见配置,请参见 https://github.com/neovim/nvim-lsp

但是,我不知道智能重命名是如何工作的。如果有人知道这一点,请更新此部分。

其他重构

我不知道LSP协议是否有计划支持更复杂的重构,例如更改类结构,向方法/功能添加参数或将方法移至其他类。有关重构的列表,请参见https://refactoring.com/catalog/


不幸的是,与现有技术相比,LSP中重构的支持目前还很薄弱。github.com/Microsoft/language-server-protocol/issues/61
Mickael

重命名的AFAIK coc-rename仅适用于当前缓冲区。它没有在项目中(跨文件)全局更新导出名称的使用。
oligofren

15

蟒蛇

对于python语言,以下插件为vim提供了“智能”重命名功能:

  • jedi-vimgithub<leader>r
  • ropevimgithubCTRL-c r r
  • python-modegithub:h pymode-rope-refactoring

13

C族

  1. 尝试使用插件Clighter对C系列进行重命名重构。它基于clang,但有局限性,该插件被标记为已弃用。

    Clighter建议的映射为

     nmap <silent> <Leader>r :call clighter#Rename()<CR>
    

    注意,后继插件clighter8已删除了提交24927db42中的重命名功能。

  2. 如果您使用neovim,则可以查看插件。这表明

     nmap <silent> <Leader>r :call ClampRename()<CR>
    

5

我为通用重构编写了此插件。它仍然需要许多改进。将来的某个时候,我将尝试放弃ctags,而使用clang进行C&C ++重构。


4

也许不是最优雅的解决方案,但我发现它非常方便:我使用ECLIM连接VIM和Eclipse。当然,我所有的源代码编辑都是在VIM中完成的,但是当需要重构时,就可以利用Eclipse在此方面的出色功能。

试试看。


3

插件因子

还有一个专用于重构的vim插件叫做factorus,可以在github上找到

当前(2017年12月),它支持以下语言

  • C,
  • java和
  • 蟒蛇。

3

插件YouCompleteMe(YCM)(在GitHub上有2万颗星)

http://ycm-core.github.io/YouCompleteMe/#the-refactorrename-new-name-subcommand

:h RefactorRename-new-name

在受支持的文件类型中,此命令尝试对游标下的标识符执行语义重命名。这包括重命名标识符的声明,定义和用法,或任何其他适合于语言的操作。具体行为由使用中的语义引擎定义。

相似 FixIt,此命令将自动修改应用于源文件。重命名操作可能涉及对多个文件的更改,这些文件当时可能在Vim缓冲区中打开,也可能未打开。YouCompleteMe为您处理所有这些。该行为在以下部分中描述。

在以下文件类型中受支持:c,cpp,objc,objcpp,cuda,java,javascript,typescript,rust,cs

默认情况下,没有映射。


所以现在这仅适用于javascript,打字稿和java?
SR

2

将光标放在要重构和键入的名称上

gd (要么 gD如果您要重构全局变量)。

然后

cgn 新名字 esc

. 一次或多次重构下一次出现

要么

:%norm . 立即重构缓冲区中的所有事件。


1

我在vim中编写了很多C / C ++代码。我最常进行的重构是重命名变量,类名等。通常,我通常:bufdo :%s/source/dest/g在文件中执行搜索/替换,这与大型IDE提供的重命名几乎相同。
但是,就我而言,我发现我通常会重命名类似的实体,拼写在不同的情况下(例如CamelCase,snake_case等),因此我决定编写一个小型实用程序来帮助进行这种“智能案例”搜索/替换,它在这里托管。它是一个命令行实用程序,而不是vim的插件,希望您能发现它有用。


0

为了进行重构,如果您正在使用Unite(并且应该这样做),则可以使用vim-qfreplace并使其变得非常容易。检查此视频演示它是如何工作的。设置好工作流程后,您可以进行一些映射来对其进行优化(而不是像视频中那样键入大多数内容)。



0

我会考虑使用emacs的spacemacs版本。它使用与Vim相同的模式和大多数击键功能,但由于其简洁的特性而具有更多的附加组件。如果要使用C ++编程,则只需添加c ++层,并且大多数IDE都已为您设置好。对于其他解释语言(例如python或bash),您无需离开spacemacs即可使用它们。他们甚至可以直接在您的文本中运行代码块,这对于将代码和数据放在同一文件中的识字编程或可再现编程非常有用。两者均以文本形式完成。

Spacemacs的初始负载繁重得多,但是您可以使用它完成的其他工作仅值几秒钟的启动成本。一层组织模式值得一试。这是我用过的最好的大纲,程序员,日定时器/待办事项列表。


0

  1. 工具godoctorgithub)支持多种重构功能
  • 改名
  • 提取功能
  • 提取局部变量
  • 切换var⇔:=
  • 添加Godoc存根

有一个vim插件https://github.com/godoctor/godoctor.vim,使它们可用

将光标放在要重命名的东西中:

:Rename <newname>

突出显示要提取的块:

:Refactor extract newfunc
  1. 维哥

    • 使用精确进行类型安全的标识符重命名:GoRename
  2. 语言服务器 gopls

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.