Vim: Semantic execution
Tags: vim, productivity
Published: 2020-06-01 16:04:53

_Originally posted at [thorn.co/blog/vim-semantic-execution/](https://thorn.co/blog/vim-semantic-execution/)_.

---

A <abbr title="read–eval–print loop">[REPL]</abbr> is an excellent tool for exploring data or spiking out ideas. We can quickly answer our questions, then get back to our editor to resume feature work. But when we are unable to get answers quickly and complexity mounts, the REPL becomes a hindrance[^1]. Much of our time is spent moving back through the command history, hunting for that _one_ thing we need.

[REPL]: https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop

[^1]: Some REPLs do provide basic functionality for dealing with complexity. In `psql`, the `\e` command will open your editor with the most recent statement. In `node`, the `.editor` command allows for multiple lines, but doesn't open the editor. We can use the [interactive_editor] gem with `irb`, but it doesn't pull the command history, so we need to remember to start the session with it.

[interactive_editor]: https://github.com/jberkel/interactive_editor

If we instead do this exploration within our editor, we can retain every piece of code we write, while maintaining the quick feedback loop. It becomes easier to make adjustments or find that _one_ thing.

We'll need to execute these scripts differently, depending on the type, which we can configure Vim to do. We can take advantage of the [filetype plugin] system to use the same mapping for all our scripts. Let's use `<leader>x` as the mapping, as a mnemonic for "execute." We'll make use of the `clear` command to keep our output isolated, so we can focus on it.

[filetype plugin]: http://vimdoc.sourceforge.net/htmldoc/filetype.html#filetype-plugins

Create a _.vim/ftplugin/ruby.vim_ file with the following:

```
nnoremap <buffer> <leader>x :!clear; ruby '%'<cr>
```

With this, we can execute simple Ruby files with our `<leader>x` mapping. Then, we can make whatever tweaks we want, and keep iterating until we get what we need.

![simple ruby file](https://dev-to-uploads.s3.amazonaws.com/i/opj41ir0571qzhgir6qt.gif)

Since this is configured with Vimscript, we can tailor it for it our needs. Let's look at a bit more complex example.

_.vim/ftplugin/ruby.vim_:
```
if getline(1) == "# rails"
  nnoremap <buffer> <leader>x :!clear; rails runner '%'<cr>
else
  nnoremap <buffer> <leader>x :!clear; ruby '%'<cr>
endif
```

With `# rails` as the first line of a Ruby script, we use `rails runner` to execute within the context of our Rails app, with access to our models and all other supporting code. We can even store these files in the _tmp/_ directory and refer to them later.

[Spring]: https://github.com/rails/spring

If we set this up for all the languages we use[^2], then Vim acts as our anchor, no matter what tools our explorations require. It feels good be to home.

[^2]: Some reference code that may be useful: [go], [html], [javascript],
    [markdown], [ruby], [sql].

[go]: https://github.com/thorncp/dotfiles/blob/9a2a9a5afe3b16fda3c5e65a9d26722da7575987/.vim/ftplugin/go.vim#L3
[html]: https://github.com/thorncp/dotfiles/blob/9a2a9a5afe3b16fda3c5e65a9d26722da7575987/.vim/ftplugin/html.vim#L5
[javascript]: https://github.com/thorncp/dotfiles/blob/9a2a9a5afe3b16fda3c5e65a9d26722da7575987/.vim/ftplugin/javascript.vim#L6
[markdown]: https://github.com/thorncp/dotfiles/blob/9a2a9a5afe3b16fda3c5e65a9d26722da7575987/.vim/ftplugin/markdown.vim#L5
[ruby]: https://github.com/thorncp/dotfiles/blob/9a2a9a5afe3b16fda3c5e65a9d26722da7575987/.vim/ftplugin/ruby.vim#L8-L17
[sql]: https://github.com/thorncp/dotfiles/blob/9a2a9a5afe3b16fda3c5e65a9d26722da7575987/.vim/ftplugin/sql.vim#L19-L23