mirror of
https://github.com/aphrody-labs/PowerShell.git
synced 2026-10-13 21:32:06 +00:00
Allow user to force the default implicit formatting to use AutoSize (#28018)
When `$PSStyle.AutoSizeDefaultFormatting = $true`, the default implicit formatting applied by PowerShell (via `Out-Default`) will enforce `AutoSize` when the chosen formatting view is `table` or `wide`, similar to running `Format-Table -AutoSize` and `Format-Wide -AutoSize` explicitly. The `List` and `Complex` views formatting won't be buffered though -- they will continue to be streamed. This allows PowerShell to generate less verbose output when used by an agent. It also makes PowerShell works better with small-window terminal.
This commit is contained in:
1 parent
a049fa38ef
commit
2179219c84
5 files changed
+194
No files matched your search
+1
@@ -2157,6 +2157,7 @@ namespace System.Management.Automation.Runspaces
|
||||
.AddItemScriptBlock(@"""$($_.StrikethroughOff)$($_.StrikethroughOff.Replace(""""`e"""",'`e'))$($_.Reset)""", label: "StrikethroughOff")
|
||||
.AddItemScriptBlock(@"""$($_.Strikethrough)$($_.Strikethrough.Replace(""""`e"""",'`e'))$($_.Reset)""", label: "Strikethrough")
|
||||
.AddItemProperty(@"OutputRendering")
|
||||
.AddItemProperty(@"AutoSizeDefaultFormatting")
|
||||
.AddItemScriptBlock(@"""$($_.Formatting.FormatAccent)$($_.Formatting.FormatAccent.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.FormatAccent")
|
||||
.AddItemScriptBlock(@"""$($_.Formatting.ErrorAccent)$($_.Formatting.ErrorAccent.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.ErrorAccent")
|
||||
.AddItemScriptBlock(@"""$($_.Formatting.Error)$($_.Formatting.Error.Replace(""""`e"""",'`e'))$($PSStyle.Reset)""", label: "Formatting.Error")
|
||||
|
||||
@@ -135,6 +135,12 @@ namespace Microsoft.PowerShell.Commands.Internal.Format
|
||||
|
||||
private void InitializeAutoSize()
|
||||
{
|
||||
// Only Table and Wide views support autosize.
|
||||
if (this is not (TableViewGenerator or WideViewGenerator))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// check the autosize flag first
|
||||
if (parameters != null && parameters.autosize.HasValue)
|
||||
{
|
||||
|
||||
@@ -641,6 +641,11 @@ namespace System.Management.Automation
|
||||
/// </summary>
|
||||
public OutputRendering OutputRendering { get; set; } = OutputRendering.Host;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether to force the default implicit formatting to use 'AutoSize'.
|
||||
/// </summary>
|
||||
public bool AutoSizeDefaultFormatting { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets value to turn off all attributes.
|
||||
/// </summary>
|
||||
|
||||
@@ -20,5 +20,20 @@ namespace Microsoft.PowerShell.Commands
|
||||
{
|
||||
this.implementation = new InnerFormatShapeCommand(FormatShape.Undefined);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hook up the AutoSize override, if requested, before handing off to the
|
||||
/// implementation.
|
||||
/// </summary>
|
||||
protected override void BeginProcessing()
|
||||
{
|
||||
if (PSStyle.Instance.AutoSizeDefaultFormatting)
|
||||
{
|
||||
var parameters = new FormattingCommandLineParameters { autosize = true };
|
||||
((InnerFormatShapeCommand)this.implementation).SetCommandLineParameters(parameters);
|
||||
}
|
||||
|
||||
base.BeginProcessing();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,6 +89,10 @@ Describe 'Tests for $PSStyle automatic variable' -Tag 'CI' {
|
||||
$PSStyle.OutputRendering | Should -BeExactly 'Host'
|
||||
}
|
||||
|
||||
It '$PSStyle default view includes AutoSizeDefaultFormatting' {
|
||||
$PSStyle | Out-String | Should -Match 'AutoSizeDefaultFormatting'
|
||||
}
|
||||
|
||||
It '$PSStyle has correct defaults for style <key>' -TestCases (Get-TestCases $styleDefaults) {
|
||||
param($key, $value)
|
||||
|
||||
@@ -603,3 +607,166 @@ Billy Bob… Senior DevOps … 13
|
||||
$text.Trim().Replace("`r", "") | Should -BeExactly $expected.Replace("`r", "")
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'Default formatting AutoSize override' -Tag 'CI' {
|
||||
BeforeAll {
|
||||
$formatFile = Join-Path $TestDrive 'AutoSizeDefaultFormatting.format.ps1xml'
|
||||
@'
|
||||
<Configuration>
|
||||
<ViewDefinitions>
|
||||
<View>
|
||||
<Name>AutoSizeWide</Name>
|
||||
<ViewSelectedBy>
|
||||
<TypeName>Test.AutoSizeWide</TypeName>
|
||||
</ViewSelectedBy>
|
||||
<WideControl>
|
||||
<WideEntries>
|
||||
<WideEntry>
|
||||
<WideItem>
|
||||
<PropertyName>Name</PropertyName>
|
||||
</WideItem>
|
||||
</WideEntry>
|
||||
</WideEntries>
|
||||
</WideControl>
|
||||
</View>
|
||||
<View>
|
||||
<Name>AutoSizeComplex</Name>
|
||||
<ViewSelectedBy>
|
||||
<TypeName>Test.AutoSizeComplex</TypeName>
|
||||
</ViewSelectedBy>
|
||||
<CustomControl>
|
||||
<CustomEntries>
|
||||
<CustomEntry>
|
||||
<CustomItem>
|
||||
<Text>Item</Text>
|
||||
<NewLine />
|
||||
</CustomItem>
|
||||
</CustomEntry>
|
||||
</CustomEntries>
|
||||
</CustomControl>
|
||||
</View>
|
||||
</ViewDefinitions>
|
||||
</Configuration>
|
||||
'@ | Set-Content -Path $formatFile
|
||||
}
|
||||
|
||||
It "Forces default table formatting to use 'AutoSize'" {
|
||||
$oldOutputRendering = $PSStyle.OutputRendering
|
||||
$oldAutoSizeDefaultFormatting = $PSStyle.AutoSizeDefaultFormatting
|
||||
|
||||
try {
|
||||
$PSStyle.OutputRendering = 'PlainText'
|
||||
$PSStyle.AutoSizeDefaultFormatting = $false
|
||||
$defaultOutput = Get-Command Import-Module | Out-String
|
||||
$PSStyle.AutoSizeDefaultFormatting = $true
|
||||
$autoSizedOutput = Get-Command Import-Module | Out-String
|
||||
|
||||
$defaultOutput = $defaultOutput.Trim().Split("`n")
|
||||
$autoSizedOutput = $autoSizedOutput.Trim().Split("`n")
|
||||
|
||||
$defaultOutput.Count | Should -BeExactly $autoSizedOutput.Count
|
||||
for ($i = 0; $i -lt $defaultOutput.Count; $i++) {
|
||||
$defaultOutput[$i].Length | Should -BeGreaterThan $autoSizedOutput[$i].Length
|
||||
$elements_1 = $defaultOutput[$i].Split(' ', [System.StringSplitOptions]::RemoveEmptyEntries)
|
||||
$elements_2 = $autoSizedOutput[$i].Split(' ', [System.StringSplitOptions]::RemoveEmptyEntries)
|
||||
$elements_1 -join ' ' | Should -BeExactly ($elements_2 -join ' ')
|
||||
}
|
||||
}
|
||||
finally {
|
||||
$PSStyle.AutoSizeDefaultFormatting = $oldAutoSizeDefaultFormatting
|
||||
$PSStyle.OutputRendering = $oldOutputRendering
|
||||
}
|
||||
}
|
||||
|
||||
It "Forces default wide formatting to use 'AutoSize'" {
|
||||
$powerShell = [PowerShell]::Create()
|
||||
|
||||
try {
|
||||
$result = $powerShell.AddScript({
|
||||
param($Path)
|
||||
|
||||
Update-FormatData -PrependPath $Path
|
||||
$oldOutputRendering = $PSStyle.OutputRendering
|
||||
$oldAutoSizeDefaultFormatting = $PSStyle.AutoSizeDefaultFormatting
|
||||
|
||||
try {
|
||||
$PSStyle.OutputRendering = 'PlainText'
|
||||
$items = 1..6 | ForEach-Object {
|
||||
[pscustomobject]@{ PSTypeName = 'Test.AutoSizeWide'; Name = "Item$_" }
|
||||
}
|
||||
|
||||
$PSStyle.AutoSizeDefaultFormatting = $false
|
||||
$defaultOutput = $items | Out-String -Width 40
|
||||
$PSStyle.AutoSizeDefaultFormatting = $true
|
||||
$autoSizedOutput = $items | Out-String -Width 40
|
||||
|
||||
[pscustomobject]@{
|
||||
DefaultOutput = $defaultOutput
|
||||
AutoSizedOutput = $autoSizedOutput
|
||||
}
|
||||
}
|
||||
finally {
|
||||
$PSStyle.AutoSizeDefaultFormatting = $oldAutoSizeDefaultFormatting
|
||||
$PSStyle.OutputRendering = $oldOutputRendering
|
||||
}
|
||||
}).AddArgument($formatFile).Invoke()
|
||||
|
||||
$powerShell.HadErrors | Should -BeFalse
|
||||
$defaultLines = $result.DefaultOutput.Trim().Split("`n")
|
||||
$autoSizedLines = $result.AutoSizedOutput.Trim().Split("`n")
|
||||
$defaultLines | Should -HaveCount 3
|
||||
$autoSizedLines | Should -HaveCount 1
|
||||
$autoSizedLines[0].Split(' ', [System.StringSplitOptions]::RemoveEmptyEntries) | Should -HaveCount 6
|
||||
}
|
||||
finally {
|
||||
$powerShell.Dispose()
|
||||
}
|
||||
}
|
||||
|
||||
It 'Does not buffer default <ViewType> formatting until pipeline completion' -TestCases @(
|
||||
@{ ViewType = 'List' }
|
||||
@{ ViewType = 'Complex' }
|
||||
) {
|
||||
param($ViewType)
|
||||
|
||||
$powerShell = [PowerShell]::Create()
|
||||
|
||||
try {
|
||||
$producerFinished = $powerShell.AddScript({
|
||||
param($Path, $ViewType)
|
||||
|
||||
Update-FormatData -PrependPath $Path
|
||||
$oldAutoSizeDefaultFormatting = $PSStyle.AutoSizeDefaultFormatting
|
||||
|
||||
try {
|
||||
$PSStyle.AutoSizeDefaultFormatting = $true
|
||||
$inputObject = $ViewType -eq 'List' ? $PSStyle : [pscustomobject]@{ PSTypeName = 'Test.AutoSizeComplex'; Name = 'Item' }
|
||||
|
||||
$script:producerFinished = $false
|
||||
& {
|
||||
$inputObject
|
||||
$script:producerFinished = $true
|
||||
} |
|
||||
Out-String -Stream |
|
||||
Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | ## Ignore the newline written out by 'Out-String'
|
||||
Select-Object -First 1 |
|
||||
Out-Null
|
||||
|
||||
$script:producerFinished
|
||||
}
|
||||
finally {
|
||||
$PSStyle.AutoSizeDefaultFormatting = $oldAutoSizeDefaultFormatting
|
||||
}
|
||||
}).AddArgument($formatFile).AddArgument($ViewType).Invoke()
|
||||
|
||||
$powerShell.HadErrors | Should -BeFalse
|
||||
# When rendering streams, the first non-whitespace string reaches 'Select-Object' before '$script:producerFinished = $true' runs. 'Select-Object -First 1' then stops
|
||||
# the upstream script, so that assignment is never evaluated and '$producerFinished' remains false.
|
||||
# If rendering is buffered, 'Out-String' emits no non-whitespace payload until the upstream script finishes and the assignment runs, making '$producerFinished' true.
|
||||
$producerFinished | Should -BeFalse
|
||||
}
|
||||
finally {
|
||||
$powerShell.Dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user