sudo apt install nvim byobu
This post describes how I conduct interactive data analysis from the terminal using vim
and byobu
. Check out this YouTube video to see the setup in action:
My setup was designed to meet 5 objectives. First, I want to use the vim
editor with all my usual plugins, shortcuts, snippets, etc. Second, I need access to standard IDE features like code completion, inline documentation, auto-indentation, etc. Third, I’d like the ability to split my terminal in side-by-side “panes,” where I can display code and/or run programs like R
, Stata
, python
or Julia
. Fourth, I need to quickly send code from pane to pane, in order to conduct interactive statistical analyses. Fifth, I want my setup to work on all (modern) operating systems and with any statistical language that allows interactive analysis (e.g., R
, python
, Stata
, Julia
).
I use two principal tools to achieve these objvectives:
neovim
(but the same setup would work with standardvim
).byobu
: A terminal multiplexer which allows me to split a single terminal into several “panes” where I can run different programs side-by-side.byobu
is a simple but convenient configuration layer built aroundtmux
.
After 15+ years of Linux and OSX, I (half-willingly) switched to a Windows 10 machine. For all of my “serious” work on this new computer, I use the Windows Subsystem Linux to run a full linux distribution (Ubuntu) inside my Windows OS. There are a ton of tutorials on the web on setting up WSL2. Here, I assume that Windows users have installed a WSL2 distribution, opened a terminal emulator like Windows Terminal or alacritty
, and executed wsl.exe
.
To begin configuration, let’s install the programs we need:
Then, we install a few vim
plugins. To do this, I use vim-plug
, which requires me to call :PlugInstall
from inside vim
, after placing the following instructions in my configuration file:
call plug#begin('$HOME/.config/nvim/plugged')
Plug 'neovim/nvim-lspconfig' " neovim-specific
Plug 'nvim-lua/completion-nvim'
Plug 'tpope/vim-tbone' " tmux interaction
Plug 'jpalardy/vim-slime'
call plug#end()
The nvim-lspconfig
and completion-nvim
plugins are optional, and only needed if you want code completition, linting, and other IDE features. These plugins only work for neovim
, but strong alternatives like coc
are available for vim
. To activate code completition, I insert this code in my vim
configuration file:
lua << EOF
require'lspconfig'.r_language_server.setup{
on_attach=require'completion'.on_attach
}
EOF
I also need to install the lspserver
package for R
. In an R
session, type:
install.packages("languageserver")
The vim-tbone
plugin allows us to send commands to byobu
(via tmux
), such as split a window into several panes, open an R
session, close panes, etc. This plugin also allows us to send text to different panes, but as far as I can tell, it can only do so line-by-line, and not based on a visual selection. For this reason, I use vim-slime
to send code from my R
script to the R
instance which runs the code.
Since byobu
is a thin configuration wrapper around tmux
, we need to tell vim-slime
that it will interact with a tmux
multiplexer. The second line of the code below saves me a few keystrokes the first time I execute a command with vim-slime
:
let g:slime_target = "tmux"
let g:slime_default_config = {"socket_name": "default", "target_pane": ":.1"}
Then, I define “comma” as my vim
mapleader, I disable the default vim-slime
keybindings, and I set my own. Typing C-k
will send the paragraph under the cursor or the visual selection to the other pane. Space
will send the current line to the other pane. Key sequences like ,t2
tell vim-slime
which of the window panes my code should be sent to. The sequence ,tr
will create ask byobu
(via tmux
) to open new terminal in a vertical split, and to launch a new instance of R
in that terminal.
let mapleader = ","
" vim-slime
let g:slime_no_mappings = 1
xmap <C-k> <Plug>SlimeRegionSend
nmap <C-k> <Plug>SlimeParagraphSend
nmap <Space> <Plug>SlimeLineSend<CR>
nmap ,t1 :let b:slime_config["target_pane"] = ":.1"<CR>
nmap ,t2 :let b:slime_config["target_pane"] = ":.2"<CR>
nmap ,t3 :let b:slime_config["target_pane"] = ":.3"<CR>
nmap ,t4 :let b:slime_config["target_pane"] = ":.4"<CR>
nmap ,t5 :let b:slime_config["target_pane"] = ":.5"<CR>
" vim-tbone
nmap ,tr :Tmux split-window -dh 'R'<CR>
Finally, to start the actual data analysis I launch byobu
, open an .R
script, and launch an R
instance in a split window:
byobu
vim tmp.R
,tr
To take a line of R
code from my script and execute it in the R
instance, I press space bar (in vim
normal mode). To send a paragraph or a selected region, I type Ctrl-k
.
The first time I try to send R
code from my script to the terminal, byobu
will ask me to confirm which pane I want to use. The default is usually “correct”, so I just type Enter
.
That’s it, we’re done!