Recently, I made the decision to go all-in with NeoVim. If you’re not family with Vi(m) or NeoVim, it’s a fairly bare-bones, but incredibly, powerful text editor. If you’ve ever opened a file in Unix terminal, whether that be on your Mac or a Linux machine, or even a server, there’s a good chance you’ve used Vi(m). While this switch is certainly not unheard of, particularly in the wider programming world, I can’t say I know many scientists (outside of CS, that is) who use it. In a world where everyone is using RStudio for R (and increasingly Python) programming, and VSCode dominates everything else, why would I possibly move to a text editor that doesn’t have all of the creature comforts that are baked into modern IDEs?
Over the next couple of posts I hope to answer that question, and maybe even convince you to give it a try. The first post in this mini-series will outline my motivations for switching and the bigger picture, and the subsequent posts will focus on the technical aspects and how I’ve made it work for me and my needs in scientific computing. Long story short, I’ve found it to be a really enjoyable experience, and it has helped me become a better programmer through gaining a deeper understanding of the tools I use every day, which has transferred back to a better understanding of the languages I use for my work.
Where I’m coming from
Before we talk about motivations, I think it’s important to outline the type of work that I do, and what tools I’ve used in the past, as no editor is a one-size-fits-all solution.
In my day-to-day work, I use the R and Julia programming languages to clean lots of population-level infection data, build statistical (think GLM) and dynamical (think SIR) models, create lots of figures, and write papers and summary reports using Quarto notebooks. All of this is fairly typical of a scientist in the modern era, where most of our work is now performed on computers.
As a result of being researcher who’s work is entirely computational, it’s important that the text editor I use fits my needs. But these needs are not the same as a software developer’s, who is the primary target for most IDEs, so seemingly inconsequential grievances can be deal-breakers for researchers.
What I need & want from an editor
Given the work outlined above, there are a number of non-negotaible features that I need from an editor:
- Interactive editing of R and Julia code, including the ability to send code chunks to a REPL/console.
- Syntax and error highlighting for R, Julia, and Markdown (and ideally LaTeX).
- Autocompletion of R and Julia code, including in a Quarto notebook.
- Easy plot creation and viewing.
Most of these should hopefully be self-explanatory given the workflow I outlined above, and it was not immediately obvious that all were possible within NeoVim (within a reasonable enough time-frame before I gave up and went back to what I was used to).
There are also a number of features that I want from an editor, but could live without:
- First-class Git integration.
- Spell checking.
- Code formatting.
- Extensibility through plugins as I decide to learn new languages or workflows.
- Quick start up times.
- Simple configuration of keymaps, snippets, etc.
- Easy navigation of files and projects.
- Good file manipulation (e.g. moving, copying, deleting, etc.).
What’s wrong with RStudio & VSCode?
Like most people, I started learning R using RStudio, and I still think it’s a great tool. It is incredibly easy to set up, and it does all of my four essentials for R out of the box. It can also do most of my wants with somewhat minimal effort. So why switch?
As mentioned, I’ve been using Julia more and more as I’ve transitioned from traditional epidemiological analysis with statistical models to building dynamical models of infectious disease, which are much more computationally intensive (particularly for ensemble stochastic simulations) and benefit from a faster language. Plus, it’s fun learning a new language and has made me a better programmer in general, which benefits my R work as well. As a result, I haven’t used R for serious work in the last couple of months, and last I checked, RStudio didn’t support Julia (outside of using a binding like the JuliaCall R package from within R scripts, which is not ideal from a reproducibility standpoint and doesn’t address needs 2. and 3. particularly well). It’s certainly not essential to use the same IDE for all languages, but it definitely makes it easier to switch between projects, and there are fewer configurations to maintain and get used to.
That rules out RStudio, but what about VSCode? Well, I actually had switched to using VSCode entirely for my R code 2 years ago. The main reason was not because I was starting to learn Julia (though it did coincide with this), but actually because RStudio couldn’t handle I didn’t search hard enough to figure out how to get RStudio to handle some of my larger projects.1
1 The issue below just outlines my reasoning at the time, and it can be worked around by sending code to a tmux terminal session within RStudio’s terminal pane (see this post for more detail).
2 If you use R and you haven’t come across {targets}
yet, do yourself a favor and go learn it now! Not only does it make your code more reproducible by removing the questions about which scripts need to be run when something is updated (this comes with the added benefit of not needing to re-run calculations when their dependencies haven’t changed) but it also makes it easier to debug as it encourages smaller modular functions.
Because I was working with larger and larger datasets, and often trying to make use of parallelization to speed up long-running code, I was running into memory issues with RStudio (at the time I was working on a 10 year old MacBook Pro that had seen it’s fair share of hardships and was absolutely not up to the task). Unfortunately, RStudio’s biggest strength was also it’s biggest weakness for me: by including everything within the IDE, by default your R code is sent to the integrated console that is bound to your editor. If RStudio crashes, it takes your R session down with it. And in my case, it was crashing a lot, requiring me to restart long computations far more often than was actually required: the same scripts (technically {targets}
pipelines) would run fine in the terminal!2 It turns out there are ways to circumvent this issue using the technique described below, and it’s been around for a while, so this point was actually my biggest weakness, not RStudio’s, but the end result was the same as I mostly use Julia now, requiring a new editor anyway.
VSCode solved this issue for me because it has an integrated terminal (like RStudio), but by default all code is sent to the terminal that is currently open. At first glance, this doesn’t seem to be any different from RStudio’s integrated console. However, the difference is that I could use a terminal multiplexer like tmux from within the VSCode terminal, allowing me to separate my R session from my editor. If you’re not familiar with terminal multiplexers like tmux, that’s OK, I wasn’t either at first. Essentially, they allow you to create multiple persistent terminals that will stay open and running even if you close your terminal window. They are useful when working on servers and you want to guard against accidentally losing connection because of internet issues etc., but as you can imagine, they come in handy for local development too. In my case, I could open up a tmux session (in the VSCode terminal), start R, and then VSCode would send the commands to the R session running in tmux, and if VSCode crashed, I could just re-open it and reconnect to the tmux session, which would still be running. And better yet, because VSCode is the most popular editor, there’s likely an extension available that will solve a problem you are facing. This includes an extension for working with R: vscode-r. It’s not perfect, and there are certainly some niceties from RStudio that are missing or need some work to be configured (e.g., setting up RStudio addins to add Roxygen docstrings), but it was a pretty good solution that I was happy with for a couple of years. And VSCode is the editor primarily suggested for Julia, so it was a natural fit to have everything in one place.
So again, why switch?
Over time, there were small details I noticed were annoying me about the VSCode (and RStudio) approach. Firstly, it was slow to start up and get going with a project. This is certainly not the biggest issue, but it adds just a little bit of friction each time you have an idea you want to test out. If I’m working on one project and I realize I should reimplement a function in another, I want to be able to move instantly to that project and start working on it, not wait for VSCode to fire up. The extra time resulted in me having multiple VSCode windows open at once, which is not ideal for many reasons (particularly on old hardware). Secondly, and this was a surprisingly large motivating factor, the plotting window in VSCode is baked in to the editor. In a similar vein to the issue with RStudio defaulting to sending code to a console, relying on an integrated plotting window makes working off a laptop annoying. Most of the time I have a monitor, but there have been enough occasions where I only have the small screen of my laptop to work with, and each time I want the code to take up all the space. Normally I don’t need to see plots as I’m writing code, and it’s possible to hide and show the plot windows, but I found that I need to view them frequently enough to notice how slow this is to accomplish using a mouse (I couldn’t find any settings that would allow me to do this using keyboard shortcuts, though this could again be a me-issue). What I wanted was to be able to send the plot window to a different “space/desktop” on my laptop, and then I could switch between the editor and the plot window with a keyboard shortcut I set up in System Preferences.3.
3 Something similar could be achieved using a tiling window manager like yabai for MacOS, which I use extensively (but that’s for a later day) or I3/Sway for Linux. I’m not sure if something similarly competent exists for Windows, but this package seems like a promising start.
What does NeoVim do better?
What are the pain points?
Reuse
Citation
@online{arnold-leps2023,
author = {Arnold-Leps, Callum},
title = {Reflections from a {Month} of {NeoVim}},
date = {2023-08-31},
langid = {en}
}