Skip to content

Commit

Permalink
Ugh custom formatting is painful
Browse files Browse the repository at this point in the history
  • Loading branch information
ShaunLawrie committed Aug 18, 2024
1 parent 46e54b3 commit 65960a2
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 54 deletions.
27 changes: 2 additions & 25 deletions PwshSpectreConsole/PwshSpectreConsole.format.ps1xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
<!-- Generated with EZOut 2.0.6: Install-Module EZOut or https://github.com/StartAutomating/EZOut -->
<Configuration>
<ViewDefinitions>
<View>
Expand All @@ -12,30 +11,8 @@
<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 {
$_ | Out-SpectreHost
}
</ScriptBlock>
$_ | Out-SpectreHost -CustomItemFormatter
</ScriptBlock>
</ExpressionBinding>
</CustomItem>
</CustomEntry>
Expand Down
12 changes: 12 additions & 0 deletions PwshSpectreConsole/PwshSpectreConsole.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ $script:DefaultValueColor = [Spectre.Console.Color]::Grey
$script:DefaultTableHeaderColor = [Spectre.Console.Color]::Default
$script:DefaultTableTextColor = [Spectre.Console.Color]::Default

# For widgets that can be streamed to the console as raw text, prompts/progress widgets do not use this.
# This allows the terminal to process them as text so they can be dumped like:
# PS> $widget = "Hello, World!" | Format-SpectrePanel -Title "My Panel" -Color Blue -Expand
# PS> $widget # uses the default powershell console writer
# PS> $widget > file.txt # redirects as string data to file
# PS> $widget | Out-SpectreHost # uses a dedicated console writer that doesn't pad the object like the default formatter
$script:SpectreConsoleWriter = [System.IO.StringWriter]::new()
$script:SpectreConsoleOutput = [Spectre.Console.AnsiConsoleOutput]::new($script:SpectreConsoleWriter)
$script:SpectreConsoleSettings = [Spectre.Console.AnsiConsoleSettings]::new()
$script:SpectreConsoleSettings.Out = $script:SpectreConsoleOutput
$script:SpectreConsole = [Spectre.Console.AnsiConsole]::Create($script:SpectreConsoleSettings)

foreach ($directory in @('private', 'public')) {
Get-ChildItem -Path "$PSScriptRoot\$directory\*.ps1" -Recurse | ForEach-Object {
. $_.FullName
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,4 @@
# 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 {
$_ | Out-SpectreHost
}
$_ | Out-SpectreHost -CustomItemFormatter
}
18 changes: 16 additions & 2 deletions PwshSpectreConsole/private/Write-AnsiConsole.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,21 @@ function Write-AnsiConsole {
param(
[Parameter(Mandatory)]
[RenderableTransformationAttribute()]
[object] $RenderableObject
[object] $RenderableObject,
[switch] $CustomItemFormatter
)
[Spectre.Console.AnsiConsole]::Render($RenderableObject)

if ($CustomItemFormatter) {
# ps1xml CustomItem formatters mangle the output because it uses the last character of the buffer width for itself
$script:SpectreConsole.Profile.Width = $Host.UI.RawUI.BufferSize.Width - 1
} else {
$script:SpectreConsole.Profile.Width = $Host.UI.RawUI.BufferSize.Width
}

$script:SpectreConsole.Write($RenderableObject)
$output = $script:SpectreConsoleWriter.ToString()

$output.ToString().TrimEnd()

$null = $script:SpectreConsoleWriter.GetStringBuilder().Clear()
}
2 changes: 1 addition & 1 deletion PwshSpectreConsole/public/demo/Start-SpectreDemo.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ $(
Clear-Host

$example = @'
Get-Module PwshSpectreConsole | Select-Object PrivateData | Format-SpectreJson -Expand
Get-Module PwshSpectreConsole | Select-Object PrivateData | Format-SpectreJson
'@
$example | Write-SpectreExample -Title "Json Data" -Description "Spectre Console can format JSON with syntax highlighting thanks to https://github.com/trackd"
Invoke-Expression $example
Expand Down
10 changes: 7 additions & 3 deletions PwshSpectreConsole/public/rendering/Out-SpectreHost.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ function Out-SpectreHost {
.PARAMETER Data
The data to write to the console.
.PARAMETER CustomItemFormatter
The default host customitem formatter has some restrictions, it needs to be one char less wide than when outputting to the standard console or it will wrap.
.EXAMPLE
$table = New-SpectreTable -Data $data
$table | Out-SpectreHost
Expand All @@ -20,18 +23,19 @@ function Out-SpectreHost {
param (
[Parameter(ValueFromPipeline, Mandatory)]
[RenderableTransformationAttribute()]
[object] $Data
[object] $Data,
[switch] $CustomItemFormatter
)

begin {}

process {
if ($Data -is [array]) {
foreach ($dataItem in $Data) {
Write-AnsiConsole -RenderableObject $dataItem
Write-AnsiConsole -RenderableObject $dataItem -CustomItemFormatter:$CustomItemFormatter
}
} else {
Write-AnsiConsole -RenderableObject $Data
Write-AnsiConsole -RenderableObject $Data -CustomItemFormatter:$CustomItemFormatter
}
}

Expand Down

0 comments on commit 65960a2

Please sign in to comment.