Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ internal sealed class FieldPropertyToken : PropertyTokenBase
internal sealed class FieldFormattingDirective
{
internal string formatString = null; // optional
internal bool isTable = false;
}

#endregion Elementary Tokens
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,12 @@ private TableRowEntry GenerateTableRowEntryFromFromProperties(PSObject so, int e
directive = activeAssociationList[k].OriginatingParameter.GetEntry(FormatParameterDefinitionKeys.FormatStringEntryKey) as FieldFormattingDirective;
}

if (directive is null)
{
directive = new FieldFormattingDirective();
directive.isTable = true;
}
Comment thread
SteveL-MSFT marked this conversation as resolved.

fpf.propertyValue = this.GetExpressionDisplayValue(so, enumerationLimit, this.activeAssociationList[k].ResolvedExpression, directive);
tre.formatPropertyFieldList.Add(fpf);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,9 @@ private static string GetObjectName(object x, PSPropertyExpressionFactory expres
/// <param name="expressionFactory">Expression factory to create PSPropertyExpression.</param>
/// <param name="enumerationLimit">Limit on IEnumerable enumeration.</param>
/// <param name="formatErrorObject">Stores errors during string conversion.</param>
/// <param name="formatFloat">Determine if to format floating point numbers using current culture.</param>
Comment thread
SteveL-MSFT marked this conversation as resolved.
/// <returns>String representation.</returns>
internal static string SmartToString(PSObject so, PSPropertyExpressionFactory expressionFactory, int enumerationLimit, StringFormatError formatErrorObject)
internal static string SmartToString(PSObject so, PSPropertyExpressionFactory expressionFactory, int enumerationLimit, StringFormatError formatErrorObject, bool formatFloat = false)
{
if (so == null)
return string.Empty;
Expand Down Expand Up @@ -294,7 +295,23 @@ internal static string SmartToString(PSObject so, PSPropertyExpressionFactory ex
return sb.ToString();
}

// take care of the case there is no base object
if (formatFloat && so.BaseObject is not null)
{
// format numbers using the current culture
if (so.BaseObject is double dbl)
{
return dbl.ToString("F");
}
else if (so.BaseObject is float f)
{
return f.ToString("F");
}
else if (so.BaseObject is decimal d)
{
return d.ToString("F");
}
}

return so.ToString();
}
catch (Exception e) when (e is ExtendedTypeSystemException || e is InvalidOperationException)
Expand Down Expand Up @@ -333,43 +350,49 @@ internal static string FormatField(FieldFormattingDirective directive, object va
StringFormatError formatErrorObject, PSPropertyExpressionFactory expressionFactory)
{
PSObject so = PSObjectHelper.AsPSObject(val);
if (directive != null && !string.IsNullOrEmpty(directive.formatString))
bool isTable = false;
if (directive is not null)
{
// we have a formatting directive, apply it
// NOTE: with a format directive, we do not make any attempt
// to deal with IEnumerable
try
isTable = directive.isTable;
if (!string.IsNullOrEmpty(directive.formatString))
{
// use some heuristics to determine if we have "composite formatting"
// 2004/11/16-JonN This is heuristic but should be safe enough
if (directive.formatString.Contains("{0") || directive.formatString.Contains('}'))
// we have a formatting directive, apply it
// NOTE: with a format directive, we do not make any attempt
// to deal with IEnumerable
try
{
// we do have it, just use it
return string.Format(CultureInfo.CurrentCulture, directive.formatString, so);
// use some heuristics to determine if we have "composite formatting"
// 2004/11/16-JonN This is heuristic but should be safe enough
if (directive.formatString.Contains("{0") || directive.formatString.Contains('}'))
{
// we do have it, just use it
return string.Format(CultureInfo.CurrentCulture, directive.formatString, so);
}
// we fall back to the PSObject's IFormattable.ToString()
// pass a null IFormatProvider
return so.ToString(directive.formatString, formatProvider: null);
}
// we fall back to the PSObject's IFormattable.ToString()
// pass a null IFormatProvider
return so.ToString(directive.formatString, null);
}
catch (Exception e) // 2004/11/17-JonN This covers exceptions thrown in
// string.Format and PSObject.ToString().
// I think we can swallow these.
{
// NOTE: we catch all the exceptions, since we do not know
// what the underlying object access would throw
if (formatErrorObject != null)
catch (Exception e) // 2004/11/17-JonN This covers exceptions thrown in
// string.Format and PSObject.ToString().
// I think we can swallow these.
{
formatErrorObject.sourceObject = so;
formatErrorObject.exception = e;
formatErrorObject.formatString = directive.formatString;
return string.Empty;
// NOTE: we catch all the exceptions, since we do not know
// what the underlying object access would throw
if (formatErrorObject is not null)
{
formatErrorObject.sourceObject = so;
formatErrorObject.exception = e;
formatErrorObject.formatString = directive.formatString;
return string.Empty;
}
}
}
}

// we do not have a formatting directive or we failed the formatting (fallback)
// but we did not report as an error;
// this call would deal with IEnumerable if the object implements it
return PSObjectHelper.SmartToString(so, expressionFactory, enumerationLimit, formatErrorObject);
return PSObjectHelper.SmartToString(so, expressionFactory, enumerationLimit, formatErrorObject, isTable);
}

private static PSMemberSet MaskDeserializedAndGetStandardMembers(PSObject so)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,27 @@ dbda : KM
$actual = $actual -replace "`r`n", "`n"
$actual | Should -BeExactly $expected
}

It 'Float, double, and decimal should not be truncated to number of decimals from current culture' {
$o = [PSCustomObject]@{
double = [double]1234.56789
float = [float]9876.543
decimal = [decimal]4567.123456789
}

$expected = @"

double : 1234.56789
float : 9876.543
decimal : 4567.123456789



"@
Comment thread
SteveL-MSFT marked this conversation as resolved.

$actual = $o | Format-List | Out-String
($actual.Replace("`r`n", "`n")) | Should -BeExactly ($expected.Replace("`r`n", "`n"))
}
}

Describe 'Format-List color tests' {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,25 @@ A Name B
$actual = $obj | Format-Table | Out-String
($actual.Replace("`r`n", "`n")) | Should -BeExactly ($expected.Replace("`r`n", "`n"))
}

It 'Table should format floats, doubles, and decimals with number of decimals from current culture' {
$o = [PSCustomObject]@{
double = [double]1234.56789
float = [float]9876.54321
decimal = [decimal]4567.123456789
}

$table = $o | Format-Table | Out-String

$line = foreach ($line in $table.split([System.Environment]::NewLine)) { if ($line -match '^1234') { $line } }
$line | Should -Not -BeNullOrEmpty
$expectedDecimals = (Get-Culture).NumberFormat.NumberDecimalDigits

foreach ($num in $line.split(' ', [System.StringSplitOptions]::RemoveEmptyEntries)) {
$numDecimals = $num.length - $num.indexOf((Get-Culture).NumberFormat.NumberDecimalSeparator) - 1
$numDecimals | Should -Be $expectedDecimals -Because $num
}
}
}

Describe 'Table color tests' {
Expand Down