From 1862b819f6c64a646f5f7ab92b0f6d56b101a06b Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Sat, 30 Oct 2021 21:03:39 -0500 Subject: [PATCH 01/49] misc updates Invoke-NinFormatter: Removed outer try->catch --- .vscode/settings.json | 2 +- Ninmonkey.Console.psm1 | 6 +- private/seeminglySci/seeminglySci_import.ps1 | 57 --------------- public/ConvertTo-Base64String.ps1 | 2 +- public/Set-ConsoleEncoding.ps1 | 3 +- .../Get-NinPSReadlineHistory.ps1 | 7 +- public_autoloader/Invoke-NinFormatter.ps1 | 73 +++++++++++++------ .../Invoke-NinFormatter.tests.ps1 | 4 +- ...0\237\226\245\357\270\217 .code-workspace" | 13 +--- 9 files changed, 67 insertions(+), 100 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 4425ec5..25dab6e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "editor.fontSize": 18, + "editor.fontSize": 15, "editor.fontFamily": "'cascadia code pl', Consolas, 'Courier New', monospace" } diff --git a/Ninmonkey.Console.psm1 b/Ninmonkey.Console.psm1 index 12477e6..683a9d5 100644 --- a/Ninmonkey.Console.psm1 +++ b/Ninmonkey.Console.psm1 @@ -167,7 +167,7 @@ $public_toDotSource = @( 'ConvertTo-Number' 'ConvertTo-HexString' 'ConvertTo-Base64String' - 'ConvertTo-BitString' + 'ConvertTo-PropertyList' # inspection @@ -272,7 +272,7 @@ $functionsToExport = @( 'ConvertTo-Number' 'ConvertTo-HexString' 'ConvertTo-Base64String' - 'ConvertTo-BitString' + 'ConvertTo-PropertyList' @@ -331,7 +331,7 @@ $functionsToExport = @( 'Test-Net' # seemingly-sci # 'Get-ElementName' - 'ConvertTo-BitString' + 'ConvertTo-Number' 'ConvertTo-HexString' 'ConvertTo-Base64String' diff --git a/private/seeminglySci/seeminglySci_import.ps1 b/private/seeminglySci/seeminglySci_import.ps1 index c17add4..7b9ef18 100644 --- a/private/seeminglySci/seeminglySci_import.ps1 +++ b/private/seeminglySci/seeminglySci_import.ps1 @@ -61,63 +61,6 @@ param() [section]: main #> -function ConvertTo-SciBitString { - [Alias('Bits')] - [CmdletBinding(PositionalBinding = $false)] - param( - [Parameter(ValueFromPipeline)] - [psobject[]] $InputObject, - - [Parameter(Position = 0)] - [ValidateRange(1, [int]::MaxValue)] - [int] $Padding, - - [Parameter(Position = 1)] - [ValidateNotNull()] - [AllowEmptyString()] - [string] $ByteSeparator = ' ', - - [Parameter(Position = 2)] - [ValidateNotNull()] - [AllowEmptyString()] - [string] $HalfByteSeparator = '.' - ) - begin { - function GetBinaryString([psobject] $item) { - $numeric = number $item - if ($null -eq $numeric) { - return - } - - $bits = [convert]::ToString($numeric, <# toBase: #> 2) - if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey((nameof { $Padding }))) { - $padAmount = $Padding * 8 - if ($padAmount -ge $bits.Length) { - return $bits.PadLeft($Padding * 8, [char]'0') - } - } - - $padAmount = 8 - ($bits.Length % 8) - if ($padAmount -eq 8) { - return $bits - } - - return $bits.PadLeft($padAmount + $bits.Length, [char]'0') - } - } - process { - foreach ($currentItem in $InputObject) { - $binaryString = GetBinaryString $currentItem - - # yield - $binaryString -replace - '[01]{8}(?=.)', "`$0$ByteSeparator" -replace - '[01]{4}(?=[01])', "`$0$HalfByteSeparator" - } - } -} - - filter decimal { foreach ($currentItem in $PSItem) { Convert-Object -InputObject $currentItem -Type ([decimal]) } } filter double { foreach ($currentItem in $PSItem) { Convert-Object -InputObject $currentItem -Type ([double]) } } filter single { foreach ($currentItem in $PSItem) { Convert-Object -InputObject $currentItem -Type ([single]) } } diff --git a/public/ConvertTo-Base64String.ps1 b/public/ConvertTo-Base64String.ps1 index 59415fc..5d956ce 100644 --- a/public/ConvertTo-Base64String.ps1 +++ b/public/ConvertTo-Base64String.ps1 @@ -4,7 +4,7 @@ function ConvertTo-Base64String { <# .synopsis - originally from: + originally from: .notes currently the same, separate same. separate for dependency clarity .example diff --git a/public/Set-ConsoleEncoding.ps1 b/public/Set-ConsoleEncoding.ps1 index 63df63e..801b877 100644 --- a/public/Set-ConsoleEncoding.ps1 +++ b/public/Set-ConsoleEncoding.ps1 @@ -57,7 +57,7 @@ function Set-ConsoleEncoding { # Which encoding to use? # [string] or [encoding] [Parameter(Mandatory, Position = 0)] - [ValidateSet('Utf8', 'Utf16-LE', 'Unicode')] + [ArgumentCompletions('Utf8', 'Utf16-LE', 'Unicode')] [string]$EncodingName ) @@ -72,6 +72,7 @@ function Set-ConsoleEncoding { break } default { + Write-Error "Not recognized: '$EncodingName', falling back to utf8" $global:OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = [System.Text.UTF8Encoding]::new() break } diff --git a/public_autoloader/Get-NinPSReadlineHistory.ps1 b/public_autoloader/Get-NinPSReadlineHistory.ps1 index 0a359d1..675e22b 100644 --- a/public_autoloader/Get-NinPSReadlineHistory.ps1 +++ b/public_autoloader/Get-NinPSReadlineHistory.ps1 @@ -22,7 +22,12 @@ function Get-NinPSReadlineHistory { [Alias('getHistory')] [CmdletBinding(PositionalBinding = $false)] param ( + # Warning, very slow + [Parameter()][switch]$IncludeProfile ) - [Microsoft.PowerShell.PSConsoleReadLine]::GetHistoryItems() + + if ($IncludeProfile) { + $profile.PSReadLineHistory | Get-Content + } } diff --git a/public_autoloader/Invoke-NinFormatter.ps1 b/public_autoloader/Invoke-NinFormatter.ps1 index 69a4e28..aa69be6 100644 --- a/public_autoloader/Invoke-NinFormatter.ps1 +++ b/public_autoloader/Invoke-NinFormatter.ps1 @@ -4,7 +4,7 @@ $script:publicToExport.function += @( 'Invoke-NinFormatter' ) $script:publicToExport.alias += @( - 'FormatScript🎨' + 'Format.ScriptPs1🎨' ) function Invoke-NinFormatter { @@ -19,6 +19,7 @@ function Invoke-NinFormatter { future: allow piping from: [HistoryInfo] | [Microsoft.PowerShell.PSConsoleReadLine+HistoryItem] .outputs + [string] #> @@ -29,11 +30,15 @@ function Invoke-NinFormatter { [Parameter( ParameterSetName = 'FromPipeOrParam', Mandatory, Position = 0, ValueFromPipeline)] - [ValidateNotNullOrEmpty()] + [AllowNull()] + [AllowEmptyString()] + [AllowEmptyCollection()] + # [ValidateNotNullOrEmpty()] [string]$ScriptDefinition, # Formats Last Command in history - [Alias('FromLastCommand', 'PrevCommand', 'FromHistory')] + # [Alias('FromLastCommand', 'PrevCommand', 'FromHistory')] + [Alias('PrevCommand')] [Parameter( Mandatory, ParameterSetName = 'FromHistory' @@ -58,34 +63,54 @@ function Invoke-NinFormatter { } process { - try { - switch ($PSCmdlet.ParameterSetName) { - 'FromPipeOrParam' { - } - 'FromHistory' { - $ScriptDefinition = (Get-History -Count 1 | ForEach-Object CommandLine) - } - 'FromClipboard' { - $ScriptDefinition = (Get-Clipboard) + # try { + switch ($PSCmdlet.ParameterSetName) { + 'FromPipeOrParam' { + if ($null -eq $ScriptDefinition) { + return } + } + 'FromHistory' { + $ScriptDefinition = (Get-History -Count 1 | ForEach-Object CommandLine) + } + 'FromClipboard' { + $ScriptDefinition = (Get-Clipboard) + } - default { - Write-Error -ea stop -Category NotImplemented -Message 'Unhandled ParameterSet' -TargetObject $PSCmdlet.ParameterSetName - # throw "Unhandled ParameterSet: $($PSCmdlet.ParameterSetName)" - } + default { + Write-Error -ea stop -Category NotImplemented -Message 'Unhandled ParameterSet' -TargetObject $PSCmdlet.ParameterSetName + # throw "Unhandled ParameterSet: $($PSCmdlet.ParameterSetName)" } + } - $invokeFormatterSplat = @{ - ScriptDefinition = $ScriptDefinition - # formatter requires path, while Invoke-ScriptAnalyzer doe - Settings = (Get-Item -ea stop $__ninConfig.Config.PSScriptAnalyzerSettings)?.FullName + $invokeFormatterSplat = @{ + ScriptDefinition = $ScriptDefinition + # formatter requires path, while Invoke-ScriptAnalyzer doe + Settings = try { + (Get-Item -ea stop $__ninConfig.Config.PSScriptAnalyzerSettings)?.FullName } + catch { + Write-Error -m ( + 'Error loading: $__ninConfig.Config.PSScriptAnalyzerSettings = "{0}"' -f @( + $__ninConfig.Config.PSScriptAnalyzerSettings + ) + ) - Invoke-Formatter @invokeFormatterSplat # -Range - } - catch { - $PSCmdlet.WriteError( $_ ) + } } + 'using: $__ninConfig.Config.PSScriptAnalyzerSettings = "{0}"' -f @( + $__ninConfig.Config.PSScriptAnalyzerSettings + ) | Write-Debug + $invokeFormatterSplat | Format-dict | Write-Debug + + + # try {} + + Invoke-Formatter @invokeFormatterSplat # -Range + # } + # catch { + # $PSCmdlet.WriteError( $_ ) + # } } end {} } diff --git a/public_autoloader/Invoke-NinFormatter.tests.ps1 b/public_autoloader/Invoke-NinFormatter.tests.ps1 index 0001252..02dc521 100644 --- a/public_autoloader/Invoke-NinFormatter.tests.ps1 +++ b/public_autoloader/Invoke-NinFormatter.tests.ps1 @@ -1,7 +1,7 @@ #requires -modules @{ModuleName='Pester';ModuleVersion='5.0.0'} -$SCRIPT:__PesterFunctionName = $myinvocation.MyCommand.Name.split('.')[0] -Describe "$__PesterFunctionName" -Tag Unit { + +Describe Invoke-NinFormatter { BeforeAll { Import-Module Ninmonkey.Console -Force # . $(Get-ChildItem -Path $PSScriptRoot/.. -Recurse -Filter "$__PesterFunctionName.ps1") diff --git "a/\360\237\220\222 Ninmonkey.Console\360\237\226\245\357\270\217 .code-workspace" "b/\360\237\220\222 Ninmonkey.Console\360\237\226\245\357\270\217 .code-workspace" index 2499339..53a5e69 100644 --- "a/\360\237\220\222 Ninmonkey.Console\360\237\226\245\357\270\217 .code-workspace" +++ "b/\360\237\220\222 Ninmonkey.Console\360\237\226\245\357\270\217 .code-workspace" @@ -3,10 +3,7 @@ { "path": ".", "name": "Ninmonkey.Console" - }, - // { - // // "path": "..\\..\\..\\dotfiles_git\\powershell\\Ninmonkey.Profile" - // } + } ], "settings": { /* @@ -34,10 +31,7 @@ */ // "powershell.scriptAnalysis.settingsPath": "PSScriptAnalyzerSettings.psd1", "terminal.integrated.drawBoldTextInBrightColors": true, - "terminal.integrated.fontSize": 18, - "editor.fontSize": 18, - "debug.console.fontSize": 18, - "editor.suggestFontSize": 14, + "editor.fontSize": 16, "markdown.preview.fontSize": 12, // "screencastMode.fontSize": 56, // "window.zoomLevel": 0, @@ -71,8 +65,7 @@ "MD025": { "front_matter_title": "" } - }, - "terminal.integrated.fontFamily": "'consolas'" + } }, "launch": { // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 From 1ad897ff7cc7406d24c758182e051c5d29e053fd Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Sat, 30 Oct 2021 21:03:55 -0500 Subject: [PATCH 02/49] Update ConvertTo-BitString.ps1 merged from Sci's gist --- public/ConvertTo-BitString.ps1 | 48 +++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/public/ConvertTo-BitString.ps1 b/public/ConvertTo-BitString.ps1 index 614ace6..c1866e2 100644 --- a/public/ConvertTo-BitString.ps1 +++ b/public/ConvertTo-BitString.ps1 @@ -1,7 +1,7 @@ function ConvertTo-BitString { - <# + <# .synopsis - originally from: + originally from: , then .notes currently the same, separate same. separate for dependency clarity .example @@ -33,14 +33,42 @@ [string] $HalfByteSeparator = '.' ) begin { + $toBytes = [psdelegate]{ + ($a) => { [MemoryMarshal]::AsBytes([MemoryExtensions]::AsSpan($a)).ToArray() } + } + function GetBinaryString([psobject] $item) { - $numeric = Number $item - if ($null -eq $numeric) { - return + $numeric = $item.psobject.BaseObject + $numericType = $numeric.GetType() + $isPrimitive = $numericType.IsPrimitive + if (-not $isPrimitive) { + if ($numericType.GetFields([BindingFlags]'Instance, Public, NonPublic').Length -gt 1) { + $PSCmdlet.WriteWarning( + 'Structs with two or more fields may show inaccurately depending on field layout and processor endianness.') + } + } + + $delegateType = [Func`2].MakeGenericType( + $numeric.GetType().MakeArrayType(), + [byte[]]) + + $toBytesCompiled = $toBytes -as $delegateType + $bytes = $toBytesCompiled.Invoke($numeric) + + # Should always do this for LE? or only makes sense for primitives? + if ([BitConverter]::IsLittleEndian) { + [array]::Reverse($bytes) + } + + $sb = [StringBuilder]::new([convert]::ToString($bytes[0], <# toBase: #> 2)) + for ($i = 1; $i -lt $bytes.Length; $i++) { + $byte = $bytes[$i] + $bits = [convert]::ToString($byte, <# toBase: #> 2) + $null = $sb.Append($bits.PadLeft(8, [char]'0')) } - $bits = [convert]::ToString($numeric, <# toBase: #> 2) - if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey((nameof { $Padding }))) { + $bits = $sb.ToString().TrimStart([char]'0') + if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey((nameof{$Padding}))) { $padAmount = $Padding * 8 if ($padAmount -ge $bits.Length) { return $bits.PadLeft($Padding * 8, [char]'0') @@ -61,8 +89,8 @@ # yield $binaryString -replace - '[01]{8}(?=.)', "`$0$ByteSeparator" -replace - '[01]{4}(?=[01])', "`$0$HalfByteSeparator" + '[01]{8}(?=.)', "`$0$ByteSeparator" -replace + '[01]{4}(?=[01])', "`$0$HalfByteSeparator" } } -} +} \ No newline at end of file From 9f19e273eee47172a1b80e03894a35ee32f04def Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Sun, 31 Oct 2021 19:14:51 -0500 Subject: [PATCH 03/49] removed extra aliases --- public_autoloader/Get-NinCommand.ps1 | 13 +++++++++---- public_autoloader/Invoke-NinFormatter.ps1 | 8 +------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/public_autoloader/Get-NinCommand.ps1 b/public_autoloader/Get-NinCommand.ps1 index 32bcb28..30eeeaa 100644 --- a/public_autoloader/Get-NinCommand.ps1 +++ b/public_autoloader/Get-NinCommand.ps1 @@ -6,9 +6,9 @@ if (! $__debugInlineNin) { 'Get-NinCommand' ) $script:publicToExport.alias += @( - 'MyGcm🐒' + # 'MyGcm🐒' 'Find-Command🐒' - 'MyGet-Command🐒' + # 'MyGet-Command🐒' ) } @@ -17,6 +17,7 @@ function Get-NinCommand { .synopsis Does far more than wrapping Get-Command. For that check out 'Ninmonkey.Console\Get-NinCommandProxy .notes + maybe this should be Find-NinCommand? todo: for Get-NinCommandArgumentCompleterAttribute note on naming standards: @@ -58,12 +59,16 @@ function Get-NinCommand { DevTool💻-GetTypeAccellerators DevTool💻-iProp DevTool💻-Params-FindCommandWithParameterAlias + .link + Dev.Nin\Get-CommandNameCompleter .outputs [string[]] | [hashtable] #> - [Alias('MyGcm🐒', 'MyGet-Command🐒', - 'Find-Command🐒')] + [Alias( + # 'MyGcm🐒', + 'Find-Command🐒' + )] [CmdletBinding(PositionalBinding = $false)] param( diff --git a/public_autoloader/Invoke-NinFormatter.ps1 b/public_autoloader/Invoke-NinFormatter.ps1 index aa69be6..cab56f0 100644 --- a/public_autoloader/Invoke-NinFormatter.ps1 +++ b/public_autoloader/Invoke-NinFormatter.ps1 @@ -30,10 +30,7 @@ function Invoke-NinFormatter { [Parameter( ParameterSetName = 'FromPipeOrParam', Mandatory, Position = 0, ValueFromPipeline)] - [AllowNull()] - [AllowEmptyString()] - [AllowEmptyCollection()] - # [ValidateNotNullOrEmpty()] + [ValidateNotNullOrEmpty()] [string]$ScriptDefinition, # Formats Last Command in history @@ -66,9 +63,6 @@ function Invoke-NinFormatter { # try { switch ($PSCmdlet.ParameterSetName) { 'FromPipeOrParam' { - if ($null -eq $ScriptDefinition) { - return - } } 'FromHistory' { $ScriptDefinition = (Get-History -Count 1 | ForEach-Object CommandLine) From ea391ac4ce7a6e7c3bbea08e075275ff4b7738d7 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Sun, 31 Oct 2021 21:41:29 -0500 Subject: [PATCH 04/49] Fixed Label's Null Input error --- public/Write-ConsoleLabel.ps1 | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/public/Write-ConsoleLabel.ps1 b/public/Write-ConsoleLabel.ps1 index bce3f50..c301dd0 100644 --- a/public/Write-ConsoleLabel.ps1 +++ b/public/Write-ConsoleLabel.ps1 @@ -138,6 +138,7 @@ function Write-ConsoleLabel { # Separator = 'x' LeaveColor = $LeaveColor IgnoreEntities = $true + Object = $InputObject # Object = $Text # both are set later anyway } @@ -161,7 +162,7 @@ function Write-ConsoleLabel { $newTextSplat_Label | Format-Table | Out-String | Write-Debug $StrLabel = New-Text @newTextSplat_Label - return + # if ($LinesBefore -gt 0) { # '' * $LinesBefore # } @@ -172,7 +173,7 @@ function Write-ConsoleLabel { # tofix: It's actually type object unless no property param if ($PropertyName) { # $newTextSplat_Text['Object'] = $Text.psobject.properties.$PropertyName - $newTextSplat_Text['Object'] = $Text.$PropertyName + $newTextSplat_Text['Object'] = $InputObject.$PropertyName if ($null -eq $Text.PropertyName) { # allow the user the option to continue with null value # future: test if property exist, then if null, @@ -194,14 +195,15 @@ function Write-ConsoleLabel { # } # $InputObject ??= $strConst.Null # if ($null -eq $newTextSplat_Text.Object) { - if ( - [string]::IsNullOrWhiteSpace( $newTextSplat_Text.Object) ) { - $StrText = New-Text @newTextSplat_Text - } - else { - $StrText = '' - Write-Error "-Object was $null" - } + $strText = New-Text @newTextSplat_Text + # if ( + # [string]::IsNullOrWhiteSpace( $newTextSplat_Text.Object) ) { + # $StrText = New-Text @newTextSplat_Text + # } + # else { + # $StrText = '' + # # Write-Error "-Object was $null" + # } $FullString = $StrLabel, $Separator, $StrText | Join-String -Sep '' $FullString Br -Count $LinesAfter From f978cb3d0fcb24a05fb1c5db099d60a040e43376 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Wed, 3 Nov 2021 10:47:26 -0500 Subject: [PATCH 05/49] Rewrite: Format-TypeName --- public/ConvertTo-PropertyList.ps1 | 2 + public/Format-TypeName.ps1 | 137 +++++++++++++++++++++++++----- public/Format-TypeName.tests.ps1 | 14 ++- public/Write-ConsoleLabel.ps1 | 41 +++------ 4 files changed, 144 insertions(+), 50 deletions(-) diff --git a/public/ConvertTo-PropertyList.ps1 b/public/ConvertTo-PropertyList.ps1 index 51efc64..e0956b8 100644 --- a/public/ConvertTo-PropertyList.ps1 +++ b/public/ConvertTo-PropertyList.ps1 @@ -53,6 +53,8 @@ function ConvertTo-PropertyList { | select -First 2 | % GetEnumerator | Join-String -sep "`n" -Property { '{0} = {1}' -f ($_.Key, $_.Value) } + .link + Select-NinProperty .link EZOut\ConvertTo-PropertySet #> diff --git a/public/Format-TypeName.ps1 b/public/Format-TypeName.ps1 index 6e5f143..0496625 100644 --- a/public/Format-TypeName.ps1 +++ b/public/Format-TypeName.ps1 @@ -1,4 +1,33 @@ -function Format-TypeName { +function _writeTypeNameString { + <# + .synopsis + macro conditionally prints with parens + + .example + _writeTypeNameString 'Foo' -Brackets + [Foo] + #> + param( + [alias('Text')] + [Parameter(Mandatory, Position = 0, ValueFromPipeline)] + [string]$TypeNameString, + + [Alias('Brackets')] + [Parameter()] + [switch]$WithBrackets + ) + process { + if (! $WithBrackets) { + $TypeNameString + return + } + '[{0}]' -f @($TypeNameString) + return + } +} + + +function Format-TypeName { <# .synopsis Formats type names to be more readable, removes common prefixes @@ -15,12 +44,18 @@ #> param( # list of types as strings - [Parameter(ParameterSetName = 'paramTypeAsString', Mandatory, ValueFromPipeline)] - [string]$TypeName, - - # list of types / type instances - [Parameter(ParameterSetName = 'paramTypeAsInstance', ValueFromPipeline)] - [System.Reflection.TypeInfo]$TypeInstance, + [Alias('Type')] + [Parameter( + ParameterSetName = 'paramTypeAsString', + Mandatory, ValueFromPipeline + )] + [object]$InputObject, + + # # list of types / type instances + # [Parameter( + # ParameterSetName = 'paramTypeAsInstance', + # ValueFromPipeline + # )][System.Reflection.TypeInfo]$TypeInstance, # A List of Namespaces or prefixes to ignore: -IgnoreNamespace [Parameter()][Alias('WithoutPrefix')] @@ -42,6 +77,9 @@ # [Parameter()][switch]$NoBrackets ) begin { + $Config = @{ + # WithoutBrackets + } $DefaultIgnorePrefix = @( 'System.Collections.Generic' 'System.Collections' @@ -51,22 +89,24 @@ 'System' ) - # Sorting by longest regex simplifies namespace collisions when handling removal - $DefaultIgnorePrefix | Join-String -sep ', ' | Label 'IgnoreDefault' | Write-Debug - $IgnorePrefix | Join-String -sep ', ' | Label 'IgnorePrefix' | Write-Debug - - $IgnorePrefix += $DefaultIgnorePrefix - $IgnorePrefix = $IgnorePrefix | Sort-Object -Property Length -Descending - $IgnorePrefix | Join-String -sep ', ' | Label 'IgnoreCombined' | Write-Debug - - - # Write-Warning 'Ignore prefix is not working?' - - if ( $IncludePrefix.Count -gt 0) { - throw 'Prefix include list NYI' + if ($IncludePrefix.count -gt 0) { + Write-Warning 'currently ignoring: -IncludePrefix' + } + if ($IgnorePrefix.count -gt 0) { + Write-Warning 'currently ignoring: -IgnorePrefix' } if ($Colorize) { - throw 'Format.ps1xml Ansi Escape NYI' + throw 'Format.ps1xml Ansi Escape NYI' + # also use ENV:NO_COLOR + } + $Str = @{ + NullSymbol = "`u{2400}" + EmptyStr = 'EmptyStr' + EmptySet = '∅' + } + + $wb = @{ + WithBrackets = $WithBrackets } } @@ -74,8 +114,63 @@ <# refactor: attempt 'typenameString' -as 'type' before other parsing + quick hack before rewrite, otherwise it consumes types #> + # todo: is type already a type? + + # true null? + $tinfo = ($InputObject)?.GetType() + if ($InputObject -is 'type') { + $tinfo = $InputObject + } + + if (($null -eq $InputObject) -or ($null -eq $tinfo)) { + _writeTypeNameString @wb $str.NullSymbol + return + } + # string-y null? + if ([string]::IsNullOrWhiteSpace( $InputObject ) ) { + _writeTypeNameString @wb $str.NullSymbol + return + } + + # is a str, but is a valid type? + $maybeFromStr = $InputObject -as 'type' + if ($maybeFromStr) { + $tinfo = $maybeFromStr + $finalString = '' + # str, but not a valid type + } else { + $finalString = $InputObject + } + + if ($finalString) { + $parsed = $finalString + } else { + $parsed = $tinfo.fullname -replace '^System\.', '' + } + + $dbgMeta = @{ + ParameterSetName = $PSCmdlet.ParameterSetName + Name = $tinfo.Name + FullName = $tinfo.FullName + Type = $tinfo + PreCastInputType = $InputObject.GetType().FullName + FinalString = $finalString + } + + + + $dbgMeta | Format-Dict | wi + + _writeTypeNameString @wb $parsed + + return + + $PSCmdlet.ParameterSetName + | str prefix 'parameterSetName' + | Write-Debug switch ( $PSCmdlet.ParameterSetName ) { 'paramTypeAsString' { if ( [string]::IsNullOrWhiteSpace( $TypeAsString ) ) { diff --git a/public/Format-TypeName.tests.ps1 b/public/Format-TypeName.tests.ps1 index f0fc585..b10eb04 100644 --- a/public/Format-TypeName.tests.ps1 +++ b/public/Format-TypeName.tests.ps1 @@ -1,5 +1,6 @@ BeforeAll { - . $PSCommandPath.Replace('.Tests.ps1', '.ps1') + # . $PSCommandPath.Replace('.Tests.ps1', '.ps1') + Import-Module Ninmonkey.Console -Force } <# @@ -10,6 +11,17 @@ if ($true) { 'system.text'.GetType() | Format-TypeName } #> +InModuleScope 'Ninmonkey.Console' { + Describe '_writeTypeNameString' { + It 'Default' { + _writeTypeNameString 'Foo' | Should -Be 'Foo' + } + It 'Bracket' { + _writeTypeNameString 'Foo' -WithBrackets | Should -Be '[Foo]' + } + } +} + Describe 'Format-TypeName' -Tag 'wip' { Describe 'Generic Types' { diff --git a/public/Write-ConsoleLabel.ps1 b/public/Write-ConsoleLabel.ps1 index c301dd0..28aaa71 100644 --- a/public/Write-ConsoleLabel.ps1 +++ b/public/Write-ConsoleLabel.ps1 @@ -57,7 +57,20 @@ function Write-ConsoleLabel { [Parameter( ParameterSetName = 'TextFromPipe', Mandatory = $false, ValueFromPipeline)] + + + + + <# + Null is allowed for the user's conveinence. + allowing null makes it easier for the user to pipe, like: + 'gc' without -raw or '-split' on newlines + + #> # Text is not required. defaults to no color. + [AllowNull()] + [AllowEmptyCollection()] + [AllowEmptyString()] [Parameter( ParameterSetName = 'TextFromParam', Mandatory = $false, Position = 1)] @@ -186,24 +199,7 @@ function Write-ConsoleLabel { $newTextSplat_Text['Object'] = $InputObject } - # = $Text - # $StrText = New-Text @newTextSplat_Text - # } - # else { - - # } - # } - # $InputObject ??= $strConst.Null - # if ($null -eq $newTextSplat_Text.Object) { $strText = New-Text @newTextSplat_Text - # if ( - # [string]::IsNullOrWhiteSpace( $newTextSplat_Text.Object) ) { - # $StrText = New-Text @newTextSplat_Text - # } - # else { - # $StrText = '' - # # Write-Error "-Object was $null" - # } $FullString = $StrLabel, $Separator, $StrText | Join-String -Sep '' $FullString Br -Count $LinesAfter @@ -214,17 +210,6 @@ function Write-ConsoleLabel { } end { - # Write-Debug 'todo: rewrite to call Write-ConsoleText' } } - -# Write-Warning "Error: rewrite: '$PSCommandPath'" # fix paramset when "label 'a' 'b'" fails - -@' -Label missing fail case: - - Label 'Final Query' $joinedQuery | Write-Information - -'@ -Write-Warning 'either: label or format-dict has a depth overflow' \ No newline at end of file From dc4674a0df8a80dd07ff9e22399f54a086cd5c7a Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Thu, 4 Nov 2021 11:15:58 -0500 Subject: [PATCH 06/49] Format-TypeName: allow nulls, empty, remove throw --- public/Format-TypeName.ps1 | 50 ++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/public/Format-TypeName.ps1 b/public/Format-TypeName.ps1 index 0496625..43bbd45 100644 --- a/public/Format-TypeName.ps1 +++ b/public/Format-TypeName.ps1 @@ -1,4 +1,16 @@ -function _writeTypeNameString { +$__ninColor = @{ + Default = @{ + SkyBlue = '#85BDD8' + Fg = 'gray85' + FgDim = 'gray60' + PesterGreen = '#3EBC77' + PesterPurple = '#A35BAA' + + } +} + + +function _writeTypeNameString { <# .synopsis macro conditionally prints with parens @@ -12,16 +24,29 @@ [Parameter(Mandatory, Position = 0, ValueFromPipeline)] [string]$TypeNameString, + # pre/post [Alias('Brackets')] [Parameter()] - [switch]$WithBrackets + [switch]$WithBrackets, + + # ansi color? + [Alias('WithColor')] + [Parameter()] + [switch]$Color ) process { if (! $WithBrackets) { $TypeNameString return } - '[{0}]' -f @($TypeNameString) + + if (! $Color ) { + '[{0}]' -f @($TypeNameString) + return + } + + + '[{0}]' -f @($TypeNameString) | Write-Color $__ninColor.Default.PesterGreen return } } @@ -41,9 +66,17 @@ function Format-TypeName { [ParameterMetadata](https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.parametermetadata?view=powershellsdk-7.0.0)] [https://docs.microsoft.com/en-us/dotnet/api/system.reflection.typeinfo?view=netcore-3.1#properties] + + .link + Dev.Nin\Get-HelpFromTypeName #> + param( # list of types as strings + + [AllowEmptyString()] + [AllowEmptyCollection()] + [AllowNull()] [Alias('Type')] [Parameter( ParameterSetName = 'paramTypeAsString', @@ -96,7 +129,7 @@ function Format-TypeName { Write-Warning 'currently ignoring: -IgnorePrefix' } if ($Colorize) { - throw 'Format.ps1xml Ansi Escape NYI' + Write-Error 'Format.ps1xml Ansi Escape NYI' # also use ENV:NO_COLOR } $Str = @{ @@ -108,6 +141,13 @@ function Format-TypeName { $wb = @{ WithBrackets = $WithBrackets } + + $color = @{ + SkyBlue = '#85BDD8' + FgDim = 'gray60' + PesterGreen = '#3EBC77' + PesterPurple = '#A35BAA' + } } Process { @@ -196,7 +236,7 @@ function Format-TypeName { $TypeAsString = $TypeInstance.FullName break } - default { throw "not implemented parameter set: $switch" } + default { Write-Error "not implemented parameter set: '$switch'" } } $filteredName = $TypeAsString From fc65cdd18e2c30e888cba888fb93447c2c2c2067 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Thu, 4 Nov 2021 11:46:37 -0500 Subject: [PATCH 07/49] Format-TypeName: Fixed indirect recursion bug --- public/Format-TypeName.ps1 | 6 +++++- public/Get-NinAlias.ps1 | 6 +++++- public_autoloader/Get-HelpFromTypeName.ps1 | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/public/Format-TypeName.ps1 b/public/Format-TypeName.ps1 index 43bbd45..7ced1a6 100644 --- a/public/Format-TypeName.ps1 +++ b/public/Format-TypeName.ps1 @@ -110,6 +110,8 @@ function Format-TypeName { # [Parameter()][switch]$NoBrackets ) begin { + # $x = 10 + # return $Config = @{ # WithoutBrackets } @@ -151,6 +153,8 @@ function Format-TypeName { } Process { + # $x2 = 0 + # return <# refactor: attempt 'typenameString' -as 'type' before other parsing @@ -202,7 +206,7 @@ function Format-TypeName { - $dbgMeta | Format-Dict | wi + $dbgMeta | Format-Table | Out-String | wi _writeTypeNameString @wb $parsed diff --git a/public/Get-NinAlias.ps1 b/public/Get-NinAlias.ps1 index 50fdb0a..631831d 100644 --- a/public/Get-NinAlias.ps1 +++ b/public/Get-NinAlias.ps1 @@ -26,9 +26,12 @@ function Get-NinAlias { PS> Get-NinAlias -List .notes - future: - [ ] dynamic completer the modules from -list + .link + Dev.Nin\Find-CommandWithParameterAlias + .link + Ninmonkey.Console\Get-NinAlias #> [CmdletBinding(DefaultParameterSetName = 'Search')] param ( @@ -54,6 +57,7 @@ function Get-NinAlias { } process { + # Next: [AliasInfo] type always shows the [Resolve-Command -Qualified] $meta = @{ MyModule = @() NoSource = Get-Alias * | Where-Object { [string]::IsNullOrWhiteSpace( $_.Source ) } diff --git a/public_autoloader/Get-HelpFromTypeName.ps1 b/public_autoloader/Get-HelpFromTypeName.ps1 index 10b1654..7c33b2d 100644 --- a/public_autoloader/Get-HelpFromTypeName.ps1 +++ b/public_autoloader/Get-HelpFromTypeName.ps1 @@ -16,6 +16,8 @@ function Get-HelpFromTypeName { . .outputs [string | None] + .link + Ninmonkey.Console\Format-TypeName #> [Alias('HelpFromType')] From 2037b8981e936b6bb2252e0c6438a8e5dcfdf632 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Thu, 4 Nov 2021 13:37:19 -0500 Subject: [PATCH 08/49] iter --- public/Format-TypeName.ps1 | 95 +++++++++++++++++++---- public/Format-TypeName.tests.ps1 | 128 ++++++++++++++++++++----------- 2 files changed, 160 insertions(+), 63 deletions(-) diff --git a/public/Format-TypeName.ps1 b/public/Format-TypeName.ps1 index 7ced1a6..c2b4729 100644 --- a/public/Format-TypeName.ps1 +++ b/public/Format-TypeName.ps1 @@ -20,10 +20,22 @@ function _writeTypeNameString { [Foo] #> param( - [alias('Text')] - [Parameter(Mandatory, Position = 0, ValueFromPipeline)] + # Can be anything, it's a string + [alias('Name')] + [Parameter( + ParameterSetName = 'NameOnly', + Mandatory, Position = 0, + ValueFromPipeline + )] [string]$TypeNameString, + # may not be a real namespace. used for color + [Alias('NameSpace')] + [Parameter(Position = 1 + # ValueFromPipelineByPropertyName + )] + [String]$Prefix, + # pre/post [Alias('Brackets')] [Parameter()] @@ -34,6 +46,14 @@ function _writeTypeNameString { [Parameter()] [switch]$Color ) + begin { + <# + todo: next: Will + - show a bunch of (visual only) tests of Format-TYpeNameColor + colorize brackets, namespace, typename + #> + + } process { if (! $WithBrackets) { $TypeNameString @@ -61,12 +81,17 @@ function Format-TypeName { PS> $cat.pstypenames | Format-TypeName | join-string -sep ', ' { "[$_]" } [Selected.System.Management.Automation.PSCustomObject], [Nin.Animal], [PSCustomObject], [Object] + .notes see also: [ParameterMetadata](https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.parametermetadata?view=powershellsdk-7.0.0)] [https://docs.microsoft.com/en-us/dotnet/api/system.reflection.typeinfo?view=netcore-3.1#properties] + warning: + A low level function like this, should (probably) never use functions like 'format-dict', + because of indirect recursion + .link Dev.Nin\Get-HelpFromTypeName #> @@ -135,9 +160,10 @@ function Format-TypeName { # also use ENV:NO_COLOR } $Str = @{ - NullSymbol = "`u{2400}" - EmptyStr = 'EmptyStr' - EmptySet = '∅' + NullSymbol = "`u{2400}" + EmptyStr = 'EmptyStr' + EmptySet = '∅' + OnlyWhitespace = 'StringIsBlank' } $wb = @{ @@ -157,6 +183,9 @@ function Format-TypeName { # return <# refactor: + + if type doesn't resolve, and get type isn't non-string, then return self + attempt 'typenameString' -as 'type' before other parsing quick hack before rewrite, otherwise it consumes types #> @@ -164,51 +193,83 @@ function Format-TypeName { # todo: is type already a type? # true null? + $startedAsString = $InputObject -is 'string' + $tinfo = ($InputObject)?.GetType() if ($InputObject -is 'type') { $tinfo = $InputObject } + # is a str, but is a valid type? + $maybeFromStr = $InputObject -as 'type' + $resolvedFromStringFailed = $null -eq $maybeFromStr + # if (($null -eq $InputObject) -or ($null -eq $tinfo)) { if (($null -eq $InputObject) -or ($null -eq $tinfo)) { + # might need to move out + Write-Debug "I think valid str-resolve-types fall here, but shouldn't '$tinfo', '$resolvedFromStringFailed'" + Write-Debug 'if type doesn''t resolve, and get type isn''t non-string, then return self' _writeTypeNameString @wb $str.NullSymbol return } # string-y null? if ([string]::IsNullOrWhiteSpace( $InputObject ) ) { - _writeTypeNameString @wb $str.NullSymbol + _writeTypeNameString @wb $str.OnlyWhitespace return } + + @{ + InputObject = $InputObject + tinfo = $tinfo + maybeFromStr = $maybeFromStr ?? '$null' + resolvedFromStringFailed = $resolvedFromStringFailed + } | Format-Table | Out-String | Write-Debug + + if (! $resolvedFromStringFailed) { + # good, keep it + $parsed = + + # if($) + + $finalString = $tinfo.GetType().FullName + } else { - # is a str, but is a valid type? - $maybeFromStr = $InputObject -as 'type' + $finalString + $maybeFromStr.GetType().FullName + } + if ($maybeFromStr) { $tinfo = $maybeFromStr $finalString = '' # str, but not a valid type } else { - $finalString = $InputObject + $finalString = $tinfo.FullName } if ($finalString) { $parsed = $finalString } else { - $parsed = $tinfo.fullname -replace '^System\.', '' + $parsed = $tinfo.FullNames } $dbgMeta = @{ - ParameterSetName = $PSCmdlet.ParameterSetName - Name = $tinfo.Name - FullName = $tinfo.FullName - Type = $tinfo - PreCastInputType = $InputObject.GetType().FullName - FinalString = $finalString + ParameterSetName = $PSCmdlet.ParameterSetName + Name = $tinfo.Name + FullName = $tinfo.FullName + Type = $tinfo + PreCastInputType = $InputObject.GetType().FullName + FinalString = $finalString + # ... extra + InputObject = $InputObject + tinfo = $tinfo + maybeFromStr = $maybeFromStr ?? '$null' + resolvedFromStringFailed = $resolvedFromStringFailed } $dbgMeta | Format-Table | Out-String | wi - _writeTypeNameString @wb $parsed + _writeTypeNameString @wb $parsed # this part, actually goes into rendering? no? return diff --git a/public/Format-TypeName.tests.ps1 b/public/Format-TypeName.tests.ps1 index b10eb04..60ff1f4 100644 --- a/public/Format-TypeName.tests.ps1 +++ b/public/Format-TypeName.tests.ps1 @@ -13,12 +13,46 @@ if ($true) { #> InModuleScope 'Ninmonkey.Console' { Describe '_writeTypeNameString' { - It 'Default' { - _writeTypeNameString 'Foo' | Should -Be 'Foo' - } - It 'Bracket' { - _writeTypeNameString 'Foo' -WithBrackets | Should -Be '[Foo]' - } + + Describe 'Color' -Tag 'Ansi', 'Color' { + Context 'Raw Strings Type' { + It 'Default' { + _writeTypeNameString 'Foo' | Should -Be 'Foo' + } + It 'Bracket' { + _writeTypeNameString 'Foo' -WithBrackets | Should -Be '[Foo]' + } + } + } + Describe 'NoColor' -Tag 'NO_COLOR' { + Context 'Raw Strings Type' { + It 'Default' { + _writeTypeNameString 'Foo' | Should -Be 'Foo' + } + It 'Bracket' { + _writeTypeNameString 'Foo' -WithBrackets | Should -Be '[Foo]' + } + } + Context 'Real Object FullNames' { + BeforeEach { + $Sample = @{ + File = Get-Item . + } + } + It 'File: -Bracket is ' -Foreach @( + @{ + Expected = 'System.IO.DirectoryInfo' ; WithBrackets = $false + } + @{ + Expected = '[System.IO.DirectoryInfo]' ; WithBrackets = $true + } + ) { + $Name = $Sample.File.GetType().FullName + _writeTypeNameString -TypeNameString $Name -WithBrackets:$WithBrackets + | Should -Be $Expected + } + } + } } } @@ -69,54 +103,56 @@ Describe 'Format-TypeName' -Tag 'wip' { | Should -Be 'Func`2[String, Object]' # or verbosely: 'System.Func`2[System.String,System.Object]' } + Describe 'IgnorePrefix' { - It 'String: FileInfo' { - 'System.IO.FileInfo' | Format-TypeName - | Should -Be '[IO.FileInfo]' - } + It 'String: FileInfo' { + 'System.IO.FileInfo' | Format-TypeName + | Should -Be '[IO.FileInfo]' + } - It 'String: FileInfo' { - 'System.IO.FileInfo' | Format-TypeName -NoBrackets - | Should -Be 'IO.FileInfo' - } + It 'String: FileInfo' { + 'System.IO.FileInfo' | Format-TypeName -NoBrackets + | Should -Be 'IO.FileInfo' + } - It 'String: FileInfo -IgnorePrefix "System.IO" -NoBrackets' { - 'System.IO.FileInfo' | Format-TypeName -IgnorePrefix 'System.IO' -NoBrackets - | Should -Be 'FileInfo' - } + It 'String: FileInfo -IgnorePrefix "System.IO" -NoBrackets' { + 'System.IO.FileInfo' | Format-TypeName -IgnorePrefix 'System.IO' -NoBrackets + | Should -Be 'FileInfo' + } - It 'TypeInfo instance: FileInfo' { - $file = (Get-ChildItem . -Directory | Select-Object -First 1) - $file.GetType() | Format-TypeName - | Should -Be '[IO.DirectoryInfo]' - } + It 'TypeInfo instance: FileInfo' { + $file = (Get-ChildItem . -Directory | Select-Object -First 1) + $file.GetType() | Format-TypeName + | Should -Be '[IO.DirectoryInfo]' + } - It 'TypeInfo instance: FileInfo' { - $file = (Get-ChildItem . -Directory | Select-Object -First 1) - $file.GetType() | Format-TypeName - | Should -Be '[IO.DirectoryInfo]' - } + It 'TypeInfo instance: FileInfo' { + $file = (Get-ChildItem . -Directory | Select-Object -First 1) + $file.GetType() | Format-TypeName + | Should -Be '[IO.DirectoryInfo]' + } - It 'String: FileInfo -IgnorePrefix "System.IO" -NoBrackets' { - $file = (Get-ChildItem . -Directory | Select-Object -First 1) - $file.GetType() | Format-TypeName -IgnorePrefix 'System.IO' -NoBrackets - | Should -Be 'DirectoryInfo' - } + It 'String: FileInfo -IgnorePrefix "System.IO" -NoBrackets' { + $file = (Get-ChildItem . -Directory | Select-Object -First 1) + $file.GetType() | Format-TypeName -IgnorePrefix 'System.IO' -NoBrackets + | Should -Be 'DirectoryInfo' + } - It 'Pipe: Types as text -NoBrackets' { - # $inputList = 'b.system.bar', 'Int32', 'foo', 'Object[]', 'foo[]' - $inputList = 'b.system.bar', (23).GetType(), 'System.foo', 'System.Object[]', 'foo[]' - $expected = 'b.system.bar', 'Int32', 'foo', 'Object[]', 'foo[]' - $inputList | Format-TypeName -NoBrackets - | Should -Be $expected - } + It 'Pipe: Types as text -NoBrackets' { + # $inputList = 'b.system.bar', 'Int32', 'foo', 'Object[]', 'foo[]' + $inputList = 'b.system.bar', (23).GetType(), 'System.foo', 'System.Object[]', 'foo[]' + $expected = 'b.system.bar', 'Int32', 'foo', 'Object[]', 'foo[]' + $inputList | Format-TypeName -NoBrackets + | Should -Be $expected + } - It 'Pipe: Types as text' { - # $inputList = 'b.system.bar', 'Int32', 'foo', 'Object[]', 'foo[]' - $inputList = 'b.system.bar', (23).GetType(), 'System.foo', 'System.Object[]', 'foo[]' - $expected = '[b.system.bar]', '[Int32]', '[foo]', '[Object[]]', '[foo[]]' - $inputList | Format-TypeName - | Should -Be $expected + It 'Pipe: Types as text' { + # $inputList = 'b.system.bar', 'Int32', 'foo', 'Object[]', 'foo[]' + $inputList = 'b.system.bar', (23).GetType(), 'System.foo', 'System.Object[]', 'foo[]' + $expected = '[b.system.bar]', '[Int32]', '[foo]', '[Object[]]', '[foo[]]' + $inputList | Format-TypeName + | Should -Be $expected + } } Context 'GenericsWithNestedClass: NYI' -Tag 'wip', 'nyi' { From 0c2ed2734a4d93310c187ccc88ebb31f367995c4 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Fri, 5 Nov 2021 11:45:30 -0500 Subject: [PATCH 09/49] Update Format-TypeName.ps1 --- public/Format-TypeName.ps1 | 127 ++++++++++++++++++++++++++++++++----- 1 file changed, 112 insertions(+), 15 deletions(-) diff --git a/public/Format-TypeName.ps1 b/public/Format-TypeName.ps1 index c2b4729..1dfe96d 100644 --- a/public/Format-TypeName.ps1 +++ b/public/Format-TypeName.ps1 @@ -10,6 +10,8 @@ } + +# } function _writeTypeNameString { <# .synopsis @@ -23,18 +25,18 @@ function _writeTypeNameString { # Can be anything, it's a string [alias('Name')] [Parameter( - ParameterSetName = 'NameOnly', + # ParameterSetName = '', Mandatory, Position = 0, - ValueFromPipeline + ValueFromPipeline, + ValueFromPipelineByPropertyName )] - [string]$TypeNameString, + [string]$TypeName, # may not be a real namespace. used for color - [Alias('NameSpace')] - [Parameter(Position = 1 - # ValueFromPipelineByPropertyName + [Parameter( + Position = 1, ValueFromPipelineByPropertyName )] - [String]$Prefix, + [String]$NameSpace, # pre/post [Alias('Brackets')] @@ -56,17 +58,17 @@ function _writeTypeNameString { } process { if (! $WithBrackets) { - $TypeNameString + $TypeName return } if (! $Color ) { - '[{0}]' -f @($TypeNameString) + '[{0}]' -f @($TypeName) return } - '[{0}]' -f @($TypeNameString) | Write-Color $__ninColor.Default.PesterGreen + '[{0}]' -f @($TypeName) | Write-Color $__ninColor.Default.PesterGreen return } } @@ -128,7 +130,10 @@ function Format-TypeName { # surround type names with '[]' ? [Alias('Brackets')] - [Parameter()][switch]$WithBrackets + [Parameter()][switch]$WithBrackets, + + # PassThru formatted typename + [Parameter()][switch]$PassThru # [Alias('WithoutBrackets')] @@ -193,9 +198,91 @@ function Format-TypeName { # todo: is type already a type? # true null? - $startedAsString = $InputObject -is 'string' - + if ($Null -eq $InputObject) { + _writeTypeNameString @wb $str.NullSymbol + return + } + + $startedAsString = $InputObject -is 'string' + $startedAsType = $InputObject -is 'type' $tinfo = ($InputObject)?.GetType() + + + if ($InputObject -is 'type') { + $tinfo = $InputObject + } else { + $tinfo = ($InputObject)?.GetType() + } + + if ($startedAsString) { + # todo: next: PR: auto cast using -as + $parsed = $InputObject -replace '^System\.', '' + # $nameSpace = + } else { + $parsed = $tinfo.FullName -replace '^System\.', '' + } + + $parsedInfo = [ordered]@{ + PSTypeName = 'nin.ParsedTypeName' + <# + duties: + external code/type has 'nin.TypeInfo' and other inspection + + Format-TypeName: + least amount of info, and dependencies as possible. + otherwise recursion + #> + # RenderName = # plus, here, it's recursive. visual, maybe not? $tinfo | Format-TypeName -WithBrackets + FullName = $tinfo.FullName + Name = $tinfo.Name # would be format style / compute some + NameSpace = $tinfo.NameSpace + OriginalReference = $tinfo + } + + if ($PassThru) { + [pscustomobject]$parsedInfo + return + } + + # -replace '^System\.', '' + _writeTypeNameString @wb -Name $parsedInfo.Name -Namespace $parsedInfo.NameSpace + # _writeTypeNameString @wb -TypeNameString $ninTypeInfo -Namespace ($tinfo.Namespace ?? '') + + + + + return + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Write-Debug 'skipping logic' if ($InputObject -is 'type') { $tinfo = $InputObject } @@ -334,9 +421,19 @@ function NestedOrNot( [type]$TypeInfo ) { $true -eq $typeinfo.IsNested | Label 'IsNested?: ' $nestedTypeName = $typeinfo.DeclaringType.Name, $typeinfo.Name -join '+' ( $typeinfo.namespace), $nestedTypeName -join '.' - } - + } } + +<# + +test it: +Import-Module Ninmonkey.Console -Force + +(gi . ) | Format-TypeName -ea break + +(gi . ).GetType() | Format-TypeName -ea break + +#> $warningText = @' 1] [string](([system.collections.generic.list[hashtable]]@()).GetType()) From f6b0f49d8c3fb147c7928a037be600a2d13cfd0b Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Sat, 6 Nov 2021 16:51:18 -0500 Subject: [PATCH 10/49] Cleaned up Errorhandling --- public/ConvertTo-Timespan.ps1 | 54 +++++++++++++++++++++----------- public/Format-TypeName.tests.ps1 | 13 ++++++++ 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/public/ConvertTo-Timespan.ps1 b/public/ConvertTo-Timespan.ps1 index b654b84..8f71df2 100644 --- a/public/ConvertTo-Timespan.ps1 +++ b/public/ConvertTo-Timespan.ps1 @@ -2,15 +2,14 @@ function ConvertTo-Timespan { <# .synopsis - converts fuzzy dates to a [datetime] + converts strings to a [timespan] .description minimal error detection, or some defaults apply less impact - ex: Without strict mode, if the $RelativeText has extra data + + ex: Without strict mode, if $RelativeText has extra data after splitting, then there's an error. new: - throw errors when no value is created, user may ignore it. - - future: decent deterministic error dectection is 1] attempt to grab matches in the orignal string: @@ -24,6 +23,30 @@ function ConvertTo-Timespan { .example 1d3h4s -> #duration(1, 3, 4)' + .example + $tslist = @( + 2 | days + 3 | hours + ) + + $ts_sum = $tslist | Measure-Object TotalMilliSeconds -Sum | % Sum | %{ + [timespan]::new(0,0,0,0,$_) + } + + $ts_sum | Should -be (RelativeTs 2d3h -debug) + + $tslist = @( + 2 | days + 3 | hours + ) + + $total_ms = $tslist | Measure-Object TotalMilliSeconds -Sum | % Sum + + $ts_sum = $total_ms | %{ + [timespan]::new(0,0,0,0,$_) + } + + $ts_sum | Should -be (RelativeTs 2d3h) .outputs [timespan] or null .notes @@ -31,6 +54,8 @@ function ConvertTo-Timespan { - [ ] better verb? better name, timespan? ConvertTo ? 'New-RelativeTimespan' or 'ConvertTo-Timespan' ? + .link + https://gist.github.com/Szeraax/43aa193e0759d9b091faaaa2f5a03cc9 #> [cmdletbinding( PositionalBinding = $false)] @@ -75,7 +100,7 @@ function ConvertTo-Timespan { # todo: If anything is **not captured**, ie: the unmatched length is > 0 # then throw a parse error if (!($RelativeText -match $Regex.ParseString)) { - Write-Error "Failed parsing string '$RelativeText'" -Category InvalidArgument + Write-Error -m "Failed parsing string '$RelativeText'" -Category InvalidArgument return } @@ -86,29 +111,22 @@ function ConvertTo-Timespan { $Milliseconds = $Matches.Milliseconds ?? 0 $Days, $Hours, $Minutes, $Seconds, $Milliseconds - | Join-String -sep ', ' | Label 'Args' | Write-Debug - + | Join-String -sep ', ' -op 'Timespan args: ' | Write-Debug $ts = [timespan]::new($Days, $Hours, $Minutes, $Seconds, $Milliseconds) - if ($ts -eq 0 -or $null -eq $ts) { - # write-debug '[timespan] == 0' - # Do I want to opt in or out? + if ($ts -eq 0 -or $null -eq $ts) { + $splatError = @{} if (! $ZeroIsValid) { $splatError = @{ ErrorAction = 'Stop' } } - Write-Error '[timespan] == 0' -TargetObject $RelativeText @splatError + Write-Error -m '[timespan] == 0' -TargetObject $RelativeText @splatError } $ts - } - catch { - Write-Error -Message "Failed parsing string '$RelativeText'" -ErrorRecord $_ + } catch { + Write-Error -Message "Failed parsing string '$RelativeText'" # throw [System.MissingFieldException]::new('Could not access field', $_.Exception) } } } - -# hr 2 -# RelativeTs '3' -ea break -# RelativeTs '0' diff --git a/public/Format-TypeName.tests.ps1 b/public/Format-TypeName.tests.ps1 index 60ff1f4..91de5d1 100644 --- a/public/Format-TypeName.tests.ps1 +++ b/public/Format-TypeName.tests.ps1 @@ -89,6 +89,19 @@ Describe 'Format-TypeName' -Tag 'wip' { $Sample = 'system.io.fileinfo' $sample | ForEach-Object { $_ -as 'type' } | Format-TypeName -Brackets } + It 'PrettyPrintMe' { + $rawString = @' +Cannot create object of type "System.Collections.Generic.Dictionary`2[System.String,System.Object]". The mystring property was not found for the System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Object, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]] object. The available property is: [Comparer ] , [Count ] , [Keys ] , [Values ] , [IsReadOnly ] , [IsFixedSize ] , [SyncRoot ] , [IsSynchronized ] +'@ + # maybe tokenize smallest chunks of [[.*?]] + $rawString -replace (@( + ReLit '[[' + '.*?' + ReLit '[[' + ) -join '') , "`n`n" + $dict = [System.Collections.Generic.Dictionary[string, object]]@{'mystring' = 'myobject' } + $False | Should -Be $True -Because 'test is not written yet' + } It 'AutoConvert Inputs' { $Sample = 'system.io.fileinfo' $res1 = $sample | Format-TypeName -Brackets From 4d2c6fabe9bfc7080e642cc695c63f19371bdf25 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Sat, 6 Nov 2021 22:09:56 -0500 Subject: [PATCH 11/49] Misc tests added --- public/ConvertTo-Timespan.tests.ps1 | 33 +++++++ public/Format-TypeName.ps1 | 2 + public/Format-TypeName.tests.ps1 | 6 ++ public/Get-ObjectType.ps1 | 28 ++++-- public/Resolve-CommandName.tests.ps1 | 14 +-- public_autoloader/Get-ObjectTypeHelp.ps1 | 87 +++++++++++++++++++ .../Get-ObjectTypeHelp.tests.ps1 | 38 ++++++++ 7 files changed, 197 insertions(+), 11 deletions(-) create mode 100644 public/ConvertTo-Timespan.tests.ps1 create mode 100644 public_autoloader/Get-ObjectTypeHelp.ps1 create mode 100644 public_autoloader/Get-ObjectTypeHelp.tests.ps1 diff --git a/public/ConvertTo-Timespan.tests.ps1 b/public/ConvertTo-Timespan.tests.ps1 new file mode 100644 index 0000000..d1f2e2b --- /dev/null +++ b/public/ConvertTo-Timespan.tests.ps1 @@ -0,0 +1,33 @@ +#Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.0' } +#Requires -Version 7 + +BeforeAll { + Import-Module Ninmonkey.Console -Force +} + +Describe 'ConvertTo-Timespan' { + it 'first' { + $tslist = @( + 2 | days + 3 | hours + ) + + $ts_sum = $tslist | Measure-Object TotalMilliSeconds -Sum | % Sum | %{ + [timespan]::new(0,0,0,0,$_) + } + + $ts_sum | Should -be (RelativeTs 2d3h -debug) + + $tslist = @( + 2 | days + 3 | hours + ) + + $total_ms = $tslist | Measure-Object TotalMilliSeconds -Sum | % Sum + + $ts_sum = $total_ms | %{ + [timespan]::new(0,0,0,0,$_) + } + + } +} \ No newline at end of file diff --git a/public/Format-TypeName.ps1 b/public/Format-TypeName.ps1 index 1dfe96d..83496ec 100644 --- a/public/Format-TypeName.ps1 +++ b/public/Format-TypeName.ps1 @@ -21,6 +21,7 @@ function _writeTypeNameString { _writeTypeNameString 'Foo' -Brackets [Foo] #> + [cmdletbinding()] param( # Can be anything, it's a string [alias('Name')] @@ -98,6 +99,7 @@ function Format-TypeName { Dev.Nin\Get-HelpFromTypeName #> + [cmdletbinding()] param( # list of types as strings diff --git a/public/Format-TypeName.tests.ps1 b/public/Format-TypeName.tests.ps1 index 91de5d1..ad49847 100644 --- a/public/Format-TypeName.tests.ps1 +++ b/public/Format-TypeName.tests.ps1 @@ -58,6 +58,12 @@ InModuleScope 'Ninmonkey.Console' { Describe 'Format-TypeName' -Tag 'wip' { + It 'First Bug' { + (Get-Item .).pstypenames | Format-TypeName -Brackets + (Get-Item .).pstypenames | Format-TypeName -Brackets + | Sort-Object -Unique | len + | Should -Not -Be 1 + } Describe 'Generic Types' { It 'Non-Instance of Generic from ClassExplorer' { diff --git a/public/Get-ObjectType.ps1 b/public/Get-ObjectType.ps1 index 6309e46..08fe9f5 100644 --- a/public/Get-ObjectType.ps1 +++ b/public/Get-ObjectType.ps1 @@ -13,6 +13,23 @@ - parameter type that is not an array [obj] - process returns array ', $array' - then optionally enumerate on [obj] if I want to inspect child element + + + .example + $f = ls . -File | first 1 + $d = gi . + $time = get-date + $ps = ps * | first 1 + + $f, $d, $time, $ps | typeof + + 'see also' + $otherCommands = @( + 'Dev.Nin\Get-DevInspectObject' + 'Dev.Nin\What-TypeInfo' + 'Ninmonkey.Console\Get-ObjectType' + [me] : 'TypeOf' + ) | resCmd -QualifiedName #> param( # InputObject[s] to get type[s] of @@ -33,6 +50,7 @@ ) begin { + # if ($PassThru) { # throw "NotImplementedError: -PassThru" # } @@ -43,11 +61,11 @@ } process { - Write-Error 'rewrite from scratch' + # Write-Error 'rewrite from scratch' $typeList.Add( $InputObject ) } end { - Write-Error 'rewrite from scratch' + # Write-Error 'rewrite from scratch' # $ switch ($Format) { @@ -202,15 +220,13 @@ function old_Get-ObjectType { if ($InputObject -is 'type') { $curTypeInfo = $InputObject $curTypeObj = $InputObject - } - elseif ($InputObject -is [string]) { + } elseif ($InputObject -is [string]) { $curTypeInfo = $InputObject -as [type] if ($null -eq $curTypeInfo) { throw "Failed on typeName: '$curTypeInfo'" } $curTypeObj = $null - } - else { + } else { $curTypeInfo = $InputObject.GetType() $curTypeObj = $InputObject } diff --git a/public/Resolve-CommandName.tests.ps1 b/public/Resolve-CommandName.tests.ps1 index e0743af..016ceab 100644 --- a/public/Resolve-CommandName.tests.ps1 +++ b/public/Resolve-CommandName.tests.ps1 @@ -9,7 +9,13 @@ BeforeAll { } Describe 'Resolve-CommandName' { - + It 'Temp test to flag bug' { + + { Get-Command '?str' | resCmd -q } | Should -Not -Throw + # output: + # gc: @splat: + # error the term jstr is not a command + } Describe 'Resolve Source Name' { It ' returns ' -ForEach @( @{ Query = 'ls'; Expected = 'Microsoft.PowerShell.Management\Get-ChildItem' } @@ -47,8 +53,7 @@ Describe 'Resolve-CommandName' { if ($null -eq $ExpectedType) { $result.count | Should -Be 0 - } - else { + } else { $result | Select-Object -First 1 | Should -BeOfType $ExpectedType } } @@ -105,8 +110,7 @@ Describe 'Resolve-CommandName' { if ($ExpectThrow) { { Resolve-CommandName -CommandName $Name -Ea:$ErrorAction } | Should -Throw -Because $Because - } - else { + } else { { Resolve-CommandName -CommandName $Name -Ea:$ErrorAction } | Should -Not -Throw -Because $Because } diff --git a/public_autoloader/Get-ObjectTypeHelp.ps1 b/public_autoloader/Get-ObjectTypeHelp.ps1 new file mode 100644 index 0000000..a74996a --- /dev/null +++ b/public_autoloader/Get-ObjectTypeHelp.ps1 @@ -0,0 +1,87 @@ +#Requires -Version 7 + +if ( $publicToExport ) { + $publicToExport.function += @( + 'Get-ObjectTypeHelp' + ) + $publicToExport.alias += @( + 'HelpFromType' + ) +} + +# 'DevTool💻.Get-HelpFromType' +function Get-ObjectTypeHelp { + <# + .synopsis + Opens the docs for the current type, in your default browser + .description + It uses 'Get-Unique -OnType' so you only get 1 result for duplicated types + .example + . + .outputs + [string | None] + .link + Ninmonkey.Console\Format-TypeName + + #> + [Alias('HelpFromType')] + [CmdletBinding(PositionalBinding = $false)] + param( + [Parameter(Mandatory, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)] + [object]$InputObject, + + # Return urls, without opening them + [Parameter()] + [switch]$PassThru + ) + + begin { + # list of full type nam;es + $NameList = [list[string]]::new() + $TemplateUrl = 'https://docs.microsoft.com/en-us/dotnet/api/{0}' + } + process { + if ( [string]::IsNullOrWhiteSpace($InputObject) ) { + return + } + # if generics cause problems, try another method + if ($InputObject -is 'type') { + $NameList.Add( $InputObject.FullName ) + $NameList.Add( @( + $InputObject | Select-Object Namespace, Name | Join-String -sep '.' + ) ) + return + } + if ($InputObject -is 'string') { + $typeInfo = $InputObject -as 'type' + $NameList.Add( $typeInfo.FullName ) + return + } + + $NameList.Add( $InputObject.GetType().FullName ) + } + end { + # '... | Get-Unique -OnType is' great if you want to limit a list to 1 per unique type + # like 'ls . -recursse | Get-HelpFromTypeName' + # But I'm using strings, so 'Sort -Unique' works + $NameList + | Sort-Object -Unique + | ForEach-Object { + $url = $TemplateUrl -f $_ + + "Url: '$url' for '$_'" | Write-Debug + + if ($PassThru) { + $url; return + } + Start-Process -path $url + } + } +} + + + + +if (! $publicToExport) { + +} diff --git a/public_autoloader/Get-ObjectTypeHelp.tests.ps1 b/public_autoloader/Get-ObjectTypeHelp.tests.ps1 new file mode 100644 index 0000000..d7f8d32 --- /dev/null +++ b/public_autoloader/Get-ObjectTypeHelp.tests.ps1 @@ -0,0 +1,38 @@ +BeforeAll { + Import-Module Ninmonkey.Console -Force +} + +Describe 'Get-HelpFromTypeName' { + BeforeAll { + $Url = @{ + 'TimeSpan' = 'https://docs.microsoft.com/en-us/dotnet/api/System.TimeSpan' + 'DateTime' = 'https://docs.microsoft.com/en-us/dotnet/api/System.DateTime' + } + } + It 'From String' { + 'System.TimeSpan' | Get-HelpFromTypeName -PassThru + | Should -Be $Url.TimeSpan + } + It 'From Instance list' { + $Expected = @( + $url.TimeSpan + $url.DateTime + ) + + $query = @( + [datetime]::Now + [timespan]::new(0) + ) | HelpFromType -PassThru + + $query | Should -Contain $url.TimeSpan + $query | Should -Contain $url.DateTime + } + It 'Throttle Duplicates' { + $files = Get-ChildItem ~ + $expected = $files | Get-Unique -OnType + + $files + | HelpFromType -PassThru + | len | Should -Be $expected + } +} \ No newline at end of file From dee336fac1d8b5882c08c16c479edd1642c1f33d Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Sun, 7 Nov 2021 18:39:47 -0600 Subject: [PATCH 12/49] ResCmd: Optionally keep aliases in output --- public/Resolve-CommandName.ps1 | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/public/Resolve-CommandName.ps1 b/public/Resolve-CommandName.ps1 index 429e567..8a35e27 100644 --- a/public/Resolve-CommandName.ps1 +++ b/public/Resolve-CommandName.ps1 @@ -33,6 +33,11 @@ function Resolve-CommandName { # Returns the source and command as text, ex: 'ls' outputs: 'Microsoft.PowerShell.Management\Get-ChildItem' [Parameter()][switch]$QualifiedName, + # preserves alias's original names in the output + [Parameter()][switch]$IncludeAlias, + + + # Error if not exactly one match is found [Alias('Strict')] [Parameter()][switch]$OneOrNone @@ -57,10 +62,9 @@ function Resolve-CommandName { $commands = Get-Command @getCommandSplat | ForEach-Object { # Get-Command -Name $_.ResolvedCommand - if ($_.CommandType -eq 'Alias') { + if ($_.CommandType -eq 'Alias' -and (! $IncludeAlias)) { $_.ResolvedCommand - } - else { + } else { $_ } } @@ -78,8 +82,7 @@ function Resolve-CommandName { if ($OneOrNone) { if ($commands.count -ne 1) { "Match count 1 != $($Commands.count)" | Write-Error - } - else { + } else { "Match count 1 != $($Commands.count)" | Write-Warning } } From 737c11f2fa02e9f5c18a679b737b2deee63e2157 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Mon, 8 Nov 2021 17:28:35 -0600 Subject: [PATCH 13/49] Improved Format->RelativePath, now it's robust against inputs --- public/Format-RelativePath.ps1 | 74 ++++++++++++++++++++++------ public/Format-RelativePath.tests.ps1 | 50 +++++++++++++++++++ 2 files changed, 108 insertions(+), 16 deletions(-) create mode 100644 public/Format-RelativePath.tests.ps1 diff --git a/public/Format-RelativePath.ps1 b/public/Format-RelativePath.ps1 index 50604e4..428df70 100644 --- a/public/Format-RelativePath.ps1 +++ b/public/Format-RelativePath.ps1 @@ -2,9 +2,18 @@ Export-ModuleMember -Alias 'ConvertTo-RelativePath' function Format-RelativePath { <# .synopsis - convert full path names to relative paths, optionally relative any path. - .notes + relative paths, allows you to pipe to commands that expects raw text like 'fzf preview'. + .description + Transforms both paths as text and (get-item)s + - convert to the raw File.FullName raw text + - convert to relative path + If not specified, it uses your current directory + + for files/folders, converts to the string relative path + this is meant to pre-process items as was as j todo: get the dotnet [io.path] method, which is a lot faster + .example + newestItem🔎 Code-Workspace💻 | StripAnsi | To->RelativePath | pipe->Peek .example 🐒> ls . -Recurse *.json | Format-RelativePath .example @@ -28,32 +37,54 @@ function Format-RelativePath { C:\Users\cppmo_000\.vscode\argv.json .example # use a specific base path - PS> ls ~\.vscode | select -First 2 | Format-RelativePath ~\.vscode\ - .\extensions - .\argv.json + 🐒> ls -Force ~\.vscode | Format-RelativePath "$Env:USERPROFILE" + + .vscode\extensions + .vscode\argv.json .example # use relative your CWD - PS> PWD - C:\Users\cppmo_000\Documents\2020\powershell - PS> ls ~\.vscode | select -First 2 | Format-RelativePath - ..\..\..\.vscode\extensions - ..\..\..\.vscode\argv.json + 🐒> ls .\My_Gist\ | To->RelativePath + + My_Gist\AngleSharp Example + My_Gist\Calling-Pwsh-Commands-With-Dynam + My_Gist\Making regular expressions reada + + .outputs + [string] + .link + https://docs.microsoft.com/en-us/dotnet/api/system.io.path.getrelativepath + .link + https://docs.microsoft.com/en-us/dotnet/api/system.io.path.getfullpath #> [Alias('ConvertTo-RelativePath')] [cmdletbinding()] param ( # Filepath - [Alias('PSPath', 'Path')] + [Alias('PSPath', 'Path', 'To->RelativePath')] [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [object[]]$InputObject, # relative path to resolve from + # future, use completions so visual and final replace are different + # it can show 'dotfiles' but really use env vars, etc. + # $items = "$Env:UserProfile", "$Env:AppData", "$Env:LocalAppData" + # | ForEach-Object tostring + # , $items [Parameter(Position = 0)] + [ArgumentCompletions( + 'C:\Users\cppmo_000\SkyDrive\Documents\2021', + 'C:\Users\cppmo_000\AppData\Roaming', + 'C:\Users\cppmo_000\AppData\Local', + 'C:\Users\cppmo_000' + )] [string]$BasePath ) begin { + $Config = @{ + AlwaysStripAnsi = $true + } # Push-Location -StackName 'temp' $BasePath if (! [string]::IsNullOrWhiteSpace( $BasePath) ) { $curDir = Get-Item $BasePath @@ -62,13 +93,24 @@ function Format-RelativePath { } process { $InputObject | ForEach-Object { - $curPath = $_ - [System.IO.Path]::GetRelativePath( $curDir, $curPath ) + $curItem = $_ + if ($curItem -is 'string') { + $curItem = $curItem | Remove-AnsiEscape + } + $curItem = Get-Item $curItem + if ($null -eq $curItem) { + Write-Error 'curItem: $null' + return + } + if ($null -eq $curDir) { + Write-Error 'curDir: $null' + return + } + + [System.IO.Path]::GetRelativePath( $curDir, $curItem ) } } - end { - - } + end { } } # write-warning 'Already wrote the code using the dotnet method, its far faster' diff --git a/public/Format-RelativePath.tests.ps1 b/public/Format-RelativePath.tests.ps1 new file mode 100644 index 0000000..65b745b --- /dev/null +++ b/public/Format-RelativePath.tests.ps1 @@ -0,0 +1,50 @@ +BeforeAll { + Import-Module Ninmonkey.Console -Force +} + +Describe 'Format-RelativePath' { + It 'from IO' -Pending { + $true | Should -Be $false + + } + It 'from fullname text' -Pending { + $true | Should -Be $false + } + + It 'from partial name text' -Pending { + + $true | Should -Be $false + } + Describe 'Text Vs Object' { + It 'With Color' { + { + newestItem🔎 -ItemType Pwsh + | First 4 + | To->RelativePath + } | Should -Not -Throw + } + It 'As Object' { + { + Get-ChildItem + | First 4 + | To->RelativePath + } | Should -Not -Throw + } + } + Describe 'Hard-coded Dotnet calls' { + BeforeAll { + $target = Get-Item $env:Nin_Dotfiles + $relativeTo = Get-Item $env:USERPROFILE + $expectedText = 'SkyDrive\Documents\2021\dotfiles_git' + } + It 'Baseline True Case' { + $result = [io.path]::GetRelativePath($relativeTo, $target) + $result | Should -Be $expectedText + } + + It 'Test True' { + $target | Format-RelativePath -BasePath $relativeTo + | Should -Be $expectedText + } + } +} From d81223f208fba1a16fc2cb2f3ff1ebaad1af6056 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Thu, 11 Nov 2021 12:58:07 -0600 Subject: [PATCH 14/49] fixed Format-RelativePath null error --- public/FindMyCommand..ps1 | 45 +++ public/Format-RelativePath.ps1 | 14 +- public/Get-ObjectType-Old.ps1 | 370 ------------------ public_autoloader/Assert-CommandType.ps1 | 75 ++++ .../Assert-CommandType.tests.ps1 | 11 + public_autoloader/Get-CommandSummary.ps1 | 4 +- public_autoloader/Get-NinVerb.ps1 | 100 +++++ 7 files changed, 245 insertions(+), 374 deletions(-) create mode 100644 public/FindMyCommand..ps1 delete mode 100644 public/Get-ObjectType-Old.ps1 create mode 100644 public_autoloader/Assert-CommandType.ps1 create mode 100644 public_autoloader/Assert-CommandType.tests.ps1 create mode 100644 public_autoloader/Get-NinVerb.ps1 diff --git a/public/FindMyCommand..ps1 b/public/FindMyCommand..ps1 new file mode 100644 index 0000000..6da1cfe --- /dev/null +++ b/public/FindMyCommand..ps1 @@ -0,0 +1,45 @@ +function Find-MyCommand { + <# + .synopsis + sketch, not ready. + #> + h1 'sketch' + $queryTerm = '*prop*', '*object*', '*hashtable*' + $query = Get-Command -m (_enumerateMyModule) $queryTerm + + + + h1 'details' + $query + | Where-Object { $_.CommandType -notin @('Alias', 'Application') } + | Sort-Object Source, Name + | Get-Random -Count 20 + | First 3 + | s -ExcludeProperty Definition, ScriptBlock + | Out-Null + + h1 'sort types' + $query | Get-Random -Count 40 + | Sort-Object Verb, Name + | Out-Null + + + & { + $randTest1 = $query | Get-Random -Count 40 + h1 'type1: verb centric' + $randTest1 | Sort-Object Verb, Name, Source + | Format-Table Name, Source -GroupBy Verb -AutoSize + + h1 'type2: Source, name' + $randTest1 + | Sort-Object Source, Name, Verb + | Format-Table Name, Verb -GroupBy Source -AutoSize + } + + '*filter->*', '*from->*', '*to->*' | ForEach-Object { + Get-Command -m (_enumerateMyModule) $_ + hr + } + + +} \ No newline at end of file diff --git a/public/Format-RelativePath.ps1 b/public/Format-RelativePath.ps1 index 428df70..9995c58 100644 --- a/public/Format-RelativePath.ps1 +++ b/public/Format-RelativePath.ps1 @@ -78,7 +78,12 @@ function Format-RelativePath { 'C:\Users\cppmo_000\AppData\Local', 'C:\Users\cppmo_000' )] - [string]$BasePath + [string]$BasePath, + + # interpret strings as literal path, verses get-item which resolves to many files + # paths with globs or 'c:\foo\*' resolve to many paths if this is off + [alias('LiteralPath')] + [switch]$AsLiteralPath ) begin { @@ -97,7 +102,9 @@ function Format-RelativePath { if ($curItem -is 'string') { $curItem = $curItem | Remove-AnsiEscape } - $curItem = Get-Item $curItem + if (! $LiteralPath) { + $curItem = Get-Item $curItem + } if ($null -eq $curItem) { Write-Error 'curItem: $null' return @@ -110,7 +117,8 @@ function Format-RelativePath { [System.IO.Path]::GetRelativePath( $curDir, $curItem ) } } - end { } + end { + } } # write-warning 'Already wrote the code using the dotnet method, its far faster' diff --git a/public/Get-ObjectType-Old.ps1 b/public/Get-ObjectType-Old.ps1 deleted file mode 100644 index 6309e46..0000000 --- a/public/Get-ObjectType-Old.ps1 +++ /dev/null @@ -1,370 +0,0 @@ -function Get-ObjectType { - [Alias('TypeOf')] - <# - .notes - parametersets 2 position-type modes - 1] object[] | TypeOf mode - 2] TypeOf object[] mode - - todo: FormatTypeName that does 'abbreviateNamespace' - - pipeline notes: - It seems like for this function I should go with - - parameter type that is not an array [obj] - - process returns array ', $array' - - then optionally enumerate on [obj] if I want to inspect child element - #> - param( - # InputObject[s] to get type[s] of - [Parameter(Mandatory, ValueFromPipeline)] - [object]$InputObject, - - # Format Mode - [Parameter(Position = 0)] - [ValidateSet('List', 'PSTypeNames', 'GetType')] - [string]$Format, - - # Returns type as Typeinfo if possible - [Parameter()][switch]$PassThru, - - # Returns a unique list of types - [Parameter()][switch]$Unique - - - ) - begin { - # if ($PassThru) { - # throw "NotImplementedError: -PassThru" - # } - $typeList = [list[object]]::new() - if ([string]::IsNullOrWhiteSpace( $Format)) { - $Format = 'GetType' - } - - } - process { - Write-Error 'rewrite from scratch' - $typeList.Add( $InputObject ) - } - end { - Write-Error 'rewrite from scratch' - # $ - - switch ($Format) { - - 'GetType' { - if ($Null -eq $curObject) { - Write-Error "`$CurObject is $null" - } - $typeInstance = $curObject.GetType() - if ($PassThru) { - $typeInstance - break - } - $typeInstance | Format-TypeName - break - } - - { 'PSTypeNames' -or 'List' } { - if ($PassThru) { - , $curObject.pstypenames - break - } - - # foreach ($Obj in $InputInputObjectect) { - $splat_JoinPSTypeName = @{ - Separator = ', ' - Property = { $_ | Format-TypeName } - } - - $curObject.pstypenames | Join-String @splat_JoinPSTypeName - break - } - - default { Throw "UnhandledCase: $Format" } - } - } -} - - -function old_Get-ObjectType { - <# - .synopsis - simplify getting type name of an object and child types - .example - PS> ls | Get-Unique -OnType | TypeOf - - Count isList Type - ----- ------ ---- - 1 False IO.DirectoryInfo - 1 False IO.FileInfo - - .example - - ls | sort -Unique { $_.GetType().FullName } | TypeOf - ls . | sort { $_.GetType().Fullname } | Get-Unique -OnType | typeof - - .notes - rename to Get-TypeName? Get-ItemTypeName? Get-TypeInfo? - - future: - - [ ] output custom object type of this commands results, because - - [ ] display output uses | Format-TypeName - - [ ] but properties are still full 'Type' instances - future: - - simplify showing - - interfaces implemented - - base/parent type - - category = class, enum, typeReflectionInfo - - future? - #> - <# - "NYI: Left off. todo: - - for objects - - [ ] obj.GetType() - - [ ] isContainer? - - [ ] @(obj)[0].GetType() - - [ ] obj.pstypenames - - [ ] @(obj)[0].pstypenames - - for [typeinfo] - - [ ] @(obj)[0].GetTypeInfo() - - [ ] obj.pstypenames ? - - [ ] @(obj)[0].pstypenames ? - " - #> - # [Alias('TypeOf')] - [cmdletbinding(PositionalBinding = $false)] - param( - # InputObject[s] to get type[s] of - [Parameter(Mandatory, ValueFromPipeline)] - [object[]]$InputObject, - - # (to refactor as a custom Format.ps1xml) include more properties - [Parameter()][switch]$Detail, - - # output format mode - [Parameter(Position = 0)] - [ValidateSet('', 'PSTypeNameList', 'Table', 'Default')] - [string]$FormatMode = 'PSTypeNameList', - - - # ignore colors using: PassThru (until refactor to move colors to format types) - # skip colors and returns an array of PSTypeNames - [Parameter()][switch]$PassThru - - # All: Test all elements similar to Select-Object -Wait - # [Parameter()][switch]$AllElements - - ) - begin { - $UseColor = ! $PassThru - $joinAsList_splat = @{ - Separator = ', ' - OutputPrefix = '{ ' - OutputSuffix = '}' - } - - $joinTypesAsList_splat = @{ - Separator = ', ' - OutputPrefix = '{ ' - OutputSuffix = '}' - Property = { $_ | Format-TypeName -WithBrackets } - } - - # vs code has issues with non-printable characters in table widths - if ((Get-TerminalName).IsVSCode) { - $UseColor = $false - } - - if ($UseColor) { - # Warning: Refactor to custom view, not raw output! - $ColorDarkGrey = 'aaaaaa' - $splatDarkGrey = @{ - ForegroundColor = $ColorDarkGrey - } - - # giant spam until refactor as formatter - $joinTypesAsList_splat.OutputPrefix = New-Text @splatDarkGrey $joinTypesAsList_splat.OutputPrefix | ForEach-Object tostring - $joinTypesAsList_splat.OutputSuffix = New-Text @splatDarkGrey $joinTypesAsList_splat.OutputSuffix | ForEach-Object tostring - $joinTypesAsList_splat.Separator = New-Text @splatDarkGrey $joinTypesAsList_splat.Separator | ForEach-Object tostring - - $joinAsList_splat.OutputPrefix = New-Text @splatDarkGrey $joinAsList_splat.OutputPrefix | ForEach-Object tostring - $joinAsList_splat.OutputSuffix = New-Text @splatDarkGrey $joinAsList_splat.OutputSuffix | ForEach-Object tostring - $joinAsList_splat.Separator = New-Text @splatDarkGrey $joinAsList_splat.Separator | ForEach-Object tostring - } - - } - - Process { - # curTypeObj = instance of Object - # curTypeInfo = [type] of Object - if ($InputObject -is 'type') { - $curTypeInfo = $InputObject - $curTypeObj = $InputObject - } - elseif ($InputObject -is [string]) { - $curTypeInfo = $InputObject -as [type] - if ($null -eq $curTypeInfo) { - throw "Failed on typeName: '$curTypeInfo'" - } - $curTypeObj = $null - } - else { - $curTypeInfo = $InputObject.GetType() - $curTypeObj = $InputObject - } - # if has children - $element1 = $InputObject | Select-Object -First 1 - - if ($FormatMode -eq 'Default') { - # if assembly is verbose, replace FullName with 'namespace', 'name' to strip assembly - #no $PassThru ? - $tinfo = $curTypeInfo.Namespace, $curTypeInfo.Name -join '.' - # $tinfo = $curTypeInfo.GetType().Namespace, $curTypeInfo.GetType().Name -join '.' - $tinfo - return - - } - if ($FormatMode -eq 'PSTypeNameList') { - if ($PassThru) { - if ($curTypeObj) { - , $curTypeObj.PSTypeNames - } - return - } - # *should* work regardless if process inputs an array or one elemenent - # foreach($item in $InputObject) {} - $splat_JoinPSTypeName = @{ - Separator = "`n- " - OutputPrefix = '- ' - Property = { $curTypeObj.PSTypeNames | Format-TypeName -WithBrackets | Join-String -sep ', ' } - } - - $InputObject | Join-String @splat_JoinPSTypeName - - # $splat_JoinPSTypeNamedsf = @{ - # OutputPrefix = { $_.PSTypeNames | Format-TypeName -WithBrackets | Join-String -sep ', ' } - # } - - # $InputObject | Join-String @splat_JoinPSTypeName - - - return - } - - - - $meta = [ordered]@{ - Count = $curTypeObj.Count - isList = $curTypeObj.Count -gt 1 - Type = $curTypeObj.GetType() | Format-TypeName - } - - $metaDetailed = [ordered]@{ - elementType = $element1.GetType() | Format-TypeName - | Format-TypeName - - # elementTypeNames = $element1.pstypenames | Join-String @joinAsList_splat # { $_ | Format-TypeName } - # elementTypeNamesAbbr = $element1.pstypenames | Join-String @joinAsList_splat -prop { $_ | Format-TypeName } - - TypeNames = $cur.pstypenames | Join-String @joinTypesAsList_splat - TypeNamesFull = $cur.pstypenames | Join-String @joinTypesAsList_splat - # TypeNames = $cur.pstypenames | Join-String @joinAsList_splat -prop { $_ | Format-TypeName } - # TypeNamesAbbr = $cur.pstypenames | Join-String @joinAsList_splat -prop { $_ | Format-TypeName } - } - - if ($Detail) { - $meta += $metaDetailed - } - - # if ($AllElements) { - # $AllTypeList = $InputObject | ForEach-Object { - # $_ | ForEach-Object GetType - # | Format-TypeName -WithBrackets - # } | Join-String @joinAsList_splat - # $meta.Add('AllTypeList', $AllTypeList ) - # } - - [pscustomobject]$meta - # $meta - } -} - - -if ($isDebugMod) { - # test cases - $items = [ordered]@{} - $items.mod = Get-Module 'Ninmonkey.Console' - $items.cmd = Get-Command 'Get-Item' - $items.nums = 2, 4, 55 - $items.hash = @{ Species = 'cat'; } - $items.object = [pscustomobject]($items['hash']) - $items.GetEnumerator() | ForEach-Object { $_.Value } | ForEach-Object gettype | ForEach-Object FullName - - H1 'try 1: As Obj Instance (required)' - $items.GetEnumerator() | ForEach-Object { $_.Value } - | ForEach-Object FullName - | TypeOf - - H1 'try 2: As Type instance (optional)' - $items.GetEnumerator() | ForEach-Object { $_.Value } - | ForEach-Object gettype | ForEach-Object FullName - | TypeOf -} - -if ($false) { - H1 'mod' - $items.mod | TypeOf - H1 'sdf' - Hr - 234, 'sdf' | TypeOf - Hr - TypeOf -InputObject 'dog' | Format-Table - Hr - TypeOf -InputObject 'dog' -Detail | Format-Table - - # # final - # hr; - # $items.mod | TypeOf - # hr; - # $items.cmd | TypeOf - # hr; - # $items.nums | TypeOf - # hr; - # $items.hash | TypeOf - # hr; - # $items.object | TypeOf - # hr -} - -if ($true -and $isDebugMod) { - H1 'enumerate all' - $results = foreach ($Key in $items.Keys) { - [pscustomobject]@{ - Label = $Key - Contents = $items[$Key] - Type = $items[$Key] | ForEach-Object gettype #| Format-TypeName -Brackets - } - } - $results - - H1 'inner results' - foreach ($Item in $Results) { - $H2splat = @{ - ForegroundColor = 'magenta' - Depth = 2 - } - - H1 $Item.Label @H2splat - $Item.Contents - - } - # foreach ($Key in $results.GetEnumerator()) { - # $Key = $_.Key - # $Value = $_.Value - - # H1 $Key - # $Value - # } -} diff --git a/public_autoloader/Assert-CommandType.ps1 b/public_autoloader/Assert-CommandType.ps1 new file mode 100644 index 0000000..1413366 --- /dev/null +++ b/public_autoloader/Assert-CommandType.ps1 @@ -0,0 +1,75 @@ +$script:publicToExport.function += @( + 'Assert-CommandType' +) +$script:publicToExport.alias += @( + # 'Where-CommandType' + '?CommandType' + 'Filter->CommandType' +) +function Assert-CommandType { + <# + .synopsis + Stuff + .description + . + .example + . + .link + System.Management.Automation.CommandTypes + .outputs + [bool] + + #> + [Alias('Where-CommandType', '?CommandType', 'Filter->CommandType')] + [CmdletBinding(PositionalBinding = $false)] + param( + # object + [Parameter(Mandatory, Position = 0)] + [object]$InputObject, + + # must be one of these types + [Alias('Is')] + [Parameter()] + [Management.Automation.CommandTypes[]]$IsOfType, + + # must not be be of these types + [Alias('IsNot')] + [Parameter()] + [Management.Automation.CommandTypes[]]$IsNotOfType + ) + + begin {} + process { + $InputObject.CommandType | str Prefix 'CommandType: ' | Write-Debug + $IsOfType | ForEach-Object { + + + $curType = $_ + $curType | str prefix 'compare: Is' | Write-Color 'green' | Write-Debug + if ($InputObject.CommandType -eq $curType) { + + '{0} : {1}' -f @( + $InputObject.CommandType + $curType + ) + | str prefix 'compare: $true' | Write-Color 'orange' | Write-Debug + $true; return + } + 'compare: $true' | Write-Color 'green' | Write-Debug + } + $IsNotOfType | ForEach-Object { + $curType = $_ + $curType | str prefix 'compare: IsNot' | Write-Color red | Write-Debug + if ($InputObject.CommandType -eq $curType) { + 'compare: $false' | Write-Color 'red' | Write-Debug + $false; return + } + } + $true # + } + end {} +} + +# $IsType +# | Get-EnumInfo +# $InputObject -notin @('Alias', 'Application') \ No newline at end of file diff --git a/public_autoloader/Assert-CommandType.tests.ps1 b/public_autoloader/Assert-CommandType.tests.ps1 new file mode 100644 index 0000000..23f284a --- /dev/null +++ b/public_autoloader/Assert-CommandType.tests.ps1 @@ -0,0 +1,11 @@ +BeforeAll { + Import-Module Ninmonkey.Profile -Force +} + +Describe 'Assert-CommandType' { + It 'hardcoded' { + Get-Command Microsoft.PowerShell.Core\Get-Command + $false | Should -Be $True + } + +} \ No newline at end of file diff --git a/public_autoloader/Get-CommandSummary.ps1 b/public_autoloader/Get-CommandSummary.ps1 index 9a51c1e..839843a 100644 --- a/public_autoloader/Get-CommandSummary.ps1 +++ b/public_autoloader/Get-CommandSummary.ps1 @@ -1,7 +1,9 @@ $script:publicToExport.function += @( 'Get-CommandSummary' ) -$script:publicToExport.alias += @('HelpCommmand') +$script:publicToExport.alias += @( + 'HelpCommmand' +) function Get-CommandSummary { <# diff --git a/public_autoloader/Get-NinVerb.ps1 b/public_autoloader/Get-NinVerb.ps1 new file mode 100644 index 0000000..3206670 --- /dev/null +++ b/public_autoloader/Get-NinVerb.ps1 @@ -0,0 +1,100 @@ + +if ( $script:publicToExport) { + +} +$script:publicToExport.function += @( + 'Get-NinVerb' +) +$script:publicToExport.alias += @( + '_enumerateNinVerb' +) + +function Get-NinVerb { + <# + .synopsis + Enumerate non-standard verbs (or aliases) + .description + Don't judge me. It's for my profile. + .notes + some of this is overlapping get commands + .example + PS> Get-NinVerb + #> + [Alias('_enumerateNinVerb')] + [cmdletbinding()] + param( + # include global/regulars? + [Parameter()] + [switch]$All + ) + + end { + $gcm_enumMine = Get-Command -m (_enumerateMyModule) * + | Where-Object CommandType -NE 'application' + + $meta = [ordered]@{ + + + + # My Module Noun, Pwsh's def of noun + BasicNouns = $gcm_enumMine + | ForEach-Object noun + | Sort-Object -Unique + + # My Module Verb, Pwsh's def of verb + BasicVerbs = $gcm_enumMine + | ForEach-Object Verb + | Sort-Object -Unique + + # My module's "->" commands + NinVerbCommands = $gcm_enumMine + | Where-Object name -Match (ReLit '->') + + # mine where no '-' anywhere + 'NinWithout-' = $gcm_enumMine + | Where-Object name -NotMatch '-' + + # under/dunder score on name + NinUnders = $gcm_enumMine + | ?Str -Begins '_' Name + + LegalVerbs = Get-Verb + | ForEach-Object Verb | Sort-Object -Unique + } + + #$verbsLegal = Get-Verb | % Verb | sort -Unique + $BasicVerbs = $gcm_enumMine + | ForEach-Object Verb + | Sort-Object -Unique + $hlegal = [HashSet[string]]::new( [string[]]$meta.LegalVerbs ) + $hmine = [HashSet[string]]::new( [string[]]$meta.BasicVerbs ) + + + # $meta['BasicVerbs'] | str csv -Sort + # | str prefix 'basicVerbs: ' | wi + + # $meta['NinVerbs'] | str csv -Sort + # | str prefix 'basicNinVerbs: ' | wi + + # $meta['NinVerbs'] | str csv -Sort + # | str prefix 'basicNinVerbs: ' | wi + + + if ($true -or $All) { + $meta += @{ + AllBasicNouns = Get-Command * + | ForEach-Object noun + | Sort-Object -Unique + + AllBasicVerbs = Get-Command * + | ForEach-Object Verb + | Sort-Object -Unique + } + } + # different results depending on queries + # Get-Command '*->*' | ? CommandType -NotIn @('Application') + [pscustomobject]$meta + + } +} + From b87c57613b00f4af5b198b207cf61b4d4c165681 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Sat, 13 Nov 2021 19:29:41 -0600 Subject: [PATCH 15/49] cleaned up a few notes --- public/ConvertTo-Timespan.ps1 | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/public/ConvertTo-Timespan.ps1 b/public/ConvertTo-Timespan.ps1 index 8f71df2..c17e686 100644 --- a/public/ConvertTo-Timespan.ps1 +++ b/public/ConvertTo-Timespan.ps1 @@ -4,33 +4,30 @@ function ConvertTo-Timespan { .synopsis converts strings to a [timespan] .description - minimal error detection, or some defaults apply less impact + by default the value 0 is an error, or when the regex does not match + throw errors when no value is created, user may ignore it. - ex: Without strict mode, if $RelativeText has extra data - after splitting, then there's an error. - new: - - throw errors when no value is created, user may ignore it. - future: - decent deterministic error dectection is + next: force a full regex match, $RelativeText has any non-matched text, + after splitting, then there's an error. + next: decent deterministic parse decetection is 1] attempt to grab matches in the orignal string: "[day]? [hour]? [minute]? [second]?" 2] strip those matches from the original string - 3] if orignal string.length > 0, + 3] if non-matching string.length > 0, throw error - that covers the majority of error cases, - without complex logic or edge cases + that covers the majority of error cases, without complex logic or edge cases .example 1d3h4s -> #duration(1, 3, 4)' .example - $tslist = @( + PS> $tslist = @( 2 | days 3 | hours ) $ts_sum = $tslist | Measure-Object TotalMilliSeconds -Sum | % Sum | %{ - [timespan]::new(0,0,0,0,$_) + [timespan]::new(0,0,0,0,$_) } $ts_sum | Should -be (RelativeTs 2d3h -debug) @@ -50,7 +47,6 @@ function ConvertTo-Timespan { .outputs [timespan] or null .notes - futrue: - [ ] better verb? better name, timespan? ConvertTo ? 'New-RelativeTimespan' or 'ConvertTo-Timespan' ? From 379f5f4d372f928e065d7dd116b82767ad95db05 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Sat, 13 Nov 2021 20:53:43 -0600 Subject: [PATCH 16/49] Updating tests, and aliases, minor 'Label' fix - New Aliases: Inspect->Property - Prevent 'Label' error when input1 is null --- Ninmonkey.Console.psd1 | 8 +++++--- README.md | 10 ++++++++++ public/ConvertTo-Timespan.tests.ps1 | 15 ++++++++------- public/Get-ObjectProperty.ps1 | 16 ++++++++++------ public/Resolve-CommandName.ps1 | 4 ++-- public/Set-NinLocation.ps1 | 5 ++--- public/Set-NinLocation.tests.ps1 | 26 ++++++++++++++++++++++++++ public/Write-ConsoleLabel.ps1 | 6 ++++-- 8 files changed, 67 insertions(+), 23 deletions(-) create mode 100644 public/Set-NinLocation.tests.ps1 diff --git a/Ninmonkey.Console.psd1 b/Ninmonkey.Console.psd1 index 338eba6..0071766 100644 --- a/Ninmonkey.Console.psd1 +++ b/Ninmonkey.Console.psd1 @@ -11,7 +11,7 @@ RootModule = 'Ninmonkey.Console.psm1' # Version number of this module. - ModuleVersion = '0.1.1' + ModuleVersion = '0.1.2' # Supported PSEditions # CompatiblePSEditions = @() @@ -26,7 +26,7 @@ CompanyName = 'Jake Bolton' # Copyright statement for this module - Copyright = '(c) Jake Bolton 2021' + Copyright = '(c) Jake Bolton 2021-2022' # Description of the functionality provided by this module Description = 'Utilities to improve the quality of interactive use, the Command Line' @@ -51,7 +51,9 @@ # Modules that must be imported into the global environment prior to importing this module RequiredModules = @( - 'Pansies', 'ClassExplorer' + 'Pansies' + 'ClassExplorer' + 'Utility' # hard dependency for now ) # Assemblies that must be loaded prior to importing this module diff --git a/README.md b/README.md index 7fa104b..eab6d06 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,16 @@ $PSDefaultParameterValues['Out-Fzf:OutVariable'] = 'Fzf' 🐒> $bytes | Base64 ``` +# Frequently used + +```ps1 +# Jump to modules +🐒> Get-Module PSKoans | Goto + pwd + +C:\Users\monkey\Documents\PowerShell\Modules\PSKoans\0.67.1 +``` + # Console Encoding ```powershell diff --git a/public/ConvertTo-Timespan.tests.ps1 b/public/ConvertTo-Timespan.tests.ps1 index d1f2e2b..9c1d13d 100644 --- a/public/ConvertTo-Timespan.tests.ps1 +++ b/public/ConvertTo-Timespan.tests.ps1 @@ -6,28 +6,29 @@ BeforeAll { } Describe 'ConvertTo-Timespan' { - it 'first' { + It 'first' { $tslist = @( 2 | days 3 | hours ) - $ts_sum = $tslist | Measure-Object TotalMilliSeconds -Sum | % Sum | %{ - [timespan]::new(0,0,0,0,$_) + $ts_sum = $tslist | Measure-Object TotalMilliSeconds -Sum | ForEach-Object Sum | ForEach-Object { + [timespan]::new(0, 0, 0, 0, $_) } - $ts_sum | Should -be (RelativeTs 2d3h -debug) + $ts_sum | Should -Be (RelativeTs 2d3h -Debug) $tslist = @( 2 | days 3 | hours ) - $total_ms = $tslist | Measure-Object TotalMilliSeconds -Sum | % Sum + $total_ms = $tslist | Measure-Object TotalMilliSeconds -Sum | ForEach-Object Sum - $ts_sum = $total_ms | %{ - [timespan]::new(0,0,0,0,$_) + $ts_sum = $total_ms | ForEach-Object { + [timespan]::new(0, 0, 0, 0, $_) } + } } \ No newline at end of file diff --git a/public/Get-ObjectProperty.ps1 b/public/Get-ObjectProperty.ps1 index c4888bb..9f1888c 100644 --- a/public/Get-ObjectProperty.ps1 +++ b/public/Get-ObjectProperty.ps1 @@ -99,12 +99,18 @@ function Get-ObjectProperty { Dev.Nin\_enumerateProperty .link Dev.Nin\iProp + .link + Ninmonkey.Console\Get-ObjectProperty .example ,(1..4) | prop -IncludeTypeTitle 1..4 | prop -IncludeTypeTitle #> [cmdletbinding(PositionalBinding = $false)] - [Alias('Prop')] + [Alias( + 'Prop', + 'Inspect->Property' + # 'Inspect-Object' + )] param( # any object with properties to inspect [Parameter(Mandatory, Position = 0, ValueFromPipeline)] @@ -180,7 +186,7 @@ function Get-ObjectProperty { $curObject = $_ if ($IncludeTypeTitle) { - $curObject.GetType() | Format-TypeName -Brackets | Join-String -op "`nTypeName: " + $curObject.GetType() | Format-TypeName -Brackets | Join-String -op "`nTypeName: " # | Label 'TypeName' # todo: once label is fixed } Write-Debug "Object: $($_.GetType().FullName)" @@ -193,8 +199,7 @@ function Get-ObjectProperty { $ValueIsNull = $null -eq $curProp.Value if ($ValueIsNull) { $DisplayedValueType = $Config.SymbolNull - } - else { + } else { $DisplayedValueType = $curProp.Value.GetType() | Format-TypeName @splat_FormatType } @@ -205,8 +210,7 @@ function Get-ObjectProperty { $curTypeInstance = $DisplayedValueType if ($curType -eq $curTypeInstance) { $typeAbbrString = $curType - } - else { + } else { $typeAbbrString = '{0} ⇾ {1}' -f @( $curType $curTypeInstance diff --git a/public/Resolve-CommandName.ps1 b/public/Resolve-CommandName.ps1 index 8a35e27..029ad15 100644 --- a/public/Resolve-CommandName.ps1 +++ b/public/Resolve-CommandName.ps1 @@ -34,7 +34,7 @@ function Resolve-CommandName { [Parameter()][switch]$QualifiedName, # preserves alias's original names in the output - [Parameter()][switch]$IncludeAlias, + [Parameter()][switch]$PreserveAlias, @@ -62,7 +62,7 @@ function Resolve-CommandName { $commands = Get-Command @getCommandSplat | ForEach-Object { # Get-Command -Name $_.ResolvedCommand - if ($_.CommandType -eq 'Alias' -and (! $IncludeAlias)) { + if ($_.CommandType -eq 'Alias' -and (! $PreserveAlias)) { $_.ResolvedCommand } else { $_ diff --git a/public/Set-NinLocation.ps1 b/public/Set-NinLocation.ps1 index d609695..e8049b7 100644 --- a/public/Set-NinLocation.ps1 +++ b/public/Set-NinLocation.ps1 @@ -52,8 +52,7 @@ function Set-NinLocation { if ($Back) { try { Pop-Location -StackName 'NinLocation' -ea Stop - } - catch { + } catch { Write-Debug 'stack was empty' } return @@ -71,7 +70,7 @@ function Set-NinLocation { ) return # todo: future: pass command to Push-Location for providers like registry - } + } if (! (Test-Path -Path $Path)) { 'Invalid path: {0}' -f $Path | Write-Error -Category 'InvalidArgument' diff --git a/public/Set-NinLocation.tests.ps1 b/public/Set-NinLocation.tests.ps1 new file mode 100644 index 0000000..eb60f4c --- /dev/null +++ b/public/Set-NinLocation.tests.ps1 @@ -0,0 +1,26 @@ +BeforeAll { + Import-Module Ninmonkey.Console -Force +} + +Describe 'Set-NinLocation' { + It 'From $Profile' { + Push-Location -StackName 'pest.nin' + $Expected = (Get-Item $PROFILE).Directory.FullName + $profile | Goto + Get-Item . | ForEach-Object FullName | Should -Be $Expected + Pop-Location -StackName 'pest.nin' + } + It 'From [IO.FileSystemInfo]' { + Push-Location -StackName 'pest.nin' + $Somefile = Get-Item .. -file | Select-Object -First 1 + + $somefile | Goto + + Get-Location | ForEach-Object tostring + | Should -Be $Somefile.Directory + + Pop-Location -StackName 'pest.nin' + } + # ($PROFILE | Split-Path -Parent) | Should -be (gi . | % fullname) + +} \ No newline at end of file diff --git a/public/Write-ConsoleLabel.ps1 b/public/Write-ConsoleLabel.ps1 index 28aaa71..8a200ff 100644 --- a/public/Write-ConsoleLabel.ps1 +++ b/public/Write-ConsoleLabel.ps1 @@ -194,10 +194,12 @@ function Write-ConsoleLabel { Write-Error "Property '$PropertyName' is invalid or = $null" $newTextSplat_Text['Object'] = $strConst.Null } - } - else { + } else { $newTextSplat_Text['Object'] = $InputObject } + if ($null -eq $newTextSplat_Text['Object'] ) { + $newTextSplat_Text['Object'] = '[␀]' + } $strText = New-Text @newTextSplat_Text $FullString = $StrLabel, $Separator, $StrText | Join-String -Sep '' From acc96304433f189d4927d6f9bb1083759d03630c Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Mon, 15 Nov 2021 14:32:16 -0600 Subject: [PATCH 17/49] renamed for clarity --- public/Format-RelativePath.ps1 | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/public/Format-RelativePath.ps1 b/public/Format-RelativePath.ps1 index 9995c58..d5d4da1 100644 --- a/public/Format-RelativePath.ps1 +++ b/public/Format-RelativePath.ps1 @@ -98,12 +98,14 @@ function Format-RelativePath { } process { $InputObject | ForEach-Object { - $curItem = $_ - if ($curItem -is 'string') { - $curItem = $curItem | Remove-AnsiEscape + $rawItem = $_ + if ($rawItem -is 'string') { + $parsedItem = $rawItem + | Remove-AnsiEscape } + if (! $LiteralPath) { - $curItem = Get-Item $curItem + $curItem = Get-Item $parsedItem } if ($null -eq $curItem) { Write-Error 'curItem: $null' @@ -114,7 +116,7 @@ function Format-RelativePath { return } - [System.IO.Path]::GetRelativePath( $curDir, $curItem ) + [System.IO.Path]::GetRelativePath( $curDir, $parsedItem ) } } end { From 36836cee8e5be48ea3a225a3456fa9aad716a8bc Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Mon, 15 Nov 2021 18:42:29 -0600 Subject: [PATCH 18/49] iter on format path --- public/Format-RelativePath.ps1 | 30 ++++---- public/Write-ConsoleLabel.ps1 | 10 +-- public_autoloader/Get-CommandSummary.ps1 | 97 +++++++++++++++++------- public_autoloader/Get-NinCommand.ps1 | 49 +++++++----- public_autoloader/Get-ObjectTypeHelp.ps1 | 37 ++++++++- 5 files changed, 155 insertions(+), 68 deletions(-) diff --git a/public/Format-RelativePath.ps1 b/public/Format-RelativePath.ps1 index d5d4da1..df45fb8 100644 --- a/public/Format-RelativePath.ps1 +++ b/public/Format-RelativePath.ps1 @@ -97,6 +97,9 @@ function Format-RelativePath { $curDir ??= Get-Location } process { + <# + ripgrep and/or grep have file line numbers at the start, or end, depending on mode + #> $InputObject | ForEach-Object { $rawItem = $_ if ($rawItem -is 'string') { @@ -122,23 +125,22 @@ function Format-RelativePath { end { } } -# write-warning 'Already wrote the code using the dotnet method, its far faster' -if ($false -and $DebugTestMode) { - # refactor to use Pester temp drives - Push-Location -StackName 'debugStack' 'C:\Users\cppmo_000\Documents\2020\powershell\MyModules_Github\Ninmonkey.Console\public' +# if ($false -and $DebugTestMode) { +# # refactor to use Pester temp drives +# Push-Location -StackName 'debugStack' 'C:\Users\cppmo_000\Documents\2020\powershell\MyModules_Github\Ninmonkey.Console\public' - $d = Get-Item . - Format-RelativePath $d -Debug +# $d = Get-Item . +# Format-RelativePath $d -Debug - $f1 = Get-Item "$PSScriptRoot\data\unicode_web_query.ps1" - $strList = @( - '.\native_wrapper\Invoke-IPython.ps1' - '.\native_wrapper\' - ) +# $f1 = Get-Item "$PSScriptRoot\data\unicode_web_query.ps1" +# $strList = @( +# '.\native_wrapper\Invoke-IPython.ps1' +# '.\native_wrapper\' +# ) - $strList | Format-RelativePath +# $strList | Format-RelativePath - Pop-Location -StackName 'debugStack' -} +# Pop-Location -StackName 'debugStack' +# } diff --git a/public/Write-ConsoleLabel.ps1 b/public/Write-ConsoleLabel.ps1 index 8a200ff..bee1367 100644 --- a/public/Write-ConsoleLabel.ps1 +++ b/public/Write-ConsoleLabel.ps1 @@ -52,11 +52,6 @@ function Write-ConsoleLabel { [AllowEmptyString()] # simplifies users errors? [string]$Label, - # Text / content - [Alias('Text')] - [Parameter( - ParameterSetName = 'TextFromPipe', - Mandatory = $false, ValueFromPipeline)] @@ -68,6 +63,11 @@ function Write-ConsoleLabel { #> # Text is not required. defaults to no color. + # Text / content + [Alias('Text')] + [Parameter( + ParameterSetName = 'TextFromPipe', + Mandatory = $false, ValueFromPipeline)] [AllowNull()] [AllowEmptyCollection()] [AllowEmptyString()] diff --git a/public_autoloader/Get-CommandSummary.ps1 b/public_autoloader/Get-CommandSummary.ps1 index 839843a..e6d18a4 100644 --- a/public_autoloader/Get-CommandSummary.ps1 +++ b/public_autoloader/Get-CommandSummary.ps1 @@ -1,10 +1,11 @@ -$script:publicToExport.function += @( - 'Get-CommandSummary' -) -$script:publicToExport.alias += @( - 'HelpCommmand' -) - +if ($script:publicToExport) { + $script:publicToExport.function += @( + 'Get-CommandSummary' + ) + $script:publicToExport.alias += @( + 'HelpCommmand' + ) +} function Get-CommandSummary { <# .synopsis @@ -63,13 +64,32 @@ function Get-CommandSummary { PSTypeName = 'Nin.CommandSummary' ResolvedCommand = $ResolvedCommand Name = $ResolvedCommand.Name + Description = $ResolvedCommand.description + Source = $ResolvedCommand.Source + HelpUri = $ResolvedCommand.HelpUri + CommandType = $ResolvedCommand.CommandType } - - [pscustomobject]$cmdSummary - return - + $AnyMatch = $false + foreach ($regex in $ModuleName) { + if ($ResolvedCommand.Source -match $regex) { + $AnyMatch = $true; + break; + } + } + if (! $ModuleName) { + $AnyMatch = $true + } + if (! $AnyMatch) { + return + } + if ($false) { + [pscustomobject]$cmdSummary + return + } + + if ($true) { $DescString = @( $helpObj.Synopsis "`n" @@ -84,11 +104,15 @@ function Get-CommandSummary { ) -join '' # ) | Join-String -sep ' ⸺ ⟶⟹ ' + $cmdSummary.DescriptionColor = $DescriptionColor + $cmdSummary.DescStr = $DescString[0..300] -join '' # $cmd | Add-Member -NotePropertyName 'Description' -NotePropertyValue ($DescString[0..300] -join '') -PassThru -ea ignore # $cmd = $cmd | Add-Member -Force -NotePropertyName 'Description' -NotePropertyValue $DescString -PassThru -ea ignore # $cmd = $cmd | Add-Member -Force -NotePropertyName 'DescriptionColor' -NotePropertyValue $DescStringColor -PassThru -ea ignore - $cmd + # $cmd } + [pscustomobject]$cmdSummary; + return } # $helpObj | Join-String -Separator "`n" -Property { $_.description } @@ -98,25 +122,40 @@ function Get-CommandSummary { } + end { + Write-Warning 'Found this old script, still super rough. will dump most of it.' + } } -if ($false -and $EnableDebugInline) { - Get-CommandSummary dev-Printtabletemplate -ea Continue -Verbose -Debug -infa Continue - # | ForEach-Object { - - Get-CommandSummary dev-Printtabletemplate -ea Continue -Verbose -Debug -infa Continue - Get-CommandSummary dev-Printtabletemplate -ea Continue -Verbose -Debug -infa Continue - - # Get-Command *console* -Module Ninmonkey.Console | ForEach-Object name | Sort-Object | +if ($false -and $script:publicToExport) { + # working example + + $f = Get-Module dev.nin | ForEach-Object ExportedCommands | ForEach-Object Keys | Select-Object -First 20 + | Get-CommandSummary -ea ignore -ModuleName dev.nin + + $f | ForEach-Object DescStr + + return + + if ($false -and $EnableDebugInline) { + Get-CommandSummary dev-Printtabletemplate -ea Continue -Verbose -Debug -infa Continue + # | ForEach-Object { + + Get-CommandSummary dev-Printtabletemplate -ea Continue -Verbose -Debug -infa Continue + Get-CommandSummary dev-Printtabletemplate -ea Continue -Verbose -Debug -infa Continue + + # Get-Command *console* -Module Ninmonkey.Console | ForEach-Object name | Sort-Object | + + # Get-Alias -Definition 'write-consoleheader' | ForEach-Object name + $sample = Get-Command 'ls', 'Get-ConsoleEncoding', 'ls.exe' + + $getCommandSummarySplat = @{ + InformationAction = 'Continue' + CommandName = 'ls', 'Get-ConsoleEncoding', 'ls.exe', 'write-consolecolor', 'Write-ConsoleHeader' + } - # Get-Alias -Definition 'write-consoleheader' | ForEach-Object name - $sample = Get-Command 'ls', 'Get-ConsoleEncoding', 'ls.exe' + $test1 = Get-CommandSummary @getCommandSummarySplat + $test1 - $getCommandSummarySplat = @{ - InformationAction = 'Continue' - CommandName = 'ls', 'Get-ConsoleEncoding', 'ls.exe', 'write-consolecolor', 'Write-ConsoleHeader' } - $test1 = Get-CommandSummary @getCommandSummarySplat - $test1 - -} +} \ No newline at end of file diff --git a/public_autoloader/Get-NinCommand.ps1 b/public_autoloader/Get-NinCommand.ps1 index 30eeeaa..ab67e83 100644 --- a/public_autoloader/Get-NinCommand.ps1 +++ b/public_autoloader/Get-NinCommand.ps1 @@ -90,23 +90,37 @@ function Get-NinCommand { [Parameter()][switch]$ListKeys ) begin { + Write-Warning 'is there a recursive loop or something hang?' + @( + @( + 'make commands from VALIDATESET' + 'commands with string "NYI"' + 'commands with string "todo"' + 'commands with "exception NYI"' + 'commands with "throw"' + ) | str ul + ) | str prefix 'Stuff todo:' + | Write-Warning + + ## now real code + if ($ListKeys) { $CategoriesMapping - hr - @( - # 'DevTool💻', 'Conversion📏', 'Style🎨', 'Format🎨', 'ArgCompleter🧙‍♂️', 'NativeApp💻', 'ExamplesRef📚', 'TextProcessing📚', 'Regex🔍', 'Prompt💻', 'Cli_Interactive🖐', 'Experimental🧪', 'UnderPublic🕵️‍♀️', 'My🐒', 'Validation🕵' - # 'Todo🚧', 'NYI🚧', - 'DevTool💻', 'Conversion📏', 'Style🎨', 'Format🎨', - 'ArgCompleter🧙‍♂️', 'NativeApp💻', 'ExamplesRef📚', 'TextProcessing📚', - 'Regex🔍', 'Prompt💻', 'Cli_Interactive🖐', 'Experimental🧪', - 'UnderPublic🕵️‍♀️', 'My🐒', 'Validation🕵', - 'Todo🚧', 'NYI🚧' - ) - | sort -unique - | Join-String -sep ', ' -SingleQuote + # hr + # @( + # # 'DevTool💻', 'Conversion📏', 'Style🎨', 'Format🎨', 'ArgCompleter🧙‍♂️', 'NativeApp💻', 'ExamplesRef📚', 'TextProcessing📚', 'Regex🔍', 'Prompt💻', 'Cli_Interactive🖐', 'Experimental🧪', 'UnderPublic🕵️‍♀️', 'My🐒', 'Validation🕵' + # # 'Todo🚧', 'NYI🚧', + # 'DevTool💻', 'Conversion📏', 'Style🎨', 'Format🎨', + # 'ArgCompleter🧙‍♂️', 'NativeApp💻', 'ExamplesRef📚', 'TextProcessing📚', + # 'Regex🔍', 'Prompt💻', 'Cli_Interactive🖐', 'Experimental🧪', + # 'UnderPublic🕵️‍♀️', 'My🐒', 'Validation🕵', + # 'Todo🚧', 'NYI🚧' + # ) + # | Sort-Object -Unique + # | Join-String -sep ', ' -SingleQuote return } - + $cached_MyModules = _enumerateMyModule # future: todo: only caches current run @@ -157,10 +171,10 @@ function Get-NinCommand { 'TextProcessing📚' = @() 'Experimental🧪' = $AllCmds | Where-Object { $_.Module -in @('dev.nin') } 'Regex🔍' = $AllCmds | ?str 'Regex' Name - 'Todo🚧' = $todoCommands - 'NYI🚧' = $NYICommands + 'Todo🚧' = $todoCommands + 'NYI🚧' = $NYICommands 'Prompt💻' = $AllCmds | ?str 'Prompt' Name - 'UnderPublic🕵️‍♀️' = $AllCmds | ?str -Starts '_' 'Name' + 'UnderPublic🕵️‍♀️' = $AllCmds | ?str -Starts '_' 'Name' 'My🐒' = $AllCmds | ?str '🐒' # 'Cli_Interactive🖐' = @() } @@ -212,7 +226,8 @@ function Get-NinCommand { # $CategoriesMapping.Values # } } - end {} + end { + } } diff --git a/public_autoloader/Get-ObjectTypeHelp.ps1 b/public_autoloader/Get-ObjectTypeHelp.ps1 index a74996a..794fcc6 100644 --- a/public_autoloader/Get-ObjectTypeHelp.ps1 +++ b/public_autoloader/Get-ObjectTypeHelp.ps1 @@ -36,7 +36,8 @@ function Get-ObjectTypeHelp { ) begin { - # list of full type nam;es + # list of full type nam;es1 + $x $NameList = [list[string]]::new() $TemplateUrl = 'https://docs.microsoft.com/en-us/dotnet/api/{0}' } @@ -45,10 +46,39 @@ function Get-ObjectTypeHelp { return } # if generics cause problems, try another method + if ($InputObject -is 'PSMethod') { + $funcName = $InputObject.Name + <# + example state from: [math]::round | HelpFromType + > $InputObject.TypeNameOfValue + + System.Management.Automation.PSMethod + + > $InputObject.GeTType() | %{ $_.Namespace, $_.Name -join '.'} + + System.Management.Automation.PSMethod`1 + + > $InputObject.Name + + Round + + #> + $maybeFullNameForUrl = $InputObject.GetType().Namespace, $InputObject.Name -join '.' + # maybe full url: + @( + $maybeFullNameForUrl | str prefix 'maybe url' | Write-Color yellow + $funcName | Write-Color yellow + $InputObject.TypeNameOfValue | Write-Color orange + $InputObject.GeTType() | ForEach-Object { $_.Namespace, $_.Name -join '.' } | Write-Color blue + ) | wi + $NameList.add($maybeFullNameForUrl) + return + + } if ($InputObject -is 'type') { $NameList.Add( $InputObject.FullName ) $NameList.Add( @( - $InputObject | Select-Object Namespace, Name | Join-String -sep '.' + $InputObject.Namespace, $InputObject.Name -join '.' ) ) return } @@ -83,5 +113,6 @@ function Get-ObjectTypeHelp { if (! $publicToExport) { - + # [math] | HelpFromType -PassThru + [math]::Round | HelpFromType -PassThru -infa Continue } From 18f3ea9afe37cbf89da4086877caeb605fd0833f Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Tue, 16 Nov 2021 10:38:40 -0600 Subject: [PATCH 19/49] New: Out-NinGridView --- public_autoloader/Out-NinGridView.ps1 | 56 +++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 public_autoloader/Out-NinGridView.ps1 diff --git a/public_autoloader/Out-NinGridView.ps1 b/public_autoloader/Out-NinGridView.ps1 new file mode 100644 index 0000000..d6f16a8 --- /dev/null +++ b/public_autoloader/Out-NinGridView.ps1 @@ -0,0 +1,56 @@ +#Requires -Version 7 +$publicToExport.function += @( + 'Out-NinGridView' +) +$publicToExport.alias += @( + 'Out-Grid' +) +function Out-NinGridView { + <# + .synopsis + Regular Out-GridView, except that it shows on top of windows + .description + next: test if -passthru blocks the window restore or not + .notes + . + .example + PS> Get-Processs | Out-NinGridView + #> + [Alias('Out-Grid')] + [cmdletbinding()] + param( + [Parameter(Mandatory, v)] + [object]$InputObject + ) + + begin { + $objList = [list[object]]::new() + } + process { + $InputObject | ForEach-Object { + $objList.Add( $_ ) + } + } + end { + # Label 'status' '=> piping...' + $objList + | Out-GridView #-PassThru + + # Label 'status' '=> restore' + if (Get-Command -ea ignore 'Window->Get') { + + $w = Window->Get '*Out-GridView*' + $w | Minimize-Window + # Start-Sleep 0.1 + $w | Restore-Window + } + # Label 'status' '=> Done' + } +} + +# works +if ($false) { + Get-ChildItem . | Out-NinGridView + Start-Sleep 0.3 + Get-ChildItem . | Select-Object * | Out-NinGridView +} From 16a8fcb6855608b1e36582a0bd3be669ffded679 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Tue, 16 Nov 2021 19:30:49 -0600 Subject: [PATCH 20/49] Cleaning up aliases --- Ninmonkey.Console.psd1 | 2 +- Ninmonkey.Console.psm1 | 12 +++++------ public/ConvertTo-PropertyList.ps1 | 11 +++++++--- public/Format-RelativePath.ps1 | 34 +++++++++++++++++++------------ public/Resolve-CommandName.ps1 | 1 + public/Select-NinProperty.ps1 | 6 +++++- 6 files changed, 42 insertions(+), 24 deletions(-) diff --git a/Ninmonkey.Console.psd1 b/Ninmonkey.Console.psd1 index 0071766..7b42829 100644 --- a/Ninmonkey.Console.psd1 +++ b/Ninmonkey.Console.psd1 @@ -11,7 +11,7 @@ RootModule = 'Ninmonkey.Console.psm1' # Version number of this module. - ModuleVersion = '0.1.2' + ModuleVersion = '0.1.3' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/Ninmonkey.Console.psm1 b/Ninmonkey.Console.psm1 index 683a9d5..a54b382 100644 --- a/Ninmonkey.Console.psm1 +++ b/Ninmonkey.Console.psm1 @@ -379,8 +379,12 @@ if ($true) { New-Alias -ea 'Ignore' 'Docs' -Value 'Get-Docs' -Description 'Jump to docs by language' New-Alias -ea 'Ignore' 'IPython' -Value 'Invoke-IPython' -Description 'ipython.exe defaults using my profile' - # now set as an alias: New-Alias -ea 'Ignore' 'Goto' -Value Set-NinLocation -Description 'a more flexible version of Set-Location / cd' + # this wasn't loading below, maybe because old system + New-Alias 'Select->Property' -Value Select-NinProperty + + + # now set as an alias: New-Alias -ea 'Ignore' 'Goto' -Value Set-NinLocation -Description 'a more flexible version of Set-Location / cd' New-Alias -ea 'Ignore' 'Here' -Value Invoke-Explorer -Description 'Open paths in explorer' # Set-Alias 'Cd' -Value 'Set-NinLocation' -ea Continue #todo: make this opt in @@ -402,11 +406,7 @@ if ($true) { 'IPython' - # smart alias - ## Select-NinProperty - 'SelectProp' # Select-NinProperty: - 'Select-Property' # Select-NinProperty: - 'ListProp' # Select-NinProperty: smart alias + 'Select->Property' # Select-NinProperty 'HelpHistory' # Find-HelpFromHistory diff --git a/public/ConvertTo-PropertyList.ps1 b/public/ConvertTo-PropertyList.ps1 index e0956b8..dc596f2 100644 --- a/public/ConvertTo-PropertyList.ps1 +++ b/public/ConvertTo-PropertyList.ps1 @@ -13,7 +13,7 @@ function ConvertTo-PropertyList { Select-Object or *-Csv or *-Json commands see also: - PS> gcm EZOut\ConvertTo-PropertySet + PS> gcm ConvertTo-HashtableFromObject .notes often you can instead use: Select-Object or *-Csv or *-Json commands @@ -58,7 +58,9 @@ function ConvertTo-PropertyList { .link EZOut\ConvertTo-PropertySet #> - [alias('Select-ObjectProperty-HashTable')] + [alias( + # 'Select-ObjectProperty-HashTable' + )] param ( # InputObject [Parameter(Mandatory, ValueFromPipeline)] @@ -71,7 +73,10 @@ function ConvertTo-PropertyList { [Parameter()][switch]$AsObject ) - begin {} + begin { + Write-Warning "Replace with 'Dev.Nin\New-Hashtable'" + + } process { $propList = $_ | Select-Object -Property $Property $collectedProp = [ordered]@{} diff --git a/public/Format-RelativePath.ps1 b/public/Format-RelativePath.ps1 index df45fb8..9a0aff6 100644 --- a/public/Format-RelativePath.ps1 +++ b/public/Format-RelativePath.ps1 @@ -2,7 +2,7 @@ Export-ModuleMember -Alias 'ConvertTo-RelativePath' function Format-RelativePath { <# .synopsis - relative paths, allows you to pipe to commands that expects raw text like 'fzf preview'. + relative paths, allows you to pipe to commands that expects raw text like 'fzf preview'. .description Transforms both paths as text and (get-item)s - convert to the raw File.FullName raw text @@ -47,9 +47,9 @@ function Format-RelativePath { 🐒> ls .\My_Gist\ | To->RelativePath My_Gist\AngleSharp Example - My_Gist\Calling-Pwsh-Commands-With-Dynam + My_Gist\Calling-Pwsh-Commands-With-Dynam My_Gist\Making regular expressions reada - + .outputs [string] .link @@ -101,28 +101,36 @@ function Format-RelativePath { ripgrep and/or grep have file line numbers at the start, or end, depending on mode #> $InputObject | ForEach-Object { - $rawItem = $_ + $rawItem = $_ # maybe always strip ansi ? if ($rawItem -is 'string') { + $parsedItem = $rawItem | Remove-AnsiEscape + } else { $parsedItem = $rawItem - | Remove-AnsiEscape } - if (! $LiteralPath) { - $curItem = Get-Item $parsedItem + try { + $curItem = Get-Item $parsedItem -ea stop + } catch { + Write-Error "Get-Item failed on: '$parsedItem', falling back to text" + $curItem = $parsedItem } + + # if (! $LiteralPath) { + # $curItem = Get-Item $parsedItem + # } if ($null -eq $curItem) { - Write-Error 'curItem: $null' - return + Write-Error 'curItem: $null' -ea Stop #SilentlyContinue + return } if ($null -eq $curDir) { - Write-Error 'curDir: $null' - return + Write-Error 'curDir: $null' -ea Stop #SilentlyContinue + return } - + [System.IO.Path]::GetRelativePath( $curDir, $parsedItem ) } } - end { + end { } } diff --git a/public/Resolve-CommandName.ps1 b/public/Resolve-CommandName.ps1 index 029ad15..1adce6b 100644 --- a/public/Resolve-CommandName.ps1 +++ b/public/Resolve-CommandName.ps1 @@ -1,5 +1,6 @@ using namespace System.Collections.Generic + function Resolve-CommandName { <# .synopsis diff --git a/public/Select-NinProperty.ps1 b/public/Select-NinProperty.ps1 index 6a10c04..3bb6588 100644 --- a/public/Select-NinProperty.ps1 +++ b/public/Select-NinProperty.ps1 @@ -1,5 +1,6 @@ using namespace System.Collections.Generic + function Select-NinProperty { <# .synopsis @@ -14,7 +15,10 @@ function Select-NinProperty { .example PS> #> - [Alias('SelectProp', 'Select-Property', 'PropList')] + [Alias( + 'Select->Prop' # select not Dive. dive would actually be the dive->member (not property) command + # 'SelectProp', 'Select-Property', 'PropList' + )] [CmdletBinding( PositionalBinding = $false)] param ( # source objects From 8885de6354d0784af5bfd9aa3904f1a06d299d44 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Fri, 19 Nov 2021 12:43:32 -0600 Subject: [PATCH 21/49] doc string --- public_autoloader/Join-Hashtable.ps1 | 16 ++++++++++++---- public_autoloader/Out-NinGridView.ps1 | 3 ++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/public_autoloader/Join-Hashtable.ps1 b/public_autoloader/Join-Hashtable.ps1 index 4da4212..4e9b7dd 100644 --- a/public_autoloader/Join-Hashtable.ps1 +++ b/public_autoloader/Join-Hashtable.ps1 @@ -11,6 +11,12 @@ Function Join-Hashtable { Copy and append BaseHash with new values from UpdateHash .notes future: add valuefrom pipeline to $UpdateHash param + .link + Ninmonkey.Console\Join-Hashtable + .link + PSScriptTools\Join-Hashtable + .link + Ninmonkey.Powershell\Join-Hashtable #> [cmdletbinding()] param( @@ -24,9 +30,11 @@ Function Join-Hashtable { ) # don't mutate $BaseHash - $NewHash = [hashtable]::new( $BaseHash ) - $UpdateHash.GetEnumerator() | ForEach-Object { - $NewHash[ $_.Key ] = $_.Value + process { + $NewHash = [hashtable]::new( $BaseHash ) + $UpdateHash.GetEnumerator() | ForEach-Object { + $NewHash[ $_.Key ] = $_.Value + } + $NewHash } - $NewHash } diff --git a/public_autoloader/Out-NinGridView.ps1 b/public_autoloader/Out-NinGridView.ps1 index d6f16a8..1df4da3 100644 --- a/public_autoloader/Out-NinGridView.ps1 +++ b/public_autoloader/Out-NinGridView.ps1 @@ -19,7 +19,8 @@ function Out-NinGridView { [Alias('Out-Grid')] [cmdletbinding()] param( - [Parameter(Mandatory, v)] + # inputobject[s] + [Parameter(Mandatory)] [object]$InputObject ) From eb45efd26d7f4716e27c0e6c53753672117e4421 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Sun, 21 Nov 2021 17:33:59 -0600 Subject: [PATCH 22/49] Added fail case to parse for later --- public/ConvertTo-Timespan.ps1 | 6 +++++- public/ConvertTo-Timespan.tests.ps1 | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/public/ConvertTo-Timespan.ps1 b/public/ConvertTo-Timespan.ps1 index c17e686..f90efdb 100644 --- a/public/ConvertTo-Timespan.ps1 +++ b/public/ConvertTo-Timespan.ps1 @@ -49,7 +49,11 @@ function ConvertTo-Timespan { .notes - [ ] better verb? better name, timespan? ConvertTo ? - 'New-RelativeTimespan' or 'ConvertTo-Timespan' ? + 'New-RelativeTimespan' or 'ConvertTo-Timespan' ? + + + + See also: Szeraax/Get-TimeStuff.ps1 .link https://gist.github.com/Szeraax/43aa193e0759d9b091faaaa2f5a03cc9 diff --git a/public/ConvertTo-Timespan.tests.ps1 b/public/ConvertTo-Timespan.tests.ps1 index 9c1d13d..93f2be7 100644 --- a/public/ConvertTo-Timespan.tests.ps1 +++ b/public/ConvertTo-Timespan.tests.ps1 @@ -27,8 +27,19 @@ Describe 'ConvertTo-Timespan' { $ts_sum = $total_ms | ForEach-Object { [timespan]::new(0, 0, 0, 0, $_) - } - + } + } + Describe 'Partial Parameters' { + It 'OnlyMs' { + ConvertTo-Timespan '1m' | ForEach-Object TotalSeconds | Should -Be 60 + } + It 'Single ms' { + ConvertTo-Timespan '1ms' | ForEach-Object TotalMilliseconds + | Should -Be 1 -Because '"ms" should parse to ms, not the partial match of "s"' + } + It 'Explicit 0s' { + ConvertTo-Timespan '0s1ms' | ForEach-Object TotalMilliseconds | Should -Be 1 + } } } \ No newline at end of file From 3cd3daa50f26d60223a20f2f7f1113b9c2abdf37 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Sun, 21 Nov 2021 20:12:53 -0600 Subject: [PATCH 23/49] Update _enumerateMyCommand.tests.ps1 --- .../_enumerateMyCommand.tests.ps1 | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/public_autoloader/_enumerateMyCommand.tests.ps1 b/public_autoloader/_enumerateMyCommand.tests.ps1 index 8547e19..e52731b 100644 --- a/public_autoloader/_enumerateMyCommand.tests.ps1 +++ b/public_autoloader/_enumerateMyCommand.tests.ps1 @@ -1,16 +1,14 @@ +#Requires -Version 7 #requires -modules @{ModuleName='Pester';ModuleVersion='5.0.0'} -$SCRIPT:__PesterFunctionName = $myinvocation.MyCommand.Name.split('.')[0] +BeforeAll { + Import-Module Ninmonkey.Console -Force +} + +Describe '_enumerateMyCommand' -Skip -Tag slow { + # Commmand name itself doesn't exist anymore -Describe "$__PesterFunctionName" -Tag Unit { - BeforeAll { - Import-Module Ninmonkey.Console -Force - # . $(Get-ChildItem -Path $PSScriptRoot/.. -Recurse -Filter "$__PesterFunctionName.ps1") - # $Mocks = Resolve-Path "$PSScriptRoot/Mocks" - $ErrorActionPreference = 'Stop' - $ErrorActionPreference = 'break' - } # It 'Runs without error' { - # # . $__PesterFunctionName Args + # # . _enumerateMyCommand Args # } Describe 'Using -Name' { From 68a68f4739a816d1870ce672cd2f62571c88b154 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Tue, 23 Nov 2021 13:38:07 -0600 Subject: [PATCH 24/49] Test-IsDirectory --- public/Test-IsDirectory.ps1 | 25 ---------- public_autoloader/Test-IsDirectory.ps1 | 49 +++++++++++++++++++ .../Test-IsDirectory.tests.ps1 | 15 ++++-- 3 files changed, 61 insertions(+), 28 deletions(-) delete mode 100644 public/Test-IsDirectory.ps1 create mode 100644 public_autoloader/Test-IsDirectory.ps1 rename {test/public => public_autoloader}/Test-IsDirectory.tests.ps1 (64%) diff --git a/public/Test-IsDirectory.ps1 b/public/Test-IsDirectory.ps1 deleted file mode 100644 index 9567b3a..0000000 --- a/public/Test-IsDirectory.ps1 +++ /dev/null @@ -1,25 +0,0 @@ -function Test-IsDirectory { - <# - .Synopsis - Does it include the attribute [IO.FileAttributes]::Directory ?' - .description - alias 'isDir' - .example - PS> Test-IsDirectory '.' - # $True - - PS> Test-IsDirectory 'foo.png' - # $False - #> - param( - # File object or path to test - [Parameter(Mandatory, Position = 0, ValueFromPipeline)] - [Alias('PSPath')] - [string]$Path - ) - process { - # Todo: see: > - $ItemPath = Get-Item $Path - ($ItemPath.Attributes -band [IO.FileAttributes]::Directory) -eq [IO.FileAttributes]::Directory - } -} diff --git a/public_autoloader/Test-IsDirectory.ps1 b/public_autoloader/Test-IsDirectory.ps1 new file mode 100644 index 0000000..9be1d09 --- /dev/null +++ b/public_autoloader/Test-IsDirectory.ps1 @@ -0,0 +1,49 @@ +function Test-IsContainer { + <# + .Synopsis + Is it a directory, or other container type??' + .example + PS> Test-IsDirectory '.' + # $True + + PS> Test-IsDirectory 'foo.png' + # $False + Todo: see: > + foreach ($item in $pathList) { + $extraArgs = ($item = Get-Item $Path -ea 0) -and $item.PSIsContainer | ?? { '' } : { '-r' } + & $code $pathList $extraArgs + } + #> + [Alias('Test-IsDirectory')] # probably a better name + [outputtype('System.Boolean')] + [CmdletBinding()] + param( + # File object or path to test + [Parameter(Mandatory, Position = 0, ValueFromPipeline)] + [Alias('PSPath')] + [string]$Path + ) + + process { + <# + #> + try { + $item = Get-Item $Path -ea stop + } catch { + # definitely didn't exist + Write-Debug 'GI failed' + $false; return + } + $isType = $Item -is 'System.IO.DirectoryInfo' + $meta = @{ + IsDirInfo = $isDir + HasAttr = $hasAttribute + IsContainer = [bool]$Item.PSIsContainer + + } + + $hasAttribute = ($item.Attributes -band [IO.FileAttributes]::Directory) -eq [IO.FileAttributes]::Directory + $isType -or $hasAttribute -or ([bool]$Item.PSIsContainer) + return + } +} diff --git a/test/public/Test-IsDirectory.tests.ps1 b/public_autoloader/Test-IsDirectory.tests.ps1 similarity index 64% rename from test/public/Test-IsDirectory.tests.ps1 rename to public_autoloader/Test-IsDirectory.tests.ps1 index b6e634d..83b0480 100644 --- a/test/public/Test-IsDirectory.tests.ps1 +++ b/public_autoloader/Test-IsDirectory.tests.ps1 @@ -1,9 +1,18 @@ - +#Requires -Version 7.0 + BeforeAll { - . $PSCommandPath.Replace('.Tests.ps1', '.ps1') + Import-Module Ninmonkey.Console -Force } -Describe "Test-IsDirectory" { +Describe 'Test-IsDirectory' { + It 'Regular filesystem' { + Get-Item . | Test-IsDirectory | Should -Be $True + # todo : ' + } + It 'Using Pansi''s Providor' { + Get-Item fg:\ | Test-IsDirectory | Should -Be $True + } + It 'Dot Path' { Test-IsDirectory '.' | Should -Be $True '.' | Test-IsDirectory | Should -Be $True From 6628bec77fe0ab1f89c0c75b0c4c5fac5746ee43 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Tue, 23 Nov 2021 15:04:36 -0600 Subject: [PATCH 25/49] Update Test-IsDirectory.ps1 --- public_autoloader/Test-IsDirectory.ps1 | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/public_autoloader/Test-IsDirectory.ps1 b/public_autoloader/Test-IsDirectory.ps1 index 9be1d09..3491c93 100644 --- a/public_autoloader/Test-IsDirectory.ps1 +++ b/public_autoloader/Test-IsDirectory.ps1 @@ -1,5 +1,16 @@ -function Test-IsContainer { - <# +#Requires -Version 7 + +if ( $experimentToExport ) { + $experimentToExport.function += @( + 'Test-IsContainer' + ) + $experimentToExport.alias += @( + 'Test-IsDirectory' + ) +} + +function Test-IsContainer { + <#c .Synopsis Is it a directory, or other container type??' .example @@ -23,7 +34,8 @@ [Alias('PSPath')] [string]$Path ) - + begin { + } process { <# #> @@ -46,4 +58,11 @@ $isType -or $hasAttribute -or ([bool]$Item.PSIsContainer) return } + end { + } } + + +if (! $experimentToExport) { + # ... +} \ No newline at end of file From 2bb68226eedf9990155577d22d16c01cfa16d8ee Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Tue, 23 Nov 2021 16:17:22 -0600 Subject: [PATCH 26/49] renaming --- public/Test-NullArg.ps1 | 10 ++-- public/Test-NullArg.tests.ps1 | 72 ++++++++++++++++++++++++++ public_autoloader/Test-IsDirectory.ps1 | 22 ++++---- 3 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 public/Test-NullArg.tests.ps1 diff --git a/public/Test-NullArg.ps1 b/public/Test-NullArg.ps1 index 18dfe1b..bae5a2a 100644 --- a/public/Test-NullArg.ps1 +++ b/public/Test-NullArg.ps1 @@ -14,20 +14,20 @@ function Test-NullArg { [object]$InputObject # Not actually text, but, ) begin { - + # finish mini pass over } process { $objIsNull = $null -eq $InputObject $meta = [ordered]@{ - Value = $objIsNull ? "␀" : $InputObject # ␀ - Type = $objIsNull ? "[Null]" : $InputObject.GetType().Name # ␀ + Value = $objIsNull ? '␀' : $InputObject # ␀ + Type = $objIsNull ? '[Null]' : $InputObject.GetType().Name # ␀ IsNull = $null -eq $InputObject IsNullOrWhiteSpace = [string]::IsNullOrWhiteSpace( $InputObject ) IsNullOrEmpty = [string]::IsNullOrEmpty( $InputObject ) AsString = "'$InputObject'" - ToString = $objIsNull ? "␀" : $InputObject.ToString() | Join-String -SingleQuote - CastString = [string]$InputObject | Join-String -SingleQuote + ToString = $objIsNull ? '␀' : $InputObject.ToString() | Join-String -SingleQuote + CastString = [string]$InputObject | Join-String -SingleQuote TestId = $i++ IsNullCodepoint = $objIsNull ? $false : "`u{0}" -eq $InputObject } diff --git a/public/Test-NullArg.tests.ps1 b/public/Test-NullArg.tests.ps1 new file mode 100644 index 0000000..5258d4e --- /dev/null +++ b/public/Test-NullArg.tests.ps1 @@ -0,0 +1,72 @@ +BeforeAll { + Import-Module Ninmonkey.Console -Force +} +# $sc = { +$sample = @( + 40 + 'a' + @(), + , @(), + 'aa' + $null + (, $null) + '' + ' ' + 10, '', ' ', 0, $null, "`u{0}" +) +# } + +$sample | ForEach-Object { + $cur = $_ + # $cuR ??= '$null' + h1 'step' + $cur | Format-Typename -WithBrackets | Write-Color pink | str prefix 'item: ' + # $cur | Join-String -DoubleQuote | str prefix 'value: ' + Test-NullArg -InputObject $cur + + +} + + +return + +# | Test-NullArg | Format-Table + +$sc | iterProp | Sort-Object MemberType, Name +| Format-List Name, Value, TypeNameOfValue, ReflectionInfo + +h1 'part1' +$scNew = $sc | iterProp | Sort-Object MemberType, Name +| ForEach-Object { + # ㏒ℹℹ️ + $_ | Add-Member -NotePropertyName 'sTypeNameOfValue' -NotePropertyValue $($_ | Format-Typename -WithBrackets) -PassThru + # $_.sTypeNameOfValue = $_ | Format-TypeName +} | s Name, Value, sTypeNameOfValue + +h1 'part3' +#| Format-List Name, Value, sTypeNameOfValue, TypeNameOfValue, ReflectionInfo + +hr +$scNew +| s #-ExcludeProperty 'TypeNameOfValue' * +| s Name, Value, sTypeNameOfValue, ReflectionInfo +# | s Value, sTypeNameOfValue, ReflectionInfo +# $scNew | s Name, Value, sTypeNameOfValue +| Format-List * + + +h1 'part2' +$scNew = $sc | iterProp | Sort-Object MemberType, Name +| ForEach-Object { + # ㏒ℹℹ️ + $_ | Add-Member -NotePropertyName 'sTypeNameOfValue' -NotePropertyValue $($_ | Format-Typename -WithBrackets) -PassThru + + '{0}{1} +{2} +' -f @( + $_.sTypeNameOfValue | Write-Color gray80 + $_.Name + $_.value + ) + # $_.sTypeNameOfValue = $_ | Format-TypeName +} #| s Name, Value, sTypeNameOfValue diff --git a/public_autoloader/Test-IsDirectory.ps1 b/public_autoloader/Test-IsDirectory.ps1 index 3491c93..819dcda 100644 --- a/public_autoloader/Test-IsDirectory.ps1 +++ b/public_autoloader/Test-IsDirectory.ps1 @@ -1,13 +1,12 @@ #Requires -Version 7 +$script:publicToExport.function += @( + 'Test-IsContainer' +) +$script:publicToExport.alias += @( + 'Test-IsDirectory' +) + -if ( $experimentToExport ) { - $experimentToExport.function += @( - 'Test-IsContainer' - ) - $experimentToExport.alias += @( - 'Test-IsDirectory' - ) -} function Test-IsContainer { <#c @@ -56,6 +55,8 @@ function Test-IsContainer { $hasAttribute = ($item.Attributes -band [IO.FileAttributes]::Directory) -eq [IO.FileAttributes]::Directory $isType -or $hasAttribute -or ([bool]$Item.PSIsContainer) + + # Wait-Debugger return } end { @@ -65,4 +66,7 @@ function Test-IsContainer { if (! $experimentToExport) { # ... -} \ No newline at end of file + Get-Item . | Test-IsDirectory | Should -Be $True + Get-Item fg:\ | Test-IsDirectory | Should -Be $True + Test-IsDirectory '.' | Should -Be $True +} From 1c1359c4ec86a2cca93c9bf44bd0bd8dac6392cf Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Fri, 26 Nov 2021 19:33:14 -0600 Subject: [PATCH 27/49] New: Converts numbered filepaths -out-fzf gains new argument: -PreviewCommand Fixed mandatory getOutGridView parameter --- Ninmonkey.Console.psm1 | 35 ++-- public/ConvertFrom-NumberedFilepath.ps1 | 221 ++++++++++++++++++++++++ public/ConvertTo-Base64String.ps1 | 4 +- public/Out-Fzf.ps1 | 12 +- public/Resolve-CommandName.ps1 | 43 ++++- public_autoloader/Out-NinGridView.ps1 | 34 ++-- public_autoloader/__init__.ps1 | 56 +++--- 7 files changed, 329 insertions(+), 76 deletions(-) create mode 100644 public/ConvertFrom-NumberedFilepath.ps1 diff --git a/Ninmonkey.Console.psm1 b/Ninmonkey.Console.psm1 index a54b382..37a942c 100644 --- a/Ninmonkey.Console.psm1 +++ b/Ninmonkey.Console.psm1 @@ -8,14 +8,12 @@ $PSDefaultParameterValues['Write-ConsoleLabel:fg'] = '7FB2C1' # $PSDefaultParameterValues['Write-Text:AsString'] = $true try { Set-PSReadLineKeyHandler -Key 'f5' -Function ShowCommandHelp -ea Stop #SilentlyContinue -} -catch { +} catch { # catch [System.Management.Automation.ParameterBindingValidationException] { if ($_.ToString() -match 'Cannot validate argument on parameter ''Function''. The argument "ShowCommandHelp"') { "Module PSReadline: version {0} is missing function: 'ShowCommandHelp'" -f @( (Get-Module PSReadLine).Version ) | Write-Warning - } - else { + } else { throw $_ } } @@ -46,8 +44,7 @@ if ($False) { if (Test-Path $FileName ) { . $FileName } - } - catch { + } catch { Write-Error "public_autoloader error: '$fileName'" } @@ -84,8 +81,7 @@ if ($psEditor) { foreach ($file in $private_seeminglySci) { # Write-Warning "file: seeminglySci -> : $File" if (Test-Path ('{0}\private\seeminglySci\{1}.ps1' -f $psscriptroot, $file)) { - } - else { + } else { Write-Error "Import: failed: private_seeminglySci: private: $File" } . ('{0}\private\seeminglySci\{1}.ps1' -f $psscriptroot, $file) @@ -102,8 +98,7 @@ $private = @( foreach ($file in $private) { if (Test-Path ('{0}\private\{1}.ps1' -f $psscriptroot, $file)) { - } - else { + } else { Write-Error "Import: private: failed: private: $File" } . ('{0}\private\{1}.ps1' -f $psscriptroot, $file) @@ -119,8 +114,7 @@ $public_NativeWrapper = @( ) foreach ($file in $public_NativeWrapper) { if (Test-Path ('{0}\public\native_wrapper\{1}.ps1' -f $psscriptroot, $file)) { - } - else { + } else { Write-Error "Import: failed: public\native_wrapper: $File" } . ('{0}\public\native_wrapper\{1}.ps1' -f $psscriptroot, $file) @@ -151,7 +145,7 @@ $public_toDotSource = @( 'Write-ConsoleLabel' 'Write-ConsoleHeader' 'Write-ConsoleNewline' - 'Format-RelativePath' + 'ConvertFrom-NumberedFilepath' 'Format-Hashtable' 'Format-ControlChar' @@ -208,7 +202,7 @@ $public_toDotSource = @( 'Format-FileSize' 'Format-NullText' # 'ConvertTo-PropertyList' - 'Test-IsDirectory' + 'Get-NinCommandSyntax' 'Format-TypeName' 'Format-GenericTypeName' @@ -232,8 +226,7 @@ $public_toDotSource = @( foreach ($file in $public_toDotSource) { if (Test-Path ('{0}\public\{1}.ps1' -f $psscriptroot, $file)) { # good - } - else { + } else { Write-Error "Import: failed: public: $File" } . ('{0}\public\{1}.ps1' -f $psscriptroot, $file) @@ -258,7 +251,7 @@ $functionsToExport = @( 'Write-ConsoleLabel' 'Write-ConsoleHeader' 'Write-ConsoleNewline' - 'Format-RelativePath' + 'ConvertFrom-NumberedFilepath' 'Find-GitRepo' 'Write-ConsoleHorizontalRule' @@ -308,7 +301,7 @@ $functionsToExport = @( 'Format-ControlChar' 'Trace-NinCommand' - 'Test-IsDirectory' + 'Set-NinLocation' 'Get-NinCommandSyntax' 'Get-NinTypeData' @@ -368,8 +361,7 @@ foreach ($typeName in $formatData) { if (Test-Path $FileName ) { Update-FormatData -PrependPath $FileName Write-Verbose "Imported: FormatData: [$TypeName] $FileName" - } - else { + } else { Write-Error "Import: failed: FormatData: [$TypeName] $FileName" } } @@ -464,8 +456,7 @@ $FileName = ('{0}\public\completer\{1}' -f $psscriptroot, 'Completer-Loader.ps1' if ( ($__ninConfig)?.HackSkipLoadCompleters ) { Write-Warning '[w] root ⟹ Completer-Loader: Skipped' -} -else { +} else { $curSplat = @{ # Verbose = -Verbose diff --git a/public/ConvertFrom-NumberedFilepath.ps1 b/public/ConvertFrom-NumberedFilepath.ps1 new file mode 100644 index 0000000..d5a42b9 --- /dev/null +++ b/public/ConvertFrom-NumberedFilepath.ps1 @@ -0,0 +1,221 @@ +Export-ModuleMember -Alias @( + 'ConvertTo-RelativePath' + 'StripNumberedFilepaths' +) +Export-ModuleMember -Function 'ConvertFrom-NumberedFilepath' + +function ConvertFrom-NumberedFilepath { + <# + .synopsis + stripFilepathNumbers | filepaths from grep or code errors have line numbers appended + .description + currently strips line numbers, although VSCode can handle it + - todo: [ ] returning object with PSPath but line numbers would be ideal + - [ ] already implemented in the Dev.Nin\Format-RipGrepResult() + future: + [ ] return VsCode filepath numbers, that are valid objects + [ ] should inputtype fileinfo return same value? + no, caller, like To->RelativePath() will test before passing to this, a low level, stable function + .example + PS> + @( + 'foo:bar:cat.PS1:345:4' + 'foo:bar:cat.PS1:345' + ) | ConvertFrom-NumberedFilepath + . + .outputs + [string | None] + .link + Dev.Nin\Format-RipGrepResult + + #> + [Alias('StripNumberedFilepaths')] + [CmdletBinding()] + param( + #piped in text/paths/etc + [AllowEmptyCollection()] + [AllowEmptyString()] + [AllowNull()] + [Parameter(Position = 0, ValueFromPipeline)] + [string]$Text, + + # toggles regex + [switch]$StripLastOnly + ) + + begin { + $Regex = @{ + StripLastNumberOnly = '(:\d+)$' + StripAllNumbers = '(:\d+){1,}$' + } + $RegexMode = $StriplastOnly ? $Regex.StripLastNumberOnly : $Regex.StripAllNumber + Write-Debug "Regex: '$RegexMode'" + } + process { + if ($null -eq $Text) { + return + } + $Text -replace $regex[$regexMode], '' + } + end { + } +} +function Format-RelativePath { + <# + .synopsis + relative paths, allows you to pipe to commands that expects raw text like 'fzf preview'. + .description + Transforms both paths as text and (get-item)s + - convert to the raw File.FullName raw text + - convert to relative path + If not specified, it uses your current directory + + for files/folders, converts to the string relative path + this is meant to pre-process items as was as j + todo: get the dotnet [io.path] method, which is a lot faster + .example + newestItem🔎 Code-Workspace💻 | StripAnsi | To->RelativePath | pipe->Peek + .example + 🐒> ls . -Recurse *.json | Format-RelativePath + .example + 🐒> ls $env:APPDATA *code* -Depth 4 + | select -First 5 | Format-RelativePath -BasePath $env:APPDATA + + Code + Code - Insiders + vscode-mssql + .example + 🐒> ls $env:APPDATA *code* -Depth 4 + | select -First 5 | Format-RelativePath -BasePath $env:UserProfile + + AppData\Roaming\Code + AppData\Roaming\Code - Insiders + AppData\Roaming\vscode-mssql + .example + # sample files for below + PS> ls ~\.vscode | select -First 2 | % FullName + C:\Users\cppmo_000\.vscode\extensions + C:\Users\cppmo_000\.vscode\argv.json + .example + # use a specific base path + 🐒> ls -Force ~\.vscode | Format-RelativePath "$Env:USERPROFILE" + + .vscode\extensions + .vscode\argv.json + .example + # use relative your CWD + + 🐒> ls .\My_Gist\ | To->RelativePath + + My_Gist\AngleSharp Example + My_Gist\Calling-Pwsh-Commands-With-Dynam + My_Gist\Making regular expressions reada + + .outputs + [string] + .link + https://docs.microsoft.com/en-us/dotnet/api/system.io.path.getrelativepath + .link + https://docs.microsoft.com/en-us/dotnet/api/system.io.path.getfullpath + #> + [Alias('ConvertTo-RelativePath')] + [cmdletbinding()] + param ( + # Filepath + [Alias('PSPath', 'Path', 'To->RelativePath')] + [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] + [object[]]$InputObject, + + # relative path to resolve from + # future, use completions so visual and final replace are different + # it can show 'dotfiles' but really use env vars, etc. + # $items = "$Env:UserProfile", "$Env:AppData", "$Env:LocalAppData" + # | ForEach-Object tostring + # , $items + [Parameter(Position = 0)] + [ArgumentCompletions( + 'C:\Users\cppmo_000\SkyDrive\Documents\2021', + 'C:\Users\cppmo_000\AppData\Roaming', + 'C:\Users\cppmo_000\AppData\Local', + 'C:\Users\cppmo_000' + )] + [string]$BasePath, + + # interpret strings as literal path, verses get-item which resolves to many files + # paths with globs or 'c:\foo\*' resolve to many paths if this is off + [alias('LiteralPath')] + [switch]$AsLiteralPath + + ) + begin { + $Config = @{ + AlwaysStripAnsi = $true + } + # Push-Location -StackName 'temp' $BasePath + if (! [string]::IsNullOrWhiteSpace( $BasePath) ) { + $curDir = Get-Item $BasePath + } + $curDir ??= Get-Location + } + process { + <# + ripgrep and/or grep have file line numbers at the start, or end, depending on mode + #> + + + $InputObject | ForEach-Object { + $rawItem = $_ # maybe always strip ansi ? + if ($rawItem -is 'string') { + $parsedItem = $rawItem | Remove-AnsiEscape + } else { + $parsedItem = $rawItem + } + + $maybeNameList = @( + $parsedItem + $parsedItem -replace '(:\d+)$', '' + ) + try { + $curItem = Get-Item $parsedItem -ea stop + } catch { + Write-Error "Get-Item failed on: '$parsedItem', falling back to text" + $curItem = $parsedItem + } + + # if (! $LiteralPath) { + # $curItem = Get-Item $parsedItem + # } + if ($null -eq $curItem) { + Write-Error 'curItem: $null' -ea Stop #SilentlyContinue + return + } + if ($null -eq $curDir) { + Write-Error 'curDir: $null' -ea Stop #SilentlyContinue + return + } + + [System.IO.Path]::GetRelativePath( $curDir, $parsedItem ) + } + } + end { + } +} + +# if ($false -and $DebugTestMode) { +# # refactor to use Pester temp drives +# Push-Location -StackName 'debugStack' 'C:\Users\cppmo_000\Documents\2020\powershell\MyModules_Github\Ninmonkey.Console\public' + +# $d = Get-Item . +# Format-RelativePath $d -Debug + + +# $f1 = Get-Item "$PSScriptRoot\data\unicode_web_query.ps1" +# $strList = @( +# '.\native_wrapper\Invoke-IPython.ps1' +# '.\native_wrapper\' +# ) + +# $strList | Format-RelativePath + +# Pop-Location -StackName 'debugStack' +# } diff --git a/public/ConvertTo-Base64String.ps1 b/public/ConvertTo-Base64String.ps1 index 5d956ce..f4ffc4d 100644 --- a/public/ConvertTo-Base64String.ps1 +++ b/public/ConvertTo-Base64String.ps1 @@ -1,4 +1,6 @@ - +using namespace System.Text + + # todo function ConvertTo-Base64String { diff --git a/public/Out-Fzf.ps1 b/public/Out-Fzf.ps1 index 7f0e68e..d97e91f 100644 --- a/public/Out-Fzf.ps1 +++ b/public/Out-Fzf.ps1 @@ -89,6 +89,11 @@ function Out-Fzf { [Parameter()][switch]$Cycle, + # fzf's preview command like: + # --preview 'bat --color=always --style=snip,header,numbers --line-range=:200 {}' + [Parameter()] + [ArgumentCompletions("--preview 'bat --color=always --style=snip,header,numbers --line-range=:200 {}'")] + [string]$PreviewCommand, <# relative path selection for user's readability. Strips path's prefix on input, prefix it back on for output. @@ -188,8 +193,7 @@ function Out-Fzf { if (! $relativePath) { $Selection = $inputList | & $binFzf @fzfArgs $Selection - } - else { + } else { $prefixPattern = '^{0}' -f @( [regex]::escape( ( Get-Item '.' | ForEach-Object FullName ) ) ) @@ -225,12 +229,12 @@ function Out-Fzf { $debugMeta += @{ InputListCount = $inputList.Count SelectionCount = $Selection.Count - Selection = $Selection | Join-String -sep ', ' -SingleQuote | Label 'Selection' + Selection = $Selection | Join-String -sep ', ' -SingleQuote | Label 'Selection' } $debugMeta | Format-HashTable -Title '@debugMeta' | Write-Debug $debugMeta.SelectionCount | Label 'Num Selected' | Write-Debug - $Selection | Join-String -sep ', ' -SingleQuote | Label 'Selection' | Write-Debug + $Selection | Join-String -sep ', ' -SingleQuote | Label 'Selection' | Write-Debug $fzfArgs | Join-String -sep "`n-" -SingleQuote | Label 'FzfArgs' | Write-Debug } diff --git a/public/Resolve-CommandName.ps1 b/public/Resolve-CommandName.ps1 index 1adce6b..1bccff1 100644 --- a/public/Resolve-CommandName.ps1 +++ b/public/Resolve-CommandName.ps1 @@ -41,7 +41,12 @@ function Resolve-CommandName { # Error if not exactly one match is found [Alias('Strict')] - [Parameter()][switch]$OneOrNone + [Parameter()][switch]$OneOrNone, + + # disabled by default for speed + [Parameter()][switch]$IncludeAll, + + [parameter()][switch]$PassThru ) begin { $NameList = [list[string]]::new() @@ -58,9 +63,15 @@ function Resolve-CommandName { end { $getCommandSplat = @{ Name = $NameList - All = $true + All = $IncludeAll } + <# + warning/todo/bug: + passing wildcard arguments get weird errors + + gcm '*find*' | rescmd -QualifiedName -PreserveAlias + #> $commands = Get-Command @getCommandSplat | ForEach-Object { # Get-Command -Name $_.ResolvedCommand if ($_.CommandType -eq 'Alias' -and (! $PreserveAlias)) { @@ -89,12 +100,28 @@ function Resolve-CommandName { } if ($QualifiedName) { - # this works - $Commands | ForEach-Object { - '{0}\{1}' -f @( $_.Source, $_.Name ) + $Commands | ForEach-Object -ea continue { + $cmd = $_ + if (! $PassThru) { + '{0}\{1}' -f @( $cmd.Source, $cmd.Name ) + } else { + # todo: return a rich type, with this name, where tostring is this? + $meta = [ordered]@{ + PSTypeName = 'nin.QualifiedCommand' + Name = '{0}\{1}' -f @( + $cmd.Source, $cmd.Name + ) + BaseName = $cmd.Name + Source = $cmd.Source + # $cmd. + # $cmd.comm + } + [pscustomobject]$meta + + } + return } - return + $Commands } - $Commands } -} +} \ No newline at end of file diff --git a/public_autoloader/Out-NinGridView.ps1 b/public_autoloader/Out-NinGridView.ps1 index 1df4da3..01c8bbf 100644 --- a/public_autoloader/Out-NinGridView.ps1 +++ b/public_autoloader/Out-NinGridView.ps1 @@ -1,10 +1,14 @@ #Requires -Version 7 -$publicToExport.function += @( - 'Out-NinGridView' -) -$publicToExport.alias += @( - 'Out-Grid' -) + +if ( $experimentToExport ) { + $experimentToExport.function += @( + 'Out-NinGridView' + ) + $experimentToExport.alias += @( + 'Out-Grid' + ) +} + function Out-NinGridView { <# .synopsis @@ -35,23 +39,27 @@ function Out-NinGridView { end { # Label 'status' '=> piping...' $objList - | Out-GridView #-PassThru + | Out-GridView -PassThru # Label 'status' '=> restore' if (Get-Command -ea ignore 'Window->Get') { $w = Window->Get '*Out-GridView*' $w | Minimize-Window - # Start-Sleep 0.1 + Start-Sleep 0.1 $w | Restore-Window } # Label 'status' '=> Done' } } -# works -if ($false) { - Get-ChildItem . | Out-NinGridView - Start-Sleep 0.3 - Get-ChildItem . | Select-Object * | Out-NinGridView +if (! $experimentToExport) { + if ($false) { + Get-ChildItem . | Out-NinGridView + Start-Sleep 0.3 + Get-ChildItem . | Select-Object * | Out-NinGridView + } + # ... } + +# works diff --git a/public_autoloader/__init__.ps1 b/public_autoloader/__init__.ps1 index eb3b4d4..ee15d09 100644 --- a/public_autoloader/__init__.ps1 +++ b/public_autoloader/__init__.ps1 @@ -13,36 +13,36 @@ # hardCoded until created # see: -try { - # $fileList = @( - # # 'Get-CommandSummary-OldMethod' - # 'Get-CommandSummafry' - # 'Find-Exception' - # ) +# try { +# $fileList = @( +# # 'Get-CommandSummary-OldMethod' +# 'Get-CommandSummafry' +# 'Find-Exception' +# ) - # Don't dot tests, don't call self. - Get-ChildItem -File -Path (Get-Item -ea stop $PSScriptRoot) - | Where-Object { $_.Name -ne '__init__.ps1' } - | Where-Object { - # are these safe? or will it alter where-object? - # Write-Debug "removing test: '$($_.Name)'" - $_.Name -notmatch '\.tests\.ps1$' - } - | ForEach-Object { - # are these safe? or will it alter where-object? - # Write-Debug "[dev.nin] importing experiment '$($_.Name)'" - $curScript = $_ - try { - . $curScript - } - catch { - Write-Error -Exception $_ -Message "DotsourceImportFailed: public_autoloader\__init__.ps1: '$($curScript)'" -TargetObject $_ -Category InvalidOperation - } - } +# Don't dot tests, don't call self. +Get-ChildItem -File -Path (Get-Item -ea stop $PSScriptRoot) +| Where-Object { $_.Name -ne '__init__.ps1' } +| Where-Object { + # are these safe? or will it alter where-object? + # Write-Debug "removing test: '$($_.Name)'" + $_.Name -notmatch '\.tests\.ps1$' } -catch { - Write-Error -Exception $_ -Message 'public_autoloader\__init__.ps1: failed' +| ForEach-Object { + # are these safe? or will it alter where-object? + # Write-Debug "[dev.nin] importing experiment '$($_.Name)'" + $curScript = $_ + try { + . $curScript + } catch { + # Write-Error -Exception $_ -Message "DotsourceImportFailed: public_autoloader\__init__.ps1: '$($curScript)'" -TargetObject $_ -Category InvalidOperation + Write-Error "todo: correctly throw: '$_'" + } } +# } catch { +# Write-Error "public_autoloader\__init__.ps1: failed`ntodo: correctly throw: '$_'" +# Write-Error -Exception $_ -Message '' +# } $script:publicToExport | Join-String -op 'ExperimentToExport' | Write-Debug @@ -59,7 +59,7 @@ if ($script:publicToExport['variable']) { Export-ModuleMember -Variable $script:publicToExport['variable'] } -$meta | Write-Information +$meta | Format-Table | Out-String | Write-Information From f701e2632ead8078a97945f8703b7643a17a21c2 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Fri, 26 Nov 2021 19:58:37 -0600 Subject: [PATCH 28/49] Fixed command logic --- public/Format-RelativePath.ps1 | 154 --------------------------- public/Resolve-CommandName.ps1 | 42 +++++--- public/Resolve-CommandName.tests.ps1 | 4 + 3 files changed, 33 insertions(+), 167 deletions(-) delete mode 100644 public/Format-RelativePath.ps1 diff --git a/public/Format-RelativePath.ps1 b/public/Format-RelativePath.ps1 deleted file mode 100644 index 9a0aff6..0000000 --- a/public/Format-RelativePath.ps1 +++ /dev/null @@ -1,154 +0,0 @@ -Export-ModuleMember -Alias 'ConvertTo-RelativePath' -function Format-RelativePath { - <# - .synopsis - relative paths, allows you to pipe to commands that expects raw text like 'fzf preview'. - .description - Transforms both paths as text and (get-item)s - - convert to the raw File.FullName raw text - - convert to relative path - If not specified, it uses your current directory - - for files/folders, converts to the string relative path - this is meant to pre-process items as was as j - todo: get the dotnet [io.path] method, which is a lot faster - .example - newestItem🔎 Code-Workspace💻 | StripAnsi | To->RelativePath | pipe->Peek - .example - 🐒> ls . -Recurse *.json | Format-RelativePath - .example - 🐒> ls $env:APPDATA *code* -Depth 4 - | select -First 5 | Format-RelativePath -BasePath $env:APPDATA - - Code - Code - Insiders - vscode-mssql - .example - 🐒> ls $env:APPDATA *code* -Depth 4 - | select -First 5 | Format-RelativePath -BasePath $env:UserProfile - - AppData\Roaming\Code - AppData\Roaming\Code - Insiders - AppData\Roaming\vscode-mssql - .example - # sample files for below - PS> ls ~\.vscode | select -First 2 | % FullName - C:\Users\cppmo_000\.vscode\extensions - C:\Users\cppmo_000\.vscode\argv.json - .example - # use a specific base path - 🐒> ls -Force ~\.vscode | Format-RelativePath "$Env:USERPROFILE" - - .vscode\extensions - .vscode\argv.json - .example - # use relative your CWD - - 🐒> ls .\My_Gist\ | To->RelativePath - - My_Gist\AngleSharp Example - My_Gist\Calling-Pwsh-Commands-With-Dynam - My_Gist\Making regular expressions reada - - .outputs - [string] - .link - https://docs.microsoft.com/en-us/dotnet/api/system.io.path.getrelativepath - .link - https://docs.microsoft.com/en-us/dotnet/api/system.io.path.getfullpath - #> - [Alias('ConvertTo-RelativePath')] - [cmdletbinding()] - param ( - # Filepath - [Alias('PSPath', 'Path', 'To->RelativePath')] - [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] - [object[]]$InputObject, - - # relative path to resolve from - # future, use completions so visual and final replace are different - # it can show 'dotfiles' but really use env vars, etc. - # $items = "$Env:UserProfile", "$Env:AppData", "$Env:LocalAppData" - # | ForEach-Object tostring - # , $items - [Parameter(Position = 0)] - [ArgumentCompletions( - 'C:\Users\cppmo_000\SkyDrive\Documents\2021', - 'C:\Users\cppmo_000\AppData\Roaming', - 'C:\Users\cppmo_000\AppData\Local', - 'C:\Users\cppmo_000' - )] - [string]$BasePath, - - # interpret strings as literal path, verses get-item which resolves to many files - # paths with globs or 'c:\foo\*' resolve to many paths if this is off - [alias('LiteralPath')] - [switch]$AsLiteralPath - - ) - begin { - $Config = @{ - AlwaysStripAnsi = $true - } - # Push-Location -StackName 'temp' $BasePath - if (! [string]::IsNullOrWhiteSpace( $BasePath) ) { - $curDir = Get-Item $BasePath - } - $curDir ??= Get-Location - } - process { - <# - ripgrep and/or grep have file line numbers at the start, or end, depending on mode - #> - $InputObject | ForEach-Object { - $rawItem = $_ # maybe always strip ansi ? - if ($rawItem -is 'string') { - $parsedItem = $rawItem | Remove-AnsiEscape - } else { - $parsedItem = $rawItem - } - - try { - $curItem = Get-Item $parsedItem -ea stop - } catch { - Write-Error "Get-Item failed on: '$parsedItem', falling back to text" - $curItem = $parsedItem - } - - # if (! $LiteralPath) { - # $curItem = Get-Item $parsedItem - # } - if ($null -eq $curItem) { - Write-Error 'curItem: $null' -ea Stop #SilentlyContinue - return - } - if ($null -eq $curDir) { - Write-Error 'curDir: $null' -ea Stop #SilentlyContinue - return - } - - [System.IO.Path]::GetRelativePath( $curDir, $parsedItem ) - } - } - end { - } -} - -# if ($false -and $DebugTestMode) { -# # refactor to use Pester temp drives -# Push-Location -StackName 'debugStack' 'C:\Users\cppmo_000\Documents\2020\powershell\MyModules_Github\Ninmonkey.Console\public' - -# $d = Get-Item . -# Format-RelativePath $d -Debug - - -# $f1 = Get-Item "$PSScriptRoot\data\unicode_web_query.ps1" -# $strList = @( -# '.\native_wrapper\Invoke-IPython.ps1' -# '.\native_wrapper\' -# ) - -# $strList | Format-RelativePath - -# Pop-Location -StackName 'debugStack' -# } diff --git a/public/Resolve-CommandName.ps1 b/public/Resolve-CommandName.ps1 index 1bccff1..31c86a4 100644 --- a/public/Resolve-CommandName.ps1 +++ b/public/Resolve-CommandName.ps1 @@ -19,6 +19,12 @@ function Resolve-CommandName { .outputs [Management.Automation.CmdletInfo[]] or [string[]] zero-to-many [CmdletInfo] or other [Command] types + .link + Dev.Nin\ResCmd + .link + Dev.Nin\cmdToFilepath + .link + Ninmonkey.Console\Resolve-CommandName #> [CmdletBinding(PositionalBinding = $false)] [OutputType([object])] @@ -106,22 +112,32 @@ function Resolve-CommandName { '{0}\{1}' -f @( $cmd.Source, $cmd.Name ) } else { # todo: return a rich type, with this name, where tostring is this? - $meta = [ordered]@{ - PSTypeName = 'nin.QualifiedCommand' - Name = '{0}\{1}' -f @( - $cmd.Source, $cmd.Name - ) - BaseName = $cmd.Name - Source = $cmd.Source - # $cmd. - # $cmd.comm + $source = if ($cmd -is 'AliasInfo') { + $cmd | ForEach-Object ResolvedCommand | ForEach-Object Module | ForEach-Object Name + } else { + # $cnds[2] -is 'functioninfo' + $cmd.Source } - [pscustomobject]$meta - } - return + $meta = [ordered]@{ + + PSTypeName = 'nin.QualifiedCommand' + Name = '{0}\{1}' -f @( + $cmd.Source, $cmd.Name + ) + BaseName = $cmd.Name + Source = $Source + # $cmd. + # $cmd.comm + } + [pscustomobject]$meta + } - $Commands + return } + + # else + $Commands } + } \ No newline at end of file diff --git a/public/Resolve-CommandName.tests.ps1 b/public/Resolve-CommandName.tests.ps1 index 016ceab..8e3f843 100644 --- a/public/Resolve-CommandName.tests.ps1 +++ b/public/Resolve-CommandName.tests.ps1 @@ -25,6 +25,10 @@ Describe 'Resolve-CommandName' { | Should -Be $Expected } + } + It 'PreserveAlias' { + + } # It 'Runs without error' { From 91daf877cfef790f3e18459b0d24d36df4f95fda Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Sat, 27 Nov 2021 10:55:09 -0600 Subject: [PATCH 29/49] ConvertFrom-NumberedFilepath tests pass --- Ninmonkey.Console.psd1 | 2 +- Ninmonkey.Console.psm1 | 4 +- .../ConvertFrom-NumberedFilepath.ps1 | 77 ++++++++++ .../ConvertFrom-NumberedFilepath.tests.ps1 | 63 ++++++++ .../ConvertTo-RelativePath.ps1 | 139 +++++++----------- 5 files changed, 193 insertions(+), 92 deletions(-) create mode 100644 public_autoloader/ConvertFrom-NumberedFilepath.ps1 create mode 100644 public_autoloader/ConvertFrom-NumberedFilepath.tests.ps1 rename public/ConvertFrom-NumberedFilepath.ps1 => public_autoloader/ConvertTo-RelativePath.ps1 (57%) diff --git a/Ninmonkey.Console.psd1 b/Ninmonkey.Console.psd1 index 7b42829..161e0f1 100644 --- a/Ninmonkey.Console.psd1 +++ b/Ninmonkey.Console.psd1 @@ -11,7 +11,7 @@ RootModule = 'Ninmonkey.Console.psm1' # Version number of this module. - ModuleVersion = '0.1.3' + ModuleVersion = '0.1.4' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/Ninmonkey.Console.psm1 b/Ninmonkey.Console.psm1 index 37a942c..c844e37 100644 --- a/Ninmonkey.Console.psm1 +++ b/Ninmonkey.Console.psm1 @@ -145,7 +145,7 @@ $public_toDotSource = @( 'Write-ConsoleLabel' 'Write-ConsoleHeader' 'Write-ConsoleNewline' - 'ConvertFrom-NumberedFilepath' + 'Format-Hashtable' 'Format-ControlChar' @@ -251,7 +251,7 @@ $functionsToExport = @( 'Write-ConsoleLabel' 'Write-ConsoleHeader' 'Write-ConsoleNewline' - 'ConvertFrom-NumberedFilepath' + 'Find-GitRepo' 'Write-ConsoleHorizontalRule' diff --git a/public_autoloader/ConvertFrom-NumberedFilepath.ps1 b/public_autoloader/ConvertFrom-NumberedFilepath.ps1 new file mode 100644 index 0000000..39d03ed --- /dev/null +++ b/public_autoloader/ConvertFrom-NumberedFilepath.ps1 @@ -0,0 +1,77 @@ +#Requires -Version 7 + +if ( $publicToExport ) { + $publicToExport.function += @( + 'ConvertFrom-NumberedFilepath' + ) + $publicToExport.alias += @( + 'StripNumberedFilepaths' + ) +} + +function ConvertFrom-NumberedFilepath { + <# + .synopsis + stripFilepathNumbers | filepaths from grep or code errors have line numbers appended + .description + currently strips line numbers, although VSCode can handle it + - todo: [ ] returning object with PSPath but line numbers would be ideal + - [ ] already implemented in the Dev.Nin\Format-RipGrepResult() + future: + [ ] return VsCode filepath numbers, that are valid objects + [ ] should inputtype fileinfo return same value? + no, caller, like To->RelativePath() will test before passing to this, a low level, stable function + .notes + Naming it remove would be consistent with Remove-AnsiEscapes + however, remove Filepath could imply it throws out the entire filepath, vs trying to transform + .example + PS> + @( + 'foo:bar:cat.PS1:345:4' + 'foo:bar:cat.PS1:345' + ) | ConvertFrom-NumberedFilepath + . + .outputs + [string | None] + .link + Dev.Nin\Format-RipGrepResult + + #> + # + [Alias( + 'StripNumberedFilepaths' + )] + [CmdletBinding()] + param( + #piped in text/paths/etc + [AllowEmptyCollection()] + [AllowEmptyString()] + [AllowNull()] + [Parameter(Position = 0, ValueFromPipeline)] + [string]$Text, + + # toggles regex + [switch]$StripLastOnly + ) + + begin { + $Regex = @{ + StripLastNumberOnly = '(:\d+)$' + StripAllNumbers = '(:\d+){1,}$' + } + $RegexMode = $StriplastOnly ? 'StripLastNumberOnly' : 'StripAllNumbers' + Write-Debug "Regex: '$RegexMode'" + } + process { + if ($null -eq $Text) { + return + } + $Text -replace $regex[$regexMode], '' + } + end { + } +} + +if (! $publicToExport) { + # ... +} \ No newline at end of file diff --git a/public_autoloader/ConvertFrom-NumberedFilepath.tests.ps1 b/public_autoloader/ConvertFrom-NumberedFilepath.tests.ps1 new file mode 100644 index 0000000..ea95381 --- /dev/null +++ b/public_autoloader/ConvertFrom-NumberedFilepath.tests.ps1 @@ -0,0 +1,63 @@ +BeforeAll { + Import-Module Ninmonkey.Console -Force +} + +Describe 'ConvertFrom-NumberedFilepath' -Skip { + It 'Does not throw' { + { 'adsfs' | ConvertFrom-NumberedFilepath } + | Should -Not -Throw + } + + Describe 'Format -As [VSCodeFilepath]' { + It 'Text: Valid filepath' { + Set-ItResult -Pending -Because 'needs to be created/merged / nyi' + # '...' | Should -BeOfType ([VSCodeFilepath]) + } + # $result = + } + + Describe 'AnsiEscapes' { + It 'FromRipGrep' { + Set-ItResult -Skipped -Because 'add handling piping from RipGrep using StripAnsi()' + } + } + + It 'DefaultArgs: "" = ""' -ForEach @( + @{ + Text = 'foo:bar:cat.ps1:345:4' + Expected = 'foo:bar:cat.ps1' + } + @{ + Text = 'foo:bar:cat.ps1:345' + Expected = 'foo:bar:cat.ps1' + } + @{ + Text = 'foo:bar:cat.ps1' + Expected = 'foo:bar:cat.ps1' + } + ) { + $Text | ConvertFrom-NumberedFilepath -StripLastOnly:$False + | Should -Be $Expected + } + It 'StripLastOnly: "" = ""' -ForEach @( + @{ + Text = 'foo:bar:cat.PS1:345:4' + Expected = 'foo:bar:cat.PS1:345' + ShouldThrow = $False + } + @{ + Text = 'foo:bar:cat.PS1:345:4' + Expected = 'foo:bar:cat.PS1:345' + ShouldThrow = $False + } + ) { + if ($ShouldThrow ?? $false) { + { $Text | ConvertFrom-NumberedFilepath -StripLastOnly } + | Should -Throw -Because 'Invalid result' + + } + + $Text | ConvertFrom-NumberedFilepath -StripLastOnly + | Should -Be $Expected + } +} diff --git a/public/ConvertFrom-NumberedFilepath.ps1 b/public_autoloader/ConvertTo-RelativePath.ps1 similarity index 57% rename from public/ConvertFrom-NumberedFilepath.ps1 rename to public_autoloader/ConvertTo-RelativePath.ps1 index d5a42b9..5f8ffd7 100644 --- a/public/ConvertFrom-NumberedFilepath.ps1 +++ b/public_autoloader/ConvertTo-RelativePath.ps1 @@ -1,66 +1,15 @@ -Export-ModuleMember -Alias @( - 'ConvertTo-RelativePath' - 'StripNumberedFilepaths' -) -Export-ModuleMember -Function 'ConvertFrom-NumberedFilepath' +#Requires -Version 7 -function ConvertFrom-NumberedFilepath { - <# - .synopsis - stripFilepathNumbers | filepaths from grep or code errors have line numbers appended - .description - currently strips line numbers, although VSCode can handle it - - todo: [ ] returning object with PSPath but line numbers would be ideal - - [ ] already implemented in the Dev.Nin\Format-RipGrepResult() - future: - [ ] return VsCode filepath numbers, that are valid objects - [ ] should inputtype fileinfo return same value? - no, caller, like To->RelativePath() will test before passing to this, a low level, stable function - .example - PS> - @( - 'foo:bar:cat.PS1:345:4' - 'foo:bar:cat.PS1:345' - ) | ConvertFrom-NumberedFilepath - . - .outputs - [string | None] - .link - Dev.Nin\Format-RipGrepResult - - #> - [Alias('StripNumberedFilepaths')] - [CmdletBinding()] - param( - #piped in text/paths/etc - [AllowEmptyCollection()] - [AllowEmptyString()] - [AllowNull()] - [Parameter(Position = 0, ValueFromPipeline)] - [string]$Text, - - # toggles regex - [switch]$StripLastOnly +if ( $publicToExport ) { + $publicToExport.function += @( + 'ConvertTo-RelativePath' + ) + $publicToExport.alias += @( + 'To->RelativePatha' ) - - begin { - $Regex = @{ - StripLastNumberOnly = '(:\d+)$' - StripAllNumbers = '(:\d+){1,}$' - } - $RegexMode = $StriplastOnly ? $Regex.StripLastNumberOnly : $Regex.StripAllNumber - Write-Debug "Regex: '$RegexMode'" - } - process { - if ($null -eq $Text) { - return - } - $Text -replace $regex[$regexMode], '' - } - end { - } } -function Format-RelativePath { + +function ConvertTo-RelativePath { <# .synopsis relative paths, allows you to pipe to commands that expects raw text like 'fzf preview'. @@ -118,11 +67,11 @@ function Format-RelativePath { .link https://docs.microsoft.com/en-us/dotnet/api/system.io.path.getfullpath #> - [Alias('ConvertTo-RelativePath')] + [Alias('To->RelativePath')] [cmdletbinding()] param ( # Filepath - [Alias('PSPath', 'Path', 'To->RelativePath')] + [Alias('PSPath', 'Path')] [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [object[]]$InputObject, @@ -132,6 +81,7 @@ function Format-RelativePath { # $items = "$Env:UserProfile", "$Env:AppData", "$Env:LocalAppData" # | ForEach-Object tostring # , $items + # todo: these completions should be short looking alias names [Parameter(Position = 0)] [ArgumentCompletions( 'C:\Users\cppmo_000\SkyDrive\Documents\2021', @@ -164,37 +114,43 @@ function Format-RelativePath { $InputObject | ForEach-Object { + # if *everything* fails, return initial value $rawItem = $_ # maybe always strip ansi ? - if ($rawItem -is 'string') { - $parsedItem = $rawItem | Remove-AnsiEscape - } else { - $parsedItem = $rawItem - } - - $maybeNameList = @( - $parsedItem - $parsedItem -replace '(:\d+)$', '' - ) try { - $curItem = Get-Item $parsedItem -ea stop + if ($rawItem -is 'string') { + $parsedItem = $rawItem | Remove-AnsiEscape + } else { + $parsedItem = $rawItem + } + + $maybeNameList = @( + $parsedItem + $parsedItem -replace '(:\d+)$', '' + ) + try { + $curItem = Get-Item $parsedItem -ea stop + } catch { + Write-Error "Get-Item failed on: '$parsedItem', falling back to text" + $curItem = $parsedItem + } + + # if (! $LiteralPath) { + # $curItem = Get-Item $parsedItem + # } + if ($null -eq $curItem) { + Write-Error 'curItem: $null' -ea Stop #SilentlyContinue + return + } + if ($null -eq $curDir) { + Write-Error 'curDir: $null' -ea Stop #SilentlyContinue + return + } + + [System.IO.Path]::GetRelativePath( $curDir, $parsedItem ) } catch { - Write-Error "Get-Item failed on: '$parsedItem', falling back to text" - $curItem = $parsedItem - } - - # if (! $LiteralPath) { - # $curItem = Get-Item $parsedItem - # } - if ($null -eq $curItem) { - Write-Error 'curItem: $null' -ea Stop #SilentlyContinue - return - } - if ($null -eq $curDir) { - Write-Error 'curDir: $null' -ea Stop #SilentlyContinue - return + Write-Warning "Conversion failed on '$rawItem'. $_" + $rawItem } - - [System.IO.Path]::GetRelativePath( $curDir, $parsedItem ) } } end { @@ -219,3 +175,8 @@ function Format-RelativePath { # Pop-Location -StackName 'debugStack' # } + + +if (! $publicToExport) { + # ... +} \ No newline at end of file From 3c12e4fa1afd5bb591a3b00ba38a03c0a60fe561 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Sat, 27 Nov 2021 11:00:46 -0600 Subject: [PATCH 30/49] Renamed: ConvertTo-RelativePath --- public_autoloader/ConvertTo-RelativePath.ps1 | 12 +++++------ .../ConvertTo-RelativePath.tests.ps1 | 20 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) rename public/Format-RelativePath.tests.ps1 => public_autoloader/ConvertTo-RelativePath.tests.ps1 (80%) diff --git a/public_autoloader/ConvertTo-RelativePath.ps1 b/public_autoloader/ConvertTo-RelativePath.ps1 index 5f8ffd7..c4f1293 100644 --- a/public_autoloader/ConvertTo-RelativePath.ps1 +++ b/public_autoloader/ConvertTo-RelativePath.ps1 @@ -25,17 +25,17 @@ function ConvertTo-RelativePath { .example newestItem🔎 Code-Workspace💻 | StripAnsi | To->RelativePath | pipe->Peek .example - 🐒> ls . -Recurse *.json | Format-RelativePath + 🐒> ls . -Recurse *.json | ConvertTo-RelativePath .example 🐒> ls $env:APPDATA *code* -Depth 4 - | select -First 5 | Format-RelativePath -BasePath $env:APPDATA + | select -First 5 | ConvertTo-RelativePath -BasePath $env:APPDATA Code Code - Insiders vscode-mssql .example 🐒> ls $env:APPDATA *code* -Depth 4 - | select -First 5 | Format-RelativePath -BasePath $env:UserProfile + | select -First 5 | ConvertTo-RelativePath -BasePath $env:UserProfile AppData\Roaming\Code AppData\Roaming\Code - Insiders @@ -47,7 +47,7 @@ function ConvertTo-RelativePath { C:\Users\cppmo_000\.vscode\argv.json .example # use a specific base path - 🐒> ls -Force ~\.vscode | Format-RelativePath "$Env:USERPROFILE" + 🐒> ls -Force ~\.vscode | ConvertTo-RelativePath "$Env:USERPROFILE" .vscode\extensions .vscode\argv.json @@ -162,7 +162,7 @@ function ConvertTo-RelativePath { # Push-Location -StackName 'debugStack' 'C:\Users\cppmo_000\Documents\2020\powershell\MyModules_Github\Ninmonkey.Console\public' # $d = Get-Item . -# Format-RelativePath $d -Debug +# ConvertTo-RelativePath $d -Debug # $f1 = Get-Item "$PSScriptRoot\data\unicode_web_query.ps1" @@ -171,7 +171,7 @@ function ConvertTo-RelativePath { # '.\native_wrapper\' # ) -# $strList | Format-RelativePath +# $strList | ConvertTo-RelativePath # Pop-Location -StackName 'debugStack' # } diff --git a/public/Format-RelativePath.tests.ps1 b/public_autoloader/ConvertTo-RelativePath.tests.ps1 similarity index 80% rename from public/Format-RelativePath.tests.ps1 rename to public_autoloader/ConvertTo-RelativePath.tests.ps1 index 65b745b..f712808 100644 --- a/public/Format-RelativePath.tests.ps1 +++ b/public_autoloader/ConvertTo-RelativePath.tests.ps1 @@ -2,20 +2,20 @@ BeforeAll { Import-Module Ninmonkey.Console -Force } -Describe 'Format-RelativePath' { +Describe 'ConvertTo-RelativePath' { It 'from IO' -Pending { $true | Should -Be $false - + } It 'from fullname text' -Pending { $true | Should -Be $false } - + It 'from partial name text' -Pending { - + $true | Should -Be $false } - Describe 'Text Vs Object' { + Describe 'Text Vs Object' { It 'With Color' { { newestItem🔎 -ItemType Pwsh @@ -25,7 +25,7 @@ Describe 'Format-RelativePath' { } It 'As Object' { { - Get-ChildItem + Get-ChildItem | First 4 | To->RelativePath } | Should -Not -Throw @@ -35,16 +35,16 @@ Describe 'Format-RelativePath' { BeforeAll { $target = Get-Item $env:Nin_Dotfiles $relativeTo = Get-Item $env:USERPROFILE - $expectedText = 'SkyDrive\Documents\2021\dotfiles_git' + $expectedText = 'SkyDrive\Documents\2021\dotfiles_git' } It 'Baseline True Case' { $result = [io.path]::GetRelativePath($relativeTo, $target) $result | Should -Be $expectedText } - + It 'Test True' { - $target | Format-RelativePath -BasePath $relativeTo - | Should -Be $expectedText + $target | ConvertTo-RelativePath -BasePath $relativeTo + | Should -Be $expectedText } } } From 7e950442ca82f4bdf5673b314586281ed34462a1 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Thu, 2 Dec 2021 18:54:38 -0600 Subject: [PATCH 31/49] rename --- public_autoloader/Get-ObjectTypeHelp.ps1 | 18 ++++++++++-------- public_autoloader/Invoke-NinFormatter.ps1 | 17 ++++++++++------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/public_autoloader/Get-ObjectTypeHelp.ps1 b/public_autoloader/Get-ObjectTypeHelp.ps1 index 794fcc6..623231e 100644 --- a/public_autoloader/Get-ObjectTypeHelp.ps1 +++ b/public_autoloader/Get-ObjectTypeHelp.ps1 @@ -22,6 +22,8 @@ function Get-ObjectTypeHelp { [string | None] .link Ninmonkey.Console\Format-TypeName + .link + Ninmonkey.Console\Get-ObjectTypeHelp #> [Alias('HelpFromType')] @@ -37,14 +39,14 @@ function Get-ObjectTypeHelp { begin { # list of full type nam;es1 - $x + $x $NameList = [list[string]]::new() - $TemplateUrl = 'https://docs.microsoft.com/en-us/dotnet/api/{0}' + $TemplateUrl = 'https://docs.microsoft.com/en-us/dotnet/api/{0}' } process { if ( [string]::IsNullOrWhiteSpace($InputObject) ) { return - } + } # if generics cause problems, try another method if ($InputObject -is 'PSMethod') { $funcName = $InputObject.Name @@ -53,15 +55,15 @@ function Get-ObjectTypeHelp { > $InputObject.TypeNameOfValue System.Management.Automation.PSMethod - + > $InputObject.GeTType() | %{ $_.Namespace, $_.Name -join '.'} - + System.Management.Automation.PSMethod`1 > $InputObject.Name - + Round - + #> $maybeFullNameForUrl = $InputObject.GetType().Namespace, $InputObject.Name -join '.' # maybe full url: @@ -70,7 +72,7 @@ function Get-ObjectTypeHelp { $funcName | Write-Color yellow $InputObject.TypeNameOfValue | Write-Color orange $InputObject.GeTType() | ForEach-Object { $_.Namespace, $_.Name -join '.' } | Write-Color blue - ) | wi + ) | wi $NameList.add($maybeFullNameForUrl) return diff --git a/public_autoloader/Invoke-NinFormatter.ps1 b/public_autoloader/Invoke-NinFormatter.ps1 index cab56f0..a01c54a 100644 --- a/public_autoloader/Invoke-NinFormatter.ps1 +++ b/public_autoloader/Invoke-NinFormatter.ps1 @@ -7,6 +7,7 @@ $script:publicToExport.alias += @( 'Format.ScriptPs1🎨' ) +# todo: make it a hotkey, also make it indent function Invoke-NinFormatter { <# .synopsis @@ -14,7 +15,8 @@ function Invoke-NinFormatter { .description . .example - . + currently piped text must be one string, todo: just collect the whole pipe + PS> gc (gi .\input1.ps1) | str nl | Invoke-NinFormatter .notes future: allow piping from: [HistoryInfo] | [Microsoft.PowerShell.PSConsoleReadLine+HistoryItem] @@ -31,7 +33,7 @@ function Invoke-NinFormatter { ParameterSetName = 'FromPipeOrParam', Mandatory, Position = 0, ValueFromPipeline)] [ValidateNotNullOrEmpty()] - [string]$ScriptDefinition, + [string[]]$ScriptDefinition, # Formats Last Command in history # [Alias('FromLastCommand', 'PrevCommand', 'FromHistory')] @@ -49,7 +51,6 @@ function Invoke-NinFormatter { ParameterSetName = 'FromClipboard' )][switch]$Clipboard - ) begin { @@ -63,12 +64,13 @@ function Invoke-NinFormatter { # try { switch ($PSCmdlet.ParameterSetName) { 'FromPipeOrParam' { + $scriptContent = $ScriptDefinition | Join-String -sep "`n" } 'FromHistory' { - $ScriptDefinition = (Get-History -Count 1 | ForEach-Object CommandLine) + $scriptContent = (Get-History -Count 1 | ForEach-Object CommandLine) } 'FromClipboard' { - $ScriptDefinition = (Get-Clipboard) + $scriptContent = (Get-Clipboard) } default { @@ -78,7 +80,7 @@ function Invoke-NinFormatter { } $invokeFormatterSplat = @{ - ScriptDefinition = $ScriptDefinition + ScriptDefinition = $scriptContent # formatter requires path, while Invoke-ScriptAnalyzer doe Settings = try { (Get-Item -ea stop $__ninConfig.Config.PSScriptAnalyzerSettings)?.FullName @@ -106,5 +108,6 @@ function Invoke-NinFormatter { # $PSCmdlet.WriteError( $_ ) # } } - end {} + end { + } } From 5165c0220b76a56532f59d06e2f2cada3269b76d Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Thu, 2 Dec 2021 19:26:35 -0600 Subject: [PATCH 32/49] you may pipe code directly to Indent-NinFormat , and cleanup --- Ninmonkey.Console.psm1 | 2 +- public/PSReadLine/ExpandAliases.ps1 | 11 +- public/PSReadLine/IndentSelections_Jaykul.ps1 | 192 +++++++++--------- public_autoloader/Invoke-NinFormatter.ps1 | 49 +++-- ...0\237\226\245\357\270\217 .code-workspace" | 61 ++++++ 5 files changed, 202 insertions(+), 113 deletions(-) diff --git a/Ninmonkey.Console.psm1 b/Ninmonkey.Console.psm1 index c844e37..6af5b48 100644 --- a/Ninmonkey.Console.psm1 +++ b/Ninmonkey.Console.psm1 @@ -7,7 +7,7 @@ $PSDefaultParameterValues['Select-NinProperty:Out-Variable'] = 'SelProp' $PSDefaultParameterValues['Write-ConsoleLabel:fg'] = '7FB2C1' # $PSDefaultParameterValues['Write-Text:AsString'] = $true try { - Set-PSReadLineKeyHandler -Key 'f5' -Function ShowCommandHelp -ea Stop #SilentlyContinue + Set-PSReadLineKeyHandler -Key 'f12' -Function ShowCommandHelp -ea Stop #SilentlyContinue } catch { # catch [System.Management.Automation.ParameterBindingValidationException] { if ($_.ToString() -match 'Cannot validate argument on parameter ''Function''. The argument "ShowCommandHelp"') { diff --git a/public/PSReadLine/ExpandAliases.ps1 b/public/PSReadLine/ExpandAliases.ps1 index 06bb63a..f0acae7 100644 --- a/public/PSReadLine/ExpandAliases.ps1 +++ b/public/PSReadLine/ExpandAliases.ps1 @@ -2,10 +2,13 @@ using namespace System.Management.Automation using namespace System.Management.Automation.Language # This example will replace any aliases on the command line with the resolved commands. -Set-PSReadLineKeyHandler -Key 'Alt+%' ` - -BriefDescription ExpandAliases ` - -LongDescription 'Replace all aliases with the full command' ` - -ScriptBlock { +$splatKeys = @{ + Key = 'Alt+%' + BriefDescription = 'Expands aliases' + LongDescription = 'Replace all aliases with the full command' +} + +Set-PSReadLineKeyHandler @splatKeys -ScriptBlock { param($key, $arg) $ast = $null diff --git a/public/PSReadLine/IndentSelections_Jaykul.ps1 b/public/PSReadLine/IndentSelections_Jaykul.ps1 index 4ec189f..ef205f9 100644 --- a/public/PSReadLine/IndentSelections_Jaykul.ps1 +++ b/public/PSReadLine/IndentSelections_Jaykul.ps1 @@ -8,104 +8,112 @@ Like VS Code's hotkeys: Original from: #> +& { -# Hack in a [ReadLine] accelerator -$xlr8r = [psobject].assembly.gettype('System.Management.Automation.TypeAccelerators') -if ($xlr8r::AddReplace) { - $xlr8r::AddReplace('ReadLine', [Microsoft.PowerShell.PSConsoleReadLine]) -} -else { - $null = $xlr8r::Remove('ReadLine') - $xlr8r::Add('ReadLine', [Microsoft.PowerShell.PSConsoleReadLine]) -} + # Hack in a [ReadLine] accelerator + $xlr8r = [psobject].assembly.gettype('System.Management.Automation.TypeAccelerators') + if ($xlr8r::AddReplace) { + $xlr8r::AddReplace('ReadLine', [Microsoft.PowerShell.PSConsoleReadLine]) + } + else { + $null = $xlr8r::Remove('ReadLine') + $xlr8r::Add('ReadLine', [Microsoft.PowerShell.PSConsoleReadLine]) + } + + # Set-PSReadLineKeyHandler -Key 'Alt+(' ` + # -BriefDescription ParenthesizeSelection ` + # -LongDescription 'Put parenthesis around the selection or entire line and move the cursor to after the closing parenthesis' ` + # -ScriptBlock -# Set-PSReadLineKeyHandler -Key 'Alt+(' ` -# -BriefDescription ParenthesizeSelection ` -# -LongDescription 'Put parenthesis around the selection or entire line and move the cursor to after the closing parenthesis' ` -# -ScriptBlock - -# Now some key handlers -Set-PSReadLineKeyHandler 'Alt+]' ` - -BriefDescription 'Indent/Dedent Selected text' ` - -Description 'Indent/Dedent Selected text like VS Code ctrl+[ / ] ctrl+[' ` - -ScriptBlock { - param($key, $arg) - $start = $null - $length = $null - [ReadLine]::GetSelectionState([ref]$start, [ref]$length) - - $command = $null - $cursor = $null - [ReadLine]::GetBufferState([ref]$command, [ref]$cursor) - - # if there's no selection, these should be set to the cursor - if ($start -lt 0) { $start = $cursor; $length = 0 } - $end = $start + $length - # Write-Host "`e[s`e[0;0H`e[32mStart:$start End:$end Length:$Length `e[u" - - # pretend that entire lines are selected - if ($start -gt 0) { - $start = $command.SubString(0, $start).LastIndexOf("`n") + 1 + # Now some key handlers + $splatReadline = @{ + BriefDescription = 'Indent/Dedent Selected text' + Description = 'Indent/Dedent Selected text like VS Code ctrl+[ / ] ctrl+[' + Chord = 'Alt+]' } - $end = $end + $command.SubString($end).IndexOf("`n") - $length = $end - $start - # Write-Host "`e[s`e[2;0H`e[34mStart:$start End:$end Length:$Length `e[u" - - $lines = $command.SubString($start, $length) - $count = ($lines -split "`n").Count - # Write-Host "`e[s`e[3;0H`e[36m$lines`e[u" - # Write-Host "`e[s`e[2;0H`e[34mStart:$start End:$end Length:$Length Lines:$Count`e[u" - [ReadLine]::Replace($start, $length, ($lines -replace '(?m)^', ' ')) - [ReadLine]::SetCursorPosition($start) - [ReadLine]::SelectLine() - - if ($count -gt 1) { - while (--$Count) { - [ReadLine]::SelectForwardChar() - [ReadLine]::SelectLine() + + Set-PSReadLineKeyHandler @splatReadline -ScriptBlock { + param($key, $arg) + $start = $null + $length = $null + [ReadLine]::GetSelectionState([ref]$start, [ref]$length) + + $command = $null + $cursor = $null + [ReadLine]::GetBufferState([ref]$command, [ref]$cursor) + + # if there's no selection, these should be set to the cursor + if ($start -lt 0) { $start = $cursor; $length = 0 } + $end = $start + $length + # Write-Host "`e[s`e[0;0H`e[32mStart:$start End:$end Length:$Length `e[u" + + # pretend that entire lines are selected + if ($start -gt 0) { + $start = $command.SubString(0, $start).LastIndexOf("`n") + 1 + } + $end = $end + $command.SubString($end).IndexOf("`n") + $length = $end - $start + # Write-Host "`e[s`e[2;0H`e[34mStart:$start End:$end Length:$Length `e[u" + + $lines = $command.SubString($start, $length) + $count = ($lines -split "`n").Count + # Write-Host "`e[s`e[3;0H`e[36m$lines`e[u" + # Write-Host "`e[s`e[2;0H`e[34mStart:$start End:$end Length:$Length Lines:$Count`e[u" + [ReadLine]::Replace($start, $length, ($lines -replace '(?m)^', ' ')) + [ReadLine]::SetCursorPosition($start) + [ReadLine]::SelectLine() + + if ($count -gt 1) { + while (--$Count) { + [ReadLine]::SelectForwardChar() + [ReadLine]::SelectLine() + } } } -} -Set-PSReadLineKeyHandler 'Alt+[' ` - -BriefDescription 'Indent/Dedent Selected text' ` - -Description 'Indent/Dedent Selected text like VS Code ctrl+[/]' ` - -ScriptBlock { - param($key, $arg) - $start = $null - $length = $null - [ReadLine]::GetSelectionState([ref]$start, [ref]$length) - - $command = $null - $cursor = $null - [ReadLine]::GetBufferState([ref]$command, [ref]$cursor) - - # if there's no selection, these should be set to the cursor - if ($start -lt 0) { $start = $cursor; $length = 0 } - $end = $start + $length - # Write-Host "`e[s`e[0;0H`e[32mStart:$start End:$end Length:$Length `e[u" - - # pretend that entire lines are selected - if ($start -gt 0) { - $start = $command.SubString(0, $start).LastIndexOf("`n") + 1 + $splatReadline = @{ + BriefDescription = 'Indent/Dedent Selected text' + Description = 'Indent/Dedent Selected text like VS Code ctrl+[/]' + Chord = 'Alt+[' } - $end = $end + $command.SubString($end).IndexOf("`n") - $length = $end - $start - # Write-Host "`e[s`e[2;0H`e[34mStart:$start End:$end Length:$Length `e[u" - - $lines = $command.SubString($start, $length) - $count = ($lines -split "`n").Count - # Write-Host "`e[s`e[3;0H`e[36m$lines`e[u" - # Write-Host "`e[s`e[2;0H`e[34mStart:$start End:$end Length:$Length Lines:$Count`e[u" - - [ReadLine]::Replace($start, $length, ($lines -replace '(?m)^ ', '')) - [ReadLine]::SetCursorPosition($start) - [ReadLine]::SelectLine() - - if ($count -gt 1) { - while (--$Count) { - [ReadLine]::SelectForwardChar() - [ReadLine]::SelectLine() + + Set-PSReadLineKeyHandler @splatReadline -ScriptBlock { + param($key, $arg) + $start = $null + $length = $null + [ReadLine]::GetSelectionState([ref]$start, [ref]$length) + + $command = $null + $cursor = $null + [ReadLine]::GetBufferState([ref]$command, [ref]$cursor) + + # if there's no selection, these should be set to the cursor + if ($start -lt 0) { $start = $cursor; $length = 0 } + $end = $start + $length + # Write-Host "`e[s`e[0;0H`e[32mStart:$start End:$end Length:$Length `e[u" + + # pretend that entire lines are selected + if ($start -gt 0) { + $start = $command.SubString(0, $start).LastIndexOf("`n") + 1 + } + $end = $end + $command.SubString($end).IndexOf("`n") + $length = $end - $start + # Write-Host "`e[s`e[2;0H`e[34mStart:$start End:$end Length:$Length `e[u" + + $lines = $command.SubString($start, $length) + $count = ($lines -split "`n").Count + # Write-Host "`e[s`e[3;0H`e[36m$lines`e[u" + # Write-Host "`e[s`e[2;0H`e[34mStart:$start End:$end Length:$Length Lines:$Count`e[u" + + [ReadLine]::Replace($start, $length, ($lines -replace '(?m)^ ', '')) + [ReadLine]::SetCursorPosition($start) + [ReadLine]::SelectLine() + + if ($count -gt 1) { + while (--$Count) { + [ReadLine]::SelectForwardChar() + [ReadLine]::SelectLine() + } } } -} \ No newline at end of file +} diff --git a/public_autoloader/Invoke-NinFormatter.ps1 b/public_autoloader/Invoke-NinFormatter.ps1 index a01c54a..974a6a2 100644 --- a/public_autoloader/Invoke-NinFormatter.ps1 +++ b/public_autoloader/Invoke-NinFormatter.ps1 @@ -15,24 +15,28 @@ function Invoke-NinFormatter { .description . .example - currently piped text must be one string, todo: just collect the whole pipe - PS> gc (gi .\input1.ps1) | str nl | Invoke-NinFormatter + . .notes future: allow piping from: [HistoryInfo] | [Microsoft.PowerShell.PSConsoleReadLine+HistoryItem] + .link + PSScriptAnalyzer\Invoke-Formatter .outputs - [string] #> [alias('FormatScript🎨')] [CmdletBinding(PositionalBinding = $false, DefaultParameterSetName = 'FromPipeOrParam')] param( + + # pipe script contents + # Must allow null for piping split text [Alias('InputObject')] + [AllowEmptyString()] + [AllowNull()] [Parameter( ParameterSetName = 'FromPipeOrParam', Mandatory, Position = 0, ValueFromPipeline)] - [ValidateNotNullOrEmpty()] [string[]]$ScriptDefinition, # Formats Last Command in history @@ -57,14 +61,10 @@ function Invoke-NinFormatter { if ($LastCommand -and $Clipboard) { Write-Error 'Choose one of: [ -LastCommand | -Clipboard ]' } - Write-Debug $ScriptDefinition - } - process { - # try { switch ($PSCmdlet.ParameterSetName) { 'FromPipeOrParam' { - $scriptContent = $ScriptDefinition | Join-String -sep "`n" + $scriptContent = '' } 'FromHistory' { $scriptContent = (Get-History -Count 1 | ForEach-Object CommandLine) @@ -79,8 +79,31 @@ function Invoke-NinFormatter { } } + } + process { + # try { + switch ($PSCmdlet.ParameterSetName) { + 'FromPipeOrParam' { + foreach ($line in $ScriptDefinition) { + $scriptContent += "`n$line" + } + } + 'FromHistory' { + break + } + 'FromClipboard' { + break + } + + default { + Write-Error -ea stop -Category NotImplemented -Message 'Unhandled ParameterSet' -TargetObject $PSCmdlet.ParameterSetName + # throw "Unhandled ParameterSet: $($PSCmdlet.ParameterSetName)" + } + } + } + end { $invokeFormatterSplat = @{ - ScriptDefinition = $scriptContent + ScriptDefinition = $scriptContent -join "`n" # formatter requires path, while Invoke-ScriptAnalyzer doe Settings = try { (Get-Item -ea stop $__ninConfig.Config.PSScriptAnalyzerSettings)?.FullName @@ -103,11 +126,5 @@ function Invoke-NinFormatter { # try {} Invoke-Formatter @invokeFormatterSplat # -Range - # } - # catch { - # $PSCmdlet.WriteError( $_ ) - # } - } - end { } } diff --git "a/\360\237\220\222 Ninmonkey.Console\360\237\226\245\357\270\217 .code-workspace" "b/\360\237\220\222 Ninmonkey.Console\360\237\226\245\357\270\217 .code-workspace" index 53a5e69..0007aec 100644 --- "a/\360\237\220\222 Ninmonkey.Console\360\237\226\245\357\270\217 .code-workspace" +++ "b/\360\237\220\222 Ninmonkey.Console\360\237\226\245\357\270\217 .code-workspace" @@ -65,6 +65,67 @@ "MD025": { "front_matter_title": "" } + }, + "workbench.colorCustomizations": { + "errorLens.warningMessageBackground": "#fff00005", + "errorLens.warningBackground": "#ff942f10", + "errorLens.errorForeground": "#f77777", + "errorLens.errorMessageBackground": "#e4545405", + "errorLens.errorBackground": "#e454540a", + "errorLens.warningForeground": "#fa973a70", + "errorLens.infoForeground": "#ea00ff", + "minimap.findMatchHighlight": "#1ef029", + "minimap.warningHighlight": "#ee6f8a6b", + "minimap.foregroundOpacity": "#ff000081", + "minimap.selectionHighlight": "#264f78", + "minimap.selectionOccurrenceHighlight": "#feef2e", + "minimap.unicodeHighlight": "#d18616", + "minimapGutter.addedBackground": "#587c0c", + "minimapGutter.deletedBackground": "#94151b", + "minimapGutter.modifiedBackground": "#0c7d9d", + "minimapSlider.activeBackground": "#bfbfbf33", + "minimapSlider.background": "#79797933", + "minimapSlider.hoverBackground": "#64646459", + "editorBracketMatch.border": "#888888", + "editorLineNumber.foreground": "#4e4e4ea1", + "editorLineNumber.activeForeground": "#929292", + "list.hoverBackground": "#ff00ff18", + "peekView.border": "#ff00ff", + "tab.lastPinnedBorder": "#2472c8", + "terminal.ansiBlack": "#000000", + "terminal.ansiBlue": "#2472c8", + "terminal.ansiBrightBlack": "#666666", + "terminal.ansiBrightBlue": "#569cd6", + "terminal.ansiBrightCyan": "#9cdcfe", + "terminal.ansiBrightGreen": "#b5cea8", + "terminal.ansiBrightMagenta": "#d38bcd", + "terminal.ansiBrightRed": "#f14c4c", + "terminal.ansiBrightWhite": "#e5e5e5", + "terminal.ansiBrightYellow": "#ecec6a", + "terminal.ansiCyan": "#11a8cd", + "terminal.ansiGreen": "#6a9955", + "terminal.ansiMagenta": "#C586C0", + "terminal.ansiRed": "#cd3131", + "terminal.ansiWhite": "#e5e5e5", + "terminal.ansiYellow": "#CE9178", + "terminal.background": "#1E1E1E", + "terminal.foreground": "#D4D4D4", + "editor.lineHighlightBackground": "#1073cf2d", + "editor.lineHighlightBorder": "#9fced11f", + "editorBracketHighlight.foreground1": "#ffd780", + "editorBracketHighlight.foreground2": "#da70d686", + "editorBracketHighlight.foreground3": "#179f80", + "editorBracketHighlight.foreground4": "#ffffff80", + "testing.message.error.decorationForeground": "#ff646440", + "testing.message.error.lineBackground": "#e4545405", + "testing.peekBorder": "#F14C4C", + "testing.peekHeaderBackground": "#F14C4C1a", + "testing.iconFailed": "#cd3131", + "testing.iconPassed": "#6a9955", + "testing.iconQueued": "#CCA700", + "testing.iconSkipped": "#ff00ff", + "testing.iconErrored": "#bb600c", + "testing.iconUnset": "#848484" } }, "launch": { From b492c3a08578e00ff840f687f11a4c041cb8ca48 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Thu, 2 Dec 2021 19:38:06 -0600 Subject: [PATCH 33/49] new dotnet completer --- Ninmonkey.Console.psd1 | 2 +- Ninmonkey.Console.psm1 | 3 +++ public/PSReadLine/ParenthesizeSelection.ps1 | 24 +++++++++++++++------ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Ninmonkey.Console.psd1 b/Ninmonkey.Console.psd1 index 161e0f1..894119c 100644 --- a/Ninmonkey.Console.psd1 +++ b/Ninmonkey.Console.psd1 @@ -11,7 +11,7 @@ RootModule = 'Ninmonkey.Console.psm1' # Version number of this module. - ModuleVersion = '0.1.4' + ModuleVersion = '0.1.5' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/Ninmonkey.Console.psm1 b/Ninmonkey.Console.psm1 index 6af5b48..06d0ee2 100644 --- a/Ninmonkey.Console.psm1 +++ b/Ninmonkey.Console.psm1 @@ -468,4 +468,7 @@ if ( ($__ninConfig)?.HackSkipLoadCompleters ) { Build-CustomCompleter @curSplat Import-CustomCompleter @curSplat Import-GeneratedCompleter @curSplat + + # this version works, run it last. + . (Get-Item (Join-Path $PSScriptRoot '/public/PSReadLine/native-dotnet-completer.ps1')) } diff --git a/public/PSReadLine/ParenthesizeSelection.ps1 b/public/PSReadLine/ParenthesizeSelection.ps1 index 5cb719f..80ce23b 100644 --- a/public/PSReadLine/ParenthesizeSelection.ps1 +++ b/public/PSReadLine/ParenthesizeSelection.ps1 @@ -12,17 +12,29 @@ Set-PSReadLineKeyHandler -Key 'Alt+(' ` $selectionStart = $null $selectionLength = $null - [Microsoft.PowerShell.PSConsoleReadLine]::GetSelectionState([ref]$selectionStart, [ref]$selectionLength) + [Microsoft.PowerShell.PSConsoleReadLine]::GetSelectionState( + [ref]$selectionStart, [ref]$selectionLength + ) $line = $null $cursor = $null - [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) + [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState( + [ref]$line, [ref]$cursor + ) + if ($selectionStart -ne -1) { - [Microsoft.PowerShell.PSConsoleReadLine]::Replace($selectionStart, $selectionLength, '(' + $line.SubString($selectionStart, $selectionLength) + ')') - [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($selectionStart + $selectionLength + 2) + [Microsoft.PowerShell.PSConsoleReadLine]::Replace( + $selectionStart, $selectionLength, + '(' + $line.SubString($selectionStart, $selectionLength) + ')' + ) + [Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition( + $selectionStart + $selectionLength + 2 + ) } else { - [Microsoft.PowerShell.PSConsoleReadLine]::Replace(0, $line.Length, '(' + $line + ')') + [Microsoft.PowerShell.PSConsoleReadLine]::Replace( + 0, $line.Length, '(' + $line + ')' + ) [Microsoft.PowerShell.PSConsoleReadLine]::EndOfLine() } -} \ No newline at end of file +} From 96f45ba01bad4a65e64facca4759509ceb106f5a Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Fri, 3 Dec 2021 10:14:39 -0600 Subject: [PATCH 34/49] New: Test-IsSubDirectory --- public/PSReadLine/native-dotnet-completer.ps1 | 10 ++++ public_autoloader/Get-CommandSummary.ps1 | 15 +++-- public_autoloader/Test-IsDirectory.ps1 | 10 +++- public_autoloader/Test-IsDirectory.tests.ps1 | 2 +- .../Test-IsSubDirectory.tests.ps1 | 16 ++++++ public_autoloader/TestIsSubDirectory.ps1 | 57 +++++++++++++++++++ 6 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 public/PSReadLine/native-dotnet-completer.ps1 create mode 100644 public_autoloader/Test-IsSubDirectory.tests.ps1 create mode 100644 public_autoloader/TestIsSubDirectory.ps1 diff --git a/public/PSReadLine/native-dotnet-completer.ps1 b/public/PSReadLine/native-dotnet-completer.ps1 new file mode 100644 index 0000000..dd13db2 --- /dev/null +++ b/public/PSReadLine/native-dotnet-completer.ps1 @@ -0,0 +1,10 @@ +<# from the docs #> +# warning: not working correctly from auto import +# manual pasting does. +$scriptblock = { + param($wordToComplete, $commandAst, $cursorPosition) + dotnet complete --position $cursorPosition $commandAst.ToString() | ForEach-Object { + [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) + } +} +Register-ArgumentCompleter -Native -CommandName dotnet -ScriptBlock $scriptblock diff --git a/public_autoloader/Get-CommandSummary.ps1 b/public_autoloader/Get-CommandSummary.ps1 index e6d18a4..da64ef9 100644 --- a/public_autoloader/Get-CommandSummary.ps1 +++ b/public_autoloader/Get-CommandSummary.ps1 @@ -75,15 +75,15 @@ function Get-CommandSummary { if ($ResolvedCommand.Source -match $regex) { $AnyMatch = $true; break; - } + } } if (! $ModuleName) { $AnyMatch = $true } if (! $AnyMatch) { - return + return } - + if ($false) { [pscustomobject]$cmdSummary return @@ -126,15 +126,14 @@ function Get-CommandSummary { Write-Warning 'Found this old script, still super rough. will dump most of it.' } } -if ($false -and $script:publicToExport) { +if ($false -and (! $script:publicToExport)) { # working example - $f = Get-Module dev.nin | ForEach-Object ExportedCommands | ForEach-Object Keys | Select-Object -First 20 | Get-CommandSummary -ea ignore -ModuleName dev.nin - + $f | ForEach-Object DescStr - - return + + return if ($false -and $EnableDebugInline) { Get-CommandSummary dev-Printtabletemplate -ea Continue -Verbose -Debug -infa Continue diff --git a/public_autoloader/Test-IsDirectory.ps1 b/public_autoloader/Test-IsDirectory.ps1 index 819dcda..3aef9d2 100644 --- a/public_autoloader/Test-IsDirectory.ps1 +++ b/public_autoloader/Test-IsDirectory.ps1 @@ -7,7 +7,6 @@ $script:publicToExport.alias += @( ) - function Test-IsContainer { <#c .Synopsis @@ -23,6 +22,8 @@ function Test-IsContainer { $extraArgs = ($item = Get-Item $Path -ea 0) -and $item.PSIsContainer | ?? { '' } : { '-r' } & $code $pathList $extraArgs } + .link + Ninmonkey.Console\Test-IsSubDirectory #> [Alias('Test-IsDirectory')] # probably a better name [outputtype('System.Boolean')] @@ -40,7 +41,8 @@ function Test-IsContainer { #> try { $item = Get-Item $Path -ea stop - } catch { + } + catch { # definitely didn't exist Write-Debug 'GI failed' $false; return @@ -54,6 +56,8 @@ function Test-IsContainer { } $hasAttribute = ($item.Attributes -band [IO.FileAttributes]::Directory) -eq [IO.FileAttributes]::Directory + # you could also do -ne 0 at the end to achieve the same thing + $hasAttribute = ($item.Attributes -band [IO.FileAttributes]::Directory) -ne 0 $isType -or $hasAttribute -or ([bool]$Item.PSIsContainer) # Wait-Debugger @@ -64,7 +68,7 @@ function Test-IsContainer { } -if (! $experimentToExport) { +if ( $false -and (! $publicToExport)) { # ... Get-Item . | Test-IsDirectory | Should -Be $True Get-Item fg:\ | Test-IsDirectory | Should -Be $True diff --git a/public_autoloader/Test-IsDirectory.tests.ps1 b/public_autoloader/Test-IsDirectory.tests.ps1 index 83b0480..d3b5726 100644 --- a/public_autoloader/Test-IsDirectory.tests.ps1 +++ b/public_autoloader/Test-IsDirectory.tests.ps1 @@ -32,4 +32,4 @@ Describe 'Test-IsDirectory' { ($fileObj, '.', 'c:\') | Test-IsDirectory | Should -Be ($False, $True, $True) } -} \ No newline at end of file +} diff --git a/public_autoloader/Test-IsSubDirectory.tests.ps1 b/public_autoloader/Test-IsSubDirectory.tests.ps1 new file mode 100644 index 0000000..d341284 --- /dev/null +++ b/public_autoloader/Test-IsSubDirectory.tests.ps1 @@ -0,0 +1,16 @@ +BeforeAll { + Import-Module Ninmonkey.Console -Force +} + +Describe 'Test-IsSubDirectory' { + It ' of is ' -ForEach @( + @{ + Child = "$env:userprofile" + Parent = 'c:\users' + Expected = $true + } + ) { + Test-IsSubDirectory $Child -Parent $Parent + | Should -Be $Expected + } +} diff --git a/public_autoloader/TestIsSubDirectory.ps1 b/public_autoloader/TestIsSubDirectory.ps1 new file mode 100644 index 0000000..4221ae6 --- /dev/null +++ b/public_autoloader/TestIsSubDirectory.ps1 @@ -0,0 +1,57 @@ +#Requires -Version 7 +$script:publicToExport.function += @( + 'Test-IsSubDirectory' +) +$script:publicToExport.alias += @( + +) + + +function Test-IsSubDirectory { + <# + .synopsis + Is X a subdir of Y? + .description + .over-engineered, I was curious if other providers would still match + .notes + todo: + assert args are actually containers + .example + Test-IsSubdirectory 'c:\' (gi .) + Test-IsSubdirectory '~' (gi .) + .link + Ninmonkey.Console\Test-IsContainer + #> + [outputtype([system.boolean])] + [CmdletBinding()] + param( + [alias('Directory')] + [Parameter(Mandatory, Position = 0)] + [object]$Child, + + [Parameter(Mandatory, Position = 1)] + [object]$Parent + ) + + begin {} + process { + try { + $Short = Get-Item -ea stop $Child + $Long = Get-Item -ea stop $Parent + Test-IsDirectory $short + Test-IsDirectory $long + } + catch { + throw "InvalidArguments: $_" + } + @( + $long -like "${short}*" + $long -match (ReLit $short) + ) | Where-Object { $_ -eq $true } + + $false; return + } + end { + + } +} From 622a79e046d47b3a4c50e6e078697867107011b6 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Fri, 3 Dec 2021 15:09:48 -0600 Subject: [PATCH 35/49] Invoke-NinFormat works on files New: Test-IsSubDirectory --- Ninmonkey.Console.psd1 | 12 ++--- public_autoloader/Invoke-NinFormatter.ps1 | 56 +++++++++++++++++-- public_autoloader/Test-IsDirectory.ps1 | 16 +++--- public_autoloader/Test-IsSubDirectory.ps1 | 66 +++++++++++++++++++++++ public_autoloader/TestIsSubDirectory.ps1 | 57 -------------------- 5 files changed, 130 insertions(+), 77 deletions(-) create mode 100644 public_autoloader/Test-IsSubDirectory.ps1 delete mode 100644 public_autoloader/TestIsSubDirectory.ps1 diff --git a/Ninmonkey.Console.psd1 b/Ninmonkey.Console.psd1 index 894119c..4a3d916 100644 --- a/Ninmonkey.Console.psd1 +++ b/Ninmonkey.Console.psd1 @@ -1,17 +1,10 @@ -# -# Module manifest for module 'Ninmonkey.Console' -# -# Generated by: cppmo_000 -# -# Generated on: 7/10/2021 - -@{ +@{ # Script module or binary module file associated with this manifest. RootModule = 'Ninmonkey.Console.psm1' # Version number of this module. - ModuleVersion = '0.1.5' + ModuleVersion = '0.1.6' # Supported PSEditions # CompatiblePSEditions = @() @@ -54,6 +47,7 @@ 'Pansies' 'ClassExplorer' 'Utility' # hard dependency for now + 'functional' ) # Assemblies that must be loaded prior to importing this module diff --git a/public_autoloader/Invoke-NinFormatter.ps1 b/public_autoloader/Invoke-NinFormatter.ps1 index 974a6a2..8f12158 100644 --- a/public_autoloader/Invoke-NinFormatter.ps1 +++ b/public_autoloader/Invoke-NinFormatter.ps1 @@ -15,7 +15,8 @@ function Invoke-NinFormatter { .description . .example - . + # formats and saves file + PS> Invoke-NinFormatter -Path 'c:\foo\bar.ps1' -WriteBack .notes future: allow piping from: [HistoryInfo] | [Microsoft.PowerShell.PSConsoleReadLine+HistoryItem] @@ -26,7 +27,11 @@ function Invoke-NinFormatter { #> [alias('FormatScript🎨')] - [CmdletBinding(PositionalBinding = $false, DefaultParameterSetName = 'FromPipeOrParam')] + [CmdletBinding( + PositionalBinding = $false, DefaultParameterSetName = 'FromPipeOrParam', + + SupportsShouldProcess, ConfirmImpact = 'high' + )] param( # pipe script contents @@ -39,6 +44,21 @@ function Invoke-NinFormatter { Mandatory, Position = 0, ValueFromPipeline)] [string[]]$ScriptDefinition, + # modify file in place + [alias('InputFile')] + [Parameter( + Mandatory, ParameterSetName = 'FromFile' + )] + [string]$Path, + + # What's the current config? + [Parameter(ParameterSetName = 'GetConfig')] + [switch]$GetConfig, + + # replace original file with formatting + [Parameter(ParameterSetName = 'FromFile')] + [switch]$WriteBack, + # Formats Last Command in history # [Alias('FromLastCommand', 'PrevCommand', 'FromHistory')] [Alias('PrevCommand')] @@ -72,6 +92,12 @@ function Invoke-NinFormatter { 'FromClipboard' { $scriptContent = (Get-Clipboard) } + 'FromFile' { + $scriptContent = Get-Content ( Get-Item $Path -ea stop) + } + 'GetConfig' { + break + } default { Write-Error -ea stop -Category NotImplemented -Message 'Unhandled ParameterSet' -TargetObject $PSCmdlet.ParameterSetName @@ -88,12 +114,18 @@ function Invoke-NinFormatter { $scriptContent += "`n$line" } } + 'GetConfig' { + break + } 'FromHistory' { break } 'FromClipboard' { break } + 'FromFile' { + break + } default { Write-Error -ea stop -Category NotImplemented -Message 'Unhandled ParameterSet' -TargetObject $PSCmdlet.ParameterSetName @@ -106,7 +138,7 @@ function Invoke-NinFormatter { ScriptDefinition = $scriptContent -join "`n" # formatter requires path, while Invoke-ScriptAnalyzer doe Settings = try { - (Get-Item -ea stop $__ninConfig.Config.PSScriptAnalyzerSettings)?.FullName +(Get-Item -ea stop $__ninConfig.Config.PSScriptAnalyzerSettings)?.FullName } catch { Write-Error -m ( @@ -120,11 +152,29 @@ function Invoke-NinFormatter { 'using: $__ninConfig.Config.PSScriptAnalyzerSettings = "{0}"' -f @( $__ninConfig.Config.PSScriptAnalyzerSettings ) | Write-Debug + + if ($GetConfig) { + [PSCustomObject]@{ + Settings = Get-Content $invokeFormatterSplat.Settings + Path = $invokeFormatterSplat.Settings + EnvVarPath = $__ninConfig.Config.PSScriptAnalyzerSettings + } + + # Wait-Debugger + return + } + $invokeFormatterSplat | Format-dict | Write-Debug # try {} + if ($WriteBack) { + if ($PSCmdlet.ShouldProcess("$($Path.Name)", 'Replace')) { + Invoke-Formatter @invokeFormatterSplat | Set-Content $Path + return + } + } Invoke-Formatter @invokeFormatterSplat # -Range } } diff --git a/public_autoloader/Test-IsDirectory.ps1 b/public_autoloader/Test-IsDirectory.ps1 index 3aef9d2..bf0f648 100644 --- a/public_autoloader/Test-IsDirectory.ps1 +++ b/public_autoloader/Test-IsDirectory.ps1 @@ -49,18 +49,18 @@ function Test-IsContainer { } $isType = $Item -is 'System.IO.DirectoryInfo' $meta = @{ - IsDirInfo = $isDir - HasAttr = $hasAttribute - IsContainer = [bool]$Item.PSIsContainer - + IsDirInfo = $isDir + HasAttr = $hasAttribute + IsContainer = [bool]$Item.PSIsContainer + PathTypeContainer = Test-Path -PathType Container -Path $Path } + $meta | Format-Table | Out-String | Write-Debug - $hasAttribute = ($item.Attributes -band [IO.FileAttributes]::Directory) -eq [IO.FileAttributes]::Directory + # $hasAttribute = ($item.Attributes -band [IO.FileAttributes]::Directory) -eq [IO.FileAttributes]::Directory # you could also do -ne 0 at the end to achieve the same thing $hasAttribute = ($item.Attributes -band [IO.FileAttributes]::Directory) -ne 0 - $isType -or $hasAttribute -or ([bool]$Item.PSIsContainer) - - # Wait-Debugger + $isContainer = Test-Path -PathType Container -Path $Path + $isType -or $hasAttribute -or ([bool]$Item.PSIsContainer) -or $isContainer return } end { diff --git a/public_autoloader/Test-IsSubDirectory.ps1 b/public_autoloader/Test-IsSubDirectory.ps1 new file mode 100644 index 0000000..56427cc --- /dev/null +++ b/public_autoloader/Test-IsSubDirectory.ps1 @@ -0,0 +1,66 @@ +#Requires -Version 7 +$script:publicToExport.function += @( + 'Test-IsSubDirectory' +) +$script:publicToExport.alias += @( + +) + + +function Test-IsSubDirectory { + <# + .synopsis + Is X a subdir of Y? + .description + .over-engineered, I was curious if other providers would still work + + .notes + todo: + - [ ] [switch] Allow Non-Existing paths + - [ ] another parameter set, value from pipeline would be the parent?child? + .example + Test-IsSubdirectory 'c:\' (gi .) + Test-IsSubdirectory '~' (gi .) + .link + Ninmonkey.Console\Test-IsContainer + #> + [outputtype([system.boolean])] + [CmdletBinding()] + param( + # child to test, can be text or file + [alias('Directory')] + [Parameter(Mandatory, Position = 0)] + [object]$Child, + + # potential parent + [Parameter(Mandatory, Position = 1)] + [object]$Parent + ) + + begin {} + process { + # try { + try { + $conditions = @( + $Short = Get-Item -ea ignore $Child + $Long = Get-Item -ea ignore $Parent + Test-IsDirectory $short + Test-IsDirectory $long + # silly compare, but it works. + ( $long -like "${short}*") -or ( + $long -match ([regex]::Escape( $short )) + ) + ) | Where-Object { $_ } + + } catch { + # Write-Error -ea continue -Category 'InvalidArgument' -Message "Bad directory: $_" + Write-Debug $_ + $false; return + } + + [bool](Test-All $Conditions) + } + end { + + } +} diff --git a/public_autoloader/TestIsSubDirectory.ps1 b/public_autoloader/TestIsSubDirectory.ps1 deleted file mode 100644 index 4221ae6..0000000 --- a/public_autoloader/TestIsSubDirectory.ps1 +++ /dev/null @@ -1,57 +0,0 @@ -#Requires -Version 7 -$script:publicToExport.function += @( - 'Test-IsSubDirectory' -) -$script:publicToExport.alias += @( - -) - - -function Test-IsSubDirectory { - <# - .synopsis - Is X a subdir of Y? - .description - .over-engineered, I was curious if other providers would still match - .notes - todo: - assert args are actually containers - .example - Test-IsSubdirectory 'c:\' (gi .) - Test-IsSubdirectory '~' (gi .) - .link - Ninmonkey.Console\Test-IsContainer - #> - [outputtype([system.boolean])] - [CmdletBinding()] - param( - [alias('Directory')] - [Parameter(Mandatory, Position = 0)] - [object]$Child, - - [Parameter(Mandatory, Position = 1)] - [object]$Parent - ) - - begin {} - process { - try { - $Short = Get-Item -ea stop $Child - $Long = Get-Item -ea stop $Parent - Test-IsDirectory $short - Test-IsDirectory $long - } - catch { - throw "InvalidArguments: $_" - } - @( - $long -like "${short}*" - $long -match (ReLit $short) - ) | Where-Object { $_ -eq $true } - - $false; return - } - end { - - } -} From 1c2d2487df19d7ebe933f236a6b6063a4276affb Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Tue, 7 Dec 2021 19:51:11 -0600 Subject: [PATCH 36/49] New: To->Base64, From-Base64, with tests --- public/ConvertTo-Base64String.ps1 | 2 + .../ConvertFrom-Base64String.ps1 | 74 +++++++++++++++++++ .../ConvertTo-Base64String.tests.ps1 | 36 +++++++++ 3 files changed, 112 insertions(+) create mode 100644 public_autoloader/ConvertFrom-Base64String.ps1 create mode 100644 public_autoloader/ConvertTo-Base64String.tests.ps1 diff --git a/public/ConvertTo-Base64String.ps1 b/public/ConvertTo-Base64String.ps1 index f4ffc4d..af3a7c5 100644 --- a/public/ConvertTo-Base64String.ps1 +++ b/public/ConvertTo-Base64String.ps1 @@ -12,6 +12,8 @@ function ConvertTo-Base64String { .example # For more see: <./test/public/ConvertTo-Base64String.tests.ps1> + .link + Utility\ConvertTo-Base64String #> [Alias('Base64')] diff --git a/public_autoloader/ConvertFrom-Base64String.ps1 b/public_autoloader/ConvertFrom-Base64String.ps1 new file mode 100644 index 0000000..7986937 --- /dev/null +++ b/public_autoloader/ConvertFrom-Base64String.ps1 @@ -0,0 +1,74 @@ +#Requires -Version 7 +using namespace System.Text + +$script:publicToExport.function += @( + 'ConvertFrom-Base64String' +) +$script:publicToExport.alias += @( + 'From->Base64' +) + + + +# todo +function ConvertFrom-Base64String { + <# + .synopsis + originally from: + .notes + currently the same, separate same. separate for dependency clarity + .example + # For more see: + <./test/public/ConvertFrom-Base64String.tests.ps1> + .link + Utility\ConvertFrom-Base64String + #> + [Alias('From->Base64')] + [OutputType([System.String])] + [CmdletBinding(PositionalBinding = $false)] + param( + [Parameter(ValueFromPipeline, Position = 0)] + [AllowEmptyString()] + [AllowNull()] + [string] $InputObject, + + [Parameter()] + [ArgumentCompleter([EncodingArgumentCompleter])] + [EncodingArgumentConverter()] + [Encoding] $Encoding + ) + begin { + if ($PSBoundParameters.ContainsKey((nameof { $Encoding }))) { + $userEncoding = $Encoding + return + } + + $userEncoding = [System.Text.Encoding]::UTF8 + #used to be: [Encoding]::Unicode # ut8 + } + process { + if ([string]::IsNullOrEmpty($InputObject)) { + return + } + + $decoded_bytes = [convert]::FromBase64String($InputObject) + return $userEncoding.GetString( $decoded_bytes ) + return + + # see: $userEncoding.GetString | fm * -Force | Get-Parameter -ea Ignore | ft -AutoSize + + $byteStr = [convert]::FromBase64String($b64) + [System.Text.UTF8Encoding]::UTF8.GetString( $byteStr ) + $userEncoding.GetString( + <# bytes: #> $byteStr) + + $userEncoding.GetString( + $InputObject + ) + + return + + + return [convert]::ToBase64String($userEncoding.GetBytes($InputObject)) + } +} diff --git a/public_autoloader/ConvertTo-Base64String.tests.ps1 b/public_autoloader/ConvertTo-Base64String.tests.ps1 new file mode 100644 index 0000000..58f8e11 --- /dev/null +++ b/public_autoloader/ConvertTo-Base64String.tests.ps1 @@ -0,0 +1,36 @@ +BeforeAll { + Import-Module Ninmonkey.Console -Force +} + +Describe 'ConvertToAndFrom-Base64String' { + Describe 'Round Trip' { + BeforeAll { + $original_string = @' + 0..4 + | Str csv sep ' ' + + h1 'someheader' +'@ + } + It 'utf8' { + + #'future' add non-utf8 enocdings as tests + $b64_str = $original_string | To->Base64 -Encoding utf8 + $final_string = $b64_str | From->Base64 -encoding Utf8 + $final_string | Should -Be $original_string -Because 'round trip of encode->decode' + } + It 'Utf16LE' { + $original_string = @' + 0..4 + | Str csv sep ' ' + + h1 'someheader' +'@ + $b64_str = $original_string | To->Base64 -Encoding Unicode + $final_string = $b64_str | From->Base64 -encoding Unicode + $final_string | Should -Be $original_string -Because 'round trip of encode->decode' + + } + + } +} From a4a20c71fc4aea7181835e16acfe35fd37301eb5 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Mon, 27 Dec 2021 10:40:24 -0600 Subject: [PATCH 37/49] Update ConvertTo-RelativePath.ps1 --- public_autoloader/ConvertTo-RelativePath.ps1 | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/public_autoloader/ConvertTo-RelativePath.ps1 b/public_autoloader/ConvertTo-RelativePath.ps1 index c4f1293..4cfa9a6 100644 --- a/public_autoloader/ConvertTo-RelativePath.ps1 +++ b/public_autoloader/ConvertTo-RelativePath.ps1 @@ -112,7 +112,6 @@ function ConvertTo-RelativePath { ripgrep and/or grep have file line numbers at the start, or end, depending on mode #> - $InputObject | ForEach-Object { # if *everything* fails, return initial value $rawItem = $_ # maybe always strip ansi ? @@ -130,19 +129,21 @@ function ConvertTo-RelativePath { try { $curItem = Get-Item $parsedItem -ea stop } catch { - Write-Error "Get-Item failed on: '$parsedItem', falling back to text" + # Write-Error "Get-Item failed on: '$parsedItem', falling back to text" + Write-Debug "Get-Item failed on: '$parsedItem', falling back to text" $curItem = $parsedItem } # if (! $LiteralPath) { # $curItem = Get-Item $parsedItem # } + # h1 'end of rel path' | Write-Host if ($null -eq $curItem) { - Write-Error 'curItem: $null' -ea Stop #SilentlyContinue + Write-Debug 'curItem: $null' -ea Stop #SilentlyContinue return } if ($null -eq $curDir) { - Write-Error 'curDir: $null' -ea Stop #SilentlyContinue + Write-Debug 'curDir: $null' -ea Stop #SilentlyContinue return } @@ -152,6 +153,7 @@ function ConvertTo-RelativePath { $rawItem } } + } end { } @@ -179,4 +181,4 @@ function ConvertTo-RelativePath { if (! $publicToExport) { # ... -} \ No newline at end of file +} From f3497e9dff39d5b7681c9fa07f77e57fadd6d757 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Mon, 27 Dec 2021 10:55:03 -0600 Subject: [PATCH 38/49] New Command: Show-XmlPreview --- public_autoloader/Show-XmlPreview.ps1 | 80 +++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 public_autoloader/Show-XmlPreview.ps1 diff --git a/public_autoloader/Show-XmlPreview.ps1 b/public_autoloader/Show-XmlPreview.ps1 new file mode 100644 index 0000000..9c9b8a8 --- /dev/null +++ b/public_autoloader/Show-XmlPreview.ps1 @@ -0,0 +1,80 @@ +#Requires -Version 7 + +if ( $publicToExport ) { + $publicToExport.function += @( + 'Show-XmlPreview' + ) + $publicToExport.alias += @( + 'ShowXml' + ) +} + + + +function Show-XmlPreview { + <# + .synopsis + simple quick way to preview xml docs, even memory only + .description + uses bat for colorizing XML + .example + PS> $doc = [xml]' None Computing ' + PS> $doc | ShowXml + .example + PS> ShowXml 'c:\test.xml' + #> + [Alias('ShowXml')] + param( + # Either an [XmlDocument] or filepath to one + [Parameter(Mandatory, ValueFromPipeline, Position = 0)] + [object]$InputObject, + + # Disable color, or 'bat' doesn't exist + [switch]$NoColor + ) + begin { + if ($Env:NO_COLOR) { + $NoColor = $true + } + } + process { + # $Options = @{ + # ShowRelativePath = $false + # } + if (Test-Path $InputObject) { + Write-Debug 'showXml [from file]' + + $DisplayPath = $InputObject | Ninmonkey.Console\ConvertTo-RelativePath + if ($DisplayPath -match (ReLit '..')) { + # quick hack, detects that it's not a child + $DisplayPath = $InputObject + + $DisplayPath = $DisplayPath -replace (Relit (Get-Item Temp:\)), 'Temp:\' + $DisplayPath = $DisplayPath -replace (relit $Env:LocalAppData), '$Env:LocalAppData' + } + if ($NoColor) { + Get-Content $InputObject + return + } + + Get-Content $InputObject | bat -l xml --style 'header,grid' --file-name ($DisplayPath) + Write-Debug "Should be: $($InputObject) " + return + } + + if ($InputObject -is 'System.Xml.XmlDocument') { + $doc = $InputObject + Write-Debug 'showXml [in memory]' + $TempDest = Join-Path (Get-Item temp:) 'render.xml' + $doc.save( $tempDest ) #| Out-Null + showXml (Get-Item $TempDest) + return + } + + } +} + + +if (! $publicToExport) { + # ... +} From 840eb7a6352d5da86f815375dfeebf9e7e96d92b Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Mon, 27 Dec 2021 11:26:37 -0600 Subject: [PATCH 39/49] New: Add-IndexProperty Adds identity columns --- public_autoloader/Add-IndexProperty.ps1 | 93 +++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 public_autoloader/Add-IndexProperty.ps1 diff --git a/public_autoloader/Add-IndexProperty.ps1 b/public_autoloader/Add-IndexProperty.ps1 new file mode 100644 index 0000000..7eff860 --- /dev/null +++ b/public_autoloader/Add-IndexProperty.ps1 @@ -0,0 +1,93 @@ +#Requires -Version 7 + +if ( $publicToExport ) { + $publicToExport.function += @( + 'Add-IndexProperty' + ) + $publicToExport.alias += @( + + ) +} + +function Add-IndexProperty { + <# + .synopsis + Add a unique Id column (ie: Index column) for a list of objects + .description + Add a unique Id property/column for a list of objects + If property exists, write-error, and skip item + + With -Force, you may overwrite the property + .example + . + .example + PS> # test + ls fg: | Get-Random -Count 3 + | Add-IndexProperty + | ft Id, *Name* + + hr + ls fg: | Get-Random -Count 3 + | Add-IndexProperty + | Add-IndexProperty -Offset 99 -Force -ea ignore + | ft Id, *Name* + + #> + # [Alias('')] + param( + # Object to modify + [Parameter(Mandatory, ValueFromPipeline, Position = 0)] + [object]$InputObject, + + # initial count to start as, default = 0 + [Parameter()][int]$Offset = 0, + + # Which Property name to use, else 'Id' + [Parameter()][string]$PropertyName = 'Id', + + # Force property write? + [Parameter()][switch]$Force + ) + begin { + # $isFirstIter = $true + $Index = $Offset + } + process { + $Target = $InputObject + $addMemberSplat = @{ + NotePropertyName = $PropertyName + NotePropertyValue = $Index++ + PassThru = $true + } + if ($Force) { + $addMemberSplat['Force'] = $Force + $ErrorAction = 'Continue' + } + if ($target.PSObject.Properties.Name -contains $PropertyName) { + $writeErrorSplat = @{ + TargetObject = $Target + Message = "Object already has the property '$PropertyName'" + } + if ($Force) { + $writeErrorSplat['ErrorAction'] = 'SilentlyContinue' + } else { + $writeErrorSplat['ErrorAction'] = 'Continue' + + } + + Write-Error @writeErrorSplat + if (! $Force) { + $Target + return + } + } + + $Target | Add-Member @addMemberSplat + + } +} + + +if (! $publicToExport) { + # ... +} From ff710d4c38955f51d9a7a788aa73aeaf694bb252 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Sat, 8 Jan 2022 19:26:29 -0600 Subject: [PATCH 40/49] minimal debug statements Silly optional status info using toast --- public/PSReadLine/ExpandAliases.ps1 | 4 ++ .../Get-ObjectTypeHelp.tests.ps1 | 58 ++++++++++++++++++- public_autoloader/Measure-NinChildItem.ps1 | 6 +- 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/public/PSReadLine/ExpandAliases.ps1 b/public/PSReadLine/ExpandAliases.ps1 index f0acae7..89745f1 100644 --- a/public/PSReadLine/ExpandAliases.ps1 +++ b/public/PSReadLine/ExpandAliases.ps1 @@ -21,6 +21,7 @@ Set-PSReadLineKeyHandler @splatKeys -ScriptBlock { foreach ($token in $tokens) { if ($token.TokenFlags -band [TokenFlags]::CommandName) { $alias = $ExecutionContext.InvokeCommand.GetCommand($token.Extent.Text, 'Alias') + # edit: why did the original not compare with null on LHS ? Accident? error? if ($alias -ne $null) { $resolvedCommand = $alias.ResolvedCommandName if ($resolvedCommand -ne $null) { @@ -38,4 +39,7 @@ Set-PSReadLineKeyHandler @splatKeys -ScriptBlock { } } } + if ($ENV:NinEnableToastDebug) { + New-BurntToastNotification -Text ($Tokens | str csv ' ' ) + } } diff --git a/public_autoloader/Get-ObjectTypeHelp.tests.ps1 b/public_autoloader/Get-ObjectTypeHelp.tests.ps1 index d7f8d32..324a04d 100644 --- a/public_autoloader/Get-ObjectTypeHelp.tests.ps1 +++ b/public_autoloader/Get-ObjectTypeHelp.tests.ps1 @@ -9,6 +9,62 @@ Describe 'Get-HelpFromTypeName' { 'DateTime' = 'https://docs.microsoft.com/en-us/dotnet/api/System.DateTime' } } + Context 'ManuallyCreatedUrls' -Tag 'manual' { + $Text = '[Math]' + $Expected = @( + + ) + + It 'TypeInfo' -Pending { + '[Math]' + | HelpFromType -PassThru | Should -BeIn @( + 'https://docs.microsoft.com/en-us/dotnet/api/system.math' + ) + + + } + It 'MethodInfo -> on TypeInfo' -Pending { + <# + Maybe help in + [math] | fm round + + #> + [math]::Round + | HelpFromType -PassThru | Should -BeIn @( + 'https://docs.microsoft.com/en-us/dotnet/api/system.math.round' + ) + + } + It 'Type: Field on static class' -Pending { + [Math]::pi + | HelpFromType -PassThru + | shoudld -be 'https://docs.microsoft.com/en-us/dotnet/api/system.math.pi' + } + It 'Env Var type' -Pending { + Get-ChildItem env: | s -first 1 + | HelpFromType + | Should -BeIn @( + 'System.Collections.DictionaryEntry' + ) -Because 'maybe' + + + + + <# + PSTypeNames: + 'System.Collections.DictionaryEntry' + 'System.Object' + 'System.ValueType' + #> + } + + + # '[Math]' + # | HelpFromType -PassThru | Should -BeIn @( + + # https://docs.microsoft.com/en-us/dotnet/api/system.math.round + # } + } It 'From String' { 'System.TimeSpan' | Get-HelpFromTypeName -PassThru | Should -Be $Url.TimeSpan @@ -35,4 +91,4 @@ Describe 'Get-HelpFromTypeName' { | HelpFromType -PassThru | len | Should -Be $expected } -} \ No newline at end of file +} diff --git a/public_autoloader/Measure-NinChildItem.ps1 b/public_autoloader/Measure-NinChildItem.ps1 index 6570236..df5b55c 100644 --- a/public_autoloader/Measure-NinChildItem.ps1 +++ b/public_autoloader/Measure-NinChildItem.ps1 @@ -87,9 +87,9 @@ function Measure-NinChildItem { $splatForceIgnore = @{ Force = $true; 'Ea' = 'Ignore' } - +# refactor: This should be in a autoloader script block, or consolidated as a type Update-TypeData -TypeName 'Nin.DiskUsageSummary' -MemberType ScriptProperty -MemberName 'RelativePath' -Value { $this.Path | Format-RelativePath -BasePath (Get-Item . ) -} @splatForceIgnore +} @splatForceIgnore | Out-Null -Update-TypeData -TypeName 'Nin.DiskUsageSummary' -DefaultDisplayPropertySet RelativePath, SizeStr, FileCount, DirectoryCount @splatForceIgnore \ No newline at end of file +Update-TypeData -TypeName 'Nin.DiskUsageSummary' -DefaultDisplayPropertySet RelativePath, SizeStr, FileCount, DirectoryCount @splatForceIgnore | Out-Null From db8ced81bee692549a2fa18720ac419ebd6ffce8 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Mon, 10 Jan 2022 14:06:34 -0600 Subject: [PATCH 41/49] refactoring Invoke-NinFormatter to two commandlets --- ...e-NinFormatter.ps1 => Invoke-NinFormatterFancy.ps1} | 7 +++---- ...er.tests.ps1 => Invoke-NinFormatterFancy.tests.ps1} | 10 +++++----- 2 files changed, 8 insertions(+), 9 deletions(-) rename public_autoloader/{Invoke-NinFormatter.ps1 => Invoke-NinFormatterFancy.ps1} (97%) rename public_autoloader/{Invoke-NinFormatter.tests.ps1 => Invoke-NinFormatterFancy.tests.ps1} (68%) diff --git a/public_autoloader/Invoke-NinFormatter.ps1 b/public_autoloader/Invoke-NinFormatterFancy.ps1 similarity index 97% rename from public_autoloader/Invoke-NinFormatter.ps1 rename to public_autoloader/Invoke-NinFormatterFancy.ps1 index 8f12158..2c60c85 100644 --- a/public_autoloader/Invoke-NinFormatter.ps1 +++ b/public_autoloader/Invoke-NinFormatterFancy.ps1 @@ -1,14 +1,14 @@ # using namespace Management.Automation $script:publicToExport.function += @( - 'Invoke-NinFormatter' + 'Invoke-NinFormatterFancy' ) $script:publicToExport.alias += @( 'Format.ScriptPs1🎨' ) # todo: make it a hotkey, also make it indent -function Invoke-NinFormatter { +function Invoke-NinFormatterFancyFancy { <# .synopsis Automatically format using user's custom rules, from the cli @@ -16,7 +16,7 @@ function Invoke-NinFormatter { . .example # formats and saves file - PS> Invoke-NinFormatter -Path 'c:\foo\bar.ps1' -WriteBack + PS> Invoke-NinFormatterFancy -Path 'c:\foo\bar.ps1' -WriteBack .notes future: allow piping from: [HistoryInfo] | [Microsoft.PowerShell.PSConsoleReadLine+HistoryItem] @@ -166,7 +166,6 @@ function Invoke-NinFormatter { $invokeFormatterSplat | Format-dict | Write-Debug - # try {} if ($WriteBack) { diff --git a/public_autoloader/Invoke-NinFormatter.tests.ps1 b/public_autoloader/Invoke-NinFormatterFancy.tests.ps1 similarity index 68% rename from public_autoloader/Invoke-NinFormatter.tests.ps1 rename to public_autoloader/Invoke-NinFormatterFancy.tests.ps1 index 02dc521..7f2bcc9 100644 --- a/public_autoloader/Invoke-NinFormatter.tests.ps1 +++ b/public_autoloader/Invoke-NinFormatterFancy.tests.ps1 @@ -1,7 +1,7 @@ #requires -modules @{ModuleName='Pester';ModuleVersion='5.0.0'} -Describe Invoke-NinFormatter { +Describe Invoke-NinFormatterFancy { BeforeAll { Import-Module Ninmonkey.Console -Force # . $(Get-ChildItem -Path $PSScriptRoot/.. -Recurse -Filter "$__PesterFunctionName.ps1") @@ -12,20 +12,20 @@ Describe Invoke-NinFormatter { } Describe 'FromPipeOrParam' { It 'FromPipe' { - $Sample | Invoke-NinFormatter | Should -Be $expected + $Sample | Invoke-NinFormatterFancy | Should -Be $expected } It 'FromParam' { - Invoke-NinFormatter -ScriptDefinition $Sample | Should -Be $Expected + Invoke-NinFormatterFancy -ScriptDefinition $Sample | Should -Be $Expected } } It 'From Clipboard' { $sample | Set-Clipboard - Invoke-NinFormatter -FromClipboard | Should -Be $expected + Invoke-NinFormatterFancy -FromClipboard | Should -Be $expected } It 'From History' -Skip { # Maybe testing history isn't easy $sample; - Invoke-NinFormatter -FromLastCommand | Should -Be $expected + Invoke-NinFormatterFancy -FromLastCommand | Should -Be $expected } } From 40dafe7efe255a903a30b108931dd30f78819c17 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Mon, 10 Jan 2022 16:36:30 -0600 Subject: [PATCH 42/49] . --- Ninmonkey.Console.psm1 | 15 ++++++--------- public_autoloader/Invoke-NinFormatterFancy.ps1 | 6 +++++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Ninmonkey.Console.psm1 b/Ninmonkey.Console.psm1 index 06d0ee2..40e0fa1 100644 --- a/Ninmonkey.Console.psm1 +++ b/Ninmonkey.Console.psm1 @@ -6,17 +6,14 @@ $PSDefaultParameterValues['Select-NinProperty:Out-Variable'] = 'SelProp' $PSDefaultParameterValues['Write-ConsoleLabel:fg'] = '7FB2C1' # $PSDefaultParameterValues['Write-Text:AsString'] = $true -try { - Set-PSReadLineKeyHandler -Key 'f12' -Function ShowCommandHelp -ea Stop #SilentlyContinue -} catch { - # catch [System.Management.Automation.ParameterBindingValidationException] { - if ($_.ToString() -match 'Cannot validate argument on parameter ''Function''. The argument "ShowCommandHelp"') { - "Module PSReadline: version {0} is missing function: 'ShowCommandHelp'" -f @( (Get-Module PSReadLine).Version ) - | Write-Warning - } else { - throw $_ + +& { + $hasFunc = (Get-PSReadLineKeyHandler -Bound -Unbound | ForEach-Object Function ) -contains 'ShowCommandHelp' + if ($hasFunc) { + Set-PSReadLineKeyHandler -Key 'f12' -Function ShowCommandHelp } } + Set-PSReadLineOption -Colors @{ Comment = '#E58BEB' # " e[38;2;229;139;235m" } diff --git a/public_autoloader/Invoke-NinFormatterFancy.ps1 b/public_autoloader/Invoke-NinFormatterFancy.ps1 index 2c60c85..6ad7c92 100644 --- a/public_autoloader/Invoke-NinFormatterFancy.ps1 +++ b/public_autoloader/Invoke-NinFormatterFancy.ps1 @@ -4,7 +4,7 @@ $script:publicToExport.function += @( 'Invoke-NinFormatterFancy' ) $script:publicToExport.alias += @( - 'Format.ScriptPs1🎨' + # 'Format.ScriptPs1🎨' ) # todo: make it a hotkey, also make it indent @@ -22,6 +22,10 @@ function Invoke-NinFormatterFancyFancy { [HistoryInfo] | [Microsoft.PowerShell.PSConsoleReadLine+HistoryItem] .link PSScriptAnalyzer\Invoke-Formatter + .link + Ninmonkey.Console\Invoke-FormatterFancy + .link + Dev.Nin\Invoke-Formatter .outputs [string] From 545a3a0a5e9c840b977b5fbcaaccff9a9496a4c3 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Mon, 10 Jan 2022 18:16:07 -0600 Subject: [PATCH 43/49] rename --- public_autoloader/Get-HelpFromTypeName.ps1 | 73 ------------------- .../Get-HelpFromTypeName.tests.ps1 | 30 -------- public_autoloader/Get-ObjectTypeHelp.ps1 | 10 ++- 3 files changed, 9 insertions(+), 104 deletions(-) delete mode 100644 public_autoloader/Get-HelpFromTypeName.ps1 delete mode 100644 public_autoloader/Get-HelpFromTypeName.tests.ps1 diff --git a/public_autoloader/Get-HelpFromTypeName.ps1 b/public_autoloader/Get-HelpFromTypeName.ps1 deleted file mode 100644 index 7c33b2d..0000000 --- a/public_autoloader/Get-HelpFromTypeName.ps1 +++ /dev/null @@ -1,73 +0,0 @@ -$script:publicToExport.function += @( - 'Get-HelpFromTypeName' -) -$script:publicToExport.alias += @( - 'HelpFromType' - # 'DevTool💻.Get-HelpFromType' -) - -function Get-HelpFromTypeName { - <# - .synopsis - Opens the docs for the current type, in your default browser - .description - It uses 'Get-Unique -OnType' so you only get 1 result for duplicated types - .example - . - .outputs - [string | None] - .link - Ninmonkey.Console\Format-TypeName - - #> - [Alias('HelpFromType')] - [CmdletBinding(PositionalBinding = $false)] - param( - [Parameter(Mandatory, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)] - [object]$InputObject, - - # Return urls, without opening them - [Parameter()] - [switch]$PassThru - ) - - begin { - # list of full type nam;es - $NameList = [list[string]]::new() - $TemplateUrl = 'https://docs.microsoft.com/en-us/dotnet/api/{0}' - } - process { - if ($InputObject -is 'type') { - $NameList.Add( $InputObject.FullName ) - return - } - if ($InputObject -is 'string') { - if ( [string]::IsNullOrWhiteSpace($InputObject) ) { - return - } - - $typeInfo = $InputObject -as 'type' - $NameList.Add( $typeInfo.FullName ) - return - } - - $NameList.Add( $InputObject.GetType().FullName ) - } - end { - # '... | Get-Unique -OnType is' great if you want to limit a list to 1 per unique type - # like 'ls . -recursse | Get-HelpFromTypeName' - # But I'm using strings, so 'Sort -Unique' works - $NameList - | Sort-Object -Unique - | ForEach-Object { - $url = $TemplateUrl -f $_ - - "Url: '$url' for '$_'" | Write-Debug - - if ($PassThru) { - $url; return - } - Start-Process -path $url - } - } -} diff --git a/public_autoloader/Get-HelpFromTypeName.tests.ps1 b/public_autoloader/Get-HelpFromTypeName.tests.ps1 deleted file mode 100644 index 70b3b3c..0000000 --- a/public_autoloader/Get-HelpFromTypeName.tests.ps1 +++ /dev/null @@ -1,30 +0,0 @@ -BeforeAll { - Import-Module Ninmonkey.Console -Force -} - -Describe 'Get-HelpFromTypeName' { - BeforeAll { - $Url = @{ - 'TimeSpan' = 'https://docs.microsoft.com/en-us/dotnet/api/System.TimeSpan' - 'DateTime' = 'https://docs.microsoft.com/en-us/dotnet/api/System.DateTime' - } - } - It 'From String' { - 'System.TimeSpan' | Get-HelpFromTypeName -PassThru - | Should -Be $Url.TimeSpan - } - It 'From Instance list' { - $Expected = @( - $url.TimeSpan - $url.DateTime - ) - - $query = @( - [datetime]::Now - [timespan]::new(0) - ) | HelpFromType -PassThru - - $query | Should -Contain $url.TimeSpan - $query | Should -Contain $url.DateTime - } -} \ No newline at end of file diff --git a/public_autoloader/Get-ObjectTypeHelp.ps1 b/public_autoloader/Get-ObjectTypeHelp.ps1 index 623231e..33f8a8e 100644 --- a/public_autoloader/Get-ObjectTypeHelp.ps1 +++ b/public_autoloader/Get-ObjectTypeHelp.ps1 @@ -1,4 +1,6 @@ #Requires -Version 7 +using namespace System.Management.Automation.PSMethod + if ( $publicToExport ) { $publicToExport.function += @( @@ -48,7 +50,13 @@ function Get-ObjectTypeHelp { return } # if generics cause problems, try another method - if ($InputObject -is 'PSMethod') { + + # Management.Automation + # if ($InputObject -is 'Management.Automation.PSMethod') { + # todo: refactor to a ProcessTypeInfo -Passthru + # This function just asks on that + if ($InputObject -is 'System.Management.Automation.PSMethod') { + 'methods not completed yet' | Write-Host -fore green $funcName = $InputObject.Name <# example state from: [math]::round | HelpFromType From c45a503c1f92f0c88e2d8429bb9e84bad2b9c0df Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Tue, 18 Jan 2022 14:46:20 -0600 Subject: [PATCH 44/49] misc renames --- public/Format-Predent.ps1 | 7 +++- public/Get-NinMyVSCode.ps1 | 6 +-- public_autoloader/ConvertTo-RelativePath.ps1 | 41 +++++++++++++------ .../Invoke-NinFormatterFancy.ps1 | 2 +- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/public/Format-Predent.ps1 b/public/Format-Predent.ps1 index e7650ba..e675f58 100644 --- a/public/Format-Predent.ps1 +++ b/public/Format-Predent.ps1 @@ -5,7 +5,7 @@ function Format-Predent { .synopsis Adds indentation to code, ex: to post on a forum .description - compare/merge with: + compare/merge with: C:\Users\cppmo_000\SkyDrive\Documents\2021\Powershell\My_Github\Dev.Nin\public_experiment\Format-IndentText.ps1 .example # use clipboard, predent it, then save to clipbard @@ -18,8 +18,11 @@ function Format-Predent { PS> $sampleText | Format-Predent -PassThru # prints result .notes + Dev.Nin\Format-IndentText probably replaces this function, after using smart alias + .LINK + Dev.Nin\Format-IndentText #> - [alias('Format-Indent')] + # [alias('Format-Indent')] param ( # Text to transform [Parameter(ValueFromPipeline)] diff --git a/public/Get-NinMyVSCode.ps1 b/public/Get-NinMyVSCode.ps1 index 1f6463e..c88231d 100644 --- a/public/Get-NinMyVSCode.ps1 +++ b/public/Get-NinMyVSCode.ps1 @@ -7,9 +7,8 @@ function Get-NinMyVSCode { This isn't a VSCode wrapper, that's "Invoke-VsCode" .notes - future: - - [ ] save or autocomplete '--user-data-dir' - - [ ] future: use env an env var + replaced by Dev.Nin/Code-Venv + .example . .link @@ -25,6 +24,7 @@ function Get-NinMyVSCode { # [Parameter(Mandatory, Position = 0)] # [string]$Name ) + Write-Error 'replaced by Dev.Nin/Code-Venv' # $Env:__ninVsCode = 'code-insiders' $DefaultBin = 'code-insiders' diff --git a/public_autoloader/ConvertTo-RelativePath.ps1 b/public_autoloader/ConvertTo-RelativePath.ps1 index 4cfa9a6..112e843 100644 --- a/public_autoloader/ConvertTo-RelativePath.ps1 +++ b/public_autoloader/ConvertTo-RelativePath.ps1 @@ -14,6 +14,8 @@ function ConvertTo-RelativePath { .synopsis relative paths, allows you to pipe to commands that expects raw text like 'fzf preview'. .description + todo: #1 #6 + Transforms both paths as text and (get-item)s - convert to the raw File.FullName raw text - convert to relative path @@ -61,7 +63,7 @@ function ConvertTo-RelativePath { My_Gist\Making regular expressions reada .outputs - [string] + [string] , or $null if emptystring/nulls are passed .link https://docs.microsoft.com/en-us/dotnet/api/system.io.path.getrelativepath .link @@ -72,6 +74,8 @@ function ConvertTo-RelativePath { param ( # Filepath [Alias('PSPath', 'Path')] + [AllowEmptyString()] + [AllowNull()] [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [object[]]$InputObject, @@ -84,10 +88,16 @@ function ConvertTo-RelativePath { # todo: these completions should be short looking alias names [Parameter(Position = 0)] [ArgumentCompletions( - 'C:\Users\cppmo_000\SkyDrive\Documents\2021', - 'C:\Users\cppmo_000\AppData\Roaming', - 'C:\Users\cppmo_000\AppData\Local', - 'C:\Users\cppmo_000' + '$Env:AppData', + '$Env:LocalAppData', + '$Env:Nin_Dotfiles', + '$Env:Nin_Home', + '$Env:Nin_PSModulePath', + '$Env:NinEnableToastDebug', + '$Env:NinNow', + '$Env:UserProfile', + '$Env:UserProfile\SkyDrive\Documents\2021', + '2021-github-downloads' )] [string]$BasePath, @@ -105,9 +115,10 @@ function ConvertTo-RelativePath { if (! [string]::IsNullOrWhiteSpace( $BasePath) ) { $curDir = Get-Item $BasePath } - $curDir ??= Get-Location + $curDir = Get-Location | Get-Item } process { + <# ripgrep and/or grep have file line numbers at the start, or end, depending on mode #> @@ -115,17 +126,23 @@ function ConvertTo-RelativePath { $InputObject | ForEach-Object { # if *everything* fails, return initial value $rawItem = $_ # maybe always strip ansi ? + + if ($null -eq $rawItem) { + return + } + try { + # Write-Warning "WIP $PSSCommand" if ($rawItem -is 'string') { $parsedItem = $rawItem | Remove-AnsiEscape } else { $parsedItem = $rawItem } - $maybeNameList = @( - $parsedItem - $parsedItem -replace '(:\d+)$', '' - ) + # $maybeNameList = @( + # $parsedItem + # $parsedItem -replace '(:\d+)$', '' + # ) try { $curItem = Get-Item $parsedItem -ea stop } catch { @@ -139,11 +156,11 @@ function ConvertTo-RelativePath { # } # h1 'end of rel path' | Write-Host if ($null -eq $curItem) { - Write-Debug 'curItem: $null' -ea Stop #SilentlyContinue + Write-Debug 'curItem: $null' return } if ($null -eq $curDir) { - Write-Debug 'curDir: $null' -ea Stop #SilentlyContinue + Write-Debug 'curDir: $null' return } diff --git a/public_autoloader/Invoke-NinFormatterFancy.ps1 b/public_autoloader/Invoke-NinFormatterFancy.ps1 index 6ad7c92..fe32f16 100644 --- a/public_autoloader/Invoke-NinFormatterFancy.ps1 +++ b/public_autoloader/Invoke-NinFormatterFancy.ps1 @@ -8,7 +8,7 @@ $script:publicToExport.alias += @( ) # todo: make it a hotkey, also make it indent -function Invoke-NinFormatterFancyFancy { +function Invoke-NinFormatterFancy { <# .synopsis Automatically format using user's custom rules, from the cli From 436ef3bbdc85065c95b038449e90056f4fb27dd3 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Wed, 19 Jan 2022 11:19:06 -0600 Subject: [PATCH 45/49] Join hashtables, new: Merge-HashtableList --- public_autoloader/ConvertTo-RelativePath.ps1 | 2 +- public_autoloader/Join-Hashtable.ps1 | 95 +++++++++++++++++++- 2 files changed, 92 insertions(+), 5 deletions(-) diff --git a/public_autoloader/ConvertTo-RelativePath.ps1 b/public_autoloader/ConvertTo-RelativePath.ps1 index 112e843..15d5edd 100644 --- a/public_autoloader/ConvertTo-RelativePath.ps1 +++ b/public_autoloader/ConvertTo-RelativePath.ps1 @@ -5,7 +5,7 @@ if ( $publicToExport ) { 'ConvertTo-RelativePath' ) $publicToExport.alias += @( - 'To->RelativePatha' + 'To->RelativePath' ) } diff --git a/public_autoloader/Join-Hashtable.ps1 b/public_autoloader/Join-Hashtable.ps1 index 4e9b7dd..940f5b8 100644 --- a/public_autoloader/Join-Hashtable.ps1 +++ b/public_autoloader/Join-Hashtable.ps1 @@ -1,30 +1,117 @@ $script:publicToExport.function += @( 'Join-Hashtable' + 'Merge-HashtableList' ) # $script:publicToExport.alias += @( # 'HelpCommmand') +Function Merge-HashtableList { + <# + .description + from the pipeline, merge all hastables in-order + .notes + . + .example + 🐒> ls . -file | select -First 4 | %{ + $_ | Lookup 'Length' -NewKeyName 'Size' + $_ | Lookup 'LastWriteTime' -NewKeyName 'Updated' + @{ 'randomProperty' = 'cats'} + get-date | dict day\b + } | Merge-HashtableList -AsObject | ft -AutoSize + + TimeOfDay Size Updated Day randomProperty + --------- ---- ------- --- -------------- + 11:16:58.6575367 253 3/14/2021 5:17:30 PM 19 cats + .example + 🐒> + ls . -file | select -First 4 | %{ + $_ | Lookup 'Length' -NewKeyName 'Size' + $_ | Lookup 'LastWriteTime' -NewKeyName 'Updated' + @{ 'randomProperty' = 'cats'} + get-date | dict day\b + } | Merge-HashtableList + + Name Value + ---- ----- + TimeOfDay 11:11:14.3477747 + Size 253 + Updated 3/14/2021 5:17:30 PM + Day 19 + randomProperty cats + + .link + Ninmonkey.Console\Join-Hashtable + .link + Ninmonkey.Console\Merge-HashtableList + .link + PSScriptTools\Join-Hashtable + .link + Ninmonkey.Powershell\Join-Hashtable + #> + [outputType('System.Collections.Hashtable')] + [cmdletbinding()] + param( + # base hashtable + [Alias('$Hashtable')] + [Parameter(Mandatory, Position = 0, ValueFromPipeline)] + [hashtable[]]$InputObject, + + # use ordered hashtables instead? + [switch]$Ordered, + + # This will return a [pscustomobject], instead of [hashtable] + [switch]$AsObject + ) + begin { + $tables = [list[hashtable]]::new() + } + # don't mutate $BaseHash + process { + if ($Ordered) { + Write-Error -Category NotImplemented -Message 'nyi' -ErrorId 'MergeHashtableParamOrered' + return + } + + foreach ($hash in $InputObject) { + $tables.Add( $hash ) + } + } + end { + $accum = @{} + foreach ($hash in $tables) { + $accum = Join-Hashtable -BaseHash $accum -UpdateHash $hash + } + if ($AsObject) { + [pscustomobject]$accum + } else { + $accum + } + } +} + Function Join-Hashtable { <# .description Copy and append BaseHash with new values from UpdateHash .notes - future: add valuefrom pipeline to $UpdateHash param + future: add valuefrom pipeline to $UpdateHash param ? .link Ninmonkey.Console\Join-Hashtable .link - PSScriptTools\Join-Hashtable + Ninmonkey.Console\Merge-HashtableList .link Ninmonkey.Powershell\Join-Hashtable + .link + PSScriptTools\Join-Hashtable #> [cmdletbinding()] param( # base hashtable [Parameter(Mandatory, Position = 0)] [hashtable]$BaseHash, - - # New values to append and/or overwrite + + # New values to append and/or overwrite [Parameter(Mandatory, Position = 1)] [hashtable]$UpdateHash ) From f0612cae5be26cd6d9b0ca585a12c36b422fc094 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Thu, 20 Jan 2022 13:46:08 -0600 Subject: [PATCH 46/49] Update Resolve-CommandName.tests.ps1 --- public/Resolve-CommandName.tests.ps1 | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/public/Resolve-CommandName.tests.ps1 b/public/Resolve-CommandName.tests.ps1 index 8e3f843..ca20571 100644 --- a/public/Resolve-CommandName.tests.ps1 +++ b/public/Resolve-CommandName.tests.ps1 @@ -10,9 +10,9 @@ BeforeAll { Describe 'Resolve-CommandName' { It 'Temp test to flag bug' { - + { Get-Command '?str' | resCmd -q } | Should -Not -Throw - # output: + # output: # gc: @splat: # error the term jstr is not a command } @@ -27,8 +27,12 @@ Describe 'Resolve-CommandName' { } It 'PreserveAlias' { - - + # todo: need to add command when preserve alias is true + rescmd rescmd -QualifiedName -PreserveAlias | ForEach-Object Name | Should -be @( + 'Ninmonkey.Console\rescmd' + 'Ninmonkey.Console\Resolve-CommandName' + ) + } # It 'Runs without error' { From 64bd74884bcaff22769e376b9ab573b80f78e2cc Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Fri, 21 Jan 2022 11:26:19 -0600 Subject: [PATCH 47/49] bugfix: Test-IsDirectory was erroring on Empty String --- public_autoloader/Test-IsDirectory.ps1 | 34 +++++++++++++++++--------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/public_autoloader/Test-IsDirectory.ps1 b/public_autoloader/Test-IsDirectory.ps1 index bf0f648..5749e6c 100644 --- a/public_autoloader/Test-IsDirectory.ps1 +++ b/public_autoloader/Test-IsDirectory.ps1 @@ -29,39 +29,49 @@ function Test-IsContainer { [outputtype('System.Boolean')] [CmdletBinding()] param( - # File object or path to test + # File object or path to test. False for whitespace or nulls. + [allowEmptyString()] + [allowNull()] [Parameter(Mandatory, Position = 0, ValueFromPipeline)] - [Alias('PSPath')] - [string]$Path + [Alias('PSPath', 'Path')] + [object]$InputObject ) begin { } process { <# #> - try { - $item = Get-Item $Path -ea stop + if ( [string]::IsNullOrEmpty( $InputObject )) { + return $false; } - catch { - # definitely didn't exist - Write-Debug 'GI failed' - $false; return + + $item = Get-Item $InputObject -ea ignore + if ($null -eq $item) { + return $false } + # try { + # $item = Get-Item $InputObject -ea stop + # } catch { + # # definitely didn't exist + # Write-Debug 'GI failed' + # return $false; + # } $isType = $Item -is 'System.IO.DirectoryInfo' $meta = @{ IsDirInfo = $isDir HasAttr = $hasAttribute IsContainer = [bool]$Item.PSIsContainer - PathTypeContainer = Test-Path -PathType Container -Path $Path + PathTypeContainer = Test-Path -PathType Container -Path $InputObject } $meta | Format-Table | Out-String | Write-Debug # $hasAttribute = ($item.Attributes -band [IO.FileAttributes]::Directory) -eq [IO.FileAttributes]::Directory # you could also do -ne 0 at the end to achieve the same thing $hasAttribute = ($item.Attributes -band [IO.FileAttributes]::Directory) -ne 0 - $isContainer = Test-Path -PathType Container -Path $Path + $isContainer = Test-Path -PathType Container -Path $InputObject + + # return [bool]: $isType -or $hasAttribute -or ([bool]$Item.PSIsContainer) -or $isContainer - return } end { } From 279b6dd9abd6881d5acee1c04b18d1e3da27be4e Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Sun, 23 Jan 2022 08:49:20 -0600 Subject: [PATCH 48/49] Update Get-ObjectTypeHelp.ps1 --- public_autoloader/Get-ObjectTypeHelp.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/public_autoloader/Get-ObjectTypeHelp.ps1 b/public_autoloader/Get-ObjectTypeHelp.ps1 index 33f8a8e..571b5d2 100644 --- a/public_autoloader/Get-ObjectTypeHelp.ps1 +++ b/public_autoloader/Get-ObjectTypeHelp.ps1 @@ -18,6 +18,9 @@ function Get-ObjectTypeHelp { Opens the docs for the current type, in your default browser .description It uses 'Get-Unique -OnType' so you only get 1 result for duplicated types + .notes + you can always fallback to the url + https://docs.microsoft.com/en-us/dotnet/api/ .example . .outputs From 0f15b228a648513eb3ff58b5c5375c8187b40175 Mon Sep 17 00:00:00 2001 From: Jake Bolton Date: Sun, 23 Jan 2022 14:54:29 -0600 Subject: [PATCH 49/49] Hashtable: Optionally mutate left input --- public_autoloader/Join-Hashtable.ps1 | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/public_autoloader/Join-Hashtable.ps1 b/public_autoloader/Join-Hashtable.ps1 index 940f5b8..429fb97 100644 --- a/public_autoloader/Join-Hashtable.ps1 +++ b/public_autoloader/Join-Hashtable.ps1 @@ -96,6 +96,8 @@ Function Join-Hashtable { Copy and append BaseHash with new values from UpdateHash .notes future: add valuefrom pipeline to $UpdateHash param ? + .example + Join-Hashtable -Base $ .link Ninmonkey.Console\Join-Hashtable .link @@ -106,6 +108,7 @@ Function Join-Hashtable { PSScriptTools\Join-Hashtable #> [cmdletbinding()] + [outputType('System.Collections.Hashtable')] param( # base hashtable [Parameter(Mandatory, Position = 0)] @@ -113,15 +116,27 @@ Function Join-Hashtable { # New values to append and/or overwrite [Parameter(Mandatory, Position = 1)] - [hashtable]$UpdateHash + [hashtable]$OtherHash, + + # normal is to not modify left, return a new hashtable + [Parameter()][switch]$MutateLeft + + # default Left wins if they share a key name + # [Parameter()][switch]$PrioritizeRight ) # don't mutate $BaseHash process { - $NewHash = [hashtable]::new( $BaseHash ) - $UpdateHash.GetEnumerator() | ForEach-Object { - $NewHash[ $_.Key ] = $_.Value + # $NewHash = [hashtable]::new( $BaseHash ) + if (! $MutateLeft ) { + $TargetHash = [hashtable]::new( $BaseHash ) + } else { + Write-Debug 'Mutate enabled' + $TargetHash = $BaseHash + } + $OtherHash.GetEnumerator() | ForEach-Object { + $TargetHash[ $_.Key ] = $_.Value } - $NewHash + $TargetHash } }