Skip to main content

The perfect shell

·1423 words·7 mins
Table of Contents

The older I get the more I enjoy just doing as much as I can in a terminal. There’s something about the lack of distractions, simplicity of the interface, and speed.

And I’m not the only one. Well-loved tools like ls and even bash have been great but faster and better solutions now exist.

So let’s take a look at what my terminal environment looks like in 2023, and see how much of it is written in Rust (spoiler: almost everything).

Terminal Emulator
#

I’m a normie. For years I just used Terminal.app on Mac OS, and when they released Windows Terminal on Windows I just started using that. They mostly did their job and came with decent standards for their systems.

But the Mac terminal had a few shortcomings that I didn’t want to deal with. Its configuration is cumbersome.

So I gave warp.dev a try. It really is incredible. It feels like a whole new terminal usage paradigm. The autocomplete is great, it all looks great, being able to share snippets is super convenient. Overall, it’s a home run, except:

  • It does not support sub-shells, so poetry shell or psql break everything
  • It does not support Vim bindings for input editing
  • Text selection is still cumbersome

Which made me go to the other extreme, Alacritty. Pure Rust multiplatform terminal emulator. As pure an emulator as it gets.

Blazingly fast, super small (5MB), configurable through a .yml file, it was really all I wanted. It took me ~30 minutes sifting through the whole configuration to really make it behave like I expected but it’s been great since then!

Shell
#

I’ve been using zsh for a decade now. Ever since it became the default on Mac OS it made me miss it every time I went back to bash. While it’s less features-packed than fish, its simplicity, extensibility, and plugins made it my favorite.

You know me though, I had to give a shiny new toy a try: enter Nushell.

Nushell is a shell written entirely in Rust where commands output can be structured. It lets you do stuff like this:

nushell example

While grep (or ripgreg as we’ll see later) can do a lot of cool things nushell lets you see command output like it was an SQL table or JSON.

It also comes with a set of great defaults and many other features and is extensible via the nu programming language. It also has the best vim support of any shell I have ever used. And it’s multi-platform, meaning it also works natively on Windows.

But like warp, being shiny and new does come with some downsides:

  • Completions are just not there yet
  • The plugins ecosystem is still very young
  • It’s not bash/zsh and it will take some time to adapt + shell excerpts you see online will require editing to work

Overall, I liked it, but not enough to make the full switch yet. The poor completions was the biggest issue for me. I like it when my shell does my job for me!

Plugins management and completions
#

Ever since I’ve used zsh, I’ve coupled it with oh-my-zsh to manage plugins and themes. It’s been decent even though a lot of plugins I enjoy (syntax highlighting and suggestions) need to jump through a few hoops to be installed.

As I was back to Mac OS I gave fig a second shot. I had quickly installed it years ago on my Macbook Air but uninstalled it as I was not comfortable with it overwriting some of my oh-my-zsh completions and configs.

Honestly, I’m sold. As a completion engine it’s the best solution for most shells. It has great support for most programs all with a sleek interface and a few added bonus:

  • alias management
  • zsh plugins management
  • ssh hosts and plugins management

It works really well for what it does. Interestingly their selling feature, scripts, is the only one I absolutely have no use for.

If fig worked inside nushell and allowed me to fix the completion issues there, I’d switch to nushell, but unfortunately it only supports bash, zsh, and fish.

I currently use the following zsh plugins managed through fig:

  • zsh-vi-mode: of course!
  • zsh-aliases-exa: we’ll talk about exa soon
  • zsh-autosuggestions: it looks cool
  • zsh-syntax-highlighting: it looks super cool
  • git-open: I’m too lazy to remember the right gh command

Prompt and font
#

Of course I used powerlevel10k on zsh like a real 1337 HAX0R. It looks great, is heavily configurable through arcane means, and works well with zsh.

But then I heard about starship:

  • Rust-based == super fast
  • Cross-shell support
  • Tons of features out of the box
  • Easily configurable

As soon as I installed it, I was sold. It’s much easier to install and setup while being faster, having more features, and working on all shells.

Sorry powerlevel10k. You were the best.

With a prompt comes a font. A Nerd Font to be precise.

In the past I used Meslo Nerd Font as it was the recommended one for powerlevel10k. But now I was freed which is usually is a bad idea seeing how much I like to try everything when I have no guidelines.

After way too much experimentation I landed of the JetBrains Mono patched with the complete nerdfonts package. You can easily download it here and I also use it in my IDE.

CLI tools
#

GNU coreutils replacements
#

Use those:

You can go deeper and use the whole coreutils Rust replacement but those try to be compatible the GNU coreutils and therefore don’t add cool new features like making the output readable.

Search#

grep is one of the most useful commands in bash-like shells. So what about using ripgrep, its super-charged Rust cousin?

It’s up to 200 times faster which is great when searching things in huge files. Something that happens often in my line of work!

Its output is also much nicer so there’s that. Use it, love it!

Filesystem jumping and viewing
#

I used z for years now and I honestly can’t use a shell without it. Jumping to directories in a few keystrokes from everywhere is just too convenient.

While re-doing my setup, I came accross zoxide and I knew I had found the holy grail: a Rust re-implementation of z!

Not much to say except that it’s all I ever wanted and it’s perfectly cross-platform thanks to Rust. My oxydation is well underway.

I’m also using joshuto relatively regularly to move files around. It’s a ranger-like terminal file manager, except it works as it’s in Rust.

broot is another nice file explorer in Rust, more focused on finding things inside your repo.

Documentation
#

tldr is a godsend for many commands. Even with fig autocomplete, having a short documentation helps so much!

It’s unfortunate that it’s in Typescript though, so… What about using tealdeer, the Rust rewrite?

I’m sure you’re starting to notice a pattern here.

Git
#

lazygit has completely supplanted my use of the VSCode interface or git CLI. It’s very fast and offers easy access to all the git features I use!

This is one of the few programs where there’s no great Rust equivalent, so I’ll keep using it for the forseeable future. It’s just too good!

Tabs and sessions
#

Alacritty does not support tabs. It does not really change anything for me as I simply open a new window when I need multiple tabs. But what if you actually want tabs in your shell?

Then zellij is your friend. It’s like tmux but with great defaults and a wasteful (but nice) user interface.

I really like it on servers when running background tasks as I find it much more ergonomic than tmux!

Conclusion
#

I’m not a Rust fanatic, but Rust tools are really taking over my terminal. Let’s do a quick recap:

TypeProgramLanguageNotes
Terminal EmulatorAlacrittyRustAlso VSCode emulator
ShellzshCnushell soon 👀
Plugins managerfigRustvi-mode!
PromptstarshipRustWith Nerd Fonts
GitlazygitGo
SearchripgrepRust
Coreutilsbat, exa, dustRust

I’m pretty satisfied about my stack honestly, and the only things I expect to change in the future are:

  • Switch to nushell
  • Switch to warp.dev once it really offers a full Vim-like workflow
  • fig replacement for an open source alternative at some point
  • My terminal file explorer, I can do better!

What are some of your favorite CLI tools that I don’t use yet? Don’t hesitate to ping me @Tolki :D