Install zsh (without WSL)

Follow these steps to have a native zsh shell on Windows without creating a WSL, including:

  • oh-my-zsh

  • Starship

  • zsh-autosuggestions

  • zsh-syntax-highlighting

  1. Install Git for Windows (https://git-scm.com/install/windows), which will include the git bash.

  2. Set up new profile in Terminal and use as default. In settings.json, for example:

    {
        "commandline": "C:\\Program Files\\Git\\bin\\bash.exe",
        "guid": "{648d1200-3839-452b-81d5-a7d238447a6c}",
        "hidden": false,
        "icon": "C:\\Program Files\\Git\\mingw64\\share\\git\\git-for-windows.ico",
        "name": "git bash",
        "startingDirectory": "%USERPROFILE%"
    },
    
  3. Install zsh (see https://dev.to/pavlosisaris/windows-command-line-revolution-unleash-zsh-and-oh-my-zsh-a-simple-guide-for-developers-271o)

  4. Create C:\Users\<USERNAME>\.bashrc and insert this into it:

    if [ -t 1 ]; then
      exec zsh
    fi
    

    This launches zsh on every start of the git bash.

  5. Install oh-my-zsh: https://github.com/ohmyzsh/ohmyzsh/wiki

  6. Download FiraCode Nerd Font from https://www.nerdfonts.com/font-downloads and install it.

  7. Install Starship.rs (see https://starship.rs/) and append

    # Enable starship.rs
    # ------------------
    eval "$(starship init zsh | sed 's|/c/Program Files/starship/bin/starship.exe|starship|g')"
    

    to your C:\Users\<USERNAME>\.zshrc (create it, if not already existing)

  8. Add starship.exe to your PATH variable e.g. C:\Program Files\starship\bin\starship.exe

  9. Create directory and config file for Starship:

    $ mkdir -p ~/.config && touch ~/.config/starship.toml
    
  10. Copy config from https://starship.rs/presets/nerd-font into your starship.toml.

  11. Install zsh-syntax-highlighting:

    $ git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
    

    and add it to your oh-my-zsh plugins (found inside C:\Users\<USERNAME>\.zshrc):

    plugins=( [plugins...] zsh-syntax-highlighting)
    

    Restart shell to see effects. See also: https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/INSTALL.md#with-a-plugin-manager

  12. Install zsh autosuggestions:

    $ git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
    

    and add it to your oh-my-zsh plugins:

    plugins=( [other plugins...] zsh-autosuggestions )
    

    Restart terminal to see effects.

Everything is now set up.

Install zsh without admin rights

I followed those steps when setting up laptop at Hensoldt, facing the following limitations:

  • no admin rights

  • no WSL

  • not very powerful PC

which lead me to the following target:

  • zsh (initialize via git-bash)

  • zsh-autosuggestions (w/o oh-my-zsh)

as I found oh-my-zsh severy impacted my shell startup time (took at least 3 seconds) and zsh-syntax-highlighting severy impacted input speed(took roughly half a second until a pressed character appeared on the terminal.

  1. Install Git for Windows (https://git-scm.com/install/windows), which will include the git bash.

    Hint

    This action requires admin rights, though IT provided the installation via the internal tool.

  2. Set up new profile in Terminal and use as default. In settings.json, for example:

    {
        "commandline": "C:\\Program Files\\Git\\bin\\bash.exe",
        "guid": "{648d1200-3839-452b-81d5-a7d238447a6c}",
        "hidden": false,
        "icon": "C:\\Program Files\\Git\\mingw64\\share\\git\\git-for-windows.ico",
        "name": "git bash",
        "startingDirectory": "%USERPROFILE%"
    },
    
  3. Download the cygwin installer and run it via

    $ setup-x86_64.exe --no-admin
    

    to allow installation without admin rights. Install any additional packages that you feel necessary (probably most listed in Basic). For the following steps, you also need to install zsh (Z-Shell).

    Add the directory, where you installed all packages to your PATH variable.

    Important

    I eventually reverted all the next steps, as I found the zsh installation and initialization via .bashrc has its shortcomings, despite the efforts. Some steps may still be interesting when using the git-bash.

    The git-bash of course has no support for zsh extensions, though it turned out to be better choice nonetheless. Windows, especially when not having admin rights just sucks and is a waste of time to set up properly for serious software development.

  4. Create C:\Users\<USERNAME>\.bashrc and insert this into it:

    if [ -t 1 ]; then
      exec zsh
    fi
    

    This launches zsh on every start of the git bash.

  5. Create the ~/.zshrc file and insert the following content:

    # replace bash prompt with zsh-compatible version
    setopt prompt_subst
    PROMPT=$'%{\e]0;%n@%m:%~\a%}%F{green}%n%F{red}@%F{yellow}%m %F{magenta}${MSYSTEM} %F{yellow}%~%F{cyan} %f%{%}'
    

    This will create a similar line prompt as in git-bash. Without it, zsh displays the original prompt, which causes encoding problems.

  6. When not using oh-my-zsh and its git plugin, we have to manually add a git prompt which is shown whenever the current directory is within a git repository. The article https://git-scm.com/book/en/v2/Appendix-A%3A-Git-in-Other-Environments-Git-in-Zsh suggests to add this to your .zshrc file:

    autoload -Uz vcs_info
    precmd_vcs_info() { vcs_info }
    precmd_functions+=( precmd_vcs_info )
    setopt prompt_subst
    RPROMPT='${vcs_info_msg_0_}'
    # PROMPT='${vcs_info_msg_0_}%# '
    zstyle ':vcs_info:git:*' formats '%b'
    

    Optionally, you may also add tab-completion for git commands:

    autoload -Uz compinit && compinit
    
  7. Sadly, zsh-syntax-highlighting decreased performance of zsh so much, that it became unusable. Luckily zsh-autosuggestions isn’t quite as heavy on the shell. To install it run

    $ mkdir ~/.zsh && cd ~/.zsh
    $ git clone https://github.com/zsh-users/zsh-autosuggestions
    

    the open .zshrc and add this line:

    # zsh-autosuggestions
    source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
    
  8. If you start the git-bash now, you will notice that Ctrl+Left or Ctrl+Right no longer jump back and forth to the next or previous entered word in the current line. To fix that, we create a new file ~/.bindings and put in this content:

    set enable-bracketed-paste Off
    
    bindkey '^[[1;5C' forward-word
    bindkey '^[[1;5D' backward-word
    bindkey '^[[1;3D' beginning-of-line
    bindkey '^[[1;3C' end-of-line
    

    This will enable the following shortcuts:

    • Ctrl+Left: Jump to beginning of previous word

    • Ctrl+Right: Jump to beginning of next word

    • Alt+Left: Jump to beginning of the line

    • Alt+Right: Jump to end of the line

    Open .zshrc and add this line:

    # source custom key bindings
    source ~/.bindings
    
  9. For git-bash to support the .bindings file, open the Options… in git-bash.exe, navigate to Keys and uncheck the option Esc/Enter reset IME to alphanumeric.

  10. Optionally, attach this function to .zshrc to automatically activate a Python virtual environment when entering a directory, which contains a .venv directory:

    # Auto-activate Python venv if .venv directory exists
    function cd() {
      builtin cd "$@"
    
      if [[ -z "$VIRTUAL_ENV" ]] ; then
        ## If env folder is found then activate the vitualenv
          if [[ -d ./.venv ]] ; then
            source ./.venv/Scripts/activate
          fi
      else
        ## check the current folder belong to earlier VIRTUAL_ENV folder
        # if yes then do nothing
        # else deactivate
          parentdir="$(dirname "$VIRTUAL_ENV")"
          if [[ "$PWD"/ != "$parentdir"/* ]] ; then
            deactivate
          fi
      fi
    }
    
  11. Also optionally, provide additional environment variables, which are not present in this setup otherwise, such as $HOSTNAME:

    # Manually defining env variables
    export SHELL="/usr/bin/zsh"
    export HOSTNAME=$(/usr/bin/hostname)
    export USER=$USERNAME
    

    Add other variables as needed.