mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-23 18:32:17 +00:00
add show_completions_on_input setting to disable popping the completions menu automatically
This commit is contained in:
parent
958fd9ad55
commit
7f3018c3f6
6 changed files with 278 additions and 236 deletions
|
@ -1937,6 +1937,10 @@ impl Editor {
|
|||
}
|
||||
|
||||
fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
|
||||
if !cx.global::<Settings>().show_completions_on_input {
|
||||
return;
|
||||
}
|
||||
|
||||
let selection = self.selections.newest_anchor();
|
||||
if self
|
||||
.buffer
|
||||
|
@ -6225,7 +6229,8 @@ pub fn styled_runs_for_code_label<'a>(
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::test::{
|
||||
assert_text_with_selections, build_editor, select_ranges, EditorTestContext,
|
||||
assert_text_with_selections, build_editor, select_ranges, EditorLspTestContext,
|
||||
EditorTestContext,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
@ -6236,7 +6241,6 @@ mod tests {
|
|||
};
|
||||
use indoc::indoc;
|
||||
use language::{FakeLspAdapter, LanguageConfig};
|
||||
use lsp::FakeLanguageServer;
|
||||
use project::FakeFs;
|
||||
use settings::EditorSettings;
|
||||
use std::{cell::RefCell, rc::Rc, time::Instant};
|
||||
|
@ -6244,7 +6248,9 @@ mod tests {
|
|||
use unindent::Unindent;
|
||||
use util::{
|
||||
assert_set_eq,
|
||||
test::{marked_text_by, marked_text_ranges, marked_text_ranges_by, sample_text},
|
||||
test::{
|
||||
marked_text_by, marked_text_ranges, marked_text_ranges_by, sample_text, TextRangeMarker,
|
||||
},
|
||||
};
|
||||
use workspace::{FollowableItem, ItemHandle, NavigationEntry, Pane};
|
||||
|
||||
|
@ -9524,199 +9530,182 @@ mod tests {
|
|||
|
||||
#[gpui::test]
|
||||
async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||
let mut language = Language::new(
|
||||
LanguageConfig {
|
||||
name: "Rust".into(),
|
||||
path_suffixes: vec!["rs".to_string()],
|
||||
let mut cx = EditorLspTestContext::new_rust(
|
||||
lsp::ServerCapabilities {
|
||||
completion_provider: Some(lsp::CompletionOptions {
|
||||
trigger_characters: Some(vec![".".to_string(), ":".to_string()]),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
Some(tree_sitter_rust::language()),
|
||||
);
|
||||
let mut fake_servers = language
|
||||
.set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
completion_provider: Some(lsp::CompletionOptions {
|
||||
trigger_characters: Some(vec![".".to_string(), ":".to_string()]),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
}))
|
||||
.await;
|
||||
|
||||
let text = "
|
||||
one
|
||||
two
|
||||
three
|
||||
"
|
||||
.unindent();
|
||||
|
||||
let fs = FakeFs::new(cx.background().clone());
|
||||
fs.insert_file("/file.rs", text).await;
|
||||
|
||||
let project = Project::test(fs, ["/file.rs".as_ref()], cx).await;
|
||||
project.update(cx, |project, _| project.languages().add(Arc::new(language)));
|
||||
let buffer = project
|
||||
.update(cx, |project, cx| project.open_local_buffer("/file.rs", cx))
|
||||
.await
|
||||
.unwrap();
|
||||
let mut fake_server = fake_servers.next().await.unwrap();
|
||||
|
||||
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
|
||||
let (_, editor) = cx.add_window(|cx| build_editor(buffer, cx));
|
||||
|
||||
editor.update(cx, |editor, cx| {
|
||||
editor.project = Some(project);
|
||||
editor.change_selections(None, cx, |s| {
|
||||
s.select_ranges([Point::new(0, 3)..Point::new(0, 3)])
|
||||
});
|
||||
editor.handle_input(&Input(".".to_string()), cx);
|
||||
});
|
||||
|
||||
handle_completion_request(
|
||||
&mut fake_server,
|
||||
"/file.rs",
|
||||
Point::new(0, 4),
|
||||
vec![
|
||||
(Point::new(0, 4)..Point::new(0, 4), "first_completion"),
|
||||
(Point::new(0, 4)..Point::new(0, 4), "second_completion"),
|
||||
],
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
editor
|
||||
.condition(&cx, |editor, _| editor.context_menu_visible())
|
||||
.await;
|
||||
|
||||
let apply_additional_edits = editor.update(cx, |editor, cx| {
|
||||
cx.set_state(indoc! {"
|
||||
one|
|
||||
two
|
||||
three"});
|
||||
cx.simulate_keystroke(".");
|
||||
handle_completion_request(
|
||||
&mut cx,
|
||||
indoc! {"
|
||||
one.|<>
|
||||
two
|
||||
three"},
|
||||
vec!["first_completion", "second_completion"],
|
||||
)
|
||||
.await;
|
||||
cx.condition(|editor, _| editor.context_menu_visible())
|
||||
.await;
|
||||
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
||||
editor.move_down(&MoveDown, cx);
|
||||
let apply_additional_edits = editor
|
||||
editor
|
||||
.confirm_completion(&ConfirmCompletion::default(), cx)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
editor.text(cx),
|
||||
"
|
||||
one.second_completion
|
||||
two
|
||||
three
|
||||
"
|
||||
.unindent()
|
||||
);
|
||||
apply_additional_edits
|
||||
.unwrap()
|
||||
});
|
||||
cx.assert_editor_state(indoc! {"
|
||||
one.second_completion|
|
||||
two
|
||||
three"});
|
||||
|
||||
handle_resolve_completion_request(
|
||||
&mut fake_server,
|
||||
Some((Point::new(2, 5)..Point::new(2, 5), "\nadditional edit")),
|
||||
)
|
||||
.await;
|
||||
apply_additional_edits.await.unwrap();
|
||||
assert_eq!(
|
||||
editor.read_with(cx, |editor, cx| editor.text(cx)),
|
||||
"
|
||||
one.second_completion
|
||||
two
|
||||
three
|
||||
additional edit
|
||||
"
|
||||
.unindent()
|
||||
);
|
||||
|
||||
editor.update(cx, |editor, cx| {
|
||||
editor.change_selections(None, cx, |s| {
|
||||
s.select_ranges([
|
||||
Point::new(1, 3)..Point::new(1, 3),
|
||||
Point::new(2, 5)..Point::new(2, 5),
|
||||
])
|
||||
});
|
||||
|
||||
editor.handle_input(&Input(" ".to_string()), cx);
|
||||
assert!(editor.context_menu.is_none());
|
||||
editor.handle_input(&Input("s".to_string()), cx);
|
||||
assert!(editor.context_menu.is_none());
|
||||
});
|
||||
|
||||
handle_completion_request(
|
||||
&mut fake_server,
|
||||
"/file.rs",
|
||||
Point::new(2, 7),
|
||||
vec![
|
||||
(Point::new(2, 6)..Point::new(2, 7), "fourth_completion"),
|
||||
(Point::new(2, 6)..Point::new(2, 7), "fifth_completion"),
|
||||
(Point::new(2, 6)..Point::new(2, 7), "sixth_completion"),
|
||||
],
|
||||
)
|
||||
.await;
|
||||
editor
|
||||
.condition(&cx, |editor, _| editor.context_menu_visible())
|
||||
.await;
|
||||
|
||||
editor.update(cx, |editor, cx| {
|
||||
editor.handle_input(&Input("i".to_string()), cx);
|
||||
});
|
||||
|
||||
handle_completion_request(
|
||||
&mut fake_server,
|
||||
"/file.rs",
|
||||
Point::new(2, 8),
|
||||
vec![
|
||||
(Point::new(2, 6)..Point::new(2, 8), "fourth_completion"),
|
||||
(Point::new(2, 6)..Point::new(2, 8), "fifth_completion"),
|
||||
(Point::new(2, 6)..Point::new(2, 8), "sixth_completion"),
|
||||
],
|
||||
)
|
||||
.await;
|
||||
editor
|
||||
.condition(&cx, |editor, _| editor.context_menu_visible())
|
||||
.await;
|
||||
|
||||
let apply_additional_edits = editor.update(cx, |editor, cx| {
|
||||
let apply_additional_edits = editor
|
||||
.confirm_completion(&ConfirmCompletion::default(), cx)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
editor.text(cx),
|
||||
"
|
||||
&mut cx,
|
||||
Some((
|
||||
indoc! {"
|
||||
one.second_completion
|
||||
two sixth_completion
|
||||
three sixth_completion
|
||||
additional edit
|
||||
"
|
||||
.unindent()
|
||||
);
|
||||
apply_additional_edits
|
||||
two
|
||||
three<>"},
|
||||
"\nadditional edit",
|
||||
)),
|
||||
)
|
||||
.await;
|
||||
apply_additional_edits.await.unwrap();
|
||||
cx.assert_editor_state(indoc! {"
|
||||
one.second_completion|
|
||||
two
|
||||
three
|
||||
additional edit"});
|
||||
|
||||
cx.set_state(indoc! {"
|
||||
one.second_completion
|
||||
two|
|
||||
three|
|
||||
additional edit"});
|
||||
cx.simulate_keystroke(" ");
|
||||
assert!(cx.editor(|e, _| e.context_menu.is_none()));
|
||||
cx.simulate_keystroke("s");
|
||||
assert!(cx.editor(|e, _| e.context_menu.is_none()));
|
||||
|
||||
cx.assert_editor_state(indoc! {"
|
||||
one.second_completion
|
||||
two s|
|
||||
three s|
|
||||
additional edit"});
|
||||
handle_completion_request(
|
||||
&mut cx,
|
||||
indoc! {"
|
||||
one.second_completion
|
||||
two s
|
||||
three <s|>
|
||||
additional edit"},
|
||||
vec!["fourth_completion", "fifth_completion", "sixth_completion"],
|
||||
)
|
||||
.await;
|
||||
cx.condition(|editor, _| editor.context_menu_visible())
|
||||
.await;
|
||||
|
||||
cx.simulate_keystroke("i");
|
||||
|
||||
handle_completion_request(
|
||||
&mut cx,
|
||||
indoc! {"
|
||||
one.second_completion
|
||||
two si
|
||||
three <si|>
|
||||
additional edit"},
|
||||
vec!["fourth_completion", "fifth_completion", "sixth_completion"],
|
||||
)
|
||||
.await;
|
||||
cx.condition(|editor, _| editor.context_menu_visible())
|
||||
.await;
|
||||
|
||||
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
||||
editor
|
||||
.confirm_completion(&ConfirmCompletion::default(), cx)
|
||||
.unwrap()
|
||||
});
|
||||
handle_resolve_completion_request(&mut fake_server, None).await;
|
||||
cx.assert_editor_state(indoc! {"
|
||||
one.second_completion
|
||||
two sixth_completion|
|
||||
three sixth_completion|
|
||||
additional edit"});
|
||||
|
||||
handle_resolve_completion_request(&mut cx, None).await;
|
||||
apply_additional_edits.await.unwrap();
|
||||
|
||||
async fn handle_completion_request(
|
||||
fake: &mut FakeLanguageServer,
|
||||
path: &'static str,
|
||||
position: Point,
|
||||
completions: Vec<(Range<Point>, &'static str)>,
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<Settings, _, _>(|settings, _| {
|
||||
settings.show_completions_on_input = false;
|
||||
})
|
||||
});
|
||||
cx.set_state("editor|");
|
||||
cx.simulate_keystroke(".");
|
||||
assert!(cx.editor(|e, _| e.context_menu.is_none()));
|
||||
cx.simulate_keystrokes(["c", "l", "o"]);
|
||||
cx.assert_editor_state("editor.clo|");
|
||||
assert!(cx.editor(|e, _| e.context_menu.is_none()));
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.show_completions(&ShowCompletions, cx);
|
||||
});
|
||||
handle_completion_request(&mut cx, "editor.<clo|>", vec!["close", "clobber"]).await;
|
||||
cx.condition(|editor, _| editor.context_menu_visible())
|
||||
.await;
|
||||
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
||||
editor
|
||||
.confirm_completion(&ConfirmCompletion::default(), cx)
|
||||
.unwrap()
|
||||
});
|
||||
cx.assert_editor_state("editor.close|");
|
||||
handle_resolve_completion_request(&mut cx, None).await;
|
||||
apply_additional_edits.await.unwrap();
|
||||
|
||||
// Handle completion request passing a marked string specifying where the completion
|
||||
// should be triggered from using '|' character, what range should be replaced, and what completions
|
||||
// should be returned using '<' and '>' to delimit the range
|
||||
async fn handle_completion_request<'a>(
|
||||
cx: &mut EditorLspTestContext<'a>,
|
||||
marked_string: &str,
|
||||
completions: Vec<&'static str>,
|
||||
) {
|
||||
fake.handle_request::<lsp::request::Completion, _, _>(move |params, _| {
|
||||
let complete_from_marker: TextRangeMarker = '|'.into();
|
||||
let replace_range_marker: TextRangeMarker = ('<', '>').into();
|
||||
let (_, mut marked_ranges) = marked_text_ranges_by(
|
||||
marked_string,
|
||||
vec![complete_from_marker.clone(), replace_range_marker.clone()],
|
||||
);
|
||||
|
||||
let complete_from_position =
|
||||
cx.to_lsp(marked_ranges.remove(&complete_from_marker).unwrap()[0].start);
|
||||
let replace_range =
|
||||
cx.to_lsp_range(marked_ranges.remove(&replace_range_marker).unwrap()[0].clone());
|
||||
|
||||
cx.handle_request::<lsp::request::Completion, _, _>(move |url, params, _| {
|
||||
let completions = completions.clone();
|
||||
async move {
|
||||
assert_eq!(
|
||||
params.text_document_position.text_document.uri,
|
||||
lsp::Url::from_file_path(path).unwrap()
|
||||
);
|
||||
assert_eq!(params.text_document_position.text_document.uri, url.clone());
|
||||
assert_eq!(
|
||||
params.text_document_position.position,
|
||||
lsp::Position::new(position.row, position.column)
|
||||
complete_from_position
|
||||
);
|
||||
Ok(Some(lsp::CompletionResponse::Array(
|
||||
completions
|
||||
.iter()
|
||||
.map(|(range, new_text)| lsp::CompletionItem {
|
||||
label: new_text.to_string(),
|
||||
.map(|completion_text| lsp::CompletionItem {
|
||||
label: completion_text.to_string(),
|
||||
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
|
||||
range: lsp::Range::new(
|
||||
lsp::Position::new(range.start.row, range.start.column),
|
||||
lsp::Position::new(range.start.row, range.start.column),
|
||||
),
|
||||
new_text: new_text.to_string(),
|
||||
range: replace_range.clone(),
|
||||
new_text: completion_text.to_string(),
|
||||
})),
|
||||
..Default::default()
|
||||
})
|
||||
|
@ -9728,23 +9717,26 @@ mod tests {
|
|||
.await;
|
||||
}
|
||||
|
||||
async fn handle_resolve_completion_request(
|
||||
fake: &mut FakeLanguageServer,
|
||||
edit: Option<(Range<Point>, &'static str)>,
|
||||
async fn handle_resolve_completion_request<'a>(
|
||||
cx: &mut EditorLspTestContext<'a>,
|
||||
edit: Option<(&'static str, &'static str)>,
|
||||
) {
|
||||
fake.handle_request::<lsp::request::ResolveCompletionItem, _, _>(move |_, _| {
|
||||
let edit = edit.map(|(marked_string, new_text)| {
|
||||
let replace_range_marker: TextRangeMarker = ('<', '>').into();
|
||||
let (_, mut marked_ranges) =
|
||||
marked_text_ranges_by(marked_string, vec![replace_range_marker.clone()]);
|
||||
|
||||
let replace_range = cx
|
||||
.to_lsp_range(marked_ranges.remove(&replace_range_marker).unwrap()[0].clone());
|
||||
|
||||
vec![lsp::TextEdit::new(replace_range, new_text.to_string())]
|
||||
});
|
||||
|
||||
cx.handle_request::<lsp::request::ResolveCompletionItem, _, _>(move |_, _, _| {
|
||||
let edit = edit.clone();
|
||||
async move {
|
||||
Ok(lsp::CompletionItem {
|
||||
additional_text_edits: edit.map(|(range, new_text)| {
|
||||
vec![lsp::TextEdit::new(
|
||||
lsp::Range::new(
|
||||
lsp::Position::new(range.start.row, range.start.column),
|
||||
lsp::Position::new(range.end.row, range.end.column),
|
||||
),
|
||||
new_text.to_string(),
|
||||
)]
|
||||
}),
|
||||
additional_text_edits: edit,
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
|
|
@ -342,17 +342,16 @@ mod tests {
|
|||
test();"});
|
||||
|
||||
let mut requests =
|
||||
cx.lsp
|
||||
.handle_request::<lsp::request::GotoDefinition, _, _>(move |_, _| async move {
|
||||
Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
|
||||
lsp::LocationLink {
|
||||
origin_selection_range: Some(symbol_range),
|
||||
target_uri: lsp::Url::from_file_path("/root/dir/file.rs").unwrap(),
|
||||
target_range,
|
||||
target_selection_range: target_range,
|
||||
},
|
||||
])))
|
||||
});
|
||||
cx.handle_request::<lsp::request::GotoDefinition, _, _>(move |url, _, _| async move {
|
||||
Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
|
||||
lsp::LocationLink {
|
||||
origin_selection_range: Some(symbol_range),
|
||||
target_uri: url.clone(),
|
||||
target_range,
|
||||
target_selection_range: target_range,
|
||||
},
|
||||
])))
|
||||
});
|
||||
cx.update_editor(|editor, cx| {
|
||||
update_go_to_definition_link(
|
||||
editor,
|
||||
|
@ -387,18 +386,17 @@ mod tests {
|
|||
// Response without source range still highlights word
|
||||
cx.update_editor(|editor, _| editor.link_go_to_definition_state.last_mouse_location = None);
|
||||
let mut requests =
|
||||
cx.lsp
|
||||
.handle_request::<lsp::request::GotoDefinition, _, _>(move |_, _| async move {
|
||||
Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
|
||||
lsp::LocationLink {
|
||||
// No origin range
|
||||
origin_selection_range: None,
|
||||
target_uri: lsp::Url::from_file_path("/root/dir/file.rs").unwrap(),
|
||||
target_range,
|
||||
target_selection_range: target_range,
|
||||
},
|
||||
])))
|
||||
});
|
||||
cx.handle_request::<lsp::request::GotoDefinition, _, _>(move |url, _, _| async move {
|
||||
Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
|
||||
lsp::LocationLink {
|
||||
// No origin range
|
||||
origin_selection_range: None,
|
||||
target_uri: url.clone(),
|
||||
target_range,
|
||||
target_selection_range: target_range,
|
||||
},
|
||||
])))
|
||||
});
|
||||
cx.update_editor(|editor, cx| {
|
||||
update_go_to_definition_link(
|
||||
editor,
|
||||
|
@ -495,17 +493,16 @@ mod tests {
|
|||
test();"});
|
||||
|
||||
let mut requests =
|
||||
cx.lsp
|
||||
.handle_request::<lsp::request::GotoDefinition, _, _>(move |_, _| async move {
|
||||
Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
|
||||
lsp::LocationLink {
|
||||
origin_selection_range: Some(symbol_range),
|
||||
target_uri: lsp::Url::from_file_path("/root/dir/file.rs").unwrap(),
|
||||
target_range,
|
||||
target_selection_range: target_range,
|
||||
},
|
||||
])))
|
||||
});
|
||||
cx.handle_request::<lsp::request::GotoDefinition, _, _>(move |url, _, _| async move {
|
||||
Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
|
||||
lsp::LocationLink {
|
||||
origin_selection_range: Some(symbol_range),
|
||||
target_uri: url,
|
||||
target_range,
|
||||
target_selection_range: target_range,
|
||||
},
|
||||
])))
|
||||
});
|
||||
cx.update_editor(|editor, cx| {
|
||||
cmd_changed(editor, &CmdChanged { cmd_down: true }, cx);
|
||||
});
|
||||
|
@ -584,17 +581,16 @@ mod tests {
|
|||
test();"});
|
||||
|
||||
let mut requests =
|
||||
cx.lsp
|
||||
.handle_request::<lsp::request::GotoDefinition, _, _>(move |_, _| async move {
|
||||
Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
|
||||
lsp::LocationLink {
|
||||
origin_selection_range: None,
|
||||
target_uri: lsp::Url::from_file_path("/root/dir/file.rs").unwrap(),
|
||||
target_range,
|
||||
target_selection_range: target_range,
|
||||
},
|
||||
])))
|
||||
});
|
||||
cx.handle_request::<lsp::request::GotoDefinition, _, _>(move |url, _, _| async move {
|
||||
Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
|
||||
lsp::LocationLink {
|
||||
origin_selection_range: None,
|
||||
target_uri: url,
|
||||
target_range,
|
||||
target_selection_range: target_range,
|
||||
},
|
||||
])))
|
||||
});
|
||||
cx.update_workspace(|workspace, cx| {
|
||||
go_to_fetched_definition(workspace, &GoToFetchedDefinition { point: hover_point }, cx);
|
||||
});
|
||||
|
|
|
@ -4,12 +4,14 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
|
||||
use futures::StreamExt;
|
||||
use anyhow::Result;
|
||||
use futures::{Future, StreamExt};
|
||||
use indoc::indoc;
|
||||
|
||||
use collections::BTreeMap;
|
||||
use gpui::{json, keymap::Keystroke, AppContext, ModelHandle, ViewContext, ViewHandle};
|
||||
use language::{point_to_lsp, FakeLspAdapter, Language, LanguageConfig, Selection};
|
||||
use lsp::request;
|
||||
use project::Project;
|
||||
use settings::Settings;
|
||||
use util::{
|
||||
|
@ -110,6 +112,13 @@ impl<'a> EditorTestContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn condition(
|
||||
&self,
|
||||
predicate: impl FnMut(&Editor, &AppContext) -> bool,
|
||||
) -> impl Future<Output = ()> {
|
||||
self.editor.condition(self.cx, predicate)
|
||||
}
|
||||
|
||||
pub fn editor<F, T>(&mut self, read: F) -> T
|
||||
where
|
||||
F: FnOnce(&Editor, &AppContext) -> T,
|
||||
|
@ -424,6 +433,7 @@ pub struct EditorLspTestContext<'a> {
|
|||
pub cx: EditorTestContext<'a>,
|
||||
pub lsp: lsp::FakeLanguageServer,
|
||||
pub workspace: ViewHandle<Workspace>,
|
||||
pub editor_lsp_url: lsp::Url,
|
||||
}
|
||||
|
||||
impl<'a> EditorLspTestContext<'a> {
|
||||
|
@ -497,6 +507,7 @@ impl<'a> EditorLspTestContext<'a> {
|
|||
},
|
||||
lsp,
|
||||
workspace,
|
||||
editor_lsp_url: lsp::Url::from_file_path("/root/dir/file.rs").unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -520,11 +531,15 @@ impl<'a> EditorLspTestContext<'a> {
|
|||
pub fn lsp_range(&mut self, marked_text: &str) -> lsp::Range {
|
||||
let (unmarked, mut ranges) = marked_text_ranges_by(marked_text, vec![('[', ']').into()]);
|
||||
assert_eq!(unmarked, self.cx.buffer_text());
|
||||
let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx));
|
||||
|
||||
let offset_range = ranges.remove(&('[', ']').into()).unwrap()[0].clone();
|
||||
let start_point = offset_range.start.to_point(&snapshot.buffer_snapshot);
|
||||
let end_point = offset_range.end.to_point(&snapshot.buffer_snapshot);
|
||||
self.to_lsp_range(offset_range)
|
||||
}
|
||||
|
||||
pub fn to_lsp_range(&mut self, range: Range<usize>) -> lsp::Range {
|
||||
let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx));
|
||||
let start_point = range.start.to_point(&snapshot.buffer_snapshot);
|
||||
let end_point = range.end.to_point(&snapshot.buffer_snapshot);
|
||||
|
||||
self.editor(|editor, cx| {
|
||||
let buffer = editor.buffer().read(cx);
|
||||
let start = point_to_lsp(
|
||||
|
@ -546,12 +561,45 @@ impl<'a> EditorLspTestContext<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn to_lsp(&mut self, offset: usize) -> lsp::Position {
|
||||
let snapshot = self.update_editor(|editor, cx| editor.snapshot(cx));
|
||||
let point = offset.to_point(&snapshot.buffer_snapshot);
|
||||
|
||||
self.editor(|editor, cx| {
|
||||
let buffer = editor.buffer().read(cx);
|
||||
point_to_lsp(
|
||||
buffer
|
||||
.point_to_buffer_offset(point, cx)
|
||||
.unwrap()
|
||||
.1
|
||||
.to_point_utf16(&buffer.read(cx)),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn update_workspace<F, T>(&mut self, update: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Workspace, &mut ViewContext<Workspace>) -> T,
|
||||
{
|
||||
self.workspace.update(self.cx.cx, update)
|
||||
}
|
||||
|
||||
pub fn handle_request<T, F, Fut>(
|
||||
&self,
|
||||
mut handler: F,
|
||||
) -> futures::channel::mpsc::UnboundedReceiver<()>
|
||||
where
|
||||
T: 'static + request::Request,
|
||||
T::Params: 'static + Send,
|
||||
F: 'static + Send + FnMut(lsp::Url, T::Params, gpui::AsyncAppContext) -> Fut,
|
||||
Fut: 'static + Send + Future<Output = Result<T::Result>>,
|
||||
{
|
||||
let url = self.editor_lsp_url.clone();
|
||||
self.lsp.handle_request::<T, _, _>(move |params, cx| {
|
||||
let url = url.clone();
|
||||
handler(url, params, cx)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for EditorLspTestContext<'a> {
|
||||
|
|
|
@ -25,6 +25,7 @@ pub struct Settings {
|
|||
pub buffer_font_size: f32,
|
||||
pub default_buffer_font_size: f32,
|
||||
pub hover_popover_enabled: bool,
|
||||
pub show_completions_on_input: bool,
|
||||
pub vim_mode: bool,
|
||||
pub autosave: Autosave,
|
||||
pub editor_defaults: EditorSettings,
|
||||
|
@ -83,6 +84,8 @@ pub struct SettingsFileContent {
|
|||
#[serde(default)]
|
||||
pub hover_popover_enabled: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub show_completions_on_input: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub vim_mode: Option<bool>,
|
||||
#[serde(default)]
|
||||
pub autosave: Option<Autosave>,
|
||||
|
@ -118,6 +121,7 @@ impl Settings {
|
|||
buffer_font_size: defaults.buffer_font_size.unwrap(),
|
||||
default_buffer_font_size: defaults.buffer_font_size.unwrap(),
|
||||
hover_popover_enabled: defaults.hover_popover_enabled.unwrap(),
|
||||
show_completions_on_input: defaults.show_completions_on_input.unwrap(),
|
||||
projects_online_by_default: defaults.projects_online_by_default.unwrap(),
|
||||
vim_mode: defaults.vim_mode.unwrap(),
|
||||
autosave: defaults.autosave.unwrap(),
|
||||
|
@ -219,6 +223,7 @@ impl Settings {
|
|||
buffer_font_size: 14.,
|
||||
default_buffer_font_size: 14.,
|
||||
hover_popover_enabled: true,
|
||||
show_completions_on_input: true,
|
||||
vim_mode: false,
|
||||
autosave: Autosave::Off,
|
||||
editor_defaults: EditorSettings {
|
||||
|
|
|
@ -24,7 +24,7 @@ pub fn marked_text(marked_text: &str) -> (String, Vec<usize>) {
|
|||
(unmarked_text, markers.remove(&'|').unwrap_or_default())
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash)]
|
||||
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||
pub enum TextRangeMarker {
|
||||
Empty(char),
|
||||
Range(char, char),
|
||||
|
|
1
styles/package-lock.json
generated
1
styles/package-lock.json
generated
|
@ -5,6 +5,7 @@
|
|||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "styles",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
|
|
Loading…
Reference in a new issue