Skip to content

Commit 158b2af

Browse files
committed
Fix doubling spaces on wrapped strings
1 parent 72fc065 commit 158b2af

File tree

4 files changed

+53
-9
lines changed

4 files changed

+53
-9
lines changed

binaryninjaapi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14275,6 +14275,7 @@ namespace BinaryNinja {
1427514275
size_t minimumContentLength;
1427614276
size_t tabWidth;
1427714277
size_t maximumAnnotationLength;
14278+
size_t stringWrappingWidth;
1427814279
std::string languageName;
1427914280
std::string commentStartString;
1428014281
std::string commentEndString;

binaryninjacore.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3670,6 +3670,7 @@ extern "C"
36703670
size_t minimumContentLength;
36713671
size_t tabWidth;
36723672
size_t maximumAnnotationLength;
3673+
size_t stringWrappingWidth;
36733674
char* languageName;
36743675
char* commentStartString;
36753676
char* commentEndString;

formatter/generic/genericformatter.cpp

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ struct ItemLayoutStackEntry
203203
size_t additionalContinuationIndentation;
204204
size_t desiredWidth;
205205
size_t desiredContinuationWidth;
206+
size_t desiredStringWidth;
207+
size_t desiredStringContinuationWidth;
206208
bool newLineOnReenteringScope;
207209
};
208210

@@ -318,7 +320,18 @@ static vector<InstructionTextToken> ParseStringToken(
318320
ConstructToken(start, curEnd);
319321
curStart = curEnd;
320322
}
321-
else if (c == ',' || c == '.' || c == ':' || c == ';' || isspace(c))
323+
else if (isspace(c))
324+
{
325+
// Flush before whitespace
326+
flushToken(curStart, curEnd);
327+
328+
size_t start = curEnd;
329+
while (curEnd < tail && isspace(src[curEnd]))
330+
curEnd++;
331+
ConstructToken(start, curEnd);
332+
curStart = curEnd;
333+
}
334+
else if (c == ',' || c == '.' || c == ':' || c == ';')
322335
{
323336
// Flush before punctuation
324337
flushToken(curStart, curEnd);
@@ -731,6 +744,24 @@ vector<DisassemblyTextLine> GenericLineFormatter::FormatLines(
731744
desiredContinuationWidth = remainingWidth;
732745
}
733746

747+
// Compute target string width for this line
748+
size_t desiredStringWidth = settings.stringWrappingWidth;
749+
if (indentation < settings.desiredLineLength)
750+
{
751+
size_t remainingStringWidth = desiredStringWidth - indentation;
752+
if (remainingStringWidth > desiredStringWidth)
753+
desiredStringWidth = remainingStringWidth;
754+
}
755+
756+
// Compute target width for continuation string wrapping lines
757+
size_t desiredStringContinuationWidth = settings.stringWrappingWidth;
758+
if (continuationIndentation < settings.desiredLineLength)
759+
{
760+
size_t remainingStringWidth = desiredStringContinuationWidth - continuationIndentation;
761+
if (remainingStringWidth > desiredStringContinuationWidth)
762+
desiredStringContinuationWidth = remainingStringWidth;
763+
}
764+
734765
// Gather the indentation tokens at the beginning of the line
735766
vector<InstructionTextToken> indentationTokens = currentLine.GetAddressAndIndentationTokens();
736767
size_t tokenIndex = indentationTokens.size();
@@ -831,7 +862,7 @@ vector<DisassemblyTextLine> GenericLineFormatter::FormatLines(
831862
string trimmedSubText = TrimString(subToken.text);
832863
if (trimmedSubText.empty())
833864
items.push_back(Item {StringWhitespace, {}, {subToken}, 0});
834-
if (trimmedSubText[0] == '%')
865+
else if (trimmedSubText[0] == '%')
835866
items.push_back(Item {FormatSpecifier, {}, {subToken}, 0});
836867
else if (!trimmedSubText.empty() && trimmedSubText[0] == '\\')
837868
items.push_back(Item {EscapeSequence, {}, {subToken}, 0});
@@ -892,7 +923,7 @@ vector<DisassemblyTextLine> GenericLineFormatter::FormatLines(
892923
bool firstTokenOfLine = true;
893924

894925
stack<ItemLayoutStackEntry> layoutStack;
895-
layoutStack.push({items, additionalContinuationIndentation, desiredWidth, desiredContinuationWidth, false});
926+
layoutStack.push({items, additionalContinuationIndentation, desiredWidth, desiredContinuationWidth, desiredStringWidth, desiredStringContinuationWidth, false});
896927

897928
auto newLine = [&]() {
898929
if (!firstTokenOfLine)
@@ -917,6 +948,7 @@ vector<DisassemblyTextLine> GenericLineFormatter::FormatLines(
917948
outputLine.tokens.emplace_back(TextToken, string(additionalContinuationIndentation, ' '));
918949
currentWidth = 0;
919950
desiredWidth = desiredContinuationWidth;
951+
desiredStringWidth = desiredStringContinuationWidth;
920952
firstTokenOfLine = true;
921953
};
922954

@@ -929,6 +961,8 @@ vector<DisassemblyTextLine> GenericLineFormatter::FormatLines(
929961
additionalContinuationIndentation = layoutStackEntry.additionalContinuationIndentation;
930962
desiredWidth = layoutStackEntry.desiredWidth;
931963
desiredContinuationWidth = layoutStackEntry.desiredContinuationWidth;
964+
desiredStringWidth = layoutStackEntry.desiredStringWidth;
965+
desiredStringContinuationWidth = layoutStackEntry.desiredStringContinuationWidth;
932966

933967
// Check to see if the scope we are returning to needs a new line. This is used when an argument
934968
// spans multiple lines. The rest of the arguments are placed on separate lines from the long argument.
@@ -937,13 +971,14 @@ vector<DisassemblyTextLine> GenericLineFormatter::FormatLines(
937971

938972
for (auto item = items.begin(); item != items.end();)
939973
{
940-
if (item->type == StringComponent && currentWidth + item->width > desiredWidth)
974+
if (item->type == StringComponent && currentWidth + item->width > desiredStringWidth)
941975
{
942976
// If a string is too wide to fit on the current line, create a newline
943977
// without additional indentation
944978
newLine();
979+
continue;
945980
}
946-
else if (currentWidth + item->width > desiredWidth && item->type != StringWhitespace)
981+
if (currentWidth + item->width > desiredWidth && item->type != StringWhitespace)
947982
{
948983
// Current item is too wide to fit on the current line, will need to start a new line.
949984
// Whitespace is allowed to be too wide; we push it on as the preceding word is wrapped.
@@ -962,7 +997,7 @@ vector<DisassemblyTextLine> GenericLineFormatter::FormatLines(
962997
if (next != items.end())
963998
{
964999
layoutStack.push({vector(next, items.end()), additionalContinuationIndentation,
965-
desiredWidth, desiredContinuationWidth, true});
1000+
desiredWidth, desiredContinuationWidth, desiredStringWidth, desiredStringContinuationWidth, true});
9661001
}
9671002

9681003
newLine();
@@ -973,8 +1008,13 @@ vector<DisassemblyTextLine> GenericLineFormatter::FormatLines(
9731008
else
9741009
desiredContinuationWidth -= settings.tabWidth;
9751010

1011+
if (desiredStringContinuationWidth < settings.minimumContentLength + settings.tabWidth)
1012+
desiredStringContinuationWidth = settings.minimumContentLength;
1013+
else
1014+
desiredStringContinuationWidth -= settings.tabWidth;
1015+
9761016
layoutStack.push({item->items, additionalContinuationIndentation, desiredWidth,
977-
desiredContinuationWidth, false});
1017+
desiredContinuationWidth, desiredStringWidth, desiredStringContinuationWidth, false});
9781018
break;
9791019
}
9801020

@@ -984,10 +1024,10 @@ vector<DisassemblyTextLine> GenericLineFormatter::FormatLines(
9841024
if (next != items.end())
9851025
{
9861026
layoutStack.push({vector(next, items.end()), additionalContinuationIndentation,
987-
desiredWidth, desiredContinuationWidth, false});
1027+
desiredWidth, desiredContinuationWidth, desiredStringWidth, desiredStringContinuationWidth, false});
9881028
}
9891029
layoutStack.push({item->items, additionalContinuationIndentation, desiredWidth,
990-
desiredContinuationWidth, false});
1030+
desiredContinuationWidth, desiredStringWidth, desiredStringContinuationWidth, false});
9911031
break;
9921032
}
9931033

lineformatter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ LineFormatterSettings LineFormatterSettings::FromAPIObject(const BNLineFormatter
5454
result.minimumContentLength = settings->minimumContentLength;
5555
result.tabWidth = settings->tabWidth;
5656
result.maximumAnnotationLength = settings->maximumAnnotationLength;
57+
result.stringWrappingWidth = settings->stringWrappingWidth;
5758
result.languageName = settings->languageName;
5859
result.commentStartString = settings->commentStartString;
5960
result.commentEndString = settings->commentEndString;
@@ -71,6 +72,7 @@ BNLineFormatterSettings LineFormatterSettings::ToAPIObject() const
7172
result.minimumContentLength = minimumContentLength;
7273
result.tabWidth = tabWidth;
7374
result.maximumAnnotationLength = maximumAnnotationLength;
75+
result.stringWrappingWidth = stringWrappingWidth;
7476
result.languageName = (char*)languageName.c_str();
7577
result.commentStartString = (char*)commentStartString.c_str();
7678
result.commentEndString = (char*)commentEndString.c_str();

0 commit comments

Comments
 (0)