303 lines
12 KiB
Markdown
303 lines
12 KiB
Markdown
+++
|
|
title = "A modern CLI renaissance?"
|
|
date = 2024-03-04T12:20:02-06:00
|
|
draft = true
|
|
+++
|
|
<!--
|
|
tool,link,year,language
|
|
ls,,1961,c
|
|
cat,,1971,c
|
|
cd,,1971,c
|
|
cp,,1971,c
|
|
man,,1971,c
|
|
rm,,1971,c
|
|
grep,,1973,c
|
|
diff,,1974,c
|
|
sed,,1974,c
|
|
bc,,1975,c
|
|
make,,1976,c
|
|
vi,,1976,c
|
|
bourne shell,,1979,c
|
|
awk,,1985,c
|
|
screen,,1987,c
|
|
bash,https://www.gnu.org/software/bash/,1989,c
|
|
zsh,https://www.zsh.org/,1990,c
|
|
vim,https://www.vim.org/,1991,c
|
|
midnight commander,,1994,c
|
|
ssh,,1995,c
|
|
curl,https://github.com/curl/curl,1996,c
|
|
fish,https://fishshell.com/,2005,c/rust
|
|
fossil,https://fossil-scm.org/home/doc/trunk/www/index.wiki,2006,c
|
|
tmux,https://github.com/tmux/tmux,2007,c
|
|
git,https://git-scm.com/,2008,c
|
|
go 1.0,https://go.dev/,2012,go
|
|
fzf,https://github.com/junegunn/fzf,2013,go
|
|
eza/exa,https://github.com/eza-community/eza,2014,rust
|
|
neovim,https://neovim.io/,2015,c
|
|
pueue,https://github.com/Nukesor/pueue,2015,rust
|
|
rust 1.0,https://www.rust-lang.org/,2015,rust
|
|
just,https://github.com/casey/just,2016,rust
|
|
micro,https://micro-editor.github.io/,2016,go
|
|
nnn,https://github.com/jarun/nnn,2016,c
|
|
ripgrep,https://github.com/BurntSushi/ripgrep,2016,rust
|
|
fd,https://github.com/sharkdp/fd,2017,rust
|
|
bat,https://github.com/sharkdp/bat,2018,rust
|
|
broot,https://dystroy.org/broot/,2018,rust
|
|
difftastic,https://difftastic.wilfred.me.uk/,2018,rust
|
|
hyperfine,https://github.com/sharkdp/hyperfine,2018,rust
|
|
lazygit,https://github.com/jesseduffield/lazygit,2018,go
|
|
lsd,https://github.com/lsd-rs/lsd,2018,rust
|
|
nushell,https://www.nushell.sh/,2018,rust
|
|
scc,https://github.com/boyter/scc,2018,go
|
|
sd,https://github.com/chmln/sd,2018,rust
|
|
git-delta,https://github.com/dandavison/delta,2019,rust
|
|
grex,https://github.com/pemistahl/grex,2019,rust
|
|
starship,https://starship.rs/,2019,rust
|
|
tre,https://github.com/dduan/tre,2019,rust
|
|
typst,https://typst.app/,2019,rust
|
|
diskonaut,https://github.com/imsnif/diskonaut,2020,rust
|
|
helix,https://helix-editor.com/,2020,rust
|
|
pijul,https://pijul.org/,2020,rust
|
|
zellij,https://zellij.dev/,2020,rust
|
|
zoxide,https://github.com/ajeetdsouza/zoxide,2020,rust
|
|
btop,https://github.com/aristocratos/btop,2021,c++
|
|
ast-grep,https://github.com/ast-grep/ast-grep,2022,rust
|
|
yazi,https://github.com/sxyazi/yazi,2024,rust
|
|
-->
|
|
|
|
<!--
|
|
open tmp.csv |
|
|
sort-by year tool |
|
|
update tool {|i| if ($i.link != "") {$"[($i.tool)]\(($i.link)\)"} else {$i.tool}} |
|
|
select tool year language |
|
|
to md |
|
|
xsel -bi
|
|
-->
|
|
|
|
<!--
|
|
ls specifically can trace its history to 1961
|
|
-->
|
|
|
|
Take a look at this [table](#appendix-the-tools) at the bottom of the page. Ill
|
|
wait. Notice the relative scarcity between ~1995 and ~2015? Id like to talk
|
|
about a trend Ive seen these past few years, where people are rewriting and
|
|
rethinking staples of the CLI, why I think this trend is a good thing, and why I
|
|
think this trend might be happening.
|
|
|
|
## History
|
|
|
|
The terminal has been a staple of computer user interfaces since before computer monitors were available,
|
|
with some of the first computers offering an interactive mode in the late 1950's.
|
|
The 'modern' Linux terminal traces its linage to the very first version of Unix, in 1971.
|
|
Many utilities that a Linux user interacts with every day,
|
|
commands like `rm`, `cat`, `cd`, `cp`, `man` and a host of other core commands trace their initial versions to this first version of Unix.
|
|
Other tools are a bit newer, such as `sed` (1974), `diff` (1974) `bc` (1975), `make` (1976) or `vi` (1976).
|
|
There were a few more tools introduced in the 90's, such as `vim` (1991) and `ssh`, (1995), but you get the picture.
|
|
The majority of the foundational CLI tools on a Linux pc, even one installed yesterday, are older than Linux itself is.
|
|
|
|
## Ok, so?
|
|
|
|
Now, theres nothing wrong with this, the tools work fine still, but,
|
|
in the half-century since they were first written,
|
|
Terminals and the broader Linux ecosystem have all changed.
|
|
Terminals now have capacity to display more colours, Unicode symbols, and even inline images.
|
|
Terminal programs now coexist with graphical user interfaces,
|
|
and only a small subset of computer users even know they exist,
|
|
wheras in the past, terminals were the only way one interacted with the computer.
|
|
|
|
Additionally, and perhaps more importantly, our knowledge has expanded,
|
|
our knowledge of user interfaces,
|
|
of what works and what doesnt,
|
|
of what usecases are common and what usecases are niche,
|
|
the way that error messages can teach,
|
|
the value of a good out of the box experience,
|
|
and the value of documentation that is easy to find and digest.
|
|
|
|
## Exploration of the solution space
|
|
|
|
These changes to the environment surrounding CLI apps has in recent years,
|
|
led to a resurgence in development of command line utilities.
|
|
Instead of just developing completely new tools,
|
|
Ive noticed that people are rethinking and reinventing tools that have existed since the early days of Unix.
|
|
|
|
<!--TODO: add more here-->
|
|
|
|
## The lessons learned from the past
|
|
|
|
A large amount of the innovation in the area, I think, can be attributed to
|
|
lessons that have been learned in 50 years of using software; sharp edges we
|
|
have repeatedly cut ourselves on, unintuitive interfaces that repeatedly trip us
|
|
up, and growing frustration at the limitations that maintaining decades of
|
|
backwards compatibility imposes on our tools.
|
|
|
|
These lessons have been gathering in the collective conciousness, through
|
|
cheatsheets, guides, and FAQs; resources to guide us through esoteric error
|
|
messages, complex configurations, and dozens upon dozens of flags.
|
|
|
|
Id like to go over a couple of the more prominent lessons that I feel terminal
|
|
tools have learned in the past several decades.
|
|
|
|
### A good out of the box experience
|
|
|
|
While configurability is great, one should not need to learn a new configuration
|
|
language and dozens or hundreds of options to get a usable piece of software.
|
|
Configuration should be for customization, not setup.
|
|
|
|
One of the earliest examples of this principle may be the fish shell.
|
|
Both zsh and fish have powerful prompt and autocompletion engines, but zsh
|
|
requires you to setup a custom prompt and enable completions in order to use the
|
|
features that set it apart from the competition. With no config file, zsh is no
|
|
better than bash. When starting fish for the first time, however, its powerful
|
|
autocompletion and information rich prompt are front and center with no
|
|
configuration required. Of course, fish still has the same level of
|
|
configurability as zsh, it just also has sensible defaults.
|
|
|
|
To demonstrate my point, this is the default prompt for zsh with no
|
|
configuration. It *only* shows the hostname, none of the advanced featurs you
|
|
can get out of a zsh prompt even without plugins.
|
|
![zsh prompt, only shows hostname](zsh_prompt.png)
|
|
Here is bash's prompt. It actually gives more info than zsh's, even though zsh
|
|
can do more when properly configured.
|
|
![bash prompt, shows hostname and current directory](bash_prompt.png)
|
|
And here is fish's default prompt. It has a few colours, shows everything the
|
|
bash prompt does, and additionally shows the git branch we are on.
|
|
![fish prompt, has colours, shows hostname, current directory, and git
|
|
info](fish_prompt.png)
|
|
|
|
Text editors are another great example of the evolution of out of the box
|
|
defaults. Vim and Neovim both improved on their predecessors, but so much of
|
|
that improvement is locked behind extremely complex configuration experiences
|
|
and plugins. Heres four different terminal text editors with no configuration
|
|
applied:
|
|
|
|
![vi, vim, neovim, and helix editors in their default
|
|
configuration](editors.png)
|
|
|
|
Vi, (top left) is our baseline, and, as far as I can tell, doesnt actually
|
|
support much for configuration. What you see out of the box is more or less
|
|
whats there.
|
|
|
|
Vim (top right) greatly improved on Vi, adding things such as syntax highlighting, line
|
|
numbers, spellchecking, split windows, folding, and even basic autocompletion.
|
|
However, everything but syntax highligting is either extremely clunky or
|
|
outright disabled without configuration. (for example, the earliest things I did
|
|
when I first made a `.vimrc` was to enable indent folding, make some better
|
|
keybinds for navigating windows, and adding a line number ruler to the side)
|
|
|
|
Neovim (bottom left) further improved on Vim, adding support for Treesitter and
|
|
the Language Server Protocoll, but the out of the box experience is the *exact*
|
|
same as vim! In order to take advantage of the LSP and Treesitter support, you
|
|
have to install plugins, which means learning a Nvim package manager, learning
|
|
how to configure LSPs, and configuring a new LSP for every language you want to
|
|
use it with. (Or finding out about Mason and being OK with having multiple
|
|
levels of package management in your Nvim install alone). Dont get me wrong,
|
|
Neovim is a great editor once you get over the hump, I still use it as my daily
|
|
driver, but so much of its functionality is simply hidden.
|
|
|
|
Then we have the Helix (bottom right) editor. Colour scheme aside, everything is
|
|
just there. Helix doesnt have plugin support
|
|
[yet](https://github.com/helix-editor/helix/discussions/3806), but it has so
|
|
much stuff in core that, looking through my neovim plugins, pretty much all of
|
|
them are in the core editor! (ironically, the one feature that I feel helix is
|
|
missing, [folding](https://github.com/helix-editor/helix/issues/1840), is a core
|
|
part of neovim, albiet one that requires some configuration to get good use out
|
|
of). Helix does have a config file where you can change a huge amount of
|
|
settings, but its an extremely usable IDE out of the box, thanks to having all
|
|
of its features enabled by default.
|
|
|
|
### Friendly error messages
|
|
|
|
<!-- look at nushells error messages-->
|
|
|
|
[before](../nushell)
|
|
|
|
### Concise and discoverable documentation
|
|
|
|
<!-- look at zellij and helix and their built in keymap cheatsheets-->
|
|
|
|
### Common usecases should be easy
|
|
|
|
<!-- look at sd, rg, and fd-->
|
|
|
|
## Shedding historical baggage
|
|
|
|
<!-- look at just command runner, simplifying the common use case of make-->
|
|
|
|
## The trendsetter
|
|
|
|
<!-- did neovim kick this all off?-->
|
|
|
|
## The languages
|
|
|
|
<!-- most of the new tools are written in rust and go.-->
|
|
|
|
<!-- rusts clap and gos cobra, CLI argument parsing libraries, help with this.-->
|
|
|
|
## Appendix: the tools
|
|
|
|
This is an extremely unscientific table of command line tools that I have tried,
|
|
have used, or currently use. It is assuredly incomplete, but *should* be broadly
|
|
representative. The date data has been gathered from the first git commit where
|
|
available, wikipedia otherwise, and sorting is by year first, then alphabetical.
|
|
|
|
|tool|year|language|
|
|
|-|-|-|
|
|
|ls|1961|c|
|
|
|cat|1971|c|
|
|
|cd|1971|c|
|
|
|cp|1971|c|
|
|
|man|1971|c|
|
|
|rm|1971|c|
|
|
|grep|1973|c|
|
|
|diff|1974|c|
|
|
|sed|1974|c|
|
|
|bc|1975|c|
|
|
|make|1976|c|
|
|
|vi|1976|c|
|
|
|bourne shell|1979|c|
|
|
|awk|1985|c|
|
|
|screen|1987|c|
|
|
|[bash](https://www.gnu.org/software/bash/)|1989|c|
|
|
|[zsh](https://www.zsh.org/)|1990|c|
|
|
|[vim](https://www.vim.org/)|1991|c|
|
|
|midnight commander|1994|c|
|
|
|ssh|1995|c|
|
|
|[curl](https://github.com/curl/curl)|1996|c|
|
|
|[fish](https://fishshell.com/)|2005|c/rust|
|
|
|[fossil](https://fossil-scm.org/home/doc/trunk/www/index.wiki)|2006|c|
|
|
|[tmux](https://github.com/tmux/tmux)|2007|c|
|
|
|[git](https://git-scm.com/)|2008|c|
|
|
|[go 1.0](https://go.dev/)|2012|go|
|
|
|[fzf](https://github.com/junegunn/fzf)|2013|go|
|
|
|[eza/exa](https://github.com/eza-community/eza)|2014|rust|
|
|
|[neovim](https://neovim.io/)|2015|c|
|
|
|[pueue](https://github.com/Nukesor/pueue)|2015|rust|
|
|
|[rust 1.0](https://www.rust-lang.org/)|2015|rust|
|
|
|[just](https://github.com/casey/just)|2016|rust|
|
|
|[micro](https://micro-editor.github.io/)|2016|go|
|
|
|[nnn](https://github.com/jarun/nnn)|2016|c|
|
|
|[ripgrep](https://github.com/BurntSushi/ripgrep)|2016|rust|
|
|
|[fd](https://github.com/sharkdp/fd)|2017|rust|
|
|
|[bat](https://github.com/sharkdp/bat)|2018|rust|
|
|
|[broot](https://dystroy.org/broot/)|2018|rust|
|
|
|[difftastic](https://difftastic.wilfred.me.uk/)|2018|rust|
|
|
|[hyperfine](https://github.com/sharkdp/hyperfine)|2018|rust|
|
|
|[lazygit](https://github.com/jesseduffield/lazygit)|2018|go|
|
|
|[lsd](https://github.com/lsd-rs/lsd)|2018|rust|
|
|
|[nushell](https://www.nushell.sh/)|2018|rust|
|
|
|[scc](https://github.com/boyter/scc)|2018|go|
|
|
|[sd](https://github.com/chmln/sd)|2018|rust|
|
|
|[git-delta](https://github.com/dandavison/delta)|2019|rust|
|
|
|[grex](https://github.com/pemistahl/grex)|2019|rust|
|
|
|[starship](https://starship.rs/)|2019|rust|
|
|
|[tre](https://github.com/dduan/tre)|2019|rust|
|
|
|[typst](https://typst.app/)|2019|rust|
|
|
|[diskonaut](https://github.com/imsnif/diskonaut)|2020|rust|
|
|
|[helix](https://helix-editor.com/)|2020|rust|
|
|
|[pijul](https://pijul.org/)|2020|rust|
|
|
|[zellij](https://zellij.dev/)|2020|rust|
|
|
|[zoxide](https://github.com/ajeetdsouza/zoxide)|2020|rust|
|
|
|[btop](https://github.com/aristocratos/btop)|2021|c++|
|
|
|[ast-grep](https://github.com/ast-grep/ast-grep)|2022|rust|
|
|
|[yazi](https://github.com/sxyazi/yazi)|2024|rust|
|