Skip to content

Commit

Permalink
Improve unresolve-highlighting, resolving, and completion
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
halirutan committed Dec 27, 2017
1 parent caebd77 commit 2969b37
Show file tree
Hide file tree
Showing 14 changed files with 186 additions and 119 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ task wrapper(type: Wrapper) {
// Information about the plugin

// Plugin version number
version '3.0pre6'
version '3.0pre7'

intellij {
version = '2017.3.1'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@

import com.intellij.codeInsight.completion.CompletionContributor;
import com.intellij.codeInsight.completion.CompletionInitializationContext;
import de.halirutan.mathematica.codeinsight.completion.providers.BuiltinFunctionCompletionProvider;
import de.halirutan.mathematica.codeinsight.completion.providers.CommentCompletionProvider;
import de.halirutan.mathematica.codeinsight.completion.providers.FileSymbolCompletion;
import de.halirutan.mathematica.codeinsight.completion.providers.ImportedSymbolCompletion;
import de.halirutan.mathematica.codeinsight.completion.providers.*;
import org.jetbrains.annotations.NotNull;

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


public MathematicaCompletionContributor() {
new BuiltinFunctionCompletionProvider().addTo(this);
new BuiltinFunctionCompletion().addTo(this);
new FileSymbolCompletion().addTo(this);
new LocalizedSymbolCompletion().addTo(this);
new ImportedSymbolCompletion().addTo(this);
new SmartContextAwareCompletion().addTo(this);
new CommentCompletionProvider().addTo(this);
new CommentCompletion().addTo(this);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
* found in the resource directory de/halirutan/mathematica/codeinsight/completion.
* @author hal (4/2/13)
*/
public class BuiltinFunctionCompletionProvider extends MathematicaCompletionProvider {
public class BuiltinFunctionCompletion extends MathematicaCompletionProvider {

@Override
public void addTo(CompletionContributor contributor) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
*
* @author patrick (4/2/13)
*/
public class CommentCompletionProvider extends MathematicaCompletionProvider {
public class CommentCompletion extends MathematicaCompletionProvider {

private static final String[] COMMENT_SECTIONS = {
"Section", "Subsection", "Subsubsection", "Text", "Package", "Title", "Subtitle", "Subsubtitle", "Chapter", "Subchapter", "Subsubsubsection", "Subsubsubsubsubsection",
Expand All @@ -66,30 +66,29 @@ public void addTo(CompletionContributor contributor) {
@Override
protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet result) {
if (parameters.getInvocationCount() > 0) {
final String prefix = findCommentPrefix(parameters);

if (isEmptyComment(parameters)) {
int priority = 100;
for (String section : COMMENT_SECTIONS) {
priority--;

final LookupElementBuilder elm = LookupElementBuilder.create(" ::" + section + ":: ")
.withPresentableText("::" + section + "::");
result.addElement(PrioritizedLookupElement.withPriority(elm, priority));
.withPresentableText("::" + section + "::");
result.withPrefixMatcher(new PlainPrefixMatcher(""))
.addElement(PrioritizedLookupElement.withPriority(elm, priority));
}
}

final CompletionResultSet resultWithPrefix = result.withPrefixMatcher(prefix);

for (String tag : COMMENT_TAGS) {
resultWithPrefix.addElement(LookupElementBuilder.create(":" + tag + ":"));
}

final PsiFile file = parameters.getOriginalFile();
final MathematicaGlobalResolveCache symbolCache = MathematicaGlobalResolveCache.getInstance(file.getProject());
final List<String> cachedDefinitions = symbolCache.getCachedFileSymbolNames(file);
for (String definition : cachedDefinitions) {
resultWithPrefix.addElement(LookupElementBuilder.create(definition));
for (String tag : COMMENT_TAGS) {
result.withPrefixMatcher(new PlainPrefixMatcher(""))
.addElement(LookupElementBuilder.create(" :" + tag + ": "));
}
} else {
final String prefix = findCommentPrefix(parameters);
final PsiFile file = parameters.getOriginalFile();
final MathematicaGlobalResolveCache symbolCache = MathematicaGlobalResolveCache.getInstance(file.getProject());
final List<String> cachedDefinitions = symbolCache.getCachedFileSymbolNames(file);
for (String definition : cachedDefinitions) {
result.withPrefixMatcher(new PlainPrefixMatcher(prefix)).addElement(LookupElementBuilder.create(definition));
}
}
}
}
Expand All @@ -98,7 +97,7 @@ private boolean isEmptyComment(CompletionParameters parameters) {
final PsiElement commentElement = parameters.getPosition();
if (commentElement instanceof PsiComment) {
final String commentText = commentElement.getText();
return commentText.matches("\\(\\*\\s*ZZZ\\s*\\*\\)") || EMPTY_COMMENT.matcher(commentText).matches();
return commentText.matches("\\(\\*ZZZ\\*\\)") || EMPTY_COMMENT.matcher(commentText).matches();
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,32 @@

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

import com.google.common.collect.Lists;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.patterns.PsiElementPattern.Capture;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiRecursiveElementVisitor;
import com.intellij.psi.ResolveState;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.ui.JBColor;
import com.intellij.util.ProcessingContext;
import com.intellij.util.containers.hash.HashSet;
import de.halirutan.mathematica.codeinsight.completion.util.LocalDefinitionCompletionProvider;
import de.halirutan.mathematica.lang.psi.LocalizationConstruct;
import de.halirutan.mathematica.lang.psi.api.Symbol;
import de.halirutan.mathematica.lang.resolve.MathematicaGlobalResolveCache;
import org.jetbrains.annotations.NotNull;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static de.halirutan.mathematica.codeinsight.completion.MathematicaCompletionContributor.GLOBAL_VARIABLE_PRIORITY;
import static de.halirutan.mathematica.codeinsight.completion.MathematicaCompletionContributor.LOCAL_VARIABLE_PRIORITY;


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

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

@Override
public void addTo(CompletionContributor contributor) {
Expand All @@ -62,57 +58,20 @@ public void addTo(CompletionContributor contributor) {

@Override
protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet result) {
final Symbol callingSymbol = (Symbol) parameters.getPosition().getParent();
final PsiFile containingFile = parameters.getOriginalFile();

if (!parameters.isExtendedCompletion()) {
String prefix = findCurrentText(parameters, parameters.getPosition());
if (prefix.isEmpty() || Character.isDigit(prefix.charAt(0))) {
return;
}
final PsiFile containingFile = parameters.getOriginalFile();
List<Symbol> variants = Lists.newArrayList();

final LocalDefinitionCompletionProvider processor = new LocalDefinitionCompletionProvider(callingSymbol);
PsiTreeUtil.treeWalkUp(processor, callingSymbol, containingFile, ResolveState.initial());

variants.addAll(processor.getSymbols());


for (Symbol currentSymbol : variants) {
result.addElement(PrioritizedLookupElement.withPriority(
LookupElementBuilder.create(currentSymbol).bold().withItemTextForeground(JBColor.GREEN),
LOCAL_VARIABLE_PRIORITY));
}

final MathematicaGlobalResolveCache cache =
MathematicaGlobalResolveCache.getInstance(callingSymbol.getProject());
cache.getCachedFileSymbolResolves(parameters.getOriginalFile())
.forEach(symbolResolveResult -> {
if (symbolResolveResult.getElement() != null) {
result.addElement(PrioritizedLookupElement.withPriority(
LookupElementBuilder.create(symbolResolveResult.getElement()).bold(),
GLOBAL_VARIABLE_PRIORITY));
}
});

} else {
final Set<String> allSymbols = new HashSet<>();
PsiRecursiveElementVisitor visitor = new PsiRecursiveElementVisitor() {
@Override
public void visitElement(PsiElement element) {
if (element instanceof Symbol) {
allSymbols.add(((Symbol) element).getFullSymbolName());
LOG.debug("Running file symbol completion");
final Set<String> symbols = PsiTreeUtil.findChildrenOfType(containingFile, Symbol.class).stream().filter(
s -> {
final LocalizationConstruct.MScope localizationConstruct = s.getLocalizationConstruct();
return s.isValid() && localizationConstruct == LocalizationConstruct.MScope.FILE_SCOPE;
}
element.acceptChildren(this);
}
};
visitor.visitFile(parameters.getOriginalFile());
for (String currentSymbol : allSymbols) {
result.addElement(PrioritizedLookupElement.withPriority(LookupElementBuilder.create(currentSymbol),
GLOBAL_VARIABLE_PRIORITY));

}

).map(
Symbol::getSymbolName
).collect(Collectors.toSet());
symbols.forEach(s -> result.addElement(PrioritizedLookupElement.withPriority(LookupElementBuilder.create(s),
GLOBAL_VARIABLE_PRIORITY)));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2017 Patrick Scheibe
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

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

import com.google.common.collect.Lists;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.patterns.PsiElementPattern.Capture;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.ResolveState;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.ui.JBColor;
import com.intellij.util.ProcessingContext;
import de.halirutan.mathematica.codeinsight.completion.util.LocalDefinitionCompletionProvider;
import de.halirutan.mathematica.lang.psi.LocalizationConstruct;
import de.halirutan.mathematica.lang.psi.api.Symbol;
import org.jetbrains.annotations.NotNull;

import java.util.List;

import static de.halirutan.mathematica.codeinsight.completion.MathematicaCompletionContributor.LOCAL_VARIABLE_PRIORITY;


/**
* @author patrick (4/2/13)
*/
public class LocalizedSymbolCompletion extends MathematicaCompletionProvider {

@Override
public void addTo(CompletionContributor contributor) {
final Capture<PsiElement> symbolPattern = PlatformPatterns.psiElement().withParent(Symbol.class);
contributor.extend(CompletionType.BASIC, symbolPattern, this);
}

@Override
protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet result) {
final Symbol callingSymbol = (Symbol) parameters.getPosition().getParent();

if (!parameters.isExtendedCompletion()) {
String prefix = findCurrentText(parameters, parameters.getPosition());
if (prefix.isEmpty() || Character.isDigit(prefix.charAt(0))) {
return;
}
final PsiFile containingFile = parameters.getOriginalFile();
List<Symbol> variants = Lists.newArrayList();

final LocalDefinitionCompletionProvider processor = new LocalDefinitionCompletionProvider(callingSymbol);
PsiTreeUtil.treeWalkUp(processor, callingSymbol, containingFile, ResolveState.initial());

variants.addAll(processor.getSymbols());

for (Symbol currentSymbol : variants) {
if (LocalizationConstruct.isLocalScoping(currentSymbol.getLocalizationConstruct())) {
final String tailText = currentSymbol.getLocalizationConstruct().toString();
result.addElement(PrioritizedLookupElement.withPriority(
LookupElementBuilder.create(currentSymbol.getSymbolName())
.withItemTextForeground(JBColor.GREEN)
.withTypeText(tailText, true),
LOCAL_VARIABLE_PRIORITY));
}
}
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ package de.halirutan.mathematica.codeinsight.highlighting.annotators

import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.Annotator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.psi.PsiElement
import de.halirutan.mathematica.codeinsight.highlighting.MathematicaSyntaxHighlighterColors
import de.halirutan.mathematica.lang.psi.LocalizationConstruct
Expand All @@ -42,12 +43,11 @@ class SymbolAnnotator : Annotator {

/** Annotates a [symbol] by checking its localization */
override fun annotate(symbol: PsiElement, holder: AnnotationHolder) {
ProgressManager.checkCanceled()
if (symbol is Symbol) {
symbol.resolve()
val scope = symbol.localizationConstruct
val scopeType = scope.type
if (LocalizationConstruct.MScope.NULL_SCOPE == scope) {
// MathematicaSyntaxHighlighterColors.setHighlighting(symbol, holder, MathematicaSyntaxHighlighterColors.UNKNOWN_SYMBOL)
return
}
scopeType.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,18 @@ package de.halirutan.mathematica.codeinsight.inspections.symbol
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.codeInspection.LocalInspectionToolSession
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiFile
import com.intellij.psi.search.PsiElementProcessor
import com.intellij.psi.util.PsiTreeUtil
import de.halirutan.mathematica.codeinsight.inspections.AbstractInspection
import de.halirutan.mathematica.codeinsight.inspections.InspectionBundle
import de.halirutan.mathematica.lang.psi.LocalizationConstruct
import de.halirutan.mathematica.lang.psi.MathematicaVisitor
import de.halirutan.mathematica.lang.psi.api.MathematicaPsiFile
import de.halirutan.mathematica.lang.psi.api.Symbol
import de.halirutan.mathematica.lang.resolve.MathematicaGlobalResolveCache

/**
*
Expand All @@ -51,16 +57,40 @@ class UnresolvedSymbolInspection : AbstractInspection() {

override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return object : MathematicaVisitor() {
override fun visitSymbol(symbol: Symbol?) {
symbol?.let {
if (!isOnTheFly) {
symbol.resolve()
}
if (symbol.localizationConstruct == LocalizationConstruct.MScope.NULL_SCOPE) {
holder.registerProblem(symbol, InspectionBundle.message("symbol.unresolved.message"))

override fun visitFile(file: PsiFile?) {
if (file is MathematicaPsiFile) {
MathematicaGlobalResolveCache.getInstance(file.project)
PsiTreeUtil.processElements(file, PsiElementProcessor { symbol: PsiElement ->
if (symbol is Symbol && symbol.localizationConstruct == LocalizationConstruct.MScope.NULL_SCOPE) {
holder.registerProblem(symbol, InspectionBundle.message("symbol.unresolved.message"))
}
return@PsiElementProcessor true
}

// { symbol: Symbol? ->
// if (symbol is Symbol && symbol.localizationConstruct == LocalizationConstruct.MScope.NULL_SCOPE) {
// holder.registerProblem(symbol, InspectionBundle.message("symbol.unresolved.message"))
// }
// }
)
}
}

// override fun visitSymbol(symbol: Symbol?) {
// symbol?.let {
// val localizationConstruct = symbol.localizationConstruct
// if (localizationConstruct == LocalizationConstruct.MScope.NULL_SCOPE || localizationConstruct == LocalizationConstruct.MScope.FILE_SCOPE) {
// ReferencesSearch.search(symbol, GlobalSearchScope.FilesScope.fileScope(symbol.containingFile)).forEach { ref ->
// ref.element?.let {
// if (it is Symbol && it.localizationConstruct == LocalizationConstruct.MScope.NULL_SCOPE) {
// holder.registerProblem(symbol, InspectionBundle.message("symbol.unresolved.message"))
// }
// }
// }
// }
// }
// }
}

}
Expand Down
Loading

0 comments on commit 2969b37

Please sign in to comment.