Detailed changes
@@ -124,6 +124,7 @@ action!(FoldSelectedRanges);
action!(Scroll, Vector2F);
action!(Select, SelectPhase);
action!(ShowCompletions);
+action!(ShowCodeActions);
action!(ConfirmCompletion, Option<usize>);
pub fn init(cx: &mut MutableAppContext, path_openers: &mut Vec<Box<dyn PathOpener>>) {
@@ -239,6 +240,7 @@ pub fn init(cx: &mut MutableAppContext, path_openers: &mut Vec<Box<dyn PathOpene
Binding::new("alt-cmd-]", Unfold, Some("Editor")),
Binding::new("alt-cmd-f", FoldSelectedRanges, Some("Editor")),
Binding::new("ctrl-space", ShowCompletions, Some("Editor")),
+ Binding::new("cmd-.", ShowCodeActions, Some("Editor")),
]);
cx.add_action(Editor::open_new);
@@ -303,6 +305,7 @@ pub fn init(cx: &mut MutableAppContext, path_openers: &mut Vec<Box<dyn PathOpene
cx.add_action(Editor::unfold);
cx.add_action(Editor::fold_selected_ranges);
cx.add_action(Editor::show_completions);
+ cx.add_action(Editor::show_code_actions);
cx.add_action(
|editor: &mut Editor, &ConfirmCompletion(ix): &ConfirmCompletion, cx| {
if let Some(task) = editor.confirm_completion(ix, cx) {
@@ -1721,6 +1724,22 @@ impl Editor {
self.completion_tasks.push((id, task));
}
+ fn show_code_actions(&mut self, _: &ShowCodeActions, cx: &mut ViewContext<Self>) {
+ let position = if let Some(selection) = self.newest_anchor_selection() {
+ selection.head()
+ } else {
+ return;
+ };
+
+ let actions = self
+ .buffer
+ .update(cx, |buffer, cx| buffer.code_actions(position.clone(), cx));
+ cx.spawn(|this, cx| async move {
+ dbg!(actions.await.unwrap());
+ })
+ .detach();
+ }
+
fn hide_completions(&mut self, cx: &mut ViewContext<Self>) -> Option<CompletionState> {
cx.notify();
self.completion_tasks.clear();
@@ -860,6 +860,21 @@ impl MultiBuffer {
})
}
+ pub fn code_actions<T>(
+ &self,
+ position: T,
+ cx: &mut ModelContext<Self>,
+ ) -> Task<Result<Vec<lsp::CodeAction>>>
+ where
+ T: ToOffset,
+ {
+ let anchor = self.read(cx).anchor_before(position);
+ let buffer = self.buffers.borrow()[&anchor.buffer_id].buffer.clone();
+ let code_actions =
+ buffer.update(cx, |buffer, cx| buffer.code_actions(anchor.text_anchor, cx));
+ cx.spawn(|this, cx| async move { code_actions.await })
+ }
+
pub fn completions<T>(
&self,
position: T,
@@ -14,7 +14,7 @@ use clock::ReplicaId;
use futures::FutureExt as _;
use gpui::{AppContext, Entity, ModelContext, MutableAppContext, Task};
use lazy_static::lazy_static;
-use lsp::LanguageServer;
+use lsp::{CodeActionKind, LanguageServer};
use parking_lot::Mutex;
use postage::{prelude::Stream, sink::Sink, watch};
use similar::{ChangeTag, TextDiff};
@@ -1848,6 +1848,69 @@ impl Buffer {
}
}
+ pub fn code_actions<T>(
+ &self,
+ position: T,
+ cx: &mut ModelContext<Self>,
+ ) -> Task<Result<Vec<lsp::CodeAction>>>
+ where
+ T: ToPointUtf16,
+ {
+ let file = if let Some(file) = self.file.as_ref() {
+ file
+ } else {
+ return Task::ready(Ok(Default::default()));
+ };
+
+ if let Some(file) = file.as_local() {
+ let server = if let Some(language_server) = self.language_server.as_ref() {
+ language_server.server.clone()
+ } else {
+ return Task::ready(Ok(Default::default()));
+ };
+ let abs_path = file.abs_path(cx);
+ let position = position.to_point_utf16(self);
+
+ cx.spawn(|this, mut cx| async move {
+ let actions = server
+ .request::<lsp::request::CodeActionRequest>(lsp::CodeActionParams {
+ text_document: lsp::TextDocumentIdentifier::new(
+ lsp::Url::from_file_path(abs_path).unwrap(),
+ ),
+ range: lsp::Range::new(
+ position.to_lsp_position(),
+ position.to_lsp_position(),
+ ),
+ work_done_progress_params: Default::default(),
+ partial_result_params: Default::default(),
+ context: lsp::CodeActionContext {
+ diagnostics: Default::default(),
+ only: Some(vec![
+ lsp::CodeActionKind::QUICKFIX,
+ lsp::CodeActionKind::REFACTOR,
+ lsp::CodeActionKind::REFACTOR_EXTRACT,
+ ]),
+ },
+ })
+ .await?
+ .unwrap_or_default()
+ .into_iter()
+ .filter_map(|entry| {
+ if let lsp::CodeActionOrCommand::CodeAction(action) = entry {
+ Some(action)
+ } else {
+ None
+ }
+ })
+ .collect();
+ Ok(actions)
+ })
+ } else {
+ log::info!("code actions are not implemented for guests");
+ Task::ready(Ok(Default::default()))
+ }
+ }
+
pub fn apply_additional_edits_for_completion(
&mut self,
completion: Completion<Anchor>,
@@ -238,6 +238,17 @@ impl LanguageServer {
link_support: Some(true),
..Default::default()
}),
+ code_action: Some(CodeActionClientCapabilities {
+ code_action_literal_support: Some(CodeActionLiteralSupport {
+ code_action_kind: CodeActionKindLiteralSupport {
+ value_set: vec![
+ CodeActionKind::REFACTOR.as_str().into(),
+ CodeActionKind::QUICKFIX.as_str().into(),
+ ],
+ },
+ }),
+ ..Default::default()
+ }),
completion: Some(CompletionClientCapabilities {
completion_item: Some(CompletionItemCapability {
snippet_support: Some(true),