Revert "Use textDocument/codeLens data in the actions menu when applicable (#26811)" (#26832)

This reverts commit b61171f152.

This PR reverts #26811, as it has broken `rust-analyzer` code actions.

With this commit reverted my code actions are working again. 

Release Notes:

- Community: Reverted https://github.com/zed-industries/zed/pull/26811.
This commit is contained in:
Marshall Bowers 2025-03-15 10:14:29 -04:00 committed by GitHub
parent b547cd1c70
commit 021d6584cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 19 additions and 618 deletions

View file

@ -69,7 +69,7 @@ pub use element::{
CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
};
use futures::{
future::{self, join, Shared},
future::{self, Shared},
FutureExt,
};
use fuzzy::StringMatchCandidate;
@ -82,10 +82,10 @@ use code_context_menus::{
use git::blame::GitBlame;
use gpui::{
div, impl_actions, point, prelude::*, pulsating_between, px, relative, size, Action, Animation,
AnimationExt, AnyElement, App, AppContext, AsyncWindowContext, AvailableSpace, Background,
Bounds, ClipboardEntry, ClipboardItem, Context, DispatchPhase, Edges, Entity,
EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent, Focusable, FontId, FontWeight,
Global, HighlightStyle, Hsla, KeyContext, Modifiers, MouseButton, MouseDownEvent, PaintQuad,
AnimationExt, AnyElement, App, AsyncWindowContext, AvailableSpace, Background, Bounds,
ClipboardEntry, ClipboardItem, Context, DispatchPhase, Edges, Entity, EntityInputHandler,
EventEmitter, FocusHandle, FocusOutEvent, Focusable, FontId, FontWeight, Global,
HighlightStyle, Hsla, KeyContext, Modifiers, MouseButton, MouseDownEvent, PaintQuad,
ParentElement, Pixels, Render, SharedString, Size, Stateful, Styled, StyledText, Subscription,
Task, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle,
WeakEntity, WeakFocusHandle, Window,
@ -1233,15 +1233,11 @@ impl Editor {
project_subscriptions.push(cx.subscribe_in(
project,
window,
|editor, _, event, window, cx| match event {
project::Event::RefreshCodeLens => {
// we always query lens with actions, without storing them, always refreshing them
}
project::Event::RefreshInlayHints => {
|editor, _, event, window, cx| {
if let project::Event::RefreshInlayHints = event {
editor
.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
}
project::Event::SnippetEdit(id, snippet_edits) => {
} else if let project::Event::SnippetEdit(id, snippet_edits) = event {
if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
let focus_handle = editor.focus_handle(cx);
if focus_handle.is_focused(window) {
@ -1261,7 +1257,6 @@ impl Editor {
}
}
}
_ => {}
},
));
if let Some(task_inventory) = project
@ -17032,16 +17027,7 @@ impl CodeActionProvider for Entity<Project> {
cx: &mut App,
) -> Task<Result<Vec<CodeAction>>> {
self.update(cx, |project, cx| {
let code_lens = project.code_lens(buffer, range.clone(), cx);
let code_actions = project.code_actions(buffer, range, None, cx);
cx.background_spawn(async move {
let (code_lens, code_actions) = join(code_lens, code_actions).await;
Ok(code_lens
.context("code lens fetch")?
.into_iter()
.chain(code_actions.context("code action fetch")?)
.collect())
})
project.code_actions(buffer, range, None, cx)
})
}

View file

@ -17233,187 +17233,6 @@ async fn test_tree_sitter_brackets_newline_insertion(cx: &mut TestAppContext) {
"});
}
#[gpui::test(iterations = 10)]
async fn test_apply_code_lens_actions_with_commands(cx: &mut gpui::TestAppContext) {
init_test(cx, |_| {});
let fs = FakeFs::new(cx.executor());
fs.insert_tree(
path!("/dir"),
json!({
"a.ts": "a",
}),
)
.await;
let project = Project::test(fs, [path!("/dir").as_ref()], cx).await;
let workspace = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
let cx = &mut VisualTestContext::from_window(*workspace.deref(), cx);
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(Arc::new(Language::new(
LanguageConfig {
name: "TypeScript".into(),
matcher: LanguageMatcher {
path_suffixes: vec!["ts".to_string()],
..Default::default()
},
..Default::default()
},
Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()),
)));
let mut fake_language_servers = language_registry.register_fake_lsp(
"TypeScript",
FakeLspAdapter {
capabilities: lsp::ServerCapabilities {
code_lens_provider: Some(lsp::CodeLensOptions {
resolve_provider: Some(true),
}),
execute_command_provider: Some(lsp::ExecuteCommandOptions {
commands: vec!["_the/command".to_string()],
..lsp::ExecuteCommandOptions::default()
}),
..lsp::ServerCapabilities::default()
},
..FakeLspAdapter::default()
},
);
let (buffer, _handle) = project
.update(cx, |p, cx| {
p.open_local_buffer_with_lsp(path!("/dir/a.ts"), cx)
})
.await
.unwrap();
cx.executor().run_until_parked();
let fake_server = fake_language_servers.next().await.unwrap();
let buffer_snapshot = buffer.update(cx, |buffer, _| buffer.snapshot());
let anchor = buffer_snapshot.anchor_at(0, text::Bias::Left);
drop(buffer_snapshot);
let actions = cx
.update_window(*workspace, |_, window, cx| {
project.code_actions(&buffer, anchor..anchor, window, cx)
})
.unwrap();
fake_server
.handle_request::<lsp::request::CodeLensRequest, _, _>(|_, _| async move {
Ok(Some(vec![
lsp::CodeLens {
range: lsp::Range::default(),
command: Some(lsp::Command {
title: "Code lens command".to_owned(),
command: "_the/command".to_owned(),
arguments: None,
}),
data: None,
},
lsp::CodeLens {
range: lsp::Range::default(),
command: Some(lsp::Command {
title: "Command not in capabilities".to_owned(),
command: "not in capabilities".to_owned(),
arguments: None,
}),
data: None,
},
lsp::CodeLens {
range: lsp::Range {
start: lsp::Position {
line: 1,
character: 1,
},
end: lsp::Position {
line: 1,
character: 1,
},
},
command: Some(lsp::Command {
title: "Command not in range".to_owned(),
command: "_the/command".to_owned(),
arguments: None,
}),
data: None,
},
]))
})
.next()
.await;
let actions = actions.await.unwrap();
assert_eq!(
actions.len(),
1,
"Should have only one valid action for the 0..0 range"
);
let action = actions[0].clone();
let apply = project.update(cx, |project, cx| {
project.apply_code_action(buffer.clone(), action, true, cx)
});
// Resolving the code action does not populate its edits. In absence of
// edits, we must execute the given command.
fake_server.handle_request::<lsp::request::CodeLensResolve, _, _>(|mut lens, _| async move {
let lens_command = lens.command.as_mut().expect("should have a command");
assert_eq!(lens_command.title, "Code lens command");
lens_command.arguments = Some(vec![json!("the-argument")]);
Ok(lens)
});
// While executing the command, the language server sends the editor
// a `workspaceEdit` request.
fake_server
.handle_request::<lsp::request::ExecuteCommand, _, _>({
let fake = fake_server.clone();
move |params, _| {
assert_eq!(params.command, "_the/command");
let fake = fake.clone();
async move {
fake.server
.request::<lsp::request::ApplyWorkspaceEdit>(
lsp::ApplyWorkspaceEditParams {
label: None,
edit: lsp::WorkspaceEdit {
changes: Some(
[(
lsp::Url::from_file_path(path!("/dir/a.ts")).unwrap(),
vec![lsp::TextEdit {
range: lsp::Range::new(
lsp::Position::new(0, 0),
lsp::Position::new(0, 0),
),
new_text: "X".into(),
}],
)]
.into_iter()
.collect(),
),
..Default::default()
},
},
)
.await
.unwrap();
Ok(Some(json!(null)))
}
}
})
.next()
.await;
// Applying the code lens command returns a project transaction containing the edits
// sent by the language server in its `workspaceEdit` request.
let transaction = apply.await.unwrap();
assert!(transaction.0.contains_key(&buffer));
buffer.update(cx, |buffer, cx| {
assert_eq!(buffer.text(), "Xa");
buffer.undo(cx);
assert_eq!(buffer.text(), "a");
});
}
mod autoclose_tags {
use super::*;
use language::language_settings::JsxTagAutoCloseSettings;