From 5079276146a94dfbda8f26e931ebe7704f5d35dc Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Thu, 25 Jun 2026 16:37:22 -0400 Subject: [PATCH] Fixed search highlights for multi-row components --- .../core/searchtext/SearchTextPlugin.java | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java index 16269cb74d..fa8e536631 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java @@ -16,6 +16,7 @@ package ghidra.app.plugin.core.searchtext; import java.awt.*; +import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; @@ -28,6 +29,7 @@ import org.apache.commons.lang3.StringUtils; import docking.*; import docking.action.builder.ActionBuilder; import docking.tool.ToolConstants; +import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.Highlight; import docking.widgets.table.threaded.*; import generic.theme.GIcon; @@ -702,32 +704,37 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList return NO_HIGHLIGHTS; } - int charOffset = searchResult.offset(); - int searchStart = charOffset; + /* + Find the highlight start and end using the ProgramLocation. The location is in + model space, but the Highlights are in view space. The field factory already knows + how to convert between these 2 spaces by providing a FieldLocation for the view + space. + */ + BigInteger dummyIndex = BigInteger.ZERO; + int dummyFieldNumber = 0; + FieldLocation fieldLocation = + fieldFactory.getFieldLocation(field, dummyIndex, dummyFieldNumber, loc); + + /* + We now need to handle the case where the view values have multiple rows. The + Highlight uses character offsets that treat multiple rows as one single line string. + Here we use the ListingField to convert from rows to a character offset. + */ + int row = fieldLocation.getRow(); + int col = fieldLocation.getCol(); + int screenOffset = field.screenLocationToTextOffset(row, col); + int searchStart = screenOffset; int searchEnd = searchStart + searchText.length(); - Pattern regexp = - UserSearchUtils.createSearchPattern(searchText, searchOptions.isCaseSensitive()); - Matcher matcher = regexp.matcher(text); - while (matcher.find()) { - int start = matcher.start(); - int end = matcher.end(); - - // ensure the particular regex match is the actual search result - if (start == searchStart && end == searchEnd) { - - Color hlColor = SearchConstants.SEARCH_HIGHLIGHT_COLOR; - if (start <= cursorTextOffset && end >= cursorTextOffset) { - // change the highlight color when in the field so it stands out - hlColor = SearchConstants.SEARCH_HIGHLIGHT_CURRENT_ADDR_COLOR; - } - - // this is the matching search hit for a single search - int endEx = end - 1; - return new Highlight[] { new Highlight(start, endEx, hlColor) }; - } + Color hlColor = SearchConstants.SEARCH_HIGHLIGHT_COLOR; + if (searchStart <= cursorTextOffset && searchEnd >= cursorTextOffset) { + // change the highlight color when in the field so it stands out + hlColor = SearchConstants.SEARCH_HIGHLIGHT_CURRENT_ADDR_COLOR; } - return NO_HIGHLIGHTS; + + // this is the matching search hit for a single search + int endInc = searchEnd - 1; // highlights are inclusive + return new Highlight[] { new Highlight(searchStart, endInc, hlColor) }; } private boolean shouldHighlight(ListingField field) {