diff --git a/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/CodeBrowserOptions.htm b/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/CodeBrowserOptions.htm
index 59f73b54a7..37cb9db6cc 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/CodeBrowserOptions.htm
+++ b/Ghidra/Features/Base/src/main/help/help/topics/CodeBrowserPlugin/CodeBrowserOptions.htm
@@ -932,7 +932,12 @@
from the Listing Display options panel; select
Underline from the Screen Element list.
-
+ Wrap on Semicolons - Option to wrap operand fields on semicolons. Some processors
+ have multiple sub instructions encoded at the same address. Normally, these are shown on
+ one line and the additional instructions are all shown within the operand field and
+ separated by semicolons. With this option on, each follow on instruction will be displayed
+ on its own line within the operand field.
+
PCode Field
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/processors/generic/PcodeFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/processors/generic/PcodeFieldFactory.java
index bc2996c9bd..46e426ce1e 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/processors/generic/PcodeFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/processors/generic/PcodeFieldFactory.java
@@ -55,7 +55,8 @@ public class PcodeFieldFactory extends FieldFactory {
}
public PcodeFieldFactory(String name, FieldFormatModel model,
- ListingHighlightProvider highlightProvider, Options displayOptions, Options fieldOptions) {
+ ListingHighlightProvider highlightProvider, Options displayOptions,
+ Options fieldOptions) {
super(name, model, highlightProvider, displayOptions, fieldOptions);
setWidth(300);
@@ -67,7 +68,8 @@ public class PcodeFieldFactory extends FieldFactory {
}
@Override
- public FieldFactory newInstance(FieldFormatModel myModel, ListingHighlightProvider highlightProvider,
+ public FieldFactory newInstance(FieldFormatModel myModel,
+ ListingHighlightProvider highlightProvider,
ToolOptions options, ToolOptions fieldOptions) {
return new PcodeFieldFactory(FIELD_NAME, myModel, highlightProvider, options, fieldOptions);
}
@@ -81,7 +83,7 @@ public class PcodeFieldFactory extends FieldFactory {
}
Instruction instr = (Instruction) obj;
- ArrayList elements = new ArrayList<>();
+ List elements = new ArrayList<>();
List pcodeListing = formatter.formatOps(instr.getProgram().getLanguage(),
instr.getProgram().getAddressFactory(), Arrays.asList(instr.getPcode(true)));
@@ -91,9 +93,8 @@ public class PcodeFieldFactory extends FieldFactory {
}
if (elements.size() > 0) {
- FieldElement[] textElements = elements.toArray(new FieldElement[elements.size()]);
- return ListingTextField.createMultilineTextField(this, proxy, textElements,
- startX + varWidth, width, Integer.MAX_VALUE, hlProvider);
+ return ListingTextField.createMultilineTextField(this, proxy, elements,
+ startX + varWidth, width, hlProvider);
}
return null;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AssignedVariableFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AssignedVariableFieldFactory.java
index 41e30d1c11..509be1e955 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AssignedVariableFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/AssignedVariableFieldFactory.java
@@ -50,7 +50,8 @@ public class AssignedVariableFieldFactory extends FieldFactory {
* @param displayOptions the Options for display properties.
* @param fieldOptions the Options for field specific properties.
*/
- private AssignedVariableFieldFactory(FieldFormatModel model, ListingHighlightProvider hsProvider,
+ private AssignedVariableFieldFactory(FieldFormatModel model,
+ ListingHighlightProvider hsProvider,
Options displayOptions, Options fieldOptions) {
super(FIELD_NAME, model, hsProvider, displayOptions, fieldOptions);
}
@@ -70,7 +71,7 @@ public class AssignedVariableFieldFactory extends FieldFactory {
}
CodeUnit cu = (CodeUnit) obj;
- ArrayList elemenetList = new ArrayList<>();
+ ArrayList elements = new ArrayList<>();
Function f = cu.getProgram().getFunctionManager().getFunctionContaining(cu.getMinAddress());
if (f != null) {
@@ -89,19 +90,16 @@ public class AssignedVariableFieldFactory extends FieldFactory {
buf.append(var.getName());
AttributedString as = new AttributedString(buf.toString(),
FunctionColors.VARIABLE_ASSIGNED, getMetrics());
- elemenetList.add(new TextFieldElement(as, 0, 0));
+ elements.add(new TextFieldElement(as, 0, 0));
}
}
}
- if (elemenetList.size() == 0) {
+ if (elements.isEmpty()) {
return null;
}
- FieldElement[] elements = new FieldElement[elemenetList.size()];
- elemenetList.toArray(elements);
-
return ListingTextField.createMultilineTextField(this, proxy, elements, startX + varWidth,
- width, elements.length + 1, hlProvider);
+ width, hlProvider);
}
@Override
@@ -134,7 +132,8 @@ public class AssignedVariableFieldFactory extends FieldFactory {
}
@Override
- public FieldFactory newInstance(FieldFormatModel formatModel, ListingHighlightProvider hsProvider,
+ public FieldFactory newInstance(FieldFormatModel formatModel,
+ ListingHighlightProvider hsProvider,
ToolOptions displayOptions, ToolOptions fieldOptions) {
return new AssignedVariableFieldFactory(formatModel, hsProvider, displayOptions,
fieldOptions);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/EolCommentFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/EolCommentFieldFactory.java
index 884f8a6c45..9a31a1bcd1 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/EolCommentFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/EolCommentFieldFactory.java
@@ -292,11 +292,7 @@ public class EolCommentFieldFactory extends FieldFactory {
elementList.addAll(elements);
}
- FieldElement[] fieldElements = elementList.toArray(new FieldElement[elementList.size()]);
- if (fieldElements.length == 0) {
- return null;
- }
- return ListingTextField.createMultilineTextField(this, proxy, fieldElements, x, width,
+ return ListingTextField.createMultilineTextField(this, proxy, elementList, x, width,
maxDisplayLines, hlProvider);
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionRepeatableCommentFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionRepeatableCommentFieldFactory.java
index 53d2c7bed4..6afa8383dc 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionRepeatableCommentFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/FunctionRepeatableCommentFieldFactory.java
@@ -16,6 +16,8 @@
package ghidra.app.util.viewer.field;
import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
import docking.widgets.fieldpanel.field.AttributedString;
import docking.widgets.fieldpanel.field.FieldElement;
@@ -70,16 +72,16 @@ public class FunctionRepeatableCommentFieldFactory extends FieldFactory {
Function f = (Function) obj;
Program program = f.getProgram();
String[] commentArr = f.getRepeatableCommentAsArray();
- FieldElement[] fields = new FieldElement[commentArr.length];
+ List fields = new ArrayList<>();
AttributedString prototype =
new AttributedString("prototype", CommentColors.REPEATABLE, getMetrics());
for (int i = 0; i < commentArr.length; i++) {
- fields[i] = CommentUtils.parseTextForAnnotations(commentArr[i], program, prototype, i);
+ fields.add(CommentUtils.parseTextForAnnotations(commentArr[i], program, prototype, i));
}
if (commentArr.length > 0) {
return ListingTextField.createMultilineTextField(this, proxy, fields, x, width,
- Integer.MAX_VALUE, hlProvider);
+ hlProvider);
}
return null;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/InstructionMaskValueFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/InstructionMaskValueFieldFactory.java
index 52f4c23d7f..b0efae3004 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/InstructionMaskValueFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/InstructionMaskValueFieldFactory.java
@@ -17,6 +17,8 @@ package ghidra.app.util.viewer.field;
import java.awt.Color;
import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
import docking.widgets.fieldpanel.field.*;
import docking.widgets.fieldpanel.support.FieldLocation;
@@ -52,7 +54,8 @@ public class InstructionMaskValueFieldFactory extends FieldFactory {
* @param displayOptions the Options for display properties.
* @param fieldOptions the Options for field specific properties.
*/
- private InstructionMaskValueFieldFactory(FieldFormatModel model, ListingHighlightProvider hsProvider,
+ private InstructionMaskValueFieldFactory(FieldFormatModel model,
+ ListingHighlightProvider hsProvider,
Options displayOptions, Options fieldOptions) {
super(FIELD_NAME, model, hsProvider, displayOptions, fieldOptions);
}
@@ -88,21 +91,21 @@ public class InstructionMaskValueFieldFactory extends FieldFactory {
}
try {
- FieldElement[] fieldElements = new FieldElement[2 * (operandCount + 1)];
- fieldElements[0] =
- getLine("M[m]: ", instructionMask.getBytes(), MaskColors.BITS, proxy, varWidth);
- fieldElements[1] =
- getLine("V[m]: ", instructionMask.applyMask(instr), MaskColors.VALUE, proxy,
- varWidth);
+ List elements = new ArrayList<>();
+ elements.add(
+ getLine("M[m]: ", instructionMask.getBytes(), MaskColors.BITS, proxy, varWidth));
+ elements.add(getLine("V[m]: ", instructionMask.applyMask(instr), MaskColors.VALUE,
+ proxy, varWidth));
+
for (int i = 0; i < operandCount; i++) {
- fieldElements[2 * (i + 1)] = getLine("M[" + i + "]: ", operandMasks[i].getBytes(),
- MaskColors.BITS, proxy, varWidth);
- fieldElements[2 * (i + 1) + 1] = getLine("V[" + i + "]: ",
- operandMasks[i].applyMask(instr), MaskColors.VALUE, proxy, varWidth);
+ elements.add(getLine("M[" + i + "]: ", operandMasks[i].getBytes(), MaskColors.BITS,
+ proxy, varWidth));
+ elements.add(getLine("V[" + i + "]: ", operandMasks[i].applyMask(instr),
+ MaskColors.VALUE, proxy, varWidth));
}
- return ListingTextField.createMultilineTextField(this, proxy, fieldElements,
- startX + varWidth, width, fieldElements.length, hlProvider);
+ return ListingTextField.createMultilineTextField(this, proxy, elements,
+ startX + varWidth, width, hlProvider);
}
catch (MemoryAccessException e) {
return null;
@@ -165,7 +168,8 @@ public class InstructionMaskValueFieldFactory extends FieldFactory {
}
@Override
- public FieldFactory newInstance(FieldFormatModel formatModel, ListingHighlightProvider hsProvider,
+ public FieldFactory newInstance(FieldFormatModel formatModel,
+ ListingHighlightProvider hsProvider,
ToolOptions toolOptions, ToolOptions fieldOptions) {
return new InstructionMaskValueFieldFactory(formatModel, hsProvider, toolOptions,
fieldOptions);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/LabelFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/LabelFieldFactory.java
index cd5d7b0ee3..a615cfc28c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/LabelFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/LabelFieldFactory.java
@@ -181,8 +181,7 @@ public class LabelFieldFactory extends FieldFactory {
return null;
}
- FieldElement[] textElements = new FieldElement[length];
- int nextPos = 0;
+ List elements = new ArrayList<>(length);
if (hasOffcuts) {
for (Address offcut : offcuts) {
@@ -193,7 +192,7 @@ public class LabelFieldFactory extends FieldFactory {
inspector.getOffcutSymbolColor(),
getMetrics(inspector.getOffcutSymbolStyle()), false, null);
}
- textElements[nextPos++] = new TextFieldElement(as, nextPos, 0);
+ elements.add(new TextFieldElement(as, elements.size(), 0));
}
}
@@ -206,11 +205,11 @@ public class LabelFieldFactory extends FieldFactory {
ColorAndStyle c = inspector.getColorAndStyle(symbol);
AttributedString as = new AttributedString(icon, checkLabelString(symbol, prog),
c.getColor(), getMetrics(c.getStyle()), false, null);
- textElements[nextPos++] = new TextFieldElement(as, nextPos, 0);
+ elements.add(new TextFieldElement(as, elements.size(), 0));
}
- return ListingTextField.createMultilineTextField(this, proxy, textElements, x, width,
- Integer.MAX_VALUE, hlProvider);
+ return ListingTextField.createMultilineTextField(this, proxy, elements, x, width,
+ hlProvider);
}
private String getOffsetText(CodeUnit cu, Address currAddr, Address offcutAddress) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ListingTextField.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ListingTextField.java
index 777f8bc923..b2de120747 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ListingTextField.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/ListingTextField.java
@@ -125,10 +125,10 @@ public class ListingTextField implements ListingField, TextField {
}
/**
- * Displays the given array of text, each on its own line.
+ * Displays the given List of text elements, each on its own line.
* @param factory the field factory that generated this field
* @param proxy the object used to populate this field
- * @param textElements the array of elements for the field.
+ * @param textElements the list of text elements
* Each of these holds text, attributes and location information.
* @param startX the starting X position of the field
* @param width the width of the field
@@ -137,18 +137,36 @@ public class ListingTextField implements ListingField, TextField {
* @return the text field.
*/
public static ListingTextField createMultilineTextField(FieldFactory factory, ProxyObj> proxy,
- FieldElement[] textElements, int startX, int width, int maxLines,
+ List textElements, int startX, int width, int maxLines,
ListingHighlightProvider provider) {
ListingFieldHighlightFactoryAdapter hlFactory =
new ListingFieldHighlightFactoryAdapter(provider);
- List list = Arrays.asList(textElements);
TextField field =
- new VerticalLayoutTextField(list, startX, width, maxLines, hlFactory);
+ new VerticalLayoutTextField(textElements, startX, width, maxLines, hlFactory);
ListingTextField listingField = new ListingTextField(factory, proxy, field, hlFactory);
return listingField;
}
+ /**
+ * Displays the given List of text elements, each on its own line with no max line restriction
+ * @param factory the field factory that generated this field
+ * @param proxy the object used to populate this field
+ * @param textElements the list of text elements
+ * Each of these holds text, attributes and location information.
+ * @param startX the starting X position of the field
+ * @param width the width of the field
+ * @param provider the highlight provider
+ * @return the text field.
+ */
+ public static ListingTextField createMultilineTextField(FieldFactory factory, ProxyObj> proxy,
+ List textElements, int startX, int width,
+ ListingHighlightProvider provider) {
+
+ return ListingTextField.createMultilineTextField(factory, proxy, textElements, startX,
+ width, Integer.MAX_VALUE, provider);
+ }
+
protected ListingTextField(FieldFactory factory, ProxyObj> proxy, TextField field,
ListingFieldHighlightFactoryAdapter hlFactory) {
this.factory = factory;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/MemoryBlockStartFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/MemoryBlockStartFieldFactory.java
index f90778b0f0..457a6082be 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/MemoryBlockStartFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/MemoryBlockStartFieldFactory.java
@@ -56,7 +56,8 @@ public class MemoryBlockStartFieldFactory extends FieldFactory {
* @param displayOptions the Options for display properties.
* @param fieldOptions the Options for field specific properties.
*/
- private MemoryBlockStartFieldFactory(FieldFormatModel model, ListingHighlightProvider hlProvider,
+ private MemoryBlockStartFieldFactory(FieldFormatModel model,
+ ListingHighlightProvider hlProvider,
Options displayOptions, Options fieldOptions) {
super(FIELD_NAME, model, hlProvider, displayOptions, fieldOptions);
}
@@ -85,7 +86,7 @@ public class MemoryBlockStartFieldFactory extends FieldFactory {
}
// Convert the text to field elements.
- FieldElement[] elements = createFieldElements(attributedStrings);
+ List elements = createFieldElements(attributedStrings);
// And put the elements in a text field.
ListingTextField ltf = ListingTextField.createMultilineTextField(this, proxy, elements,
@@ -227,7 +228,7 @@ public class MemoryBlockStartFieldFactory extends FieldFactory {
return lines;
}
- private FieldElement[] createFieldElements(List attributedStrings) {
+ private List createFieldElements(List attributedStrings) {
List elements = new ArrayList<>();
int lineNum = 0;
for (AttributedString line : attributedStrings) {
@@ -235,11 +236,6 @@ public class MemoryBlockStartFieldFactory extends FieldFactory {
elements.add(blockElement);
lineNum++;
}
-
- // Convert to an array
- FieldElement[] elementsArray = new FieldElement[elements.size()];
- elements.toArray(elementsArray);
-
- return elementsArray;
+ return elements;
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/OperandFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/OperandFieldFactory.java
index 10ad68c0c0..55739f8fc2 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/OperandFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/OperandFieldFactory.java
@@ -89,7 +89,8 @@ public class OperandFieldFactory extends OperandFieldHelper {
}
@Override
- public FieldFactory newInstance(FieldFormatModel formatModel, ListingHighlightProvider hsProvider,
+ public FieldFactory newInstance(FieldFormatModel formatModel,
+ ListingHighlightProvider hsProvider,
ToolOptions displayOptions, ToolOptions fieldOptions) {
return new OperandFieldFactory(formatModel, hsProvider, displayOptions, fieldOptions);
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/OperandFieldHelper.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/OperandFieldHelper.java
index c3d456b94f..c1bfcc69bf 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/OperandFieldHelper.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/OperandFieldHelper.java
@@ -48,14 +48,17 @@ import ghidra.util.HelpLocation;
*/
abstract class OperandFieldHelper extends FieldFactory {
- private final static String ENABLE_WORD_WRAP_MSG =
+ private final static String ENABLE_WORD_WRAP_OPTION =
GhidraOptions.OPERAND_GROUP_TITLE + Options.DELIMITER + FieldUtils.WORD_WRAP_OPTION_NAME;
- private final static String MAX_DISPLAY_LINES_MSG =
+ private final static String MAX_DISPLAY_LINES_OPTION =
GhidraOptions.OPERAND_GROUP_TITLE + Options.DELIMITER + "Maximum Lines To Display";
private final static String UNDERLINE_OPTION =
GhidraOptions.OPERAND_GROUP_TITLE + Options.DELIMITER + "Underline References";
private final static String SPACE_AFTER_SEPARATOR_OPTION =
GhidraOptions.OPERAND_GROUP_TITLE + Options.DELIMITER + "Add Space After Separator";
+ private final static String WRAP_ON_SEMICOLON_OPTION =
+ GhidraOptions.OPERAND_GROUP_TITLE + Options.DELIMITER + "Wrap on Semicolons";
+ private final static OperandFieldElement LINE_BREAK = new OperandFieldElement(null, 0, 0, 0);
public enum UNDERLINE_CHOICE {
Hidden, All, None
@@ -75,6 +78,7 @@ abstract class OperandFieldHelper extends FieldFactory {
private boolean isWordWrap = false;
private int maxDisplayLines = 2;
private boolean spaceAfterSeparator = false;
+ private boolean wrapOnSemicolon = false;
protected BrowserCodeUnitFormat codeUnitFormat;
private ChangeListener codeUnitFormatListener = e -> OperandFieldHelper.this.model.update();
@@ -102,9 +106,9 @@ abstract class OperandFieldHelper extends FieldFactory {
setOptions(displayOptions);
HelpLocation hl = new HelpLocation("CodeBrowserPlugin", "Operands_Field");
- fieldOptions.registerOption(ENABLE_WORD_WRAP_MSG, false, hl,
+ fieldOptions.registerOption(ENABLE_WORD_WRAP_OPTION, false, hl,
"Enables word wrapping of strings in the operands field.");
- fieldOptions.registerOption(MAX_DISPLAY_LINES_MSG, 2, hl,
+ fieldOptions.registerOption(MAX_DISPLAY_LINES_OPTION, 2, hl,
"The maximum number of lines used to display the strings in the operands field.");
fieldOptions.registerOption(UNDERLINE_OPTION, UNDERLINE_CHOICE.Hidden, hl,
"Select 'All' to underline any operand field that has a reference; " +
@@ -112,16 +116,16 @@ abstract class OperandFieldHelper extends FieldFactory {
"select 'None' for no underlines.");
fieldOptions.registerOption(SPACE_AFTER_SEPARATOR_OPTION, false, hl,
"Add space between separator and next operand");
+ fieldOptions.registerOption(WRAP_ON_SEMICOLON_OPTION, false, hl,
+ "Wrap operand field on semicolons");
- setMaximumLinesToDisplay(fieldOptions.getInt(MAX_DISPLAY_LINES_MSG, 2), fieldOptions);
- isWordWrap = fieldOptions.getBoolean(ENABLE_WORD_WRAP_MSG, false);
-
+ setMaximumLinesToDisplay(fieldOptions.getInt(MAX_DISPLAY_LINES_OPTION, 2), fieldOptions);
+ isWordWrap = fieldOptions.getBoolean(ENABLE_WORD_WRAP_OPTION, false);
underlineChoice = fieldOptions.getEnum(UNDERLINE_OPTION, UNDERLINE_CHOICE.Hidden);
-
spaceAfterSeparator = fieldOptions.getBoolean(SPACE_AFTER_SEPARATOR_OPTION, false);
+ wrapOnSemicolon = fieldOptions.getBoolean(WRAP_ON_SEMICOLON_OPTION, false);
inspector = new SymbolInspector(displayOptions, null);
- fieldOptions.getOptions(GhidraOptions.OPERAND_GROUP_TITLE).setOptionsHelpLocation(hl);
// Create code unit format and associated options - listen for changes
codeUnitFormat = new BrowserCodeUnitFormat(fieldOptions, true);
@@ -141,22 +145,29 @@ abstract class OperandFieldHelper extends FieldFactory {
Object newValue) {
boolean updateModel = false;
- if (optionName.equals(MAX_DISPLAY_LINES_MSG)) {
- setMaximumLinesToDisplay(((Integer) newValue).intValue(), options);
- updateModel = true;
- }
- else if (optionName.equals(ENABLE_WORD_WRAP_MSG)) {
- isWordWrap = ((Boolean) newValue).booleanValue();
- updateModel = true;
- }
- else if (optionName.equals(UNDERLINE_OPTION)) {
- underlineChoice = (UNDERLINE_CHOICE) newValue;
- updateModel = true;
- }
- else if (optionName.equals(SPACE_AFTER_SEPARATOR_OPTION)) {
- spaceAfterSeparator = ((Boolean) newValue).booleanValue();
- updateModel = true;
+ switch (optionName) {
+ case MAX_DISPLAY_LINES_OPTION:
+ setMaximumLinesToDisplay(((Integer) newValue).intValue(), options);
+ updateModel = true;
+ break;
+ case ENABLE_WORD_WRAP_OPTION:
+ isWordWrap = ((Boolean) newValue).booleanValue();
+ updateModel = true;
+ break;
+ case UNDERLINE_OPTION:
+ underlineChoice = (UNDERLINE_CHOICE) newValue;
+ updateModel = true;
+ break;
+ case SPACE_AFTER_SEPARATOR_OPTION:
+ spaceAfterSeparator = ((Boolean) newValue).booleanValue();
+ updateModel = true;
+ break;
+ case WRAP_ON_SEMICOLON_OPTION:
+ wrapOnSemicolon = ((Boolean) newValue).booleanValue();
+ updateModel = true;
+ break;
}
+
if (updateModel) {
model.update();
}
@@ -165,19 +176,18 @@ abstract class OperandFieldHelper extends FieldFactory {
private void setMaximumLinesToDisplay(int maxLines, Options options) {
if (maxLines < 1) {
maxLines = 1;
- options.setInt(MAX_DISPLAY_LINES_MSG, maxLines);
+ options.setInt(MAX_DISPLAY_LINES_OPTION, maxLines);
}
this.maxDisplayLines = maxLines;
}
- FieldLocation getFieldLocation(BigInteger index, int fieldNum, ListingField bf, int opIndex,
- int column) {
- if (bf instanceof ListingTextField) {
- ListingTextField btf = (ListingTextField) bf;
- RowColLocation rcl = btf.dataToScreenLocation(opIndex, column);
+ FieldLocation getFieldLocation(BigInteger index, int fieldNum, ListingField field,
+ int opIndex, int column) {
+ if (field instanceof ListingTextField listingField) {
+ RowColLocation rcl = listingField.dataToScreenLocation(opIndex, column);
return new FieldLocation(index, fieldNum, rcl.row(), rcl.col());
}
- else if (bf instanceof ImageFactoryField) {
+ else if (field instanceof ImageFactoryField) {
return new FieldLocation(index, fieldNum, 0, 0);
}
return null;
@@ -435,14 +445,50 @@ abstract class OperandFieldHelper extends FieldFactory {
characterOffset = 0;
}
- // There may be operands with no representation objects, so we don't want to create a composite field element.
+ // There may be operands with no representation objects, so we don't want to create a
+ // composite field element.
if (elements.isEmpty()) {
return null;
}
+ if (wrapOnSemicolon) {
+ List lines = breakIntoLines(elements);
+ if (lines.size() == 1) {
+ return ListingTextField.createSingleLineTextField(this, proxy,
+ lines.get(0), startX + varWidth, width, hlProvider);
+ }
+ return ListingTextField.createMultilineTextField(this, proxy, lines, startX, width,
+ hlProvider);
+ }
return ListingTextField.createSingleLineTextField(this, proxy,
new CompositeFieldElement(elements), startX + varWidth, width, hlProvider);
}
+ private List breakIntoLines(List elements) {
+ // This method groups all elements between LINE_BREAK elements into composite elements
+ // where each composite element will be display on its own line.
+ //
+ // It does this by collecting elements in the lineElements list until it find a LINE_BREAK
+ List fieldElements = new ArrayList<>();
+ List lineElements = new ArrayList<>();
+
+ for (OperandFieldElement operandFieldElement : elements) {
+ if (operandFieldElement == LINE_BREAK) {
+ if (!lineElements.isEmpty()) {
+ fieldElements.add(new CompositeFieldElement(lineElements));
+ lineElements.clear();
+ }
+ }
+ else {
+ lineElements.add(operandFieldElement);
+ }
+ }
+ if (!lineElements.isEmpty()) {
+ fieldElements.add(new CompositeFieldElement(lineElements));
+ lineElements.clear();
+ }
+ return fieldElements;
+ }
+
private int addElementsForOperand(Instruction inst, List elements,
int opIndex, OperandRepresentationList opRepList, int characterOffset) {
int subOpIndex = 0;
@@ -493,7 +539,11 @@ abstract class OperandFieldHelper extends FieldFactory {
AttributedString as = new AttributedString(opElem.toString(), attributes.colorAttribute,
getMetrics(attributes.styleAttribute), underline, ListingColors.UNDERLINE);
+
elements.add(new OperandFieldElement(as, opIndex, subOpIndex, characterOffset));
+ if (wrapOnSemicolon && opElem instanceof Character c && c == ';') {
+ elements.add(LINE_BREAK);
+ }
return characterOffset + as.length();
}
@@ -742,5 +792,4 @@ abstract class OperandFieldHelper extends FieldFactory {
operandSubIndex, column);
}
}
-
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/PostCommentFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/PostCommentFieldFactory.java
index aeb541f8b0..f90ffda7bc 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/PostCommentFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/PostCommentFieldFactory.java
@@ -449,26 +449,26 @@ public class PostCommentFieldFactory extends FieldFactory {
(comments.length == 0 || alwaysShowAutomatic) ? autoComment.length : 0;
AttributedString prototypeString =
new AttributedString("prototype", color, getMetrics());
- FieldElement[] fields =
- new FieldElement[comments.length + nLinesAfterBlocks + nLinesAutoComment];
- if (fields.length > 0) {
+ int commentLineCount = comments.length + nLinesAfterBlocks + nLinesAutoComment;
+ List elements = new ArrayList<>(commentLineCount);
+ if (commentLineCount > 0) {
for (int i = 0; i < nLinesAutoComment; i++) {
AttributedString as = new AttributedString(autoComment[i],
CommentColors.AUTO, getMetrics(automaticCommentStyle), false, null);
- fields[i] = new TextFieldElement(as, i, 0);
+ elements.add(new TextFieldElement(as, i, 0));
}
for (int i = 0; i < comments.length; i++) {
int index = nLinesAutoComment + i;
- fields[index] = CommentUtils.parseTextForAnnotations(comments[i],
- instr.getProgram(), prototypeString, index);
+ elements.add(CommentUtils.parseTextForAnnotations(comments[i],
+ instr.getProgram(), prototypeString, index));
}
- for (int i = fields.length - nLinesAfterBlocks; i < fields.length; i++) {
+ for (int i = commentLineCount - nLinesAfterBlocks; i < commentLineCount; i++) {
// add blank lines for end-of-block
AttributedString as = new AttributedString("", color, getMetrics());
- fields[i] = new TextFieldElement(as, i, 0);
+ elements.add(new TextFieldElement(as, i, 0));
}
- return ListingTextField.createMultilineTextField(this, proxy, fields, xStart,
- width, Integer.MAX_VALUE, hlProvider);
+ return ListingTextField.createMultilineTextField(this, proxy, elements, xStart,
+ width, hlProvider);
}
}
}
@@ -516,10 +516,9 @@ public class PostCommentFieldFactory extends FieldFactory {
fields.add(new TextFieldElement(as, fields.size(), 0));
}
}
- FieldElement[] elements = fields.toArray(new FieldElement[fields.size()]);
- return ListingTextField.createMultilineTextField(this, proxy, elements, xStart, width,
- Integer.MAX_VALUE, hlProvider);
+ return ListingTextField.createMultilineTextField(this, proxy, fields, xStart, width,
+ hlProvider);
}
private void init(Options options) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/PreCommentFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/PreCommentFieldFactory.java
index d651af5b2c..b6154b5318 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/PreCommentFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/PreCommentFieldFactory.java
@@ -386,10 +386,8 @@ public class PreCommentFieldFactory extends FieldFactory {
fields = FieldUtils.wrap(fields, width);
}
- FieldElement[] elements = fields.toArray(new FieldElement[fields.size()]);
-
- return ListingTextField.createMultilineTextField(this, proxy, elements, xStart, width,
- Integer.MAX_VALUE, hlProvider);
+ return ListingTextField.createMultilineTextField(this, proxy, fields, xStart, width,
+ hlProvider);
}
private void init(Options options) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/RegisterFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/RegisterFieldFactory.java
index 117db23d66..f53d72e02a 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/RegisterFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/RegisterFieldFactory.java
@@ -199,14 +199,14 @@ public class RegisterFieldFactory extends FieldFactory {
return setRegisters;
}
- private FieldElement[] getFieldElements(String[] registerStrings) {
- FieldElement[] fieldElements = new FieldElement[registerStrings.length];
+ private List getFieldElements(String[] registerStrings) {
+ List elements = new ArrayList<>(registerStrings.length);
for (int i = 0; i < registerStrings.length; i++) {
AttributedString str =
new AttributedString(registerStrings[i], ListingColors.REGISTER, getMetrics());
- fieldElements[i] = new TextFieldElement(str, i, 0);
+ elements.add(new TextFieldElement(str, i, 0));
}
- return fieldElements;
+ return elements;
}
private ListingTextField getTextField(String[] registerStrings, ProxyObj> proxy, int xStart) {
@@ -214,9 +214,9 @@ public class RegisterFieldFactory extends FieldFactory {
return null;
}
- FieldElement[] fieldElements = getFieldElements(registerStrings);
- return ListingTextField.createMultilineTextField(this, proxy, fieldElements, xStart, width,
- Integer.MAX_VALUE, hlProvider);
+ List elements = getFieldElements(registerStrings);
+ return ListingTextField.createMultilineTextField(this, proxy, elements, xStart, width,
+ hlProvider);
}
private class RegComparator implements Comparator {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/RegisterTransitionFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/RegisterTransitionFieldFactory.java
index b2714290b4..f780de1e4d 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/RegisterTransitionFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/RegisterTransitionFieldFactory.java
@@ -55,7 +55,8 @@ public class RegisterTransitionFieldFactory extends FieldFactory {
* @param displayOptions the Options for display properties.
* @param fieldOptions the Options for field specific properties.
*/
- private RegisterTransitionFieldFactory(FieldFormatModel model, ListingHighlightProvider hsProvider,
+ private RegisterTransitionFieldFactory(FieldFormatModel model,
+ ListingHighlightProvider hsProvider,
Options displayOptions, Options fieldOptions) {
super(FIELD_NAME, model, hsProvider, displayOptions, fieldOptions);
initOptions(displayOptions, fieldOptions);
@@ -118,22 +119,22 @@ public class RegisterTransitionFieldFactory extends FieldFactory {
if (stackDepthStr != null) {
numElements++;
}
- FieldElement[] fieldElements = new FieldElement[numElements];
+ List elements = new ArrayList<>(numElements);
for (int i = 0; i < numRegisters; i++) {
Register register = transitionRegisters.get(i);
AttributedString str = new AttributedString(
"assume " + register.getName() + " = " +
getValueString(register, context, curAddress),
ListingColors.REGISTER, getMetrics());
- fieldElements[i] = new TextFieldElement(str, i, 0);
+ elements.add(new TextFieldElement(str, i, 0));
}
if (stackDepthStr != null) {
AttributedString str =
new AttributedString(stackDepthStr, ListingColors.REGISTER, getMetrics());
- fieldElements[numRegisters] = new TextFieldElement(str, numRegisters, 0);
+ elements.add(new TextFieldElement(str, numRegisters, 0));
}
- return ListingTextField.createMultilineTextField(this, proxy, fieldElements,
- startX + varWidth, width, Integer.MAX_VALUE, hlProvider);
+ return ListingTextField.createMultilineTextField(this, proxy, elements,
+ startX + varWidth, width, hlProvider);
}
private String getValueString(Register register, ProgramContext context, Address curAddress) {
@@ -242,7 +243,8 @@ public class RegisterTransitionFieldFactory extends FieldFactory {
}
@Override
- public FieldFactory newInstance(FieldFormatModel fieldFormatModel, ListingHighlightProvider hsProvider,
+ public FieldFactory newInstance(FieldFormatModel fieldFormatModel,
+ ListingHighlightProvider hsProvider,
ToolOptions displayOptions, ToolOptions fieldOptions) {
return new RegisterTransitionFieldFactory(fieldFormatModel, hsProvider, displayOptions,
fieldOptions);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/SpaceFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/SpaceFieldFactory.java
index 039103994b..2e6cc4fd9e 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/SpaceFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/SpaceFieldFactory.java
@@ -16,6 +16,8 @@
package ghidra.app.util.viewer.field;
import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
import docking.widgets.fieldpanel.field.*;
import docking.widgets.fieldpanel.support.FieldLocation;
@@ -78,14 +80,15 @@ public class SpaceFieldFactory extends FieldFactory {
else if (n < 0) {
n = -n;
}
- FieldElement[] fes = new FieldElement[n];
+
+ List elements = new ArrayList<>(n);
AttributedString as = new AttributedString("", Colors.FOREGROUND, getMetrics());
for (int i = 0; i < n; i++) {
- fes[i] = new TextFieldElement(as, 0, 0);
+ elements.add(new TextFieldElement(as, 0, 0));
}
- return ListingTextField.createMultilineTextField(this, proxy, fes, startX + varWidth,
- width, n + 1, hlProvider);
+ return ListingTextField.createMultilineTextField(this, proxy, elements,
+ startX + varWidth, width, hlProvider);
}
return null;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/VariableCommentFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/VariableCommentFieldFactory.java
index d523cd4ad7..ff267a5fb9 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/VariableCommentFieldFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/VariableCommentFieldFactory.java
@@ -16,6 +16,8 @@
package ghidra.app.util.viewer.field;
import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
import docking.widgets.fieldpanel.field.*;
import docking.widgets.fieldpanel.support.FieldLocation;
@@ -69,15 +71,15 @@ public class VariableCommentFieldFactory extends AbstractVariableFieldFactory {
String comment = sv.getComment();
String[] comments = StringUtilities.toLines(comment);
if ((comments != null) && (comments.length > 0)) {
- FieldElement[] fields = new FieldElement[comments.length];
+ List elements = new ArrayList<>(comments.length);
for (int i = 0; i < comments.length; i++) {
AttributedString as =
new AttributedString(comments[i], getColor(sv), getMetrics(sv));
- fields[i] = new TextFieldElement(as, i, 0);
+ elements.add(new TextFieldElement(as, i, 0));
}
- return ListingTextField.createMultilineTextField(this, proxy, fields, startX + varWidth,
- width, Integer.MAX_VALUE, hlProvider);
+ return ListingTextField.createMultilineTextField(this, proxy, elements,
+ startX + varWidth, width, hlProvider);
}
return null;
}
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/codebrowser/CodeBrowserOptionsTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/codebrowser/CodeBrowserOptionsTest.java
index 503137cc9d..02429d5a34 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/codebrowser/CodeBrowserOptionsTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/codebrowser/CodeBrowserOptionsTest.java
@@ -745,7 +745,7 @@ public class CodeBrowserOptionsTest extends AbstractGhidraHeadedIntegrationTest
loadProgram();
Options options = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
List names = getOptionNames(options, "Operands Field");
- assertEquals(15, names.size());
+ assertEquals(16, names.size());
assertEquals("Operands Field.Add Space After Separator", names.get(0));
assertEquals("Operands Field.Always Show Primary Reference", names.get(1));
assertEquals("Operands Field.Display Abbreviated Default Label Names", names.get(2));
@@ -761,6 +761,7 @@ public class CodeBrowserOptionsTest extends AbstractGhidraHeadedIntegrationTest
assertEquals("Operands Field.Show Block Names", names.get(12));
assertEquals("Operands Field.Show Offcut Information", names.get(13));
assertEquals("Operands Field.Underline References", names.get(14));
+ assertEquals("Operands Field.Wrap on Semicolons", names.get(15));
NamespaceWrappedOption namespaceOption =
(NamespaceWrappedOption) options.getCustomOption(names.get(3),
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/VerticalLayoutTextField.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/VerticalLayoutTextField.java
index 1001e70a1e..1bc36c28e2 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/VerticalLayoutTextField.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/VerticalLayoutTextField.java
@@ -492,11 +492,19 @@ public class VerticalLayoutTextField implements TextField {
@Override
public RowColLocation dataToScreenLocation(int dataRow, int dataColumn) {
- FieldRow fieldRow = getFieldRowFromDataRow(dataRow);
- TextField field = fieldRow.field;
- RowColLocation location = field.dataToScreenLocation(dataRow, dataColumn);
- int screenRow = fieldRow.screenRow;
- return location.withRow(screenRow);
+ // search each line looking for a match for the given row and column
+ for (int i = 0; i < subFields.size(); i++) {
+ FieldRow row = subFields.get(i);
+ RowColLocation loc = row.field.dataToScreenLocation(dataRow, dataColumn);
+
+ // A DefaultRowColLocation means that the line did not have an exact match for
+ // the dataRow and dataColumn, so need to keep looking at each line.
+ if (!(loc instanceof DefaultRowColLocation)) {
+ return new RowColLocation(i, loc.col());
+ }
+ }
+ // We did not find a match for the given row and column, so return a default location of 0,0
+ return new DefaultRowColLocation();
}
@Override
diff --git a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/VerticalLayoutTextFieldTest.java b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/VerticalLayoutTextFieldTest.java
index 9325668b2c..434a363133 100644
--- a/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/VerticalLayoutTextFieldTest.java
+++ b/Ghidra/Framework/Docking/src/test/java/docking/widgets/fieldpanel/VerticalLayoutTextFieldTest.java
@@ -92,7 +92,7 @@ public class VerticalLayoutTextFieldTest extends AbstractGenericTest {
assertEquals(new RowColLocation(2, 0), field.dataToScreenLocation(2, 0));
assertEquals(new RowColLocation(2, 4), field.dataToScreenLocation(2, 4));
assertEquals(new RowColLocation(2, 12), field.dataToScreenLocation(2, 12));
- assertEquals(new DefaultRowColLocation(2, 12), field.dataToScreenLocation(2, 15));
+ assertEquals(new DefaultRowColLocation(0, 0), field.dataToScreenLocation(2, 15));
assertEquals(new RowColLocation(3, 0), field.dataToScreenLocation(3, 0));
assertEquals(new RowColLocation(3, 4), field.dataToScreenLocation(3, 4));