I was catching up to stuff I have RSS Feeds for. One of them is NeoVim Subreddit Posts (I like learning something new from them or learning that new plugin exist etc).
I noticed this post in particular:
- Vim motions vs Regular IDE - Reddit Post
- Vim motions vs Regular IDE - Reddit Post - Web Archive Link
- Vim motions vs Regular IDE - Old Reddit Post - Web Archive Link
Linking this video:
- Vim vs IDE - YouTube Video
- Vim vs IDE - YouTube Video - Web Archive Link
- Vim vs IDE - YouTube Video - PreserveTube Link
Where I definitively agree with one comment, specifically this one Link.
@realtimberstalker
You are using none of the features of either.
In VIM theres probably some kind of match thing you can do, and VS has a select next occurrence shortcut.
So I wondered at the time of watching it and at the time of seeing this comment what are ways you could do it really. And how video like this if it really would want to be really useful would look like.
For context let's ignore AI comment in original video.
Ok Let's see all the ways.
Code Example from the video
function calculateTotal(price, rate) {
rate = rate == null ?
0.16 :
rate;
let taxes = price * rate;
return price + taxes;
}
Tasks:
- Rename rate variable to taxRate
- Introduce defaultTaxes(taxRate) function that is extraction of rate logic
Let's ignore for the purpose of argument that I feel like there are few specific problems with this code like:
- Why is there ternary instead of null coalescing operator (What I mean exactly is why its not just
rate = rate ?? 0.16instead) - let keyword that is picked by linters like deno-lint because it could be const instead
- fact that you could collapse 2 bottom lines of a function to something like
return price * (1 + rate)
Legend for solutions
Solutions will be written like this:
Solution for task 1
Solution for task 2
tasks will be separated by new line (so I can wrap text so it will be better displayed in browser like Lagrange).
Special things as "syntax" in solutions
<XXX>is some keyboard key for example<Escape>is Escape key<- XXX ->is some specific action for example<- Select first option in the menu ->
Idea of this "syntax" is that they show keyboard inputs required to achieve task. They will be grouped by motion.
Vim Side (Vim Mode Things)
Solution 1: Basic Editing
This solution is basically what was done in the video. This solution would probably work in any vim mode thing.
f, w cetaxRate<Escape> j 0 w cetaxRate<Escape> w w cetaxRate<Escape> j j _ cetaxRate<Escape>
2G f= w v j j t; d idefaultTaxRate(taxRate)<Escape> j j j
ofunction<Space>defaultTaxRate(taxRate)<Space>{<Enter><Enter>}<Escape>
k p == Ireturn A;
Solution 2: Search and Replace
This solution only optimizes first task. Optimization of second task is not really achievable until we introduce more things (at least I think so).
This solution would probably work in any vim mode thing too.
v$ h :s/rate/taxRate/g<Enter>
<- Same as previous solution ->
This solution is much faster but it will change all "rate" in this function so it can be not good in few cases.
Solution 3a: NeoVim + LSP
This solution needs strictly NeoVim with LSP setup.
f, w grn <Backspace><Backspace><Backspace><Backspace>taxRate<Enter>
j 0 f= l v j j t; gra
<- Select option called "Extract to function in global scope" -><Enter>
<- <Backspace> current name ->defaultTaxRate<Enter>
This solution uses LSP rename action functionality that will change name of variable. It's bound by default to grn (Noted in :help lsp-defaults).
Solution 3b: Vim Mode in Visual Studio Code
This solution uses vscodevim.vim extension for vim mode in Visual Studio Code.
(I specifically tested in VS Codium)
This solution can do both tasks better so here will be 2 lines.
f, w <F2> <Backspace>taxRate<Enter>
j 0 f= l v j j t; <C-S-r>
<- Select option called "Extract to function in global scope" -><Enter>
defaultTaxRate<Enter>
Bonus Solution 3c: Helix
This is not Vim mode though its close enough and still interesting.
f, l l <Space>r <Backspace><Backspace><Backspace><Backspace>taxRate<Enter>
j F= F= F= l v11w <space>a
<- Extract to function in global scope -> <- move cursor to function name ->
<space>r <- <Backspace> current name ->defaultTaxRate
Solution 4: NeoVim with Plugins
You could optimize things using plugins and some configuration.
Firstly if you prefer F2 instead of grn you can just add this to your neovim config:
vim.keymap.set(
"n",
"<F2>",
"<cmd>lua vim.lsp.buf.rename()<cr>",
{ desc = "Rename through LSP" }
)
Using LSP first task is easy enough. Second task is worse, let's explore ways for optimization here.
First option, which I didn't test is this plugin: ThePrimeagen/refactoring.nvim.
This plugin has extract method function so it could work.
Second option, more universal is this plugin: MeanderingProgrammer/treesitter-modules.nvim or nvim-treesitter master branch.
Treesitter had module called incremental selection. Currently it doesn't have it in main branch. So treesitter-modules.nvim is plugin that adds it back. This could help us select all of value that we want to extract into the new function. It doesn't automatically extract it we have to do that ourselves but we can optimize selecting thing we want to extract into function using this.
Config (using vim.pack as plugin manager that is currently in nightly and on the way in NeoVim 0.12):
vim.pack.add({
{
src = "https://github.com/MeanderingProgrammer/treesitter-modules.nvim",
name = "treesitter-modules.nvim",
},
})
so our selection would be just using default keybind of gni few times until we have value of this var = value; expression selected we can delete it and paste into new function.
IDE Side
VS Code without Vim Mode
This solution is literally same as Vim mode one we just use mouse instead. But still F2 to rename and Ctrl+Shift+R to access refactor menu.
IntelliJ IDEA
Same as VSCode one though with this keybinds instead: rename - Shift-F6, extract function - Ctrl+Alt+M (this is directly instead of using refactor menu)
Conclusion for me
This whole thing for me shows that both VIM way and IDE way can be quite fast. In my opinion I prefer Vim way now just because I started using it and I'm not planning to stop using it. I love NeoVim and what you can do in it. And for me trying to look more objectively is just preference in most part. Though I definitively feel like Vim motions are quite good to learn and have in toolbox because they are more universal. You can use Vim motions in a lot of programs. Where you technically can use same keybinds everywhere in IDE but its more pain to set up or even impossible sometimes because program you want to adapt to "your way" don't have keybind settings good enough for that. And your way of keybinds is pain to port to new IDE or Editor or anything. Where Vim motions give you enough basics that would always be same that you don't need rebinding and even if you need rebinding Vim modes in few programs are good enough to let you just use :map functions and something like vimrc which will have similar syntax to your Vim configuration (if you have it in Vim script if not its easy enough to port things you need to it). But that's just my perspective.