lsp: Provide completion reason in the request (#12893)
This should help LS make a better call about the completions it should return back to the caller. For example, it speeds up import completions for typescript. Before: https://github.com/zed-industries/zed/assets/24362066/b38fd565-f9ff-4db7-a87f-c3b31a9fdc96 after: https://github.com/zed-industries/zed/assets/24362066/d4fbc9ae-9aab-4543-b9f6-16acf1619576 This should be merged after 06.12 Preview to give it some time on Nightly. Release Notes: - N/A
This commit is contained in:
parent
eb7b5a7131
commit
0a13b9ee01
12 changed files with 86 additions and 26 deletions
|
@ -2350,7 +2350,7 @@ impl ContextEditor {
|
||||||
editor.insert(&format!("/{name}"), cx);
|
editor.insert(&format!("/{name}"), cx);
|
||||||
if command.requires_argument() {
|
if command.requires_argument() {
|
||||||
editor.insert(" ", cx);
|
editor.insert(" ", cx);
|
||||||
editor.show_completions(&ShowCompletions, cx);
|
editor.show_completions(&ShowCompletions::default(), cx);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -217,6 +217,7 @@ impl CompletionProvider for SlashCommandCompletionProvider {
|
||||||
&self,
|
&self,
|
||||||
buffer: &Model<Buffer>,
|
buffer: &Model<Buffer>,
|
||||||
buffer_position: Anchor,
|
buffer_position: Anchor,
|
||||||
|
_: editor::CompletionContext,
|
||||||
cx: &mut ViewContext<Editor>,
|
cx: &mut ViewContext<Editor>,
|
||||||
) -> Task<Result<Vec<project::Completion>>> {
|
) -> Task<Result<Vec<project::Completion>>> {
|
||||||
let Some((name, argument, command_range, argument_range)) =
|
let Some((name, argument, command_range, argument_range)) =
|
||||||
|
|
|
@ -14,7 +14,9 @@ use language::{
|
||||||
};
|
};
|
||||||
use lsp::FakeLanguageServer;
|
use lsp::FakeLanguageServer;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use project::{search::SearchQuery, Project, ProjectPath, SearchResult};
|
use project::{
|
||||||
|
search::SearchQuery, Project, ProjectPath, SearchResult, DEFAULT_COMPLETION_CONTEXT,
|
||||||
|
};
|
||||||
use rand::{
|
use rand::{
|
||||||
distributions::{Alphanumeric, DistString},
|
distributions::{Alphanumeric, DistString},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
@ -829,7 +831,7 @@ impl RandomizedTest for ProjectCollaborationTest {
|
||||||
.map_ok(|_| ())
|
.map_ok(|_| ())
|
||||||
.boxed(),
|
.boxed(),
|
||||||
LspRequestKind::Completion => project
|
LspRequestKind::Completion => project
|
||||||
.completions(&buffer, offset, cx)
|
.completions(&buffer, offset, DEFAULT_COMPLETION_CONTEXT, cx)
|
||||||
.map_ok(|_| ())
|
.map_ok(|_| ())
|
||||||
.boxed(),
|
.boxed(),
|
||||||
LspRequestKind::CodeAction => project
|
LspRequestKind::CodeAction => project
|
||||||
|
|
|
@ -46,6 +46,7 @@ impl CompletionProvider for MessageEditorCompletionProvider {
|
||||||
&self,
|
&self,
|
||||||
buffer: &Model<Buffer>,
|
buffer: &Model<Buffer>,
|
||||||
buffer_position: language::Anchor,
|
buffer_position: language::Anchor,
|
||||||
|
_: editor::CompletionContext,
|
||||||
cx: &mut ViewContext<Editor>,
|
cx: &mut ViewContext<Editor>,
|
||||||
) -> Task<anyhow::Result<Vec<Completion>>> {
|
) -> Task<anyhow::Result<Vec<Completion>>> {
|
||||||
let Some(handle) = self.0.upgrade() else {
|
let Some(handle) = self.0.upgrade() else {
|
||||||
|
|
|
@ -125,6 +125,11 @@ pub struct ExpandExcerptsDown {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub(super) lines: u32,
|
pub(super) lines: u32,
|
||||||
}
|
}
|
||||||
|
#[derive(PartialEq, Clone, Deserialize, Default)]
|
||||||
|
pub struct ShowCompletions {
|
||||||
|
#[serde(default)]
|
||||||
|
pub(super) trigger: Option<char>,
|
||||||
|
}
|
||||||
|
|
||||||
impl_actions!(
|
impl_actions!(
|
||||||
editor,
|
editor,
|
||||||
|
@ -147,6 +152,7 @@ impl_actions!(
|
||||||
SelectToBeginningOfLine,
|
SelectToBeginningOfLine,
|
||||||
SelectToEndOfLine,
|
SelectToEndOfLine,
|
||||||
SelectUpByLines,
|
SelectUpByLines,
|
||||||
|
ShowCompletions,
|
||||||
ToggleCodeActions,
|
ToggleCodeActions,
|
||||||
ToggleComments,
|
ToggleComments,
|
||||||
UnfoldAt,
|
UnfoldAt,
|
||||||
|
@ -274,7 +280,6 @@ gpui::actions!(
|
||||||
SelectToStartOfParagraph,
|
SelectToStartOfParagraph,
|
||||||
SelectUp,
|
SelectUp,
|
||||||
ShowCharacterPalette,
|
ShowCharacterPalette,
|
||||||
ShowCompletions,
|
|
||||||
ShowInlineCompletion,
|
ShowInlineCompletion,
|
||||||
ShuffleLines,
|
ShuffleLines,
|
||||||
SortLinesCaseInsensitive,
|
SortLinesCaseInsensitive,
|
||||||
|
|
|
@ -93,7 +93,8 @@ use linked_editing_ranges::refresh_linked_ranges;
|
||||||
use task::{ResolvedTask, TaskTemplate, TaskVariables};
|
use task::{ResolvedTask, TaskTemplate, TaskVariables};
|
||||||
|
|
||||||
use hover_links::{HoverLink, HoveredLinkState, InlayHighlight};
|
use hover_links::{HoverLink, HoveredLinkState, InlayHighlight};
|
||||||
use lsp::{DiagnosticSeverity, LanguageServerId};
|
pub use lsp::CompletionContext;
|
||||||
|
use lsp::{CompletionTriggerKind, DiagnosticSeverity, LanguageServerId};
|
||||||
use mouse_context_menu::MouseContextMenu;
|
use mouse_context_menu::MouseContextMenu;
|
||||||
use movement::TextLayoutDetails;
|
use movement::TextLayoutDetails;
|
||||||
pub use multi_buffer::{
|
pub use multi_buffer::{
|
||||||
|
@ -2300,7 +2301,7 @@ impl Editor {
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
if show_completions {
|
if show_completions {
|
||||||
self.show_completions(&ShowCompletions, cx);
|
self.show_completions(&ShowCompletions { trigger: None }, cx);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
drop(context_menu);
|
drop(context_menu);
|
||||||
|
@ -3494,7 +3495,12 @@ impl Editor {
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
if self.is_completion_trigger(text, trigger_in_words, cx) {
|
if self.is_completion_trigger(text, trigger_in_words, cx) {
|
||||||
self.show_completions(&ShowCompletions, cx);
|
self.show_completions(
|
||||||
|
&ShowCompletions {
|
||||||
|
trigger: text.chars().last(),
|
||||||
|
},
|
||||||
|
cx,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
self.hide_context_menu(cx);
|
self.hide_context_menu(cx);
|
||||||
}
|
}
|
||||||
|
@ -3890,7 +3896,7 @@ impl Editor {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_completions(&mut self, _: &ShowCompletions, cx: &mut ViewContext<Self>) {
|
pub fn show_completions(&mut self, options: &ShowCompletions, cx: &mut ViewContext<Self>) {
|
||||||
if self.pending_rename.is_some() {
|
if self.pending_rename.is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3908,7 +3914,29 @@ impl Editor {
|
||||||
};
|
};
|
||||||
|
|
||||||
let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
|
let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
|
||||||
let completions = provider.completions(&buffer, buffer_position, cx);
|
let is_followup_invoke = {
|
||||||
|
let context_menu_state = self.context_menu.read();
|
||||||
|
matches!(
|
||||||
|
context_menu_state.deref(),
|
||||||
|
Some(ContextMenu::Completions(_))
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let trigger_kind = match (options.trigger, is_followup_invoke) {
|
||||||
|
(_, true) => CompletionTriggerKind::TRIGGER_FOR_INCOMPLETE_COMPLETIONS,
|
||||||
|
(Some(_), _) => CompletionTriggerKind::TRIGGER_CHARACTER,
|
||||||
|
_ => CompletionTriggerKind::INVOKED,
|
||||||
|
};
|
||||||
|
let completion_context = CompletionContext {
|
||||||
|
trigger_character: options.trigger.and_then(|c| {
|
||||||
|
if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
|
||||||
|
Some(String::from(c))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
trigger_kind,
|
||||||
|
};
|
||||||
|
let completions = provider.completions(&buffer, buffer_position, completion_context, cx);
|
||||||
|
|
||||||
let id = post_inc(&mut self.next_completion_id);
|
let id = post_inc(&mut self.next_completion_id);
|
||||||
let task = cx.spawn(|this, mut cx| {
|
let task = cx.spawn(|this, mut cx| {
|
||||||
|
@ -4166,7 +4194,7 @@ impl Editor {
|
||||||
}
|
}
|
||||||
|
|
||||||
if completion.show_new_completions_on_confirm {
|
if completion.show_new_completions_on_confirm {
|
||||||
self.show_completions(&ShowCompletions, cx);
|
self.show_completions(&ShowCompletions { trigger: None }, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
let provider = self.completion_provider.as_ref()?;
|
let provider = self.completion_provider.as_ref()?;
|
||||||
|
@ -11428,6 +11456,7 @@ pub trait CompletionProvider {
|
||||||
&self,
|
&self,
|
||||||
buffer: &Model<Buffer>,
|
buffer: &Model<Buffer>,
|
||||||
buffer_position: text::Anchor,
|
buffer_position: text::Anchor,
|
||||||
|
trigger: CompletionContext,
|
||||||
cx: &mut ViewContext<Editor>,
|
cx: &mut ViewContext<Editor>,
|
||||||
) -> Task<Result<Vec<Completion>>>;
|
) -> Task<Result<Vec<Completion>>>;
|
||||||
|
|
||||||
|
@ -11462,10 +11491,11 @@ impl CompletionProvider for Model<Project> {
|
||||||
&self,
|
&self,
|
||||||
buffer: &Model<Buffer>,
|
buffer: &Model<Buffer>,
|
||||||
buffer_position: text::Anchor,
|
buffer_position: text::Anchor,
|
||||||
|
options: CompletionContext,
|
||||||
cx: &mut ViewContext<Editor>,
|
cx: &mut ViewContext<Editor>,
|
||||||
) -> Task<Result<Vec<Completion>>> {
|
) -> Task<Result<Vec<Completion>>> {
|
||||||
self.update(cx, |project, cx| {
|
self.update(cx, |project, cx| {
|
||||||
project.completions(&buffer, buffer_position, cx)
|
project.completions(&buffer, buffer_position, options, cx)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6705,7 +6705,7 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||||
cx.assert_editor_state("editor.cloˇ");
|
cx.assert_editor_state("editor.cloˇ");
|
||||||
assert!(cx.editor(|e, _| e.context_menu.read().is_none()));
|
assert!(cx.editor(|e, _| e.context_menu.read().is_none()));
|
||||||
cx.update_editor(|editor, cx| {
|
cx.update_editor(|editor, cx| {
|
||||||
editor.show_completions(&ShowCompletions, cx);
|
editor.show_completions(&ShowCompletions { trigger: None }, cx);
|
||||||
});
|
});
|
||||||
handle_completion_request(
|
handle_completion_request(
|
||||||
&mut cx,
|
&mut cx,
|
||||||
|
|
|
@ -15,7 +15,7 @@ use http::{FakeHttpClient, Response};
|
||||||
use language::{LanguageMatcher, LanguageRegistry, LanguageServerBinaryStatus, LanguageServerName};
|
use language::{LanguageMatcher, LanguageRegistry, LanguageServerBinaryStatus, LanguageServerName};
|
||||||
use node_runtime::FakeNodeRuntime;
|
use node_runtime::FakeNodeRuntime;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use project::Project;
|
use project::{Project, DEFAULT_COMPLETION_CONTEXT};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use settings::{Settings as _, SettingsStore};
|
use settings::{Settings as _, SettingsStore};
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -657,7 +657,9 @@ async fn test_extension_store_with_gleam_extension(cx: &mut TestAppContext) {
|
||||||
});
|
});
|
||||||
|
|
||||||
let completion_labels = project
|
let completion_labels = project
|
||||||
.update(cx, |project, cx| project.completions(&buffer, 0, cx))
|
.update(cx, |project, cx| {
|
||||||
|
project.completions(&buffer, 0, DEFAULT_COMPLETION_CONTEXT, cx)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
@ -1061,7 +1061,7 @@ impl LanguageServer {
|
||||||
select! {
|
select! {
|
||||||
response = rx.fuse() => {
|
response = rx.fuse() => {
|
||||||
let elapsed = started.elapsed();
|
let elapsed = started.elapsed();
|
||||||
log::trace!("Took {elapsed:?} to receive response to {method:?} id {id}");
|
log::info!("Took {elapsed:?} to receive response to {method:?} id {id}");
|
||||||
cancel_on_drop.abort();
|
cancel_on_drop.abort();
|
||||||
response?
|
response?
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,9 @@ use language::{
|
||||||
OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Transaction, Unclipped,
|
OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Transaction, Unclipped,
|
||||||
};
|
};
|
||||||
use lsp::{
|
use lsp::{
|
||||||
CompletionListItemDefaultsEditRange, DocumentHighlightKind, LanguageServer, LanguageServerId,
|
CompletionContext, CompletionListItemDefaultsEditRange, CompletionTriggerKind,
|
||||||
LinkedEditingRangeServerCapabilities, OneOf, ServerCapabilities,
|
DocumentHighlightKind, LanguageServer, LanguageServerId, LinkedEditingRangeServerCapabilities,
|
||||||
|
OneOf, ServerCapabilities,
|
||||||
};
|
};
|
||||||
use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};
|
use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};
|
||||||
use text::{BufferId, LineEnding};
|
use text::{BufferId, LineEnding};
|
||||||
|
@ -127,6 +128,7 @@ pub(crate) struct GetHover {
|
||||||
|
|
||||||
pub(crate) struct GetCompletions {
|
pub(crate) struct GetCompletions {
|
||||||
pub position: PointUtf16,
|
pub position: PointUtf16,
|
||||||
|
pub context: CompletionContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -1464,7 +1466,7 @@ impl LspCommand for GetCompletions {
|
||||||
lsp::TextDocumentIdentifier::new(lsp::Uri::from_file_path(path).unwrap().into()),
|
lsp::TextDocumentIdentifier::new(lsp::Uri::from_file_path(path).unwrap().into()),
|
||||||
point_to_lsp(self.position),
|
point_to_lsp(self.position),
|
||||||
),
|
),
|
||||||
context: Default::default(),
|
context: Some(self.context.clone()),
|
||||||
work_done_progress_params: Default::default(),
|
work_done_progress_params: Default::default(),
|
||||||
partial_result_params: Default::default(),
|
partial_result_params: Default::default(),
|
||||||
}
|
}
|
||||||
|
@ -1649,7 +1651,13 @@ impl LspCommand for GetCompletions {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.ok_or_else(|| anyhow!("invalid position"))??;
|
.ok_or_else(|| anyhow!("invalid position"))??;
|
||||||
Ok(Self { position })
|
Ok(Self {
|
||||||
|
position,
|
||||||
|
context: CompletionContext {
|
||||||
|
trigger_kind: CompletionTriggerKind::INVOKED,
|
||||||
|
trigger_character: None,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn response_to_proto(
|
fn response_to_proto(
|
||||||
|
|
|
@ -58,7 +58,7 @@ use language::{
|
||||||
};
|
};
|
||||||
use log::error;
|
use log::error;
|
||||||
use lsp::{
|
use lsp::{
|
||||||
DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions,
|
CompletionContext, DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions,
|
||||||
DocumentHighlightKind, Edit, FileSystemWatcher, LanguageServer, LanguageServerBinary,
|
DocumentHighlightKind, Edit, FileSystemWatcher, LanguageServer, LanguageServerBinary,
|
||||||
LanguageServerId, LspRequestFuture, MessageActionItem, OneOf, ServerCapabilities,
|
LanguageServerId, LspRequestFuture, MessageActionItem, OneOf, ServerCapabilities,
|
||||||
ServerHealthStatus, ServerStatus, TextEdit, Uri,
|
ServerHealthStatus, ServerStatus, TextEdit, Uri,
|
||||||
|
@ -651,6 +651,12 @@ pub enum SearchResult {
|
||||||
LimitReached,
|
LimitReached,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
|
pub const DEFAULT_COMPLETION_CONTEXT: CompletionContext = CompletionContext {
|
||||||
|
trigger_kind: lsp::CompletionTriggerKind::INVOKED,
|
||||||
|
trigger_character: None,
|
||||||
|
};
|
||||||
|
|
||||||
impl Project {
|
impl Project {
|
||||||
pub fn init_settings(cx: &mut AppContext) {
|
pub fn init_settings(cx: &mut AppContext) {
|
||||||
WorktreeSettings::register(cx);
|
WorktreeSettings::register(cx);
|
||||||
|
@ -5875,6 +5881,7 @@ impl Project {
|
||||||
&self,
|
&self,
|
||||||
buffer: &Model<Buffer>,
|
buffer: &Model<Buffer>,
|
||||||
position: PointUtf16,
|
position: PointUtf16,
|
||||||
|
context: CompletionContext,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Task<Result<Vec<Completion>>> {
|
) -> Task<Result<Vec<Completion>>> {
|
||||||
let language_registry = self.languages.clone();
|
let language_registry = self.languages.clone();
|
||||||
|
@ -5908,7 +5915,10 @@ impl Project {
|
||||||
this.request_lsp(
|
this.request_lsp(
|
||||||
buffer.clone(),
|
buffer.clone(),
|
||||||
LanguageServerToQuery::Other(server_id),
|
LanguageServerToQuery::Other(server_id),
|
||||||
GetCompletions { position },
|
GetCompletions {
|
||||||
|
position,
|
||||||
|
context: context.clone(),
|
||||||
|
},
|
||||||
cx,
|
cx,
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
@ -5935,7 +5945,7 @@ impl Project {
|
||||||
let task = self.send_lsp_proto_request(
|
let task = self.send_lsp_proto_request(
|
||||||
buffer.clone(),
|
buffer.clone(),
|
||||||
project_id,
|
project_id,
|
||||||
GetCompletions { position },
|
GetCompletions { position, context },
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
let language = buffer.read(cx).language().cloned();
|
let language = buffer.read(cx).language().cloned();
|
||||||
|
@ -5969,10 +5979,11 @@ impl Project {
|
||||||
&self,
|
&self,
|
||||||
buffer: &Model<Buffer>,
|
buffer: &Model<Buffer>,
|
||||||
position: T,
|
position: T,
|
||||||
|
context: CompletionContext,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Task<Result<Vec<Completion>>> {
|
) -> Task<Result<Vec<Completion>>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(buffer.read(cx));
|
||||||
self.completions_impl(buffer, position, cx)
|
self.completions_impl(buffer, position, context, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_completions(
|
pub fn resolve_completions(
|
||||||
|
|
|
@ -2499,7 +2499,7 @@ async fn test_completions_without_edit_ranges(cx: &mut gpui::TestAppContext) {
|
||||||
let text = "let a = b.fqn";
|
let text = "let a = b.fqn";
|
||||||
buffer.update(cx, |buffer, cx| buffer.set_text(text, cx));
|
buffer.update(cx, |buffer, cx| buffer.set_text(text, cx));
|
||||||
let completions = project.update(cx, |project, cx| {
|
let completions = project.update(cx, |project, cx| {
|
||||||
project.completions(&buffer, text.len(), cx)
|
project.completions(&buffer, text.len(), DEFAULT_COMPLETION_CONTEXT, cx)
|
||||||
});
|
});
|
||||||
|
|
||||||
fake_server
|
fake_server
|
||||||
|
@ -2526,7 +2526,7 @@ async fn test_completions_without_edit_ranges(cx: &mut gpui::TestAppContext) {
|
||||||
let text = "let a = \"atoms/cmp\"";
|
let text = "let a = \"atoms/cmp\"";
|
||||||
buffer.update(cx, |buffer, cx| buffer.set_text(text, cx));
|
buffer.update(cx, |buffer, cx| buffer.set_text(text, cx));
|
||||||
let completions = project.update(cx, |project, cx| {
|
let completions = project.update(cx, |project, cx| {
|
||||||
project.completions(&buffer, text.len() - 1, cx)
|
project.completions(&buffer, text.len() - 1, DEFAULT_COMPLETION_CONTEXT, cx)
|
||||||
});
|
});
|
||||||
|
|
||||||
fake_server
|
fake_server
|
||||||
|
@ -2591,7 +2591,7 @@ async fn test_completions_with_carriage_returns(cx: &mut gpui::TestAppContext) {
|
||||||
let text = "let a = b.fqn";
|
let text = "let a = b.fqn";
|
||||||
buffer.update(cx, |buffer, cx| buffer.set_text(text, cx));
|
buffer.update(cx, |buffer, cx| buffer.set_text(text, cx));
|
||||||
let completions = project.update(cx, |project, cx| {
|
let completions = project.update(cx, |project, cx| {
|
||||||
project.completions(&buffer, text.len(), cx)
|
project.completions(&buffer, text.len(), DEFAULT_COMPLETION_CONTEXT, cx)
|
||||||
});
|
});
|
||||||
|
|
||||||
fake_server
|
fake_server
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue