Making the windows terminal great again

Once again my employeer forces me to work from an inferior platform, so what are my options to get the best possible working environment? Heres some tips to what I’ve done so far.

The windows terminal is one of the better things produced by Microsoft the last couple of years. I have already written a bit about it before, so search for windows terminal, and you will get the other articles. Even though the terminal is nice, there are some minor annoyances, when you are used to work in a bash environment.

  1. No nice “inline” editor
  2. Does not obey ctrl-d to exit the session
  3. Does not have tab completion on entries in the ssh config file

To fix these three annoyances, we need to download vim from www.vim.org, install it and the rest is done creating and configuring a powershell profile, lets dive into it.

Not only do I have to work from a windows machine (my department does primarily FOSS solutions) I also don’t have any elevated permissions on my machine. IT proffesionlas are treated just the same as office workers 🙁

This means I cannot install any software, besides whats picked by the Windows admins. Luckily vim is not picky, and you can install it in your own home folder. So lauch the installer and change the install path accordingly.

When vim is installed, all we need to do is to create a powershell profile file. The file has to be named Microsoft.PowerShell_Profile.ps1 and has to be placed under $home\Documents\PowerShell\
When placed here it will be a user specific profile, you can also do system-wide profiles, take a look at $pshome.

The profile file I have created looks like this:

using namespace System.Management.Automation

# Set aliases

Set-Alias -name vim $home\Vim\vim90\vim.exe
Set-Alias -name vi $home\Vim\vim90\vim.exe

# Obey ctrl-d

Set-PSReadlineKeyHandler -Key ctrl+d -Function ViExit

# Enable ssh tab completion
# Credits to backerman and contributers at github for creating the code

Register-ArgumentCompleter -CommandName ssh,scp,sftp -Native -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)

function Get-SSHHostList($sshConfigPath) {
    Get-Content -Path $sshConfigPath `
    | Select-String -Pattern '^Host ' `
    | ForEach-Object { $_ -replace 'Host ', '' } `
    | ForEach-Object { $_ -split ' ' } `
    | Sort-Object -Unique `
    | Select-String -Pattern '^.*[*!?].*$' -NotMatch
}

function Get-SSHConfigFileList ($sshConfigFilePath) {
    $sshConfigDir = Split-Path -Path $sshConfigFilePath -Resolve -Parent

    $sshConfigFilePaths = @()
    $sshConfigFilePaths += $sshConfigFilePath

    $pathsPatterns = @()
    Get-Content -Path $sshConfigFilePath `
    | Select-String -Pattern '^Include ' `
    | ForEach-Object { $_ -replace 'Include ', '' }  `
    | ForEach-Object { $_ -replace '~', $Env:USERPROFILE } `
    | ForEach-Object { $_ -replace '\$Env:USERPROFILE', $Env:USERPROFILE } `
    | ForEach-Object { $_ -replace '\$Env:HOMEPATH', $Env:USERPROFILE } `
    | ForEach-Object { 
    $sshConfigFilePaths += $(Get-ChildItem -Path $sshConfigDir\$_ -File -ErrorAction SilentlyContinue -Force).FullName `
    | ForEach-Object { Get-SSHConfigFileList $_ } 
    }

    if (($sshConfigFilePaths.Length -eq 1) -and ($sshConfigFilePaths.item(0) -eq $sshConfigFilePath) ) {
        return $sshConfigFilePath
    }

    return $sshConfigFilePaths | Sort-Object -Unique
}

$sshPath = "$Env:USERPROFILE\.ssh"
$hosts = Get-SSHConfigFileList "$sshPath\config" `
| ForEach-Object { Get-SSHHostList $_ } `

# For now just assume it's a hostname.
$textToComplete = $wordToComplete
$generateCompletionText = {
    param($x)
    $x
}
if ($wordToComplete -match "^(?<user>[-\w/\\]+)@(?<host>[-.\w]+)$") {
    $textToComplete = $Matches["host"]
    $generateCompletionText = {
        param($hostname)
        $Matches["user"] + "@" + $hostname
    }
}

$hosts `
| Where-Object { $_ -like "${textToComplete}*" } `
| ForEach-Object { [CompletionResult]::new((&$generateCompletionText($_)), $_, [CompletionResultType]::ParameterValue, $_) }}

Exit your terminal and lauch it again, hopefully you can be a bit more productive with the new “features”

Finally a decent terminal for Windows

Tip! Check out my new post about making the terminal great again here

For years and years Windows users have had to work with disabled tools when trying to work in the command line interface. The old cmd had a bad interface, and even powershell until very recent, has also been a pain. One of the most annoying things has been the missing ability to adjust the window size to your needs, furthermore tab completion has either been missing or bad implemented. All in all, flexibility has not been a keyword for any of the old terminals, but this is all in the past, because now we have Windows terminal!

Easy to install from the Windows store or with command line package manager like chocolatey, and has a great deal of the features you know from various Linux terminals.

Windows terminal supports multiple terminals in tabs, split panes horizontal and vertical, custom background and a lot more. Check it out here: https://github.com/microsoft/terminal

If you are a Linux user and sometimes have to work from Windows, Windows terminal also work perfect with WSL (Windows Subsystem for Linux). Install the terminal, install your favorite Linux, and you are good to go. Here are some small tips to make the experience even better:

  1. Make Linux the default shell by editing the json settings file. You find it by clicking the small “down-arrow” and select settings. Add the guid number of the Linux you want to start to the defaultprofile setting.
  2. Make the Linux shell start in the Linux home folder by adding this setting to the bottom of the paragraph of your Linux profile:
    “commandline”: “wsl.exe ~”

If you are interested in command line stuff, and working on Windows, this is a nice resource to follow: https://devblogs.microsoft.com/commandline/