Compare commits
4 commits
18d9d70cea
...
a0ba7c8f06
Author | SHA1 | Date | |
---|---|---|---|
a0ba7c8f06 | |||
d8bd99e013 | |||
f85c29c2d2 | |||
189e095c16 |
1 changed files with 406 additions and 0 deletions
406
2025-06-05_zsh-gnu-stow.md
Normal file
406
2025-06-05_zsh-gnu-stow.md
Normal file
|
@ -0,0 +1,406 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
date: 2025-06-05
|
||||||
|
title: zsh and GNU stow
|
||||||
|
tags:
|
||||||
|
|
||||||
|
- software
|
||||||
|
- linux
|
||||||
|
- development
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
In [my last post exploring `nvim`](https://blog.mcknight.tech/2025/05/21/nvim/), I mentioned some potential next projects on my agenda.
|
||||||
|
Well, I wasted no time continuing down the path of trying to perfect my shell experience. I very quickly updated my
|
||||||
|
[dotfiles repository](https://forge.mcknight.tech/d_mcknight/dotfiles) to be compatible with GNU `stow` and then went on to work on my
|
||||||
|
`.zshrc` file. Neither of these are major projects, so I figured they can share this one post.
|
||||||
|
|
||||||
|
## GNU stow
|
||||||
|
|
||||||
|
There are a few ways to use GNU stow and I always recommend people to
|
||||||
|
[RTFM](https://www.gnu.org/software/stow/manual/stow.html#Invoking-Stow) if you ever run into problems or have questions about
|
||||||
|
CLI arguments. Alternatively, this package is old and stable enough that Claude or ChatGPT can easily answer any questions you
|
||||||
|
may have. For my use, I am [already keeping my dotfiles](https://blog.mcknight.tech/2024/06/21/Dotfiles/) in `~/.dotfiles`, so
|
||||||
|
it makes sense for me to make that repository look like my home directory. By default, `stow` will apply the contents of
|
||||||
|
my stow directory (`~/.dotfiels`) to its parent directory (`~/`).
|
||||||
|
|
||||||
|
You can see my [dotfiles repository](https://forge.mcknight.tech/d_mcknight/dotfiles/src/commit/e23e66f801b0549d6195d7115ed6f033ed4318e6)
|
||||||
|
now contains the same files it did before, but they are organized as if the repository root is my Home directory. One potential downside
|
||||||
|
of this organization is that it adds complexity if I wanted to apply only specific dotfiles or directories, but I can't think of anything
|
||||||
|
here that I would want to selectively apply to any environments. It is also worth noting that I had to remove any existing files or
|
||||||
|
symlinks before running `stow .` from my `~/.dotfiles` directory, otherwise `stow` would refuse to overwrite existing files. There may be
|
||||||
|
an argument to force overwrite destination files, but I prefer to manually delete things, just to make sure I'm not deleting/overwriting
|
||||||
|
something I want to keep.
|
||||||
|
|
||||||
|
### Some dotfiles updates
|
||||||
|
|
||||||
|
There are a few updates to my dotfiles that I never documented in my
|
||||||
|
[original dotfiles post](https://blog.mcknight.tech/2024/06/21/Dotfiles/), or [Neovim post](https://blog.mcknight.tech/2025/05/21/nvim/).
|
||||||
|
This may not be exhaustive, but here are some of the highlights:
|
||||||
|
|
||||||
|
#### `alacritty.toml`
|
||||||
|
|
||||||
|
I have been using [Alacritty](https://alacritty.org/) for my regular terminal emulator,
|
||||||
|
so I have [some customizations](https://forge.mcknight.tech/d_mcknight/dotfiles/src/commit/e23e66f801b0549d6195d7115ed6f033ed4318e6/.config/alacritty/alacritty.toml)
|
||||||
|
I like to apply. Below is my configuration with annotations explaining everything.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[general]
|
||||||
|
# Apply a GitHub dark theme for a consistent look
|
||||||
|
import = ["./github_dark_high_contrast.toml" ]
|
||||||
|
|
||||||
|
[colors.primary]
|
||||||
|
# Override background to a neutral dark color
|
||||||
|
background = "#111111"
|
||||||
|
|
||||||
|
[colors.normal]
|
||||||
|
# I picked this color when configuring tmux, override terminal text color to match
|
||||||
|
cyan = '#008b8b'
|
||||||
|
|
||||||
|
[font.normal]
|
||||||
|
# Use a Nerd Font for extra symbols. I have this included in my `dotfiles` repository
|
||||||
|
family = 'JetBrainsMono Nerd Font Mono'
|
||||||
|
style = 'Regular'
|
||||||
|
|
||||||
|
[cursor]
|
||||||
|
# I prefer a blinking input cursor
|
||||||
|
blink_interval = 500
|
||||||
|
blink_timeout = 0
|
||||||
|
|
||||||
|
[cursor.style]
|
||||||
|
# I tried `Underline`, but I think I prefer the default block
|
||||||
|
blinking = "Always"
|
||||||
|
#shape = "Underline"
|
||||||
|
|
||||||
|
[window]
|
||||||
|
# Make the window slightly transparent to peek at what's behind
|
||||||
|
opacity = 0.95
|
||||||
|
# Hide the top bar because I never close the terminal and use gTile to position it on screen
|
||||||
|
decorations = "None"
|
||||||
|
# I have `level` set, but it doesn't appear to do anything in Cinnamon :/
|
||||||
|
level = "AlwaysOnTop"
|
||||||
|
# dynamic_padding splits extra vertical/horizontal space which makes tmux and nvim status bars look a little nicer
|
||||||
|
dynamic_padding = true
|
||||||
|
```
|
||||||
|
|
||||||
|
#### JetBrains Nerd Font
|
||||||
|
|
||||||
|
[Nerd Fonts](https://www.nerdfonts.com/font-downloads) let you get a consistent font
|
||||||
|
that includes extra characters like filetype icons, emojis, and ligatures (special
|
||||||
|
characters for things like `==`, `->`, and other character combinations). Since I
|
||||||
|
have this configured in my terminal config, it makes sense to make sure the font is
|
||||||
|
always available so I just include it in my dotfiles repository.
|
||||||
|
|
||||||
|
## zsh
|
||||||
|
|
||||||
|
[`zsh`](https://www.zsh.org/) is a shell, like [`bash`](https://www.gnu.org/software/bash/),
|
||||||
|
but with some different features that are interesting. It's worth nothing that I fully intend on using `bash`
|
||||||
|
for scripting since it is far more ubiquitous than `zsh` and I am more familiar with it and its quirks.
|
||||||
|
I will also note that zsh is NOT a [POSIX shell](https://en.wikipedia.org/wiki/POSIX);
|
||||||
|
this is a common complaint that I see. Personally, I am okay with this since I
|
||||||
|
haven't run into any issues thus far and `zsh` is good enough to be the default shell in popular
|
||||||
|
operating systems, including macOS and TrueNAS.
|
||||||
|
|
||||||
|
There are a couple reasons I decided to try `zsh`, the first being tab completion which
|
||||||
|
I find helpful when completing a path or command where there are only a couple options to tab through.
|
||||||
|
I also wanted to try out some of the plugins and the configuration, which I find much easier to work with,
|
||||||
|
compared to `bashrc`.
|
||||||
|
|
||||||
|
### RC Files
|
||||||
|
|
||||||
|
[Run Commands files](https://en.wikipedia.org/wiki/RUNCOM) are basically files that
|
||||||
|
are executed when a program starts. I
|
||||||
|
[previously detailed my `.bashrc` file](https://blog.mcknight.tech/2024/03/27/Shell-Customizations/#BASH-Configuration),
|
||||||
|
which is executed whenever I open a new `bash` shell.
|
||||||
|
I wanted to experiment with `zsh` configuration because it feels a little more modern
|
||||||
|
and powerful to me compared to `bash`. For example, my `bash` shell prompt looks like:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
color_off="\[\033[0m\]" # Text Reset
|
||||||
|
|
||||||
|
# Regular Colors
|
||||||
|
black="\[\033[0;30m\]"
|
||||||
|
red="\[\033[0;31m\]"
|
||||||
|
green="\[\033[0;32m\]"
|
||||||
|
yellow="\[\033[0;33m\]"
|
||||||
|
blue="\[\033[0;34m\]"
|
||||||
|
purple="\[\033[0;35m\]"
|
||||||
|
cyan="\[\033[0;36m\]"
|
||||||
|
white="\[\033[0;37m\]"
|
||||||
|
|
||||||
|
path_color=$blue
|
||||||
|
chrome_color=$purple
|
||||||
|
context_color=$cyan
|
||||||
|
prompt_symbol=@ # 🚀💲
|
||||||
|
prompt='\$'
|
||||||
|
if [ "$EUID" -eq 0 ]; then # Change prompt colors for root user
|
||||||
|
context_color=$red
|
||||||
|
prompt_symbol=💀
|
||||||
|
fi
|
||||||
|
PROMPT_COMMAND='if [[ $? != 0 && $? != 130 ]];then echo -e "⚠️ \a";else echo -e "\a";fi'
|
||||||
|
PS1="$chrome_color┌──"'${debian_chroot:+('${path_color}'$debian_chroot'${chrome_color}')─}${VIRTUAL_ENV:+('${path_color}'$(realpath $VIRTUAL_ENV --relative-to $PWD --relative-base /home)'${chrome_color}')─}'"[${context_color}\u${chrome_color}${prompt_symbol}${context_color}\h${chrome_color}]─(${path_color}\w${chrome_color})\n${chrome_color}└${context_color}${prompt}${color_off} "
|
||||||
|
PS2="$chrome_color└>$color_off "
|
||||||
|
```
|
||||||
|
|
||||||
|
and in zsh:
|
||||||
|
|
||||||
|
```zsh
|
||||||
|
function precmd {
|
||||||
|
# Check previous command output and notify
|
||||||
|
if [[ $? != 0 && $? != 130 ]];then
|
||||||
|
echo -e "⚠️ \a"
|
||||||
|
else
|
||||||
|
echo -e "\a"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$EUID" -eq 0 ];then
|
||||||
|
chrome_color="{red}"
|
||||||
|
else
|
||||||
|
chrome_color="{magenta}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Static prefix
|
||||||
|
prefix="%F$chrome_color┌──[%F{cyan}%n%F$chrome_color@%F{cyan}%m%F$chrome_color]-"
|
||||||
|
|
||||||
|
# Calculate extra path
|
||||||
|
if [[ ${debian_chroot} ]]; then
|
||||||
|
path_extra="(%F{red}${debian_chroot}%F$chrome_color)-"
|
||||||
|
elif [[ ${VIRTUAL_ENV} ]]; then
|
||||||
|
rel_venv=$(realpath $VIRTUAL_ENV --relative-to $PWD --relative-base /home)
|
||||||
|
path_extra="[%F{blue}${rel_venv}%F$chrome_color]-"
|
||||||
|
else;
|
||||||
|
path_extra=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Static suffix
|
||||||
|
suffix="(%F{blue}%~%F${chrome_color})"$'\n'"└%F{cyan}%#%F{white} "
|
||||||
|
|
||||||
|
PROMPT=$prefix$path_extra$suffix
|
||||||
|
PS2="%F$chrome_color└%F{cyan}>%F{white} "
|
||||||
|
```
|
||||||
|
|
||||||
|
I find the `zsh` version to be much more readable and easier to modify, since I have a
|
||||||
|
method to generate the prompt instead of a single variable to cram everything into.
|
||||||
|
I believe I have these two prompts looking identical in all cases and it only took me
|
||||||
|
about an hour to get my `zshrc` working identically to my `bashrc`; this included
|
||||||
|
some refactoring from `.bashrc` into `.bash_aliases` and `.profile`. I also
|
||||||
|
made sure `.profile` is always sourced in `bash` and `zsh` shells to avoid duplicating
|
||||||
|
code in those rc files. I considered using a common `aliases` file, but decided against it since
|
||||||
|
I use different aliases for different shells (i.e. `sudosu` is shell-specific).
|
||||||
|
|
||||||
|
### `zsh` Plugins
|
||||||
|
|
||||||
|
Another interesting feature of `zsh` is that it supports plugins.
|
||||||
|
Now, just like with Neovim, there are a number of different plugin managers that can be
|
||||||
|
used with `zsh`. I don't know if there is a "best" choice, but after some light reading
|
||||||
|
up on the popular options I could find and some [LLM summary comparisons](https://search.brave.com/search?q=zinit+vs+omz&source=desktop&summary=1&conversation=f5495011020a89faf13bf1),
|
||||||
|
I settled on [Zinit](https://github.com/zdharma-continuum/zinit) as a lightweight and
|
||||||
|
apparently maintained option.
|
||||||
|
|
||||||
|
#### OMZ extract
|
||||||
|
|
||||||
|
This convenience command lets me extract files without having to remember the syntax for
|
||||||
|
extracting `.tar.xz`, `.zip`, `.tar.gz`, etc. A simple `extract <file>` is much easier
|
||||||
|
to remember than the specific commands for each compression algorithm.
|
||||||
|
|
||||||
|
#### OMZ colored-man-pages
|
||||||
|
|
||||||
|
This adds some color to man pages which I think makes it a little easier to skim to find
|
||||||
|
CLI args and section headers. Its not the *best* IMO, but something is better than nothing
|
||||||
|
when trying to skim through what can be pretty dense documentation.
|
||||||
|
|
||||||
|
#### OMZ encode64
|
||||||
|
|
||||||
|
It isn't every day that I need to get a b64-encoded representation of a string, but its
|
||||||
|
handy to be able to do so quickly and easily.
|
||||||
|
|
||||||
|
#### OMZ pip
|
||||||
|
|
||||||
|
I like having tab completion for pip. I haven't used it too much yet, but I already see
|
||||||
|
how this will save me from trying to `pip isntall` when I really mean `pip install`. I
|
||||||
|
do this more than I'd like to admit. Other than that, its nice to have reminders for the
|
||||||
|
less commonly used flags.
|
||||||
|
|
||||||
|
#### OMZ sudo
|
||||||
|
|
||||||
|
The Oh My Zsh sudo plugin adds a convenience keybind (`esc`+`esc`) to prepend `sudo` to
|
||||||
|
the current command or the previous command if the input is empty. I find this to be
|
||||||
|
convenient as it is fairly common to re-run the previous command with elevated privileges
|
||||||
|
or to prepend `sudo` if I forgot to start with that (saving 5 keystrokes compared to
|
||||||
|
`sudo !!`)
|
||||||
|
|
||||||
|
#### zsh-autosuggestions
|
||||||
|
|
||||||
|
This plugin feels much like suggestions in an IDE, providing a suggested command completion
|
||||||
|
that can be filled in with a bound key (I am using `Shift`+`Tab`).
|
||||||
|
I find this mapping more convenient than the default `->`, since I can reach it without
|
||||||
|
moving my fingers from the home row and it is easy to remember `tab` and `shift`+`tab`
|
||||||
|
are both a kind of completion.
|
||||||
|
|
||||||
|
#### zsh-syntax-highlighting
|
||||||
|
|
||||||
|
This plugin highlights syntax as you type in a command. This clearly identifies unresolved
|
||||||
|
commands or files to help catch errors before trying to run an incomplete command. It also
|
||||||
|
helps to identify un-escaped characters in a quoted string.
|
||||||
|
|
||||||
|
### `.zshrc`
|
||||||
|
|
||||||
|
Now that I've explained the components, here's my `.zshrc` file in its entirety:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Lines configured by zsh-newuser-install
|
||||||
|
HISTFILE=~/.histfile
|
||||||
|
HISTSIZE=1000
|
||||||
|
SAVEHIST=1000
|
||||||
|
setopt autocd notify
|
||||||
|
unsetopt beep
|
||||||
|
bindkey -v
|
||||||
|
# End of lines configured by zsh-newuser-install
|
||||||
|
|
||||||
|
# SSH completion
|
||||||
|
zstyle ':completion:*:(ssh|scp|ftp|sftp|rsync):*' hosts $hosts
|
||||||
|
|
||||||
|
# The following lines were added by compinstall
|
||||||
|
zstyle :compinstall filename '/home/d_mcknight/.zshrc'
|
||||||
|
|
||||||
|
autoload -Uz compinit
|
||||||
|
compinit
|
||||||
|
# End of lines added by compinstall
|
||||||
|
|
||||||
|
# Source common envvars
|
||||||
|
[ -f ~/.profile ] && source ~/.profile
|
||||||
|
|
||||||
|
# Prompt
|
||||||
|
function precmd {
|
||||||
|
# Check previous command output and notify
|
||||||
|
if [[ $? != 0 && $? != 130 ]];then
|
||||||
|
echo -e "⚠️ \a"
|
||||||
|
else
|
||||||
|
echo -e "\a"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$EUID" -eq 0 ];then
|
||||||
|
chrome_color="{red}"
|
||||||
|
else
|
||||||
|
chrome_color="{magenta}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Static prefix
|
||||||
|
prefix="%F$chrome_color┌──[%F{cyan}%n%F$chrome_color@%F{cyan}%m%F$chrome_color]-"
|
||||||
|
|
||||||
|
# Calculate extra path
|
||||||
|
if [[ ${debian_chroot} ]]; then
|
||||||
|
path_extra="(%F{red}${debian_chroot}%F$chrome_color)-"
|
||||||
|
elif [[ ${VIRTUAL_ENV} ]]; then
|
||||||
|
rel_venv=$(realpath $VIRTUAL_ENV --relative-to $PWD --relative-base /home)
|
||||||
|
path_extra="[%F{blue}${rel_venv}%F$chrome_color]-"
|
||||||
|
else;
|
||||||
|
path_extra=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Static suffix
|
||||||
|
suffix="(%F{blue}%~%F${chrome_color})"$'\n'"└%F{cyan}%#%F{white} "
|
||||||
|
|
||||||
|
PROMPT=$prefix$path_extra$suffix
|
||||||
|
PS2="%F$chrome_color└%F{cyan}>%F{white} "
|
||||||
|
}
|
||||||
|
|
||||||
|
# Aliases
|
||||||
|
alias .=source
|
||||||
|
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
|
||||||
|
alias k9=k9s
|
||||||
|
alias rsync="rsync -e 'ssh -o RemoteCommand=none'"
|
||||||
|
alias sudosu="sudo ZDOTDIR=$(dirname ${0:a}) zsh"
|
||||||
|
alias ll='ls -alFh'
|
||||||
|
alias ls="ls --color=auto"
|
||||||
|
alias lsl="ls --color=auto -lah"
|
||||||
|
alias ssh=ssh
|
||||||
|
# Use tmux for local unelevated shells
|
||||||
|
if [ -z "${SUDO_USER}" ] && [ -z "${SSH_CONNECTION}" ] && [ -z "${TERM_PROGRAM}" ]; then
|
||||||
|
tmux new -A -s local_tmux
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Define a function to use autossh with a custom bashrc
|
||||||
|
function assh() {
|
||||||
|
remote_file=$(mktemp)
|
||||||
|
if $(ssh "$@" "cat > ${remote_file}" < ~/.bashrc > /dev/null 2>&1); then
|
||||||
|
# Successfully copied bashrc to the remote. Source it upon ssh
|
||||||
|
autossh -t "$@" "bash --rcfile ${remote_file}; rm ${remote_file}"
|
||||||
|
else
|
||||||
|
# SSH Config specifies a RemoteCommand; connect normally
|
||||||
|
autossh "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
# Use ssh completion for autossh
|
||||||
|
compdef autossh=ssh
|
||||||
|
compdef assh=ssh
|
||||||
|
|
||||||
|
# Custom dircolors
|
||||||
|
[ -f ~/.dircolors ] && eval "$(dircolors ~/.dircolors)"
|
||||||
|
|
||||||
|
# Kubernetes Completion
|
||||||
|
which kubectl 1> /dev/null && source <(kubectl completion zsh)
|
||||||
|
which helm 1> /dev/null && source <(helm completion zsh)
|
||||||
|
|
||||||
|
# doctl completion
|
||||||
|
which doctl 1> /dev/null && source <(doctl completion zsh)
|
||||||
|
|
||||||
|
# Start in the home directory
|
||||||
|
cd ~
|
||||||
|
|
||||||
|
# Ensure zinit is installed
|
||||||
|
ZINIT_HOME="${XDG_DATA_HOME:-${HOME}/.local/share}/zinit/zinit.git"
|
||||||
|
[ ! -d $ZINIT_HOME ] && mkdir -p "$(dirname $ZINIT_HOME)"
|
||||||
|
[ ! -d $ZINIT_HOME/.git ] && git clone https://github.com/zdharma-continuum/zinit.git "$ZINIT_HOME"
|
||||||
|
source "${ZINIT_HOME}/zinit.zsh"
|
||||||
|
|
||||||
|
# Load zinit plugins
|
||||||
|
zinit snippet OMZP::extract
|
||||||
|
zinit snippet OMZP::colored-man-pages
|
||||||
|
zinit snippet OMZP::encode64
|
||||||
|
zinit snippet OMZP::gh
|
||||||
|
zinit snippet OMZP::pip
|
||||||
|
zinit snippet OMZP::sudo
|
||||||
|
|
||||||
|
zinit light zsh-users/zsh-autosuggestions
|
||||||
|
zinit light zsh-users/zsh-syntax-highlighting
|
||||||
|
|
||||||
|
# Key bindings config
|
||||||
|
KEYTIMEOUT=5
|
||||||
|
# ^[ for esc; ^I for tab
|
||||||
|
bindkey '^[[Z' autosuggest-accept
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Some notes on `autossh`
|
||||||
|
|
||||||
|
I have only been using `autossh` for a couple hours at this point, based on internet recommendations
|
||||||
|
that it will do better at resuming with `tmux` (via `tmux-resurrect`). Based on initial testing, it
|
||||||
|
appears to be working but I don't yet know if it is markedly better than plain `ssh`.
|
||||||
|
|
||||||
|
Not necessarily related to `autossh`, the `assh` function I included allows for connecting to a
|
||||||
|
server and applying my `.bashrc` without making permanent changes to the remote server. This does
|
||||||
|
not apply to connections that use a `RemoteCommand` in the SSH config, which is intentional; I have
|
||||||
|
remotes that run a `tmux` session for remote connections and I wouldn't want to mess with shell
|
||||||
|
configurations when multiple connections will be attaching the same `tmux` session.
|
||||||
|
This also highlights that I still do use `bash` for most of my remote connections, since `bash`
|
||||||
|
is available by default on every Linux distribution I've come across and `zsh` is far less ubiquitous.
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
I don't think my shell configuration will ever be "done", but I've reached a point where I'm
|
||||||
|
satisfied for now. GNU `stow` has simplified my dotfile management and made it easier to
|
||||||
|
manage more configurations as I add tools to my repertoire. I now have `zsh` looking like
|
||||||
|
my `bash` shell and all of my aliases and `PATH` management better organized to minimize
|
||||||
|
redundant code in shell-specific config files. I've enabled a few zsh plugins that create a
|
||||||
|
more pleasant shell experience with extra text highlighting and shortkeys.
|
||||||
|
|
||||||
|
I have no immediate plans for what to work on next, though I
|
||||||
|
[still have some ideas](https://blog.mcknight.tech/2025/05/21/nvim/#What-to-do-next). I may continue my search for a good
|
||||||
|
visual file manager in the terminal, or try out Pop!_OS for its window tiling features,
|
||||||
|
although I'll likely wait for their [Cosmic DE](https://system76.com/cosmic/) to graduate to
|
||||||
|
beta and try that.
|
||||||
|
|
||||||
|
I also still have some [IDE exploration to do](https://blog.mcknight.tech/2025/05/18/Code-Server/#Future-Plans).
|
||||||
|
As I spend more time using `nvim`, I am starting to use it more for coding tasks and it may become my primary "IDE".
|
||||||
|
In any case, I am actively adding to my `nvim` configuration, so I probably have enough thoughts for another post
|
||||||
|
about that.
|
Loading…
Reference in a new issue