PSLeap.psm1

function Add-LeapLocation {
    <#
    .SYNOPSIS
    Adds a leap point (A vista!) to the leap points database
 
    .DESCRIPTION
    Long description
 
    .PARAMETER Name
    The name of the leap point to save
 
    .PARAMETER Path
    The path to save (can be relative or absolute)
 
    .PARAMETER Notes
    Any notes that you want to save about the vista
 
    .PARAMETER Include
    A regex pattern that will be checked against each vista path when retrieving vista
 
    .PARAMETER Scope
    Whether to store the leap point in memory only or persistently in the vista database
 
    .EXAMPLE
    Adds a persistent leap point with the name, path, and notes specified.
    PS> Add-LeapLocation -Name github -Path ~\Documents\Gitlab -Notes "Contains my personal gitlab account repos"
 
    .EXAMPLE
    Adds a persistent leap point to the current path with the specified name.
    PS> cd C:\Windows\System32; Add-LeapLocation -Name sys32
 
    #>

    [CmdletBinding()]
    param (
        $Name,
        $Path = $pwd,
        $Notes,
        $Include,
        [ValidateSet("Persistent", "Temporary")]
        $Scope = $script:orb.DefaultStore
    )

    $item = [Bookmark]@{
        Name    = $Name
        Path    = $Path
        Notes   = $Notes
        Include = $Include
    }
    if ($Scope -eq "Temporary") {
        $item.TempText = $script:orb.TemporaryDesignation
        $script:orb.TempArgumentList += $item
        $script:orb.Update()
    }
    else {
        $script:orb.PersistentArgumentList += $item
        $script:orb.Export()
    }
}
function Get-LeapInternal {
    <#
    .SYNOPSIS
    Retrieves the module internal object for fine tuning and manipulation
 
    .DESCRIPTION
    The object returned is used to set various settings for storing, retrieving, and displaying vistas.
 
 
    .EXAMPLE
    PS> $internal = Get-Leapinternal
 
    .EXAMPLE
    PS> $internal.ListFormat = "{0}"
 
    Change the name of the text in the list view (PSReadline Ctrl + Space) for Set-LeapLocation
    to only display the name of the vista.
    (Default is to display the name and if it is a temporary/in-memory vista)
    See https://gitlab.com/devirich/psleap/-/blob/main/src/Private/~import.ps1#L14-19 for possible replacements
 
    .EXAMPLE
    PS> $internal.TemporaryDesignation = " (!!)"
 
    Change the text to be used to denote which vistas are temporary (in memory only) in Set-LeapLocation parameter list view
 
    .EXAMPLE
    PS> $internal.PersistentArgumentList[0].Notes = "Cooler notes"
    PS> $internal.Export()
 
    Update the vista persistent database and set the 1st item's Notes to "Cooler Notes"
 
    .EXAMPLE
    PS> $internal.Update()
 
    Update the list view database (such as after changing data in the vista persistent database or an entry in $internal.TemporaryArgumentList)
 
    .EXAMPLE
    PS> $internal.DefaultStore = "Temporary"
 
    Set the default location for new vistas to be in memory instead of stored persistently to disk.
 
    .EXAMPLE
    PS> $internal.StartsWithFallback = $false
 
    Enable strict matching of vista names (default is true and will attempt to find a matching vista that starts with your $name text)
 
    .EXAMPLE
    #>

    [cmdletbinding()]
    param()
    $script:orb
}
function Set-LeapLocation {
    <#
    .SYNOPSIS
    Changes your current directory to a leap point (as stored in either the vista file or in memory)
 
    .PARAMETER Name
    The name of the leap point (a vista!) that you want to travel to.
 
    .EXAMPLE
    Jumps to the specified leap point/vista (assuming you have a leap point titled sys32)
    PS> Set-LeapPoint sys32
 
    .EXAMPLE
    Jumps to the specified leap point/vista
    Assuming you have a leap point titled sys32 and StartsWithFallback has been left on
    PS> Set-LeapPoint sys
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [string]$Name
    )

    if ($bookmark = $script:orb.Get($Name)) {
        Set-Location $bookmark.Path
    }
    else {
        throw "No leap point found for query '$Name'. Exiting."
    }
}
class Bookmark {
    [parameter(Mandatory)]$Name
    [string]$Path
    [string]$Notes
    [string]$Include
    [string]$TempText

    Bookmark() {}
    Bookmark([object]$obj) {
        $this.Name = $obj.Name
        $this.Path = $obj.Path
        $this.Notes = $obj.Notes
        $this.Include = $obj.Include
        $this.TempText = $obj.TempText
    }
    Bookmark([string]$str) {
        $this.Name = $str
    }
}

class LeapData {
    $DatabaseName = "PSLeapVistas.csv"
    $DatabaseDirectory = "~\Documents\PowerShell\Config\PSLeap"
    [ValidateSet("Persistent", "Temporary")]
    $DefaultStore = "Persistent"
    [string]$TemporaryDesignation = " (Temp)"
    [string]$ListFormat = "{0}{1}"
    $StartsWithFallback = $true
    [bookmark[]]$PersistentArgumentList
    [bookmark[]]$TempArgumentList
    hidden [bookmark[]]$ArgumentList

    LeapData() {}

    [bookmark[]] Get() { return $this.ArgumentList }
    [bookmark] Get([string]$Name) {
        if ($out = $this.ArgumentList.Where{ $_.Name -eq $Name }[0]) {}
        elseif ($this.StartsWithFallback -and ($out = $this.ArgumentList.Where{ $_.Name -like "$Name*" }[0])) {}

        if ($out) { return $out }
        else { return $null }
    }

    Update() {
        $this.ArgumentList = @()
        if ($this.TempArgumentList.count) {
            $this.ArgumentList += $this.TempArgumentList | Sort-Object Name
        }

        # Get persistent locations and add them to the db content
        if (Test-Path "$($script:orb.DatabaseDirectory)\$($script:orb.DatabaseName)") {
            $this.PersistentArgumentList = Import-Csv "$($script:orb.DatabaseDirectory)\$($script:orb.DatabaseName)"
            $this.ArgumentList += $this.PersistentArgumentList | Sort-Object Name
        }
    }

    Export() {
        mkdir -ea silent $this.DatabaseDirectory | Out-Null
        $this.PersistentArgumentList | Where-Object { -not $_.TempText } | Export-Csv "$($script:orb.DatabaseDirectory)\$($script:orb.DatabaseName)"
        $this.Update()
    }
}
# I'm calling the master object an orb because it is short and sweet.
$script:orb = [LeapData]::new()

$script = {
    param ( $commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter )

    $script:orb.ArgumentList |
    Where-Object name -Like "$wordToComplete*" |
    Where-Object { $pwd -match $_.Include } |
    ForEach-Object {
        if ($_.Include) { $include = "`nInclude filter: {2}" }
        else { $include = '' }
        [System.Management.Automation.CompletionResult]::new(
            $_.Name,
            ($script:orb.ListFormat -f @(
                $_.Name
                $_.TempText
                $_.Path
                $_.Notes
                $_.Include
                Split-Path -Leaf $_.Path
            )),
            "ParameterValue",
            ("{0}$include`n{1}" -f $_.Path, $_.Notes, $_.Include)
        )
    }

}
Register-ArgumentCompleter -CommandName Set-LeapLocation -ScriptBlock $script -ParameterName Name

$script:orb.Update()