Skip to main content

Alex Smith

My Minimal, Terminal-based Work Setup

Table of Contents

Here I describe the various software I use to form a development environment for programming projects.

# dtach

The basis for my setup is dtach. dtach executes a program in a session which the user can ‘detach’ from, returning them to the shell while the program continues to run. Later, the session can be reattached to. It allows me to, for example, start Neovim in a terminal window, make changes to some files and detach, allowing me to use the terminal window again for some other purpose or even close it entirely without disturbing Neovim. This is useful is because it allows me to attach to an existing session after connecting to the machine it’s running on via SSH. I can open a project and begin working while sitting at my desk, and then later access the same session remotely. dtach will also save you if the connection drops because you just reconnect and attach to the session again. If you want to replicate a setup like mine and you don’t need SSH then you may not need dtach.

# dvtm

dvtm is a terminal multiplexer I use to construct my development environment user interface. It allows you to open various programs using one terminal window and display them in various layouts. It functions similarly to dwm. I’ll usually have open my text editor and several instances of bash displayed side-by-side, which I can switch between when required. Windows may be closed and new ones opened as necessary.

dvtm example

Window positions are determined by preconfigured layouts which can be cycled between to suit requirements. I almost never use anything other than the default ‘master and stack’ layout displayed above (master window on the left, other windows in ’the stack’ on the right).

# Neovim

Neovim is my text editor of choice. I dislike the tendency people often have of weighing Vim/Neovim down with loads of useless plugins. However, there are two that I use which contribute well to speedy and efficient development:

## fzf

fzf is a command-line fuzzy finder and there is a plugin that allows its usage from within Vim/Neovim. It can be configured to fuzzy-find any kind of text content, but I use it for finding files from within Neovim. The two commands I use are :Files and :Buffers mapped to <Leader>f and <Leader>b, respectively. :Files fuzzy-finds all files from the current directory, whereas :Buffers fuzzy-finds only opened buffers. I have fzf configured to open inside a split where results appear as I type. The results can be cycled between and selecting an entry will open the file. fzf itself is very fast and its incorporation into Vim/Neovim saves a lot of time spent hunting for files.

## Fugitive

Fugitive adds Git integration to Vim/Neovim. The key feature for me is the ability to easily add files to staged changes with a keystroke. Fugitive also makes it trivial to add only specific hunks to staged changes and even just specific lines. It allows me to have fine-grained control over what changes are to be committed and a clear view of those changes with its summary window in which I can open diffs. It is very good and if you use Vim/Neovim and Git then I recommend you use Fugitive.

# The clipboard problem

I use lemonade for clipboard usage over SSH which works well, but there’s an issue when switching between between local and remote. A dtach session started in the context of an X server will contain the DISPLAY environment variable which Neovim uses to determine whether to call xclip. The problem is that this variable is still present if the session is attached to later over SSH, which means Neovim executes xclip instead of lemonade.

The solution is to simply remove the variable from Neovim while it’s running with :unlet $DISPLAY and then reload the clipboard provider:

:unlet g:loaded_clipboard_provider
:runtime autoload/provider/clipboard.vim

You can assign this to a function which can be called via a key-binding:

function ResetClipboardProvider()
  :unlet g:loaded_clipboard_provider
  :runtime autoload/provider/clipboard.vim
endfunction
nnoremap <Leader>cr :call ResetClipboardProvider()<CR>

If you have the opposite problem (session created outside of X) then the solution is the same except you set the variable rather than removing it: :let $DISPLAY=':0'.

In windows running a shell you’ll need to export DISPLAY=:0 as appropriate.

# Putting it all together

There are a couple of shell scripts I use to open all the programs. First, my work script:

#!/bin/sh

dtach_dir="$HOME/.dtach"

mkdir -p "$dtach_dir"

dtach -c "$dtach_dir/$(echo "$1" | tr / "\n" | tac | sed '/^\s*$/d' | head -n 1)" \
  dvtm-work "$1"

This takes a single argument, which is the directory of a project it changes into, and spawns a dtach session inside which the dvtm-work script is called:

#!/bin/sh

FIFO="/tmp/dvtm-status.$$"

[ -p "$FIFO" ] || mkfifo -m 600 "$FIFO" || exit 1

STATUS_PID=$!

cd "$1" || exit 1

dvtm -M -t "$(pwd)" -s "$FIFO" nvim "bash -l" "bash -l"

kill $STATUS_PID
wait $STATUS_PID 2> /dev/null
rm -f "$FIFO"

This script is a small modification of dvtm’s dvtm-status script, the only change being the removal of the time in the status bar and a tweak to the invocation of dvtm itself. dvtm, upon opening, will open three windows: Neovim and two instances of bash.

Say I have a project located at projects/my-project which I want to begin work on, I just call the work script with the project’s directory:

$ work projects/my-project

A dtach session will spawn, starting dvtm-work, which then starts Neovim and bash. I’m then ready to begin working. I can detach using Ctrl+\ and later reattach with dtach -a .dtach/my-project, resuming where I left off.

# Conclusion

There’s not a huge amount to say about this setup. It’s small, simple and only uses a few components. Its simplicity makes modifications easy. It’s powerful. It’s good at staying out of my way so I can just pursue the task of programming. The result is Vim-powered text editing; fast file access; Git integration with concise in-editor diffs and quick, fine-grained file staging; shell access; all displayed neatly in automatically determined layouts.

## Why don’t you just use VS Code or similar?

With only a handful of components I’ve satisfied all my requirements for programming tasks. VS Code is bloated software that comes with many features that I’ll likely never use. I believe it’s a better choice to go with something smaller and simpler. If I discover a requirement then there will most likely be a way I can work it into my setup.

## Neovim has terminal support, why don’t you use it?

I find it a bit cumbersome to have to manually open up splits and call the :term command. The idea with dvtm is that layouts are handled automatically by the software, so when a new window is opened it goes where you expect it to without any extra fiddling.

## No NERDTree or similar?

I don’t think file-tree-like explorers suit Vim/Neovim. fzf works well for fuzzy finding files from within Neovim and I have access to a shell with programs like ls and find for file discovery.