A Guide to Overengineering a Windows Terminal

·

13 min read

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!

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!

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 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.

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.

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 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.

Terminal Tools

Scoop

Let's first install scoop, a package manager for Windows. We will be then using scoop to install other tools.

To install scoop run the following in PowerShell:

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:

iwr -useb get.scoop.sh | iex

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

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 which you can use as a package manager but we will stick with scoop for this article.

z

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:

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):

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:

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:

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.

scoop install nvm

This will install nvm.

Now download the stable release of Node.js with:

nvm install lts

for the latest release do:

nvm install latest

you can even specify a certain version like this:

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:

scoop install git

or

using winget

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:

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 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:

winget install oh-my-posh

or

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.

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.

nvim user_profile.ps1

Now type in the following into your powershell config:

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, 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:

{
  "$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:

. $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:

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:

Import-Module Terminal-Icons

Aliases

Aliases can be useful in saving time.

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

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:

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:

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:

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:

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 - 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 - 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 - An extension of gh cli to display a dashboard with pull requests and issues.
  • dunk - You can use this to get prettier git diffs.
  • 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" by @stephanlamoureux, it goes through setting up WSL quite nicely.

Conclusion

So, that's finished! You can find my config files here 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