diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.cc index 009d5bbb64..4b687b53f1 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/prettyprint.cc @@ -595,11 +595,21 @@ void EmitPrettyPrint::overflow(void) else break; } + int4 newspaceremain; if (!indentstack.empty()) - spaceremain = indentstack.back(); + newspaceremain = indentstack.back(); else - spaceremain = maxlinesize; + newspaceremain = maxlinesize; + if (newspaceremain == spaceremain) + return; // Line breaking doesn't give us any additional space + if (commentmode && (newspaceremain == spaceremain + commentfill.size())) + return; // Line breaking doesn't give us any additional space + spaceremain = newspaceremain; lowlevel->tagLine(maxlinesize-spaceremain); + if (commentmode &&(commentfill.size() != 0)) { + lowlevel->print(commentfill.c_str(),EmitXml::comment_color); + spaceremain -= commentfill.size(); + } } /// Content and markup is sent to the low-level emitter if appropriate. The diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/ClangTextField.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/ClangTextField.java index c8c82e6f3f..cf04541e90 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/ClangTextField.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/ClangTextField.java @@ -44,7 +44,7 @@ public class ClangTextField extends WrappingVerticalLayoutTextField { * * @param initialX The original x value passed to the constructor of this class * @param lineNumberElement he line number element for this field from which we get a width - * @return + * @return the calculated offset */ private static int calculateXPositionWithLineNumberOffset(int initialX, FieldElement lineNumberElement) { @@ -70,7 +70,7 @@ public class ClangTextField extends WrappingVerticalLayoutTextField { FieldElement lineNumberFieldElement, int x, int width, HighlightFactory hlFactory) { super(createSingleLineElement(fieldElements), calculateXPositionWithLineNumberOffset(x, lineNumberFieldElement), - calculateWidthFromXPosition(x, lineNumberFieldElement, width), 30, hlFactory); + calculateWidthFromXPosition(x, lineNumberFieldElement, width), 30, hlFactory, false); this.tokenList = tokenList; this.lineNumberFieldElement = lineNumberFieldElement; } @@ -157,8 +157,8 @@ public class ClangTextField extends WrappingVerticalLayoutTextField { } @Override - public void paint(JComponent c, Graphics g, PaintContext context, - Rectangle clip, FieldBackgroundColorManager selectionMap, RowColLocation cursorLoc, int rowHeight) { + public void paint(JComponent c, Graphics g, PaintContext context, Rectangle clip, + FieldBackgroundColorManager selectionMap, RowColLocation cursorLoc, int rowHeight) { // Don't print line numbers; don't copy line numbers. We are assuming that the user only // wants to copy code. diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/WrappingVerticalLayoutTextField.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/WrappingVerticalLayoutTextField.java index 9123414861..2244301df5 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/WrappingVerticalLayoutTextField.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/WrappingVerticalLayoutTextField.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,35 +17,46 @@ package docking.widgets.fieldpanel.field; import docking.widgets.fieldpanel.support.*; - public class WrappingVerticalLayoutTextField extends VerticalLayoutTextField { - - /** - * This constructor will create a text field from an single AttributedString. The string will - * be word wrapped. - * - * @param textElement the AttributedString to display - * @param startX the x position to draw the string - * @param width the max width allocated to this field - * @param maxLines the max number of lines to display - * @param hlFactory the highlight factory - */ - public WrappingVerticalLayoutTextField(FieldElement textElement, - int startX, - int width, - int maxLines, - HighlightFactory hlFactory) { - - super(FieldUtils.wrap(textElement, width), startX, width, maxLines, hlFactory, ""); - } - /** + /** + * This constructor will create a text field from an single AttributedString. The string will + * be word wrapped. + * + * @param textElement the AttributedString to display + * @param startX the x position to draw the string + * @param width the max width allocated to this field + * @param maxLines the max number of lines to display + * @param hlFactory the highlight factory + */ + public WrappingVerticalLayoutTextField(FieldElement textElement, int startX, int width, + int maxLines, HighlightFactory hlFactory) { + + super(FieldUtils.wrap(textElement, width), startX, width, maxLines, hlFactory, ""); + } + + /** + * Create a text field from a single FieldElement. The text is wrapped, either an words or simply + * @param textElement is the element to display + * @param startX is the position to draw the string + * @param width is the max width allocated to this field + * @param maxLines is the max number of lines to display + * @param hlFactory is the highlight factory + * @param breakOnWhiteSpace is true if wrapping should break on word boundaries + */ + public WrappingVerticalLayoutTextField(FieldElement textElement, int startX, int width, + int maxLines, HighlightFactory hlFactory, boolean breakOnWhiteSpace) { + super(FieldUtils.wrap(textElement, width, breakOnWhiteSpace), startX, width, maxLines, + hlFactory, ""); + } + + /** * Finds the corresponding row, column for string index, and offset * @param index index into the string array * @param offset offset into the indexed string. */ - @Override - public RowColLocation dataToScreenLocation(int index, int offset) { - return textOffsetToScreenLocation(offset); - } + @Override + public RowColLocation dataToScreenLocation(int index, int offset) { + return textOffsetToScreenLocation(offset); + } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/support/FieldUtils.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/support/FieldUtils.java index f93835d8fc..5e0ddbab88 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/support/FieldUtils.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/support/FieldUtils.java @@ -31,7 +31,7 @@ public class FieldUtils { } public static List wrap(List fieldElements, int width) { - List wrappedElements = new ArrayList(); + List wrappedElements = new ArrayList<>(); for (FieldElement fieldElement : fieldElements) { wrappedElements.addAll(wordWrapList(fieldElement, width)); } @@ -52,7 +52,7 @@ public class FieldUtils { return new FieldElement[] { originalFieldElement }; } - List lines = new ArrayList(); + List lines = new ArrayList<>(); int wordWrapPos = findWordWrapPosition(originalFieldElement, width); while (wordWrapPos > 0) { lines.add(originalFieldElement.substring(0, wordWrapPos)); @@ -66,6 +66,42 @@ public class FieldUtils { return lines.toArray(new FieldElement[lines.size()]); } + /** + * Splits the given FieldElement into sub-elements by wrapping the element in some fashion. + * If breakOnWhiteSpace is indicated, wrapping will break lines on a white space character + * if possible, otherwise wrapping occurs on the last possible character. + * @param fieldElement is the element to wrap + * @param width is the maximum width to allow before wrapping + * @param breakOnWhiteSpace determines whether line breaks should happen at white space chars + * @return the wrapped elements + */ + public static FieldElement[] wrap(FieldElement fieldElement, int width, + boolean breakOnWhiteSpace) { + if (breakOnWhiteSpace) { + return wrap(fieldElement, width); + } + FieldElement originalFieldElement = fieldElement.replaceAll(WHITE_SPACE, ' '); + if (originalFieldElement.getStringWidth() <= width) { + return new FieldElement[] { originalFieldElement }; + } + + List lines = new ArrayList<>(); + int wordWrapPos = originalFieldElement.getMaxCharactersForWidth(width); + if (wordWrapPos == originalFieldElement.length()) { + wordWrapPos = 0; + } + while (wordWrapPos > 0) { + lines.add(originalFieldElement.substring(0, wordWrapPos)); + originalFieldElement = originalFieldElement.substring(wordWrapPos); + wordWrapPos = originalFieldElement.getMaxCharactersForWidth(width); + if (wordWrapPos == originalFieldElement.length()) { + wordWrapPos = 0; + } + } + lines.add(originalFieldElement); + return lines.toArray(new FieldElement[lines.size()]); + } + /** * Splits the given FieldElement into sub-elements by wrapping the element on whitespace. * @@ -74,7 +110,7 @@ public class FieldUtils { * @return The wrapped elements */ public static List wordWrapList(FieldElement fieldElement, int width) { - List lines = new ArrayList(); + List lines = new ArrayList<>(); FieldElement originalFieldElement = fieldElement.replaceAll(WHITE_SPACE, ' '); if (originalFieldElement.getStringWidth() <= width) {