I am back to Neovim 😋 Home sweet home 🏠 Neovim is simply beautiful! My setup is mainly for R and Julia and it might help you with migrating to Neovim.
Neovim 0.5 is really exciting, with its native LSP, treesitter and Lua API.
I just spent about one month relentlessly setting up and hacking my Neovim so I can use it as soon as possible. Pretty much setup most things the way I wanted. Now I try to feature-freeze, refactor, cleanup and pay off technical debts. Feel free to use it.
Summary of setups
- Neovim's built-in terminal emulator to replace my Tmux
- For session management, I use abduco. Attach/detach Neovim sessions and/or specific process
- Theme minimalist.nvim
- Vim-like keybindings for plot (not related to Neovim)
- LSP
- Completion nvim-cmp
- Symbol, definition, references, code action, etc lspsaga
- Symbols outline symbols-outline
- Signature lsp_signature
- Diagnostics trouble.nvim
- Terminal
- Terminal buffer management neoterm
- CLI and Neovim integration (e.g. open file from terminal in neovim) with nvr and neomux
open my_file
ff
: callff
command in CLI and use telescope.nvim to preview and open file in Neovim- Send command or copy registers from CLI to Neovim, or vice verse
- Use nvim as git editor for commit/rebase/etc
- Floating terminal window management toggleterm
- REPL
- I customize my own REPL for sending to terminal and highlighting the codes sent e.g.
- Send word under cursor
- Send
str
,names
and help?
for word under the cursor - Send line/paragraph/selection/motion
- Send language-specific (R and Julia) blocks/code-blocks (e.g. R's function/for loop, Julia's function/struct/for loop)
- Send chain (e.g. R's chain
%>%
) - Send partial chain. I stole the idea from MilesMcBain/breakerofchains.
- R REPL auto-suggestion
- fzf-like history search for R REPL. For Julia, use JLFzf.jl.
- I customize my own REPL for sending to terminal and highlighting the codes sent e.g.
- RMarkdown
- Go to prev/next chunk and highlight chunk
- Send chunk to REPL and highlight chunk
- Chunk object (e.g. change/delete/select) chunk with
if
,af
, etc
- Git
- fzf-like find/filter/preview telescope.nvim
- Search & replace panel nvim-spectre
- orgmode-like note-taking apps neorg
- Motion (This is real good!) lightspeed
- Autopairs auto-pairs
Other R-related setup
- R REPL terminal output {colorout}
- Custom {skimr} summary stats
- Use R help system with Vimium
- {theme} for R packages: {ggplot2}, {plotly}, {shiny}, {rmarkdown}, {ggdist}, {ggdag}, etc
My <escape>
for both text and terminal buffers is capslock, which is mapped to <f10>
in Neovim and remapped by OS-level tools AutoHotKey. So whenever you see <f10>
, it's <escape>
. And whenever you see comment AHKREMAP
, which stands for AutoHotKey remap, it means the keybind is remapped using OS-level tools because some keybinds are not recognized by Neovim/terminal.
code
git clone [email protected]:kar9222/nvim.git
make init
# install and configure other tools (e.g. rg, fd)...
NOTE You can
- Filter symbols by class (e.g. function, variable) with
<c-l>
and - Query as usual
I customize my own REPL for sending to terminal and highlighting the codes sent e.g.
- Send word under cursor
- Send
str
,names
and help?
for word under the cursor - Send line/paragraph/selection/motion
- Send language-specific (R and Julia) blocks/code-blocks (e.g. R's function/for loop, Julia's function/struct/for loop)
- Send chain (e.g. R's chain
%>%
) - Send partial chain. I stole the idea from MilesMcBain/breakerofchains.
- fzf-like history search for R REPL. For Julia, use JLFzf.jl.
- Go to prev/next chunk and highlight chunk
- Send chunk to REPL and highlight chunk
- Chunk object (e.g. change/delete/select) chunk with
if
,af
, etc
Start typing, suggestions will automatically shown inline, press keybind (e.g. <m-l>
) to complete the sentence, or continue typing to trigger other suggestions, or simply ignore it.
Interactive R history search with Neovim's floating window. Great for single-line history search and can be used together with native {radian} REPL's ctrl+r
multi-line history search.
Details
Call bash script send_r_history
and Neovim's floating window search_history
defined in toggle_float.lua with either
- radian REPL keybind mapped to Python (radian is written in Python):
import os ; os.system('nvr --nostart -c "lua search_history(\\"send_r_history\\", _hist_opts)"')
- or Neovim's terminal mode keybind e.g.
vim.api.nvim_set_keymap('t', ..., '<cmd>lua search_history("send_r_history", _hist_opts)<CR>', ...)
I use radian REPL keybind, so that it's process-specific and doesn't clash with other keybinds. For Neovim's keybind, to make it process-specific or terminal-specific, you have to identify the process stored in terminal buffer's variable vim.b.term_title
, for example, in Lua:
if string.match(vim.b.term_title, 'radian') then vim.api.nvim_set_keymap(...) end
Bash script send_r_history
#! /bin/bash
# R history: Remove duplicates, commented lines, blank lines, starting `+` symbol
# NOTE Edit the path ~/.radian_history (default) if necessary
tac ~/.radian_history | \
awk '!a[$0]++' | \
sed -e '/^#/d ; /^$/d ; s/^+//g' | \
fzf --exact --no-sort
I use multiple terminals on the right windows, with named terminal buffers on the statusline (R, Julia and shell). Use neoterm to manage it, bind Tprev
and Tnext
for navigating between multiple terminals.
abduco session management
abduco
#! /bin/bash
# Usage:
# NOTE `:qa` exits nvim and hence it kills the session. Hence only use it if the intention is to kill the session. To quit without killing the session, for example
# - detach session
# - close the terminal window.
# unset NVIM_LISTEN_ADDRESS # TODO Need this for SSH?
session=`basename $PWD`
# If the session isn't exist, force creation of session when there is an already terminated session of the same name, after showing its exit status.
# And attach to the session.
# Detach key is <c-/>
abduco -e ^_ -fA $session nvim
CLI is still the best when it matters. You can call Neovim from CLI, for example,
open my_file
ff
: callff
command in CLI and use telescope.nvim to preview and open file in Neovimge
: simiar asff
, but for live grep
See both telescope.lua and below for details. Once you get the hang of it, you can use similar logic for any other CLI-Neovim integration. Please share them with me! 😄
Details: General CLI-Neovim integration and to call Neovim functions from CLI
if [ -n "$NVIM_LISTEN_ADDRESS" ]; then
alias nvim=nvr -cc split --remote-wait +'set bufhidden=wipe'
fi
# For example, file explorer on the left is the first window.
# To open file in the middle window, it's the second window. Adjust as needed.
export MIDDLE_WIN_NR=2
export EDITOR="nvr -cc '${MIDDLE_WIN_NR}wincmd w' --remote-wait +'set bufhidden=wipe'"
export VISUAL="nvr -cc '${MIDDLE_WIN_NR}wincmd w' --remote-wait +'set bufhidden=wipe'"
open() { # Open neovim middle window
out=$1
if [[ $out != "" ]]; then
vw $MIDDLE_WIN_NR $out
fi
}
copen() { # Create and open file
mkdir -p $(dirname $1)
touch $1
open $1
}
# Save directory for telescope's find_files_custom_dir and find_files_live_grep
save_dir() { echo $PWD | vc 'z' } # Save directory in register `z`
ff() { # Find files in custom directory
save_dir
nvr -c 'lua find_files_custom_dir()'
nvr -c 'startinsert'
}
aff() { # Find files (inc. hidden) in custom directory
save_dir
nvr -c 'lua find_files_hidden_custom_dir()'
nvr -c 'startinsert'
}
iff() { # Find files (inc. hidden & ignored) in custom directory
save_dir
nvr -c 'lua find_files_hidden_ignore_custom_dir()'
nvr -c 'startinsert'
}
ge() { # Live grep
save_dir
nvr -c 'lua live_grep_custom_dir()'
nvr -c 'startinsert'
}
Syntax-highlighting pager delta
Use delta in terminal buffer in floating window. See telescope.lua and delta.lua for details.
<leader>gb
preview diff for current file<leader>gd
preview diffq
quit<c-s>
stage current buffer<c-u>
unstage current buffer<c-s-s>
stage unstage<c-u-u>
unstage stage- It's pager (default to
less
), hence all theless
navigation commands work:d
,u
,f
,b
,g
,G
, search/
?
,n
,N
, etc
Terminal UI lazygit with delta integration
Magit clone for Neovim neogit
Git decorations gitsigns
For plot, I use httpgd
- Focus/minimize plot
- Toggle position at top right window (re-position right terminals to bottom)
- Increase/decrease window size
- Move plot window left/right/up/down
Plot
#ifWinActive ahk_group plot ; TODO Clashes key with vscode.ahk
plot__toggle_activate_minimized:
^!p::
winGet, state, minMax, R Plot
if (state == -1) ; Minimized
winActivate, R Plot
else ; Not minimized
winMinimize, R Plot
; TODO Bug: Window is activated but not focus e.g. keybindings not working. Hacky workaround: call `msgbox` with minimal timeout so that it disappear almost instantly. When it disappears, R plot windows is focused.
msgbox,,,, 0.001
return
; Init and restore R plot window, hacky solution to enlarge/restore shell pane, etc TODO Optimize
plot_toggle := 0
plot__toggle_init_restore:
+!p::
setKeyDelay, 100
toggle := ! toggle
; Init plot
if (toggle = 1) {
winActivate ahk_exe WindowsTerminal.exe
winWaitActive ahk_exe WindowsTerminal.exe
send ^+!{f8} ; Call nvim's plot_init
; R plot window: set `alwaysOnTop` and position to top-right corner
winActivate R Plot
winWaitActive R Plot
winSet, alwaysOnTop, , R Plot
winMove, R Plot, , 1044, -32, 881, 597 ; NOTE Also move and resize to default size. Same as win_pos___standard
send !{tab}
}
; Restore plot
else {
winActivate ahk_exe WindowsTerminal.exe
winWaitActive ahk_exe WindowsTerminal.exe
send ^+!{f7} ; Call nvim's plot_restore
; R plot window: set `alwaysOnTop` and restore default position
winActivate R Plot
winWaitActive R Plot
winSet, alwaysOnTop, , R Plot
winMove, R Plot, , 523.5, 166 ; Same as from .Rprofile
winMinimize, R Plot
}
; Restore default
setKeyDelay, -1
return
; _ Navigation, window management ---------------
#ifWinActive R Plot
plot__minimize:
p::
winMinimize A
return
plot__increase_size:
i::
; Increase width and height by 25%
; Move upper-left: decrease x and y by 25%
winActivate R Plot
winGetPos, x, y, width, height, A
winMove, A, , .75*x, .75*y, 1.25*width, 1.25*height
return
plot__decrease_size:
e::
; TODO Correct? Very slightly diff compared to default size. Test by `plot__increase_size`, `plot__decrease_size`, `get_info_of_active_window`
; Decrease width and height by 20% (1/1.25 == .8)
; Move lower-right: increase x and y by 33% (1/.75 == 1.33)
winActivate R Plot
winGetPos, x, y, width, height, A
winMove, A, , 1.33*x, 1.33*y, .8*width, .8*height
return
plot__move_win_up:
+k::
winGetPos, , y, , , A
winMove, A, , , y-200
return
plot__move_win_dn:
+j::
winGetPos, , y, , , A
winMove, A, , , y+200
return
plot__move_win_left:
+h::
winGetPos, x, , , , A
winMove, A, , x-200
return
plot__move_win_right:
+l::
winGetPos, x, , , , A
winMove, A, , x+200
return
Rust's implementation of process/system monitor
CLI file manager joshuto
See My {colorout}
See Custom {skimr} summary stats
See Use R help system with Vimium
See {theme} for R packages: {ggplot2}, {plotly}, {shiny}, {rmarkdown}, {ggdist}, {ggdag}, etc.
In my config, you will realize I love using
- Tabs for multiple workspace (like virtual desktop environment), e.g. for
- terminal UI lazygit
- Neogit
- splitting windows for different files and/or terminals
- basically anything
- Floating terminal so that I can focus it in the center of my screen, with the option of re-positioning it to the right of the window. See toggleterm.lua
REPL: There are many REPL plugins out there like vim-slime, but they lacks some features which I use. Hence, I customize them myself.
telescope.nvim: Alternative to fzf, telescope is native to Neovim, hence it has better integration/keybinds/etc and much more easily customize/hack.
Neovim's built-in terminal emulator to replace my Tmux
- Pros
- Better overall integration and easier to hack
- Better keybindings integration
- Use everything (e.g. floating window/terminal) in full screen inside neovim
- Cons
- Redraw issues
- Minor issues I can live with
For completion, I am happy with nvim-cmp and some of its features. coq_nvim is the fastest but for me, it's 'too fast', poping out too frequently. I just love old-school typing and manually trigger completion when I need it. I also played with it and feel free to use my config coq_nvim.lua. I might use it in the future.
This repo is mainly for sharing my setup. Thank you open source.
Some idea and codes are stolen from others lol. (I have no idea how to credit them, please let me know if I have done anything wrong in this regard, miss out your names, or remove your name, thanks!). I have included their repo and name in the file e.g. see vim/repl.vim.
Hence, I would like to credit them. They are also the authors of this repo
-
Should I move all the gists to this repo so other people can easier refer to them?
-
textwidth
for rmd.vim and pandoc.vim -
nvim-cmp's highlights
-
Nvim v0.6.0 potential break: See change log, pull #15585, etc
-
Document
paste_markdown_link
-
lazygit issue #1698
-
Add docs for toggle_term_tab (lazydocker) and btm
-
packer package snapshot (#370)
-
Potential break for update of plugins
-
https://github.com/kyazdani42/nvim-tree.lua/commit/0e7856fd8de18edaaee8fa0c2f2c9432c973aef5
-
toggleterm:
terminal_mappings
pull #149 -
(Feat) lightspeed: Bidirectional search, cross-window motions
-
Update julia-vim (changes from 9 Feb 22 onwards)
-
telescope:
wrap_results
pull #1735- LSP
ignore_symbols
pull #1745 - LSP filter diagnostics pull 1610
-
nvim-cmp:
THROTTLE_TIME
-
Luasnip: Deprecated
autosnippets
aeea587 -
Explore rcarriga/nvim-notify
-
nvim --remote
. Potentially replacenvr
-
Explore highlight: support for blend in nvim_set_hl (#17516) (b5bf487)
-
Explore ggandor/leap.nvim and ggandor/flit.nvim
-
Explore toggleterm pull #245 with new, default feature
persist_mode = true
-
Explore cmp pull #901 and #1026
-
Explore nvim-cmp pull #1067 and #1003
-
Explore gitsigns commit f6c95960, fe6b09b, 88d7aae
-
Use glepnir/lspsaga.nvim
-
Explore
set winbar
andset laststatus=3
-
Explore feat(runtime)!: enable filetype.lua by default #19216
-
Explore toggleterm commit d358641, 42438b3, c8574d7, 01a84bc, 81ea9f7
-
Explore nvimtree commit 69a07d1
-
Explore spectre commit 17b7c84
-
Explore telescope commit 84d53df
-
Fix HOTFIX tag
-
Explore nvimtree Open At Startup
-
Explore: See
lspconfig-single-file-support
-
TODO_URGENT NvimTree bugs (6da7467)
- See
view.preserve_window_proportions
- See
-
See commented-out
a.nvim_command("wincmd " .. move_to)
removes the error
function M.reposition_window()
local move_to = move_tbl[M.View.side]
-- a.nvim_command("wincmd " .. move_to)
M.resize()
end