<-

Developer Environment

For more than 7 years I have been working professionally as a Software Engineer. During this time I put together a nice developer setup. This article is my attempt to review it, improve it and share it with others.

Most of the time I spend in the command line, writing code in Nvim, executing commands in Zsh shell, switching panes and sessions in Tmux and all that is rendered in Alacritty terminal emulator running on my Mac.

What my developer environment consists of?

  • MacOS as main operation system
  • Ansible for installation and configuration
  • Alacritty as a terminal emulator
  • ZSH as command interpreter (shell)
  • Tmux as a terminal multiplexer (sessions, panes)
  • Nvim as the main text editor

Table of Contents

Structure of Command line

Most of the time I spend in the command line, reading and writing code in Nvim, jumping between terminal sessions in Tmux and running commands in Zsh and all that is rendered in Alacritty terminal emulator.

Shell

Command-line Shell is a program which takes text commands, parses it, executes and prints back result. The shell defines syntax and concepts of the scripting language that you can input in. Different shells have different rules. Examples: Bash, Zsh, Fish.

Terminal Emulator

Terminal is a program which runs your shell of choice and renders GUI window where you can interact with your CLI shell. Examples: iTerm2, Alacritty, Kitty. Some terminals provide you with features like multiple windows, tabs, splits etc.

Terminal Multiplexer

Terminal Multiplexer is a program which orchestrates multiple terminal sessions into a single terminal window. It is command-line window manager, where windows are terminals, each terminal can have multiple windows and windows can be split into panes.

Alacritty

Alacritty

At the start of my career, my terminal usage mostly was to run a script to compile code, run tests or interact with git. For quite a long period of time, I was fun of terminal that is integrated into my editor.

Some forces attracted me into the world of text-based apps and instead of having the terminal in the Editor, I'm having Editor in the terminal.

When you heavily use the command line, especially when you search, move around, or write code in Nvim - you expect your terminal to render text fast. At some point performance of my terminal frustrated me and I found a solution - Alacritty.

Alacritty is just a very fast window with a shell running inside. It is written in Rust and uses GPU acceleration for rendering. There are no GUI features like windows, tabs or splits.

Installation

---
- name: Make sure alacritty is present
homebrew_cask:
name: alacritty
state: present
- name: Make sure config directory is present
file:
path: ~/.config/alacritty
state: directory
- name: Make sure the config file is present
template:
src: templates/alacritty.yml.j2
dest: ~/.config/alacritty/alacritty.yml

Configuration

Alacritty is configured using a global text file located in ~/.config/alacritty/alacritty.yml

Config line below fixes colours rendering:

env:
TERM: xterm-256color

I'm using Fira Code font, but Alacritty doesn't support font ligatures --> :(

font:
normal:
family: Fira Code
style: Regular
bold:
family: Fira Code
style: Bold
italic:
family: Fira Code
style: Italic
size: 14.0

Configuring default shell, Zsh in my case:

shell:
program: /usr/local/bin/zsh
args:
- --login

Key bindings

In order to be able to use ^, when you type <ctrl>6, in Nvim to switch between files, I had to configure Alacritty to send \x1e hex code.

key_bindings:
- {key: Key6, mods: Control, chars: "\x1e"}

Full Alacritty configuration is here .alacritty.yml

Tmux

Tmux logo

Tmux is a terminal multiplexer which allows having multiple sessions, windows and splits in one terminal window. Command-line window manager.

  • sessions: list of terminals, each has one or more windows
  • window: window takes one screen and can be split into panes
  • pane: the smallest part of the window

Usually, I have session per project open and multiple windows in each session. For example, I can have session work, with 2 windows open, one for code in Nvim and one window for running build scripts and tests.

Tmux allows to quickly navigate between sessions, windows and panes. With some additional configuration, I was able to get Vim key bindings to be used for jumping between splits, browsing logs and copy-pasting text.

Plugins

Tmux Plugin Manager (tmp) is used to simplify plugins management. It simplifies the installation process and management of plugins.

It has to be cloned to ~/.tmux/plugins/tpm.

# predefined settings
set -g @plugin 'tmux-plugins/tmux-sensible'
# copy to the system clipboard
set -g @plugin 'tmux-plugins/tmux-yank'
# regex search
set -g @plugin 'tmux-plugins/tmux-copycat'
# open highlighted selection
set -g @plugin 'tmux-plugins/tmux-open'

Colors problem

At some moment I noticed that Nvim colours when it is opened in Tmux are different comparing to Nvim opened outside of Tmux control, to fix that:

# fix terminal colours
# set -g default-terminal screen-256color
set -g default-terminal "screen-256color" # colors!
# tell Tmux that outside terminal supports true colour
set -ga terminal-overrides ",xterm-256color*:Tc"

Vim-like copy paste

# starts selection mode
bind C-[ copy-mode
bind -T copy-mode-vi 'v' send -X begin-selection
# copy with 'enter' or 'y' and send to mac os clipboard: http://goo.gl/2Bfn8
unbind -T copy-mode-vi Enter
bind -T copy-mode-vi 'y' send -X copy-pipe-and-cancel "reattach-to-user-namespace pbcopy"
# paste
bind p paste-buffer
# paste from system clipboard MacOS
bind C-v run \"tmux set-buffer \"$(reattach-to-user-namespace pbpaste)\"; tmux paste-buffer"

Vim-like pane navigation

To be able to navigate between panes using Vim key-bindings, just install the next plugin:

set -g @plugin 'christoomey/vim-tmux-navigator'

To be able to use the navigation in the fzf window, fzf needs to be added to is_vim check.

is_vim="ps -o state= -o comm= -t '#{pane_tty}' \
| grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|fzf|n?vim?x?)(diff)?$'"
bind-key -n 'C-h' if-shell "$is_vim" 'send-keys C-h' 'select-pane -L'
bind-key -n 'C-j' if-shell "$is_vim" 'send-keys C-j' 'select-pane -D'
bind-key -n 'C-k' if-shell "$is_vim" 'send-keys C-k' 'select-pane -U'
bind-key -n 'C-l' if-shell "$is_vim" 'send-keys C-l' 'select-pane -R'
tmux_version='$(tmux -V | sed -En "s/^tmux ([0-9]+(.[0-9]+)?).*/\1/p")'
if-shell -b '[ "$(echo "$tmux_version < 3.0" | bc)" = 1 ]' \
"bind-key -n 'C-\\' if-shell \"$is_vim\" 'send-keys C-\\' 'select-pane -l'"
if-shell -b '[ "$(echo "$tmux_version >= 3.0" | bc)" = 1 ]' \
"bind-key -n 'C-\\' if-shell \"$is_vim\" 'send-keys C-\\\\' 'select-pane -l'"
bind-key -T copy-mode-vi 'C-h' select-pane -L
bind-key -T copy-mode-vi 'C-j' select-pane -D
bind-key -T copy-mode-vi 'C-k' select-pane -U
bind-key -T copy-mode-vi 'C-l' select-pane -R
bind-key -T copy-mode-vi 'C-\' select-pane -l

Shortcuts

Most of the shortcuts have a prefix key as part of them. My prefix is <ctrl>a. For example to create new window <prefix> c, I have to hold <ctrl>a + c.

<c-a> - Prefix
<prefix>r - reload config

Sessions

<prefix>:new -s <session-name> - creates new session
<prefix>s - open session list
<prefix>w - open session list with tabs

Windows

<prefix>c - create new window
<prefix>h - toggle window line
<prefix>1 - go to window 1
<prefix>2 - go to window 2
.
<prefix><N> - go to window N

Splits

<prefix>| - vertical split
<prefix>- - horizontal split
<ctrl>h - go to left split
<ctrl>l - go to right split
<ctrl>k - go to top split
<ctrl>j - go to bottom split

Copy mode

<prefix><c-]> - activate copy mode
v - start copy selection
y - copy selection
p - paste selection

Here you can find full .tmux.config

Nvim

Nvim logo

Nvim - a community-driven, refactored version of vim.

Nvim allows me to edit text faster than anything else. It designed to keep hands always in an optimum position to input text, to scroll, to navigate or to apply commands.

Config files are here: .nvimrc

Contents

Plugins

Vim-plug is used to simplify plugin management. It supports on-demand plugin loading for start time fast, and parallel installation/updates.

File explorer

The Nerdtree presents filesystem in the form of the tree and allows to browse, navigate and manipulate files and directories using Nvim navigation shortcuts.

Plug 'scrooloose/nerdtree'

Configuration:

let NERDTreeShowHidden=1 " show hidden files
let g:NERDTreeAutoDeleteBuffer = 1 " delete buffer when delete file

Shortcuts:

While the buffer is in focus:

<leader>fe - toggle file tree
<leader>ff - find current file

While the file tree is in focus:

t - open file in new tab
i - open file in a hsplit
s - open file in a vsplit
o / enter - open file in the main buffer

Tabs / Splits and Status line

Vim-airline is a plugin which draws editor status in a bottom line. It shows current vim mode, current git branch, the position of the cursor relative to the beginning of the file.

Plug 'bling/vim-airline'

In addition it can be used to make tabs nice:

let g:airline#extensions#tabline#enabled = 1
let g:airline#extensions#tabline#fnamemod = ':t'
let g:airline#extensions#tabline#tab_min_count = 2
let g:airline#extensions#tabline#show_buffers = 0
let g:airline#extensions#tabline#tab_nr_type = 1
let g:airline#extensions#tabline#tabs_label = ''
let g:airline#extensions#tabline#show_splits = 0
let g:airline#extensions#tabline#show_tab_count = 0
let g:airline#extensions#tabline#show_close_button = 0

Tabs mappings:

<leader>tt - new tab
<leader>tp - go to prev tab
<leader>tn - go to next tab
<leader>to - close all tabs expect current one
<leader>1 - go to 1 tab
<leader>2 - go to 2 tab
.
<leader>n - go to nth tab
<leader>0 - go to last tab

Splits mappings:

<c-h> - go to left split
<c-j> - go to bottom split
<c-k> - go to top split
<c-l> - go to left split
<c-\> - go between split
<c-w>o - close all splits except focused one

Search and navigation is done via fzf. It is a generic command-line fuzzy finder. It can be used to search in any list: files, command history, processes, hostnames, bookmarks, git commits. From the shell it is used to execute commands from command history, to select git branches, to choose npm scripts and so on.

From inside of the editor it is used via fzf.vim to search for files by filename and to quickly jump between buffers. To search by files content, fzf is used in conjunction with ripgrep, which is grep rewritten in rust.

Plug '/usr/local/opt/fzf'
Plug 'junegunn/fzf.vim'

Shortcuts:

<ctrl>p - search files by filename
<ctrl>f - search files by content
<ctrl>b - search buffers by filename

Autocomplete

Having an editor to predict what are you going to type is must-have nowadays. So far the experience with autocompletion I had with YouCompleteMe.

Linting / Formatting

Plug 'w0rp/ale'

While writing code automatic formating and linting is must-have. The best vim plugin for that is Ale. It provides integration with most linting, formating tools and to LSP servers.

Reasons to use it:

  • async execution of linters / fixers
  • list of integrations is huge

Shortcuts:

<leader>al - lint
<leader>af - fix
<leader>ad - error details

Git

Git integration is done by the next plugins:

Plug 'tpope/vim-fugitive' " git commands
Plug 'junegunn/gv.vim' " git commit browser
Plug 'airblade/vim-gitgutter' " git diff sign
  • Fugitive - git wrapper, provides all git commands as nvim commands and more.
  • Gv - git commit browser, allows viewing huge history line and jump between commits.
  • Gitgutter - shows git diff sign for the current file, makes it easy to understand what's changed.

Shortcuts:

<leader>gpr - git pull -r
<leader>gc - git commit
<leader>gp - git push
<leader>gb - git blame
<leader>gl - git log
<leader>gd - git diff in vertical split

Zsh

ZSH - highly customizable shell, supports aliases, completions, custom colour scheme.

Plugins

zplug - plugin manager used to simplify plugin management. Can manage all types of plugins (git, oh-my-zsh, gist files), parallel installation, lazy loading.

Vim keybindings

zplug "plugins/vi-mode", from:oh-my-zsh

vi-mode - adds vim keybindings to shell. While you edit text you can exit insert mode and go to command mode where it is possible to navigate and change text the same way like in Vim.

zsh-users/zsh-history-substring-search

Allows to search for command based on typed part. Next bindings are used j k to cycle through matches.

bindkey '^[[A' history-substring-search-up
bindkey '^[[B' history-substring-search-down
bindkey -M vicmd 'k' history-substring-search-up
bindkey -M vicmd 'j' history-substring-search-down
zplug "plugins/fzf", from:oh-my-zsh

The plugin allows to quickly search in command history using fuzzy search.

<ctrl><space> opens fzf fuzzy search with full history.

Fish like autosuggestions

zplug "zsh-users/zsh-autosuggestions"

While you type, the plugin shows autosuggestion under cursor in grey colour based on your history.

Completitions library

zplug "zsh-users/zsh-completions"

While you type and hit <tab>, plugins shows possible suggestions for a command if it is present in competition library.

Conclusion

Getting proficient with Vim opened next-level productivity experience for me, allowing having common shortcuts scheme through the whole developer setup.

Working directly with command-line tools, gave me a broad understanding of what is behind fancy buttons people love.

Only with Vim, I learned how actually linters and formatters work, how editors highlight code, what way LSP servers work etc.

Each time returning back to work after long travel and opening laptop with my carefully configured setup, I feel like a kid who just got his new toy.