Merge remote-tracking branch 'origin/GP-4289_ghidragon_wrap_operands_on_semicolon--SQUASHED'

This commit is contained in:
Ryan Kurtz 2024-04-04 12:39:06 -04:00
commit 77aa79caf1
20 changed files with 221 additions and 138 deletions

View File

@ -932,7 +932,12 @@
from the <I><A href="#Listing_Display">Listing Display</A></I> options panel; select
<I>Underline</I> from the <I>Screen Element</I> list.</P>
</BLOCKQUOTE>
</BLOCKQUOTE>
<P><B>Wrap on Semicolons -</B> 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.
</P> </BLOCKQUOTE>
<H3><A name="Pcode_Field"></A>PCode Field</H3>

View File

@ -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<TextFieldElement> elements = new ArrayList<>();
List<FieldElement> elements = new ArrayList<>();
List<AttributedString> 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;
}

View File

@ -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<FieldElement> elemenetList = new ArrayList<>();
ArrayList<FieldElement> 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);

View File

@ -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);
}

View File

@ -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<FieldElement> 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;
}

View File

@ -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<FieldElement> 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);

View File

@ -181,8 +181,7 @@ public class LabelFieldFactory extends FieldFactory {
return null;
}
FieldElement[] textElements = new FieldElement[length];
int nextPos = 0;
List<FieldElement> 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) {

View File

@ -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<FieldElement> textElements, int startX, int width, int maxLines,
ListingHighlightProvider provider) {
ListingFieldHighlightFactoryAdapter hlFactory =
new ListingFieldHighlightFactoryAdapter(provider);
List<FieldElement> 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<FieldElement> 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;

View File

@ -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<FieldElement> 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<AttributedString> attributedStrings) {
private List<FieldElement> createFieldElements(List<AttributedString> attributedStrings) {
List<FieldElement> 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;
}
}

View File

@ -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);
}

View File

@ -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<FieldElement> 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<FieldElement> breakIntoLines(List<OperandFieldElement> 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<FieldElement> fieldElements = new ArrayList<>();
List<OperandFieldElement> 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<OperandFieldElement> 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);
}
}
}

View File

@ -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<FieldElement> 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) {

View File

@ -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) {

View File

@ -199,14 +199,14 @@ public class RegisterFieldFactory extends FieldFactory {
return setRegisters;
}
private FieldElement[] getFieldElements(String[] registerStrings) {
FieldElement[] fieldElements = new FieldElement[registerStrings.length];
private List<FieldElement> getFieldElements(String[] registerStrings) {
List<FieldElement> 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<FieldElement> elements = getFieldElements(registerStrings);
return ListingTextField.createMultilineTextField(this, proxy, elements, xStart, width,
hlProvider);
}
private class RegComparator implements Comparator<Register> {

View File

@ -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<FieldElement> 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);

View File

@ -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<FieldElement> 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;

View File

@ -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<FieldElement> 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;
}

View File

@ -745,7 +745,7 @@ public class CodeBrowserOptionsTest extends AbstractGhidraHeadedIntegrationTest
loadProgram();
Options options = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_FIELDS);
List<String> 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),

View File

@ -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

View File

@ -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));