From 1626d2ee1be756ed459e2f1592f3d25f4034d4d0 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Mon, 1 Apr 2019 18:25:05 -0400 Subject: [PATCH] GT-2716 - Decompiler - Fixed 'Find' highlight ghosts --- .../app/plugin/core/byteviewer/ByteField.java | 8 +++--- .../decompiler/component/ClangTextField.java | 5 ++++ .../decompiler/component/DecompilerPanel.java | 25 +++++++++++++++++- .../actions/FieldBasedSearchLocation.java | 6 ++++- .../core/decompile/actions/FindAction.java | 10 ++++++- .../java/docking/widgets/SearchLocation.java | 7 +++-- .../fieldpanel/field/ClippingTextField.java | 15 +++++------ .../field/ReverseClippingTextField.java | 18 ++++++------- .../fieldpanel/field/SimpleTextField.java | 11 ++++---- .../field/VerticalLayoutTextField.java | 2 +- .../fieldpanel/support/HighlightFactory.java | 26 +++++++++++++++---- 11 files changed, 94 insertions(+), 39 deletions(-) diff --git a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteField.java b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteField.java index b2e3dbd969..db7371f355 100644 --- a/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteField.java +++ b/Ghidra/Features/ByteViewer/src/main/java/ghidra/app/plugin/core/byteviewer/ByteField.java @@ -15,8 +15,6 @@ */ package ghidra.app.plugin.core.byteviewer; -import ghidra.util.ColorUtils; - import java.awt.*; import java.math.BigInteger; @@ -28,6 +26,7 @@ import docking.widgets.fieldpanel.internal.FieldBackgroundColorManager; import docking.widgets.fieldpanel.internal.PaintContext; import docking.widgets.fieldpanel.support.HighlightFactory; import docking.widgets.fieldpanel.support.RowColLocation; +import ghidra.util.ColorUtils; /** * Fields for the ByteViewer. This class extends the SimpleTextField to include @@ -52,7 +51,8 @@ public class ByteField extends SimpleTextField { * @param hlFactory the factory used to create highlights */ public ByteField(String text, FontMetrics fontMetrics, int startX, int width, - boolean allowCursorAtEnd, int fieldOffset, BigInteger index, HighlightFactory hlFactory) { + boolean allowCursorAtEnd, int fieldOffset, BigInteger index, + HighlightFactory hlFactory) { super(text, fontMetrics, startX, width, allowCursorAtEnd, hlFactory); this.fieldOffset = fieldOffset; @@ -64,7 +64,7 @@ public class ByteField extends SimpleTextField { public void paint(JComponent c, Graphics g, PaintContext context, FieldBackgroundColorManager colorManager, RowColLocation cursorLoc, int rowHeight) { paintSelection(g, colorManager, 0); - paintHighlights(g, hlFactory.getHighlights(text, -1)); + paintHighlights(g, hlFactory.getHighlights(this, text, -1)); g.setFont(metrics.getFont()); if (foregroundColor == null) { foregroundColor = context.getForeground(); 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 46020f53ca..4968cf02c6 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 @@ -1,5 +1,6 @@ /* ### * 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. @@ -197,4 +198,8 @@ public class ClangTextField extends WrappingVerticalLayoutTextField { return lineNumberFieldElement.getStringWidth(); } + public int getLineNumber() { + String text = lineNumberFieldElement.getText().trim(); + return Integer.parseInt(text); + } } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerPanel.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerPanel.java index aed2123de5..d178ad955a 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerPanel.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/component/DecompilerPanel.java @@ -1,5 +1,6 @@ /* ### * 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. @@ -37,6 +38,7 @@ import docking.widgets.indexedscrollpane.IndexedScrollPane; import ghidra.app.decompiler.*; import ghidra.app.decompiler.component.hover.DecompilerHoverService; import ghidra.app.plugin.core.decompile.DecompileClipboardProvider; +import ghidra.app.plugin.core.decompile.actions.FieldBasedSearchLocation; import ghidra.program.model.address.*; import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Program; @@ -175,6 +177,9 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field if (clipboard != null) { clipboard.selectionChanged(null); } + + // don't highlight search results across functions + currentSearchLocation = null; } private void setLocation(DecompileData oldData, DecompileData newData) { @@ -696,9 +701,27 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field } class SearchHighlightFactory implements HighlightFactory { + @Override public Highlight[] getHighlights(String text, int cursorTextOffset) { - if (currentSearchLocation == null || cursorTextOffset == -1) { + // the search highlight needs the Field in order to work correctly + return new Highlight[0]; + } + + @Override + public Highlight[] getHighlights(Field field, String text, int cursorTextOffset) { + if (currentSearchLocation == null) { + return new Highlight[0]; + } + + ClangTextField cField = (ClangTextField) field; + int highlightLine = cField.getLineNumber(); + + FieldLocation searchCursorLocation = + ((FieldBasedSearchLocation) currentSearchLocation).getFieldLocation(); + int searchLineNumber = searchCursorLocation.getIndex().intValue() + 1; + if (highlightLine != searchLineNumber) { + // only highlight the match on the actual line return new Highlight[0]; } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FieldBasedSearchLocation.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FieldBasedSearchLocation.java index 0d1434155c..191c32cc21 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FieldBasedSearchLocation.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FieldBasedSearchLocation.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. @@ -39,4 +38,9 @@ public class FieldBasedSearchLocation extends SearchLocation { public CursorPosition getCursorPosition() { return new DecompilerCursorPosition(fieldLocation); } + + @Override + protected String fieldsToString() { + return super.fieldsToString() + ", fieldLocation=" + fieldLocation; + } } diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FindAction.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FindAction.java index 78c48a7cf4..70b23623e0 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FindAction.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/actions/FindAction.java @@ -1,5 +1,6 @@ /* ### * 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. @@ -77,13 +78,20 @@ public class FindAction extends DockingAction { if (text != null) { dialog.setSearchText(text); } + // show over the root frame, so the user can still see the Decompiler window tool.showDialog(dialog); } protected FindDialog getFindDialog() { if (findDialog == null) { - findDialog = new FindDialog("Decompiler Find Text", new DecompilerSearcher()); + findDialog = new FindDialog("Decompiler Find Text", new DecompilerSearcher()) { + @Override + protected void dialogClosed() { + // clear the search results when the dialog is closed + decompilerPanel.setSearchResults(null); + } + }; findDialog.setHelpLocation(new HelpLocation("DecompilePlugin", "Find")); } return findDialog; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/SearchLocation.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/SearchLocation.java index 9dd7087fe0..064f241389 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/SearchLocation.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/SearchLocation.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. @@ -60,6 +59,10 @@ public class SearchLocation { @Override public String toString() { - return searchText + "[start=" + startIndexInclusive + ", end=" + endIndexInclusive + "]"; + return searchText + "[" + fieldsToString() + "]"; + } + + protected String fieldsToString() { + return startIndexInclusive + ", end=" + endIndexInclusive; } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/ClippingTextField.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/ClippingTextField.java index 506e1f8667..bb25ba0477 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/ClippingTextField.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/ClippingTextField.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. @@ -129,8 +128,8 @@ public class ClippingTextField implements TextField { int x = findX(col) + startX; - return new Rectangle(x, -textElement.getHeightAbove(), 2, textElement.getHeightAbove() + - textElement.getHeightBelow()); + return new Rectangle(x, -textElement.getHeightAbove(), 2, + textElement.getHeightAbove() + textElement.getHeightBelow()); } /** @@ -315,7 +314,7 @@ public class ClippingTextField implements TextField { if (cursorLoc != null) { cursorTextOffset = screenLocationToTextOffset(cursorLoc.row(), cursorLoc.col()); } - paintHighlights(g, hlFactory.getHighlights(getString(), cursorTextOffset)); + paintHighlights(g, hlFactory.getHighlights(this, getString(), cursorTextOffset)); } protected void paintSelection(Graphics g, FieldBackgroundColorManager colorManager, int row, @@ -344,10 +343,10 @@ public class ClippingTextField implements TextField { } protected void paintHighlights(Graphics g, Highlight[] highlights) { - for (int i = 0; i < highlights.length; i++) { - int startCol = Math.max(highlights[i].getStart(), 0); - int endCol = Math.min(highlights[i].getEnd(), getString().length()); - Color c = highlights[i].getColor(); + for (Highlight highlight : highlights) { + int startCol = Math.max(highlight.getStart(), 0); + int endCol = Math.min(highlight.getEnd(), getString().length()); + Color c = highlight.getColor(); if (endCol >= startCol) { int start = findX(startCol); int end = findX(endCol + 1); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/ReverseClippingTextField.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/ReverseClippingTextField.java index 3ffa173ccb..bffa921952 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/ReverseClippingTextField.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/ReverseClippingTextField.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. @@ -142,8 +141,8 @@ public class ReverseClippingTextField implements TextField { int x = findX(col) + textStartX; - return new Rectangle(x, -textElement.getHeightAbove(), 2, textElement.getHeightAbove() + - textElement.getHeightBelow()); + return new Rectangle(x, -textElement.getHeightAbove(), 2, + textElement.getHeightAbove() + textElement.getHeightBelow()); } /** @@ -336,8 +335,7 @@ public class ReverseClippingTextField implements TextField { private void paintDots(Graphics g, int x) { int pos = 1; // skip one pixel for (int i = 0; i < 3; i++) { - if (pos < DOT_DOT_DOT_WIDTH - 2) { // don't paint too close to next - // field. + if (pos < DOT_DOT_DOT_WIDTH - 2) { // don't paint too close to next field g.drawRect(x + pos, -2, 1, 1); pos += 4; // add in size of dot and padding } @@ -349,14 +347,14 @@ public class ReverseClippingTextField implements TextField { if (cursorLoc != null) { cursorTextOffset = screenLocationToTextOffset(cursorLoc.row(), cursorLoc.col()); } - paintHighlights(g, hlFactory.getHighlights(getString(), cursorTextOffset)); + paintHighlights(g, hlFactory.getHighlights(this, getString(), cursorTextOffset)); } protected void paintHighlights(Graphics g, Highlight[] highlights) { - for (int i = 0; i < highlights.length; i++) { - int startCol = Math.max(highlights[i].getStart() - startingCharIndex, 0); - int endCol = Math.min(highlights[i].getEnd() - startingCharIndex, getString().length()); - Color c = highlights[i].getColor(); + for (Highlight highlight : highlights) { + int startCol = Math.max(highlight.getStart() - startingCharIndex, 0); + int endCol = Math.min(highlight.getEnd() - startingCharIndex, getString().length()); + Color c = highlight.getColor(); if (endCol >= startCol) { int start = findX(startCol); int end = findX(endCol + 1); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/SimpleTextField.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/SimpleTextField.java index a4dbdbbbaf..f75903abb6 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/SimpleTextField.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/field/SimpleTextField.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. @@ -202,7 +201,7 @@ public class SimpleTextField implements Field { public void paint(JComponent c, Graphics g, PaintContext context, FieldBackgroundColorManager colorManager, RowColLocation cursorLoc, int rowHeight) { paintSelection(g, colorManager, 0); - paintHighlights(g, hlFactory.getHighlights(text, -1)); + paintHighlights(g, hlFactory.getHighlights(this, text, -1)); g.setFont(metrics.getFont()); if (foregroundColor == null) { foregroundColor = context.getForeground(); @@ -226,10 +225,10 @@ public class SimpleTextField implements Field { } protected void paintHighlights(Graphics g, Highlight[] highlights) { - for (int i = 0; i < highlights.length; i++) { - int startCol = Math.max(highlights[i].getStart(), 0); - int endCol = Math.min(highlights[i].getEnd(), text.length()); - Color c = highlights[i].getColor(); + for (Highlight highlight : highlights) { + int startCol = Math.max(highlight.getStart(), 0); + int endCol = Math.min(highlight.getEnd(), text.length()); + Color c = highlight.getColor(); if (endCol >= startCol) { int start = findX(startCol); int end = findX(endCol + 1); 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 7f4e79319a..dad543cad9 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 @@ -268,7 +268,7 @@ public class VerticalLayoutTextField implements TextField { cursorRow = cursorLoc.row(); } - Highlight[] highlights = hlFactory.getHighlights(getText(), cursorTextOffset); + Highlight[] highlights = hlFactory.getHighlights(this, getText(), cursorTextOffset); int columns = 0; int n = subFields.size(); Color fieldBackgroundColor = colorManager.getBackgroundColor(); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/support/HighlightFactory.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/support/HighlightFactory.java index 3d46ca7e66..4a97453560 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/support/HighlightFactory.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/fieldpanel/support/HighlightFactory.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. @@ -16,13 +15,30 @@ */ package docking.widgets.fieldpanel.support; +import docking.widgets.fieldpanel.field.Field; + public interface HighlightFactory { + /** - * Returns the highlights for the given text. - * @param text the text to be considered for highlighting. + * Returns the highlights for the given text + * + * @param text the text to be considered for highlighting * @param cursorTextOffset the position in the given text of the cursor. A -1 indicates the - * cursor is not in this field. - * @return an array of highlights to be rendered. + * cursor is not in this field. + * @return an array of highlights to be rendered */ public Highlight[] getHighlights(String text, int cursorTextOffset); + + /** + * Returns the highlights for the given text + * + * @param field the field that is requesting the highlight + * @param text the text to be considered for highlighting + * @param cursorTextOffset the position in the given text of the cursor. A -1 indicates the + * cursor is not in this field. + * @return an array of highlights to be rendered + */ + public default Highlight[] getHighlights(Field field, String text, int cursorTextOffset) { + return getHighlights(text, cursorTextOffset); + } }