• Stars
    star
    2,465
  • Rank 17,886 (Top 0.4 %)
  • Language
    Lua
  • License
    MIT License
  • Created almost 3 years ago
  • Updated about 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

The Refactoring library based off the Refactoring book by Martin Fowler

refactoring.nvim

The Refactoring library based off the Refactoring book by Martin Fowler
'If I use an environment that has good automated refactorings, I can trust those refactorings' - Martin Fowler

Lua Neovim Nightly Work In Progress

Table of Contents

Installation

Requirements

  • Neovim Nightly
  • Treesitter
  • Plenary

Setup Using Packer

use {
    "ThePrimeagen/refactoring.nvim",
    requires = {
        {"nvim-lua/plenary.nvim"},
        {"nvim-treesitter/nvim-treesitter"}
    }
}

Setup Using Lazy

  {
    "ThePrimeagen/refactoring.nvim",
    dependencies = {
      "nvim-lua/plenary.nvim",
      "nvim-treesitter/nvim-treesitter",
    },
    config = function()
      require("refactoring").setup()
    end,
  },

Quickstart

require('refactoring').setup()

Features

Supported Languages

Given that this is a work in progress, the languages supported for the operations listed below is constantly changing. As of now, these languages are supported (with individual support for each function may vary):

  • TypeScript
  • JavaScript
  • Lua
  • C/C++
  • Golang
  • Python
  • Java
  • PHP
  • Ruby

Refactoring Features

  • Support for various common refactoring operations
    • 106: Extract Function
      • Extracts the last highlighted code from visual mode to a separate function
      • Optionally prompts for function param types and return types (see configuration for type prompt operations)
      • Also possible to Extract Block.
      • Both Extract Function and Extract Block have the capability to extract to a separate file.
    • 115: Inline Function
      • Inverse of extract function
      • In normal mode, inline occurrences of the function under the cursor
      • The function under the cursor has to be the declaration of the function
    • 119: Extract Variable
      • In visual mode, extracts occurrences of a selected expression to its own variable, replacing occurrences of that expression with the variable
    • 123: Inline Variable
      • Inverse of extract variable
      • Replaces all occurrences of a variable with its value
      • Can be used in normal mode or visual mode
        • Using this function in normal mode will automatically find the variable under the cursor and inline it
        • Using this function in visual mode will find the variable(s) in the visual selection.
          • If there is more than one variable in the selection, the plugin will prompt for which variable to inline,
          • If there is only one variable in the visual selection, it will automatically inline that variable

Debug Features

  • Also comes with various useful features for debugging
    • Printf: Automated insertion of print statement to mark the calling of a function
    • Print var: Automated insertion of print statement to print a variable at a given point in the code. This map can be made with either visual or normal mode:
      • Using this function in visual mode will print out whatever is in the visual selection.
      • Using this function in normal mode will print out the identifier under the cursor
    • Cleanup: Automated cleanup of all print statements generated by the plugin

Configuration

There are many ways to configure this plugin. Below are some example configurations.

Setup Function

No matter which configuration option you use, you must first call the setup function.

require('refactoring').setup({})

Here are all the available options for the setup function and their defaults:

require('refactoring').setup({
    prompt_func_return_type = {
        go = false,
        java = false,

        cpp = false,
        c = false,
        h = false,
        hpp = false,
        cxx = false,
    },
    prompt_func_param_type = {
        go = false,
        java = false,

        cpp = false,
        c = false,
        h = false,
        hpp = false,
        cxx = false,
    },
    printf_statements = {},
    print_var_statements = {},
})

See each of the sections below for details on each configuration option.

Configuration for Refactoring Operations

Ex Commands

The plugin offers the :Refactor command as an alternative to the Lua API.

The first argument to the command selects the type of refactor to perform. Additional arguments will be passed to each refactor if needed (e.g. the name of the extracted function for extract).

The first argument can be tab completed, so there is no need to memorize them all. (e.g. :Refactor e<tab> will suggest extract_block_to_file, extract, extract_block, extract_var and extract_to_file).

The main advantage of using an Ex command instead of the Lua API is that you will be able to preview the changes made by the refactor before committing to them.

command_showcase.mp4

The command can also be used in mappings:

vim.keymap.set("x", "<leader>re", ":Refactor extract ")
vim.keymap.set("x", "<leader>rf", ":Refactor extract_to_file ")

vim.keymap.set("x", "<leader>rv", ":Refactor extract_var ")

vim.keymap.set({ "n", "x" }, "<leader>ri", ":Refactor inline_var")

vim.keymap.set( "n", "<leader>rI", ":Refactor inline_func")

vim.keymap.set("n", "<leader>rb", ":Refactor extract_block")
vim.keymap.set("n", "<leader>rbf", ":Refactor extract_block_to_file")

The (space) at the end of some mappings is intentional because those mappings expect an additional argument (all of these mappings leave the user in command mode to utilize the preview command feature).

Lua API

If you want to make remaps for a specific refactoring operation, you can do so by configuring the plugin like this:

vim.keymap.set("x", "<leader>re", function() require('refactoring').refactor('Extract Function') end)
vim.keymap.set("x", "<leader>rf", function() require('refactoring').refactor('Extract Function To File') end)
-- Extract function supports only visual mode
vim.keymap.set("x", "<leader>rv", function() require('refactoring').refactor('Extract Variable') end)
-- Extract variable supports only visual mode
vim.keymap.set("n", "<leader>rI", function() require('refactoring').refactor('Inline Function') end)
-- Inline func supports only normal
vim.keymap.set({ "n", "x" }, "<leader>ri", function() require('refactoring').refactor('Inline Variable') end)
-- Inline var supports both normal and visual mode

vim.keymap.set("n", "<leader>rb", function() require('refactoring').refactor('Extract Block') end)
vim.keymap.set("n", "<leader>rbf", function() require('refactoring').refactor('Extract Block To File') end)
-- Extract block supports only normal mode

Using Built-In Neovim Selection

You can also set up the plugin to prompt for a refactoring operation to apply using Neovim's built in selection API. Here is an example remap to demonstrate this functionality:

-- prompt for a refactor to apply when the remap is triggered
vim.keymap.set(
    {"n", "x"},
    "<leader>rr",
    function() require('refactoring').select_refactor() end
)
-- Note that not all refactor support both normal and visual mode

Using Telescope

If you would prefer to use Telescope to choose a refactor, you can do so using the Telescope extension. Here is an example config for this setup:

-- load refactoring Telescope extension
require("telescope").load_extension("refactoring")

vim.keymap.set(
	{"n", "x"},
	"<leader>rr",
	function() require('telescope').extensions.refactoring.refactors() end
)

Configuration for Debug Operations

Finally, you can configure remaps for the debug operations of this plugin like this:

-- You can also use below = true here to to change the position of the printf
-- statement (or set two remaps for either one). This remap must be made in normal mode.
vim.keymap.set(
	"n",
	"<leader>rp",
	function() require('refactoring').debug.printf({below = false}) end
)

-- Print var

vim.keymap.set({"x", "n"}, "<leader>rv", function() require('refactoring').debug.print_var() end)
-- Supports both visual and normal mode

vim.keymap.set("n", "<leader>rc", function() require('refactoring').debug.cleanup({}) end)
-- Supports only normal mode

Customizing Printf and Print Var Statements

It is possible to override the statements used in the printf and print var functionalities.

Customizing Printf Statements

You can add to the printf statements for any language by adding something like the below to your configuration:

require('refactoring').setup({
  -- overriding printf statement for cpp
  printf_statements = {
      -- add a custom printf statement for cpp
      cpp = {
          'std::cout << "%s" << std::endl;'
      }
  }
})

In any custom printf statement, it is possible to optionally add a max of one %s pattern, which is where the debug path will go. For an example custom printf statement, go to this folder, select your language, and click on multiple-statements/printf.config.

Customizing Print Var Statements

The print var functionality can also be extended for any given language, as shown below:

require('refactoring').setup({
  -- overriding printf statement for cpp
  print_var_statements = {
      -- add a custom print var statement for cpp
      cpp = {
          'printf("a custom statement %%s %s", %s)'
      }
  }
})

In any custom print var statement, it is possible to optionally add a max of two %s patterns, which is where the debug path and the actual variable reference will go, respectively. To add a literal "%s" to the string, escape the sequence like this: %%s. For an example custom print var statement, go to this folder, select your language, and view multiple-statements/print_var.config.

Note: for either of these functions, if you have multiple custom statements, the plugin will prompt for which one should be inserted. If you just have one custom statement in your config, it will override the default automatically.

Customizing Extract variable Statements

When performing an extract_var refactor operation, you can custom how the new variable would be declared by setting configuration like the below example.

require('refactoring').setup({
  -- overriding extract statement for go
  extract_var_statements = {
    go = "%s := %s // poggers"
  }
})

Configuration for Type Prompt Operations

For certain languages like Golang, types are required for functions that return an object(s) and parameters of functions. Unfortunately, for some parameters and functions there is no way to automatically find their type. In those instances, we want to provide a way to input a type instead of inserting a placeholder value.

By default all prompts are turned off. The configuration below shows how to enable prompts for all the languages currently supported.

require('refactoring').setup({
    -- prompt for return type
    prompt_func_return_type = {
        go = true,
        cpp = true,
        c = true,
        java = true,
    },
    -- prompt for function parameters
    prompt_func_param_type = {
        go = true,
        cpp = true,
        c = true,
        java = true,
    },
})

More Repositories

1

harpoon

Lua
5,055
star
2

init.lua

Lua
2,727
star
3

vim-be-good

vim-be-good is a nvim plugin designed to make you better at Vim Movements.
Lua
2,692
star
4

.dotfiles

Perl
2,611
star
5

kata-machine

TypeScript
1,041
star
6

git-worktree.nvim

Lua
613
star
7

ts-rust-zig-deez

Java
520
star
8

htmx-lsp

its so over
Rust
454
star
9

tyrone-biggums

Clearly a repo about websockets and their comparison...
ReScript
450
star
10

anime

The repo that everyone deserves
448
star
11

vim-royale

Because Nano sucks
Rust
406
star
12

vim-apm

Vim APM, Actions per minute, is the greatest plugin since vim-slicedbread
Lua
282
star
13

neovimrc

Lua
261
star
14

CHADstack

Dockerfile
252
star
15

keyboards

239
star
16

fem-algos

FrontEnd Master algorithms!
JavaScript
237
star
17

undefined

A project to turn a file of JSON responses into TypeScript types
TypeScript
231
star
18

rust-for-typescript-devs

JavaScript
207
star
19

ansible

Dockerfile
203
star
20

primestack

Rust
135
star
21

ThePrimeagen

109
star
22

vmrss

Shell
83
star
23

web3-smart-contracts

JavaScript
82
star
24

BunSpreader

We spread the buns
Zig
74
star
25

vim-with-me

Rust
73
star
26

fem-algos-2

The Last Algorithm Class You Want
JavaScript
68
star
27

jvim.nvim

A simple json traverser for NeoVim
Lua
67
star
28

aoc

2020
Rust
63
star
29

vimrc

62
star
30

yew-have-ligma

Elixir
61
star
31

htmx_golang

Go
57
star
32

orgwasm

CSS
55
star
33

2-simple-steps

Its literally that simple
TypeScript
54
star
34

fem-htmx-proj

Go
47
star
35

coin-toss-me-daddy

Rust
44
star
36

js-perf-example

TypeScript
40
star
37

vim-nav-playground

C
39
star
38

htmx-class-template

The starter template with server in go or rust
Rust
39
star
39

lsp-debug-tools.nvim

this probably isn't the droid you are looking for
OCaml
35
star
40

neural-js

A kick-ass neural network for javascript
JavaScript
34
star
41

leftPadDeez

nuts
JavaScript
34
star
42

yt

All my yt videos that require to have some codes.
TypeScript
32
star
43

rusty-arduino

Rust
31
star
44

titty-sprinkles

Yes... This is the name for my NodeConfEU project
TypeScript
30
star
45

htmx-subscribe

HTML
28
star
46

htmx

Rust
27
star
47

public-edging

Rust
26
star
48

jpegdegens

TypeScript
26
star
49

beat-me-daddy

I put my sonic in my pi
Rust
26
star
50

ts-go-rust

JavaScript
26
star
51

go-vs-rust

The greatest cli comparison ever created
Elixir
26
star
52

uhh

When you keep forgetting those sweet sweet sweet sweet commands.
Go
25
star
53

best-of-stackoverflow

A DRAMATIC READING OF STACK OVERFLOW
23
star
54

objects-to-buffer

TypeScript
23
star
55

bun-vs-node

TypeScript
22
star
56

fem-htmx

JavaScript
22
star
57

rust-wasm-serverless

Rust
21
star
58

json-vs-proto

TypeScript
20
star
59

no-flap-november

the greatest
Go
19
star
60

gspot

Rust
18
star
61

fem-jsperf

JavaScript
18
star
62

ts-go-rust-projector

TypeScript
17
star
63

ocaml-aoc

OCaml
16
star
64

i-fixed

16
star
65

shooter-js

TypeScript
15
star
66

vim-deathmatch

Rust
15
star
67

milo

TypeScript
15
star
68

zig-deez-structures

Zig
14
star
69

big-chungus

is amungus
TypeScript
13
star
70

this-isnt-rust

There is no rust in this suppository
TypeScript
13
star
71

your-first-plugin

Example NeoVim Lua Plugin
Lua
12
star
72

tree-navigation

Lua
12
star
73

more-htmx-eploration

Rust
12
star
74

javascwipt-performance

suck it piq
TypeScript
12
star
75

why-are-promises-slow

they are
11
star
76

real-prog-dvorak-zmk

Rust
11
star
77

tier-list

HTML
11
star
78

projector

Project my config into your prebuild
Go
10
star
79

dev

my next gen build for starting my system
Shell
10
star
80

cargo-chadr

Rust
10
star
81

test-these-besties

Go
10
star
82

chat-js

Rust
9
star
83

he-uses-tabs

Rust
8
star
84

neovim-irc

C
8
star
85

git-bisect

JavaScript
8
star
86

rxjs-examples

JavaScript
7
star
87

jest-mem-test

JavaScript
7
star
88

todo

yes
C++
6
star
89

first-deno-project

JavaScript
6
star
90

fizzbuzz

A real programmers fizzbuzz
JavaScript
6
star
91

ansible-dev-prod

Dockerfile
6
star
92

99-ocaml-problems

6
star
93

neovim-irc-ui

Lua
5
star
94

first-nvim-plugin

The template for writing your first nvim plugin
5
star
95

the-hoff

9000
TypeScript
5
star
96

mini-wasm-env

When full wasms just wont due
C
4
star
97

crypto-legends

Like Apex Legends. Just more, better, faster, and less recoil
Go
4
star
98

keyboard

Simple keyboard
JavaScript
4
star
99

fem-vim

Vim Script
4
star
100

flatbuffers-benchmarks

The hello server that will take in either flatbuffs or json and add one to the `count` field, then resend the data back through the socket connection.
JavaScript
4
star