Skip to main content

Refactoring Using Neovim

·2 mins

This post is about how you can use Neovim to have refactoring tooling inspired in Refactoring and your tooling from Learn Go with tests.

Extract/Inline #

I am using refactoring.nvim plugin.

Extract Variable #

vim.keymap.set("x", "<leader>rv", function() require('refactoring').refactor('Extract Variable') end)

You need to select the part of your code that you want to extract to a variable and then press <leader>rv.

More about extract variable: https://refactoring.guru/extract-variable

Inline Variable #

vim.keymap.set({ "n", "x" }, "<leader>ri", function() require('refactoring').refactor('Inline Variable') end)

It’s the inverse of extract variable. It will remove the variable and replace it with its value.

Extract Method #

vim.keymap.set("x", "<leader>re", function() require('refactoring').refactor('Extract Function') end)

Rename #

Here my goal is to rename symbols accross the codebase. It is possible to achieve this using Language Server Protocol as demonstrated by mjlbach in this issue comment if the LSP support it.

I am using lsp-zero with default keymaps. To rename I need to use the F2 key. For go using go using gopls it is working to rename accross the codebase.

local lsp = require("lsp-zero")

lsp.on_attach(function(client, bufnr) lsp.default_keymaps({buffer = bufnr}) end)

Run Format and Goimports on Save #

Using lsp-zero #

-- Run gofmt/gofmpt, import packages automatically on save
vim.api.nvim_create_autocmd('BufWritePre', {
  group = vim.api.nvim_create_augroup('setGoFormatting', { clear = true }),
  pattern = '*.go',
  callback = function()
    local params = vim.lsp.util.make_range_params()
    params.context = { only = { "source.organizeImports" } }
    local result = vim.lsp.buf_request_sync(0, "textDocument/codeAction", params, 2000)
    for _, res in pairs(result or {}) do
      for _, r in pairs(res.result or {}) do
        if r.edit then
          vim.lsp.util.apply_workspace_edit(r.edit, "utf-16")
        else
          vim.lsp.buf.execute_command(r.command)
        end
      end
    end

    vim.lsp.buf.format()
  end
})

Testing #

I am using vim-test plugin to run tests.

vim.cmd([[
let g:test#echo_command = 0

let test#python#runner = 'pytest'

if exists('$TMUX')
  let g:test#preserve_screen = 1
  let g:test#strategy = 'vimux'
endif

nmap <silent> <leader>t :TestNearest<CR>
nmap <silent> <leader>T :TestFile<CR>
nmap <silent> <leader>a :TestSuite<CR>
nmap <silent> <leader>l :TestLast<CR>
nmap <silent> <leader>g :TestVisit<CR>
]])

View Function Signature #

I am using LSP for that, when I am in a function I can press K to see the function signature and when I am writing a function I can see the signature of the function I am calling.

View Function Definition #

I am using LSP for that, when I am in a function I can press gd to go to the definition of the function. I can use Ctrl-o to go back.

Find Usage of a Symbol #

I am using LSP for that, when I am in a symbol I can press gr to see the usages of the symbol.