Last active
June 25, 2024 22:20
-
-
Save trackd/2c670e3c1a127ab32d885a68168c06a9 to your computer and use it in GitHub Desktop.
ft as markdowntable
This file contains hidden or 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
function ConvertTo-MarkdownTable { | |
<# | |
.DESCRIPTION | |
Convert an object to a markdown table. | |
.PARAMETER InputObject | |
The object to convert to a markdown table. | |
.PARAMETER Property | |
The properties to display in the table. | |
Passthru to Format-Table. | |
.PARAMETER Autosize | |
Autosize the columns. | |
.PARAMETER Grid | |
Add a grid to the table. | |
.PARAMETER AllowVT | |
Allow VT codes to be included in the output. | |
.PARAMETER Padding | |
The padding to add to each cell (before and after value). | |
defaults to a space. | |
.PARAMETER View | |
The view to use for the table. | |
.PARAMETER Delimiter | |
The delimiter to use for the table. | |
Defaults to '|'. | |
.EXAMPLE | |
ls | ConvertTo-MarkdownTable | |
ls | ConvertTo-MarkdownTable -Autosize | |
ls | ft | ConvertTo-MarkdownTable | |
for fun, | |
gps | ConvertTo-MarkdownTable -Delimiter '😄' | |
.NOTES | |
saw https://gist.github.com/JustinGrote/595973381d6438d987552d6a33851515 | |
and wanted to try my own version. | |
#> | |
[CmdletBinding()] | |
[Alias('ctmt')] | |
[OutputType([string])] | |
param( | |
[Parameter(Mandatory, ValueFromPipeline)] | |
[AllowNull()] | |
[AllowEmptyString()] | |
[object[]] $InputObject, | |
[object[]] $Property, | |
[switch] $Autosize, | |
[switch] $Grid, | |
[ValidateLength(1,2)] | |
[string] $Padding = ' ', | |
[switch] $AllowVT, | |
[string] $View, | |
[ValidateLength(1,2)] | |
[string] $Delimiter = '|', | |
[ValidateLength(1,1)] | |
[String] $VerticalDelimiter = '-' | |
) | |
begin { | |
$Objects = [System.Collections.Generic.List[object]]::new() | |
$sb = [System.Text.StringBuilder]::new() | |
$e = [char]27 | |
$VTCodes = @( | |
# color | |
[Regex]::new("$e\[\d*(;\d+)*m") | |
# CSI | |
[Regex]::new("$e\[\?\d+[hl]") | |
# link | |
[Regex]::new("$e\]8;;.*?$e\\") | |
) -join '|' | |
$len = @{} | |
# for formatting the output. | |
$Cell = $Padding + '{0}' + $Padding + $Delimiter | |
$CellStart = $Delimiter + $Cell | |
function GetColumnWidths { | |
<# | |
for autosize, get the width of each column. | |
#> | |
param( | |
[string[]] $Strings, | |
[int] $Count | |
) | |
if ([String]::IsNullOrEmpty($Strings)) { | |
return @{} | |
} | |
$widths = @{} | |
for ($i = 0; $i -lt $Strings.Length; $i++) { | |
$columnIndex = $i % $Count | |
$string = $Strings[$i] -replace $VTCodes | |
if ($widths.ContainsKey($columnIndex)) { | |
if ($string.Length -gt $widths[$columnIndex]) { | |
$widths[$columnIndex] = $string.Length | |
} | |
} | |
else { | |
$widths[$columnIndex] = $string.Length | |
} | |
} | |
$widths | |
} | |
} | |
process { | |
if ($null -eq $InputObject) { | |
return | |
} | |
if ($MyInvocation.ExpectingInput) { | |
return $Objects.Add($InputObject) | |
} | |
foreach ($entry in $InputObject) { | |
if ([String]::IsNullOrEmpty($entry)) { | |
continue | |
} | |
$Objects.Add($entry) | |
} | |
} | |
end { | |
if ($Objects.Count -eq 0) { | |
return | |
} | |
if ($Objects[0].GetType().Name -ne 'FormatStartData') { | |
$ft = @{} | |
if ($Property) { | |
$ft.Property = $Property | |
} | |
if ($View) { | |
$ft.View = $View | |
} | |
$Objects = $Objects | Format-Table @ft | |
} | |
$null = & { | |
# suppress all stringbuilder output in one go. | |
if ($Objects[0].Gettype().Name -eq 'FormatStartData') { | |
$ColumnIndex = 0 | |
$ColumnCount = $Objects[0].shapeinfo.tablecolumninfolist.count | |
if ($Autosize) { | |
$widthSplat = @{ | |
Strings = $Objects.FormatEntryInfo.formatPropertyFieldList.propertyValue | |
Count = $ColumnCount | |
} | |
$WidthCheck = GetColumnWidths @widthSplat | |
} | |
foreach ($header in $Objects[0].shapeinfo.tablecolumninfolist) { | |
# property header | |
if ($null -ne $header.label) { | |
$Name = $header.label | |
} | |
else { | |
$Name = $header.propertyname | |
} | |
# column width | |
if ($Autosize) { | |
$header.Width = $WidthCheck[$ColumnIndex] | |
if ($Name.Length -gt $header.Width) { | |
$header.Width = $Name.Length | |
} | |
} | |
elseif ($header.width -eq 0) { | |
$header.width = ($host.UI.RawUI.WindowSize.Width - 10) / $ColumnCount | |
} | |
# add to the string builder | |
if ($ColumnIndex -eq 0) { | |
$sb.AppendFormat($CellStart, $Name.PadRight($header.Width)) | |
} | |
else { | |
$sb.AppendFormat($Cell, $Name.PadRight($header.Width)) | |
} | |
$len[$ColumnIndex] = $header.Width | |
$ColumnIndex++ | |
} | |
$bar = $sb.ToString() -replace $VTCodes -replace "[^$Delimiter]",$VerticalDelimiter | |
$sb.AppendLine().Append($bar) | |
if ($Grid) { | |
$sb.Insert(0, $bar + "`n") | |
} | |
} | |
if ($Objects.FormatEntryInfo) { | |
foreach ($row in $Objects.FormatEntryInfo) { | |
if ($row.formatPropertyFieldList) { | |
$ColumnIndex = 0 | |
$sb.AppendLine().Append($Delimiter) | |
foreach ($value in $row.formatPropertyFieldList) { | |
$pad = $len[$ColumnIndex] | |
# need both to get the length of the string without VT codes for padding. | |
$valWithVT = $value.propertyValue.ToString() | |
$valWithoutVT = $valWithVT -replace $VTCodes | |
if ($AllowVT) { | |
$sb.AppendFormat( | |
$Cell, | |
$valWithVT.PadRight( | |
$pad + ($valWithVT.Length - $valWithoutVT.Length) | |
) | |
) | |
} | |
else { | |
$sb.AppendFormat($Cell, $valWithoutVT.PadRight($pad)) | |
} | |
$ColumnIndex++ | |
} | |
if ($Grid) { | |
$sb.AppendLine().Append($bar) | |
} | |
} | |
else { | |
# string array, no properties or header. | |
if ($sb.Length -eq 0) { | |
$sb.AppendFormat($CellStart, $row.text) | |
} | |
else { | |
$sb.AppendLine().AppendFormat($CellStart, $row.text) | |
} | |
} | |
} | |
} | |
} | |
$sb.Insert(0,"`n").AppendLine().ToString() | |
} | |
} | |
Register-ArgumentCompleter -CommandName ConvertTo-MarkdownTable -ParameterName View -ScriptBlock { | |
param ($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) | |
$commandPipeline = $commandAst.Parent | |
$pipelineIndex = if ($commandPipeline.PipelineElements) { | |
$commandPipeline.PipelineElements.IndexOf($commandAst) | |
} | |
else { | |
-1 | |
} | |
if ($pipelineIndex) { | |
$priorPipeline = $commandPipeline.PipelineElements[0..($pipelineIndex - 1)].Extent -join ' | ' | |
$tabtrick = '{0} | Format-Table -View "{1}' -f $priorPipeline, $wordToComplete | |
return (TabExpansion2 -inputScript $tabtrick -cursorColumn $tabtrick.Length).CompletionMatches | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment