public void ProcessCompletionList(ModuleAnalysis analysis, PythonAst tree, SourceLocation location, CompletionList completions) { var evt = PostProcessCompletion; if (evt != null) { var e = new Extensibility.CompletionEventArgs(analysis, tree, location, completions); try { evt(this, e); completions = e.CompletionList; completions.items = completions.items ?? Array.Empty <CompletionItem>(); } catch (Exception ex) when(!ex.IsCriticalException()) { // We do not replace res in this case. } } }
public override Task <CompletionList> Completion(CompletionParams @params) { var uri = @params.textDocument.uri; // Make sure document is enqueued for processing var openFile = _openFiles.GetDocument(uri); _projectFiles.GetAnalysis(@params.textDocument, @params.position, @params._version, out var entry, out var tree); TraceMessage($"Completions in {uri} at {@params.position}"); tree = GetParseTree(entry, uri, CancellationToken, out var version) ?? tree; var analysis = entry?.Analysis; if (analysis == null) { TraceMessage($"No analysis found for {uri}"); return(Task.FromResult(new CompletionList())); } var opts = GetOptions(@params.context); var ctxt = new CompletionAnalysis(analysis, tree, @params.position, opts, _displayTextBuilder, this, () => entry.ReadDocument(_projectFiles.GetPart(uri), out _)); var members = ctxt.GetCompletionsFromString(@params._expr) ?? ctxt.GetCompletions(); if (members == null) { TraceMessage($"Do not trigger at {@params.position} in {uri}"); return(Task.FromResult(new CompletionList())); } if (_settings.SuppressAdvancedMembers) { members = members.Where(m => !m.label.StartsWith("__")); } var filterKind = @params.context?._filterKind; if (filterKind.HasValue && filterKind != CompletionItemKind.None) { TraceMessage($"Only returning {filterKind.Value} items"); members = members.Where(m => m.kind == filterKind.Value); } var res = new CompletionList { items = members.ToArray(), _expr = ctxt.ParentExpression?.ToCodeString(tree, CodeFormattingOptions.Traditional), _commitByDefault = ctxt.ShouldCommitByDefault }; SourceLocation trigger = @params.position; if (ctxt.ApplicableSpan.HasValue) { res._applicableSpan = ctxt.ApplicableSpan; } else if (ctxt.Node != null) { var span = ctxt.Node.GetSpan(tree); if (@params.context?.triggerKind == CompletionTriggerKind.TriggerCharacter) { if (span.End > trigger) { span = new SourceSpan(span.Start, trigger); } } if (span.End != span.Start) { res._applicableSpan = span; } } else if (@params.context?.triggerKind == CompletionTriggerKind.TriggerCharacter) { var ch = @params.context?.triggerCharacter.FirstOrDefault() ?? '\0'; res._applicableSpan = new SourceSpan( trigger.Line, Tokenizer.IsIdentifierStartChar(ch) ? Math.Max(1, trigger.Column - 1) : trigger.Column, trigger.Line, trigger.Column ); } LogMessage(MessageType.Info, $"Found {res.items.Length} completions for {uri} at {@params.position} after filtering"); var evt = PostProcessCompletion; if (evt != null) { var e = new Extensibility.CompletionEventArgs(analysis, tree, @params.position, res); try { evt(this, e); res = e.CompletionList; res.items = res.items ?? Array.Empty <CompletionItem>(); LogMessage(MessageType.Info, $"Found {res.items.Length} completions after hooks"); } catch (Exception ex) when(!ex.IsCriticalException()) { // We do not replace res in this case. LogMessage(MessageType.Error, $"Error while post-processing completions: {ex}"); } } return(Task.FromResult(res)); }