Skip to content

Commit d4afb3a

Browse files
committed
jsdoc: type/member completion in @see tags
1 parent ed95070 commit d4afb3a

File tree

4 files changed

+141
-10
lines changed

4 files changed

+141
-10
lines changed

plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/javascript/internal/core/codeassist/JSCompletionEngine.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.eclipse.dltk.codeassist.ICompletionEngine;
1515
import org.eclipse.dltk.core.ISourceModule;
1616
import org.eclipse.dltk.javascript.typeinfo.TypeMode;
17+
import org.eclipse.dltk.javascript.typeinfo.model.Member;
1718

1819
public interface JSCompletionEngine extends ICompletionEngine {
1920

@@ -24,4 +25,9 @@ public interface JSCompletionEngine extends ICompletionEngine {
2425
void completeTypes(ISourceModule module, TypeMode mode, String prefix,
2526
int offset);
2627

28+
void completeGlobals(ISourceModule module, String prefix, int offset,
29+
boolean jsdoc);
30+
31+
void completeMembers(ISourceModule module, String prefix, int offset,
32+
boolean jsdoc, Iterable<Member> memers);
2733
}

plugins/org.eclipse.dltk.javascript.core/src/org/eclipse/dltk/javascript/internal/core/codeassist/JavaScriptCompletionEngine2.java

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.eclipse.dltk.compiler.env.IModuleSource;
2727
import org.eclipse.dltk.compiler.problem.IValidationStatus;
2828
import org.eclipse.dltk.compiler.problem.ValidationStatus;
29+
import org.eclipse.dltk.core.CompletionContext;
2930
import org.eclipse.dltk.core.CompletionProposal;
3031
import org.eclipse.dltk.core.DLTKCore;
3132
import org.eclipse.dltk.core.IAccessRule;
@@ -151,6 +152,58 @@ public void completeTypes(ISourceModule module, TypeMode mode,
151152
Collections.<IValidatorExtension> emptyList()));
152153
}
153154

155+
public void completeGlobals(ISourceModule module, final String prefix,
156+
final int offset, boolean jsdoc) {
157+
final CompletionContext completionContext = new CompletionContext();
158+
completionContext.setOffset(offset);
159+
completionContext.setDoc(jsdoc);
160+
requestor.acceptContext(completionContext);
161+
setSourceRange(offset - prefix.length(), offset);
162+
final TypeInferencer2 inferencer2 = new TypeInferencer2();
163+
inferencer2.setModelElement(module);
164+
final CompletionVisitor visitor = new CompletionVisitor(inferencer2,
165+
Integer.MAX_VALUE);
166+
inferencer2.setVisitor(visitor);
167+
final Script script = JavaScriptParserUtil.parse(module, null);
168+
try {
169+
inferencer2.doInferencing(script);
170+
} catch (PositionReachedException e) {
171+
// e.printStackTrace();
172+
}
173+
ITypeSystem.CURRENT.runWith(inferencer2, new Runnable() {
174+
public void run() {
175+
final Reporter reporter = new Reporter(inferencer2, prefix,
176+
offset, visitor.createValidatorExtensions());
177+
doGlobalCompletion(visitor.getCollection(), reporter);
178+
}
179+
});
180+
}
181+
182+
/**
183+
* Generate completion proposals for the matching members from the specified
184+
* {@link Iterable}.
185+
*/
186+
public void completeMembers(ISourceModule module, String prefix,
187+
int offset, boolean jsdoc, Iterable<Member> memers) {
188+
final CompletionContext completionContext = new CompletionContext();
189+
completionContext.setOffset(offset);
190+
completionContext.setDoc(jsdoc);
191+
requestor.acceptContext(completionContext);
192+
setSourceRange(offset - prefix.length(), offset);
193+
final TypeInferencer2 inferencer2 = new TypeInferencer2();
194+
inferencer2.setModelElement(module);
195+
final CompletionVisitor visitor = new CompletionVisitor(inferencer2,
196+
offset);
197+
final Reporter reporter = new Reporter(inferencer2, prefix, offset,
198+
visitor.createValidatorExtensions());
199+
for (Member member : memers) {
200+
final String name = member.getName();
201+
if (reporter.matches(name)) {
202+
reporter.report(name, member);
203+
}
204+
}
205+
}
206+
154207
private void doCompletionOnType(TypeMode mode, Reporter reporter) {
155208
final ITypeInferenceContext context = reporter.context;
156209
Set<String> typeNames = context.listTypes(mode, reporter.getPrefix());
@@ -342,9 +395,7 @@ public void reportValueTypeMembers(IValueReference valueRef) {
342395
reportMember(member, member.getName(), true);
343396
}
344397
for (Member member : typeQuery.ignoreDuplicates(processed)) {
345-
if (member.isVisible()
346-
&& CharOperation.prefixEquals(prefix, member.getName(),
347-
false)) {
398+
if (member.isVisible() && matches(member.getName())) {
348399
reportMember(member, member.getName(),
349400
typeQuery.contains(member.getDeclaringType()));
350401
}
@@ -461,7 +512,7 @@ private void reportMember(Member member, String memberName,
461512
relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);
462513
proposal.setRelevance(relevance);
463514

464-
proposal.setCompletion(memberName);
515+
proposal.setCompletion(isFunction ? memberName + "()" : memberName);
465516
proposal.setName(memberName);
466517
proposal.setExtraInfo(member);
467518
proposal.setReplaceRange(startPosition - offset, endPosition
@@ -521,7 +572,9 @@ private void reportReference(IValueReference reference) {
521572
relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);
522573
proposal.setRelevance(relevance);
523574

524-
proposal.setCompletion(reference.getName());
575+
proposal.setCompletion(proposalKind == CompletionProposal.METHOD_REF ? reference
576+
.getName() + "()"
577+
: reference.getName());
525578
proposal.setName(reference.getName());
526579
proposal.setExtraInfo(reference);
527580
proposal.setReplaceRange(startPosition - offset, endPosition
@@ -592,8 +645,13 @@ private void doGlobalCompletion(IValueCollection collection,
592645
Reporter reporter) {
593646
reportItems(reporter, collection);
594647
if (allowGlobals) {
595-
doCompletionOnType(TypeMode.CODE, reporter);
596-
doCompletionOnKeyword(reporter.getPrefix(), reporter.getPosition());
648+
if (!requestor.isIgnored(CompletionProposal.TYPE_REF)) {
649+
doCompletionOnType(TypeMode.CODE, reporter);
650+
}
651+
if (!requestor.isIgnored(CompletionProposal.KEYWORD)) {
652+
doCompletionOnKeyword(reporter.getPrefix(),
653+
reporter.getPosition());
654+
}
597655
reportGlobals(reporter);
598656
}
599657
}

plugins/org.eclipse.dltk.javascript.ui/src/org/eclipse/dltk/javascript/internal/ui/text/completion/JSDocCompletionProposalComputer.java

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
import org.eclipse.core.runtime.IProgressMonitor;
1111
import org.eclipse.dltk.codeassist.ICompletionEngine;
1212
import org.eclipse.dltk.compiler.CharOperation;
13+
import org.eclipse.dltk.core.CompletionProposal;
1314
import org.eclipse.dltk.core.DLTKLanguageManager;
1415
import org.eclipse.dltk.core.ISourceModule;
16+
import org.eclipse.dltk.internal.javascript.ti.TypeInferencer2;
1517
import org.eclipse.dltk.javascript.core.JSKeywordCategory;
1618
import org.eclipse.dltk.javascript.core.JSKeywordManager;
1719
import org.eclipse.dltk.javascript.core.JavaScriptNature;
@@ -20,6 +22,8 @@
2022
import org.eclipse.dltk.javascript.internal.ui.templates.JSDocTemplateCompletionProcessor;
2123
import org.eclipse.dltk.javascript.parser.jsdoc.JSDocTag;
2224
import org.eclipse.dltk.javascript.typeinfo.TypeMode;
25+
import org.eclipse.dltk.javascript.typeinfo.model.Type;
26+
import org.eclipse.dltk.javascript.typeinfo.model.TypeKind;
2327
import org.eclipse.dltk.javascript.ui.text.IJavaScriptPartitions;
2428
import org.eclipse.dltk.ui.DLTKPluginImages;
2529
import org.eclipse.dltk.ui.templates.ScriptTemplateProposal;
@@ -87,16 +91,27 @@ public List<ICompletionProposal> computeCompletionProposals(
8791
index - tagStart));
8892
}
8993
final int tagEnd = index;
94+
final String tagName = new String(line, tagStart, tagEnd - tagStart);
9095
index = skipSpaces(line, index, offsetInLine);
96+
if (JSDocTag.SEE.equals(tagName)) {
97+
int valueStart = index;
98+
while (index < offsetInLine) {
99+
if (Character.isWhitespace(line[index])) {
100+
return Collections.emptyList();
101+
}
102+
++index;
103+
}
104+
return completionAfterSee(context, new String(line, valueStart,
105+
index - valueStart));
106+
}
91107
int depth = 0;
92108
int nameStart = index;
93109
boolean breakOnSpace = false;
94110
if (index < offsetInLine && line[index] == '{') {
95111
++index;
96112
depth = 1;
97113
nameStart = index;
98-
} else if (JSDocTag.TYPE.equals(new String(line, tagStart, tagEnd
99-
- tagStart))) {
114+
} else if (JSDocTag.TYPE.equals(tagName)) {
100115
breakOnSpace = true;
101116
} else {
102117
return Collections.emptyList();
@@ -127,6 +142,58 @@ public List<ICompletionProposal> computeCompletionProposals(
127142
return Collections.emptyList();
128143
}
129144

145+
private static final char JSDOC_MEMBER_SEPARATOR = '#';
146+
147+
/**
148+
* @param context
149+
* @param prefix
150+
* @return
151+
*/
152+
private List<ICompletionProposal> completionAfterSee(
153+
ContentAssistInvocationContext context, String prefix) {
154+
if (!(context instanceof ScriptContentAssistInvocationContext)) {
155+
return Collections.emptyList();
156+
}
157+
int pos = prefix.indexOf(JSDOC_MEMBER_SEPARATOR);
158+
if (pos < 0) {
159+
return completionOnType(context, prefix);
160+
} else {
161+
final JSCompletionEngine engine = getCompletionEngine();
162+
if (engine == null) {
163+
return Collections.emptyList();
164+
}
165+
final ISourceModule module = ((ScriptContentAssistInvocationContext) context)
166+
.getSourceModule();
167+
final JavaScriptCompletionProposalCollector collector = new JavaScriptCompletionProposalCollector(
168+
module);
169+
collector
170+
.setInvocationContext((ScriptContentAssistInvocationContext) context);
171+
engine.setRequestor(collector);
172+
collector.setAttribute(TypeMode.JSDOC, Boolean.TRUE);
173+
final String typeName = prefix.substring(0, pos);
174+
if (typeName.length() != 0) {
175+
final TypeInferencer2 inferencer2 = new TypeInferencer2();
176+
inferencer2.setModelElement(module);
177+
final Type type = inferencer2.getType(typeName);
178+
if (type == null || type.getKind() == TypeKind.UNKNOWN) {
179+
return Collections.emptyList();
180+
}
181+
engine.completeMembers(module, prefix.substring(pos + 1),
182+
context.getInvocationOffset(), true, type.getMembers());
183+
return Arrays.<ICompletionProposal> asList(collector
184+
.getScriptCompletionProposals());
185+
} else {
186+
collector.setIgnored(CompletionProposal.KEYWORD, true);
187+
collector.setIgnored(CompletionProposal.TYPE_REF, true);
188+
engine.setAllowGlobals(false);
189+
engine.completeGlobals(module, prefix.substring(1),
190+
context.getInvocationOffset(), true);
191+
return Arrays.<ICompletionProposal> asList(collector
192+
.getScriptCompletionProposals());
193+
}
194+
}
195+
}
196+
130197
private IRegion getLineRegion(IDocument document, int offset)
131198
throws BadLocationException {
132199
final IRegion region = document.getLineInformationOfOffset(offset);

plugins/org.eclipse.dltk.javascript.ui/src/org/eclipse/dltk/javascript/internal/ui/text/completion/JavaScriptContentAssistPreference.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ private void configureJSDocProcessor(ContentAssistant assistant,
5454
return;
5555
// String triggers= store.getString(AUTOACTIVATION_TRIGGERS_JAVADOC);
5656
// if (triggers != null)
57-
jdcp.setCompletionProposalAutoActivationCharacters("@".toCharArray());
57+
jdcp.setCompletionProposalAutoActivationCharacters("@#".toCharArray());
5858
// boolean enabled= store.getBoolean(CASE_SENSITIVITY);
5959
// jdcp.restrictProposalsToMatchingCases(enabled);
6060
}

0 commit comments

Comments
 (0)