Some pearls from my zshrc
Tags: tutorial, linux
Published: 2022-01-08 14:31:10

## Intro:

First of all, why using ZSH instead of bash? Well, I would say that the extensibility as one of most precious assets in the UNIX/Linux community gains a lot when we dive into zshell world. 

Most of the things we are going to see here also work in bash, but I cannot guarantee 100% compatibility

### Refereces:

- https://www.youtube.com/watch?v=bTLYiNvRIVI
- https://github.com/ChristianChiarulli
- https://jdhao.github.io/2019/06/13/zsh_bind_keys/

## Aliases

They are shorter versions of your favorite commands, for example: Open the last neovim edited file:

```sh
# Now you can type in your shell "lvim" 
alias lvim='vim -c "normal '\''0"'
```

If you have `xclip` installed then the aliases are set

```sh
(( $+commands[xclip] )) && {
    alias pbpaste='xclip -i -selection clipboard -o'
    alias pbcopy='xclip -selection clipboard'
}
```

Another useful alias to check your zsh startup time.

```sh
alias timezsh='for i in $(seq 1 10); do time zsh -i -c exit; done'
```

## Keybindings

```sh
# pressing Ctrl+Alt+l will run our previous "alias -> lvim"
bindkey -s '^[^L' 'lvim^M'
```

Press `Ctrl+g` to show your git status
```sh
bindkey -s '^g' 'git status --short^M'
```

To figure out keybindings You can manually find which key code is sent when you press a key. You can use `showkey -a` to print the key codes.

## Widgets

Widgets are some functions that add extra features to the shell, for example, I have one widget to open wherever I have in the clipboard into a neovim session and a shortcut/keybinding associated with that:

```sh
# Edit content of clipboard on vim
function _edit_clipboard(){
    nvim -c '0pu+'
    # I don't know why "xclip -i -selection clipboard -o" does not work
}
zle -N edit-clipboard _edit_clipboard
bindkey '^x^v' edit-clipboard
```

## Autoloaded functions

I have a folder `~/.dotfiles/zsh/autoloaded` with a lot of functions that are autoloaded in the code below:

```sh
MY_ZSH_FPATH=${ZDOTDIR}/autoloaded
fpath=( $MY_ZSH_FPATH $fpath )

if [[ -d "$MY_ZSH_FPATH" ]]; then
    for func in $MY_ZSH_FPATH/*; do
        autoload -Uz ${func:t}
    done
fi
unset MY_ZSH_FPATH
```

## Integrate FZF

What about pressing `Ctrl+o` in your shell and getting a FZF search conveyed to the nvim, and more, if you give up nothing will happen.

In my case I have restricted the range of the FZF search to my `~/.dotfiles` because there I have a wiki with almost everything I have written down for the last couple of years.

```sh
# source:https://stackoverflow.com/a/65375231/2571881
# ~/.dotfiles/zsh/autoload/vif
function vif() {
    local fname
    local current_dir=$PWD
    cd ~/.dotfiles
    fname=$(fzf) || return
    vim "$fname"
    cd $current_dir
}
# https://jdhao.github.io/2019/06/13/zsh_bind_keys/
bindkey -s '^o' 'vif^M'
```

```sh
# send a list of "oldfiles" to FZF
function old(){
    [[ -f /tmp/oldfiles.txt ]] && \rm /tmp/oldfiles.txt
    vim -c 'redir >> /tmp/oldfiles.txt | silent oldfiles | redir end | q'

    local fname

    FILES=()
    # for i in $(awk '/home/ && !/man:/ {print $2}' /tmp/oldfiles.txt); do
    for i in $(awk '!/man:/ {print $2}' /tmp/oldfiles.txt); do
        [[ -f $i ]] && FILES+=($i)
    done

    fname=$(printf "%s\n" "${FILES[@]}" | awk '!a[$0]++' | fzf) || return

    vim "$fname"
}
```

## Performance improviments

There is an important type of file in zsh called **zcompdump**:

zcompdump files are produced to speed up the running of compinit, Which initializes the shell completion in zsh. zcompdump is used by zsh completion system to speed up completion. The lines below are meant to make your zcompdump faster.

First you have to define where will be your `ZSH_COMPDUMP` file located:

```sh
# ~/.zshenv
export ZSH_COMPDUMP="${ZDOTFILES}/.zcompdump"
```

```sh
autoload -Uz zrecompile
autoload -Uz compinit
dump=$ZSH_COMPDUMP

# http://zsh.sourceforge.net/Doc/Release/Conditional-Expressions.html
if [[ -s $dump(#qN.mh+24) && (! -s "$dump.zwc" || "$dump" -nt "$dump.zwc") ]]; then
    compinit -i d $ZSH_COMPDUMP
    zrecompile $ZSH_COMPDUMP
fi
compinit -C
```

### Lazy loading 

If you search about zsh performance improvements you will see some mentions about lazy loading nvm, npm and nodejs.

The actual nvm, node and so on are inside a function with their names, on those functions we call them, which means, only at first run they will be loaded.

```sh
#  virtual machine management
nvm() {
    unfunction $0
    export NVM_DIR=~/.nvm
    [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"  # This loads nvm
    nvm "$@"
}

node() {
    unfunction $0
    export NVM_DIR=~/.nvm
    [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"  # This loads nvm
    node "$@"
}

npm() {
    unfunction $0
    export NVM_DIR=~/.nvm
    [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"  # This loads nvm
    npm "$@"
}
```

To make sure you have set everything ok just run:

```sh
which node
node --version
which node
```

You will see that when you run `which node` it will show your lazy-loading function definition, after runnin `node --version` the node is at this point already loaded, so, when you run `which node` you will see the real node path.

## Some aliases that worth mention:

```sh
# Note: most of these aliases only work on zsh because I am using `$(( $comand[] ))`

# the below alias uses pbpaste alias mentioned earlier
# and defines an anonymous function 
# yt-dlp is a youtube-dl fork with improviments
alias ya='(){yt-dlp -x --audio-format mp3 -o "%(title)s.%(ext)s" $(pbpaste);}'

(( $#commands[(I)(trash|gio)] == 2 )) && alias trash='gio trash'

# https://askubuntu.com/a/63203/3798
# https://www.cnx-software.com/2016/12/16/compress-decompress-files-faster-with-lbzip2-multi-threaded-version-of-bzip2/
(( $+commands[lbzip2] )) && alias tar='tar --use-compress-program=lbzip2'

##alias upgrade='sudo pacman -Syyu'
alias upgrade='doas xbps-install -Suv'
alias xi='doas xbps-install -Sy'
alias xq='doas xbps-query -Rs'
alias xr='doas xbps-remove -R'

# Just in case you mess your vim settings use this
alias vinone="nvim -u NONE -U NONE -N -i NONE -c 'set mouse=a| syntax on | set nu'"

alias mkcd='(){mkdir -p "$1"; cd "$1"}'
# using trans (translator)
(( $+commands[trans] )) && {
    alias pt='(){trans -b en:pt "$1";}'
    alias en='(){trans -b pt:en "$1";}'
}

(( $+commands[perl-rename] )) &&  {
    alias prename='perl-rename'
    alias rename='perl-rename'
}

# to fix utf-8 filenames, see more here: https://stackoverflow.com/a/26941707/2571881
alias wget='wget --restrict-file-names=nocontrol'

```

## Function to add plugins on zsh

```sh
function zsh_add_plugin() {
    PLUGIN_NAME=${1##*/}
    [[ -d $ZDOTDIR/plugins ]] || mkdir "$ZDOTDIR/plugins"
    if [ -d "$ZDOTDIR/plugins/$PLUGIN_NAME" ]; then
        zsh_add_file "plugins/$PLUGIN_NAME/$PLUGIN_NAME.plugin.zsh" || \
        zsh_add_file "plugins/$PLUGIN_NAME/$PLUGIN_NAME.zsh"
    else
        git clone "https://github.com/$1.git" "$ZDOTDIR/plugins/$PLUGIN_NAME"
    fi
}
```

Now you can put on your zshrc:

`zsh_add_plugin "zsh-users/zsh-autosuggestions"`


## Making this post better

If you have any suggestions give us some comment below and we will love to talk about it!