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 308f8f633..ad398b08f 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 @@ -34,7 +34,7 @@ public abstract class AbstractCodeArea extends RSyntaxTextArea { this.contentPanel = contentPanel; this.node = contentPanel.getNode(); - setMarkOccurrences(true); + setMarkOccurrences(false); setEditable(false); setCodeFoldingEnabled(false); loadSettings(); 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 87719890d..a69202ac6 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 @@ -36,7 +36,8 @@ public final class CodeArea extends AbstractCodeArea { super(contentPanel); setSyntaxEditingStyle(node.getSyntaxName()); - if (node instanceof JClass) { + boolean isJavaCode = node instanceof JClass; + if (isJavaCode) { ((RSyntaxDocument) getDocument()).setSyntaxStyle(new JadxTokenMaker(this)); addMenuItems(); } @@ -46,6 +47,7 @@ public final class CodeArea extends AbstractCodeArea { CodeLinkGenerator codeLinkGenerator = new CodeLinkGenerator(this); setLinkGenerator(codeLinkGenerator); addMouseListener(new MouseAdapter() { + @SuppressWarnings("deprecation") @Override public void mouseClicked(MouseEvent e) { if (e.isControlDown()) { @@ -57,6 +59,9 @@ public final class CodeArea extends AbstractCodeArea { } } }); + if (isJavaCode) { + addMouseMotionListener(new MouseHoverHighlighter(this, codeLinkGenerator)); + } } @Override diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/JadxTokenMaker.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/JadxTokenMaker.java index a0e23af1b..2a8b7f4c3 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/JadxTokenMaker.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/JadxTokenMaker.java @@ -26,7 +26,7 @@ public final class JadxTokenMaker extends JavaTokenMaker { @Override public Token getTokenList(Segment text, int initialTokenType, int startOffset) { Token tokens = super.getTokenList(text, initialTokenType, startOffset); - if (startOffset > 0 && tokens.getType() != TokenTypes.NULL) { + if (tokens.getType() != TokenTypes.NULL) { try { processTokens(tokens); } catch (Exception e) { @@ -41,11 +41,14 @@ public final class JadxTokenMaker extends JavaTokenMaker { Token current = tokens; while (current != null) { if (prev != null) { - int tokenType = current.getType(); - if (tokenType == TokenTypes.IDENTIFIER) { - current = mergeLongClassNames(prev, current, false); - } else if (tokenType == TokenTypes.ANNOTATION) { - current = mergeLongClassNames(prev, current, true); + switch (current.getType()) { + case TokenTypes.IDENTIFIER: + current = mergeLongClassNames(prev, current, false); + break; + + case TokenTypes.ANNOTATION: + current = mergeLongClassNames(prev, current, true); + break; } } prev = current; @@ -55,7 +58,7 @@ public final class JadxTokenMaker extends JavaTokenMaker { @NotNull private Token mergeLongClassNames(Token prev, Token current, boolean annotation) { - int offset = current.getOffset(); + int offset = current.getTextOffset(); if (annotation) { offset++; } @@ -66,7 +69,7 @@ public final class JadxTokenMaker extends JavaTokenMaker { if (annotation && lexeme.length() > 1) { lexeme = lexeme.substring(1); } - if (!lexeme.equals(name) && javaNode.getFullName().startsWith(lexeme)) { + if (!lexeme.equals(name) && isClassNameStart(javaNode, lexeme)) { // try to replace long class name with one token Token replace = concatTokensUntil(current, name); if (replace != null && prev instanceof TokenImpl) { @@ -79,6 +82,18 @@ public final class JadxTokenMaker extends JavaTokenMaker { return current; } + private boolean isClassNameStart(JavaNode javaNode, String lexeme) { + if (javaNode.getFullName().startsWith(lexeme)) { + // full class name + return true; + } + if (javaNode.getTopParentClass().getName().startsWith(lexeme)) { + // inner class references from parent class + return true; + } + return false; + } + @Nullable private Token concatTokensUntil(Token start, String endText) { StringBuilder sb = new StringBuilder(); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/MouseHoverHighlighter.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/MouseHoverHighlighter.java new file mode 100644 index 000000000..ff1db8a2b --- /dev/null +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/MouseHoverHighlighter.java @@ -0,0 +1,57 @@ +package jadx.gui.ui.codearea; + +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; + +import javax.swing.text.Highlighter; + +import org.fife.ui.rsyntaxtextarea.Token; +import org.fife.ui.rsyntaxtextarea.TokenTypes; +import org.fife.ui.rtextarea.SmartHighlightPainter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jadx.gui.utils.JumpPosition; + +class MouseHoverHighlighter extends MouseMotionAdapter { + private static final Logger LOG = LoggerFactory.getLogger(MouseHoverHighlighter.class); + + private final CodeArea codeArea; + private final CodeLinkGenerator codeLinkGenerator; + private final Highlighter.HighlightPainter highlighter; + + private boolean added; + + public MouseHoverHighlighter(CodeArea codeArea, CodeLinkGenerator codeLinkGenerator) { + this.codeArea = codeArea; + this.codeLinkGenerator = codeLinkGenerator; + this.highlighter = new SmartHighlightPainter(codeArea.getMarkOccurrencesColor()); + } + + @Override + public void mouseMoved(MouseEvent e) { + Highlighter highlighter = codeArea.getHighlighter(); + if (added) { + highlighter.removeAllHighlights(); + added = false; + } + if (e.getModifiersEx() != 0) { + return; + } + try { + Token token = codeArea.viewToToken(e.getPoint()); + if (token == null || token.getType() != TokenTypes.IDENTIFIER) { + return; + } + JumpPosition jump = codeLinkGenerator.getJumpLinkAtOffset(codeArea, token.getOffset()); + if (jump == null) { + return; + } + highlighter.removeAllHighlights(); + highlighter.addHighlight(token.getOffset(), token.getEndOffset(), this.highlighter); + added = true; + } catch (Exception exc) { + LOG.error("Mouse hover highlight error", exc); + } + } +}