nav-utils.ps1
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# nav-utils.ps1 — navigation utilities ========================================

# Navigate up the directory tree.
#
# Usage:
#   up           — go up one level
#   up 3         — go up N levels
#   up src       — jump to nearest parent named 'src'
function Invoke-Up {
    [CmdletBinding()]
    param(
        [Parameter(Position = 0)]
        [string]$Target,

        [Alias('h')]
        [switch]$Help
    )

    if ($Help) { $MyInvocation.MyCommand | Get-Help; return }

    $Cwd = (Get-Location).Path
    $Parts = $Cwd -split [regex]::Escape([System.IO.Path]::DirectorySeparatorChar)

    # No argument — one level up
    if (-not $Target) {
        Set-Location ..
        return
    }

    # Numeric — up N levels
    $N = $null
    if ([int]::TryParse($Target, [ref]$N)) {
        if ($N -lt 1) {
            Write-Error "up: level must be >= 1, got $N"
            return
        }
        if ($N -ge $Parts.Count) {
            Write-Error "up: cannot go up $N levels from '$Cwd' (only $($Parts.Count - 1) available)"
            return
        }
        $NewPath = $Parts[0..($Parts.Count - 1 - $N)] -join [System.IO.Path]::DirectorySeparatorChar
        Set-Location $NewPath
        return
    }

    # Name-based — find nearest ancestor with that name
    $Matched = @()
    for ($i = 0; $i -lt $Parts.Count; $i++) {
        if ($Parts[$i] -eq $Target) { $Matched += $i }
    }

    if ($Matched.Count -eq 0) {
        Write-Error "up: no parent directory named '$Target' found in '$Cwd'"
        return
    }

    # Take the deepest (nearest) match
    $NewPath = $Parts[0..$Matched[-1]] -join [System.IO.Path]::DirectorySeparatorChar
    Set-Location $NewPath
}

# Create a directory and immediately move into it
function Invoke-MkCd {
    [CmdletBinding()]
    param(
        [Parameter(Position = 0)]
        [string]$Dir,

        [Alias('h')]
        [switch]$Help
    )

    if ($Help) { $MyInvocation.MyCommand | Get-Help; return }

    try {
        New-Item -ItemType Directory -Path $Dir -Force | Out-Null
        Set-Location -Path $Dir
    }
    catch {
        Write-Warning "mkcd: failed to create or move into '$Dir'"
    }
}

# Go up one level
function Set-LocationUp { Set-Location .. }

# Go up two levels
function Set-LocationUpUp { Set-Location ../.. }

Set-Alias -Name up   -Value Invoke-Up        -Scope Global
Set-Alias -Name mkcd -Value Invoke-MkCd      -Scope Global
Set-Alias -Name ..   -Value Set-LocationUp   -Scope Global
Set-Alias -Name ...  -Value Set-LocationUpUp -Scope Global