Merge branch 'main' into zed2-breadcrumbs
This commit is contained in:
+202
-169
@@ -40,11 +40,12 @@ use fuzzy::{StringMatch, StringMatchCandidate};
|
||||
use git::diff_hunk_to_display;
|
||||
use gpui::{
|
||||
actions, div, point, prelude::*, px, relative, rems, size, uniform_list, Action, AnyElement,
|
||||
AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Context, ElementId,
|
||||
EventEmitter, FocusHandle, FocusableView, FontFeatures, FontStyle, FontWeight, HighlightStyle,
|
||||
Hsla, InputHandler, InteractiveText, KeyContext, Model, MouseButton, ParentElement, Pixels,
|
||||
Render, RenderOnce, SharedString, Styled, StyledText, Subscription, Task, TextRun, TextStyle,
|
||||
UniformListScrollHandle, View, ViewContext, VisualContext, WeakView, WhiteSpace, WindowContext,
|
||||
AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Context,
|
||||
DispatchPhase, Div, ElementId, EventEmitter, FocusHandle, FocusableView, FontFeatures,
|
||||
FontStyle, FontWeight, HighlightStyle, Hsla, InputHandler, InteractiveText, KeyContext, Model,
|
||||
MouseButton, ParentElement, Pixels, Render, RenderOnce, SharedString, Styled, StyledText,
|
||||
Subscription, Task, TextRun, TextStyle, UniformListScrollHandle, View, ViewContext,
|
||||
VisualContext, WeakView, WhiteSpace, WindowContext,
|
||||
};
|
||||
use highlight_matching_bracket::refresh_matching_bracket_highlights;
|
||||
use hover_popover::{hide_hover, HoverState};
|
||||
@@ -72,7 +73,7 @@ use ordered_float::OrderedFloat;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use project::{FormatTrigger, Location, Project, ProjectPath, ProjectTransaction};
|
||||
use rand::prelude::*;
|
||||
use rpc::proto::*;
|
||||
use rpc::proto::{self, *};
|
||||
use scroll::{
|
||||
autoscroll::Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide,
|
||||
};
|
||||
@@ -98,12 +99,13 @@ use text::{OffsetUtf16, Rope};
|
||||
use theme::{
|
||||
ActiveTheme, DiagnosticStyle, PlayerColor, SyntaxTheme, Theme, ThemeColors, ThemeSettings,
|
||||
};
|
||||
use ui::{h_stack, v_stack, HighlightedLabel, IconButton, Popover, StyledExt, Tooltip};
|
||||
use ui::prelude::*;
|
||||
use ui::{h_stack, v_stack, HighlightedLabel, IconButton, Popover, Tooltip};
|
||||
use util::{post_inc, RangeExt, ResultExt, TryFutureExt};
|
||||
use workspace::{
|
||||
item::{ItemEvent, ItemHandle},
|
||||
searchable::SearchEvent,
|
||||
ItemNavHistory, SplitDirection, ViewId, Workspace,
|
||||
ItemNavHistory, Pane, SplitDirection, ViewId, Workspace,
|
||||
};
|
||||
|
||||
const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
|
||||
@@ -152,7 +154,6 @@ pub fn render_parsed_markdown(
|
||||
}),
|
||||
);
|
||||
|
||||
// todo!("add the ability to change cursor style for link ranges")
|
||||
let mut links = Vec::new();
|
||||
let mut link_ranges = Vec::new();
|
||||
for (range, region) in parsed.region_ranges.iter().zip(&parsed.regions) {
|
||||
@@ -529,8 +530,6 @@ pub fn init(cx: &mut AppContext) {
|
||||
// cx.register_action_type(Editor::context_menu_next);
|
||||
// cx.register_action_type(Editor::context_menu_last);
|
||||
|
||||
hover_popover::init(cx);
|
||||
|
||||
workspace::register_project_item::<Editor>(cx);
|
||||
workspace::register_followable_item::<Editor>(cx);
|
||||
workspace::register_deserializable_item::<Editor>(cx);
|
||||
@@ -663,6 +662,7 @@ pub struct Editor {
|
||||
pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
|
||||
gutter_width: Pixels,
|
||||
style: Option<EditorStyle>,
|
||||
editor_actions: Vec<Box<dyn Fn(&mut ViewContext<Self>)>>,
|
||||
}
|
||||
|
||||
pub struct EditorSnapshot {
|
||||
@@ -970,95 +970,94 @@ impl CompletionsMenu {
|
||||
|
||||
fn pre_resolve_completion_documentation(
|
||||
&self,
|
||||
_editor: &Editor,
|
||||
_cx: &mut ViewContext<Editor>,
|
||||
editor: &Editor,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> Option<Task<()>> {
|
||||
// todo!("implementation below ");
|
||||
None
|
||||
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)
|
||||
})
|
||||
.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(
|
||||
&mut self,
|
||||
@@ -1079,10 +1078,9 @@ impl CompletionsMenu {
|
||||
let completions = self.completions.clone();
|
||||
let completions_guard = completions.read();
|
||||
let completion = &completions_guard[completion_index];
|
||||
// todo!()
|
||||
// if completion.documentation.is_some() {
|
||||
// return;
|
||||
// }
|
||||
if completion.documentation.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
let server_id = completion.server_id;
|
||||
let completion = completion.lsp_completion.clone();
|
||||
@@ -1141,41 +1139,40 @@ impl CompletionsMenu {
|
||||
client: Arc<Client>,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
) {
|
||||
// todo!()
|
||||
// let request = proto::ResolveCompletionDocumentation {
|
||||
// project_id,
|
||||
// language_server_id: server_id.0 as u64,
|
||||
// lsp_completion: serde_json::to_string(&completion).unwrap().into_bytes(),
|
||||
// };
|
||||
let request = proto::ResolveCompletionDocumentation {
|
||||
project_id,
|
||||
language_server_id: server_id.0 as u64,
|
||||
lsp_completion: serde_json::to_string(&completion).unwrap().into_bytes(),
|
||||
};
|
||||
|
||||
// let Some(response) = client
|
||||
// .request(request)
|
||||
// .await
|
||||
// .context("completion documentation resolve proto request")
|
||||
// .log_err()
|
||||
// else {
|
||||
// return;
|
||||
// };
|
||||
let Some(response) = client
|
||||
.request(request)
|
||||
.await
|
||||
.context("completion documentation resolve proto request")
|
||||
.log_err()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
// if response.text.is_empty() {
|
||||
// let mut completions = completions.write();
|
||||
// let completion = &mut completions[completion_index];
|
||||
// completion.documentation = Some(Documentation::Undocumented);
|
||||
// }
|
||||
if response.text.is_empty() {
|
||||
let mut completions = completions.write();
|
||||
let completion = &mut completions[completion_index];
|
||||
completion.documentation = Some(Documentation::Undocumented);
|
||||
}
|
||||
|
||||
// let documentation = if response.is_markdown {
|
||||
// Documentation::MultiLineMarkdown(
|
||||
// markdown::parse_markdown(&response.text, &language_registry, None).await,
|
||||
// )
|
||||
// } else if response.text.lines().count() <= 1 {
|
||||
// Documentation::SingleLine(response.text)
|
||||
// } else {
|
||||
// Documentation::MultiLinePlainText(response.text)
|
||||
// };
|
||||
let documentation = if response.is_markdown {
|
||||
Documentation::MultiLineMarkdown(
|
||||
markdown::parse_markdown(&response.text, &language_registry, None).await,
|
||||
)
|
||||
} else if response.text.lines().count() <= 1 {
|
||||
Documentation::SingleLine(response.text)
|
||||
} else {
|
||||
Documentation::MultiLinePlainText(response.text)
|
||||
};
|
||||
|
||||
// let mut completions = completions.write();
|
||||
// let completion = &mut completions[completion_index];
|
||||
// completion.documentation = Some(documentation);
|
||||
let mut completions = completions.write();
|
||||
let completion = &mut completions[completion_index];
|
||||
completion.documentation = Some(documentation);
|
||||
}
|
||||
|
||||
async fn resolve_completion_documentation_local(
|
||||
@@ -1185,38 +1182,37 @@ impl CompletionsMenu {
|
||||
completion: lsp::CompletionItem,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
) {
|
||||
// todo!()
|
||||
// let can_resolve = server
|
||||
// .capabilities()
|
||||
// .completion_provider
|
||||
// .as_ref()
|
||||
// .and_then(|options| options.resolve_provider)
|
||||
// .unwrap_or(false);
|
||||
// if !can_resolve {
|
||||
// return;
|
||||
// }
|
||||
let can_resolve = server
|
||||
.capabilities()
|
||||
.completion_provider
|
||||
.as_ref()
|
||||
.and_then(|options| options.resolve_provider)
|
||||
.unwrap_or(false);
|
||||
if !can_resolve {
|
||||
return;
|
||||
}
|
||||
|
||||
// let request = server.request::<lsp::request::ResolveCompletionItem>(completion);
|
||||
// let Some(completion_item) = request.await.log_err() else {
|
||||
// return;
|
||||
// };
|
||||
let request = server.request::<lsp::request::ResolveCompletionItem>(completion);
|
||||
let Some(completion_item) = request.await.log_err() else {
|
||||
return;
|
||||
};
|
||||
|
||||
// if let Some(lsp_documentation) = completion_item.documentation {
|
||||
// let documentation = language::prepare_completion_documentation(
|
||||
// &lsp_documentation,
|
||||
// &language_registry,
|
||||
// None, // TODO: Try to reasonably work out which language the completion is for
|
||||
// )
|
||||
// .await;
|
||||
if let Some(lsp_documentation) = completion_item.documentation {
|
||||
let documentation = language::prepare_completion_documentation(
|
||||
&lsp_documentation,
|
||||
&language_registry,
|
||||
None, // TODO: Try to reasonably work out which language the completion is for
|
||||
)
|
||||
.await;
|
||||
|
||||
// let mut completions = completions.write();
|
||||
// let completion = &mut completions[completion_index];
|
||||
// completion.documentation = Some(documentation);
|
||||
// } else {
|
||||
// let mut completions = completions.write();
|
||||
// let completion = &mut completions[completion_index];
|
||||
// completion.documentation = Some(Documentation::Undocumented);
|
||||
// }
|
||||
let mut completions = completions.write();
|
||||
let completion = &mut completions[completion_index];
|
||||
completion.documentation = Some(documentation);
|
||||
} else {
|
||||
let mut completions = completions.write();
|
||||
let completion = &mut completions[completion_index];
|
||||
completion.documentation = Some(Documentation::Undocumented);
|
||||
}
|
||||
}
|
||||
|
||||
fn visible(&self) -> bool {
|
||||
@@ -1272,6 +1268,13 @@ impl CompletionsMenu {
|
||||
multiline_docs.map(|div| {
|
||||
div.id("multiline_docs")
|
||||
.max_h(max_height)
|
||||
.flex_1()
|
||||
.px_1p5()
|
||||
.py_1()
|
||||
.min_w(px(260.))
|
||||
.max_w(px(640.))
|
||||
.w(px(500.))
|
||||
.text_ui()
|
||||
.overflow_y_scroll()
|
||||
// Prevent a mouse down on documentation from being propagated to the editor,
|
||||
// because that would move the cursor.
|
||||
@@ -1322,13 +1325,18 @@ impl CompletionsMenu {
|
||||
|
||||
div()
|
||||
.id(mat.candidate_id)
|
||||
.min_w(px(300.))
|
||||
.max_w(px(700.))
|
||||
.min_w(px(220.))
|
||||
.max_w(px(540.))
|
||||
.whitespace_nowrap()
|
||||
.overflow_hidden()
|
||||
.bg(gpui::green())
|
||||
.hover(|style| style.bg(gpui::blue()))
|
||||
.when(item_ix == selected_item, |div| div.bg(gpui::red()))
|
||||
.text_ui()
|
||||
.px_1()
|
||||
.rounded(px(4.))
|
||||
.bg(cx.theme().colors().ghost_element_background)
|
||||
.hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
|
||||
.when(item_ix == selected_item, |div| {
|
||||
div.bg(cx.theme().colors().ghost_element_selected)
|
||||
})
|
||||
.on_mouse_down(
|
||||
MouseButton::Left,
|
||||
cx.listener(move |editor, event, cx| {
|
||||
@@ -1887,6 +1895,7 @@ impl Editor {
|
||||
pixel_position_of_newest_cursor: None,
|
||||
gutter_width: Default::default(),
|
||||
style: None,
|
||||
editor_actions: Default::default(),
|
||||
_subscriptions: vec![
|
||||
cx.observe(&buffer, Self::on_buffer_changed),
|
||||
cx.subscribe(&buffer, Self::on_buffer_event),
|
||||
@@ -2018,10 +2027,14 @@ impl Editor {
|
||||
&self.buffer
|
||||
}
|
||||
|
||||
fn workspace(&self) -> Option<View<Workspace>> {
|
||||
pub fn workspace(&self) -> Option<View<Workspace>> {
|
||||
self.workspace.as_ref()?.0.upgrade()
|
||||
}
|
||||
|
||||
pub fn pane(&self, cx: &AppContext) -> Option<View<Pane>> {
|
||||
self.workspace()?.read(cx).pane_for(&self.handle.upgrade()?)
|
||||
}
|
||||
|
||||
pub fn title<'a>(&self, cx: &'a AppContext) -> Cow<'a, str> {
|
||||
self.buffer().read(cx).title(cx)
|
||||
}
|
||||
@@ -4369,7 +4382,7 @@ impl Editor {
|
||||
editor.fold_at(&FoldAt { buffer_row }, cx);
|
||||
}
|
||||
}))
|
||||
.color(ui::Color::Muted)
|
||||
.icon_color(ui::Color::Muted)
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
@@ -9178,6 +9191,26 @@ impl Editor {
|
||||
cx.emit(EditorEvent::Blurred);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn register_action<A: Action>(
|
||||
&mut self,
|
||||
listener: impl Fn(&A, &mut WindowContext) + 'static,
|
||||
) -> &mut Self {
|
||||
let listener = Arc::new(listener);
|
||||
|
||||
self.editor_actions.push(Box::new(move |cx| {
|
||||
let view = cx.view().clone();
|
||||
let cx = cx.window_context();
|
||||
let listener = listener.clone();
|
||||
cx.on_action(TypeId::of::<A>(), move |action, phase, cx| {
|
||||
let action = action.downcast_ref().unwrap();
|
||||
if phase == DispatchPhase::Bubble {
|
||||
listener(action, cx)
|
||||
}
|
||||
})
|
||||
}));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CollaborationHub {
|
||||
|
||||
+338
-340
@@ -5427,178 +5427,177 @@ async fn test_strip_whitespace_and_format_via_lsp(cx: &mut gpui::TestAppContext)
|
||||
);
|
||||
}
|
||||
|
||||
//todo!(completion)
|
||||
// #[gpui::test]
|
||||
// async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||
// init_test(cx, |_| {});
|
||||
#[gpui::test]
|
||||
async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
// let mut cx = EditorLspTestContext::new_rust(
|
||||
// lsp::ServerCapabilities {
|
||||
// completion_provider: Some(lsp::CompletionOptions {
|
||||
// trigger_characters: Some(vec![".".to_string(), ":".to_string()]),
|
||||
// resolve_provider: Some(true),
|
||||
// ..Default::default()
|
||||
// }),
|
||||
// ..Default::default()
|
||||
// },
|
||||
// cx,
|
||||
// )
|
||||
// .await;
|
||||
let mut cx = EditorLspTestContext::new_rust(
|
||||
lsp::ServerCapabilities {
|
||||
completion_provider: Some(lsp::CompletionOptions {
|
||||
trigger_characters: Some(vec![".".to_string(), ":".to_string()]),
|
||||
resolve_provider: Some(true),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
|
||||
// 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.context_menu_next(&Default::default(), cx);
|
||||
// editor
|
||||
// .confirm_completion(&ConfirmCompletion::default(), cx)
|
||||
// .unwrap()
|
||||
// });
|
||||
// cx.assert_editor_state(indoc! {"
|
||||
// one.second_completionˇ
|
||||
// two
|
||||
// three
|
||||
// "});
|
||||
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.context_menu_next(&Default::default(), cx);
|
||||
editor
|
||||
.confirm_completion(&ConfirmCompletion::default(), cx)
|
||||
.unwrap()
|
||||
});
|
||||
cx.assert_editor_state(indoc! {"
|
||||
one.second_completionˇ
|
||||
two
|
||||
three
|
||||
"});
|
||||
|
||||
// handle_resolve_completion_request(
|
||||
// &mut cx,
|
||||
// Some(vec![
|
||||
// (
|
||||
// //This overlaps with the primary completion edit which is
|
||||
// //misbehavior from the LSP spec, test that we filter it out
|
||||
// indoc! {"
|
||||
// one.second_ˇcompletion
|
||||
// two
|
||||
// threeˇ
|
||||
// "},
|
||||
// "overlapping additional edit",
|
||||
// ),
|
||||
// (
|
||||
// indoc! {"
|
||||
// one.second_completion
|
||||
// two
|
||||
// threeˇ
|
||||
// "},
|
||||
// "\nadditional edit",
|
||||
// ),
|
||||
// ]),
|
||||
// )
|
||||
// .await;
|
||||
// apply_additional_edits.await.unwrap();
|
||||
// cx.assert_editor_state(indoc! {"
|
||||
// one.second_completionˇ
|
||||
// two
|
||||
// three
|
||||
// additional edit
|
||||
// "});
|
||||
handle_resolve_completion_request(
|
||||
&mut cx,
|
||||
Some(vec![
|
||||
(
|
||||
//This overlaps with the primary completion edit which is
|
||||
//misbehavior from the LSP spec, test that we filter it out
|
||||
indoc! {"
|
||||
one.second_ˇcompletion
|
||||
two
|
||||
threeˇ
|
||||
"},
|
||||
"overlapping additional edit",
|
||||
),
|
||||
(
|
||||
indoc! {"
|
||||
one.second_completion
|
||||
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.read().is_none()));
|
||||
// cx.simulate_keystroke("s");
|
||||
// assert!(cx.editor(|e, _| e.context_menu.read().is_none()));
|
||||
cx.set_state(indoc! {"
|
||||
one.second_completion
|
||||
twoˇ
|
||||
threeˇ
|
||||
additional edit
|
||||
"});
|
||||
cx.simulate_keystroke(" ");
|
||||
assert!(cx.editor(|e, _| e.context_menu.read().is_none()));
|
||||
cx.simulate_keystroke("s");
|
||||
assert!(cx.editor(|e, _| e.context_menu.read().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.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");
|
||||
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;
|
||||
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()
|
||||
// });
|
||||
// cx.assert_editor_state(indoc! {"
|
||||
// one.second_completion
|
||||
// two sixth_completionˇ
|
||||
// three sixth_completionˇ
|
||||
// additional edit
|
||||
// "});
|
||||
let apply_additional_edits = cx.update_editor(|editor, cx| {
|
||||
editor
|
||||
.confirm_completion(&ConfirmCompletion::default(), cx)
|
||||
.unwrap()
|
||||
});
|
||||
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();
|
||||
handle_resolve_completion_request(&mut cx, None).await;
|
||||
apply_additional_edits.await.unwrap();
|
||||
|
||||
// cx.update(|cx| {
|
||||
// cx.update_global::<SettingsStore, _, _>(|settings, cx| {
|
||||
// settings.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
// settings.show_completions_on_input = Some(false);
|
||||
// });
|
||||
// })
|
||||
// });
|
||||
// cx.set_state("editorˇ");
|
||||
// cx.simulate_keystroke(".");
|
||||
// assert!(cx.editor(|e, _| e.context_menu.read().is_none()));
|
||||
// cx.simulate_keystroke("c");
|
||||
// cx.simulate_keystroke("l");
|
||||
// cx.simulate_keystroke("o");
|
||||
// cx.assert_editor_state("editor.cloˇ");
|
||||
// assert!(cx.editor(|e, _| e.context_menu.read().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();
|
||||
// }
|
||||
cx.update(|cx| {
|
||||
cx.update_global::<SettingsStore, _>(|settings, cx| {
|
||||
settings.update_user_settings::<EditorSettings>(cx, |settings| {
|
||||
settings.show_completions_on_input = Some(false);
|
||||
});
|
||||
})
|
||||
});
|
||||
cx.set_state("editorˇ");
|
||||
cx.simulate_keystroke(".");
|
||||
assert!(cx.editor(|e, _| e.context_menu.read().is_none()));
|
||||
cx.simulate_keystroke("c");
|
||||
cx.simulate_keystroke("l");
|
||||
cx.simulate_keystroke("o");
|
||||
cx.assert_editor_state("editor.cloˇ");
|
||||
assert!(cx.editor(|e, _| e.context_menu.read().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();
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
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]
|
||||
// async fn test_completions_with_additional_edits(cx: &mut gpui::TestAppContext) {
|
||||
// init_test(cx, |_| {});
|
||||
#[gpui::test]
|
||||
async fn test_completions_with_additional_edits(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
// let mut cx = EditorLspTestContext::new_rust(
|
||||
// lsp::ServerCapabilities {
|
||||
// completion_provider: Some(lsp::CompletionOptions {
|
||||
// trigger_characters: Some(vec![".".to_string()]),
|
||||
// resolve_provider: Some(true),
|
||||
// ..Default::default()
|
||||
// }),
|
||||
// ..Default::default()
|
||||
// },
|
||||
// cx,
|
||||
// )
|
||||
// .await;
|
||||
let mut cx = EditorLspTestContext::new_rust(
|
||||
lsp::ServerCapabilities {
|
||||
completion_provider: Some(lsp::CompletionOptions {
|
||||
trigger_characters: Some(vec![".".to_string()]),
|
||||
resolve_provider: Some(true),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
|
||||
// cx.set_state(indoc! {"fn main() { let a = 2ˇ; }"});
|
||||
// cx.simulate_keystroke(".");
|
||||
// let completion_item = lsp::CompletionItem {
|
||||
// label: "some".into(),
|
||||
// kind: Some(lsp::CompletionItemKind::SNIPPET),
|
||||
// detail: Some("Wrap the expression in an `Option::Some`".to_string()),
|
||||
// documentation: Some(lsp::Documentation::MarkupContent(lsp::MarkupContent {
|
||||
// kind: lsp::MarkupKind::Markdown,
|
||||
// value: "```rust\nSome(2)\n```".to_string(),
|
||||
// })),
|
||||
// deprecated: Some(false),
|
||||
// sort_text: Some("fffffff2".to_string()),
|
||||
// filter_text: Some("some".to_string()),
|
||||
// insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
|
||||
// text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
|
||||
// range: lsp::Range {
|
||||
// start: lsp::Position {
|
||||
// line: 0,
|
||||
// character: 22,
|
||||
// },
|
||||
// end: lsp::Position {
|
||||
// line: 0,
|
||||
// character: 22,
|
||||
// },
|
||||
// },
|
||||
// new_text: "Some(2)".to_string(),
|
||||
// })),
|
||||
// additional_text_edits: Some(vec![lsp::TextEdit {
|
||||
// range: lsp::Range {
|
||||
// start: lsp::Position {
|
||||
// line: 0,
|
||||
// character: 20,
|
||||
// },
|
||||
// end: lsp::Position {
|
||||
// line: 0,
|
||||
// character: 22,
|
||||
// },
|
||||
// },
|
||||
// new_text: "".to_string(),
|
||||
// }]),
|
||||
// ..Default::default()
|
||||
// };
|
||||
cx.set_state(indoc! {"fn main() { let a = 2ˇ; }"});
|
||||
cx.simulate_keystroke(".");
|
||||
let completion_item = lsp::CompletionItem {
|
||||
label: "some".into(),
|
||||
kind: Some(lsp::CompletionItemKind::SNIPPET),
|
||||
detail: Some("Wrap the expression in an `Option::Some`".to_string()),
|
||||
documentation: Some(lsp::Documentation::MarkupContent(lsp::MarkupContent {
|
||||
kind: lsp::MarkupKind::Markdown,
|
||||
value: "```rust\nSome(2)\n```".to_string(),
|
||||
})),
|
||||
deprecated: Some(false),
|
||||
sort_text: Some("fffffff2".to_string()),
|
||||
filter_text: Some("some".to_string()),
|
||||
insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
|
||||
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
|
||||
range: lsp::Range {
|
||||
start: lsp::Position {
|
||||
line: 0,
|
||||
character: 22,
|
||||
},
|
||||
end: lsp::Position {
|
||||
line: 0,
|
||||
character: 22,
|
||||
},
|
||||
},
|
||||
new_text: "Some(2)".to_string(),
|
||||
})),
|
||||
additional_text_edits: Some(vec![lsp::TextEdit {
|
||||
range: lsp::Range {
|
||||
start: lsp::Position {
|
||||
line: 0,
|
||||
character: 20,
|
||||
},
|
||||
end: lsp::Position {
|
||||
line: 0,
|
||||
character: 22,
|
||||
},
|
||||
},
|
||||
new_text: "".to_string(),
|
||||
}]),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// let closure_completion_item = completion_item.clone();
|
||||
// let mut request = cx.handle_request::<lsp::request::Completion, _, _>(move |_, _, _| {
|
||||
// let task_completion_item = closure_completion_item.clone();
|
||||
// async move {
|
||||
// Ok(Some(lsp::CompletionResponse::Array(vec![
|
||||
// task_completion_item,
|
||||
// ])))
|
||||
// }
|
||||
// });
|
||||
let closure_completion_item = completion_item.clone();
|
||||
let mut request = cx.handle_request::<lsp::request::Completion, _, _>(move |_, _, _| {
|
||||
let task_completion_item = closure_completion_item.clone();
|
||||
async move {
|
||||
Ok(Some(lsp::CompletionResponse::Array(vec![
|
||||
task_completion_item,
|
||||
])))
|
||||
}
|
||||
});
|
||||
|
||||
// request.next().await;
|
||||
request.next().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(indoc! {"fn main() { let a = 2.Some(2)ˇ; }"});
|
||||
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(indoc! {"fn main() { let a = 2.Some(2)ˇ; }"});
|
||||
|
||||
// cx.handle_request::<lsp::request::ResolveCompletionItem, _, _>(move |_, _, _| {
|
||||
// let task_completion_item = completion_item.clone();
|
||||
// async move { Ok(task_completion_item) }
|
||||
// })
|
||||
// .next()
|
||||
// .await
|
||||
// .unwrap();
|
||||
// apply_additional_edits.await.unwrap();
|
||||
// cx.assert_editor_state(indoc! {"fn main() { let a = Some(2)ˇ; }"});
|
||||
// }
|
||||
cx.handle_request::<lsp::request::ResolveCompletionItem, _, _>(move |_, _, _| {
|
||||
let task_completion_item = completion_item.clone();
|
||||
async move { Ok(task_completion_item) }
|
||||
})
|
||||
.next()
|
||||
.await
|
||||
.unwrap();
|
||||
apply_additional_edits.await.unwrap();
|
||||
cx.assert_editor_state(indoc! {"fn main() { let a = Some(2)ˇ; }"});
|
||||
}
|
||||
|
||||
// #[gpui::test]
|
||||
// async fn test_completions_in_languages_with_extra_word_characters(cx: &mut gpui::TestAppContext) {
|
||||
// init_test(cx, |_| {});
|
||||
#[gpui::test]
|
||||
async fn test_completions_in_languages_with_extra_word_characters(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
// let mut cx = EditorLspTestContext::new(
|
||||
// Language::new(
|
||||
// LanguageConfig {
|
||||
// path_suffixes: vec!["jsx".into()],
|
||||
// overrides: [(
|
||||
// "element".into(),
|
||||
// LanguageConfigOverride {
|
||||
// word_characters: Override::Set(['-'].into_iter().collect()),
|
||||
// ..Default::default()
|
||||
// },
|
||||
// )]
|
||||
// .into_iter()
|
||||
// .collect(),
|
||||
// ..Default::default()
|
||||
// },
|
||||
// Some(tree_sitter_typescript::language_tsx()),
|
||||
// )
|
||||
// .with_override_query("(jsx_self_closing_element) @element")
|
||||
// .unwrap(),
|
||||
// lsp::ServerCapabilities {
|
||||
// completion_provider: Some(lsp::CompletionOptions {
|
||||
// trigger_characters: Some(vec![":".to_string()]),
|
||||
// ..Default::default()
|
||||
// }),
|
||||
// ..Default::default()
|
||||
// },
|
||||
// cx,
|
||||
// )
|
||||
// .await;
|
||||
let mut cx = EditorLspTestContext::new(
|
||||
Language::new(
|
||||
LanguageConfig {
|
||||
path_suffixes: vec!["jsx".into()],
|
||||
overrides: [(
|
||||
"element".into(),
|
||||
LanguageConfigOverride {
|
||||
word_characters: Override::Set(['-'].into_iter().collect()),
|
||||
..Default::default()
|
||||
},
|
||||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
Some(tree_sitter_typescript::language_tsx()),
|
||||
)
|
||||
.with_override_query("(jsx_self_closing_element) @element")
|
||||
.unwrap(),
|
||||
lsp::ServerCapabilities {
|
||||
completion_provider: Some(lsp::CompletionOptions {
|
||||
trigger_characters: Some(vec![":".to_string()]),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
|
||||
// cx.lsp
|
||||
// .handle_request::<lsp::request::Completion, _, _>(move |_, _| async move {
|
||||
// Ok(Some(lsp::CompletionResponse::Array(vec![
|
||||
// lsp::CompletionItem {
|
||||
// label: "bg-blue".into(),
|
||||
// ..Default::default()
|
||||
// },
|
||||
// lsp::CompletionItem {
|
||||
// label: "bg-red".into(),
|
||||
// ..Default::default()
|
||||
// },
|
||||
// lsp::CompletionItem {
|
||||
// label: "bg-yellow".into(),
|
||||
// ..Default::default()
|
||||
// },
|
||||
// ])))
|
||||
// });
|
||||
cx.lsp
|
||||
.handle_request::<lsp::request::Completion, _, _>(move |_, _| async move {
|
||||
Ok(Some(lsp::CompletionResponse::Array(vec![
|
||||
lsp::CompletionItem {
|
||||
label: "bg-blue".into(),
|
||||
..Default::default()
|
||||
},
|
||||
lsp::CompletionItem {
|
||||
label: "bg-red".into(),
|
||||
..Default::default()
|
||||
},
|
||||
lsp::CompletionItem {
|
||||
label: "bg-yellow".into(),
|
||||
..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
|
||||
// // word character in the 'element' scope, which contains the cursor.
|
||||
// cx.simulate_keystroke("-");
|
||||
// cx.executor().run_until_parked();
|
||||
// cx.update_editor(|editor, _| {
|
||||
// if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() {
|
||||
// assert_eq!(
|
||||
// menu.matches.iter().map(|m| &m.string).collect::<Vec<_>>(),
|
||||
// &["bg-red", "bg-blue", "bg-yellow"]
|
||||
// );
|
||||
// } else {
|
||||
// panic!("expected completion menu to be open");
|
||||
// }
|
||||
// });
|
||||
// Trigger completion when typing a dash, because the dash is an extra
|
||||
// word character in the 'element' scope, which contains the cursor.
|
||||
cx.simulate_keystroke("-");
|
||||
cx.executor().run_until_parked();
|
||||
cx.update_editor(|editor, _| {
|
||||
if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() {
|
||||
assert_eq!(
|
||||
menu.matches.iter().map(|m| &m.string).collect::<Vec<_>>(),
|
||||
&["bg-red", "bg-blue", "bg-yellow"]
|
||||
);
|
||||
} else {
|
||||
panic!("expected completion menu to be open");
|
||||
}
|
||||
});
|
||||
|
||||
// cx.simulate_keystroke("l");
|
||||
// cx.executor().run_until_parked();
|
||||
// cx.update_editor(|editor, _| {
|
||||
// if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() {
|
||||
// assert_eq!(
|
||||
// menu.matches.iter().map(|m| &m.string).collect::<Vec<_>>(),
|
||||
// &["bg-blue", "bg-yellow"]
|
||||
// );
|
||||
// } else {
|
||||
// panic!("expected completion menu to be open");
|
||||
// }
|
||||
// });
|
||||
cx.simulate_keystroke("l");
|
||||
cx.executor().run_until_parked();
|
||||
cx.update_editor(|editor, _| {
|
||||
if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() {
|
||||
assert_eq!(
|
||||
menu.matches.iter().map(|m| &m.string).collect::<Vec<_>>(),
|
||||
&["bg-blue", "bg-yellow"]
|
||||
);
|
||||
} else {
|
||||
panic!("expected completion menu to be open");
|
||||
}
|
||||
});
|
||||
|
||||
// // When filtering completions, consider the character after the '-' to
|
||||
// // be the start of a subword.
|
||||
// cx.set_state(r#"<p class="yelˇ" />"#);
|
||||
// cx.simulate_keystroke("l");
|
||||
// cx.executor().run_until_parked();
|
||||
// cx.update_editor(|editor, _| {
|
||||
// if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() {
|
||||
// assert_eq!(
|
||||
// menu.matches.iter().map(|m| &m.string).collect::<Vec<_>>(),
|
||||
// &["bg-yellow"]
|
||||
// );
|
||||
// } else {
|
||||
// panic!("expected completion menu to be open");
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// When filtering completions, consider the character after the '-' to
|
||||
// be the start of a subword.
|
||||
cx.set_state(r#"<p class="yelˇ" />"#);
|
||||
cx.simulate_keystroke("l");
|
||||
cx.executor().run_until_parked();
|
||||
cx.update_editor(|editor, _| {
|
||||
if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() {
|
||||
assert_eq!(
|
||||
menu.matches.iter().map(|m| &m.string).collect::<Vec<_>>(),
|
||||
&["bg-yellow"]
|
||||
);
|
||||
} else {
|
||||
panic!("expected completion menu to be open");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) {
|
||||
|
||||
+148
-114
@@ -5,7 +5,9 @@ use crate::{
|
||||
},
|
||||
editor_settings::ShowScrollbar,
|
||||
git::{diff_hunk_to_display, DisplayDiffHunk},
|
||||
hover_popover::hover_at,
|
||||
hover_popover::{
|
||||
self, hover_at, HOVER_POPOVER_GAP, MIN_POPOVER_CHARACTER_WIDTH, MIN_POPOVER_LINE_HEIGHT,
|
||||
},
|
||||
link_go_to_definition::{
|
||||
go_to_fetched_definition, go_to_fetched_type_definition, update_go_to_definition_link,
|
||||
update_inlay_link_and_hover_points, GoToDefinitionTrigger,
|
||||
@@ -20,10 +22,11 @@ use collections::{BTreeMap, HashMap};
|
||||
use gpui::{
|
||||
div, point, px, relative, size, transparent_black, Action, AnyElement, AvailableSpace,
|
||||
BorrowWindow, Bounds, ContentMask, Corners, DispatchPhase, Edges, Element, ElementId,
|
||||
ElementInputHandler, Entity, EntityId, Hsla, InteractiveElement, IntoElement, LineLayout,
|
||||
MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, RenderOnce,
|
||||
ScrollWheelEvent, ShapedLine, SharedString, Size, StatefulInteractiveElement, Style, Styled,
|
||||
TextRun, TextStyle, View, ViewContext, WeakView, WindowContext, WrappedLine,
|
||||
ElementInputHandler, Entity, EntityId, Hsla, InteractiveBounds, InteractiveElement,
|
||||
IntoElement, LineLayout, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
|
||||
ParentElement, Pixels, RenderOnce, ScrollWheelEvent, ShapedLine, SharedString, Size,
|
||||
StackingOrder, StatefulInteractiveElement, Style, Styled, TextRun, TextStyle, View,
|
||||
ViewContext, WeakView, WindowContext, WrappedLine,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use language::language_settings::ShowWhitespaceSetting;
|
||||
@@ -45,6 +48,7 @@ use std::{
|
||||
};
|
||||
use sum_tree::Bias;
|
||||
use theme::{ActiveTheme, PlayerColor};
|
||||
use ui::prelude::*;
|
||||
use ui::{h_stack, IconButton, Tooltip};
|
||||
use util::ResultExt;
|
||||
use workspace::item::Item;
|
||||
@@ -126,6 +130,11 @@ impl EditorElement {
|
||||
|
||||
fn register_actions(&self, cx: &mut WindowContext) {
|
||||
let view = &self.editor;
|
||||
self.editor.update(cx, |editor, cx| {
|
||||
for action in editor.editor_actions.iter() {
|
||||
(action)(cx)
|
||||
}
|
||||
});
|
||||
register_action(view, cx, Editor::move_left);
|
||||
register_action(view, cx, Editor::move_right);
|
||||
register_action(view, cx, Editor::move_down);
|
||||
@@ -257,6 +266,7 @@ impl EditorElement {
|
||||
// on_action(cx, Editor::open_excerpts); todo!()
|
||||
register_action(view, cx, Editor::toggle_soft_wrap);
|
||||
register_action(view, cx, Editor::toggle_inlay_hints);
|
||||
register_action(view, cx, hover_popover::hover);
|
||||
register_action(view, cx, Editor::reveal_in_finder);
|
||||
register_action(view, cx, Editor::copy_path);
|
||||
register_action(view, cx, Editor::copy_relative_path);
|
||||
@@ -308,6 +318,7 @@ impl EditorElement {
|
||||
position_map: &PositionMap,
|
||||
text_bounds: Bounds<Pixels>,
|
||||
gutter_bounds: Bounds<Pixels>,
|
||||
stacking_order: &StackingOrder,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> bool {
|
||||
let mut click_count = event.click_count;
|
||||
@@ -318,6 +329,9 @@ impl EditorElement {
|
||||
} else if !text_bounds.contains_point(&event.position) {
|
||||
return false;
|
||||
}
|
||||
if !cx.was_top_layer(&event.position, stacking_order) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let point_for_position = position_map.point_for_position(text_bounds, event.position);
|
||||
let position = point_for_position.previous_valid;
|
||||
@@ -376,6 +390,7 @@ impl EditorElement {
|
||||
event: &MouseUpEvent,
|
||||
position_map: &PositionMap,
|
||||
text_bounds: Bounds<Pixels>,
|
||||
stacking_order: &StackingOrder,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> bool {
|
||||
let end_selection = editor.has_pending_selection();
|
||||
@@ -388,6 +403,7 @@ impl EditorElement {
|
||||
if !pending_nonempty_selections
|
||||
&& event.modifiers.command
|
||||
&& text_bounds.contains_point(&event.position)
|
||||
&& cx.was_top_layer(&event.position, stacking_order)
|
||||
{
|
||||
let point = position_map.point_for_position(text_bounds, event.position);
|
||||
let could_be_inlay = point.as_valid().is_none();
|
||||
@@ -410,6 +426,7 @@ impl EditorElement {
|
||||
position_map: &PositionMap,
|
||||
text_bounds: Bounds<Pixels>,
|
||||
gutter_bounds: Bounds<Pixels>,
|
||||
stacking_order: &StackingOrder,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> bool {
|
||||
let modifiers = event.modifiers;
|
||||
@@ -449,10 +466,12 @@ impl EditorElement {
|
||||
|
||||
let text_hovered = text_bounds.contains_point(&event.position);
|
||||
let gutter_hovered = gutter_bounds.contains_point(&event.position);
|
||||
let was_top = cx.was_top_layer(&event.position, stacking_order);
|
||||
|
||||
editor.set_gutter_hovered(gutter_hovered, cx);
|
||||
|
||||
// Don't trigger hover popover if mouse is hovering over context menu
|
||||
if text_hovered {
|
||||
if text_hovered && was_top {
|
||||
let point_for_position = position_map.point_for_position(text_bounds, event.position);
|
||||
|
||||
match point_for_position.as_valid() {
|
||||
@@ -482,7 +501,7 @@ impl EditorElement {
|
||||
} else {
|
||||
update_go_to_definition_link(editor, None, modifiers.command, modifiers.shift, cx);
|
||||
hover_at(editor, None, cx);
|
||||
gutter_hovered
|
||||
gutter_hovered && was_top
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,10 +509,10 @@ impl EditorElement {
|
||||
editor: &mut Editor,
|
||||
event: &ScrollWheelEvent,
|
||||
position_map: &PositionMap,
|
||||
bounds: Bounds<Pixels>,
|
||||
bounds: &InteractiveBounds,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> bool {
|
||||
if !bounds.contains_point(&event.position) {
|
||||
if !bounds.visibly_contains(&event.position, cx) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1024,8 +1043,8 @@ impl EditorElement {
|
||||
}
|
||||
});
|
||||
|
||||
if let Some((position, mut context_menu)) = layout.context_menu.take() {
|
||||
cx.with_z_index(1, |cx| {
|
||||
cx.with_z_index(1, |cx| {
|
||||
if let Some((position, mut context_menu)) = layout.context_menu.take() {
|
||||
let available_space =
|
||||
size(AvailableSpace::MinContent, AvailableSpace::MinContent);
|
||||
let context_menu_size = context_menu.measure(available_space, cx);
|
||||
@@ -1052,81 +1071,74 @@ impl EditorElement {
|
||||
list_origin.y -= layout.position_map.line_height + list_height;
|
||||
}
|
||||
|
||||
context_menu.draw(list_origin, available_space, cx);
|
||||
})
|
||||
}
|
||||
cx.break_content_mask(|cx| {
|
||||
context_menu.draw(list_origin, available_space, cx)
|
||||
});
|
||||
}
|
||||
|
||||
// if let Some((position, hover_popovers)) = layout.hover_popovers.as_mut() {
|
||||
// cx.scene().push_stacking_context(None, None);
|
||||
if let Some((position, mut hover_popovers)) = layout.hover_popovers.take() {
|
||||
let available_space =
|
||||
size(AvailableSpace::MinContent, AvailableSpace::MinContent);
|
||||
|
||||
// // This is safe because we check on layout whether the required row is available
|
||||
// let hovered_row_layout =
|
||||
// &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
|
||||
// This is safe because we check on layout whether the required row is available
|
||||
let hovered_row_layout = &layout.position_map.line_layouts
|
||||
[(position.row() - start_row) as usize]
|
||||
.line;
|
||||
|
||||
// // Minimum required size: Take the first popover, and add 1.5 times the minimum popover
|
||||
// // height. This is the size we will use to decide whether to render popovers above or below
|
||||
// // the hovered line.
|
||||
// let first_size = hover_popovers[0].size();
|
||||
// let height_to_reserve = first_size.y
|
||||
// + 1.5 * MIN_POPOVER_LINE_HEIGHT as f32 * layout.position_map.line_height;
|
||||
// Minimum required size: Take the first popover, and add 1.5 times the minimum popover
|
||||
// height. This is the size we will use to decide whether to render popovers above or below
|
||||
// the hovered line.
|
||||
let first_size = hover_popovers[0].measure(available_space, cx);
|
||||
let height_to_reserve = first_size.height
|
||||
+ 1.5 * MIN_POPOVER_LINE_HEIGHT * layout.position_map.line_height;
|
||||
|
||||
// // Compute Hovered Point
|
||||
// let x = hovered_row_layout.x_for_index(position.column() as usize) - scroll_left;
|
||||
// let y = position.row() as f32 * layout.position_map.line_height - scroll_top;
|
||||
// let hovered_point = content_origin + point(x, y);
|
||||
// Compute Hovered Point
|
||||
let x = hovered_row_layout.x_for_index(position.column() as usize)
|
||||
- layout.position_map.scroll_position.x;
|
||||
let y = position.row() as f32 * layout.position_map.line_height
|
||||
- layout.position_map.scroll_position.y;
|
||||
let hovered_point = content_origin + point(x, y);
|
||||
|
||||
// if hovered_point.y - height_to_reserve > 0.0 {
|
||||
// // There is enough space above. Render popovers above the hovered point
|
||||
// let mut current_y = hovered_point.y;
|
||||
// for hover_popover in hover_popovers {
|
||||
// let size = hover_popover.size();
|
||||
// let mut popover_origin = point(hovered_point.x, current_y - size.y);
|
||||
if hovered_point.y - height_to_reserve > Pixels::ZERO {
|
||||
// There is enough space above. Render popovers above the hovered point
|
||||
let mut current_y = hovered_point.y;
|
||||
for mut hover_popover in hover_popovers {
|
||||
let size = hover_popover.measure(available_space, cx);
|
||||
let mut popover_origin =
|
||||
point(hovered_point.x, current_y - size.height);
|
||||
|
||||
// let x_out_of_bounds = bounds.max_x - (popover_origin.x + size.x);
|
||||
// if x_out_of_bounds < 0.0 {
|
||||
// popover_origin.set_x(popover_origin.x + x_out_of_bounds);
|
||||
// }
|
||||
let x_out_of_bounds =
|
||||
text_bounds.upper_right().x - (popover_origin.x + size.width);
|
||||
if x_out_of_bounds < Pixels::ZERO {
|
||||
popover_origin.x = popover_origin.x + x_out_of_bounds;
|
||||
}
|
||||
|
||||
// hover_popover.paint(
|
||||
// popover_origin,
|
||||
// Bounds::<Pixels>::from_points(
|
||||
// gpui::Point::<Pixels>::zero(),
|
||||
// point(f32::MAX, f32::MAX),
|
||||
// ), // Let content bleed outside of editor
|
||||
// editor,
|
||||
// cx,
|
||||
// );
|
||||
cx.break_content_mask(|cx| {
|
||||
hover_popover.draw(popover_origin, available_space, cx)
|
||||
});
|
||||
|
||||
// current_y = popover_origin.y - HOVER_POPOVER_GAP;
|
||||
// }
|
||||
// } else {
|
||||
// // There is not enough space above. Render popovers below the hovered point
|
||||
// let mut current_y = hovered_point.y + layout.position_map.line_height;
|
||||
// for hover_popover in hover_popovers {
|
||||
// let size = hover_popover.size();
|
||||
// let mut popover_origin = point(hovered_point.x, current_y);
|
||||
current_y = popover_origin.y - HOVER_POPOVER_GAP;
|
||||
}
|
||||
} else {
|
||||
// There is not enough space above. Render popovers below the hovered point
|
||||
let mut current_y = hovered_point.y + layout.position_map.line_height;
|
||||
for mut hover_popover in hover_popovers {
|
||||
let size = hover_popover.measure(available_space, cx);
|
||||
let mut popover_origin = point(hovered_point.x, current_y);
|
||||
|
||||
// let x_out_of_bounds = bounds.max_x - (popover_origin.x + size.x);
|
||||
// if x_out_of_bounds < 0.0 {
|
||||
// popover_origin.set_x(popover_origin.x + x_out_of_bounds);
|
||||
// }
|
||||
let x_out_of_bounds =
|
||||
text_bounds.upper_right().x - (popover_origin.x + size.width);
|
||||
if x_out_of_bounds < Pixels::ZERO {
|
||||
popover_origin.x = popover_origin.x + x_out_of_bounds;
|
||||
}
|
||||
|
||||
// hover_popover.paint(
|
||||
// popover_origin,
|
||||
// Bounds::<Pixels>::from_points(
|
||||
// gpui::Point::<Pixels>::zero(),
|
||||
// point(f32::MAX, f32::MAX),
|
||||
// ), // Let content bleed outside of editor
|
||||
// editor,
|
||||
// cx,
|
||||
// );
|
||||
hover_popover.draw(popover_origin, available_space, cx);
|
||||
|
||||
// current_y = popover_origin.y + size.y + HOVER_POPOVER_GAP;
|
||||
// }
|
||||
// }
|
||||
|
||||
// cx.scene().pop_stacking_context();
|
||||
// }
|
||||
current_y = popover_origin.y + size.height + HOVER_POPOVER_GAP;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -1992,15 +2004,23 @@ impl EditorElement {
|
||||
}
|
||||
|
||||
let visible_rows = start_row..start_row + line_layouts.len() as u32;
|
||||
// todo!("hover")
|
||||
// let mut hover = editor.hover_state.render(
|
||||
// &snapshot,
|
||||
// &style,
|
||||
// visible_rows,
|
||||
// editor.workspace.as_ref().map(|(w, _)| w.clone()),
|
||||
// cx,
|
||||
// );
|
||||
// let mode = editor.mode;
|
||||
let max_size = size(
|
||||
(120. * em_width) // Default size
|
||||
.min(bounds.size.width / 2.) // Shrink to half of the editor width
|
||||
.max(MIN_POPOVER_CHARACTER_WIDTH * em_width), // Apply minimum width of 20 characters
|
||||
(16. * line_height) // Default size
|
||||
.min(bounds.size.height / 2.) // Shrink to half of the editor height
|
||||
.max(MIN_POPOVER_LINE_HEIGHT * line_height), // Apply minimum height of 4 lines
|
||||
);
|
||||
|
||||
let mut hover = editor.hover_state.render(
|
||||
&snapshot,
|
||||
&style,
|
||||
visible_rows,
|
||||
max_size,
|
||||
editor.workspace.as_ref().map(|(w, _)| w.clone()),
|
||||
cx,
|
||||
);
|
||||
|
||||
let mut fold_indicators = cx.with_element_id(Some("gutter_fold_indicators"), |cx| {
|
||||
editor.render_fold_indicators(
|
||||
@@ -2013,27 +2033,6 @@ impl EditorElement {
|
||||
)
|
||||
});
|
||||
|
||||
// todo!("hover popovers")
|
||||
// if let Some((_, hover_popovers)) = hover.as_mut() {
|
||||
// for hover_popover in hover_popovers.iter_mut() {
|
||||
// hover_popover.layout(
|
||||
// SizeConstraint {
|
||||
// min: gpui::Point::<Pixels>::zero(),
|
||||
// max: point(
|
||||
// (120. * em_width) // Default size
|
||||
// .min(size.x / 2.) // Shrink to half of the editor width
|
||||
// .max(MIN_POPOVER_CHARACTER_WIDTH * em_width), // Apply minimum width of 20 characters
|
||||
// (16. * line_height) // Default size
|
||||
// .min(size.y / 2.) // Shrink to half of the editor height
|
||||
// .max(MIN_POPOVER_LINE_HEIGHT * line_height), // Apply minimum height of 4 lines
|
||||
// ),
|
||||
// },
|
||||
// editor,
|
||||
// cx,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
let invisible_symbol_font_size = font_size / 2.;
|
||||
let tab_invisible = cx
|
||||
.text_system()
|
||||
@@ -2102,7 +2101,7 @@ impl EditorElement {
|
||||
fold_indicators,
|
||||
tab_invisible,
|
||||
space_invisible,
|
||||
// hover_popovers: hover,
|
||||
hover_popovers: hover,
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -2294,10 +2293,15 @@ impl EditorElement {
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
let content_origin = text_bounds.origin + point(layout.gutter_margin, Pixels::ZERO);
|
||||
let interactive_bounds = InteractiveBounds {
|
||||
bounds: bounds.intersect(&cx.content_mask().bounds),
|
||||
stacking_order: cx.stacking_order().clone(),
|
||||
};
|
||||
|
||||
cx.on_mouse_event({
|
||||
let position_map = layout.position_map.clone();
|
||||
let editor = self.editor.clone();
|
||||
let interactive_bounds = interactive_bounds.clone();
|
||||
|
||||
move |event: &ScrollWheelEvent, phase, cx| {
|
||||
if phase != DispatchPhase::Bubble {
|
||||
@@ -2305,7 +2309,7 @@ impl EditorElement {
|
||||
}
|
||||
|
||||
let should_cancel = editor.update(cx, |editor, cx| {
|
||||
Self::scroll(editor, event, &position_map, bounds, cx)
|
||||
Self::scroll(editor, event, &position_map, &interactive_bounds, cx)
|
||||
});
|
||||
if should_cancel {
|
||||
cx.stop_propagation();
|
||||
@@ -2316,6 +2320,7 @@ impl EditorElement {
|
||||
cx.on_mouse_event({
|
||||
let position_map = layout.position_map.clone();
|
||||
let editor = self.editor.clone();
|
||||
let stacking_order = cx.stacking_order().clone();
|
||||
|
||||
move |event: &MouseDownEvent, phase, cx| {
|
||||
if phase != DispatchPhase::Bubble {
|
||||
@@ -2323,7 +2328,15 @@ impl EditorElement {
|
||||
}
|
||||
|
||||
let should_cancel = editor.update(cx, |editor, cx| {
|
||||
Self::mouse_down(editor, event, &position_map, text_bounds, gutter_bounds, cx)
|
||||
Self::mouse_down(
|
||||
editor,
|
||||
event,
|
||||
&position_map,
|
||||
text_bounds,
|
||||
gutter_bounds,
|
||||
&stacking_order,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
if should_cancel {
|
||||
@@ -2335,9 +2348,18 @@ impl EditorElement {
|
||||
cx.on_mouse_event({
|
||||
let position_map = layout.position_map.clone();
|
||||
let editor = self.editor.clone();
|
||||
let stacking_order = cx.stacking_order().clone();
|
||||
|
||||
move |event: &MouseUpEvent, phase, cx| {
|
||||
let should_cancel = editor.update(cx, |editor, cx| {
|
||||
Self::mouse_up(editor, event, &position_map, text_bounds, cx)
|
||||
Self::mouse_up(
|
||||
editor,
|
||||
event,
|
||||
&position_map,
|
||||
text_bounds,
|
||||
&stacking_order,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
if should_cancel {
|
||||
@@ -2363,13 +2385,23 @@ impl EditorElement {
|
||||
cx.on_mouse_event({
|
||||
let position_map = layout.position_map.clone();
|
||||
let editor = self.editor.clone();
|
||||
let stacking_order = cx.stacking_order().clone();
|
||||
|
||||
move |event: &MouseMoveEvent, phase, cx| {
|
||||
if phase != DispatchPhase::Bubble {
|
||||
return;
|
||||
}
|
||||
|
||||
let stop_propogating = editor.update(cx, |editor, cx| {
|
||||
Self::mouse_moved(editor, event, &position_map, text_bounds, gutter_bounds, cx)
|
||||
Self::mouse_moved(
|
||||
editor,
|
||||
event,
|
||||
&position_map,
|
||||
text_bounds,
|
||||
gutter_bounds,
|
||||
&stacking_order,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
if stop_propogating {
|
||||
@@ -2629,9 +2661,11 @@ impl Element for EditorElement {
|
||||
// We call with_z_index to establish a new stacking context.
|
||||
cx.with_z_index(0, |cx| {
|
||||
cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
|
||||
// Paint mouse listeners first, so any elements we paint on top of the editor
|
||||
// Paint mouse listeners at z-index 0 so any elements we paint on top of the editor
|
||||
// take precedence.
|
||||
self.paint_mouse_listeners(bounds, gutter_bounds, text_bounds, &layout, cx);
|
||||
cx.with_z_index(0, |cx| {
|
||||
self.paint_mouse_listeners(bounds, gutter_bounds, text_bounds, &layout, cx);
|
||||
});
|
||||
let input_handler = ElementInputHandler::new(bounds, self.editor.clone(), cx);
|
||||
cx.handle_input(&focus_handle, input_handler);
|
||||
|
||||
@@ -3287,7 +3321,7 @@ pub struct LayoutState {
|
||||
max_row: u32,
|
||||
context_menu: Option<(DisplayPoint, AnyElement)>,
|
||||
code_actions_indicator: Option<CodeActionsIndicator>,
|
||||
// hover_popovers: Option<(DisplayPoint, Vec<AnyElement>)>,
|
||||
hover_popovers: Option<(DisplayPoint, Vec<AnyElement>)>,
|
||||
fold_indicators: Vec<Option<IconButton>>,
|
||||
tab_invisible: ShapedLine,
|
||||
space_invisible: ShapedLine,
|
||||
@@ -4085,7 +4119,7 @@ fn scale_horizontal_mouse_autoscroll_delta(delta: Pixels) -> f32 {
|
||||
// }
|
||||
// }
|
||||
|
||||
fn register_action<T: Action>(
|
||||
pub fn register_action<T: Action>(
|
||||
view: &View<Editor>,
|
||||
cx: &mut WindowContext,
|
||||
listener: impl Fn(&mut Editor, &T, &mut ViewContext<Editor>) + 'static,
|
||||
|
||||
+917
-935
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@ use crate::{
|
||||
Anchor, DisplayPoint, Editor, EditorSnapshot, GoToDefinition, GoToTypeDefinition, InlayId,
|
||||
SelectPhase,
|
||||
};
|
||||
use gpui::{Task, ViewContext};
|
||||
use gpui::{px, Task, ViewContext};
|
||||
use language::{Bias, ToOffset};
|
||||
use lsp::LanguageServerId;
|
||||
use project::{
|
||||
@@ -13,6 +13,7 @@ use project::{
|
||||
ResolveState,
|
||||
};
|
||||
use std::ops::Range;
|
||||
use theme::ActiveTheme as _;
|
||||
use util::TryFutureExt;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@@ -485,40 +486,45 @@ pub fn show_link_definition(
|
||||
});
|
||||
|
||||
if any_definition_does_not_contain_current_location {
|
||||
// todo!()
|
||||
// // Highlight symbol using theme link definition highlight style
|
||||
// let style = theme::current(cx).editor.link_definition;
|
||||
// let highlight_range =
|
||||
// symbol_range.unwrap_or_else(|| match &trigger_point {
|
||||
// TriggerPoint::Text(trigger_anchor) => {
|
||||
// let snapshot = &snapshot.buffer_snapshot;
|
||||
// // If no symbol range returned from language server, use the surrounding word.
|
||||
// let (offset_range, _) =
|
||||
// snapshot.surrounding_word(*trigger_anchor);
|
||||
// RangeInEditor::Text(
|
||||
// snapshot.anchor_before(offset_range.start)
|
||||
// ..snapshot.anchor_after(offset_range.end),
|
||||
// )
|
||||
// }
|
||||
// TriggerPoint::InlayHint(highlight, _, _) => {
|
||||
// RangeInEditor::Inlay(highlight.clone())
|
||||
// }
|
||||
// });
|
||||
let style = gpui::HighlightStyle {
|
||||
underline: Some(gpui::UnderlineStyle {
|
||||
thickness: px(1.),
|
||||
..Default::default()
|
||||
}),
|
||||
color: Some(gpui::red()),
|
||||
..Default::default()
|
||||
};
|
||||
let highlight_range =
|
||||
symbol_range.unwrap_or_else(|| match &trigger_point {
|
||||
TriggerPoint::Text(trigger_anchor) => {
|
||||
let snapshot = &snapshot.buffer_snapshot;
|
||||
// If no symbol range returned from language server, use the surrounding word.
|
||||
let (offset_range, _) =
|
||||
snapshot.surrounding_word(*trigger_anchor);
|
||||
RangeInEditor::Text(
|
||||
snapshot.anchor_before(offset_range.start)
|
||||
..snapshot.anchor_after(offset_range.end),
|
||||
)
|
||||
}
|
||||
TriggerPoint::InlayHint(highlight, _, _) => {
|
||||
RangeInEditor::Inlay(highlight.clone())
|
||||
}
|
||||
});
|
||||
|
||||
// match highlight_range {
|
||||
// RangeInEditor::Text(text_range) => this
|
||||
// .highlight_text::<LinkGoToDefinitionState>(
|
||||
// vec![text_range],
|
||||
// style,
|
||||
// cx,
|
||||
// ),
|
||||
// RangeInEditor::Inlay(highlight) => this
|
||||
// .highlight_inlays::<LinkGoToDefinitionState>(
|
||||
// vec![highlight],
|
||||
// style,
|
||||
// cx,
|
||||
// ),
|
||||
// }
|
||||
match highlight_range {
|
||||
RangeInEditor::Text(text_range) => this
|
||||
.highlight_text::<LinkGoToDefinitionState>(
|
||||
vec![text_range],
|
||||
style,
|
||||
cx,
|
||||
),
|
||||
RangeInEditor::Inlay(highlight) => this
|
||||
.highlight_inlays::<LinkGoToDefinitionState>(
|
||||
vec![highlight],
|
||||
style,
|
||||
cx,
|
||||
),
|
||||
}
|
||||
} else {
|
||||
hide_link_definition(this, cx);
|
||||
}
|
||||
|
||||
@@ -595,31 +595,32 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
self.select(selections)
|
||||
}
|
||||
|
||||
pub fn select_anchor_ranges<I: IntoIterator<Item = Range<Anchor>>>(&mut self, ranges: I) {
|
||||
todo!()
|
||||
// let buffer = self.buffer.read(self.cx).snapshot(self.cx);
|
||||
// let selections = ranges
|
||||
// .into_iter()
|
||||
// .map(|range| {
|
||||
// let mut start = range.start;
|
||||
// let mut end = range.end;
|
||||
// let reversed = if start.cmp(&end, &buffer).is_gt() {
|
||||
// mem::swap(&mut start, &mut end);
|
||||
// true
|
||||
// } else {
|
||||
// false
|
||||
// };
|
||||
// Selection {
|
||||
// id: post_inc(&mut self.collection.next_selection_id),
|
||||
// start,
|
||||
// end,
|
||||
// reversed,
|
||||
// goal: SelectionGoal::None,
|
||||
// }
|
||||
// })
|
||||
// .collect::<Vec<_>>();
|
||||
|
||||
// self.select_anchors(selections)
|
||||
pub fn select_anchor_ranges<I>(&mut self, ranges: I)
|
||||
where
|
||||
I: IntoIterator<Item = Range<Anchor>>,
|
||||
{
|
||||
let buffer = self.buffer.read(self.cx).snapshot(self.cx);
|
||||
let selections = ranges
|
||||
.into_iter()
|
||||
.map(|range| {
|
||||
let mut start = range.start;
|
||||
let mut end = range.end;
|
||||
let reversed = if start.cmp(&end, &buffer).is_gt() {
|
||||
mem::swap(&mut start, &mut end);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
Selection {
|
||||
id: post_inc(&mut self.collection.next_selection_id),
|
||||
start,
|
||||
end,
|
||||
reversed,
|
||||
goal: SelectionGoal::None,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
self.select_anchors(selections)
|
||||
}
|
||||
|
||||
pub fn new_selection_id(&mut self) -> usize {
|
||||
|
||||
@@ -27,7 +27,7 @@ pub fn marked_display_snapshot(
|
||||
let (unmarked_text, markers) = marked_text_offsets(text);
|
||||
|
||||
let font = cx.text_style().font();
|
||||
let font_size: Pixels = 14.into();
|
||||
let font_size: Pixels = 14usize.into();
|
||||
|
||||
let buffer = MultiBuffer::build_simple(&unmarked_text, cx);
|
||||
let display_map = cx.build_model(|cx| DisplayMap::new(buffer, font, font_size, None, 1, 1, cx));
|
||||
|
||||
Reference in New Issue
Block a user