Merge branch 'main' into terminal-element
This commit is contained in:
@@ -162,7 +162,7 @@ impl WrapMap {
|
||||
{
|
||||
let tab_snapshot = new_snapshot.tab_snapshot.clone();
|
||||
let range = TabPoint::zero()..tab_snapshot.max_point();
|
||||
let edits = new_snapshot
|
||||
edits = new_snapshot
|
||||
.update(
|
||||
tab_snapshot,
|
||||
&[TabEdit {
|
||||
|
||||
+246
-585
File diff suppressed because it is too large
Load Diff
+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) {
|
||||
|
||||
+294
-772
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,7 @@ use lsp::DiagnosticSeverity;
|
||||
use project::{HoverBlock, HoverBlockKind, InlayHintLabelPart, Project};
|
||||
use settings::Settings;
|
||||
use std::{ops::Range, sync::Arc, time::Duration};
|
||||
use ui::Tooltip;
|
||||
use ui::{StyledExt, Tooltip};
|
||||
use util::TryFutureExt;
|
||||
use workspace::Workspace;
|
||||
|
||||
@@ -476,8 +476,10 @@ impl InfoPopover {
|
||||
) -> AnyElement {
|
||||
div()
|
||||
.id("info_popover")
|
||||
.elevation_2(cx)
|
||||
.text_ui()
|
||||
.p_2()
|
||||
.overflow_y_scroll()
|
||||
.bg(gpui::red())
|
||||
.max_w(max_size.width)
|
||||
.max_h(max_size.height)
|
||||
// Prevent a mouse move on the popover from being propagated to the editor,
|
||||
|
||||
+353
-363
@@ -4,13 +4,14 @@ use crate::{
|
||||
EditorEvent, EditorSettings, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot,
|
||||
NavigationData, ToPoint as _,
|
||||
};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use collections::HashSet;
|
||||
use futures::future::try_join_all;
|
||||
use gpui::{
|
||||
div, point, AnyElement, AppContext, AsyncAppContext, Entity, EntityId, EventEmitter,
|
||||
FocusHandle, Model, ParentElement, Pixels, SharedString, Styled, Subscription, Task, View,
|
||||
ViewContext, VisualContext, WeakView, WindowContext,
|
||||
div, point, AnyElement, AppContext, AsyncAppContext, AsyncWindowContext, Context, Div, Entity,
|
||||
EntityId, EventEmitter, FocusHandle, IntoElement, Model, ParentElement, Pixels, Render,
|
||||
SharedString, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView,
|
||||
WindowContext,
|
||||
};
|
||||
use language::{
|
||||
proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, CharKind, OffsetRangeExt,
|
||||
@@ -20,6 +21,7 @@ use project::{search::SearchQuery, FormatTrigger, Item as _, Project, ProjectPat
|
||||
use rpc::proto::{self, update_view, PeerId};
|
||||
use settings::Settings;
|
||||
use smallvec::SmallVec;
|
||||
use std::fmt::Write;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
cmp::{self, Ordering},
|
||||
@@ -31,8 +33,11 @@ use std::{
|
||||
use text::Selection;
|
||||
use theme::{ActiveTheme, Theme};
|
||||
use ui::{Color, Label};
|
||||
use util::{paths::PathExt, ResultExt, TryFutureExt};
|
||||
use workspace::item::{BreadcrumbText, FollowEvent, FollowableEvents, FollowableItemHandle};
|
||||
use util::{paths::PathExt, paths::FILE_ROW_COLUMN_DELIMITER, ResultExt, TryFutureExt};
|
||||
use workspace::{
|
||||
item::{BreadcrumbText, FollowEvent, FollowableEvents, FollowableItemHandle},
|
||||
StatusItemView,
|
||||
};
|
||||
use workspace::{
|
||||
item::{FollowableItem, Item, ItemEvent, ItemHandle, ProjectItem},
|
||||
searchable::{Direction, SearchEvent, SearchableItem, SearchableItemHandle},
|
||||
@@ -71,110 +76,108 @@ impl FollowableItem for Editor {
|
||||
workspace: View<Workspace>,
|
||||
remote_id: ViewId,
|
||||
state: &mut Option<proto::view::Variant>,
|
||||
cx: &mut AppContext,
|
||||
cx: &mut WindowContext,
|
||||
) -> Option<Task<Result<View<Self>>>> {
|
||||
todo!()
|
||||
let project = workspace.read(cx).project().to_owned();
|
||||
let Some(proto::view::Variant::Editor(_)) = state else {
|
||||
return None;
|
||||
};
|
||||
let Some(proto::view::Variant::Editor(state)) = state.take() else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let client = project.read(cx).client();
|
||||
let replica_id = project.read(cx).replica_id();
|
||||
let buffer_ids = state
|
||||
.excerpts
|
||||
.iter()
|
||||
.map(|excerpt| excerpt.buffer_id)
|
||||
.collect::<HashSet<_>>();
|
||||
let buffers = project.update(cx, |project, cx| {
|
||||
buffer_ids
|
||||
.iter()
|
||||
.map(|id| project.open_buffer_by_id(*id, cx))
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
|
||||
let pane = pane.downgrade();
|
||||
Some(cx.spawn(|mut cx| async move {
|
||||
let mut buffers = futures::future::try_join_all(buffers).await?;
|
||||
let editor = pane.update(&mut cx, |pane, cx| {
|
||||
let mut editors = pane.items_of_type::<Self>();
|
||||
editors.find(|editor| {
|
||||
let ids_match = editor.remote_id(&client, cx) == Some(remote_id);
|
||||
let singleton_buffer_matches = state.singleton
|
||||
&& buffers.first()
|
||||
== editor.read(cx).buffer.read(cx).as_singleton().as_ref();
|
||||
ids_match || singleton_buffer_matches
|
||||
})
|
||||
})?;
|
||||
|
||||
let editor = if let Some(editor) = editor {
|
||||
editor
|
||||
} else {
|
||||
pane.update(&mut cx, |_, cx| {
|
||||
let multibuffer = cx.build_model(|cx| {
|
||||
let mut multibuffer;
|
||||
if state.singleton && buffers.len() == 1 {
|
||||
multibuffer = MultiBuffer::singleton(buffers.pop().unwrap(), cx)
|
||||
} else {
|
||||
multibuffer = MultiBuffer::new(replica_id);
|
||||
let mut excerpts = state.excerpts.into_iter().peekable();
|
||||
while let Some(excerpt) = excerpts.peek() {
|
||||
let buffer_id = excerpt.buffer_id;
|
||||
let buffer_excerpts = iter::from_fn(|| {
|
||||
let excerpt = excerpts.peek()?;
|
||||
(excerpt.buffer_id == buffer_id)
|
||||
.then(|| excerpts.next().unwrap())
|
||||
});
|
||||
let buffer =
|
||||
buffers.iter().find(|b| b.read(cx).remote_id() == buffer_id);
|
||||
if let Some(buffer) = buffer {
|
||||
multibuffer.push_excerpts(
|
||||
buffer.clone(),
|
||||
buffer_excerpts.filter_map(deserialize_excerpt_range),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(title) = &state.title {
|
||||
multibuffer = multibuffer.with_title(title.clone())
|
||||
}
|
||||
|
||||
multibuffer
|
||||
});
|
||||
|
||||
cx.build_view(|cx| {
|
||||
let mut editor =
|
||||
Editor::for_multibuffer(multibuffer, Some(project.clone()), cx);
|
||||
editor.remote_id = Some(remote_id);
|
||||
editor
|
||||
})
|
||||
})?
|
||||
};
|
||||
|
||||
update_editor_from_message(
|
||||
editor.downgrade(),
|
||||
project,
|
||||
proto::update_view::Editor {
|
||||
selections: state.selections,
|
||||
pending_selection: state.pending_selection,
|
||||
scroll_top_anchor: state.scroll_top_anchor,
|
||||
scroll_x: state.scroll_x,
|
||||
scroll_y: state.scroll_y,
|
||||
..Default::default()
|
||||
},
|
||||
&mut cx,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(editor)
|
||||
}))
|
||||
}
|
||||
// let project = workspace.read(cx).project().to_owned();
|
||||
// let Some(proto::view::Variant::Editor(_)) = state else {
|
||||
// return None;
|
||||
// };
|
||||
// let Some(proto::view::Variant::Editor(state)) = state.take() else {
|
||||
// unreachable!()
|
||||
// };
|
||||
|
||||
// let client = project.read(cx).client();
|
||||
// let replica_id = project.read(cx).replica_id();
|
||||
// let buffer_ids = state
|
||||
// .excerpts
|
||||
// .iter()
|
||||
// .map(|excerpt| excerpt.buffer_id)
|
||||
// .collect::<HashSet<_>>();
|
||||
// let buffers = project.update(cx, |project, cx| {
|
||||
// buffer_ids
|
||||
// .iter()
|
||||
// .map(|id| project.open_buffer_by_id(*id, cx))
|
||||
// .collect::<Vec<_>>()
|
||||
// });
|
||||
|
||||
// let pane = pane.downgrade();
|
||||
// Some(cx.spawn(|mut cx| async move {
|
||||
// let mut buffers = futures::future::try_join_all(buffers).await?;
|
||||
// let editor = pane.read_with(&cx, |pane, cx| {
|
||||
// let mut editors = pane.items_of_type::<Self>();
|
||||
// editors.find(|editor| {
|
||||
// let ids_match = editor.remote_id(&client, cx) == Some(remote_id);
|
||||
// let singleton_buffer_matches = state.singleton
|
||||
// && buffers.first()
|
||||
// == editor.read(cx).buffer.read(cx).as_singleton().as_ref();
|
||||
// ids_match || singleton_buffer_matches
|
||||
// })
|
||||
// })?;
|
||||
|
||||
// let editor = if let Some(editor) = editor {
|
||||
// editor
|
||||
// } else {
|
||||
// pane.update(&mut cx, |_, cx| {
|
||||
// let multibuffer = cx.add_model(|cx| {
|
||||
// let mut multibuffer;
|
||||
// if state.singleton && buffers.len() == 1 {
|
||||
// multibuffer = MultiBuffer::singleton(buffers.pop().unwrap(), cx)
|
||||
// } else {
|
||||
// multibuffer = MultiBuffer::new(replica_id);
|
||||
// let mut excerpts = state.excerpts.into_iter().peekable();
|
||||
// while let Some(excerpt) = excerpts.peek() {
|
||||
// let buffer_id = excerpt.buffer_id;
|
||||
// let buffer_excerpts = iter::from_fn(|| {
|
||||
// let excerpt = excerpts.peek()?;
|
||||
// (excerpt.buffer_id == buffer_id)
|
||||
// .then(|| excerpts.next().unwrap())
|
||||
// });
|
||||
// let buffer =
|
||||
// buffers.iter().find(|b| b.read(cx).remote_id() == buffer_id);
|
||||
// if let Some(buffer) = buffer {
|
||||
// multibuffer.push_excerpts(
|
||||
// buffer.clone(),
|
||||
// buffer_excerpts.filter_map(deserialize_excerpt_range),
|
||||
// cx,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
// if let Some(title) = &state.title {
|
||||
// multibuffer = multibuffer.with_title(title.clone())
|
||||
// }
|
||||
|
||||
// multibuffer
|
||||
// });
|
||||
|
||||
// cx.add_view(|cx| {
|
||||
// let mut editor =
|
||||
// Editor::for_multibuffer(multibuffer, Some(project.clone()), cx);
|
||||
// editor.remote_id = Some(remote_id);
|
||||
// editor
|
||||
// })
|
||||
// })?
|
||||
// };
|
||||
|
||||
// update_editor_from_message(
|
||||
// editor.downgrade(),
|
||||
// project,
|
||||
// proto::update_view::Editor {
|
||||
// selections: state.selections,
|
||||
// pending_selection: state.pending_selection,
|
||||
// scroll_top_anchor: state.scroll_top_anchor,
|
||||
// scroll_x: state.scroll_x,
|
||||
// scroll_y: state.scroll_y,
|
||||
// ..Default::default()
|
||||
// },
|
||||
// &mut cx,
|
||||
// )
|
||||
// .await?;
|
||||
|
||||
// Ok(editor)
|
||||
// }))
|
||||
// }
|
||||
|
||||
fn set_leader_peer_id(&mut self, leader_peer_id: Option<PeerId>, cx: &mut ViewContext<Self>) {
|
||||
self.leader_peer_id = leader_peer_id;
|
||||
@@ -195,7 +198,7 @@ impl FollowableItem for Editor {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn to_state_proto(&self, cx: &AppContext) -> Option<proto::view::Variant> {
|
||||
fn to_state_proto(&self, cx: &WindowContext) -> Option<proto::view::Variant> {
|
||||
let buffer = self.buffer.read(cx);
|
||||
let scroll_anchor = self.scroll_manager.anchor();
|
||||
let excerpts = buffer
|
||||
@@ -242,7 +245,7 @@ impl FollowableItem for Editor {
|
||||
&self,
|
||||
event: &Self::FollowableEvent,
|
||||
update: &mut Option<proto::update_view::Variant>,
|
||||
cx: &AppContext,
|
||||
cx: &WindowContext,
|
||||
) -> bool {
|
||||
let update =
|
||||
update.get_or_insert_with(|| proto::update_view::Variant::Editor(Default::default()));
|
||||
@@ -315,7 +318,7 @@ impl FollowableItem for Editor {
|
||||
})
|
||||
}
|
||||
|
||||
fn is_project_item(&self, _cx: &AppContext) -> bool {
|
||||
fn is_project_item(&self, _cx: &WindowContext) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -324,132 +327,129 @@ async fn update_editor_from_message(
|
||||
this: WeakView<Editor>,
|
||||
project: Model<Project>,
|
||||
message: proto::update_view::Editor,
|
||||
cx: &mut AsyncAppContext,
|
||||
cx: &mut AsyncWindowContext,
|
||||
) -> Result<()> {
|
||||
todo!()
|
||||
// Open all of the buffers of which excerpts were added to the editor.
|
||||
let inserted_excerpt_buffer_ids = message
|
||||
.inserted_excerpts
|
||||
.iter()
|
||||
.filter_map(|insertion| Some(insertion.excerpt.as_ref()?.buffer_id))
|
||||
.collect::<HashSet<_>>();
|
||||
let inserted_excerpt_buffers = project.update(cx, |project, cx| {
|
||||
inserted_excerpt_buffer_ids
|
||||
.into_iter()
|
||||
.map(|id| project.open_buffer_by_id(id, cx))
|
||||
.collect::<Vec<_>>()
|
||||
})?;
|
||||
let _inserted_excerpt_buffers = try_join_all(inserted_excerpt_buffers).await?;
|
||||
|
||||
// Update the editor's excerpts.
|
||||
this.update(cx, |editor, cx| {
|
||||
editor.buffer.update(cx, |multibuffer, cx| {
|
||||
let mut removed_excerpt_ids = message
|
||||
.deleted_excerpts
|
||||
.into_iter()
|
||||
.map(ExcerptId::from_proto)
|
||||
.collect::<Vec<_>>();
|
||||
removed_excerpt_ids.sort_by({
|
||||
let multibuffer = multibuffer.read(cx);
|
||||
move |a, b| a.cmp(&b, &multibuffer)
|
||||
});
|
||||
|
||||
let mut insertions = message.inserted_excerpts.into_iter().peekable();
|
||||
while let Some(insertion) = insertions.next() {
|
||||
let Some(excerpt) = insertion.excerpt else {
|
||||
continue;
|
||||
};
|
||||
let Some(previous_excerpt_id) = insertion.previous_excerpt_id else {
|
||||
continue;
|
||||
};
|
||||
let buffer_id = excerpt.buffer_id;
|
||||
let Some(buffer) = project.read(cx).buffer_for_id(buffer_id) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let adjacent_excerpts = iter::from_fn(|| {
|
||||
let insertion = insertions.peek()?;
|
||||
if insertion.previous_excerpt_id.is_none()
|
||||
&& insertion.excerpt.as_ref()?.buffer_id == buffer_id
|
||||
{
|
||||
insertions.next()?.excerpt
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
multibuffer.insert_excerpts_with_ids_after(
|
||||
ExcerptId::from_proto(previous_excerpt_id),
|
||||
buffer,
|
||||
[excerpt]
|
||||
.into_iter()
|
||||
.chain(adjacent_excerpts)
|
||||
.filter_map(|excerpt| {
|
||||
Some((
|
||||
ExcerptId::from_proto(excerpt.id),
|
||||
deserialize_excerpt_range(excerpt)?,
|
||||
))
|
||||
}),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
|
||||
multibuffer.remove_excerpts(removed_excerpt_ids, cx);
|
||||
});
|
||||
})?;
|
||||
|
||||
// Deserialize the editor state.
|
||||
let (selections, pending_selection, scroll_top_anchor) = this.update(cx, |editor, cx| {
|
||||
let buffer = editor.buffer.read(cx).read(cx);
|
||||
let selections = message
|
||||
.selections
|
||||
.into_iter()
|
||||
.filter_map(|selection| deserialize_selection(&buffer, selection))
|
||||
.collect::<Vec<_>>();
|
||||
let pending_selection = message
|
||||
.pending_selection
|
||||
.and_then(|selection| deserialize_selection(&buffer, selection));
|
||||
let scroll_top_anchor = message
|
||||
.scroll_top_anchor
|
||||
.and_then(|anchor| deserialize_anchor(&buffer, anchor));
|
||||
anyhow::Ok((selections, pending_selection, scroll_top_anchor))
|
||||
})??;
|
||||
|
||||
// Wait until the buffer has received all of the operations referenced by
|
||||
// the editor's new state.
|
||||
this.update(cx, |editor, cx| {
|
||||
editor.buffer.update(cx, |buffer, cx| {
|
||||
buffer.wait_for_anchors(
|
||||
selections
|
||||
.iter()
|
||||
.chain(pending_selection.as_ref())
|
||||
.flat_map(|selection| [selection.start, selection.end])
|
||||
.chain(scroll_top_anchor),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
})?
|
||||
.await?;
|
||||
|
||||
// Update the editor's state.
|
||||
this.update(cx, |editor, cx| {
|
||||
if !selections.is_empty() || pending_selection.is_some() {
|
||||
editor.set_selections_from_remote(selections, pending_selection, cx);
|
||||
editor.request_autoscroll_remotely(Autoscroll::newest(), cx);
|
||||
} else if let Some(scroll_top_anchor) = scroll_top_anchor {
|
||||
editor.set_scroll_anchor_remote(
|
||||
ScrollAnchor {
|
||||
anchor: scroll_top_anchor,
|
||||
offset: point(message.scroll_x, message.scroll_y),
|
||||
},
|
||||
cx,
|
||||
);
|
||||
}
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
// Previous implementation of the above
|
||||
// // Open all of the buffers of which excerpts were added to the editor.
|
||||
// let inserted_excerpt_buffer_ids = message
|
||||
// .inserted_excerpts
|
||||
// .iter()
|
||||
// .filter_map(|insertion| Some(insertion.excerpt.as_ref()?.buffer_id))
|
||||
// .collect::<HashSet<_>>();
|
||||
// let inserted_excerpt_buffers = project.update(cx, |project, cx| {
|
||||
// inserted_excerpt_buffer_ids
|
||||
// .into_iter()
|
||||
// .map(|id| project.open_buffer_by_id(id, cx))
|
||||
// .collect::<Vec<_>>()
|
||||
// })?;
|
||||
// let _inserted_excerpt_buffers = try_join_all(inserted_excerpt_buffers).await?;
|
||||
|
||||
// // Update the editor's excerpts.
|
||||
// this.update(cx, |editor, cx| {
|
||||
// editor.buffer.update(cx, |multibuffer, cx| {
|
||||
// let mut removed_excerpt_ids = message
|
||||
// .deleted_excerpts
|
||||
// .into_iter()
|
||||
// .map(ExcerptId::from_proto)
|
||||
// .collect::<Vec<_>>();
|
||||
// removed_excerpt_ids.sort_by({
|
||||
// let multibuffer = multibuffer.read(cx);
|
||||
// move |a, b| a.cmp(&b, &multibuffer)
|
||||
// });
|
||||
|
||||
// let mut insertions = message.inserted_excerpts.into_iter().peekable();
|
||||
// while let Some(insertion) = insertions.next() {
|
||||
// let Some(excerpt) = insertion.excerpt else {
|
||||
// continue;
|
||||
// };
|
||||
// let Some(previous_excerpt_id) = insertion.previous_excerpt_id else {
|
||||
// continue;
|
||||
// };
|
||||
// let buffer_id = excerpt.buffer_id;
|
||||
// let Some(buffer) = project.read(cx).buffer_for_id(buffer_id) else {
|
||||
// continue;
|
||||
// };
|
||||
|
||||
// let adjacent_excerpts = iter::from_fn(|| {
|
||||
// let insertion = insertions.peek()?;
|
||||
// if insertion.previous_excerpt_id.is_none()
|
||||
// && insertion.excerpt.as_ref()?.buffer_id == buffer_id
|
||||
// {
|
||||
// insertions.next()?.excerpt
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
// });
|
||||
|
||||
// multibuffer.insert_excerpts_with_ids_after(
|
||||
// ExcerptId::from_proto(previous_excerpt_id),
|
||||
// buffer,
|
||||
// [excerpt]
|
||||
// .into_iter()
|
||||
// .chain(adjacent_excerpts)
|
||||
// .filter_map(|excerpt| {
|
||||
// Some((
|
||||
// ExcerptId::from_proto(excerpt.id),
|
||||
// deserialize_excerpt_range(excerpt)?,
|
||||
// ))
|
||||
// }),
|
||||
// cx,
|
||||
// );
|
||||
// }
|
||||
|
||||
// multibuffer.remove_excerpts(removed_excerpt_ids, cx);
|
||||
// });
|
||||
// })?;
|
||||
|
||||
// // Deserialize the editor state.
|
||||
// let (selections, pending_selection, scroll_top_anchor) = this.update(cx, |editor, cx| {
|
||||
// let buffer = editor.buffer.read(cx).read(cx);
|
||||
// let selections = message
|
||||
// .selections
|
||||
// .into_iter()
|
||||
// .filter_map(|selection| deserialize_selection(&buffer, selection))
|
||||
// .collect::<Vec<_>>();
|
||||
// let pending_selection = message
|
||||
// .pending_selection
|
||||
// .and_then(|selection| deserialize_selection(&buffer, selection));
|
||||
// let scroll_top_anchor = message
|
||||
// .scroll_top_anchor
|
||||
// .and_then(|anchor| deserialize_anchor(&buffer, anchor));
|
||||
// anyhow::Ok((selections, pending_selection, scroll_top_anchor))
|
||||
// })??;
|
||||
|
||||
// // Wait until the buffer has received all of the operations referenced by
|
||||
// // the editor's new state.
|
||||
// this.update(cx, |editor, cx| {
|
||||
// editor.buffer.update(cx, |buffer, cx| {
|
||||
// buffer.wait_for_anchors(
|
||||
// selections
|
||||
// .iter()
|
||||
// .chain(pending_selection.as_ref())
|
||||
// .flat_map(|selection| [selection.start, selection.end])
|
||||
// .chain(scroll_top_anchor),
|
||||
// cx,
|
||||
// )
|
||||
// })
|
||||
// })?
|
||||
// .await?;
|
||||
|
||||
// // Update the editor's state.
|
||||
// this.update(cx, |editor, cx| {
|
||||
// if !selections.is_empty() || pending_selection.is_some() {
|
||||
// editor.set_selections_from_remote(selections, pending_selection, cx);
|
||||
// editor.request_autoscroll_remotely(Autoscroll::newest(), cx);
|
||||
// } else if let Some(scroll_top_anchor) = scroll_top_anchor {
|
||||
// editor.set_scroll_anchor_remote(
|
||||
// ScrollAnchor {
|
||||
// anchor: scroll_top_anchor,
|
||||
// offset: point(message.scroll_x, message.scroll_y),
|
||||
// },
|
||||
// cx,
|
||||
// );
|
||||
// }
|
||||
// })?;
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
fn serialize_excerpt(
|
||||
buffer_id: u64,
|
||||
@@ -529,39 +529,38 @@ fn deserialize_anchor(buffer: &MultiBufferSnapshot, anchor: proto::EditorAnchor)
|
||||
|
||||
impl Item for Editor {
|
||||
fn navigate(&mut self, data: Box<dyn std::any::Any>, cx: &mut ViewContext<Self>) -> bool {
|
||||
todo!();
|
||||
// if let Ok(data) = data.downcast::<NavigationData>() {
|
||||
// let newest_selection = self.selections.newest::<Point>(cx);
|
||||
// let buffer = self.buffer.read(cx).read(cx);
|
||||
// let offset = if buffer.can_resolve(&data.cursor_anchor) {
|
||||
// data.cursor_anchor.to_point(&buffer)
|
||||
// } else {
|
||||
// buffer.clip_point(data.cursor_position, Bias::Left)
|
||||
// };
|
||||
if let Ok(data) = data.downcast::<NavigationData>() {
|
||||
let newest_selection = self.selections.newest::<Point>(cx);
|
||||
let buffer = self.buffer.read(cx).read(cx);
|
||||
let offset = if buffer.can_resolve(&data.cursor_anchor) {
|
||||
data.cursor_anchor.to_point(&buffer)
|
||||
} else {
|
||||
buffer.clip_point(data.cursor_position, Bias::Left)
|
||||
};
|
||||
|
||||
// let mut scroll_anchor = data.scroll_anchor;
|
||||
// if !buffer.can_resolve(&scroll_anchor.anchor) {
|
||||
// scroll_anchor.anchor = buffer.anchor_before(
|
||||
// buffer.clip_point(Point::new(data.scroll_top_row, 0), Bias::Left),
|
||||
// );
|
||||
// }
|
||||
let mut scroll_anchor = data.scroll_anchor;
|
||||
if !buffer.can_resolve(&scroll_anchor.anchor) {
|
||||
scroll_anchor.anchor = buffer.anchor_before(
|
||||
buffer.clip_point(Point::new(data.scroll_top_row, 0), Bias::Left),
|
||||
);
|
||||
}
|
||||
|
||||
// drop(buffer);
|
||||
drop(buffer);
|
||||
|
||||
// if newest_selection.head() == offset {
|
||||
// false
|
||||
// } else {
|
||||
// let nav_history = self.nav_history.take();
|
||||
// self.set_scroll_anchor(scroll_anchor, cx);
|
||||
// self.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||
// s.select_ranges([offset..offset])
|
||||
// });
|
||||
// self.nav_history = nav_history;
|
||||
// true
|
||||
// }
|
||||
// } else {
|
||||
// false
|
||||
// }
|
||||
if newest_selection.head() == offset {
|
||||
false
|
||||
} else {
|
||||
let nav_history = self.nav_history.take();
|
||||
self.set_scroll_anchor(scroll_anchor, cx);
|
||||
self.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||
s.select_ranges([offset..offset])
|
||||
});
|
||||
self.nav_history = nav_history;
|
||||
true
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn tab_tooltip_text(&self, cx: &AppContext) -> Option<SharedString> {
|
||||
@@ -765,35 +764,34 @@ impl Item for Editor {
|
||||
}
|
||||
|
||||
fn breadcrumbs(&self, variant: &Theme, cx: &AppContext) -> Option<Vec<BreadcrumbText>> {
|
||||
todo!();
|
||||
// let cursor = self.selections.newest_anchor().head();
|
||||
// let multibuffer = &self.buffer().read(cx);
|
||||
// let (buffer_id, symbols) =
|
||||
// multibuffer.symbols_containing(cursor, Some(&theme.editor.syntax), cx)?;
|
||||
// let buffer = multibuffer.buffer(buffer_id)?;
|
||||
let cursor = self.selections.newest_anchor().head();
|
||||
let multibuffer = &self.buffer().read(cx);
|
||||
let (buffer_id, symbols) =
|
||||
multibuffer.symbols_containing(cursor, Some(&variant.syntax()), cx)?;
|
||||
let buffer = multibuffer.buffer(buffer_id)?;
|
||||
|
||||
// let buffer = buffer.read(cx);
|
||||
// let filename = buffer
|
||||
// .snapshot()
|
||||
// .resolve_file_path(
|
||||
// cx,
|
||||
// self.project
|
||||
// .as_ref()
|
||||
// .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
|
||||
// .unwrap_or_default(),
|
||||
// )
|
||||
// .map(|path| path.to_string_lossy().to_string())
|
||||
// .unwrap_or_else(|| "untitled".to_string());
|
||||
let buffer = buffer.read(cx);
|
||||
let filename = buffer
|
||||
.snapshot()
|
||||
.resolve_file_path(
|
||||
cx,
|
||||
self.project
|
||||
.as_ref()
|
||||
.map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.map(|path| path.to_string_lossy().to_string())
|
||||
.unwrap_or_else(|| "untitled".to_string());
|
||||
|
||||
// let mut breadcrumbs = vec![BreadcrumbText {
|
||||
// text: filename,
|
||||
// highlights: None,
|
||||
// }];
|
||||
// breadcrumbs.extend(symbols.into_iter().map(|symbol| BreadcrumbText {
|
||||
// text: symbol.text,
|
||||
// highlights: Some(symbol.highlight_ranges),
|
||||
// }));
|
||||
// Some(breadcrumbs)
|
||||
let mut breadcrumbs = vec![BreadcrumbText {
|
||||
text: filename,
|
||||
highlights: None,
|
||||
}];
|
||||
breadcrumbs.extend(symbols.into_iter().map(|symbol| BreadcrumbText {
|
||||
text: symbol.text,
|
||||
highlights: Some(symbol.highlight_ranges),
|
||||
}));
|
||||
Some(breadcrumbs)
|
||||
}
|
||||
|
||||
fn added_to_workspace(&mut self, workspace: &mut Workspace, cx: &mut ViewContext<Self>) {
|
||||
@@ -1120,86 +1118,78 @@ pub struct CursorPosition {
|
||||
_observe_active_editor: Option<Subscription>,
|
||||
}
|
||||
|
||||
// impl Default for CursorPosition {
|
||||
// fn default() -> Self {
|
||||
// Self::new()
|
||||
// }
|
||||
// }
|
||||
impl Default for CursorPosition {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
// impl CursorPosition {
|
||||
// pub fn new() -> Self {
|
||||
// Self {
|
||||
// position: None,
|
||||
// selected_count: 0,
|
||||
// _observe_active_editor: None,
|
||||
// }
|
||||
// }
|
||||
impl CursorPosition {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
position: None,
|
||||
selected_count: 0,
|
||||
_observe_active_editor: None,
|
||||
}
|
||||
}
|
||||
|
||||
// fn update_position(&mut self, editor: View<Editor>, cx: &mut ViewContext<Self>) {
|
||||
// let editor = editor.read(cx);
|
||||
// let buffer = editor.buffer().read(cx).snapshot(cx);
|
||||
fn update_position(&mut self, editor: View<Editor>, cx: &mut ViewContext<Self>) {
|
||||
let editor = editor.read(cx);
|
||||
let buffer = editor.buffer().read(cx).snapshot(cx);
|
||||
|
||||
// self.selected_count = 0;
|
||||
// let mut last_selection: Option<Selection<usize>> = None;
|
||||
// for selection in editor.selections.all::<usize>(cx) {
|
||||
// self.selected_count += selection.end - selection.start;
|
||||
// if last_selection
|
||||
// .as_ref()
|
||||
// .map_or(true, |last_selection| selection.id > last_selection.id)
|
||||
// {
|
||||
// last_selection = Some(selection);
|
||||
// }
|
||||
// }
|
||||
// self.position = last_selection.map(|s| s.head().to_point(&buffer));
|
||||
self.selected_count = 0;
|
||||
let mut last_selection: Option<Selection<usize>> = None;
|
||||
for selection in editor.selections.all::<usize>(cx) {
|
||||
self.selected_count += selection.end - selection.start;
|
||||
if last_selection
|
||||
.as_ref()
|
||||
.map_or(true, |last_selection| selection.id > last_selection.id)
|
||||
{
|
||||
last_selection = Some(selection);
|
||||
}
|
||||
}
|
||||
self.position = last_selection.map(|s| s.head().to_point(&buffer));
|
||||
|
||||
// cx.notify();
|
||||
// }
|
||||
// }
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
// impl Entity for CursorPosition {
|
||||
// type Event = ();
|
||||
// }
|
||||
impl Render for CursorPosition {
|
||||
type Element = Div;
|
||||
|
||||
// impl View for CursorPosition {
|
||||
// fn ui_name() -> &'static str {
|
||||
// "CursorPosition"
|
||||
// }
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
div().when_some(self.position, |el, position| {
|
||||
let mut text = format!(
|
||||
"{}{FILE_ROW_COLUMN_DELIMITER}{}",
|
||||
position.row + 1,
|
||||
position.column + 1
|
||||
);
|
||||
if self.selected_count > 0 {
|
||||
write!(text, " ({} selected)", self.selected_count).unwrap();
|
||||
}
|
||||
|
||||
// fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
|
||||
// if let Some(position) = self.position {
|
||||
// let theme = &theme::current(cx).workspace.status_bar;
|
||||
// let mut text = format!(
|
||||
// "{}{FILE_ROW_COLUMN_DELIMITER}{}",
|
||||
// position.row + 1,
|
||||
// position.column + 1
|
||||
// );
|
||||
// if self.selected_count > 0 {
|
||||
// write!(text, " ({} selected)", self.selected_count).unwrap();
|
||||
// }
|
||||
// Label::new(text, theme.cursor_position.clone()).into_any()
|
||||
// } else {
|
||||
// Empty::new().into_any()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
el.child(Label::new(text))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// impl StatusItemView for CursorPosition {
|
||||
// fn set_active_pane_item(
|
||||
// &mut self,
|
||||
// active_pane_item: Option<&dyn ItemHandle>,
|
||||
// cx: &mut ViewContext<Self>,
|
||||
// ) {
|
||||
// if let Some(editor) = active_pane_item.and_then(|item| item.act_as::<Editor>(cx)) {
|
||||
// self._observe_active_editor = Some(cx.observe(&editor, Self::update_position));
|
||||
// self.update_position(editor, cx);
|
||||
// } else {
|
||||
// self.position = None;
|
||||
// self._observe_active_editor = None;
|
||||
// }
|
||||
impl StatusItemView for CursorPosition {
|
||||
fn set_active_pane_item(
|
||||
&mut self,
|
||||
active_pane_item: Option<&dyn ItemHandle>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
if let Some(editor) = active_pane_item.and_then(|item| item.act_as::<Editor>(cx)) {
|
||||
self._observe_active_editor = Some(cx.observe(&editor, Self::update_position));
|
||||
self.update_position(editor, cx);
|
||||
} else {
|
||||
self.position = None;
|
||||
self._observe_active_editor = None;
|
||||
}
|
||||
|
||||
// cx.notify();
|
||||
// }
|
||||
// }
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
fn path_for_buffer<'a>(
|
||||
buffer: &Model<MultiBuffer>,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
use crate::{DisplayPoint, Editor, EditorMode, SelectMode};
|
||||
use gpui::{Pixels, Point, ViewContext};
|
||||
use crate::{
|
||||
DisplayPoint, Editor, EditorMode, FindAllReferences, GoToDefinition, GoToTypeDefinition,
|
||||
Rename, RevealInFinder, SelectMode, ToggleCodeActions,
|
||||
};
|
||||
use gpui::{DismissEvent, Pixels, Point, Subscription, View, ViewContext};
|
||||
|
||||
pub struct MouseContextMenu {
|
||||
pub(crate) position: Point<Pixels>,
|
||||
pub(crate) context_menu: View<ui::ContextMenu>,
|
||||
_subscription: Subscription,
|
||||
}
|
||||
|
||||
pub fn deploy_context_menu(
|
||||
editor: &mut Editor,
|
||||
@@ -7,50 +16,57 @@ pub fn deploy_context_menu(
|
||||
point: DisplayPoint,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) {
|
||||
todo!();
|
||||
if !editor.is_focused(cx) {
|
||||
editor.focus(cx);
|
||||
}
|
||||
|
||||
// if !editor.focused {
|
||||
// cx.focus_self();
|
||||
// }
|
||||
// Don't show context menu for inline editors
|
||||
if editor.mode() != EditorMode::Full {
|
||||
return;
|
||||
}
|
||||
|
||||
// // Don't show context menu for inline editors
|
||||
// if editor.mode() != EditorMode::Full {
|
||||
// return;
|
||||
// }
|
||||
// Don't show the context menu if there isn't a project associated with this editor
|
||||
if editor.project.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
// // Don't show the context menu if there isn't a project associated with this editor
|
||||
// if editor.project.is_none() {
|
||||
// return;
|
||||
// }
|
||||
// Move the cursor to the clicked location so that dispatched actions make sense
|
||||
editor.change_selections(None, cx, |s| {
|
||||
s.clear_disjoint();
|
||||
s.set_pending_display_range(point..point, SelectMode::Character);
|
||||
});
|
||||
|
||||
// // Move the cursor to the clicked location so that dispatched actions make sense
|
||||
// editor.change_selections(None, cx, |s| {
|
||||
// s.clear_disjoint();
|
||||
// s.set_pending_display_range(point..point, SelectMode::Character);
|
||||
// });
|
||||
let context_menu = ui::ContextMenu::build(cx, |menu, cx| {
|
||||
menu.action("Rename Symbol", Box::new(Rename), cx)
|
||||
.action("Go to Definition", Box::new(GoToDefinition), cx)
|
||||
.action("Go to Type Definition", Box::new(GoToTypeDefinition), cx)
|
||||
.action("Find All References", Box::new(FindAllReferences), cx)
|
||||
.action(
|
||||
"Code Actions",
|
||||
Box::new(ToggleCodeActions {
|
||||
deployed_from_indicator: false,
|
||||
}),
|
||||
cx,
|
||||
)
|
||||
.separator()
|
||||
.action("Reveal in Finder", Box::new(RevealInFinder), cx)
|
||||
});
|
||||
let context_menu_focus = context_menu.focus_handle(cx);
|
||||
cx.focus(&context_menu_focus);
|
||||
|
||||
// editor.mouse_context_menu.update(cx, |menu, cx| {
|
||||
// menu.show(
|
||||
// position,
|
||||
// AnchorCorner::TopLeft,
|
||||
// vec![
|
||||
// ContextMenuItem::action("Rename Symbol", Rename),
|
||||
// ContextMenuItem::action("Go to Definition", GoToDefinition),
|
||||
// ContextMenuItem::action("Go to Type Definition", GoToTypeDefinition),
|
||||
// ContextMenuItem::action("Find All References", FindAllReferences),
|
||||
// ContextMenuItem::action(
|
||||
// "Code Actions",
|
||||
// ToggleCodeActions {
|
||||
// deployed_from_indicator: false,
|
||||
// },
|
||||
// ),
|
||||
// ContextMenuItem::Separator,
|
||||
// ContextMenuItem::action("Reveal in Finder", RevealInFinder),
|
||||
// ],
|
||||
// cx,
|
||||
// );
|
||||
// });
|
||||
// cx.notify();
|
||||
let _subscription = cx.subscribe(&context_menu, move |this, _, event: &DismissEvent, cx| {
|
||||
this.mouse_context_menu.take();
|
||||
if context_menu_focus.contains_focused(cx) {
|
||||
this.focus(cx);
|
||||
}
|
||||
});
|
||||
|
||||
editor.mouse_context_menu = Some(MouseContextMenu {
|
||||
position,
|
||||
context_menu,
|
||||
_subscription,
|
||||
});
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
|
||||
@@ -592,31 +592,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