Skip to content

Commit 4c243c3

Browse files
committed
Fix search scope, fixed exception in search, goto symbol, imported completion
Fixes an exception that appears when you Ctrl + hover over a symbol. This was due to that it needs to be done under a progress indicator.
1 parent 6527125 commit 4c243c3

8 files changed

Lines changed: 143 additions & 95 deletions

File tree

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@
3434
*/
3535
public class MathematicaCompletionContributor extends CompletionContributor {
3636

37-
public static final double LOCAL_VARIABLE_PRIORITY = 4000;
38-
public static final double GLOBAL_VARIABLE_PRIORITY = 3500;
39-
public static final double IMPORT_VARIABLE_PRIORITY = 3000;
37+
public static final double LOCAL_VARIABLE_PRIORITY = 40;
38+
public static final double GLOBAL_VARIABLE_PRIORITY = 35;
39+
public static final double IMPORT_VARIABLE_PRIORITY = 30;
4040

4141

4242
public MathematicaCompletionContributor() {
4343
new BuiltinFunctionCompletion().addTo(this);
44-
new FileSymbolCompletion().addTo(this);
4544
new LocalizedSymbolCompletion().addTo(this);
45+
new FileSymbolCompletion().addTo(this);
4646
new ImportedSymbolCompletion().addTo(this);
4747
new SmartContextAwareCompletion().addTo(this);
4848
new CommentCompletion().addTo(this);

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
package de.halirutan.mathematica.codeinsight.completion.providers;
2525

2626
import com.intellij.codeInsight.completion.*;
27+
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher;
2728
import com.intellij.codeInsight.lookup.LookupElementBuilder;
2829
import com.intellij.openapi.diagnostic.Logger;
2930
import com.intellij.patterns.PlatformPatterns;
@@ -60,7 +61,11 @@ public void addTo(CompletionContributor contributor) {
6061
protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet result) {
6162
final PsiFile containingFile = parameters.getOriginalFile();
6263

63-
if (!parameters.isExtendedCompletion()) {
64+
String prefix = findCurrentText(parameters, parameters.getPosition());
65+
if (!parameters.isExtendedCompletion() && !prefix.isEmpty()) {
66+
final CamelHumpMatcher matcher = new CamelHumpMatcher(prefix, true);
67+
CompletionResultSet result2 = result.withPrefixMatcher(matcher);
68+
6469
LOG.debug("Running file symbol completion");
6570
final Set<String> symbols = PsiTreeUtil.findChildrenOfType(containingFile, Symbol.class).stream().filter(
6671
s -> {
@@ -70,7 +75,7 @@ protected void addCompletions(@NotNull CompletionParameters parameters, Processi
7075
).map(
7176
Symbol::getSymbolName
7277
).collect(Collectors.toSet());
73-
symbols.forEach(s -> result.addElement(PrioritizedLookupElement.withPriority(LookupElementBuilder.create(s),
78+
symbols.forEach(s -> result2.addElement(PrioritizedLookupElement.withPriority(LookupElementBuilder.create(s),
7479
GLOBAL_VARIABLE_PRIORITY)));
7580
}
7681
}

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

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,25 @@
2525

2626
import com.intellij.codeInsight.completion.*;
2727
import com.intellij.codeInsight.lookup.LookupElementBuilder;
28+
import com.intellij.openapi.module.Module;
29+
import com.intellij.openapi.module.ModuleUtilCore;
2830
import com.intellij.openapi.project.Project;
2931
import com.intellij.patterns.PlatformPatterns;
3032
import com.intellij.patterns.PsiElementPattern.Capture;
3133
import com.intellij.psi.PsiElement;
34+
import com.intellij.psi.search.GlobalSearchScope;
35+
import com.intellij.psi.search.ProjectScope;
3236
import com.intellij.util.ProcessingContext;
3337
import com.intellij.util.indexing.FileBasedIndex;
34-
import de.halirutan.mathematica.codeinsight.completion.util.ImportedContextVisitor;
3538
import de.halirutan.mathematica.index.packageexport.MathematicaPackageExportIndex;
36-
import de.halirutan.mathematica.index.packageexport.PackageExportSymbol;
3739
import de.halirutan.mathematica.lang.psi.api.Symbol;
3840
import org.jetbrains.annotations.NotNull;
3941

40-
import java.util.Collection;
41-
4242
import static de.halirutan.mathematica.codeinsight.completion.MathematicaCompletionContributor.IMPORT_VARIABLE_PRIORITY;
4343

4444

4545
/**
46-
* @author patrick (4/2/13)
46+
* Accesses the file index to provide completion for functions that are defined in other packages.
4747
*/
4848
public class ImportedSymbolCompletion extends MathematicaCompletionProvider {
4949

@@ -59,18 +59,27 @@ protected void addCompletions(@NotNull CompletionParameters parameters, Processi
5959
final Project project = callingSymbol.getProject();
6060

6161
String prefix = findCurrentText(parameters, parameters.getPosition());
62-
if (parameters.isExtendedCompletion() || !(prefix.isEmpty() || Character.isDigit(prefix.charAt(0)))) {
62+
final Module module =
63+
ModuleUtilCore.findModuleForFile(parameters.getOriginalFile().getVirtualFile(), project);
64+
if (module != null) {
6365

64-
ImportedContextVisitor importVisitor = new ImportedContextVisitor();
65-
callingSymbol.getContainingFile().accept(importVisitor);
66-
final FileBasedIndex index = FileBasedIndex.getInstance();
67-
final Collection<PackageExportSymbol> allKeys = index.getAllKeys(MathematicaPackageExportIndex.INDEX_ID, project);
68-
for (PackageExportSymbol key : allKeys) {
69-
if (key.isExported()) {
70-
result.addElement(PrioritizedLookupElement.withPriority(
71-
LookupElementBuilder.create(key.getSymbol()).appendTailText("(" + key.getFileName() + ")", true),
72-
IMPORT_VARIABLE_PRIORITY));
73-
}
66+
if (!parameters.isExtendedCompletion() || !(prefix.isEmpty() || Character.isDigit(prefix.charAt(0)))) {
67+
final GlobalSearchScope moduleScope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module)
68+
.union(ProjectScope.getLibrariesScope(project));
69+
final FileBasedIndex index = FileBasedIndex.getInstance();
70+
index.processAllKeys(
71+
MathematicaPackageExportIndex.INDEX_ID,
72+
key -> {
73+
if (key.isExported()) {
74+
result.addElement(PrioritizedLookupElement.withPriority(
75+
LookupElementBuilder.create(key.getSymbol()).withTypeText("(" + key.getFileName() + ")", true),
76+
IMPORT_VARIABLE_PRIORITY));
77+
}
78+
return true;
79+
},
80+
moduleScope,
81+
null
82+
);
7483
}
7584
}
7685
}

src/de/halirutan/mathematica/codeinsight/navigation/GotoSymbolItem.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@
2323

2424
import com.intellij.navigation.GotoRelatedItem;
2525
import com.intellij.psi.PsiElement;
26+
import de.halirutan.mathematica.util.MathematicaIcons;
2627
import org.jetbrains.annotations.NotNull;
2728
import org.jetbrains.annotations.Nullable;
2829

30+
import javax.swing.*;
31+
2932
/**
3033
* Provides a {@link GotoRelatedItem} that is useful to give information about the usage of a Mathematica symbol
3134
*
@@ -67,4 +70,9 @@ int getLineNumber() {
6770
return myLineNumber;
6871
}
6972

73+
@Nullable
74+
@Override
75+
public Icon getCustomIcon() {
76+
return MathematicaIcons.FILE_ICON;
77+
}
7078
}

src/de/halirutan/mathematica/codeinsight/navigation/MathematicaGotoRelatedProvider.kt

Lines changed: 38 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -43,47 +43,46 @@ import java.util.*
4343
*/
4444
class MathematicaGotoRelatedProvider : GotoRelatedProvider() {
4545

46-
override fun getItems(psiElement: PsiElement): List<GotoRelatedItem> {
47-
// I want the entries in the suggestion window to be sorted by line number!
48-
val symbol = when {
49-
psiElement is Symbol -> psiElement
50-
psiElement is LeafPsiElement && psiElement.elementType == MathematicaElementTypes.IDENTIFIER -> psiElement.parent
51-
else -> psiElement
52-
}
53-
val declarations = SortedList(Comparator.comparingInt<GotoSymbolItem>({ it.lineNumber }))
54-
if (symbol is Symbol) {
55-
val containingFile = symbol.getContainingFile()
56-
val resolve = symbol.resolve() ?: return declarations
57-
val usages = ReferencesSearch.search(resolve, GlobalSearchScope.fileScope(containingFile)).findAll()
58-
val project = symbol.getProject()
59-
val documentManager = PsiDocumentManager.getInstance(project)
60-
val fileName = containingFile.name
61-
val document = documentManager.getDocument(containingFile) ?: return declarations
62-
for (usage in usages) {
63-
val usageElement = usage.element
64-
if (usageElement is Symbol && usageElement.isValid) {
65-
// What follows is that want to collect code around the found element.
66-
// I will collect neighbouring PsiElements but not more than 20 characters to the right and
67-
// to the left of the current usageElement.
68-
val elementTextOffset = usageElement.getTextOffset()
69-
val lineNumber = document.getLineNumber(elementTextOffset)
70-
val lineStartOffset = document.getLineStartOffset(lineNumber)
71-
val lineEndOffset = document.getLineEndOffset(lineNumber)
72-
assert(lineStartOffset <= lineEndOffset)
46+
override fun getItems(psiElement: PsiElement): List<GotoRelatedItem> {
47+
// I want the entries in the suggestion window to be sorted by line number!
48+
val symbol = when {
49+
psiElement is Symbol -> psiElement
50+
psiElement is LeafPsiElement && psiElement.elementType == MathematicaElementTypes.IDENTIFIER -> psiElement.parent
51+
else -> psiElement
52+
}
53+
val declarations = SortedList(Comparator.comparingInt<GotoSymbolItem>({ it.lineNumber }))
54+
if (symbol is Symbol) {
55+
val containingFile = symbol.getContainingFile()
56+
val resolve = symbol.resolve() ?: return declarations
57+
val usages = ReferencesSearch.search(resolve, GlobalSearchScope.fileScope(containingFile)).findAll()
58+
val project = symbol.getProject()
59+
val documentManager = PsiDocumentManager.getInstance(project)
60+
val fileName = containingFile.name
61+
val document = documentManager.getDocument(containingFile) ?: return declarations
62+
for (usage in usages) {
63+
val usageElement = usage.element
64+
if (usageElement is Symbol && usageElement.isValid) {
65+
// What follows is that want to collect code around the found element.
66+
// I will collect neighbouring PsiElements but not more than 20 characters to the right and
67+
// to the left of the current usageElement.
68+
val elementTextOffset = usageElement.getTextOffset()
69+
val lineNumber = document.getLineNumber(elementTextOffset)
70+
val lineStartOffset = document.getLineStartOffset(lineNumber)
71+
val lineEndOffset = document.getLineEndOffset(lineNumber)
72+
assert(lineStartOffset <= lineEndOffset)
7373

74-
var textToShow = document.getText(TextRange.create(lineStartOffset, lineEndOffset)).trim { it <= ' ' }
75-
textToShow = if (textToShow.length > 80) textToShow.substring(0, 80) else textToShow
74+
var textToShow = document.getText(TextRange.create(lineStartOffset, lineEndOffset)).trim { it <= ' ' }
75+
textToShow = if (textToShow.length > 80) textToShow.substring(0, 80) else textToShow
7676

77-
val item = GotoSymbolItem(
78-
usageElement,
79-
textToShow,
80-
"(line ${lineNumber + 1} in $fileName)",
81-
lineNumber)
82-
declarations.add(item)
83-
}
84-
}
77+
val item = GotoSymbolItem(
78+
usageElement,
79+
textToShow,
80+
"(line ${lineNumber + 1} in $fileName)",
81+
lineNumber)
82+
declarations.add(item)
8583
}
86-
return declarations
84+
}
8785
}
88-
86+
return declarations
87+
}
8988
}

src/de/halirutan/mathematica/lang/psi/util/MathematicaFullFormCreator.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,14 @@ private void visitBlankLikeElement(PsiElement blank) {
125125

126126
}
127127

128+
@Override
129+
public void visitGroup(Group group) {
130+
final PsiElement[] children = group.getChildren();
131+
if (children.length == 1) {
132+
children[0].accept(this);
133+
}
134+
}
135+
128136
@Override
129137
public void visitStringifiedSymbol(StringifiedSymbol stringifiedSymbol) {
130138
addContent("\"" + stringifiedSymbol.getText() + "\"");

src/de/halirutan/mathematica/lang/psi/util/UsageMessages.kt

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,24 @@ fun extractUsageMessageString(symbol: Symbol): Pair<Symbol, List<String>> {
4747
if (resolve is Symbol) {
4848
return Pair(resolve, doUsageMessageExtract(resolve))
4949
}
50-
51-
// Find all references and look if one of them is a usage message
52-
ReferencesSearch.search(resolve).find { psiReference ->
53-
ProgressManager.checkCanceled()
54-
val elm = psiReference.element ?: return@find false
55-
if (elm is Symbol) {
56-
val messages = doUsageMessageExtract(elm)
57-
if (messages.isNotEmpty()) {
58-
return Pair(elm, messages)
50+
var result: Pair<Symbol, List<String>> = Pair(symbol, emptyList())
51+
val progressManager = ProgressManager.getInstance()
52+
val progressIndicator = progressManager.progressIndicator ?: return result
53+
progressManager.runProcess({
54+
ReferencesSearch.search(resolve).find { psiReference ->
55+
ProgressManager.checkCanceled()
56+
val elm = psiReference.element ?: return@find false
57+
if (elm is Symbol) {
58+
val messages = doUsageMessageExtract(elm)
59+
if (messages.isNotEmpty()) {
60+
result = Pair(elm, messages)
61+
}
5962
}
63+
return@find false
6064
}
61-
return@find false
62-
}
63-
return Pair(symbol, emptyList())
65+
}, progressIndicator)
66+
// Find all references and look if one of them is a usage message
67+
return result
6468
}
6569

6670
/**

src/de/halirutan/mathematica/lang/resolve/MathematicaGlobalSymbolResolver.java

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,25 @@
2323

2424
package de.halirutan.mathematica.lang.resolve;
2525

26+
import com.intellij.openapi.module.Module;
27+
import com.intellij.openapi.module.ModuleUtilCore;
2628
import com.intellij.openapi.project.Project;
2729
import com.intellij.openapi.vfs.VirtualFile;
2830
import com.intellij.psi.PsiFile;
2931
import com.intellij.psi.PsiManager;
3032
import com.intellij.psi.ResolveResult;
3133
import com.intellij.psi.search.GlobalSearchScope;
34+
import com.intellij.psi.search.ProjectScope;
3235
import com.intellij.psi.util.PsiTreeUtil;
3336
import com.intellij.util.indexing.FileBasedIndex;
3437
import de.halirutan.mathematica.index.packageexport.MathematicaPackageExportIndex;
35-
import de.halirutan.mathematica.index.packageexport.PackageExportSymbol;
3638
import de.halirutan.mathematica.lang.psi.api.Symbol;
3739
import de.halirutan.mathematica.lang.resolve.processors.GlobalDefinitionResolveProcessor;
3840
import org.jetbrains.annotations.NotNull;
3941

42+
import java.util.ArrayList;
4043
import java.util.Collection;
44+
import java.util.List;
4145

4246
import static de.halirutan.mathematica.lang.psi.util.MathematicaPsiUtilities.isBuiltInSymbol;
4347

@@ -80,32 +84,43 @@ public ResolveResult[] resolve(@NotNull Symbol ref, @NotNull PsiFile containingF
8084
return new ResolveResult[]{result};
8185
}
8286

83-
final FileBasedIndex fileIndex = FileBasedIndex.getInstance();
84-
final Project project = ref.getProject();
85-
final Collection<PackageExportSymbol> allKeys =
86-
fileIndex.getAllKeys(MathematicaPackageExportIndex.INDEX_ID, project);
87-
88-
for (PackageExportSymbol key : allKeys) {
89-
if (key.isExported() && key.getSymbol().equals(ref.getSymbolName())) {
90-
final Collection<VirtualFile> containingFiles =
91-
fileIndex.getContainingFiles(MathematicaPackageExportIndex.INDEX_ID, key,
92-
GlobalSearchScope.allScope(project));
93-
if (containingFiles.size() > 0) {
94-
final VirtualFile file = containingFiles.iterator().next();
95-
final PsiFile psiFile = PsiManager.getInstance(project).findFile(file);
96-
if (psiFile != null) {
97-
final Symbol externalSymbol =
98-
PsiTreeUtil.findElementOfClassAtOffset(psiFile, key.getOffset(), Symbol.class, true);
99-
if (externalSymbol != null) {
100-
final SymbolResolveResult result = symbolCache.cacheExternalSymbol(ref, externalSymbol, psiFile);
101-
return new ResolveResult[]{result};
87+
final Project project = containingFile.getProject();
88+
final Module module =
89+
ModuleUtilCore.findModuleForFile(containingFile.getVirtualFile(), project);
90+
if (module != null) {
91+
final List<SymbolResolveResult> references = new ArrayList<>();
92+
final PsiManager psiManager = PsiManager.getInstance(project);
93+
final FileBasedIndex fileIndex = FileBasedIndex.getInstance();
94+
final GlobalSearchScope moduleScope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module)
95+
.union(ProjectScope.getLibrariesScope(project));
96+
fileIndex.processAllKeys(
97+
MathematicaPackageExportIndex.INDEX_ID,
98+
key -> {
99+
if (key.isExported() && key.getSymbol().equals(ref.getSymbolName())) {
100+
final Collection<VirtualFile> containingFiles =
101+
fileIndex.getContainingFiles(MathematicaPackageExportIndex.INDEX_ID, key, moduleScope);
102+
containingFiles.forEach(file -> {
103+
final PsiFile psiFile = psiManager.findFile(file);
104+
if (psiFile != null) {
105+
final Symbol externalSymbol =
106+
PsiTreeUtil.findElementOfClassAtOffset(psiFile, key.getOffset(), Symbol.class, true);
107+
if (externalSymbol != null) {
108+
final SymbolResolveResult result = symbolCache.cacheExternalSymbol(ref, externalSymbol, psiFile);
109+
references.add(result);
110+
}
111+
}
112+
});
102113
}
103-
}
104-
}
114+
return true;
115+
}, moduleScope, null);
116+
fileIndex.getAllKeys(MathematicaPackageExportIndex.INDEX_ID, project);
117+
if (!references.isEmpty()) {
118+
return references.toArray(new ResolveResult[0]);
105119
}
106120
}
107121

108122
final SymbolResolveResult result = symbolCache.cacheInvalidFileSymbol(ref, containingFile);
109123
return new ResolveResult[]{result};
110124
}
125+
111126
}

0 commit comments

Comments
 (0)