diff --git a/jadx-core/src/main/java/jadx/api/CodePosition.java b/jadx-core/src/main/java/jadx/api/CodePosition.java index 678b12e9b..bd58e1b52 100644 --- a/jadx-core/src/main/java/jadx/api/CodePosition.java +++ b/jadx-core/src/main/java/jadx/api/CodePosition.java @@ -5,6 +5,7 @@ public final class CodePosition { private final JavaNode node; private final int line; private final int offset; + private int usagePosition = -1; public CodePosition(JavaNode node, int line, int offset) { this.node = node; @@ -18,6 +19,15 @@ public final class CodePosition { this.offset = offset; } + public int getUsagePosition() { + return usagePosition; + } + + public CodePosition setUsagePosition(int usagePosition) { + this.usagePosition = usagePosition; + return this; + } + public JavaNode getNode() { return node; } diff --git a/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java b/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java index b3d5e738e..2c7caa4a0 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java +++ b/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java @@ -120,8 +120,16 @@ public class CodeWriter { CodeWriter add(CodeWriter code) { line--; for (Map.Entry entry : code.annotations.entrySet()) { + Object val = entry.getValue(); + if (val instanceof DefinitionWrapper) { + LineAttrNode node = ((DefinitionWrapper) val).getNode(); + node.setDefPosition(node.getDefPosition() + this.buf.length()); + } CodePosition pos = entry.getKey(); - attachAnnotation(entry.getValue(), new CodePosition(line + pos.getLine(), pos.getOffset())); + int usagePos = pos.getUsagePosition() + bufLength(); + attachAnnotation(val, + new CodePosition(line + pos.getLine(), pos.getOffset()) + .setUsagePosition(usagePos)); } for (Map.Entry entry : code.lineMap.entrySet()) { attachSourceLine(line + entry.getKey(), entry.getValue()); @@ -211,12 +219,14 @@ public class CodeWriter { } public void attachDefinition(LineAttrNode obj) { + obj.setDefPosition(buf.length()); attachAnnotation(obj); attachAnnotation(new DefinitionWrapper(obj), new CodePosition(line, offset)); } public void attachAnnotation(Object obj) { - attachAnnotation(obj, new CodePosition(line, offset + 1)); + attachAnnotation(obj, + new CodePosition(line, offset + 1).setUsagePosition(bufLength())); } public void attachLineAnnotation(Object obj) { diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/LineAttrNode.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/LineAttrNode.java index ae4adc492..03efffa64 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/LineAttrNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/LineAttrNode.java @@ -8,6 +8,17 @@ public abstract class LineAttrNode extends AttrNode { private int decompiledLine; + // the position exactly where a node declared at in decompiled java code. + private int defPosition; + + public int getDefPosition() { + return this.defPosition; + } + + public void setDefPosition(int defPosition) { + this.defPosition = defPosition; + } + public int getSourceLine() { return sourceLine; } diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/CodeNode.java b/jadx-gui/src/main/java/jadx/gui/treemodel/CodeNode.java index 3af2e97f5..9442d6d82 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/CodeNode.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/CodeNode.java @@ -13,6 +13,8 @@ public class CodeNode extends JNode { private final transient JClass jParent; private final transient StringRef line; private final transient int lineNum; + private transient int pos = -1; + private transient boolean precise; public CodeNode(JNode jNode, int lineNum, StringRef lineStr) { this.jNode = jNode; @@ -93,4 +95,25 @@ public class CodeNode extends JNode { public int hashCode() { return jNode.hashCode(); } + + public int getPos() { + return pos; + } + + public CodeNode setPos(int pos) { + this.pos = pos; + return this; + } + + public CodeNode setPrecisePos(int pos) { + this.pos = pos; + if (pos > -1) { + this.precise = true; + } + return this; + } + + public boolean isPrecisePos() { + return precise; + } } diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JField.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JField.java index 6f9052d36..83275615d 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JField.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JField.java @@ -29,6 +29,10 @@ public class JField extends JNode { this.jParent = jClass; } + public JavaField getJavaField() { + return (JavaField) getJavaNode(); + } + @Override public JavaNode getJavaNode() { return field; diff --git a/jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java b/jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java index 7aad72141..7feccda89 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java @@ -11,7 +11,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; -import java.util.List; import java.util.Map; import javax.swing.*; @@ -20,7 +19,6 @@ import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; -import org.fife.ui.rsyntaxtextarea.DocumentRange; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rtextarea.SearchContext; @@ -33,7 +31,7 @@ import org.slf4j.LoggerFactory; import jadx.gui.jobs.BackgroundJob; import jadx.gui.jobs.BackgroundWorker; import jadx.gui.jobs.DecompileJob; -import jadx.gui.treemodel.JNode; +import jadx.gui.treemodel.*; import jadx.gui.ui.codearea.AbstractCodeArea; import jadx.gui.utils.CacheObject; import jadx.gui.utils.JumpPosition; @@ -111,9 +109,18 @@ public abstract class CommonSearchDialog extends JDialog { if (selectedId == -1) { return; } - int pos = Math.max(0, resultsModel.renderer.getFirstMarkOfCode(selectedId)); + JumpPosition jmpPos; JNode node = (JNode) resultsModel.getValueAt(selectedId, 0); - tabbedPane.codeJump(new JumpPosition(node.getRootClass(), node.getLine(), pos)); + if (node instanceof CodeNode) { + CodeNode codeNode = (CodeNode) node; + jmpPos = new JumpPosition(node.getRootClass(), node.getLine(), codeNode.getPos()); + if (codeNode.isPrecisePos()) { + jmpPos.setPrecise(codeNode.getPos()); + } + } else { + jmpPos = new JumpPosition(node.getRootClass(), node.getLine()); + } + tabbedPane.codeJump(jmpPos); dispose(); } @@ -413,19 +420,6 @@ public abstract class CommonSearchDialog extends JDialog { this.codeBackground = area.getBackground(); } - public int getFirstMarkOfCode(int row) { - Component comp = componentCache.get(makeID(row, 1)); - if (comp instanceof RSyntaxTextArea) { - List ranges = ((RSyntaxTextArea) comp).getMarkAllHighlightRanges(); - if (ranges.size() > 0) { - // minus 2 cuz the start of textArea of the column is added 2 - // spaces in makeCell method. - return ranges.get(0).getStartOffset() - 2; - } - } - return 0; - } - @Override public Component getTableCellRendererComponent(JTable table, Object obj, boolean isSelected, boolean hasFocus, int row, int column) { diff --git a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java index ea872174e..fa70bc004 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -81,6 +81,7 @@ import jadx.api.JadxArgs; import jadx.api.JavaClass; import jadx.api.JavaNode; import jadx.api.ResourceFile; +import jadx.core.utils.StringUtils; import jadx.core.utils.Utils; import jadx.core.utils.files.FileUtils; import jadx.gui.JadxWrapper; @@ -100,6 +101,7 @@ import jadx.gui.treemodel.JNode; import jadx.gui.treemodel.JPackage; import jadx.gui.treemodel.JResource; import jadx.gui.treemodel.JRoot; +import jadx.gui.ui.codearea.AbstractCodeContentPanel; import jadx.gui.update.JadxUpdate; import jadx.gui.update.JadxUpdate.IUpdateCallback; import jadx.gui.update.data.Release; @@ -228,7 +230,8 @@ public class MainWindow extends JFrame { return; } JNode node = cacheObject.getNodeCache().makeFrom(javaNode); - tabbedPane.codeJump(new JumpPosition(node.getRootClass(), node.getLine())); + tabbedPane.codeJump(new JumpPosition(node.getRootClass(), node.getLine()) + .setPrecise(JumpPosition.getDefPos(node))); } } @@ -513,7 +516,8 @@ public class MainWindow extends JFrame { continue; } JNode newNode = cacheObject.getNodeCache().makeFrom(newClass); - tabbedPane.codeJump(new JumpPosition(newNode, position)); + tabbedPane.codeJump(new JumpPosition(newNode, position) + .setPrecise(JumpPosition.getDefPos(newNode))); } } @@ -646,7 +650,8 @@ public class MainWindow extends JFrame { JNode node = (JNode) obj; JClass cls = node.getRootClass(); if (cls != null) { - tabbedPane.codeJump(new JumpPosition(cls, node.getLine())); + tabbedPane.codeJump(new JumpPosition(cls, node.getLine()) + .setPrecise(JumpPosition.getDefPos(node))); } } } catch (Exception e) { @@ -812,6 +817,14 @@ public class MainWindow extends JFrame { Action textSearchAction = new AbstractAction(NLS.str("menu.text_search"), ICON_SEARCH) { @Override public void actionPerformed(ActionEvent e) { + ContentPanel panel = tabbedPane.getSelectedCodePanel(); + if (panel instanceof AbstractCodeContentPanel) { + String preferText = ((AbstractCodeContentPanel) panel).getCodeArea().getSelectedText(); + if (!StringUtils.isEmpty(preferText)) { + SearchDialog.searchText(MainWindow.this, preferText); + return; + } + } new SearchDialog(MainWindow.this, true).setVisible(true); } }; diff --git a/jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java b/jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java index 57f62a2b2..9ef7817d3 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/SearchDialog.java @@ -21,6 +21,7 @@ import io.reactivex.Flowable; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; +import jadx.core.utils.StringUtils; import jadx.gui.treemodel.JNode; import jadx.gui.utils.NLS; import jadx.gui.utils.TextStandardActions; @@ -47,6 +48,7 @@ public class SearchDialog extends CommonSearchDialog { private transient Disposable searchDisposable; private transient SearchEventEmitter searchEmitter; + private transient String text = null; public SearchDialog(MainWindow mainWindow, boolean textSearch) { super(mainWindow); @@ -286,13 +288,23 @@ public class SearchDialog extends CommonSearchDialog { @Override protected void loadFinished() { + if (!StringUtils.isEmpty(text)) { + searchField.setText(text); + } resultsTable.setEnabled(true); searchField.setEnabled(true); } @Override protected void loadStart() { + text = cache.getLastSearch(); // SearchDialog is opened by menu item, let loadFinished to set text + cache.setLastSearch(""); resultsTable.setEnabled(false); searchField.setEnabled(false); } + + public static void searchText(MainWindow window, String text) { + window.getCacheObject().setLastSearch(text); + new SearchDialog(window, true).setVisible(true); + } } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java b/jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java index c4f4bf056..15565be24 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java @@ -168,7 +168,7 @@ public class TabbedPane extends JTabbedPane { line = pos.getNode().getLine(); } } - if (pos.getPos() <= 0) { + if (pos.getPos() < 0) { codeArea.scrollToLine(line); } else { int lineNum = Math.max(0, line - 1); @@ -225,6 +225,9 @@ public class TabbedPane extends JTabbedPane { } public void navBack() { + if (jumps.size() > 1) { + jumps.updateCurPosition(getCurrentPosition()); + } JumpPosition pos = jumps.getPrev(); if (pos != null) { showCode(pos); @@ -232,6 +235,9 @@ public class TabbedPane extends JTabbedPane { } public void navForward() { + if (jumps.size() > 1) { + jumps.updateCurPosition(getCurrentPosition()); + } JumpPosition pos = jumps.getNext(); if (pos != null) { showCode(pos); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/AbstractCodeArea.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/AbstractCodeArea.java index 57832c9cd..061b7c5c7 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/AbstractCodeArea.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/AbstractCodeArea.java @@ -32,11 +32,6 @@ public abstract class AbstractCodeArea extends RSyntaxTextArea { public static final Color MARK_ALL_HIGHLIGHT_COLOR = Color.decode("#FFED89"); - @Override - public boolean getHighlightCurrentLine() { - return super.getHighlightCurrentLine(); - } - protected final ContentPanel contentPanel; protected final JNode node; @@ -115,13 +110,7 @@ public abstract class AbstractCodeArea extends RSyntaxTextArea { @Override public void caretUpdate(CaretEvent e) { - int pos = e.getDot(); - if (pos == 0) { - // not accepting 0, cuz sometimes the underlying RSyntaxTextArea - // will fire a fake event to force repaint caret, and its dot is - // usually 0, so we just ignore 0 anyway as a workaround. - return; - } + int pos = getCaretPosition(); if (lastPos != pos) { lastPos = pos; lastText = highlightCaretWord(lastText, pos); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodeArea.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodeArea.java index 9e6ee544d..4e2048774 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodeArea.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodeArea.java @@ -145,7 +145,8 @@ public final class CodeArea extends AbstractCodeArea { return null; } JNode jNode = convertJavaNode(foundNode); - return new JumpPosition(jNode.getRootClass(), pos.getLine()); + return new JumpPosition(jNode.getRootClass(), pos.getLine()) + .setPrecise(JumpPosition.getDefPos(jNode)); } private JNode convertJavaNode(JavaNode javaNode) { diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodePanel.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodePanel.java index 45c97831a..5eefeeb10 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodePanel.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodePanel.java @@ -8,9 +8,16 @@ import java.util.Map; import java.util.Set; import javax.swing.*; +import javax.swing.JPopupMenu.Separator; import javax.swing.border.EmptyBorder; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; import jadx.api.ICodeInfo; +import jadx.core.utils.StringUtils; +import jadx.gui.ui.MainWindow; +import jadx.gui.ui.SearchDialog; +import jadx.gui.utils.NLS; import jadx.gui.utils.UiUtils; /** @@ -42,6 +49,56 @@ public class CodePanel extends JPanel { searchBar.toggle(); } }); + JMenuItem searchItem = new JMenuItem(); + JMenuItem globalSearchItem = new JMenuItem(); + AbstractAction searchAction = new AbstractAction(NLS.str("popup.search", "")) { + @Override + public void actionPerformed(ActionEvent e) { + searchBar.toggle(); + } + }; + AbstractAction globalSearchAction = new AbstractAction(NLS.str("popup.search_global", "")) { + @Override + public void actionPerformed(ActionEvent e) { + MainWindow mainWindow = codeArea.getContentPanel().getTabbedPane().getMainWindow(); + SearchDialog.searchText(mainWindow, codeArea.getSelectedText()); + } + }; + searchItem.setAction(searchAction); + globalSearchItem.setAction(globalSearchAction); + Separator separator = new Separator(); + JPopupMenu popupMenu = codeArea.getPopupMenu(); + popupMenu.addPopupMenuListener(new PopupMenuListener() { + @Override + public void popupMenuWillBecomeVisible(PopupMenuEvent e) { + String preferText = codeArea.getSelectedText(); + if (!StringUtils.isEmpty(preferText)) { + if (preferText.length() >= 23) { + preferText = preferText.substring(0, 20) + " ..."; + } + searchAction.putValue(Action.NAME, NLS.str("popup.search", preferText)); + globalSearchAction.putValue(Action.NAME, NLS.str("popup.search_global", preferText)); + popupMenu.add(separator); + popupMenu.add(globalSearchItem); + popupMenu.add(searchItem); + } else { + popupMenu.remove(separator); + popupMenu.remove(globalSearchItem); + popupMenu.remove(searchItem); + } + } + + @Override + public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { + + } + + @Override + public void popupMenuCanceled(PopupMenuEvent e) { + + } + }); + } public void loadSettings() { diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/SearchBar.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/SearchBar.java index 7c96b210a..9cd66af06 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/SearchBar.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/SearchBar.java @@ -15,6 +15,7 @@ import org.fife.ui.rtextarea.SearchResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jadx.core.utils.StringUtils; import jadx.gui.utils.NLS; import jadx.gui.utils.TextStandardActions; import jadx.gui.utils.UiUtils; @@ -113,6 +114,10 @@ class SearchBar extends JToolBar { setVisible(visible); if (visible) { + String preferText = rTextArea.getSelectedText(); + if (!StringUtils.isEmpty(preferText)) { + searchField.setText(preferText); + } searchField.requestFocus(); searchField.selectAll(); } else { diff --git a/jadx-gui/src/main/java/jadx/gui/utils/CodeUsageInfo.java b/jadx-gui/src/main/java/jadx/gui/utils/CodeUsageInfo.java index d4963cf90..2f577463c 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/CodeUsageInfo.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/CodeUsageInfo.java @@ -64,7 +64,7 @@ public class CodeUsageInfo { JavaNode javaNodeByLine = linesInfo.getJavaNodeByLine(line); StringRef codeLine = lines.get(line - 1); JNode node = nodeCache.makeFrom(javaNodeByLine == null ? javaClass : javaNodeByLine); - CodeNode codeNode = new CodeNode(node, line, codeLine); + CodeNode codeNode = new CodeNode(node, line, codeLine).setPrecisePos(codePosition.getUsagePosition()); usageInfo.addUsage(codeNode); } diff --git a/jadx-gui/src/main/java/jadx/gui/utils/JumpManager.java b/jadx-gui/src/main/java/jadx/gui/utils/JumpManager.java index 355b5b82d..5f74af18f 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/JumpManager.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/JumpManager.java @@ -28,6 +28,14 @@ public class JumpManager { } } + public void updateCurPosition(JumpPosition pos) { + list.set(currentPos, pos); + } + + public int size() { + return list.size(); + } + private boolean ignoreJump(JumpPosition pos) { JumpPosition current = getCurrent(); if (current == null) { diff --git a/jadx-gui/src/main/java/jadx/gui/utils/JumpPosition.java b/jadx-gui/src/main/java/jadx/gui/utils/JumpPosition.java index bb9dd7415..a14fcba6b 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/JumpPosition.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/JumpPosition.java @@ -1,19 +1,20 @@ package jadx.gui.utils; -import jadx.gui.treemodel.JNode; +import jadx.api.JavaClass; +import jadx.api.JavaField; +import jadx.api.JavaMethod; +import jadx.api.JavaNode; +import jadx.core.utils.exceptions.JadxRuntimeException; +import jadx.gui.treemodel.*; public class JumpPosition { private final JNode node; private final int line; - // the position of the node in java code, - // call codeArea.scrollToPos(pos) to set caret private int pos; - // Precise means caret can be set right at the node in codeArea, - // not just the start of the line. private boolean precise; public JumpPosition(JNode node, int line) { - this(node, line, 0); + this(node, line, -1); } public JumpPosition(JNode node, int line, int pos) { @@ -44,6 +45,32 @@ public class JumpPosition { return line; } + public static int getDefPos(JNode node) { + if (node instanceof JClass) { + return ((JClass) node).getCls().getClassNode().getDefPosition(); + } + if (node instanceof JMethod) { + return ((JMethod) node).getJavaMethod().getMethodNode().getDefPosition(); + } + if (node instanceof JField) { + return ((JField) node).getJavaField().getFieldNode().getDefPosition(); + } + throw new JadxRuntimeException("Unexpected node " + node); + } + + public static int getDefPos(JavaNode node) { + if (node instanceof JavaClass) { + return ((JavaClass) node).getClassNode().getDefPosition(); + } + if (node instanceof JavaMethod) { + return ((JavaMethod) node).getMethodNode().getDefPosition(); + } + if (node instanceof JavaField) { + return ((JavaField) node).getFieldNode().getDefPosition(); + } + throw new JadxRuntimeException("Unexpected node " + node); + } + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/jadx-gui/src/main/java/jadx/gui/utils/search/CodeIndex.java b/jadx-gui/src/main/java/jadx/gui/utils/search/CodeIndex.java index 52b9f9d42..9654e2819 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/search/CodeIndex.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/search/CodeIndex.java @@ -35,7 +35,9 @@ public class CodeIndex { return Flowable.create(emitter -> { LOG.debug("Code search started: {} ...", searchSettings.getSearchString()); for (CodeNode node : values) { - if (isMatched(node.getLineStr(), searchSettings)) { + int pos = searchSettings.find(node.getLineStr()); + node.setPos(pos); + if (pos > -1) { emitter.onNext(node); } if (emitter.isCancelled()) { diff --git a/jadx-gui/src/main/java/jadx/gui/utils/search/TextSearchIndex.java b/jadx-gui/src/main/java/jadx/gui/utils/search/TextSearchIndex.java index 942df0791..f6215708d 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/search/TextSearchIndex.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/search/TextSearchIndex.java @@ -158,7 +158,7 @@ public class TextSearchIndex { int lineStart = 1 + code.lastIndexOf(CodeWriter.NL, pos); int lineEnd = code.indexOf(CodeWriter.NL, pos + searchSettings.getSearchString().length()); StringRef line = StringRef.subString(code, lineStart, lineEnd == -1 ? code.length() : lineEnd); - emitter.onNext(new CodeNode(nodeCache.makeFrom(javaClass), -pos, line.trim())); + emitter.onNext(new CodeNode(nodeCache.makeFrom(javaClass), -pos, line.trim()).setPos(pos)); return lineEnd; } diff --git a/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties b/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties index b0c2048af..fb24d254d 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_de_DE.properties @@ -160,6 +160,8 @@ popup.find_usage=Verwendung suchen popup.go_to_declaration=Zur Erklärung gehen popup.exclude=Ausschließen popup.rename=Umbennen +#popup.search= +#popup.search_global= confirm.save_as_title=Speichern unter bestätigen confirm.save_as_message=%s existiert bereits.\nErsetzen? diff --git a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties index c6687adb5..22369d5f9 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_en_US.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_en_US.properties @@ -160,6 +160,8 @@ popup.find_usage=Find Usage popup.go_to_declaration=Go to declaration popup.exclude=Exclude popup.rename=Rename +popup.search=Search "%s" +popup.search_global=Global Search "%s" confirm.save_as_title=Confirm Save as confirm.save_as_message=%s already exists.\nDo you want to replace it? diff --git a/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties b/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties index 963e9ff66..111ae3c88 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_es_ES.properties @@ -160,6 +160,8 @@ popup.select_all=Seleccionar todo #popup.go_to_declaration= #popup.exclude= popup.rename=Nimeta ümber +#popup.search= +#popup.search_global= #confirm.save_as_title= #confirm.save_as_message= diff --git a/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties b/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties index a23fac39f..778729cae 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_ko_KR.properties @@ -160,6 +160,8 @@ popup.find_usage=사용 찾기 popup.go_to_declaration=선언문으로 이동 popup.exclude=제외 popup.rename=이름 바꾸기 +#popup.search= +#popup.search_global= confirm.save_as_title=다른 이름으로 저장 확인 confirm.save_as_message=%s이(가) 이미 있습니다.\n바꾸시겠습니까? diff --git a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties index 539c1966f..d2db46860 100644 --- a/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties +++ b/jadx-gui/src/main/resources/i18n/Messages_zh_CN.properties @@ -160,6 +160,8 @@ popup.find_usage=查找用例 popup.go_to_declaration=跳到声明 popup.exclude=排除 popup.rename=改名 +#popup.search= +#popup.search_global= confirm.save_as_title=确认另存为 confirm.save_as_message=%s 已存在。\n你想替换它吗?