Skip to content

Commit

Permalink
Merge pull request apache#5013 from matthiasblaesing/typehints
Browse files Browse the repository at this point in the history
Make more hints for java available
  • Loading branch information
matthiasblaesing authored Dec 26, 2022
2 parents 08edf24 + f148d56 commit 8415222
Show file tree
Hide file tree
Showing 14 changed files with 872 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,12 @@
import javax.swing.text.View;
import org.netbeans.spi.editor.highlighting.HighlightsSequence;

/**
* TODO
*/

public final class PrependedTextView extends EditorView {

private final AttributeSet attributes;
private final EditorView delegate;
private final TextLayout prependedTextLayout;
private final double leftShift;
private final double prependedTextWidth;

public PrependedTextView(DocumentViewOp op, AttributeSet attributes, EditorView delegate) {
Expand All @@ -49,10 +46,13 @@ public PrependedTextView(DocumentViewOp op, AttributeSet attributes, EditorView
this.delegate = delegate;
Font font = ViewUtils.getFont(attributes, op.getDefaultHintFont());
prependedTextLayout = op.createTextLayout((String) attributes.getAttribute(ViewUtils.KEY_VIRTUAL_TEXT_PREPEND), font);
Rectangle2D textBounds = prependedTextLayout.getBounds(); //TODO: allocation!
// Advance represents the width of the full string, including leading
// and trailing spaces
float width = prependedTextLayout.getAdvance();
// The prependTextWidth is rounded to full char widths, so that layout
// is not destroyed too much
double em = op.getDefaultCharWidth();
leftShift = em / 2;
prependedTextWidth = Math.ceil(textBounds.getWidth() + em);
prependedTextWidth = Math.ceil(width / em) * em;
}

@Override
Expand Down Expand Up @@ -93,7 +93,7 @@ public void paint(Graphics2D g, Shape hViewAlloc, Rectangle clipBounds) {
}

g.setColor(Color.gray);
span.setRect(span.getX() + leftShift, span.getY(), prependedTextWidth - 2 * leftShift, span.getHeight());
span.setRect(span.getX(), span.getY(), prependedTextWidth, span.getHeight());
HighlightsViewUtils.paintTextLayout(g, span, prependedTextLayout, getDocumentView());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ CTL_Tasklist_DisplayName=Tasklist
CTL_Tasklist_ToolTip=Tasklist Settings
KW_TaskList=Error Badges,Tasklist

#Inlinehints Subcategory
CTL_InlineHints_DisplayName=Inline Hints
CTL_InlineHints_ToolTip=Inline Hints Settings
KW_InlineHints=Inline Hints, Type Hints

#LanguageBasedOptionPanel
LBL_Language=&Language:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,19 @@ public static OptionsPanelController markOccurrences() {
return new FolderBasedController("MarkOccurrences/", "netbeans.optionsDialog.editor.markOccurences", false);
}

@OptionsPanelController.SubRegistration(
id="InlineHints",
displayName="#CTL_InlineHints_DisplayName",
location=OptionsDisplayer.EDITOR,
keywords="#KW_InlineHints",
keywordsCategory="Editor/InlineHints",
position=500
// toolTip="#CTL_MarkOccurences_ToolTip"
)
public static OptionsPanelController inlineHints() {
return new FolderBasedController("InlineHints/", "netbeans.optionsDialog.editor.inlineHints", false);
}

public static OptionsPanelController create (Map args) {
FolderBasedController folderBasedController = new FolderBasedController(
(String) args.get (OPTIONS_SUB_FOLDER),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
*/
@OptionsPanelController.KeywordsRegistration({
@OptionsPanelController.Keywords(keywords = {"#KW_Hints"}, location = OptionsDisplayer.EDITOR, tabTitle="#CTL_Hints_DisplayName"),
@OptionsPanelController.Keywords(keywords = {"#KW_Mark"}, location = OptionsDisplayer.EDITOR, tabTitle="#CTL_MarkOccurences_DisplayName")
@OptionsPanelController.Keywords(keywords = {"#KW_Mark"}, location = OptionsDisplayer.EDITOR, tabTitle="#CTL_MarkOccurences_DisplayName"),
@OptionsPanelController.Keywords(keywords = {"#KW_InlineHints"}, location = OptionsDisplayer.EDITOR, tabTitle="#CTL_InlineHints_DisplayName")
})
public final class FolderBasedOptionPanel extends JPanel implements ActionListener {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
*/
package org.netbeans.modules.java.editor.base.semantic;

import com.sun.source.tree.BindingPatternTree;
import com.sun.source.tree.CaseLabelTree;
import com.sun.source.tree.CaseTree;
import com.sun.source.tree.ClassTree;
Expand Down Expand Up @@ -51,19 +50,19 @@
import java.util.EnumSet;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import java.util.stream.Collectors;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.swing.text.Document;
import org.netbeans.api.java.lexer.JavaTokenId;
Expand All @@ -84,6 +83,7 @@
import org.netbeans.modules.parsing.spi.SchedulerEvent;
import org.netbeans.modules.parsing.spi.TaskIndexingMode;
import org.openide.filesystems.FileUtil;
import org.openide.util.NbPreferences;
import org.openide.util.Pair;


Expand All @@ -92,15 +92,53 @@
* @author Jan Lahoda
*/
public abstract class SemanticHighlighterBase extends JavaParserResultTask {


public static final String JAVA_INLINE_HINT_PARAMETER_NAME = "javaInlineHintParameterName"; //NOI18N
public static final String JAVA_INLINE_HINT_CHAINED_TYPES = "javaInlineHintChainedTypes"; //NOI18N
public static final String JAVA_INLINE_HINT_VAR_TYPE = "javaInlineHintVarType"; //NOI18N

private static final Map<String, Boolean> DEFAULT_VALUES;

static {
Map<String, Boolean> defaultValuesBuilder = new HashMap<>();
defaultValuesBuilder.put(JAVA_INLINE_HINT_PARAMETER_NAME, true);
defaultValuesBuilder.put(JAVA_INLINE_HINT_CHAINED_TYPES, false);
defaultValuesBuilder.put(JAVA_INLINE_HINT_VAR_TYPE, false);
DEFAULT_VALUES = Collections.unmodifiableMap(defaultValuesBuilder);
}

private static boolean javaInlineHintParameterName;
private static boolean javaInlineHintChainedTypes;
private static boolean javaInlineHintVarType;

private static boolean isJavaInlineHintParameterName() {
return javaInlineHintParameterName;
}

private static boolean isJavaInlineHintChainedTypes() {
return javaInlineHintChainedTypes;
}

private static boolean isJavaInlineHintVarType() {
return javaInlineHintVarType;
}

private static void updateFromPreferences() {
Preferences preferences = NbPreferences.root().node("/org/netbeans/modules/java/editor/InlineHints/default");
javaInlineHintParameterName = preferences.getBoolean(JAVA_INLINE_HINT_PARAMETER_NAME, DEFAULT_VALUES.get(JAVA_INLINE_HINT_PARAMETER_NAME));
javaInlineHintChainedTypes = preferences.getBoolean(JAVA_INLINE_HINT_CHAINED_TYPES, DEFAULT_VALUES.get(JAVA_INLINE_HINT_CHAINED_TYPES));
javaInlineHintVarType = preferences.getBoolean(JAVA_INLINE_HINT_VAR_TYPE, DEFAULT_VALUES.get(JAVA_INLINE_HINT_VAR_TYPE));
}

private AtomicBoolean cancel = new AtomicBoolean();

protected SemanticHighlighterBase() {
super(Phase.RESOLVED, TaskIndexingMode.ALLOWED_DURING_SCAN);
}

@Override
public void run(Result result, SchedulerEvent event) {

CompilationInfo info = CompilationInfo.get(result);

if (info == null) {
Expand Down Expand Up @@ -151,6 +189,8 @@ public Class<? extends Scheduler> getSchedulerClass() {
protected abstract boolean process(CompilationInfo info, final Document doc);

protected boolean process(CompilationInfo info, final Document doc, ErrorDescriptionSetter setter) {
updateFromPreferences();

DetectorVisitor v = new DetectorVisitor(info, doc, cancel);

Map<Token, Coloring> newColoring = new IdentityHashMap<>();
Expand Down Expand Up @@ -227,7 +267,9 @@ protected boolean process(CompilationInfo info, final Document doc, ErrorDescrip
return true;

if (computeUnusedImports) {
setter.setHighlights(doc, extraColoring, v.preText);
Map<int[], String> preTextWithSpans = new HashMap<>();
v.preText.forEach((pos, text) -> preTextWithSpans.put(new int[] {pos, pos + 1}, text));
setter.setHighlights(doc, extraColoring, preTextWithSpans);
}

setter.setColorings(doc, newColoring);
Expand All @@ -253,7 +295,7 @@ private static boolean isLocalVariableClosure(Element el) {
return el.getKind() == ElementKind.PARAMETER ||
LOCAL_VARIABLES.contains(el.getKind());
}

private static class Use {
private boolean declaration;
private TreePath tree;
Expand All @@ -279,7 +321,7 @@ private static class DetectorVisitor extends CancellableTreePathScanner<Void, Vo
private Map<Tree, List<Token>> tree2Tokens;
private List<Token> contextKeywords;
private List<Pair<int[], Coloring>> extraColoring;
private Map<int[], String> preText;
private Map<Integer, String> preText;
private TokenList tl;
private long memberSelectBypass = -1;
private SourcePositions sourcePositions;
Expand Down Expand Up @@ -690,6 +732,7 @@ public Void visitUses(UsesTree tree, Void p) {

@Override
public Void visitMethodInvocation(MethodInvocationTree tree, Void p) {
int startTokenIndex = tl.index();
Tree possibleIdent = tree.getMethodSelect();

if (possibleIdent.getKind() == Kind.IDENTIFIER) {
Expand Down Expand Up @@ -727,13 +770,27 @@ public Void visitMethodInvocation(MethodInvocationTree tree, Void p) {
scan(tree.getArguments(), p);

addParameterInlineHint(tree);

Tree parent = getCurrentPath().getParentPath().getLeaf();
Tree parentParent = getCurrentPath().getParentPath().getParentPath().getLeaf();

if (parent.getKind() != Kind.MEMBER_SELECT ||
parentParent.getKind() != Kind.METHOD_INVOCATION ||
((MemberSelectTree) parent).getExpression() != tree) {
int afterInvocation = tl.index();
tl.resetToIndex(startTokenIndex);
addChainedTypes(getCurrentPath());
tl.resetToIndex(afterInvocation);
}

return null;
}

@Override
public Void visitExpressionStatement(ExpressionStatementTree node, Void p) {
private void addChainedTypes(TreePath current) {
if(! isJavaInlineHintChainedTypes()) {
return;
}
List<TreePath> chain = new ArrayList<>(); //TODO: avoid creating an instance if possible!
TreePath current = new TreePath(getCurrentPath(), node.getExpression());
OUTER: while (true) {
chain.add(current);
switch (current.getLeaf().getKind()) {
Expand All @@ -748,29 +805,59 @@ public Void visitExpressionStatement(ExpressionStatementTree node, Void p) {
break OUTER;
}
}
int prevIndex = tl.index();
Collections.reverse(chain);
List<Pair<String, Integer>> typeToPosition = new ArrayList<>();
List<Pair<String, Integer>> forcedTypeToPosition = new ArrayList<>();
for (TreePath tp : chain) {
long end = info.getTrees().getSourcePositions().getEndPosition(tp.getCompilationUnit(), tp.getLeaf());
tl.moveToOffset(end);
Token t = tl.currentToken();
if (t != null && (t.id() == JavaTokenId.COMMA || t.id() == JavaTokenId.SEMICOLON)) {
tl.moveNext();
t = tl.currentToken();
} else if (t != null && t.id() == JavaTokenId.RPAREN) {
while (t != null && t.id() == JavaTokenId.RPAREN) {
tl.moveNext();
t = tl.currentToken();
}
if (t != null && (t.id() == JavaTokenId.COMMA || t.id() == JavaTokenId.SEMICOLON)) {
tl.moveNext();
t = tl.currentToken();
}
}
int pos;
if (t != null && t.id() == JavaTokenId.WHITESPACE && (pos = t.text().toString().indexOf("\n")) != -1) {
TypeMirror type = info.getTrees().getTypeMirror(tp);
String typeName = info.getTypeUtilities().getTypeName(type).toString();
if (typeToPosition.isEmpty() || !typeName.equals(typeToPosition.get(typeToPosition.size() - 1).first())) {
typeToPosition.add(Pair.of(typeName, tl.offset() + pos));
String typeName;
if (type.getKind().isPrimitive() || type.getKind() == TypeKind.DECLARED) {
typeName = info.getTypeUtilities().getTypeName(type).toString();
} else {
typeName = "";
}
int preTextPos = tl.offset() + pos;
if (typeToPosition.isEmpty() || !typeName.equals(typeToPosition.get(typeToPosition.size() - 1).first()) || preText.containsKey(preTextPos)) {
typeToPosition.add(Pair.of(typeName, preTextPos));
}
if (preText.containsKey(preTextPos)) {
forcedTypeToPosition.add(Pair.of(typeName, preTextPos));
}
}
}
if (typeToPosition.size() >= 2) {
for (Pair<String, Integer> typeAndPosition : typeToPosition) {
preText.put(new int[] {(int) typeAndPosition.second(), (int) typeAndPosition.second() + 1},
" " + typeAndPosition.first());
preText.compute(typeAndPosition.second(),
(p, n) -> (n == null ? " " : ";" ) + " " + typeAndPosition.first());
}
} else {
for (Pair<String, Integer> typeAndPosition : forcedTypeToPosition) {
preText.compute(typeAndPosition.second(),
(p, n) -> (n == null ? " " : n + ";" ) + " " + typeAndPosition.first());
}
}
tl.resetToIndex(prevIndex);
}

@Override
public Void visitExpressionStatement(ExpressionStatementTree node, Void p) {
return super.visitExpressionStatement(node, p);
}

Expand Down Expand Up @@ -876,6 +963,13 @@ public Void visitVariable(VariableTree tree, Void p) {

tl.moveNext();

if (info.getTreeUtilities().isVarType(getCurrentPath()) && isJavaInlineHintVarType()) {
int afterName = tl.offset();
TypeMirror type = info.getTrees().getTypeMirror(new TreePath(getCurrentPath(), tree.getType()));

this.preText.put(afterName, " : " + info.getTypeUtilities().getTypeName(type));
}

scan(tree.getInitializer(), p);

return null;
Expand Down Expand Up @@ -1062,6 +1156,9 @@ private int leadingIndent(String line) {
}

private void addParameterInlineHint(Tree tree) {
if(! isJavaInlineHintParameterName()) {
return;
}
TreePath pp = getCurrentPath().getParentPath();
Tree leaf = pp.getLeaf();
if (leaf != null &&
Expand All @@ -1076,7 +1173,6 @@ private void addParameterInlineHint(Tree tree) {
Element invoked = info.getTrees().getElement(pp);
if (invoked != null && (invoked.getKind() == ElementKind.METHOD || invoked.getKind() == ElementKind.CONSTRUCTOR)) {
long start = sourcePositions.getStartPosition(info.getCompilationUnit(), tree);
long end = start + 1;
ExecutableElement invokedMethod = (ExecutableElement) invoked;
pos = Math.min(pos, invokedMethod.getParameters().size() - 1);
if (pos != (-1)) {
Expand All @@ -1087,7 +1183,7 @@ private void addParameterInlineHint(Tree tree) {
shouldBeAdded = false;
}
if (shouldBeAdded) {
preText.put(new int[] {(int) start, (int) end},
preText.put((int) start,
invokedMethod.getParameters().get(pos).getSimpleName() + ":");
}
}
Expand Down
Loading

0 comments on commit 8415222

Please sign in to comment.