From 4c2a144819156f4484472537ceadf73e8067351b Mon Sep 17 00:00:00 2001 From: Yotic Date: Thu, 17 Jul 2025 06:15:12 +0300 Subject: [PATCH 1/2] Changed formatting of tooltips for numeric types, removed octal formatting --- .../NumberDocumentViewerToolTipProvider.cs | 40 ++++++------- .../Tabs/DocViewer/ToolTips/NumberUtils.cs | 57 ++++++++++++++----- 2 files changed, 64 insertions(+), 33 deletions(-) diff --git a/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberDocumentViewerToolTipProvider.cs b/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberDocumentViewerToolTipProvider.cs index b8d392a0fa..a1349603e0 100644 --- a/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberDocumentViewerToolTipProvider.cs +++ b/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberDocumentViewerToolTipProvider.cs @@ -53,11 +53,10 @@ sealed class NumberDocumentViewerToolTipProvider : IDocumentViewerToolTipProvide return null; } - static readonly (int @base, int groupSize)[] numberBases = new (int, int)[] { - (2, 4), - (8, 4), - (10, 3), - (16, 4), + static readonly (int @base, int groupSize, string groupSeparator)[] numberBases = new (int, int, string)[] { + (2, 4, " "), + (10, 3, "_"), + (16, 0, string.Empty), }; object Create(IDocumentViewerToolTipProviderContext context, Func toBase) { var provider = context.Create(); @@ -74,26 +73,26 @@ object Create(IDocumentViewerToolTipProviderContext context, Func Create(context, (sb, n) => NumberUtils.ToString(sb, n, value)); - object CreateByte(IDocumentViewerToolTipProviderContext context, byte value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value)); - object CreateInt16(IDocumentViewerToolTipProviderContext context, short value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value)); - object CreateUInt16(IDocumentViewerToolTipProviderContext context, ushort value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value)); - object CreateInt32(IDocumentViewerToolTipProviderContext context, int value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value)); - object CreateUInt32(IDocumentViewerToolTipProviderContext context, uint value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value)); - object CreateInt64(IDocumentViewerToolTipProviderContext context, long value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value)); - object CreateUInt64(IDocumentViewerToolTipProviderContext context, ulong value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value)); + object CreateSByte(IDocumentViewerToolTipProviderContext context, sbyte value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value, sizeof(sbyte))); + object CreateByte(IDocumentViewerToolTipProviderContext context, byte value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value, sizeof(byte))); + object CreateInt16(IDocumentViewerToolTipProviderContext context, short value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value, sizeof(short))); + object CreateUInt16(IDocumentViewerToolTipProviderContext context, ushort value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value, sizeof(ushort))); + object CreateInt32(IDocumentViewerToolTipProviderContext context, int value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value, sizeof(int))); + object CreateUInt32(IDocumentViewerToolTipProviderContext context, uint value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value, sizeof(uint))); + object CreateInt64(IDocumentViewerToolTipProviderContext context, long value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value, sizeof(long))); + object CreateUInt64(IDocumentViewerToolTipProviderContext context, ulong value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value, sizeof(ulong))); - object CreateFloat(IDocumentViewerToolTipProviderContext context, string valueStr, string serializedFormatStr, string serializedValueStr, Func getRawValue) { + object CreateFloat(IDocumentViewerToolTipProviderContext context, string valueStr, string serializedFormatStr, string serializedValueStr, Func getRawValue) { var provider = context.Create(); provider.Image = DsImages.ConstantPublic; - + var sb = new StringBuilder(); provider.Output.Write(BoxedTextColor.Number, valueStr); @@ -104,8 +103,7 @@ object CreateFloat(IDocumentViewerToolTipProviderContext context, string valueSt provider.Output.Write(BoxedTextColor.Number, serializedValueStr); provider.Output.WriteLine(); - var rawValueStr = getRawValue(); - rawValueStr = "0x" + NumberUtils.AddDigitSeparators(sb, rawValueStr, 4, "_"); + var rawValueStr = getRawValue(sb); provider.Output.Write(BoxedTextColor.Text, dnSpy_Resources.RawValue); provider.Output.Write(BoxedTextColor.Text, " "); provider.Output.Write(BoxedTextColor.Number, rawValueStr); @@ -115,16 +113,18 @@ object CreateFloat(IDocumentViewerToolTipProviderContext context, string valueSt object CreateSingle(IDocumentViewerToolTipProviderContext context, float value) { const string format = "G9"; + const bool upper = true; uint rawValue = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0); return CreateFloat(context, value.ToString(), format, value.ToString(format), - () => rawValue.ToString("X8")); + sb => NumberUtils.ToFixedSizeHexadecimalArray(sb, rawValue, 4, upper)); } object CreateDouble(IDocumentViewerToolTipProviderContext context, double value) { const string format = "G17"; + const bool upper = true; ulong rawValue = BitConverter.ToUInt64(BitConverter.GetBytes(value), 0); return CreateFloat(context, value.ToString(), format, value.ToString(format), - () => rawValue.ToString("X16")); + sb => NumberUtils.ToFixedSizeHexadecimalArray(sb, rawValue, 8, upper)); } } } diff --git a/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberUtils.cs b/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberUtils.cs index 2ed156d2df..08f9d394cc 100644 --- a/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberUtils.cs +++ b/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberUtils.cs @@ -23,22 +23,22 @@ You should have received a copy of the GNU General Public License namespace dnSpy.Documents.Tabs.DocViewer.ToolTips { static class NumberUtils { - internal static string ToString(StringBuilder sb, int @base, long value) { - if (value < 0) - return "-" + ToString(sb, @base, (ulong)(-value)); - return ToString(sb, @base, (ulong)value); + internal static string ToString(StringBuilder sb, int @base, long value, int @sizeof) { + if (@base == 10 && value < 0) + return "-" + ToString(sb, @base, (ulong)(-value), @sizeof); + return ToString(sb, @base, unchecked((ulong)value), @sizeof); } - internal static string ToString(StringBuilder sb, int @base, ulong value) { + internal static string ToString(StringBuilder sb, int @base, ulong value, int @sizeof) { const int digits = 0; const bool upper = true; switch (@base) { - case 2: return ToBinary(sb, value, digits); - case 8: return ToOctal(sb, value, digits); - case 10: return value.ToString(); - case 16: return ToHexadecimal(sb, value, digits, upper); - default: throw new ArgumentOutOfRangeException(nameof(@base)); + case 2: return ToBinary(sb, value, digits, @sizeof << 3); + case 8: return ToOctal(sb, value, digits, @sizeof << 2); + case 10: return value.ToString(); + case 16: return ToHexadecimal(sb, value, digits, @sizeof << 1, upper); + default: throw new ArgumentOutOfRangeException(nameof(@base)); } } @@ -60,7 +60,29 @@ internal static string AddDigitSeparators(StringBuilder sb, string rawNumber, in return sb.ToString(); } - static string ToHexadecimal(StringBuilder sb, ulong value, int digits, bool upper) { + internal static string ToFixedSizeHexadecimalArray(StringBuilder sb, ulong value, int bytesCount, bool upper) { + sb.Clear(); + + int digitRemains = bytesCount << 1; + char hexHigh = upper ? (char)('A' - 10) : (char)('a' - 10); + while (digitRemains > 0) { + int digit = (int)(value & 0xF); + value >>= 4; + digitRemains--; + + if (digit > 9) + sb.Append((char)(digit + hexHigh)); + else + sb.Append((char)(digit + '0')); + + if ((digitRemains & 1) == 0 && digitRemains != 0) + sb.Append(' '); + } + + return sb.ToString(); + } + + static string ToHexadecimal(StringBuilder sb, ulong value, int digits, int maxDigits, bool upper) { sb.Clear(); if (digits == 0) { @@ -73,6 +95,9 @@ static string ToHexadecimal(StringBuilder sb, ulong value, int digits, bool uppe } } + if (digits > maxDigits) + digits = maxDigits; + char hexHigh = upper ? (char)('A' - 10) : (char)('a' - 10); for (int i = 0; i < digits; i++) { int digit = (int)((value >> ((digits - i - 1) << 2)) & 0xF); @@ -85,7 +110,7 @@ static string ToHexadecimal(StringBuilder sb, ulong value, int digits, bool uppe return sb.ToString(); } - static string ToOctal(StringBuilder sb, ulong value, int digits) { + static string ToOctal(StringBuilder sb, ulong value, int digits, int maxDigits) { sb.Clear(); if (digits == 0) { @@ -98,6 +123,9 @@ static string ToOctal(StringBuilder sb, ulong value, int digits) { } } + if (digits > maxDigits) + digits = maxDigits; + for (int i = 0; i < digits; i++) { int digit = (int)((value >> (digits - i - 1) * 3) & 7); sb.Append((char)(digit + '0')); @@ -106,7 +134,7 @@ static string ToOctal(StringBuilder sb, ulong value, int digits) { return sb.ToString(); } - static string ToBinary(StringBuilder sb, ulong value, int digits) { + static string ToBinary(StringBuilder sb, ulong value, int digits, int maxDigits) { sb.Clear(); if (digits == 0) { @@ -119,6 +147,9 @@ static string ToBinary(StringBuilder sb, ulong value, int digits) { } } + if (digits > maxDigits) + digits = maxDigits; + for (int i = 0; i < digits; i++) { int digit = (int)((value >> (digits - i - 1)) & 1); sb.Append((char)(digit + '0')); From 447e51bd33a88debf59fb14912d18688e6e649b2 Mon Sep 17 00:00:00 2001 From: Yotic Date: Thu, 17 Jul 2025 08:54:41 +0300 Subject: [PATCH 2/2] NumberUtils.ToFixedSizeHexadecimalArray is slightly optimized --- .../Tabs/DocViewer/ToolTips/NumberUtils.cs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberUtils.cs b/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberUtils.cs index 08f9d394cc..e81627b1a0 100644 --- a/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberUtils.cs +++ b/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberUtils.cs @@ -63,19 +63,25 @@ internal static string AddDigitSeparators(StringBuilder sb, string rawNumber, in internal static string ToFixedSizeHexadecimalArray(StringBuilder sb, ulong value, int bytesCount, bool upper) { sb.Clear(); - int digitRemains = bytesCount << 1; char hexHigh = upper ? (char)('A' - 10) : (char)('a' - 10); - while (digitRemains > 0) { - int digit = (int)(value & 0xF); + while (bytesCount > 0) { + int ldigit = (int)(value & 0xF); value >>= 4; - digitRemains--; + int hdigit = (int)(value & 0xF); + value >>= 4; + bytesCount--; - if (digit > 9) - sb.Append((char)(digit + hexHigh)); + if (hdigit > 9) + sb.Append((char)(hdigit + hexHigh)); else - sb.Append((char)(digit + '0')); + sb.Append((char)(hdigit + '0')); + + if (ldigit > 9) + sb.Append((char)(ldigit + hexHigh)); + else + sb.Append((char)(ldigit + '0')); - if ((digitRemains & 1) == 0 && digitRemains != 0) + if (bytesCount != 0) sb.Append(' '); }