Apollon Development

Zsh on Windows

First of all, I don't take part in the OS wars, thus there is nothing wrong in trying hard to get decent unix shell on Windows. By default Windows provides us with cmd.exe which hardly serves a command line interface for any but very simple tasks, as well as with PowerShell, which is much more versatile tool. Yet, instead of being a shell, it's a heavy solaris looking console, bloated with tons of badly documented scripts to interact with Windows functionality that are part of the PS dynamic libraries and not independent applications which you would find in POSIX.

Working with three (or even four, if you count BSD and Linux separately) environments simultaneously, my choice was ZSH, which I won't explain in details in this article except that I highly recommend it even for Windows.

Cygwin

Lets start off by getting the Cygwin installer, which we'll need it setup basic POSIX environment on our Windows machine. By default, Cygwin downloads basic set of packages, but we'll need a few more to be able to proceed. Make sure you install your favourite editor (ie nano) as well as some file download tool (ie wget).

The reason I don't download all prerequisites now is because I much more prefer to use apt-cyg helper which mimics debian's apt.

apt-cyg  

Run the Cygwin Terminal which will spin off with bash shell and run the following commands

wget rawgit.com/transcode-open/apt-cyg/master/apt-cyg
install apt-cyg /bin

Cmder

Installing cmder will give you a neat wrapper around shells with plenty of options to change keybindings, themes and whatnot. Head to their page and get the mini version as are going to build git binaries ourselves. That's because we don't want to have the overhead from git for windows version and we need to run version 2.21 or above, which, at the time of writing, is not included in cmder's full package.

Unpack the program to a convenient directory and run it. By default cmder will open Window's cmd.exe, yet we need to access bash. It also won't know about location of your bash.exe as it'll be looking for it in a full package directory. To make it automatically grab it from the cygwin's location, open cmder settings, navigate to startup > tasks, select all predefined tasks, remove them and then push add/refresh default tasks.

ConEmu settings window

You will get an entry named Bash::CygWin bash. Close the settings and create a new cygwin bash console.

Zsh

Installing zsh is as simple as running

apt-cyg install zsh

But it's not ready to be used yet. To make it look good we need some zsh extensions which we'll install using antibody. Unfortunately antibody doesn't have a pre-compiled binaries for Win32 so we'll have to build them ourselves.

Building Git

At the time of writing this article, cygwin doesn't have pre-compiled git v2.21+ binaries. We need this version as it includes long awaiting fix for Windows paths under cygwin which lack of will cause trouble when running golang builder, which needed to build antibody.

Firstly, the prerequisites

apt-cyg install make gcc-core gettext gettext-devel libiconv-devel openssl-devel zlib-devel libcurl-devel libexpat-devel

Some of those packages above installed git for us, so we need to remove it

apt-cyg remove git

Now we're ready to build the binaries

wget https://github.com/git/git/archive/v2.21.0.tar.gz
tar -zxvf v2.21.0.tar.gz
cd git-2.21.0/
make prefix=/usr/local
make install prefix=/usr/local

Make sure that you are running the proper version

git version

Building antibody

Get and install golang binaries. You might want to reboot Windows now to make sure Go is in your $PATH or just add it yourself for this session.

export PATH="/cygdrive/c/Go/bin:$PATH"

Now load go environment variables

source <(go env)

Download antibody

git clone https://github.com/getantibody/antibody

Before building it, we need to do some changes to the antibody source code. That's because the shell scripts it's generating contain windows paths which zsh won't understand.

Open antibody/shell/init.go file and replace the Init function with code below

func Init() (string, error) {
	executable := os.Getenv("ANTIBODY_BIN")
	var template = template.Must(template.New("init").Parse(tmpl))
	var out bytes.Buffer
	err := template.Execute(&out, executable)
	return out.String(), err
}

Then, open antibody/bundle/zsh.go file and replace

return strings.Join(lines, "\n"), err

with

return strings.ReplaceAll(strings.ReplaceAll(strings.Join(lines, "\n"), os.Getenv("CYGWIN_ROOT"), ""), "\\", "/"), err

Time to build the binary

cd antibody/
go build
cp antibody.exe /usr/local/bin/

And make that sure antibody is installed

antibody

Vital environmental variables

It's important that we set a few environmental variables in the .zshrc file so that antibody doesn't get lost in Windows environment.

Here's the basic .zshrc you'll need. Make sure that you adjust the cygwin path if you installed in on a different drive.

#!/bin/zsh
unset LSCOLORS
export HISTFILE="$HOME/.zsh_history"
export HISTSIZE=1000
export SAVEHIST=1000
export CLICOLOR=1
export CLICOLOR_FORCE=1
export CYGWIN_ROOT="C:\\cygwin64"
export ANTIBODY_HOME="cygwin64/$HOME/.antibody"
export ANTIBODY_BIN="/usr/local/bin"

setopt hist_ignore_all_dups 
setopt hist_reduce_blanks 
setopt inc_append_history 
setopt share_history 

autoload -Uz promptinit; promptinit

source <(antibody init)

PURE_GIT_PULL=1

antibody bundle < ~/.zsh_plugins

As well as ~/.zsh_plugins

zsh-users/zsh-completions
zsh-users/zsh-syntax-highlighting
zsh-users/zsh-history-substring-search
mafredri/zsh-async branch:no-zpty
sindresorhus/pure

Fonts

As a bonus, you might want to install powerline fonts that will support characters that pure theme is using.

Myself I use Roboto Mono as the main font and Menlo as a unicode font. Here's how this look like in cmder settings

And here goes the final result of our new Windows Z-shell

Z-shell