Skip to content

Instantly share code, notes, and snippets.

@loilo
Created July 15, 2021 10:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save loilo/db7c4bb261bcb3baf711aacf68d835f9 to your computer and use it in GitHub Desktop.
Save loilo/db7c4bb261bcb3baf711aacf68d835f9 to your computer and use it in GitHub Desktop.
Shorten a path in PowerShell Core 7+
# Shorten a path in PowerShell by omitting segments from the beginning.
# Parameter defaults are designed to be used in a prompt.
# Requires at least PowerShell Core 7.
function shorten-path {
<#
.SYNOPSIS
Shortens a path from the end.
.DESCRIPTION
Shortens a path by omitting segments from the beginning. Useful e.g. to shorten the CWD in prompt.
.EXAMPLE
PS> shorten-path 'C:\foo\bar\baz\qux'
foo\bar\baz\qux
.EXAMPLE
PS> shorten-path -Path 'C:\foo\bar\baz\qux'
foo\bar\baz\qux
.EXAMPLE
PS> 'C:\foo\bar\baz\qux' | shorten-path
foo\bar\baz\qux
.EXAMPLE
PS> shorten-path -MaxLength 5 'C:\foo\bar\baz\qux'
baz\qux
.EXAMPLE
PS> shorten-path -MaxLength 1 'C:\foo\bar\baz\qux'
qux
.EXAMPLE
PS> shorten-path -MaxSegments 3 'C:\foo\bar\baz\qux'
bar\baz\qux
.EXAMPLE
PS> shorten-path -MaxSegments 0 'C:\foo\bar\baz\qux'
C:\foo\bar\baz\qux
#>
[CmdletBinding(PositionalBinding = $false)]
param (
[Parameter(ValueFromPipeline, Position = 0, HelpMessage = "The path to shorten.")]
[string]
$Path = (Get-Location),
[Parameter(HelpMessage = "Maximum number of path segments to keep, 0 to disable. Defaults to 4.")]
[int]
$MaxSegments = 4,
[Parameter(HelpMessage = "Maximum length of shortened path, 0 to disable. Defaults to 1/3 of the terminal width, minimum 30.")]
[int]
$MaxLength = [math]::Max(
[math]::Round($Host.UI.RawUI.WindowSize.Width) / 3,
30
)
)
$array = @();
# Fallback result is a single folder
$result = $Path | Split-Path -Leaf;
$max_i = ($MaxSegments -eq 0 ? [double]::PositiveInfinity : $MaxSegments);
for ($i = 0; $i -lt $max_i; $i++) {
# Get the path leaf for the current iteration
# (e.g. iterated leaf for $i = 1 of "C:\foo\bar" would be "foo")
$iterated_leaf = $Path;
for ($j = 0; $j -lt $i; $j++) {
$next_iterated_leaf = ($iterated_leaf | Split-Path);
# Bail out if file system root was reached early
if ($next_iterated_leaf.Length -eq 0) {
Write-Verbose "Done; root segment '$iterated_leaf' was reached."
return $result;
}
$iterated_leaf = $next_iterated_leaf;
}
$iterated_leaf = ($iterated_leaf | Split-Path -Leaf);
$array = $array + $iterated_leaf;
$reversed = $array[($array.Length - 1)..0];
$next_result = (($reversed.Length -eq 1) ?
$reversed[0] :
(Join-Path @reversed));
# Bail out if maximum path length was reached early
if (($MaxLength -gt 0) -And ($next_result.Length -gt $MaxLength)) {
if ($array.Length -eq 1) {
Write-Verbose "Done; initial segment '$($iterated_leaf)' already exceeds maximum length ($MaxLength)."
}
else {
Write-Verbose "Done; maximum length ($MaxLength) would be exceeded with additional segment '$($iterated_leaf)'."
}
return $result;
}
$result = $next_result;
}
Write-Verbose "Done; maximum number of segments ($MaxSegments) reached."
return $result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment