terminal

Introduction

Throughout my career I have used Windows, Linux, Mac and Windows again, and each year that passes I discover myself using the terminal more and more. Most of my work is done there, except when doing some heavy coding. Therefore I believe it is important to have the same flow no matter which operative system is in use in order not to lose productivity.

Back when using Windows, the WSL (Windows Subsystem for Linux) did not exist, and therefore the portability between Unix and Windows was unthinkable. Now with WSL, one is able to install brew and manage all of the non-GUI related programs in the same way that on Mac and Linux.

This guide is very opinionated towards what my flow is, however, you can pick and choose what you prefer. There are some sections that are only Windows or Mac related so do the ones that are applicable to your operative system.

[Windows] Enable WSL

As mentioned before, enabling the Linux sub-system is the starting point for Windows.

  1. Open a cmd terminal as administrator and execute: wsl --install.
  2. After logging in, execute: sudo apt update; sudo apt upgrade.

A reboot might be needed after the 1st or 2nd step. When that is done, open the Windows Terminal, you can download it from the microsoft store if you don’t have it, and set up Ubuntu as your default profile from the preferences menu.

From now on, every time you have to execute a command you will do it on the Windows Terminal with the Ubuntu profile, unless the guide says otherwise. The Ubuntu profile will also be later configured in Visual Studio Code as the default terminal.

Fonts

The terminal tooling, that is going to be installed later, requires quite a lot of support for font icons such as folders, home, branches, etc; therefore a complete font is needed. Download and install CaskaydiaCove NF.

Homebrew

Brew is the preferred package manager on Mac and it also works on Ubuntu, meaning it also works on WSL. Install Homebrew by executing the following command either on the Windows Terminal or the default terminal on Mac / Linux.

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

After installing it, you will notice a suggestion message to execute two commands, these contain path related information, so be sure to copy paste from your terminal. In my case they looked like this:

echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' >> /home/pabmo/.profile
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"

ZSH, jump and OhMyPosh

OhMyPosh is a modern replacement for oh-my-zsh or oh-my-fish. It is built in Go and the configuration is described in a json file which is very understandable and portable. Create one you like, use it for all your environments, share it with your friends and community!

Jump, installed in the 5th step, allows one to jump from directory to directory; in other words, if you visit the path user/documents/devandchill you can later jump from any other directory to the mentioned one executing j devand and so.

Execute in order:

  1. brew install zsh.
  2. Follow instructions (if any) to make zsh default shell instead of bash.
  3. brew install zsh-completions.
  4. brew install zsh-syntax-highlighting.
  5. Save the path that brew reports after installing the syntax highlighting.
  6. brew install jump.
  7. brew tap jandedobbeleer/oh-my-posh && brew install oh-my-posh.

In your terminal create the file ~/.zshrc if it does not yet exists and add the contents below. Feel free to remove the parts annotated with ## OPTIONAL.

## MAKE HISTORY TO BE PRESERVED FOR SEARCH
HISTFILE=~/.zsh_history
HISTSIZE=10000
SAVEHIST=10000
setopt appendhistory

## UP AND DOWN SEARCH HISTORY BEGINNING WITH BUFFERED WORD
## https://superuser.com/a/418299
bindkey '\e[A' history-beginning-search-backward
bindkey '\e[B' history-beginning-search-forward

## OPTIONAL: ALIASES
alias kb='kubectl'
alias git='LANG=en_GB git'
alias dcd='docker compose down -v --remove-orphans'
alias dcu='docker compose pull; docker compose up -d'
alias me='eval $(minikube -p minikube docker-env)'
alias uuid='uuidgen | tr '\''[:upper:]'\'' '\''[:lower:]'\'' | tee /dev/stderr | pbcopy'
alias gorun='env $(cat local.env) go run cmd/main.go'
alias gotest='env $(cat local.env) go test -v -tags=integration --count=1 ./...'

## EXPORTS
export GPG_TTY=$(tty)

## OPTIONAL: EXPORTS - MAY NEED DIRECTORY MODIFICATIONS
export GOPATH=$HOME/go
export DOTNET_HOME=/usr/local/share/dotnet/dotnet
export PATH=$PATH:$GOPATH/bin:$DOTNET_HOME/bin

## ZSH COMPLETIONS
if type brew &>/dev/null; then
    FPATH=$(brew --prefix)/share/zsh-completions:$FPATH
    autoload -Uz compinit
    compinit
fi

## OPTIONAL: .NET COMPLETIONS
_dotnet_zsh_complete()
{
  local completions=("$(dotnet complete "$words")")
  reply=( "${(ps:\n:)completions}" )
}
compctl -K _dotnet_zsh_complete dotnet

## OPTIONAL: KUBERNETES AUTOCOMPLETE
source <(kubectl completion zsh)

## ENABLE JUMP
eval "$(jump shell)"

## OH MY POSH
eval "$(oh-my-posh --init --shell zsh --config '~/ohmyposhv3.json')"

## SYNTAX HIGHLIGHT - GOES AT THE END
## USE THE PATH SAVED FROM THE 4TH STEP
source /usr/local/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh

As you can see on the OhMyPosh line, the configuration is being loaded from the specified path: --config '~/ohmyposhv3.json'. Adjust that if you want, and in the path chosen create the following json file:

{
    "$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json",
    "blocks": [
        {
            "type": "prompt",
            "alignment": "left",
            "segments": [
                {
                    "type": "session",
                    "style": "diamond",
                    "leading_diamond": "\uE0B6",
                    "trailing_diamond": "",
                    "background": "#100e23",
                    "foreground": "#ffffff",
                    "properties": {
                        "template": "{{ .UserName }}"
                    }
                },
                {
                    "type": "kubectl",
                    "style": "powerline",
                    "powerline_symbol": "\uE0B0",
                    "foreground": "#000000",
                    "background": "#ffffff",
                    "properties": {
                        "template": "{{.Context}} {{.Namespace}}"
                    }
                },
                {
                    "type": "path",
                    "style": "powerline",
                    "powerline_symbol": "\uE0B0",
                    "foreground": "#100e23",
                    "background": "#91ddff",
                    "properties": {
                        "home_icon": "\uF7DB",
                        "folder_icon": "\uF115",
                        "folder_separator_icon": " \uE0B1 ",
                        "style": "mixed"
                    }
                },
                {
                    "type": "git",
                    "style": "powerline",
                    "powerline_symbol": "\uE0B0",
                    "foreground": "#193549",
                    "background_templates": [
                        "{{ if .Working.Changed }}#fffb38{{ else }}#95ffa4{{ end }}"
                    ],
                    "properties": {
                        "branch_icon": "\ue725",
                        "fetch_status": true,
                        "fetch_upstream_icon": true,
                        "template": "{{ .UpstreamIcon }}{{ .HEAD }}{{ .BranchStatus }}{{ if .Working.Changed }} \uF044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }}\uF046 {{ .Staging.String }}{{ end }}"
                    }
                },
                {
                    "type": "exit",
                    "style": "powerline",
                    "powerline_symbol": "\uE0B0",
                    "foreground": "#ffffff",
                    "background": "#ff8080",
                    "properties": {
                        "template": "{{ .Text }}"
                    }
                }
            ]
        }
    ],
    "final_space": true
}

[Windows] Windows Terminal

So far, the default profile is configured to be Ubuntu, now you need to configure the font and the font size for that profile. The font should be the previously installed: CaskaydiaCove NF and the size is up to you (but I don’t see much anymore so I use 18px).

You can further customize the theme of the terminal so the background might be transparent, dark, etc.

[Mac] Iterm2

The default MacOS terminal does not support background colors for the segments defined on the OhMyPosh json file. Download iTerm2 instead and enjoy of vertical and horizontal splits as well of other useful features. You can install it with brew install --cask iterm2.

When you have finished the installation, configure the font to be CaskaydiaCove NF and the font size you want. For this, go to preferences (cmd + ,), profiles, default, text.

In order to make option + -> and option + <- go one word forward and backwards you need to follow the instructions here.

iterm2

Kubernetes segment

The OhMyPosh json contains a segment for displaying the current Kubernetes cluster:

{
    "type": "kubectl",
    "style": "powerline",
    "powerline_symbol": "\uE0B0",
    "foreground": "#000000",
    "background": "#ffffff",
    "properties": {
        "template": "{{.Context}} {{.Namespace}}"
    }
},

In case there is no ~/.kube/config file created it will just avoid the segment. If you use Kubernetes you have to install the command line to make this work, execute: brew install kubernetes-cli.

Git segment

The OhMyPosh json also contains a git segment. In case you are not sure if it is installed, execute: brew install git.

[Windows] Installing git on Windows

The git command line installed for WSL is not visible for Windows. This needs to be fixed as OhMyPosh is trying to use the git.exe. To solve this, open a cmd terminal and execute: winget install -e --id Git.Git.

This is just for display purposes, as all the commits you are going to do with the terminal are going to go through the WSL one.


Done!

After finishing with the step above your terminal should be working correctly with the format displaying correctly as well.

You can stop reading now that your terminal is working, or continue reading for:

  • Sign git commits.
  • Configure Visual Studio Code.
  • Useful non-GUI applications
  • Useful GUI applications.

Sign git commits

Regardless of your operative system, you can customize your global git configuration and enable signed commits . Follow the steps:

  1. Execute brew install gnupg.
  2. If you are on Mac, execute also: brew install pinentry-mac.

You can now follow the steps described here for generating a GPG key and adding it to Github.

In your terminal, create the file ~/.gitconfig. Here you can add your basic git user data and your GPG key ID, indicating that you always want to sign your commits:

[user]
    name = Pablo Morelli
    email = [email protected]
    signingKey = <SOME-KEY-ID>
[gpg]
    program = gpg
[commit]
    gpgsign = true
[credential]
    helper = store

You can also create the file ~/.gnupg/gpg-agent.conf to add customizations like avoiding the gpg agent to ask you for your GPG passphrase every time you commit with default-cache-ttl 3600.

Configure Visual Studio Code

Visual studio code is the default text editor and programming IDE for most of the developers nowadays. The way it allows one to configure both settings and keyboard shortcuts as a JSON makes it possible for developers to port configuration from a machine to other.

  • MacOS: Execute: brew install --cask visual-studio-code.
  • Windows: On a cmd terminal, execute: winget install -e --id Microsoft.VisualStudioCode.

Settings

Open VSCode and access the command pallette either with Cmd + Shift + P or Control + Shift + P. Write Open Settings (JSON) and replace the json with the following:

{
    "search.useIgnoreFiles": false,
    "terminal.integrated.defaultProfile.osx": "zsh",
    "terminal.integrated.defaultProfile.windows": "Ubuntu (WSL)",
    "terminal.integrated.fontFamily": "CaskaydiaCove NF",
    "terminal.integrated.fontSize": 18,
    "terminal.integrated.copyOnSelection": true,
    "files.trimTrailingWhitespace": true,
    "files.insertFinalNewline": true,
    "files.trimFinalNewlines": true,
    "editor.fontLigatures": true,
    "editor.fontSize": 18,
    "editor.fontFamily": "CaskaydiaCove NF",
    "editor.formatOnSave": true,
    "diffEditor.ignoreTrimWhitespace": false,
    "explorer.confirmDelete": false,
    "go.formatTool": "goimports",
    "go.useLanguageServer": true,
    "go.toolsManagement.autoUpdate": true,
    "go.lintTool": "golangci-lint",
    "go.buildTags": "integration",
    "workbench.iconTheme": "material-icon-theme",
    "extensions.ignoreRecommendations": false,
    "window.zoomLevel": 1,
    "security.workspace.trust.untrustedFiles": "open",
    "liveshare.presence": true,
    "go.testEnvFile": "${workspaceFolder}/local.env"
}

Both terminal.integrated.defaultProfile.osx and terminal.integrated.defaultProfile.windows can coexist, but remove the one that does not apply to your environment if you don’t like having both.

Feel free to remove workbench.iconTheme if you do not wish to install the Material Icon Theme extension described on the section below, and same for the liveshare.presence in case you do not wish to install it either.

The terminal.integrated.fontFamily should be the CaskaydiaCove NF as configured on iTerm2 / Windows Terminal; but feel free to change your editor.fontFamily as you see fit. Also feel free to change the font size on both parts.

All the go.* settings might not be needed for you if you don’t plan using Go, so you can remove them.

Keyboard shortcuts

This is very opinionated, but I am used to two things:

  1. Going back to a previous tab using cmd/ctrl + -, instead of zooming out a window.
  2. Getting the autocomplete suggestions to prompt when I press cmd/ctrl + enter instead of space.

Open the command pallette once again and write Open Keyboard Shortcuts (JSON), replace the json with the one shown below. If you are using Windows replace cmd with ctrl.

[
    {
        "key": "cmd+-",
        "command": "workbench.action.navigateBack"
    },
    {
        "key": "cmd+[Enter]",
        "command": "editor.action.quickFix",
        "when": "editorHasCodeActionsProvider && editorTextFocus && !editorReadonly"
    },
]

Extensions

Go to the extensions tab and add Material Icon Theme and Live Share. Optionally, you can find below other extensions I use:

  • C#: Lint and syntax support.
  • C# Extensions: Useful right click actions such as create class, etc.
  • Code Spell Checker: Good for not native english speakers.
  • Diff: Shows the difference between two files.
  • Go: Lint and syntax support.
  • HashiCorp Terraform: Lint and syntax support.
  • String Manipulation: Provides functionality like reversing a word, etc.
  • Trailing Spaces: Highlights trailing spaces at the end of each line.
  • vscode-base64: Decode and encode utility.

Useful non-GUI applications

Below you can find some utilities that I often use and are compatible with all the operative systems. Install the ones you need.

Programming languages

  1. brew install go.
  2. brew install golangci-lint: Linter for golang.
  3. brew install [email protected].
  4. brew install --cask dotnet-sdk: Only for MacOS.

Installing .NET on Windows (and WSL):

  1. On a cmd terminal, execute: winget install -e --id Microsoft.dotnet.
  2. For WSL follow the steps here.

Docker

  • Mac: brew install --cask docker.
  • Windows: On a cmd terminal execute: winget install -e --id Docker.DockerDesktop. Make sure to enable WSL 2 while installing it, in case it never prompt check on preferences that Use the WSL 2 based engine is enabled.

For both OS, go to preferences and tick the Use Docker Compose V2 box, so you can now use docker compose instead of the old docker-compose.

Kubernetes related

  1. brew tap johanhaleby/kubetail && brew install kubetail: Displays the output of all containers sharing names or labels.
  2. brew install istioctl: Istio command line utility.
  3. brew install minikube: Your own Kubernetes cluster.

Other utilities

  1. brew install git-crypt: Commit encrypted secrets in repositories.
  2. brew install hugo: The framework used to build this blog.
  3. brew install vegeta: Load testing utility for HTTP.
  4. brew install yq: Manipulate yaml files.
  5. brew install libpq: Adds psql to execute postgres database related commands.
  6. brew install terraform: Infrastructure as a code utility.

Ngrok

Reverse proxy utility for testing localhost callbacks from chat bots or others related.

Useful GUI applications

MacOS:

  1. brew install --cask slack.
  2. brew install --cask whatsapp.
  3. brew install --cask postman: Suite for testing HTTP requests.
  4. brew install --cask dbeaver-community: Visual interface for database querying.

Windows, on a cmd terminal:

  1. winget install -e --id SlackTechnologies.Slack.
  2. winget install -e --id WhatsApp.WhatsApp.
  3. winget install -e --id Postman.Postman.
  4. winget install -e --id dbeaver.dbeaver.
  5. winget install -e --id 7zip.7zip: If you need to decompress .rar.

Closing line

If you are setting up your computer from zero, a nice reminder: