-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Loads of changes for powershell built-in formatters and switch to ret…
…urning renderables instead of always outputting to ansi console to allow nesting
- Loading branch information
1 parent
5d8c175
commit 9da6338
Showing
32 changed files
with
1,573 additions
and
1,173 deletions.
There are no files selected for viewing
13 changes: 13 additions & 0 deletions
13
PwshSpectreConsole.Docs/src/content/docs/guides/upgrading-to-1-0.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Upgrading to 1.0 | ||
|
||
I started this as a learning excercise in how to bridge the gap between C# libraries and PowerShell and wow have I learned a lot. Things I thought made sense when I first wrote this have now made it difficult to maintain. I've tried to maintain as much backwards compatibility as I can but there are some areas which will have breaking changes when upgrading to 1.0. | ||
|
||
## New Features | ||
|
||
- Renderable items use PowerShell formatters (thanks @startautomating) so you can now assign the output of functions like `Format-SpectreJson` to a variable and use it inside other Spectre Console functions like `Format-SpectreTable`. | ||
|
||
## Changes | ||
|
||
- Parameter names for a lot of commandlets have been aligned with the terminology in Spectre.Console, this affects commands all throughout this module but to maintain backwards compatibility the old parameter names have been kept as aliases so existing scripts will continue to work. Exceptions to this are: | ||
- Format-SpectreJson parameters removed are `-Border`, `-Title`, `-NoBorder`. To wrap the json in a border the suggested option is to pipe the output to Format-SpectrePanel e.g. `Format-SpectreJson -Data $data | Format-SpectrePanel` | ||
- TODO find the others |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#requires -Module EZOut | ||
# Install-Module EZOut or https://github.com/StartAutomating/EZOut | ||
$myFile = $MyInvocation.MyCommand.ScriptBlock.File | ||
$myModuleName = $($myFile | Split-Path -Leaf) -replace '\.ezformat\.ps1', '' -replace '\.ezout\.ps1', '' | ||
$myRoot = $myFile | Split-Path | ||
Push-Location $myRoot | ||
$formatting = @( | ||
# Add your own Write-FormatView here, | ||
# or put them in a Formatting or Views directory | ||
foreach ($potentialDirectory in 'Formatting','Views','Types') { | ||
Join-Path $myRoot $potentialDirectory | | ||
Get-ChildItem -ea ignore | | ||
Import-FormatView -FilePath {$_.Fullname} | ||
} | ||
) | ||
|
||
$destinationRoot = $myRoot | ||
|
||
if ($formatting) { | ||
$myFormatFilePath = Join-Path $destinationRoot "$myModuleName.format.ps1xml" | ||
# You can also output to multiple paths by passing a hashtable to -OutputPath. | ||
$formatting | Out-FormatData -Module $MyModuleName -OutputPath $myFormatFilePath | ||
} | ||
|
||
$types = @( | ||
# Add your own Write-TypeView statements here | ||
# or declare them in the 'Types' directory | ||
Join-Path $myRoot Types | | ||
Get-Item -ea ignore | | ||
Import-TypeView | ||
|
||
) | ||
|
||
if ($types) { | ||
$myTypesFilePath = Join-Path $destinationRoot "$myModuleName.types.ps1xml" | ||
# You can also output to multiple paths by passing a hashtable to -OutputPath. | ||
$types | Out-TypeData -OutputPath $myTypesFilePath | ||
} | ||
Pop-Location |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<!-- Generated with EZOut 2.0.6: Install-Module EZOut or https://github.com/StartAutomating/EZOut --> | ||
<Configuration> | ||
<ViewDefinitions> | ||
<View> | ||
<Name>Spectre.Console.Rendering.Renderable</Name> | ||
<ViewSelectedBy> | ||
<TypeName>Spectre.Console.Rendering.Renderable</TypeName> | ||
</ViewSelectedBy> | ||
<CustomControl> | ||
<CustomEntries> | ||
<CustomEntry> | ||
<CustomItem> | ||
<ExpressionBinding> | ||
<ScriptBlock> | ||
# Work out if the current object is being piped to another command, there isn't access to the pipeline in the format view script block so it's using a janky regex workaround | ||
try { | ||
$line = $MyInvocation.Line | ||
$start = $MyInvocation.OffsetInLine | ||
$lineAfterOffset = $line.SubString($start, ($line.Length - $start)) | ||
$targetIsInPipeline = $lineAfterOffset | Select-String "^[^;]+?\|" | ||
$pipelineSegment = $lineAfterOffset | Select-String "^[^;]+?(;|$)" | Select-Object -ExpandProperty Matches -First 1 | Select-Object -ExpandProperty Value | ||
$targetIsPipedToSpectreFunction = $pipelineSegment -match ".*\|.*(Write|Format|Out)-Spectre.*" | ||
Write-Debug "Line: $line" | ||
Write-Debug "Start: $start" | ||
Write-Debug "Line after offset: $lineAfterOffset" | ||
Write-Debug "Target is in pipeline: $targetIsInPipeline" | ||
Write-Debug "Pipeline segment: $pipelineSegment" | ||
Write-Debug "Target is piped to Spectre function: $targetIsPipedToSpectreFunction" | ||
} catch { | ||
Write-Debug "Failed to discover pipeline state for Spectre.Console.Rendering.Renderable: $_" | ||
} | ||
|
||
if ($targetIsInPipeline -and -not $targetIsPipedToSpectreFunction) { | ||
$_ | ||
} else { | ||
Write-AnsiConsole $_ | ||
} | ||
</ScriptBlock> | ||
</ExpressionBinding> | ||
</CustomItem> | ||
</CustomEntry> | ||
</CustomEntries> | ||
</CustomControl> | ||
</View> | ||
</ViewDefinitions> | ||
</Configuration> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
PwshSpectreConsole/formatting/Spectre.Console.AnsiConsole.format.ps1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# TODO - Ask @startautomating how this can be done better | ||
Write-FormatView -TypeName "Spectre.Console.Rendering.Renderable" -Action { | ||
# Work out if the current object is being piped to another command, there isn't access to the pipeline in the format view script block so it's using a janky regex workaround | ||
try { | ||
$line = $MyInvocation.Line | ||
$start = $MyInvocation.OffsetInLine | ||
$lineAfterOffset = $line.SubString($start, ($line.Length - $start)) | ||
$targetIsInPipeline = $lineAfterOffset | Select-String "^[^;]+?\|" | ||
$pipelineSegment = $lineAfterOffset | Select-String "^[^;]+?(;|$)" | Select-Object -ExpandProperty Matches -First 1 | Select-Object -ExpandProperty Value | ||
$targetIsPipedToSpectreFunction = $pipelineSegment -match ".*\|.*(Write|Format|Out)-Spectre.*" | ||
Write-Debug "Line: $line" | ||
Write-Debug "Start: $start" | ||
Write-Debug "Line after offset: $lineAfterOffset" | ||
Write-Debug "Target is in pipeline: $targetIsInPipeline" | ||
Write-Debug "Pipeline segment: $pipelineSegment" | ||
Write-Debug "Target is piped to Spectre function: $targetIsPipedToSpectreFunction" | ||
} catch { | ||
Write-Debug "Failed to discover pipeline state for Spectre.Console.Rendering.Renderable: $_" | ||
} | ||
|
||
if ($targetIsInPipeline -and -not $targetIsPipedToSpectreFunction) { | ||
$_ | ||
} else { | ||
Write-AnsiConsole $_ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,40 @@ | ||
using namespace Spectre.Console | ||
|
||
<# | ||
.SYNOPSIS | ||
Recursively adds child nodes to a parent node in a Spectre.Console tree. | ||
.DESCRIPTION | ||
The Add-SpectreTreeNode function adds child nodes to a parent node in a Spectre.Console tree. It does this recursively, so it can handle nested child nodes. | ||
.PARAMETER Node | ||
The parent node to which the child nodes will be added. | ||
.PARAMETER Children | ||
An array of child nodes to be added to the parent node. Each child node should be an object with a 'Label' property and a 'Children' property (which can be an empty array if the child has no children of its own). | ||
.NOTES | ||
See Format-SpectreTree for usage. | ||
#> | ||
function Add-SpectreTreeNode { | ||
param ( | ||
[Parameter(Mandatory)] | ||
[IHasTreeNodes] $Node, | ||
[Parameter(Mandatory)] | ||
[array] $Children | ||
) | ||
|
||
foreach ($child in $Children) { | ||
$newNode = [HasTreeNodeExtensions]::AddNode($Node, $child.Label) | ||
if ($child.Children.Count -gt 0) { | ||
Add-SpectreTreeNode -Node $newNode -Children $child.Children | ||
} | ||
} | ||
using namespace Spectre.Console | ||
|
||
<# | ||
.SYNOPSIS | ||
Recursively adds child nodes to a parent node in a Spectre.Console tree. | ||
.DESCRIPTION | ||
The Add-SpectreTreeNode function adds child nodes to a parent node in a Spectre.Console tree. It does this recursively, so it can handle nested child nodes. | ||
.PARAMETER Node | ||
The parent node to which the child nodes will be added. | ||
.PARAMETER Children | ||
An array of child nodes to be added to the parent node. Each child node should be an object with a 'Label' property and a 'Children' property (which can be an empty array if the child has no children of its own). | ||
.NOTES | ||
See Format-SpectreTree for usage. | ||
#> | ||
function Add-SpectreTreeNode { | ||
param ( | ||
[Parameter(Mandatory)] | ||
[IHasTreeNodes] $Node, | ||
[Parameter(Mandatory)] | ||
[array] $Children | ||
) | ||
|
||
foreach ($child in $Children) { | ||
|
||
# Backwards compatibility: Value used to be called Label | ||
if ($child.ContainsKey("Label")) { | ||
$child["Value"] = $child["Label"] | ||
$child.Remove("Label") | ||
} | ||
|
||
$newNode = [HasTreeNodeExtensions]::AddNode($Node, $child.Value) | ||
if ($child.Children.Count -gt 0) { | ||
Add-SpectreTreeNode -Node $newNode -Children $child.Children | ||
} | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
PwshSpectreConsole/private/Convert-HashtableToRenderSafePSObject.ps1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
function Convert-HashtableToRenderSafePSObject { | ||
param( | ||
[object] $Hashtable, | ||
[hashtable] $Renderables | ||
) | ||
$customObject = @{} | ||
foreach ($item in $Hashtable.GetEnumerator()) { | ||
if ($item.Value -is [hashtable] -or $item.Value -is [ordered]) { | ||
$item.Value = Convert-HashtableToRenderSafePSObject -Hashtable $item.Value | ||
} elseif ($item.Value -is [Spectre.Console.Rendering.Renderable]) { | ||
$renderableKey = "RENDERABLE__$([Guid]::NewGuid().Guid)" | ||
$Renderables[$renderableKey] = $item.Value | ||
$item.Value = $renderableKey | ||
} | ||
$customObject[$item.Key] = $item.Value | ||
} | ||
return [pscustomobject]$customObject | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,25 @@ | ||
using namespace Spectre.Console | ||
|
||
<# | ||
.SYNOPSIS | ||
Writes an object to the console using [AnsiConsole]::Write() | ||
.DESCRIPTION | ||
This function is required for mocking ansiconsole in unit tests that write objects to the console. | ||
.PARAMETER RenderableObject | ||
The renderable object to write to the console e.g. [BarChart] | ||
.EXAMPLE | ||
Write-SpectreConsoleOutput -Object "Hello, World!" -ForegroundColor Green -BackgroundColor Black | ||
#> | ||
function Write-AnsiConsole { | ||
param( | ||
[Parameter(Mandatory)] | ||
[Rendering.Renderable] $RenderableObject | ||
) | ||
[AnsiConsole]::Write($RenderableObject) | ||
using module ".\completions\Transformers.psm1" | ||
using namespace Spectre.Console | ||
|
||
<# | ||
.SYNOPSIS | ||
Writes an object to the console using [AnsiConsole]::Write() | ||
.DESCRIPTION | ||
This function is required for mocking ansiconsole in unit tests that write objects to the console. | ||
.PARAMETER RenderableObject | ||
The renderable object to write to the console e.g. [BarChart] | ||
.EXAMPLE | ||
Write-SpectreConsoleOutput -Object "Hello, World!" -ForegroundColor Green -BackgroundColor Black | ||
#> | ||
function Write-AnsiConsole { | ||
[CmdletBinding()] | ||
param( | ||
[Parameter(Mandatory)] | ||
[RenderableTransformationAttribute()] | ||
[object] $RenderableObject | ||
) | ||
[AnsiConsole]::Render($RenderableObject) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.