A Guide to Overengineering a Windows Terminal
Tags: beginners, windows, tutorial, powershell
Published: 2022-06-04 08:13:28

For decades, Windows users have been made fun of by the Linux community for the lack of a cool terminal (among other things). Well, it's about time we fight!

<img src="https://c.tenor.com/WRRQ9hWToPsAAAAd/aot-snk.gif" />

In this article, we will go through setting up a development workflow in the Windows terminal.

## Prerequisites

- Know how to type
- Windows 10/11 (Some things may not work for you in this article if you are on some other version)
- (Optional) Know Basic Unix Commands such as `cd`, `mkdir`, etc

## What will we be doing

We will set up the following:

1. Powershell
2. Nerd Fonts
3. Theme
4. Scoop
5. z Directory Jumper
6. Terminal Icons
7. Node & Git
8. Neovim
9. Oh-My-Posh
10. Autocomplete
11. Aliases
12. Utilities

Well, then, let's get started!

## Things to remember during the article

1. `~` stands for your root or home directory, the default directory where the terminal will generally open.
2. If anything doesn't work even after installing/configuring just close and reopen the terminal.
3. The command pallete opens with `ctrl+shift+p`.
4. Terminal settings open with `ctrl+,`

## Getting Started

### Powershell

First of all, let's install Powershell, this is not Windows Powershell that comes with Windows. You will have to go to the Microsoft Store and search for it, it's free so don't worry.

After you have done that open Terminal (not PowerShell or Command Prompt), you can search it up, it's pre-installed on your PC.

Press `Ctrl+,` to open settings, here we will set Powershell as our default, it would be Command Prompt in default if you haven’t changed it before.

In the startup menu, change the default profile to PowerShell and save, that's it!

<img src="https://i.ibb.co/Rzt7W2B/Image-1.png" />

### Nerd Fonts

So, what are Nerd Fonts? Nerd fonts let you use font ligatures and more glyphs in general, it's something everyone should use while coding. You might actually be using it without knowing in your IDE/text editor. I used Fira Code for a long time before knowing it was a Nerd Font.

To install a nerd font, first, go to the nerd-fonts [GitHub Repo](https://github.com/ryanoasis/nerd-fonts) and download the zip file of your preferred Nerd Font from the latest release. Extract the zip file and install the fonts. If you have never installed a font before, that’s fine, you can just double-click the `.ttf` files and click on install.

<img src="https://i.ibb.co/848rhtL/Image-2.png" />

I use the JetBrains Mono NF and another of my favorites is Hack NF (NF stands for Nerd Fonts).

### Themes

To change the theme of your terminal, open settings and click on "Open JSON file", this will open the settings.json file for your terminal.

<img src="https://i.ibb.co/RpXTwcF/Image-3.png" />

Now to change the theme you have three options:

1. Choose a theme from the themes already present in the terminal by default
2. Create your own theme from scratch or modify one already present.
3. Use a pre-written theme

I use a pre-written theme, you can find a lot of them [here](https://windowsterminalthemes.dev/) and paste it into your settings.json under “schemes”. Save the file.

Now, go back to your Terminal settings (not settings.json) and choose the theme you just added.

<img src="https://i.ibb.co/TkG8hBz/image-4.png" />

## Terminal Tools

### Scoop

Let's first install [scoop](https://github.com/ScoopInstaller/Scoop), a package manager for Windows. We will be then using scoop to install other tools.

To install scoop run the following in PowerShell:

```bash
winget install scoop
```

This will install scoop. If you are wondering what winget is, it is a package manager that comes by default in Windows 10/11.

In case, you don't have winget do the following:

```bash
iwr -useb get.scoop.sh | iex
```

Now type `scoop` and if it returns an output like the below then all is good.

```text
Usage: scoop <command> [<args>]

Some useful commands are:

alias       Manage scoop aliases
bucket      Manage Scoop buckets
cache       Show or clear the download cache
cat         Show content of specified manifest. If available, `bat` will be used to
            pretty-print the JSON.
checkup     Check for potential problems
cleanup     Cleanup apps by removing old versions
config      Get or set configuration values
create      Create a custom app manifest
depends     List dependencies for an app
download    Download apps in the cache folder and verify hashes
export      Exports (an importable) list of installed apps
help        Show help for a command
hold        Hold an app to disable updates
home        Opens the app homepage
info        Display information about an app
install     Install apps
list        List installed apps
prefix      Returns the path to the specified app
reset       Reset an app to resolve conflicts
search      Search available apps
shim        Manipulate Scoop shims
status      Show status and check for new app versions
unhold      Unhold an app to enable updates
uninstall   Uninstall an app
update      Update apps, or Scoop itself
virustotal  Look for app's hash on virustotal.com
which       Locate a shim/executable (similar to 'which' on Linux)

Type 'scoop help <command>' to get help for a specific command.
```

If it doesn't return an output, just close and reopen the terminal, and it will work.

This is the moment you stop using those installers, now you are a terminal guy. You can even install Mozilla Firefox, just do `scoop install firefox`.

There is also [choco/chocolatey](https://chocolatey.org/) which you can use as a package manager but we will stick with scoop for this article.

### z

[z](https://github.com/badmotorfinger/z) is a directory jumper. What is a directory jumper? Let's say you are in the directory `~/Desktop/Development/NextJS/tutorial`, and you want to go to `~/SomewhereElse/Products/Product1/prod-website`, the one way of doing this in your terminal would be this:

```bash
cd ../../../../

cd SomewhereElse/Products/Product1/prod-website
```

This looks small but you don't always remember where all your projects are so add 4-5 more commands in there. This wastes our time, especially over a prolonged period. This is where a directory jumper comes in, with just a single command you can go from one project to another.

Let's take the above example this time you just have to do this (assume you are in `~/Desktop/Development/NextJS/tutorial`):

```bash
z prod-website
```

That's it! You just should have visited the directory once in your lifetime (which you most probably will during the project setup). You don't even need to use the full name of your project directory, you can just do `z prod` and you would jump to the most recent directory which has `prod` in its name somewhere (in this case, the prod-website).

One thing to note is, to try not to include spaces in your directory names that may make it hard for the directory jumper to find them. It's a good practice in general too to not include spaces in directory names.

Now to install `z`, just type in the following and hit enter and there you go:

```bash
Install-Module -Name z -Force
```

Huh? This is not scoop, is it? Yes, it is not, we are currently installing a PowerShell Module (you can install some modules using scoop or winget too) and thus, we are using the `Install-Module` command that is builtin into PowerShell.


Try it out, if it doesn't work open a new Terminal tab (shortcut: ctrl+shift+t), and it should work now.

### Terminal Icons

As the name suggests it adds icons for when you do `ls`. To install it do the following:

```bash
Install-Module -Name Terminal-Icons
```

This will install the module. To be able to use it globally, we need to add it to our powershell profile, which we will cover in this article later.

### Node & Git

If you use Node.js install it but if you don’t there is no need to.


To install Node, first install `nvm` which stands for Node Version Manager, it also lets you have multiple versions of node installed at the same time.

```bash
scoop install nvm
```

This will install nvm.

Now download the stable release of Node.js with:

```bash
nvm install lts
```

for the latest release do:

```bash
nvm install latest
```

you can even specify a certain version like this:

```bash
nvm install 18.1.0
```

To list out the versions of node available use `nvm list`, the one with a `*` denotes the one being used currently. To change the version do `nvm use version_number`.

Quick Tip: You can also install `sudo` by doing `scoop install sudo`, by using that you don’t have to close and reopen the terminal for admin commands. You can use it like, `sudo nvm use 18.1.0`.

Now for git just do either of the following:

using scoop:

```bash
scoop install git
```

or

using winget

```bash
winget install git
```

That's it!

## Neovim

Neovim is a fork of Vim that is better for plugins and extensions.

To install Neovim, type in the following and hit the enter key:

```bash
scoop install neovim
```

Also, install any other packages it asks you to. I don't recommend jumping into Neovim right ahead if you haven't seen it ever before in your life or don't know the common commands/keybindings. You can check out this [article](https://dev.to/aviavinav/vim-a-beginners-guide-from-a-beginner-b11) of mine for learning a bit about it and how to set it up.

I will be using Neovim here for editing files, but it's alright you can just follow along with the steps in your preferred text editor or IDE too.

## Oh-My-Posh

Now that all your terminal tools are all set up, let's start with customizing your prompt.

First of all, to install it you can do either of the following:

```bash
winget install oh-my-posh
```

or

```bash
scoop install https://github.com/JanDeDobbeleer/oh-my-posh/releases/latest/download/oh-my-posh.json
```

Now, we will start messing with config files!

First, let's create a config file for our PowerShell, we will be using this file to customize our prompt as well as to set aliases and utilities. The config file will be in PowerShell script.

You can create it anywhere but you will have to link it accordingly in your PowerShell profile. PowerShell profile is from where PowerShell will load its config, you can write your config there directly but we will write it in a separate file.

Let's make ours in `~/.config/powershell`.

```bash
cd .config

mkdir powershell && cd powershell
```

Again, you can name your file anything just make sure it will be the same in your PowerShell profile.

Let's get started with the editing then, create a file `user_profile.ps1` in your preferred editor, I will be using Neovim here.

```bash
nvim user_profile.ps1
```

Now type in the following into your powershell config:

```powershell
oh-my-posh init pwsh --config ~/.config/powershell/avi.omp.json | Invoke-Expression
```

Save it now. In here you can see "avi.omp.json" and you can name it anything like "your_name.omp.json" just make sure to replace it in the config. Now, you may ask me though, what even is that file? That file is the one that will contain our oh-my-posh configuration for the prompt.

You can create your own custom prompt from scratch by looking at the [docs](https://ohmyposh.dev/docs/), but there are a lot of awesome ones already there. I use one of them and just modified it a bit. You can check it out on their website and copy the config. Here's the one I am using:

```json
{
  "$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes
/schema.json",
  "blocks": [
    {
      "alignment": "left",
      "segments": [
        {
          "foreground": "#41A6B5",
          "style": "plain",
          "template": "@avi",
          "type": "session"
        },
        {
          "foreground": "#7AA2F7",
          "properties": {
            "folder_separator_icon": "/",
            "style": "full"
          },
          "style": "plain",
          "template": " \uf07b {{ .Path }} ",
          "type": "path"
        },
        {
          "foreground": "#BB9AF7",
          "powerline_symbol": "\ue0b0",
          "properties": {
            "fetch_stash_count": true,
            "fetch_upstream_icon": true
          },
          "style": "plain",
          "template": "{{ .UpstreamIcon }}{{ .HEAD }}{{ if gt .StashCount 0 }} \uf692
{{ .StashCount }}{{ end }} ",
          "type": "git"
        }
      ],
      "type": "prompt"
    },
    {
      "alignment": "left",
      "newline": true,
      "segments": [
        {
          "foreground": "#cd5e42",
          "style": "plain",
          "template": "\ue3bf ",
          "type": "root"
        },
        {
          "foreground": "#CD4277",
          "style": "plain",
          "template": "> ",
          "type": "text"
        }
      ],
      "type": "prompt"
    }
  ],
  "version": 2
}
```

Next, open your powershell profile (you can do it by `nvim $profile`, do it from the home directory if you are not on Neovim, the file is located at ~/My Documents/powershell/Microsoft.PowerShell_profile.ps1), and type in the following:

```powershell
. $env:USERPROFILE\.config\powershell\user_profile.ps1
```

Save that. Close and reopen the terminal. Your prompt should load now.

Awesome! Now, let's add autocomplete.

## Autocomplete

PSReadline is a module of PowerShell that comes pre-installed which will help us out with the autocomplete.

To configure it open your `user_profile.ps1` and add the following:

```powershell
Set-PSReadLineOption -PredictionSource History

Set-PSReadLineOption -PredictionViewStyle ListView
```

You can choose "HistoryAndPlugin" or "Plugin" too as PredictionSource. For PredictionViewStyle, the other option is InlineView, you can also switch between them by pressing the F2 key.

I talked about adding Terminal Icons to the config before, you can do it by just adding the following line into your config:

```powershell
Import-Module Terminal-Icons
```

## Aliases

Aliases can be useful in saving time.

It's quite simple to set aliases, for example:

```powershell
Set-Alias g git
```

The above will set the alias for `git` as `g`, but that will only make it the alias for this particular terminal session/tab not globally. To make it a global alias add the exact same command as above in your powershell config file. Now, g is the alias for git. Similarly, you can set other aliases. Here are a few of mine:

```powershell
Set-Alias v nvim
Set-Alias g git
Set-Alias y yarn
Set-Alias p pnpm
Set-Alias tig 'C:\Program Files\Git\usr\bin\tig.exe'
Set-Alias explorer explorer.exe
```

These are PowerShell aliases, you can also setup aliases for git to speed up your development process, I won't go into the detail of it here.

There is another way to set aliases for commands like `npm start`, `yarn dev`. Here is an example of making alias `yd` for `yarn dev`:

```powershell
function yarnDev {
  yarn dev
}

New-Alias yd yarnDev
```

I don’t have experience with PowerShell script, so in the above, I can only explain that we create a function `yarnDev` and add whatever we want to run when we call the function. After that, we set the alias to call the function as `yd`.


Similarly, you can setup other aliases for such commands.

## Utilities

You can even make your own little commands by setting them in your PowerShell config. For example, `touch` command (used to create a file) which is not present in PowerShell, here is how you can add it:

```powershell
function touch ($command) {
    New-Item -Path $command -ItemType File | out-null && Write-Host Created $command
}
```

What we are doing above is creating a function `touch` and letting it have a parameter. Then, in `New-Item -Path $command -ItemType File`, we are using built-in PowerShell commands to create a file, you will have to research PowerShell commands to create more utilities on your own, the documentation is amazing, so it won’t be a problem. In the second half of the function, we are just telling it to output `Created [file_name]`.

Here is how you can add `rm` command from Linux:

```powershell
function rm ($command) {
    Remove-Item $command -Recurse && Write-Host Removed $command
}
```

To use this just do `rm [file_name/directory_name]` and it will delete the file.

It is not exactly the same as the `rm` command in Linux though.

## Other tools

Here are some of the other CLI tools you can use:

- [Commitizen](https://commitizen-tools.github.io/commitizen/) - Commitizen is used for defining a standard way of committing rules and communicating them in Git. It is designed for teams, but I also use it for my personal projects.
- [gh CLI](https://github.com/cli/cli) - gh is GitHub on the command line. It brings pull requests, issues, and other GitHub concepts to the terminal next to where you are already working with git and your code.
- [gh-dash extension](https://github.com/dlvhdr/gh-dash) - An extension of gh cli to display a dashboard with pull requests and issues.
- [dunk](https://github.com/darrenburns/dunk) - You can use this to get prettier git diffs.
- [Rich CLI](https://github.com/Textualize/rich-cli) - Rich-cli is a command-line toolbox for fancy output in the terminal.

## WSL Setup

Now, you might have already heard of WSL or might even be using it, nothing wrong with it if you are not. WSL stands for Windows Subsystem For Linux, it lets you have the Linux terminal on your windows machine.

I will not be discussing WSL setup here but you can check out ["The Complete Windows Developer Setup Guide"](https://dev.to/stephanlamoureux/the-complete-windows-developer-setup-guide-fie) by @stephanlamoureux, it goes through setting up WSL quite nicely.

## Conclusion

So, that's finished! You can find my config files [here](https://github.com/aviAvinav/public-config-files) on GitHub if you want, before copying anything go through the readme once, also do not copy anything you don’t know the meaning of.

If anyone wants to add something, correct me somewhere, or ask anything please feel free to do so in the comments.


## Resources

- for themes - https://windowsterminalthemes.dev/ or https://github.com/atomcorp/themes
- docs for PSReadline - https://docs.microsoft.com/en-us/powershell/module/psreadline/?view=powershell-7.2
- video by devsalife on setting up powershell - https://www.youtube.com/watch?v=5-aK2_WwrmM 
- Documentation for all other tools has been linked with their introductions in the article