Skip to content

Commit 2969b37

Browse files
committed
Improve unresolve-highlighting, resolving, and completion
* The file-indexer for libraries and packages will now recognize usage messages that are hidden inside an If[..] statement as this is sometimes used * The unresolved symbol annotation is a bit slower now but should pick up changes more consistently * Contexts of packages are now available for completion * Inside an empty (**) comment, it should now reliably work that sections and author, etc. annotations can be completed with Ctrl+Space * Non empty comments offer completion for function names * The completion panel shows now the localization for local variables * Hopefully fixed the "should not be null" assertion
1 parent caebd77 commit 2969b37

14 files changed

Lines changed: 186 additions & 119 deletions

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ task wrapper(type: Wrapper) {
7575
// Information about the plugin
7676

7777
// Plugin version number
78-
version '3.0pre6'
78+
version '3.0pre7'
7979

8080
intellij {
8181
version = '2017.3.1'

src/de/halirutan/mathematica/codeinsight/completion/MathematicaCompletionContributor.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@
2323

2424
import com.intellij.codeInsight.completion.CompletionContributor;
2525
import com.intellij.codeInsight.completion.CompletionInitializationContext;
26-
import de.halirutan.mathematica.codeinsight.completion.providers.BuiltinFunctionCompletionProvider;
27-
import de.halirutan.mathematica.codeinsight.completion.providers.CommentCompletionProvider;
28-
import de.halirutan.mathematica.codeinsight.completion.providers.FileSymbolCompletion;
29-
import de.halirutan.mathematica.codeinsight.completion.providers.ImportedSymbolCompletion;
26+
import de.halirutan.mathematica.codeinsight.completion.providers.*;
3027
import org.jetbrains.annotations.NotNull;
3128

3229
/**
@@ -43,11 +40,12 @@ public class MathematicaCompletionContributor extends CompletionContributor {
4340

4441

4542
public MathematicaCompletionContributor() {
46-
new BuiltinFunctionCompletionProvider().addTo(this);
43+
new BuiltinFunctionCompletion().addTo(this);
4744
new FileSymbolCompletion().addTo(this);
45+
new LocalizedSymbolCompletion().addTo(this);
4846
new ImportedSymbolCompletion().addTo(this);
4947
new SmartContextAwareCompletion().addTo(this);
50-
new CommentCompletionProvider().addTo(this);
48+
new CommentCompletion().addTo(this);
5149
}
5250

5351
@Override

src/de/halirutan/mathematica/codeinsight/completion/providers/BuiltinFunctionCompletionProvider.java renamed to src/de/halirutan/mathematica/codeinsight/completion/providers/BuiltinFunctionCompletion.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
* found in the resource directory de/halirutan/mathematica/codeinsight/completion.
4545
* @author hal (4/2/13)
4646
*/
47-
public class BuiltinFunctionCompletionProvider extends MathematicaCompletionProvider {
47+
public class BuiltinFunctionCompletion extends MathematicaCompletionProvider {
4848

4949
@Override
5050
public void addTo(CompletionContributor contributor) {

src/de/halirutan/mathematica/codeinsight/completion/providers/CommentCompletionProvider.java renamed to src/de/halirutan/mathematica/codeinsight/completion/providers/CommentCompletion.java

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
*
4646
* @author patrick (4/2/13)
4747
*/
48-
public class CommentCompletionProvider extends MathematicaCompletionProvider {
48+
public class CommentCompletion extends MathematicaCompletionProvider {
4949

5050
private static final String[] COMMENT_SECTIONS = {
5151
"Section", "Subsection", "Subsubsection", "Text", "Package", "Title", "Subtitle", "Subsubtitle", "Chapter", "Subchapter", "Subsubsubsection", "Subsubsubsubsubsection",
@@ -66,30 +66,29 @@ public void addTo(CompletionContributor contributor) {
6666
@Override
6767
protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet result) {
6868
if (parameters.getInvocationCount() > 0) {
69-
final String prefix = findCommentPrefix(parameters);
70-
7169
if (isEmptyComment(parameters)) {
7270
int priority = 100;
7371
for (String section : COMMENT_SECTIONS) {
7472
priority--;
7573

7674
final LookupElementBuilder elm = LookupElementBuilder.create(" ::" + section + ":: ")
77-
.withPresentableText("::" + section + "::");
78-
result.addElement(PrioritizedLookupElement.withPriority(elm, priority));
75+
.withPresentableText("::" + section + "::");
76+
result.withPrefixMatcher(new PlainPrefixMatcher(""))
77+
.addElement(PrioritizedLookupElement.withPriority(elm, priority));
7978
}
80-
}
8179

82-
final CompletionResultSet resultWithPrefix = result.withPrefixMatcher(prefix);
83-
84-
for (String tag : COMMENT_TAGS) {
85-
resultWithPrefix.addElement(LookupElementBuilder.create(":" + tag + ":"));
86-
}
87-
88-
final PsiFile file = parameters.getOriginalFile();
89-
final MathematicaGlobalResolveCache symbolCache = MathematicaGlobalResolveCache.getInstance(file.getProject());
90-
final List<String> cachedDefinitions = symbolCache.getCachedFileSymbolNames(file);
91-
for (String definition : cachedDefinitions) {
92-
resultWithPrefix.addElement(LookupElementBuilder.create(definition));
80+
for (String tag : COMMENT_TAGS) {
81+
result.withPrefixMatcher(new PlainPrefixMatcher(""))
82+
.addElement(LookupElementBuilder.create(" :" + tag + ": "));
83+
}
84+
} else {
85+
final String prefix = findCommentPrefix(parameters);
86+
final PsiFile file = parameters.getOriginalFile();
87+
final MathematicaGlobalResolveCache symbolCache = MathematicaGlobalResolveCache.getInstance(file.getProject());
88+
final List<String> cachedDefinitions = symbolCache.getCachedFileSymbolNames(file);
89+
for (String definition : cachedDefinitions) {
90+
result.withPrefixMatcher(new PlainPrefixMatcher(prefix)).addElement(LookupElementBuilder.create(definition));
91+
}
9392
}
9493
}
9594
}
@@ -98,7 +97,7 @@ private boolean isEmptyComment(CompletionParameters parameters) {
9897
final PsiElement commentElement = parameters.getPosition();
9998
if (commentElement instanceof PsiComment) {
10099
final String commentText = commentElement.getText();
101-
return commentText.matches("\\(\\*\\s*ZZZ\\s*\\*\\)") || EMPTY_COMMENT.matcher(commentText).matches();
100+
return commentText.matches("\\(\\*ZZZ\\*\\)") || EMPTY_COMMENT.matcher(commentText).matches();
102101
}
103102
return false;
104103
}

src/de/halirutan/mathematica/codeinsight/completion/providers/FileSymbolCompletion.java

Lines changed: 17 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -23,36 +23,32 @@
2323

2424
package de.halirutan.mathematica.codeinsight.completion.providers;
2525

26-
import com.google.common.collect.Lists;
2726
import com.intellij.codeInsight.completion.*;
2827
import com.intellij.codeInsight.lookup.LookupElementBuilder;
28+
import com.intellij.openapi.diagnostic.Logger;
2929
import com.intellij.patterns.PlatformPatterns;
3030
import com.intellij.patterns.PsiElementPattern.Capture;
3131
import com.intellij.psi.PsiElement;
3232
import com.intellij.psi.PsiFile;
33-
import com.intellij.psi.PsiRecursiveElementVisitor;
34-
import com.intellij.psi.ResolveState;
3533
import com.intellij.psi.util.PsiTreeUtil;
36-
import com.intellij.ui.JBColor;
3734
import com.intellij.util.ProcessingContext;
38-
import com.intellij.util.containers.hash.HashSet;
39-
import de.halirutan.mathematica.codeinsight.completion.util.LocalDefinitionCompletionProvider;
35+
import de.halirutan.mathematica.lang.psi.LocalizationConstruct;
4036
import de.halirutan.mathematica.lang.psi.api.Symbol;
41-
import de.halirutan.mathematica.lang.resolve.MathematicaGlobalResolveCache;
4237
import org.jetbrains.annotations.NotNull;
4338

44-
import java.util.List;
4539
import java.util.Set;
40+
import java.util.stream.Collectors;
4641

4742
import static de.halirutan.mathematica.codeinsight.completion.MathematicaCompletionContributor.GLOBAL_VARIABLE_PRIORITY;
48-
import static de.halirutan.mathematica.codeinsight.completion.MathematicaCompletionContributor.LOCAL_VARIABLE_PRIORITY;
4943

5044

5145
/**
52-
* @author patrick (4/2/13)
46+
* Provides completion for symbols that are defined at File Scope (opposed to locally bound variables).
5347
*/
5448
public class FileSymbolCompletion extends MathematicaCompletionProvider {
5549

50+
private static final Logger LOG =
51+
Logger.getInstance("#de.halirutan.mathematica.codeinsight.completion.providers.FileSymbolCompletion");
5652

5753
@Override
5854
public void addTo(CompletionContributor contributor) {
@@ -62,57 +58,20 @@ public void addTo(CompletionContributor contributor) {
6258

6359
@Override
6460
protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet result) {
65-
final Symbol callingSymbol = (Symbol) parameters.getPosition().getParent();
61+
final PsiFile containingFile = parameters.getOriginalFile();
6662

6763
if (!parameters.isExtendedCompletion()) {
68-
String prefix = findCurrentText(parameters, parameters.getPosition());
69-
if (prefix.isEmpty() || Character.isDigit(prefix.charAt(0))) {
70-
return;
71-
}
72-
final PsiFile containingFile = parameters.getOriginalFile();
73-
List<Symbol> variants = Lists.newArrayList();
74-
75-
final LocalDefinitionCompletionProvider processor = new LocalDefinitionCompletionProvider(callingSymbol);
76-
PsiTreeUtil.treeWalkUp(processor, callingSymbol, containingFile, ResolveState.initial());
77-
78-
variants.addAll(processor.getSymbols());
79-
80-
81-
for (Symbol currentSymbol : variants) {
82-
result.addElement(PrioritizedLookupElement.withPriority(
83-
LookupElementBuilder.create(currentSymbol).bold().withItemTextForeground(JBColor.GREEN),
84-
LOCAL_VARIABLE_PRIORITY));
85-
}
86-
87-
final MathematicaGlobalResolveCache cache =
88-
MathematicaGlobalResolveCache.getInstance(callingSymbol.getProject());
89-
cache.getCachedFileSymbolResolves(parameters.getOriginalFile())
90-
.forEach(symbolResolveResult -> {
91-
if (symbolResolveResult.getElement() != null) {
92-
result.addElement(PrioritizedLookupElement.withPriority(
93-
LookupElementBuilder.create(symbolResolveResult.getElement()).bold(),
94-
GLOBAL_VARIABLE_PRIORITY));
95-
}
96-
});
97-
98-
} else {
99-
final Set<String> allSymbols = new HashSet<>();
100-
PsiRecursiveElementVisitor visitor = new PsiRecursiveElementVisitor() {
101-
@Override
102-
public void visitElement(PsiElement element) {
103-
if (element instanceof Symbol) {
104-
allSymbols.add(((Symbol) element).getFullSymbolName());
64+
LOG.debug("Running file symbol completion");
65+
final Set<String> symbols = PsiTreeUtil.findChildrenOfType(containingFile, Symbol.class).stream().filter(
66+
s -> {
67+
final LocalizationConstruct.MScope localizationConstruct = s.getLocalizationConstruct();
68+
return s.isValid() && localizationConstruct == LocalizationConstruct.MScope.FILE_SCOPE;
10569
}
106-
element.acceptChildren(this);
107-
}
108-
};
109-
visitor.visitFile(parameters.getOriginalFile());
110-
for (String currentSymbol : allSymbols) {
111-
result.addElement(PrioritizedLookupElement.withPriority(LookupElementBuilder.create(currentSymbol),
112-
GLOBAL_VARIABLE_PRIORITY));
113-
114-
}
115-
70+
).map(
71+
Symbol::getSymbolName
72+
).collect(Collectors.toSet());
73+
symbols.forEach(s -> result.addElement(PrioritizedLookupElement.withPriority(LookupElementBuilder.create(s),
74+
GLOBAL_VARIABLE_PRIORITY)));
11675
}
11776
}
11877

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright (c) 2017 Patrick Scheibe
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
23+
package de.halirutan.mathematica.codeinsight.completion.providers;
24+
25+
import com.google.common.collect.Lists;
26+
import com.intellij.codeInsight.completion.*;
27+
import com.intellij.codeInsight.lookup.LookupElementBuilder;
28+
import com.intellij.patterns.PlatformPatterns;
29+
import com.intellij.patterns.PsiElementPattern.Capture;
30+
import com.intellij.psi.PsiElement;
31+
import com.intellij.psi.PsiFile;
32+
import com.intellij.psi.ResolveState;
33+
import com.intellij.psi.util.PsiTreeUtil;
34+
import com.intellij.ui.JBColor;
35+
import com.intellij.util.ProcessingContext;
36+
import de.halirutan.mathematica.codeinsight.completion.util.LocalDefinitionCompletionProvider;
37+
import de.halirutan.mathematica.lang.psi.LocalizationConstruct;
38+
import de.halirutan.mathematica.lang.psi.api.Symbol;
39+
import org.jetbrains.annotations.NotNull;
40+
41+
import java.util.List;
42+
43+
import static de.halirutan.mathematica.codeinsight.completion.MathematicaCompletionContributor.LOCAL_VARIABLE_PRIORITY;
44+
45+
46+
/**
47+
* @author patrick (4/2/13)
48+
*/
49+
public class LocalizedSymbolCompletion extends MathematicaCompletionProvider {
50+
51+
@Override
52+
public void addTo(CompletionContributor contributor) {
53+
final Capture<PsiElement> symbolPattern = PlatformPatterns.psiElement().withParent(Symbol.class);
54+
contributor.extend(CompletionType.BASIC, symbolPattern, this);
55+
}
56+
57+
@Override
58+
protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet result) {
59+
final Symbol callingSymbol = (Symbol) parameters.getPosition().getParent();
60+
61+
if (!parameters.isExtendedCompletion()) {
62+
String prefix = findCurrentText(parameters, parameters.getPosition());
63+
if (prefix.isEmpty() || Character.isDigit(prefix.charAt(0))) {
64+
return;
65+
}
66+
final PsiFile containingFile = parameters.getOriginalFile();
67+
List<Symbol> variants = Lists.newArrayList();
68+
69+
final LocalDefinitionCompletionProvider processor = new LocalDefinitionCompletionProvider(callingSymbol);
70+
PsiTreeUtil.treeWalkUp(processor, callingSymbol, containingFile, ResolveState.initial());
71+
72+
variants.addAll(processor.getSymbols());
73+
74+
for (Symbol currentSymbol : variants) {
75+
if (LocalizationConstruct.isLocalScoping(currentSymbol.getLocalizationConstruct())) {
76+
final String tailText = currentSymbol.getLocalizationConstruct().toString();
77+
result.addElement(PrioritizedLookupElement.withPriority(
78+
LookupElementBuilder.create(currentSymbol.getSymbolName())
79+
.withItemTextForeground(JBColor.GREEN)
80+
.withTypeText(tailText, true),
81+
LOCAL_VARIABLE_PRIORITY));
82+
}
83+
}
84+
}
85+
}
86+
87+
88+
}

src/de/halirutan/mathematica/codeinsight/highlighting/annotators/SymbolAnnotator.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ package de.halirutan.mathematica.codeinsight.highlighting.annotators
2525

2626
import com.intellij.lang.annotation.AnnotationHolder
2727
import com.intellij.lang.annotation.Annotator
28+
import com.intellij.openapi.progress.ProgressManager
2829
import com.intellij.psi.PsiElement
2930
import de.halirutan.mathematica.codeinsight.highlighting.MathematicaSyntaxHighlighterColors
3031
import de.halirutan.mathematica.lang.psi.LocalizationConstruct
@@ -42,12 +43,11 @@ class SymbolAnnotator : Annotator {
4243

4344
/** Annotates a [symbol] by checking its localization */
4445
override fun annotate(symbol: PsiElement, holder: AnnotationHolder) {
46+
ProgressManager.checkCanceled()
4547
if (symbol is Symbol) {
46-
symbol.resolve()
4748
val scope = symbol.localizationConstruct
4849
val scopeType = scope.type
4950
if (LocalizationConstruct.MScope.NULL_SCOPE == scope) {
50-
// MathematicaSyntaxHighlighterColors.setHighlighting(symbol, holder, MathematicaSyntaxHighlighterColors.UNKNOWN_SYMBOL)
5151
return
5252
}
5353
scopeType.let {

src/de/halirutan/mathematica/codeinsight/inspections/symbol/UnresolvedSymbolInspection.kt

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,18 @@ package de.halirutan.mathematica.codeinsight.inspections.symbol
2626
import com.intellij.codeHighlighting.HighlightDisplayLevel
2727
import com.intellij.codeInspection.LocalInspectionToolSession
2828
import com.intellij.codeInspection.ProblemsHolder
29+
import com.intellij.psi.PsiElement
2930
import com.intellij.psi.PsiElementVisitor
31+
import com.intellij.psi.PsiFile
32+
import com.intellij.psi.search.PsiElementProcessor
33+
import com.intellij.psi.util.PsiTreeUtil
3034
import de.halirutan.mathematica.codeinsight.inspections.AbstractInspection
3135
import de.halirutan.mathematica.codeinsight.inspections.InspectionBundle
3236
import de.halirutan.mathematica.lang.psi.LocalizationConstruct
3337
import de.halirutan.mathematica.lang.psi.MathematicaVisitor
38+
import de.halirutan.mathematica.lang.psi.api.MathematicaPsiFile
3439
import de.halirutan.mathematica.lang.psi.api.Symbol
40+
import de.halirutan.mathematica.lang.resolve.MathematicaGlobalResolveCache
3541

3642
/**
3743
*
@@ -51,16 +57,40 @@ class UnresolvedSymbolInspection : AbstractInspection() {
5157

5258
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
5359
return object : MathematicaVisitor() {
54-
override fun visitSymbol(symbol: Symbol?) {
55-
symbol?.let {
56-
if (!isOnTheFly) {
57-
symbol.resolve()
58-
}
59-
if (symbol.localizationConstruct == LocalizationConstruct.MScope.NULL_SCOPE) {
60-
holder.registerProblem(symbol, InspectionBundle.message("symbol.unresolved.message"))
60+
61+
override fun visitFile(file: PsiFile?) {
62+
if (file is MathematicaPsiFile) {
63+
MathematicaGlobalResolveCache.getInstance(file.project)
64+
PsiTreeUtil.processElements(file, PsiElementProcessor { symbol: PsiElement ->
65+
if (symbol is Symbol && symbol.localizationConstruct == LocalizationConstruct.MScope.NULL_SCOPE) {
66+
holder.registerProblem(symbol, InspectionBundle.message("symbol.unresolved.message"))
67+
}
68+
return@PsiElementProcessor true
6169
}
70+
71+
// { symbol: Symbol? ->
72+
// if (symbol is Symbol && symbol.localizationConstruct == LocalizationConstruct.MScope.NULL_SCOPE) {
73+
// holder.registerProblem(symbol, InspectionBundle.message("symbol.unresolved.message"))
74+
// }
75+
// }
76+
)
6277
}
6378
}
79+
80+
// override fun visitSymbol(symbol: Symbol?) {
81+
// symbol?.let {
82+
// val localizationConstruct = symbol.localizationConstruct
83+
// if (localizationConstruct == LocalizationConstruct.MScope.NULL_SCOPE || localizationConstruct == LocalizationConstruct.MScope.FILE_SCOPE) {
84+
// ReferencesSearch.search(symbol, GlobalSearchScope.FilesScope.fileScope(symbol.containingFile)).forEach { ref ->
85+
// ref.element?.let {
86+
// if (it is Symbol && it.localizationConstruct == LocalizationConstruct.MScope.NULL_SCOPE) {
87+
// holder.registerProblem(symbol, InspectionBundle.message("symbol.unresolved.message"))
88+
// }
89+
// }
90+
// }
91+
// }
92+
// }
93+
// }
6494
}
6595

6696
}

0 commit comments

Comments
 (0)