Address some TODOs in editor2 crate (#3445)
* Fix crash when jumping to definition * Enabling resolution of completions * Make links in interactive text clickable * Enable code paths that use `select_anchors`
This commit is contained in:
commit
c95a7c7387
6 changed files with 574 additions and 555 deletions
|
@ -73,7 +73,7 @@ use ordered_float::OrderedFloat;
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use project::{FormatTrigger, Location, Project, ProjectPath, ProjectTransaction};
|
use project::{FormatTrigger, Location, Project, ProjectPath, ProjectTransaction};
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use rpc::proto::*;
|
use rpc::proto::{self, *};
|
||||||
use scroll::{
|
use scroll::{
|
||||||
autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide,
|
autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide,
|
||||||
};
|
};
|
||||||
|
@ -155,7 +155,6 @@ pub fn render_parsed_markdown(
|
||||||
);
|
);
|
||||||
let runs = text_runs_for_highlights(&parsed.text, &editor_style.text, highlights);
|
let runs = text_runs_for_highlights(&parsed.text, &editor_style.text, highlights);
|
||||||
|
|
||||||
// todo!("add the ability to change cursor style for link ranges")
|
|
||||||
let mut links = Vec::new();
|
let mut links = Vec::new();
|
||||||
let mut link_ranges = Vec::new();
|
let mut link_ranges = Vec::new();
|
||||||
for (range, region) in parsed.region_ranges.iter().zip(&parsed.regions) {
|
for (range, region) in parsed.region_ranges.iter().zip(&parsed.regions) {
|
||||||
|
@ -972,95 +971,94 @@ impl CompletionsMenu {
|
||||||
|
|
||||||
fn pre_resolve_completion_documentation(
|
fn pre_resolve_completion_documentation(
|
||||||
&self,
|
&self,
|
||||||
_editor: &Editor,
|
editor: &Editor,
|
||||||
_cx: &mut ViewContext<Editor>,
|
cx: &mut ViewContext<Editor>,
|
||||||
) -> Option<Task<()>> {
|
) -> Option<Task<()>> {
|
||||||
// todo!("implementation below ");
|
let settings = EditorSettings::get_global(cx);
|
||||||
None
|
if !settings.show_completion_documentation {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(project) = editor.project.clone() else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let client = project.read(cx).client();
|
||||||
|
let language_registry = project.read(cx).languages().clone();
|
||||||
|
|
||||||
|
let is_remote = project.read(cx).is_remote();
|
||||||
|
let project_id = project.read(cx).remote_id();
|
||||||
|
|
||||||
|
let completions = self.completions.clone();
|
||||||
|
let completion_indices: Vec<_> = self.matches.iter().map(|m| m.candidate_id).collect();
|
||||||
|
|
||||||
|
Some(cx.spawn(move |this, mut cx| async move {
|
||||||
|
if is_remote {
|
||||||
|
let Some(project_id) = project_id else {
|
||||||
|
log::error!("Remote project without remote_id");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
for completion_index in completion_indices {
|
||||||
|
let completions_guard = completions.read();
|
||||||
|
let completion = &completions_guard[completion_index];
|
||||||
|
if completion.documentation.is_some() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let server_id = completion.server_id;
|
||||||
|
let completion = completion.lsp_completion.clone();
|
||||||
|
drop(completions_guard);
|
||||||
|
|
||||||
|
Self::resolve_completion_documentation_remote(
|
||||||
|
project_id,
|
||||||
|
server_id,
|
||||||
|
completions.clone(),
|
||||||
|
completion_index,
|
||||||
|
completion,
|
||||||
|
client.clone(),
|
||||||
|
language_registry.clone(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
_ = this.update(&mut cx, |_, cx| cx.notify());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for completion_index in completion_indices {
|
||||||
|
let completions_guard = completions.read();
|
||||||
|
let completion = &completions_guard[completion_index];
|
||||||
|
if completion.documentation.is_some() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let server_id = completion.server_id;
|
||||||
|
let completion = completion.lsp_completion.clone();
|
||||||
|
drop(completions_guard);
|
||||||
|
|
||||||
|
let server = project
|
||||||
|
.read_with(&mut cx, |project, _| {
|
||||||
|
project.language_server_for_id(server_id)
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
.flatten();
|
||||||
|
let Some(server) = server else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::resolve_completion_documentation_local(
|
||||||
|
server,
|
||||||
|
completions.clone(),
|
||||||
|
completion_index,
|
||||||
|
completion,
|
||||||
|
language_registry.clone(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
_ = this.update(&mut cx, |_, cx| cx.notify());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
// {
|
|
||||||
// let settings = EditorSettings::get_global(cx);
|
|
||||||
// if !settings.show_completion_documentation {
|
|
||||||
// return None;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let Some(project) = editor.project.clone() else {
|
|
||||||
// return None;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let client = project.read(cx).client();
|
|
||||||
// let language_registry = project.read(cx).languages().clone();
|
|
||||||
|
|
||||||
// let is_remote = project.read(cx).is_remote();
|
|
||||||
// let project_id = project.read(cx).remote_id();
|
|
||||||
|
|
||||||
// let completions = self.completions.clone();
|
|
||||||
// let completion_indices: Vec<_> = self.matches.iter().map(|m| m.candidate_id).collect();
|
|
||||||
|
|
||||||
// Some(cx.spawn(move |this, mut cx| async move {
|
|
||||||
// if is_remote {
|
|
||||||
// let Some(project_id) = project_id else {
|
|
||||||
// log::error!("Remote project without remote_id");
|
|
||||||
// return;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// for completion_index in completion_indices {
|
|
||||||
// let completions_guard = completions.read();
|
|
||||||
// let completion = &completions_guard[completion_index];
|
|
||||||
// if completion.documentation.is_some() {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let server_id = completion.server_id;
|
|
||||||
// let completion = completion.lsp_completion.clone();
|
|
||||||
// drop(completions_guard);
|
|
||||||
|
|
||||||
// Self::resolve_completion_documentation_remote(
|
|
||||||
// project_id,
|
|
||||||
// server_id,
|
|
||||||
// completions.clone(),
|
|
||||||
// completion_index,
|
|
||||||
// completion,
|
|
||||||
// client.clone(),
|
|
||||||
// language_registry.clone(),
|
|
||||||
// )
|
|
||||||
// .await;
|
|
||||||
|
|
||||||
// _ = this.update(&mut cx, |_, cx| cx.notify());
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// for completion_index in completion_indices {
|
|
||||||
// let completions_guard = completions.read();
|
|
||||||
// let completion = &completions_guard[completion_index];
|
|
||||||
// if completion.documentation.is_some() {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let server_id = completion.server_id;
|
|
||||||
// let completion = completion.lsp_completion.clone();
|
|
||||||
// drop(completions_guard);
|
|
||||||
|
|
||||||
// let server = project.read_with(&mut cx, |project, _| {
|
|
||||||
// project.language_server_for_id(server_id)
|
|
||||||
// });
|
|
||||||
// let Some(server) = server else {
|
|
||||||
// return;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// Self::resolve_completion_documentation_local(
|
|
||||||
// server,
|
|
||||||
// completions.clone(),
|
|
||||||
// completion_index,
|
|
||||||
// completion,
|
|
||||||
// language_registry.clone(),
|
|
||||||
// )
|
|
||||||
// .await;
|
|
||||||
|
|
||||||
// _ = this.update(&mut cx, |_, cx| cx.notify());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }))
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn attempt_resolve_selected_completion_documentation(
|
fn attempt_resolve_selected_completion_documentation(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -1081,10 +1079,9 @@ impl CompletionsMenu {
|
||||||
let completions = self.completions.clone();
|
let completions = self.completions.clone();
|
||||||
let completions_guard = completions.read();
|
let completions_guard = completions.read();
|
||||||
let completion = &completions_guard[completion_index];
|
let completion = &completions_guard[completion_index];
|
||||||
// todo!()
|
if completion.documentation.is_some() {
|
||||||
// if completion.documentation.is_some() {
|
return;
|
||||||
// return;
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
let server_id = completion.server_id;
|
let server_id = completion.server_id;
|
||||||
let completion = completion.lsp_completion.clone();
|
let completion = completion.lsp_completion.clone();
|
||||||
|
@ -1143,41 +1140,40 @@ impl CompletionsMenu {
|
||||||
client: Arc<Client>,
|
client: Arc<Client>,
|
||||||
language_registry: Arc<LanguageRegistry>,
|
language_registry: Arc<LanguageRegistry>,
|
||||||
) {
|
) {
|
||||||
// todo!()
|
let request = proto::ResolveCompletionDocumentation {
|
||||||
// let request = proto::ResolveCompletionDocumentation {
|
project_id,
|
||||||
// project_id,
|
language_server_id: server_id.0 as u64,
|
||||||
// language_server_id: server_id.0 as u64,
|
lsp_completion: serde_json::to_string(&completion).unwrap().into_bytes(),
|
||||||
// lsp_completion: serde_json::to_string(&completion).unwrap().into_bytes(),
|
};
|
||||||
// };
|
|
||||||
|
|
||||||
// let Some(response) = client
|
let Some(response) = client
|
||||||
// .request(request)
|
.request(request)
|
||||||
// .await
|
.await
|
||||||
// .context("completion documentation resolve proto request")
|
.context("completion documentation resolve proto request")
|
||||||
// .log_err()
|
.log_err()
|
||||||
// else {
|
else {
|
||||||
// return;
|
return;
|
||||||
// };
|
};
|
||||||
|
|
||||||
// if response.text.is_empty() {
|
if response.text.is_empty() {
|
||||||
// let mut completions = completions.write();
|
let mut completions = completions.write();
|
||||||
// let completion = &mut completions[completion_index];
|
let completion = &mut completions[completion_index];
|
||||||
// completion.documentation = Some(Documentation::Undocumented);
|
completion.documentation = Some(Documentation::Undocumented);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// let documentation = if response.is_markdown {
|
let documentation = if response.is_markdown {
|
||||||
// Documentation::MultiLineMarkdown(
|
Documentation::MultiLineMarkdown(
|
||||||
// markdown::parse_markdown(&response.text, &language_registry, None).await,
|
markdown::parse_markdown(&response.text, &language_registry, None).await,
|
||||||
// )
|
)
|
||||||
// } else if response.text.lines().count() <= 1 {
|
} else if response.text.lines().count() <= 1 {
|
||||||
// Documentation::SingleLine(response.text)
|
Documentation::SingleLine(response.text)
|
||||||
// } else {
|
} else {
|
||||||
// Documentation::MultiLinePlainText(response.text)
|
Documentation::MultiLinePlainText(response.text)
|
||||||
// };
|
};
|
||||||
|
|
||||||
// let mut completions = completions.write();
|
let mut completions = completions.write();
|
||||||
// let completion = &mut completions[completion_index];
|
let completion = &mut completions[completion_index];
|
||||||
// completion.documentation = Some(documentation);
|
completion.documentation = Some(documentation);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn resolve_completion_documentation_local(
|
async fn resolve_completion_documentation_local(
|
||||||
|
@ -1187,38 +1183,37 @@ impl CompletionsMenu {
|
||||||
completion: lsp::CompletionItem,
|
completion: lsp::CompletionItem,
|
||||||
language_registry: Arc<LanguageRegistry>,
|
language_registry: Arc<LanguageRegistry>,
|
||||||
) {
|
) {
|
||||||
// todo!()
|
let can_resolve = server
|
||||||
// let can_resolve = server
|
.capabilities()
|
||||||
// .capabilities()
|
.completion_provider
|
||||||
// .completion_provider
|
.as_ref()
|
||||||
// .as_ref()
|
.and_then(|options| options.resolve_provider)
|
||||||
// .and_then(|options| options.resolve_provider)
|
.unwrap_or(false);
|
||||||
// .unwrap_or(false);
|
if !can_resolve {
|
||||||
// if !can_resolve {
|
return;
|
||||||
// return;
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// let request = server.request::<lsp::request::ResolveCompletionItem>(completion);
|
let request = server.request::<lsp::request::ResolveCompletionItem>(completion);
|
||||||
// let Some(completion_item) = request.await.log_err() else {
|
let Some(completion_item) = request.await.log_err() else {
|
||||||
// return;
|
return;
|
||||||
// };
|
};
|
||||||
|
|
||||||
// if let Some(lsp_documentation) = completion_item.documentation {
|
if let Some(lsp_documentation) = completion_item.documentation {
|
||||||
// let documentation = language::prepare_completion_documentation(
|
let documentation = language::prepare_completion_documentation(
|
||||||
// &lsp_documentation,
|
&lsp_documentation,
|
||||||
// &language_registry,
|
&language_registry,
|
||||||
// None, // TODO: Try to reasonably work out which language the completion is for
|
None, // TODO: Try to reasonably work out which language the completion is for
|
||||||
// )
|
)
|
||||||
// .await;
|
.await;
|
||||||
|
|
||||||
// let mut completions = completions.write();
|
let mut completions = completions.write();
|
||||||
// let completion = &mut completions[completion_index];
|
let completion = &mut completions[completion_index];
|
||||||
// completion.documentation = Some(documentation);
|
completion.documentation = Some(documentation);
|
||||||
// } else {
|
} else {
|
||||||
// let mut completions = completions.write();
|
let mut completions = completions.write();
|
||||||
// let completion = &mut completions[completion_index];
|
let completion = &mut completions[completion_index];
|
||||||
// completion.documentation = Some(Documentation::Undocumented);
|
completion.documentation = Some(Documentation::Undocumented);
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visible(&self) -> bool {
|
fn visible(&self) -> bool {
|
||||||
|
|
|
@ -5427,178 +5427,177 @@ async fn test_strip_whitespace_and_format_via_lsp(cx: &mut gpui::TestAppContext)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo!(completion)
|
#[gpui::test]
|
||||||
// #[gpui::test]
|
async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||||
// async fn test_completion(cx: &mut gpui::TestAppContext) {
|
init_test(cx, |_| {});
|
||||||
// init_test(cx, |_| {});
|
|
||||||
|
|
||||||
// let mut cx = EditorLspTestContext::new_rust(
|
let mut cx = EditorLspTestContext::new_rust(
|
||||||
// lsp::ServerCapabilities {
|
lsp::ServerCapabilities {
|
||||||
// completion_provider: Some(lsp::CompletionOptions {
|
completion_provider: Some(lsp::CompletionOptions {
|
||||||
// trigger_characters: Some(vec![".".to_string(), ":".to_string()]),
|
trigger_characters: Some(vec![".".to_string(), ":".to_string()]),
|
||||||
// resolve_provider: Some(true),
|
resolve_provider: Some(true),
|
||||||
// ..Default::default()
|
..Default::default()
|
||||||
// }),
|
}),
|
||||||
// ..Default::default()
|
..Default::default()
|
||||||
// },
|
},
|
||||||
// cx,
|
cx,
|
||||||
// )
|
)
|
||||||
// .await;
|
.await;
|
||||||
|
|
||||||
// cx.set_state(indoc! {"
|
cx.set_state(indoc! {"
|
||||||
// oneˇ
|
oneˇ
|
||||||
// two
|
two
|
||||||
// three
|
three
|
||||||
// "});
|
"});
|
||||||
// cx.simulate_keystroke(".");
|
cx.simulate_keystroke(".");
|
||||||
// handle_completion_request(
|
handle_completion_request(
|
||||||
// &mut cx,
|
&mut cx,
|
||||||
// indoc! {"
|
indoc! {"
|
||||||
// one.|<>
|
one.|<>
|
||||||
// two
|
two
|
||||||
// three
|
three
|
||||||
// "},
|
"},
|
||||||
// vec!["first_completion", "second_completion"],
|
vec!["first_completion", "second_completion"],
|
||||||
// )
|
)
|
||||||
// .await;
|
.await;
|
||||||
// cx.condition(|editor, _| editor.context_menu_visible())
|
cx.condition(|editor, _| editor.context_menu_visible())
|
||||||
// .await;
|
.await;
|
||||||
// let apply_additional_edits = cx.update_editor(|editor, cx| {
|
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
||||||
// editor.context_menu_next(&Default::default(), cx);
|
editor.context_menu_next(&Default::default(), cx);
|
||||||
// editor
|
editor
|
||||||
// .confirm_completion(&ConfirmCompletion::default(), cx)
|
.confirm_completion(&ConfirmCompletion::default(), cx)
|
||||||
// .unwrap()
|
.unwrap()
|
||||||
// });
|
});
|
||||||
// cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
// one.second_completionˇ
|
one.second_completionˇ
|
||||||
// two
|
two
|
||||||
// three
|
three
|
||||||
// "});
|
"});
|
||||||
|
|
||||||
// handle_resolve_completion_request(
|
handle_resolve_completion_request(
|
||||||
// &mut cx,
|
&mut cx,
|
||||||
// Some(vec![
|
Some(vec![
|
||||||
// (
|
(
|
||||||
// //This overlaps with the primary completion edit which is
|
//This overlaps with the primary completion edit which is
|
||||||
// //misbehavior from the LSP spec, test that we filter it out
|
//misbehavior from the LSP spec, test that we filter it out
|
||||||
// indoc! {"
|
indoc! {"
|
||||||
// one.second_ˇcompletion
|
one.second_ˇcompletion
|
||||||
// two
|
two
|
||||||
// threeˇ
|
threeˇ
|
||||||
// "},
|
"},
|
||||||
// "overlapping additional edit",
|
"overlapping additional edit",
|
||||||
// ),
|
),
|
||||||
// (
|
(
|
||||||
// indoc! {"
|
indoc! {"
|
||||||
// one.second_completion
|
one.second_completion
|
||||||
// two
|
two
|
||||||
// threeˇ
|
threeˇ
|
||||||
// "},
|
"},
|
||||||
// "\nadditional edit",
|
"\nadditional edit",
|
||||||
// ),
|
),
|
||||||
// ]),
|
]),
|
||||||
// )
|
)
|
||||||
// .await;
|
.await;
|
||||||
// apply_additional_edits.await.unwrap();
|
apply_additional_edits.await.unwrap();
|
||||||
// cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
// one.second_completionˇ
|
one.second_completionˇ
|
||||||
// two
|
two
|
||||||
// three
|
three
|
||||||
// additional edit
|
additional edit
|
||||||
// "});
|
"});
|
||||||
|
|
||||||
// cx.set_state(indoc! {"
|
cx.set_state(indoc! {"
|
||||||
// one.second_completion
|
one.second_completion
|
||||||
// twoˇ
|
twoˇ
|
||||||
// threeˇ
|
threeˇ
|
||||||
// additional edit
|
additional edit
|
||||||
// "});
|
"});
|
||||||
// cx.simulate_keystroke(" ");
|
cx.simulate_keystroke(" ");
|
||||||
// assert!(cx.editor(|e, _| e.context_menu.read().is_none()));
|
assert!(cx.editor(|e, _| e.context_menu.read().is_none()));
|
||||||
// cx.simulate_keystroke("s");
|
cx.simulate_keystroke("s");
|
||||||
// assert!(cx.editor(|e, _| e.context_menu.read().is_none()));
|
assert!(cx.editor(|e, _| e.context_menu.read().is_none()));
|
||||||
|
|
||||||
// cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
// one.second_completion
|
one.second_completion
|
||||||
// two sˇ
|
two sˇ
|
||||||
// three sˇ
|
three sˇ
|
||||||
// additional edit
|
additional edit
|
||||||
// "});
|
"});
|
||||||
// handle_completion_request(
|
handle_completion_request(
|
||||||
// &mut cx,
|
&mut cx,
|
||||||
// indoc! {"
|
indoc! {"
|
||||||
// one.second_completion
|
one.second_completion
|
||||||
// two s
|
two s
|
||||||
// three <s|>
|
three <s|>
|
||||||
// additional edit
|
additional edit
|
||||||
// "},
|
"},
|
||||||
// vec!["fourth_completion", "fifth_completion", "sixth_completion"],
|
vec!["fourth_completion", "fifth_completion", "sixth_completion"],
|
||||||
// )
|
)
|
||||||
// .await;
|
.await;
|
||||||
// cx.condition(|editor, _| editor.context_menu_visible())
|
cx.condition(|editor, _| editor.context_menu_visible())
|
||||||
// .await;
|
.await;
|
||||||
|
|
||||||
// cx.simulate_keystroke("i");
|
cx.simulate_keystroke("i");
|
||||||
|
|
||||||
// handle_completion_request(
|
handle_completion_request(
|
||||||
// &mut cx,
|
&mut cx,
|
||||||
// indoc! {"
|
indoc! {"
|
||||||
// one.second_completion
|
one.second_completion
|
||||||
// two si
|
two si
|
||||||
// three <si|>
|
three <si|>
|
||||||
// additional edit
|
additional edit
|
||||||
// "},
|
"},
|
||||||
// vec!["fourth_completion", "fifth_completion", "sixth_completion"],
|
vec!["fourth_completion", "fifth_completion", "sixth_completion"],
|
||||||
// )
|
)
|
||||||
// .await;
|
.await;
|
||||||
// cx.condition(|editor, _| editor.context_menu_visible())
|
cx.condition(|editor, _| editor.context_menu_visible())
|
||||||
// .await;
|
.await;
|
||||||
|
|
||||||
// let apply_additional_edits = cx.update_editor(|editor, cx| {
|
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
||||||
// editor
|
editor
|
||||||
// .confirm_completion(&ConfirmCompletion::default(), cx)
|
.confirm_completion(&ConfirmCompletion::default(), cx)
|
||||||
// .unwrap()
|
.unwrap()
|
||||||
// });
|
});
|
||||||
// cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
// one.second_completion
|
one.second_completion
|
||||||
// two sixth_completionˇ
|
two sixth_completionˇ
|
||||||
// three sixth_completionˇ
|
three sixth_completionˇ
|
||||||
// additional edit
|
additional edit
|
||||||
// "});
|
"});
|
||||||
|
|
||||||
// handle_resolve_completion_request(&mut cx, None).await;
|
handle_resolve_completion_request(&mut cx, None).await;
|
||||||
// apply_additional_edits.await.unwrap();
|
apply_additional_edits.await.unwrap();
|
||||||
|
|
||||||
// cx.update(|cx| {
|
cx.update(|cx| {
|
||||||
// cx.update_global::<SettingsStore, _, _>(|settings, cx| {
|
cx.update_global::<SettingsStore, _>(|settings, cx| {
|
||||||
// settings.update_user_settings::<EditorSettings>(cx, |settings| {
|
settings.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||||
// settings.show_completions_on_input = Some(false);
|
settings.show_completions_on_input = Some(false);
|
||||||
// });
|
});
|
||||||
// })
|
})
|
||||||
// });
|
});
|
||||||
// cx.set_state("editorˇ");
|
cx.set_state("editorˇ");
|
||||||
// cx.simulate_keystroke(".");
|
cx.simulate_keystroke(".");
|
||||||
// assert!(cx.editor(|e, _| e.context_menu.read().is_none()));
|
assert!(cx.editor(|e, _| e.context_menu.read().is_none()));
|
||||||
// cx.simulate_keystroke("c");
|
cx.simulate_keystroke("c");
|
||||||
// cx.simulate_keystroke("l");
|
cx.simulate_keystroke("l");
|
||||||
// cx.simulate_keystroke("o");
|
cx.simulate_keystroke("o");
|
||||||
// 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, cx);
|
||||||
// });
|
});
|
||||||
// handle_completion_request(&mut cx, "editor.<clo|>", vec!["close", "clobber"]).await;
|
handle_completion_request(&mut cx, "editor.<clo|>", vec!["close", "clobber"]).await;
|
||||||
// cx.condition(|editor, _| editor.context_menu_visible())
|
cx.condition(|editor, _| editor.context_menu_visible())
|
||||||
// .await;
|
.await;
|
||||||
// let apply_additional_edits = cx.update_editor(|editor, cx| {
|
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
||||||
// editor
|
editor
|
||||||
// .confirm_completion(&ConfirmCompletion::default(), cx)
|
.confirm_completion(&ConfirmCompletion::default(), cx)
|
||||||
// .unwrap()
|
.unwrap()
|
||||||
// });
|
});
|
||||||
// cx.assert_editor_state("editor.closeˇ");
|
cx.assert_editor_state("editor.closeˇ");
|
||||||
// handle_resolve_completion_request(&mut cx, None).await;
|
handle_resolve_completion_request(&mut cx, None).await;
|
||||||
// apply_additional_edits.await.unwrap();
|
apply_additional_edits.await.unwrap();
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_toggle_comment(cx: &mut gpui::TestAppContext) {
|
async fn test_toggle_comment(cx: &mut gpui::TestAppContext) {
|
||||||
|
@ -7803,197 +7802,196 @@ async fn test_language_server_restart_due_to_settings_change(cx: &mut gpui::Test
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo!(completions)
|
#[gpui::test]
|
||||||
// #[gpui::test]
|
async fn test_completions_with_additional_edits(cx: &mut gpui::TestAppContext) {
|
||||||
// async fn test_completions_with_additional_edits(cx: &mut gpui::TestAppContext) {
|
init_test(cx, |_| {});
|
||||||
// init_test(cx, |_| {});
|
|
||||||
|
|
||||||
// let mut cx = EditorLspTestContext::new_rust(
|
let mut cx = EditorLspTestContext::new_rust(
|
||||||
// lsp::ServerCapabilities {
|
lsp::ServerCapabilities {
|
||||||
// completion_provider: Some(lsp::CompletionOptions {
|
completion_provider: Some(lsp::CompletionOptions {
|
||||||
// trigger_characters: Some(vec![".".to_string()]),
|
trigger_characters: Some(vec![".".to_string()]),
|
||||||
// resolve_provider: Some(true),
|
resolve_provider: Some(true),
|
||||||
// ..Default::default()
|
..Default::default()
|
||||||
// }),
|
}),
|
||||||
// ..Default::default()
|
..Default::default()
|
||||||
// },
|
},
|
||||||
// cx,
|
cx,
|
||||||
// )
|
)
|
||||||
// .await;
|
.await;
|
||||||
|
|
||||||
// cx.set_state(indoc! {"fn main() { let a = 2ˇ; }"});
|
cx.set_state(indoc! {"fn main() { let a = 2ˇ; }"});
|
||||||
// cx.simulate_keystroke(".");
|
cx.simulate_keystroke(".");
|
||||||
// let completion_item = lsp::CompletionItem {
|
let completion_item = lsp::CompletionItem {
|
||||||
// label: "some".into(),
|
label: "some".into(),
|
||||||
// kind: Some(lsp::CompletionItemKind::SNIPPET),
|
kind: Some(lsp::CompletionItemKind::SNIPPET),
|
||||||
// detail: Some("Wrap the expression in an `Option::Some`".to_string()),
|
detail: Some("Wrap the expression in an `Option::Some`".to_string()),
|
||||||
// documentation: Some(lsp::Documentation::MarkupContent(lsp::MarkupContent {
|
documentation: Some(lsp::Documentation::MarkupContent(lsp::MarkupContent {
|
||||||
// kind: lsp::MarkupKind::Markdown,
|
kind: lsp::MarkupKind::Markdown,
|
||||||
// value: "```rust\nSome(2)\n```".to_string(),
|
value: "```rust\nSome(2)\n```".to_string(),
|
||||||
// })),
|
})),
|
||||||
// deprecated: Some(false),
|
deprecated: Some(false),
|
||||||
// sort_text: Some("fffffff2".to_string()),
|
sort_text: Some("fffffff2".to_string()),
|
||||||
// filter_text: Some("some".to_string()),
|
filter_text: Some("some".to_string()),
|
||||||
// insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
|
insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
|
||||||
// text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
|
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
|
||||||
// range: lsp::Range {
|
range: lsp::Range {
|
||||||
// start: lsp::Position {
|
start: lsp::Position {
|
||||||
// line: 0,
|
line: 0,
|
||||||
// character: 22,
|
character: 22,
|
||||||
// },
|
},
|
||||||
// end: lsp::Position {
|
end: lsp::Position {
|
||||||
// line: 0,
|
line: 0,
|
||||||
// character: 22,
|
character: 22,
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// new_text: "Some(2)".to_string(),
|
new_text: "Some(2)".to_string(),
|
||||||
// })),
|
})),
|
||||||
// additional_text_edits: Some(vec![lsp::TextEdit {
|
additional_text_edits: Some(vec![lsp::TextEdit {
|
||||||
// range: lsp::Range {
|
range: lsp::Range {
|
||||||
// start: lsp::Position {
|
start: lsp::Position {
|
||||||
// line: 0,
|
line: 0,
|
||||||
// character: 20,
|
character: 20,
|
||||||
// },
|
},
|
||||||
// end: lsp::Position {
|
end: lsp::Position {
|
||||||
// line: 0,
|
line: 0,
|
||||||
// character: 22,
|
character: 22,
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// new_text: "".to_string(),
|
new_text: "".to_string(),
|
||||||
// }]),
|
}]),
|
||||||
// ..Default::default()
|
..Default::default()
|
||||||
// };
|
};
|
||||||
|
|
||||||
// let closure_completion_item = completion_item.clone();
|
let closure_completion_item = completion_item.clone();
|
||||||
// let mut request = cx.handle_request::<lsp::request::Completion, _, _>(move |_, _, _| {
|
let mut request = cx.handle_request::<lsp::request::Completion, _, _>(move |_, _, _| {
|
||||||
// let task_completion_item = closure_completion_item.clone();
|
let task_completion_item = closure_completion_item.clone();
|
||||||
// async move {
|
async move {
|
||||||
// Ok(Some(lsp::CompletionResponse::Array(vec![
|
Ok(Some(lsp::CompletionResponse::Array(vec![
|
||||||
// task_completion_item,
|
task_completion_item,
|
||||||
// ])))
|
])))
|
||||||
// }
|
}
|
||||||
// });
|
});
|
||||||
|
|
||||||
// request.next().await;
|
request.next().await;
|
||||||
|
|
||||||
// cx.condition(|editor, _| editor.context_menu_visible())
|
cx.condition(|editor, _| editor.context_menu_visible())
|
||||||
// .await;
|
.await;
|
||||||
// let apply_additional_edits = cx.update_editor(|editor, cx| {
|
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
||||||
// editor
|
editor
|
||||||
// .confirm_completion(&ConfirmCompletion::default(), cx)
|
.confirm_completion(&ConfirmCompletion::default(), cx)
|
||||||
// .unwrap()
|
.unwrap()
|
||||||
// });
|
});
|
||||||
// cx.assert_editor_state(indoc! {"fn main() { let a = 2.Some(2)ˇ; }"});
|
cx.assert_editor_state(indoc! {"fn main() { let a = 2.Some(2)ˇ; }"});
|
||||||
|
|
||||||
// cx.handle_request::<lsp::request::ResolveCompletionItem, _, _>(move |_, _, _| {
|
cx.handle_request::<lsp::request::ResolveCompletionItem, _, _>(move |_, _, _| {
|
||||||
// let task_completion_item = completion_item.clone();
|
let task_completion_item = completion_item.clone();
|
||||||
// async move { Ok(task_completion_item) }
|
async move { Ok(task_completion_item) }
|
||||||
// })
|
})
|
||||||
// .next()
|
.next()
|
||||||
// .await
|
.await
|
||||||
// .unwrap();
|
.unwrap();
|
||||||
// apply_additional_edits.await.unwrap();
|
apply_additional_edits.await.unwrap();
|
||||||
// cx.assert_editor_state(indoc! {"fn main() { let a = Some(2)ˇ; }"});
|
cx.assert_editor_state(indoc! {"fn main() { let a = Some(2)ˇ; }"});
|
||||||
// }
|
}
|
||||||
|
|
||||||
// #[gpui::test]
|
#[gpui::test]
|
||||||
// async fn test_completions_in_languages_with_extra_word_characters(cx: &mut gpui::TestAppContext) {
|
async fn test_completions_in_languages_with_extra_word_characters(cx: &mut gpui::TestAppContext) {
|
||||||
// init_test(cx, |_| {});
|
init_test(cx, |_| {});
|
||||||
|
|
||||||
// let mut cx = EditorLspTestContext::new(
|
let mut cx = EditorLspTestContext::new(
|
||||||
// Language::new(
|
Language::new(
|
||||||
// LanguageConfig {
|
LanguageConfig {
|
||||||
// path_suffixes: vec!["jsx".into()],
|
path_suffixes: vec!["jsx".into()],
|
||||||
// overrides: [(
|
overrides: [(
|
||||||
// "element".into(),
|
"element".into(),
|
||||||
// LanguageConfigOverride {
|
LanguageConfigOverride {
|
||||||
// word_characters: Override::Set(['-'].into_iter().collect()),
|
word_characters: Override::Set(['-'].into_iter().collect()),
|
||||||
// ..Default::default()
|
..Default::default()
|
||||||
// },
|
},
|
||||||
// )]
|
)]
|
||||||
// .into_iter()
|
.into_iter()
|
||||||
// .collect(),
|
.collect(),
|
||||||
// ..Default::default()
|
..Default::default()
|
||||||
// },
|
},
|
||||||
// Some(tree_sitter_typescript::language_tsx()),
|
Some(tree_sitter_typescript::language_tsx()),
|
||||||
// )
|
)
|
||||||
// .with_override_query("(jsx_self_closing_element) @element")
|
.with_override_query("(jsx_self_closing_element) @element")
|
||||||
// .unwrap(),
|
.unwrap(),
|
||||||
// lsp::ServerCapabilities {
|
lsp::ServerCapabilities {
|
||||||
// completion_provider: Some(lsp::CompletionOptions {
|
completion_provider: Some(lsp::CompletionOptions {
|
||||||
// trigger_characters: Some(vec![":".to_string()]),
|
trigger_characters: Some(vec![":".to_string()]),
|
||||||
// ..Default::default()
|
..Default::default()
|
||||||
// }),
|
}),
|
||||||
// ..Default::default()
|
..Default::default()
|
||||||
// },
|
},
|
||||||
// cx,
|
cx,
|
||||||
// )
|
)
|
||||||
// .await;
|
.await;
|
||||||
|
|
||||||
// cx.lsp
|
cx.lsp
|
||||||
// .handle_request::<lsp::request::Completion, _, _>(move |_, _| async move {
|
.handle_request::<lsp::request::Completion, _, _>(move |_, _| async move {
|
||||||
// Ok(Some(lsp::CompletionResponse::Array(vec![
|
Ok(Some(lsp::CompletionResponse::Array(vec![
|
||||||
// lsp::CompletionItem {
|
lsp::CompletionItem {
|
||||||
// label: "bg-blue".into(),
|
label: "bg-blue".into(),
|
||||||
// ..Default::default()
|
..Default::default()
|
||||||
// },
|
},
|
||||||
// lsp::CompletionItem {
|
lsp::CompletionItem {
|
||||||
// label: "bg-red".into(),
|
label: "bg-red".into(),
|
||||||
// ..Default::default()
|
..Default::default()
|
||||||
// },
|
},
|
||||||
// lsp::CompletionItem {
|
lsp::CompletionItem {
|
||||||
// label: "bg-yellow".into(),
|
label: "bg-yellow".into(),
|
||||||
// ..Default::default()
|
..Default::default()
|
||||||
// },
|
},
|
||||||
// ])))
|
])))
|
||||||
// });
|
});
|
||||||
|
|
||||||
// cx.set_state(r#"<p class="bgˇ" />"#);
|
cx.set_state(r#"<p class="bgˇ" />"#);
|
||||||
|
|
||||||
// // Trigger completion when typing a dash, because the dash is an extra
|
// Trigger completion when typing a dash, because the dash is an extra
|
||||||
// // word character in the 'element' scope, which contains the cursor.
|
// word character in the 'element' scope, which contains the cursor.
|
||||||
// cx.simulate_keystroke("-");
|
cx.simulate_keystroke("-");
|
||||||
// cx.executor().run_until_parked();
|
cx.executor().run_until_parked();
|
||||||
// cx.update_editor(|editor, _| {
|
cx.update_editor(|editor, _| {
|
||||||
// if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() {
|
if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() {
|
||||||
// assert_eq!(
|
assert_eq!(
|
||||||
// menu.matches.iter().map(|m| &m.string).collect::<Vec<_>>(),
|
menu.matches.iter().map(|m| &m.string).collect::<Vec<_>>(),
|
||||||
// &["bg-red", "bg-blue", "bg-yellow"]
|
&["bg-red", "bg-blue", "bg-yellow"]
|
||||||
// );
|
);
|
||||||
// } else {
|
} else {
|
||||||
// panic!("expected completion menu to be open");
|
panic!("expected completion menu to be open");
|
||||||
// }
|
}
|
||||||
// });
|
});
|
||||||
|
|
||||||
// cx.simulate_keystroke("l");
|
cx.simulate_keystroke("l");
|
||||||
// cx.executor().run_until_parked();
|
cx.executor().run_until_parked();
|
||||||
// cx.update_editor(|editor, _| {
|
cx.update_editor(|editor, _| {
|
||||||
// if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() {
|
if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() {
|
||||||
// assert_eq!(
|
assert_eq!(
|
||||||
// menu.matches.iter().map(|m| &m.string).collect::<Vec<_>>(),
|
menu.matches.iter().map(|m| &m.string).collect::<Vec<_>>(),
|
||||||
// &["bg-blue", "bg-yellow"]
|
&["bg-blue", "bg-yellow"]
|
||||||
// );
|
);
|
||||||
// } else {
|
} else {
|
||||||
// panic!("expected completion menu to be open");
|
panic!("expected completion menu to be open");
|
||||||
// }
|
}
|
||||||
// });
|
});
|
||||||
|
|
||||||
// // When filtering completions, consider the character after the '-' to
|
// When filtering completions, consider the character after the '-' to
|
||||||
// // be the start of a subword.
|
// be the start of a subword.
|
||||||
// cx.set_state(r#"<p class="yelˇ" />"#);
|
cx.set_state(r#"<p class="yelˇ" />"#);
|
||||||
// cx.simulate_keystroke("l");
|
cx.simulate_keystroke("l");
|
||||||
// cx.executor().run_until_parked();
|
cx.executor().run_until_parked();
|
||||||
// cx.update_editor(|editor, _| {
|
cx.update_editor(|editor, _| {
|
||||||
// if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() {
|
if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() {
|
||||||
// assert_eq!(
|
assert_eq!(
|
||||||
// menu.matches.iter().map(|m| &m.string).collect::<Vec<_>>(),
|
menu.matches.iter().map(|m| &m.string).collect::<Vec<_>>(),
|
||||||
// &["bg-yellow"]
|
&["bg-yellow"]
|
||||||
// );
|
);
|
||||||
// } else {
|
} else {
|
||||||
// panic!("expected completion menu to be open");
|
panic!("expected completion menu to be open");
|
||||||
// }
|
}
|
||||||
// });
|
});
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) {
|
async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
Anchor, DisplayPoint, Editor, EditorSnapshot, GoToDefinition, GoToTypeDefinition, InlayId,
|
Anchor, DisplayPoint, Editor, EditorSnapshot, GoToDefinition, GoToTypeDefinition, InlayId,
|
||||||
SelectPhase,
|
SelectPhase,
|
||||||
};
|
};
|
||||||
use gpui::{Task, ViewContext};
|
use gpui::{px, Task, ViewContext};
|
||||||
use language::{Bias, ToOffset};
|
use language::{Bias, ToOffset};
|
||||||
use lsp::LanguageServerId;
|
use lsp::LanguageServerId;
|
||||||
use project::{
|
use project::{
|
||||||
|
@ -13,6 +13,7 @@ use project::{
|
||||||
ResolveState,
|
ResolveState,
|
||||||
};
|
};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
use theme::ActiveTheme as _;
|
||||||
use util::TryFutureExt;
|
use util::TryFutureExt;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -485,40 +486,45 @@ pub fn show_link_definition(
|
||||||
});
|
});
|
||||||
|
|
||||||
if any_definition_does_not_contain_current_location {
|
if any_definition_does_not_contain_current_location {
|
||||||
// todo!()
|
let style = gpui::HighlightStyle {
|
||||||
// // Highlight symbol using theme link definition highlight style
|
underline: Some(gpui::UnderlineStyle {
|
||||||
// let style = theme::current(cx).editor.link_definition;
|
thickness: px(1.),
|
||||||
// let highlight_range =
|
..Default::default()
|
||||||
// symbol_range.unwrap_or_else(|| match &trigger_point {
|
}),
|
||||||
// TriggerPoint::Text(trigger_anchor) => {
|
color: Some(gpui::red()),
|
||||||
// let snapshot = &snapshot.buffer_snapshot;
|
..Default::default()
|
||||||
// // If no symbol range returned from language server, use the surrounding word.
|
};
|
||||||
// let (offset_range, _) =
|
let highlight_range =
|
||||||
// snapshot.surrounding_word(*trigger_anchor);
|
symbol_range.unwrap_or_else(|| match &trigger_point {
|
||||||
// RangeInEditor::Text(
|
TriggerPoint::Text(trigger_anchor) => {
|
||||||
// snapshot.anchor_before(offset_range.start)
|
let snapshot = &snapshot.buffer_snapshot;
|
||||||
// ..snapshot.anchor_after(offset_range.end),
|
// If no symbol range returned from language server, use the surrounding word.
|
||||||
// )
|
let (offset_range, _) =
|
||||||
// }
|
snapshot.surrounding_word(*trigger_anchor);
|
||||||
// TriggerPoint::InlayHint(highlight, _, _) => {
|
RangeInEditor::Text(
|
||||||
// RangeInEditor::Inlay(highlight.clone())
|
snapshot.anchor_before(offset_range.start)
|
||||||
// }
|
..snapshot.anchor_after(offset_range.end),
|
||||||
// });
|
)
|
||||||
|
}
|
||||||
|
TriggerPoint::InlayHint(highlight, _, _) => {
|
||||||
|
RangeInEditor::Inlay(highlight.clone())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// match highlight_range {
|
match highlight_range {
|
||||||
// RangeInEditor::Text(text_range) => this
|
RangeInEditor::Text(text_range) => this
|
||||||
// .highlight_text::<LinkGoToDefinitionState>(
|
.highlight_text::<LinkGoToDefinitionState>(
|
||||||
// vec![text_range],
|
vec![text_range],
|
||||||
// style,
|
style,
|
||||||
// cx,
|
cx,
|
||||||
// ),
|
),
|
||||||
// RangeInEditor::Inlay(highlight) => this
|
RangeInEditor::Inlay(highlight) => this
|
||||||
// .highlight_inlays::<LinkGoToDefinitionState>(
|
.highlight_inlays::<LinkGoToDefinitionState>(
|
||||||
// vec![highlight],
|
vec![highlight],
|
||||||
// style,
|
style,
|
||||||
// cx,
|
cx,
|
||||||
// ),
|
),
|
||||||
// }
|
}
|
||||||
} else {
|
} else {
|
||||||
hide_link_definition(this, cx);
|
hide_link_definition(this, cx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -595,31 +595,32 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||||
self.select(selections)
|
self.select(selections)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select_anchor_ranges<I: IntoIterator<Item = Range<Anchor>>>(&mut self, ranges: I) {
|
pub fn select_anchor_ranges<I>(&mut self, ranges: I)
|
||||||
todo!()
|
where
|
||||||
// let buffer = self.buffer.read(self.cx).snapshot(self.cx);
|
I: IntoIterator<Item = Range<Anchor>>,
|
||||||
// let selections = ranges
|
{
|
||||||
// .into_iter()
|
let buffer = self.buffer.read(self.cx).snapshot(self.cx);
|
||||||
// .map(|range| {
|
let selections = ranges
|
||||||
// let mut start = range.start;
|
.into_iter()
|
||||||
// let mut end = range.end;
|
.map(|range| {
|
||||||
// let reversed = if start.cmp(&end, &buffer).is_gt() {
|
let mut start = range.start;
|
||||||
// mem::swap(&mut start, &mut end);
|
let mut end = range.end;
|
||||||
// true
|
let reversed = if start.cmp(&end, &buffer).is_gt() {
|
||||||
// } else {
|
mem::swap(&mut start, &mut end);
|
||||||
// false
|
true
|
||||||
// };
|
} else {
|
||||||
// Selection {
|
false
|
||||||
// id: post_inc(&mut self.collection.next_selection_id),
|
};
|
||||||
// start,
|
Selection {
|
||||||
// end,
|
id: post_inc(&mut self.collection.next_selection_id),
|
||||||
// reversed,
|
start,
|
||||||
// goal: SelectionGoal::None,
|
end,
|
||||||
// }
|
reversed,
|
||||||
// })
|
goal: SelectionGoal::None,
|
||||||
// .collect::<Vec<_>>();
|
}
|
||||||
|
})
|
||||||
// self.select_anchors(selections)
|
.collect::<Vec<_>>();
|
||||||
|
self.select_anchors(selections)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_selection_id(&mut self) -> usize {
|
pub fn new_selection_id(&mut self) -> usize {
|
||||||
|
|
|
@ -265,7 +265,9 @@ impl TextState {
|
||||||
pub struct InteractiveText {
|
pub struct InteractiveText {
|
||||||
element_id: ElementId,
|
element_id: ElementId,
|
||||||
text: StyledText,
|
text: StyledText,
|
||||||
click_listener: Option<Box<dyn Fn(InteractiveTextClickEvent, &mut WindowContext<'_>)>>,
|
click_listener:
|
||||||
|
Option<Box<dyn Fn(&[Range<usize>], InteractiveTextClickEvent, &mut WindowContext<'_>)>>,
|
||||||
|
clickable_ranges: Vec<Range<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InteractiveTextClickEvent {
|
struct InteractiveTextClickEvent {
|
||||||
|
@ -284,6 +286,7 @@ impl InteractiveText {
|
||||||
element_id: id.into(),
|
element_id: id.into(),
|
||||||
text,
|
text,
|
||||||
click_listener: None,
|
click_listener: None,
|
||||||
|
clickable_ranges: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +295,7 @@ impl InteractiveText {
|
||||||
ranges: Vec<Range<usize>>,
|
ranges: Vec<Range<usize>>,
|
||||||
listener: impl Fn(usize, &mut WindowContext<'_>) + 'static,
|
listener: impl Fn(usize, &mut WindowContext<'_>) + 'static,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self.click_listener = Some(Box::new(move |event, cx| {
|
self.click_listener = Some(Box::new(move |ranges, event, cx| {
|
||||||
for (range_ix, range) in ranges.iter().enumerate() {
|
for (range_ix, range) in ranges.iter().enumerate() {
|
||||||
if range.contains(&event.mouse_down_index) && range.contains(&event.mouse_up_index)
|
if range.contains(&event.mouse_down_index) && range.contains(&event.mouse_up_index)
|
||||||
{
|
{
|
||||||
|
@ -300,6 +303,7 @@ impl InteractiveText {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
self.clickable_ranges = ranges;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -334,6 +338,19 @@ impl Element for InteractiveText {
|
||||||
|
|
||||||
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||||
if let Some(click_listener) = self.click_listener {
|
if let Some(click_listener) = self.click_listener {
|
||||||
|
if let Some(ix) = state
|
||||||
|
.text_state
|
||||||
|
.index_for_position(bounds, cx.mouse_position())
|
||||||
|
{
|
||||||
|
if self
|
||||||
|
.clickable_ranges
|
||||||
|
.iter()
|
||||||
|
.any(|range| range.contains(&ix))
|
||||||
|
{
|
||||||
|
cx.set_cursor_style(crate::CursorStyle::PointingHand)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let text_state = state.text_state.clone();
|
let text_state = state.text_state.clone();
|
||||||
let mouse_down = state.mouse_down_index.clone();
|
let mouse_down = state.mouse_down_index.clone();
|
||||||
if let Some(mouse_down_index) = mouse_down.get() {
|
if let Some(mouse_down_index) = mouse_down.get() {
|
||||||
|
@ -343,6 +360,7 @@ impl Element for InteractiveText {
|
||||||
text_state.index_for_position(bounds, event.position)
|
text_state.index_for_position(bounds, event.position)
|
||||||
{
|
{
|
||||||
click_listener(
|
click_listener(
|
||||||
|
&self.clickable_ranges,
|
||||||
InteractiveTextClickEvent {
|
InteractiveTextClickEvent {
|
||||||
mouse_down_index,
|
mouse_down_index,
|
||||||
mouse_up_index,
|
mouse_up_index,
|
||||||
|
|
|
@ -717,8 +717,9 @@ async fn location_links_from_lsp(
|
||||||
})?
|
})?
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
buffer.update(&mut cx, |origin_buffer, cx| {
|
cx.update(|cx| {
|
||||||
let origin_location = origin_range.map(|origin_range| {
|
let origin_location = origin_range.map(|origin_range| {
|
||||||
|
let origin_buffer = buffer.read(cx);
|
||||||
let origin_start =
|
let origin_start =
|
||||||
origin_buffer.clip_point_utf16(point_from_lsp(origin_range.start), Bias::Left);
|
origin_buffer.clip_point_utf16(point_from_lsp(origin_range.start), Bias::Left);
|
||||||
let origin_end =
|
let origin_end =
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue