Published in Articles on by Michiel van Oosterhout ~ 4 min read

Recently we designed and implemented an extension system for Windows Command Processor (see part 1, part 2, part 3, and part 4 of the 4-part series of articles, as well as this follow-up article that added support for intercepting commands). But what good is an extension system without extensions? This article introduces an extension that adds support for using the ~ as a replacement for the path to your home directory with the cd, chdir, and pushd commands.

Home Sweet Home, artwork by Banksy
Home Sweet Home, artwork by Banksy Photo by Matthew, CC BY-NC-ND

cd ~

We will split the implementation into two extensions. The first extension will replace a ~ at the start of a parameter to cd (and chdir and pushd) with the path to the current user's home directory. The second extension (see below) will do something similar to the output of cd (and chdir).

The Windows PowerShell script below installs the first extension, named TildeIn. This extension contains three identical filters, one for each of the commands that can be used to change the current directory.

# Declare the filter script contents
$script = @"
@echo off
setlocal enabledelayedexpansion

for /f "delims=; tokens=1,*" %%a in ("%~1") do (
    if "%%~b"=="" (set next=%%~a) else (set next=call %%~a "%%b")
)

shift
:loop_params

set param=%~1
set start=%param:~0,1%

if "%start%"=="~" (

    set n=0
    :length_loop
    if not "!param:~%n%!"=="" set /a n+=1 & goto :length_loop

    set /a n-=1
    set param=%HOMEDRIVE%%HOMEPATH%!param:~1,%n%!
)

set next=%next% "%param%"

shift && if not "%~1"=="" goto loop_params

endlocal && %next%
"@

# Ensure the extension's directory exists
$path = "$Env:LOCALAPPDATA\Commando\TildeIn"
$_ = New-Item $path -Force -ItemType Directory

# Create the filter scripts
@("cd", "chdir", "pushd") | ForEach-Object {
    Set-Content -Path "$path\$_.filter.cmd" -Value $script
}

The first for loop is explained in Intercepting commands in Windows Command Processor, and is part of the standard code that every filter should implement.

The filter uses :loop_params to inspect each parameter param, and if param's first character start is ~, it first computes the length n using :length_loop, and then uses n-1 to truncate the first character from the parameter (!param:~1,%n%!, which means take a substring of length n starting at index 1), and prepends the path to the current user's home directory (%HOMEDRIVE%%HOMEPATH%).

Finally, the filter executes next, but does so outside of the scope that ends with endscope, so that the directory change takes effect in the Windows Command Processor session (remember, these extensions are for interactive use of Windows Command Processor).

Using `~` with the `cd` command on Windows
Using ~ with the cd command on Windows

Replacing ~ on stdout

The Windows PowerShell script below installs the second extension, named TildeOut. Like the first extension, this extension also contains multiple identical filters, one for each of the commands that can be used to print the current directory (cd and chdir).

# Declare the filter script contents
$script = @"
@echo off
setlocal enabledelayedexpansion

for /f "delims=; tokens=1,*" %%a in ("%~1") do (
    if "%%~b"=="" (set next=%%~a) else (set next=call %%~a "%%b")
)

set params=0

shift
:loop_params
set next=%next% %1 && shift && if not "%~1"=="" set /a params+=1 && goto loop_params

endlocal && if "%params%"=="0" for /f "tokens=*" %%l in ('%next%') do (
    setlocal enabledelayedexpansion

    set line=%%l
    echo !line:%HOMEDRIVE%%HOMEPATH%=~!

    endlocal
) else (%next%)
"@

# Ensure the extension's directory exists
$path = "$Env:LOCALAPPDATA\Commando\TildeOut"
$_ = New-Item $path -Force -ItemType Directory

# Create the filter scripts
@("cd", "chdir") | ForEach-Object {
    Set-Content -Path "$path\$_.filter.cmd" -Value $script
}

Like the first extension, this extension's first for loop is standard code that every filter should implement.

The filter uses :loop_params to save the number of parameters in params. Then the filter executes next (again, outside of the scope that ends with endscope), but if params is 0 then it parses each line of output with for /f "tokens=*" and replaces any occurence of the current user's home directory (%HOMEDRIVE%%HOMEPATH%) with ~.

The `cd` command on Windows printing `~`
The cd command on Windows printing ~

Summary

Extensions for Windows Command Processor can provide filters to intercept commands. These filters can alter input (parameters) or output. Multiple filters for the same command can be combined, as long as each filter correctly executes the next filter.

Updates

  • Fixed a bug in the extension so cd continues to work with a quoted path.