Vim 中的重构

当然,您可以在 IDE 上进行重构对许多人来说是无价的,我在编写代码时很少这样做,但是我可能会在编辑其他人的源代码时尝试这样做。如何在 Vim 中跨多个文件完成这样一个微不足道的任务?

I found 这个插件 for refactoring Ruby, but how about "any" language?

73792 次浏览

我同意“ Vim 不是 IDE”的范例。但有时候并没有 IDE。下面是我在这种情况下使用的方法:

免责声明 : 自从我写这篇文章以来,Language Server Protocol 服务器、 linters 和 fixers 的无处不在也为 Vim (和其他编辑器)带来了一些伟大的重构能力。在我看来,它们与专门构建的 IDE 的功能相比还有很长的路要走(对于这些特性,我更喜欢 ALENvim-lspconfig)。有关更多信息,请参见此问题的其他答案!

:grep, :vimgrep, :GrepperAg, :Ggrep

重构与常规替换有更多的关系,我通常在项目树上使用 :grep,然后使用 记录一个宏来执行重构-: g 和: s。通常它会让我快速修改大量的文件,很少的努力。说实话,我用这种方法比其他任何方法都多。

根据您的工作流程,内置命令可能会很慢/不方便。如果您使用 git,那么您将希望使用优秀的 Fugitive插件及其 :Ggrep命令来只搜索签入 git 的文件。我也喜欢 Vim-Grepper,因为它不依赖于搜索工具(支持 ag、 filter、 ripgrep 等) ,而且速度很快。

: argdo,: cdo,and: bufdo

Cdo 校对: argdo可以方便地对一组文件执行 vim 命令。

命令行

当通过 :vimgrep难以确定需要更改的文件列表时,我使用命令行 grep/find 命令来更好地管理需要重构的文件列表。将列表保存到一个文本文件中,并使用 :e和宏录制的 mashup 来进行我需要进行的更改。

I find that the less rusty I keep my macro recording skills the more useful I find Vim for refactoring: feeling comfortable saving/restoring from registers, incrementing/decrementing register counter variables, cleaning/saving macro recordings to file for later use, etc.


Update

自从为我所描述的方法写了这篇文章以来,更多的视频已经发表在 vimcasts.org 上(我鼓励你观看 所有的 Vimcast!)。关于重构,请注意以下几点:

维姆高尔夫也是一种很好的练习方式。

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

Maybe not the most elegant solution, but I found it very handy: I use ECLIM to connect VIM and Eclipse. Of course all my source code editing is done in VIM, but when it's time to refactor, one can take advantage of Eclipse's superior cababilities in this matter.

试试看。

我用 vim 编写了很多 C/C + + 代码。最常见的重构是重命名变量、类名等。通常,我使用 :bufdo :%s/source/dest/g在文件中进行搜索/替换,这几乎与大 IDE 提供的重命名相同。
然而,在我的案例中,我发现我通常重命名相似的实体,在不同的情况下拼写(如 CamelCase,Snake _ case,等) ,所以我决定编写一个小实用程序来帮助这种“智能案例”搜索/替换,它是托管 给你。它是一个命令行实用程序,而不是一个用于 vim 的插件,我希望你能发现它的用处。

C-Family

  1. 尝试使用插件 更亮为 c-family 进行重命名重构。它基于 clang,但是有一些限制,并且插件被标记为已弃用。

    通过 再亮一点建议的映射如下

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

    Note, the successor plugin 克拉特 has removed the renaming functionality in the 提交24927db42.

  2. 如果你使用 neovim,你可以看看插件 夹子

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

对于重构,如果您正在使用 团结起来(您应该这样做) ,那么您可以使用 Vim-qfreplace并使其变得非常简单。检查这个演示它如何工作的 video。设置好工作流之后,您可以制作一些映射来优化它(而不是像视频中那样键入大多数内容)。

巨蟒

For the 巨蟒 language following plugins provide 'smart' renaming capabilities for vim:

  • jedi-vim (Github) <leader>r
  • ropevim(Github) CTRL-c r r
  • python-mode(Github) :h pymode-rope-refactoring

两个插件的组合: [ em > vim-ripgrep ],查找跨文件并将结果放在快速修复窗口中,和 快速修复反射器,在快速修复窗口中保存更改,并让它自动保存跨文件的每个更改。

插件 因素

还有另一个专门用于重构的 vim 插件,称为 因子,可在 Github上获得。

目前(2017-12) ,它支持语言

  • C,
  • java, and
  • 巨蟒。

语言服务器协议 (LSP)

The Language server protocol contains the feature for smart renaming of symbols across a project:

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。

Neovim

Neovim 从 2019年11月13日开始就内置了对 lsp 的支持

请参阅 LSP 的常见配置项目 Nvim-lspconfig,它建议将 <space>rn作为 vim.lsp.buf.rename()的映射。

其他重构

我不知道 LSP 协议是否有计划支持更复杂的重构,比如改变类结构、为方法/函数添加参数或者将方法移动到不同的类。有关重构的列表,请参见 https://refactoring.com/catalog/

插件 < em > YouCompleteMe (YCM)(github 上的2万颗星)

Http://ycm-core.github.io/youcompleteme/#the-refactorrename-new-name-subcommand

:h RefactorRename-new-name

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

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

支持文件类型: c,cpp,objecc,objeccpp,cuda,java,javascript, 打字稿,生锈,

默认情况下没有映射。

I would consider using the spacemacs version of emacs. It is uses the same modes and most keystrokes as Vim but has many more add-on because of it's lisp nature. If you want to program in C++ you just add the c++ layer and most of the IDE is just set up for you already. For other interpreted languages like python or bash you do not need to leave spacemacs to use them. They even have a way to run blocks of code directly within your text which works fantastic for literate programming or reproducible programming where the code and the data are in the same file. Both done as text.

Spacemacs 的初始负载要重得多,但你可以用它做的额外事情值得几秒钟的启动成本。一层组织模式值得一试。它是最好的轮廓线,程序员,日计时器/待办事项列表,我曾经使用过。

将光标置于名称处以重构和键入

gd(如果要重构全局变量,则为 gD)。

然后

New _ name esc

还有

.一次或多次重构下一次发生的事件

或者

:%norm .一次重构缓冲区中的所有匹配项。

去吧

  1. 工具 好样的,医生(Github)支持多种重构功能
  • 重命名
  • 提取功能
  • Extract Local Variable
  • Toggle var something: =
  • Add Godoc stubs

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

用游标重命名:

:Rename <newname>

Highlighting block to extract:

:Refactor extract newfunc
  1. Vim-Go

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

CoC 插件具有(在其他特性中)重命名变量的能力。

Https://github.com/neoclide/coc.nvim

" Symbol renaming.
nmap <leader>rn <Plug>(coc-rename)