diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs index 3fd396518f..07b579ae8b 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHostUserInterface.cs @@ -1752,7 +1752,7 @@ namespace Microsoft.PowerShell // is overridden by the tab char charUnderCursor = GetCharacterUnderCursor(c); - Write(new string(' ', leftover)); + Write(StringUtil.Padding(leftover)); RawUI.CursorPosition = c; restOfLine = s[i] + (charUnderCursor + s.Substring(i + 1)); diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/PendingProgress.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/PendingProgress.cs index 252565c9df..d383743757 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/PendingProgress.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/PendingProgress.cs @@ -689,7 +689,7 @@ namespace Microsoft.PowerShell } ArrayList result = new ArrayList(); - string border = new string(' ', maxWidth); + string border = StringUtil.Padding(maxWidth); result.Add(border); RenderHelper(result, _topLevelNodes, 0, maxWidth, rawUI); diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ProgressNode.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ProgressNode.cs index 6c0ad589aa..d11e78431d 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ProgressNode.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ProgressNode.cs @@ -171,7 +171,7 @@ namespace Microsoft.PowerShell void RenderFull(ArrayList strCollection, int indentation, int maxWidth, PSHostRawUserInterface rawUI, bool isFullPlus) { - string indent = new string(' ', indentation); + string indent = StringUtil.Padding(indentation); // First line: the activity @@ -180,7 +180,7 @@ namespace Microsoft.PowerShell rawUI, StringUtil.Format(" {0}{1} ", indent, this.Activity), maxWidth)); indentation += 3; - indent = new string(' ', indentation); + indent = StringUtil.Padding(indentation); // Second line: the status description @@ -209,7 +209,7 @@ namespace Microsoft.PowerShell " {0}[{1}{2}] ", indent, new string('o', mercuryWidth), - new string(' ', thermoWidth - mercuryWidth)), + StringUtil.Padding(thermoWidth - mercuryWidth)), maxWidth)); } @@ -291,7 +291,7 @@ namespace Microsoft.PowerShell void RenderCompact(ArrayList strCollection, int indentation, int maxWidth, PSHostRawUserInterface rawUI) { - string indent = new string(' ', indentation); + string indent = StringUtil.Padding(indentation); // First line: the activity @@ -301,7 +301,7 @@ namespace Microsoft.PowerShell StringUtil.Format(" {0}{1} ", indent, this.Activity), maxWidth)); indentation += 3; - indent = new string(' ', indentation); + indent = StringUtil.Padding(indentation); // Second line: the status description with percentage and time remaining, if applicable. @@ -372,7 +372,7 @@ namespace Microsoft.PowerShell void RenderMinimal(ArrayList strCollection, int indentation, int maxWidth, PSHostRawUserInterface rawUI) { - string indent = new string(' ', indentation); + string indent = StringUtil.Padding(indentation); // First line: Everything mushed into one line @@ -512,7 +512,7 @@ namespace Microsoft.PowerShell // Start with 1 for the Activity int lines = 1; // Use 5 spaces as the heuristic indent. 5 spaces stand for the indent for the CurrentOperation of the first-level child node - var indent = new string(' ', 5); + var indent = StringUtil.Padding(5); var temp = new ArrayList(); if (isFullPlus) diff --git a/src/System.Management.Automation/commands/utility/FormatAndOutput/common/ComplexWriter.cs b/src/System.Management.Automation/commands/utility/FormatAndOutput/common/ComplexWriter.cs index f03c0e5cd9..027f04834f 100644 --- a/src/System.Management.Automation/commands/utility/FormatAndOutput/common/ComplexWriter.cs +++ b/src/System.Management.Automation/commands/utility/FormatAndOutput/common/ComplexWriter.cs @@ -8,6 +8,7 @@ using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Text; using System.Globalization; +using System.Management.Automation.Internal; namespace Microsoft.PowerShell.Commands.Internal.Format { @@ -715,7 +716,7 @@ namespace Microsoft.PowerShell.Commands.Internal.Format internal static string PadLeft(string val, int count) { - return new string(' ', count) + val; + return StringUtil.Padding(count) + val; } private static readonly char[] s_newLineChar = new char[] { '\n' }; diff --git a/src/System.Management.Automation/commands/utility/FormatAndOutput/common/ListWriter.cs b/src/System.Management.Automation/commands/utility/FormatAndOutput/common/ListWriter.cs index 2538b88c56..b8789a496c 100644 --- a/src/System.Management.Automation/commands/utility/FormatAndOutput/common/ListWriter.cs +++ b/src/System.Management.Automation/commands/utility/FormatAndOutput/common/ListWriter.cs @@ -4,6 +4,7 @@ Copyright (c) Microsoft Corporation. All rights reserved. using System.Collections.Specialized; using System.Diagnostics; +using System.Management.Automation.Internal; namespace Microsoft.PowerShell.Commands.Internal.Format { @@ -86,7 +87,7 @@ namespace Microsoft.PowerShell.Commands.Internal.Format if (propertyNameCellCounts[k] < _propertyLabelsDisplayLength) { // shorter than the max, add padding - _propertyLabels[k] = propertyNames[k] + new string(' ', _propertyLabelsDisplayLength - propertyNameCellCounts[k]); + _propertyLabels[k] = propertyNames[k] + StringUtil.Padding(_propertyLabelsDisplayLength - propertyNameCellCounts[k]); } else if (propertyNameCellCounts[k] > _propertyLabelsDisplayLength) { @@ -181,7 +182,7 @@ namespace Microsoft.PowerShell.Commands.Internal.Format else { if (padding == null) - padding = prependString = new string(' ', _propertyLabelsDisplayLength); + padding = StringUtil.Padding(_propertyLabelsDisplayLength); prependString = padding; } @@ -209,7 +210,7 @@ namespace Microsoft.PowerShell.Commands.Internal.Format StringCollection sc = StringManipulationHelper.GenerateLines(lo.DisplayCells, line, fieldCellCount, fieldCellCount); // padding to use in the lines after the first - string padding = new string(' ', _propertyLabelsDisplayLength); + string padding = StringUtil.Padding(_propertyLabelsDisplayLength); // display the string collection for (int k = 0; k < sc.Count; k++) diff --git a/src/System.Management.Automation/commands/utility/FormatAndOutput/common/TableWriter.cs b/src/System.Management.Automation/commands/utility/FormatAndOutput/common/TableWriter.cs index 885b0a0260..d8c9b74fbb 100644 --- a/src/System.Management.Automation/commands/utility/FormatAndOutput/common/TableWriter.cs +++ b/src/System.Management.Automation/commands/utility/FormatAndOutput/common/TableWriter.cs @@ -3,6 +3,7 @@ Copyright (c) Microsoft Corporation. All rights reserved. --********************************************************************/ using System.Collections.Specialized; +using System.Management.Automation.Internal; using System.Text; namespace Microsoft.PowerShell.Commands.Internal.Format @@ -248,7 +249,7 @@ namespace Microsoft.PowerShell.Commands.Internal.Format // skipping the first ones, add a separator for catenation for (int j = 0; j < scArray[k].Count; j++) { - scArray[k][j] = new string(' ', ScreenInfo.separatorCharacterCount) + scArray[k][j]; + scArray[k][j] = StringUtil.Padding(ScreenInfo.separatorCharacterCount) + scArray[k][j]; } } else @@ -258,7 +259,7 @@ namespace Microsoft.PowerShell.Commands.Internal.Format { for (int j = 0; j < scArray[k].Count; j++) { - scArray[k][j] = new string(' ', _startColumn) + scArray[k][j]; + scArray[k][j] = StringUtil.Padding(_startColumn) + scArray[k][j]; } } } @@ -288,7 +289,7 @@ namespace Microsoft.PowerShell.Commands.Internal.Format { for (int j = 0; j < paddingEntries; j++) { - scArray[col].Add(new string(' ', paddingBlanks)); + scArray[col].Add(StringUtil.Padding(paddingBlanks)); } } } @@ -339,14 +340,14 @@ namespace Microsoft.PowerShell.Commands.Internal.Format // pad with a blank (or any character that ALWAYS maps to a single screen cell if (k > 0) { - sb.Append(new string(' ', ScreenInfo.separatorCharacterCount)); + sb.Append(StringUtil.Padding(ScreenInfo.separatorCharacterCount)); } else { // add indentation padding if needed if (_startColumn > 0) { - sb.Append(new string(' ', _startColumn)); + sb.Append(StringUtil.Padding(_startColumn)); } } sb.Append(GenerateRowField(values[k], _si.columnInfo[k].width, alignment[k], dc)); @@ -372,7 +373,7 @@ namespace Microsoft.PowerShell.Commands.Internal.Format { case TextAlignment.Right: { - s = new string(' ', padCount) + s; + s = StringUtil.Padding(padCount) + s; } break; @@ -382,14 +383,14 @@ namespace Microsoft.PowerShell.Commands.Internal.Format int padLeft = padCount / 2; int padRight = padCount - padLeft; - s = new string(' ', padLeft) + s + new string(' ', padRight); + s = StringUtil.Padding(padLeft) + s + StringUtil.Padding(padRight); } break; default: { // left align is the default - s += new string(' ', padCount); + s += StringUtil.Padding(padCount); } break; } diff --git a/src/System.Management.Automation/engine/parser/token.cs b/src/System.Management.Automation/engine/parser/token.cs index dfe2d52701..9d87896ab1 100644 --- a/src/System.Management.Automation/engine/parser/token.cs +++ b/src/System.Management.Automation/engine/parser/token.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.Management.Automation.Internal; using System.Text; namespace System.Management.Automation.Language @@ -1236,7 +1237,7 @@ namespace System.Management.Automation.Language internal virtual string ToDebugString(int indent) { - return string.Format(CultureInfo.InvariantCulture, "{0}{1}: <{2}>", new string(' ', indent), _kind, Text); + return string.Format(CultureInfo.InvariantCulture, "{0}{1}: <{2}>", StringUtil.Padding(indent), _kind, Text); } } @@ -1256,7 +1257,7 @@ namespace System.Management.Automation.Language internal override string ToDebugString(int indent) { return string.Format(CultureInfo.InvariantCulture, - "{0}{1}: <{2}> Value:<{3}> Type:<{4}>", new string(' ', indent), Kind, Text, _value, _value.GetType().Name); + "{0}{1}: <{2}> Value:<{3}> Type:<{4}>", StringUtil.Padding(indent), Kind, Text, _value, _value.GetType().Name); } /// @@ -1298,7 +1299,7 @@ namespace System.Management.Automation.Language internal override string ToDebugString(int indent) { return string.Format(CultureInfo.InvariantCulture, - "{0}{1}: <-{2}{3}>", new string(' ', indent), Kind, _parameterName, _usedColon ? ":" : ""); + "{0}{1}: <-{2}{3}>", StringUtil.Padding(indent), Kind, _parameterName, _usedColon ? ":" : ""); } } @@ -1326,7 +1327,7 @@ namespace System.Management.Automation.Language internal override string ToDebugString(int indent) { return string.Format(CultureInfo.InvariantCulture, - "{0}{1}: <{2}> Name:<{3}>", new string(' ', indent), Kind, Text, Name); + "{0}{1}: <{2}> Name:<{3}>", StringUtil.Padding(indent), Kind, Text, Name); } } @@ -1349,7 +1350,7 @@ namespace System.Management.Automation.Language internal override string ToDebugString(int indent) { return string.Format(CultureInfo.InvariantCulture, - "{0}{1}: <{2}> Value:<{3}>", new string(' ', indent), Kind, Text, Value); + "{0}{1}: <{2}> Value:<{3}>", StringUtil.Padding(indent), Kind, Text, Value); } } diff --git a/src/System.Management.Automation/utils/StringUtil.cs b/src/System.Management.Automation/utils/StringUtil.cs index 5784d2d96b..825372d148 100644 --- a/src/System.Management.Automation/utils/StringUtil.cs +++ b/src/System.Management.Automation/utils/StringUtil.cs @@ -3,6 +3,7 @@ Copyright (c) Microsoft Corporation. All rights reserved. --********************************************************************/ using System.Management.Automation.Host; +using System.Threading; using Dbg = System.Management.Automation.Diagnostics; namespace System.Management.Automation.Internal @@ -68,6 +69,25 @@ namespace System.Management.Automation.Internal return result; } + + // Typical padding is at most a screen's width, any more than that and we won't bother caching. + private const int IndentCacheMax = 120; + private static readonly string[] IndentCache = new string[IndentCacheMax]; + internal static string Padding(int countOfSpaces) + { + if (countOfSpaces >= IndentCacheMax) + return new string(' ', countOfSpaces); + + var result = IndentCache[countOfSpaces]; + + if (result == null) + { + Interlocked.CompareExchange(ref IndentCache[countOfSpaces], new string(' ', countOfSpaces), null); + result = IndentCache[countOfSpaces]; + } + + return result; + } } } // namespace