mirror of
https://github.com/zed-industries/zed.git
synced 2026-05-31 19:05:00 +07:00
Fix task modal fallback when LSP tasks are empty (#58090)
References [FR-28](https://linear.app/zed-industries/issue/FR-28/task-modal-does-not-show-runnable-rust-test). The bug this PR aims to fix is > I can click the play button beside a rust test function, but it does not show up in the task modal. I wasn't able to reproduce it, but I suspect this was caused by the task system preferring LSP code actions by default. It checked that an LSP was queried for a task instead of checking if the queried LSP actually returned any tasks. So the fix was just adding the below if statement as a check. ```rust if !new_lsp_tasks.is_empty() { lsp_tasks .entry(source_kind) .or_insert_with(Vec::new) .append(&mut new_lsp_tasks); } ``` I also added a regression test for this Self-Review Checklist: - [x] I have reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the UI/UX checklist - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - Fixed task modal failing to show language tasks in some cases
This commit is contained in:
parent
122619624d
commit
7f4a99aa95
2 changed files with 112 additions and 7 deletions
|
|
@ -164,12 +164,14 @@ pub fn lsp_tasks(
|
|||
},
|
||||
));
|
||||
}
|
||||
if !new_lsp_tasks.is_empty() {
|
||||
lsp_tasks
|
||||
.entry(source_kind)
|
||||
.or_insert_with(Vec::new)
|
||||
.append(&mut new_lsp_tasks);
|
||||
}
|
||||
}
|
||||
}
|
||||
lsp_tasks.into_iter().collect()
|
||||
})
|
||||
.with_timeout(Duration::from_millis(200), &cx.background_executor())
|
||||
|
|
|
|||
|
|
@ -734,11 +734,14 @@ mod tests {
|
|||
use std::{path::PathBuf, sync::Arc};
|
||||
|
||||
use editor::{Editor, SelectionEffects};
|
||||
use gpui::{TestAppContext, VisualTestContext};
|
||||
use language::{Language, LanguageConfig, LanguageMatcher, Point};
|
||||
use gpui::{App, Entity, Task, TestAppContext, VisualTestContext};
|
||||
use language::{
|
||||
Buffer, ContextProvider, FakeLspAdapter, Language, LanguageConfig, LanguageMatcher,
|
||||
LanguageServerName, Point,
|
||||
};
|
||||
use project::{ContextProviderWithTasks, FakeFs, Project};
|
||||
use serde_json::json;
|
||||
use task::TaskTemplates;
|
||||
use task::{TaskTemplate, TaskTemplates};
|
||||
use util::path;
|
||||
use workspace::{CloseInactiveTabsAndPanes, MultiWorkspace, OpenOptions, OpenVisible};
|
||||
|
||||
|
|
@ -1033,6 +1036,80 @@ mod tests {
|
|||
cx.executor().run_until_parked();
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_empty_lsp_task_response_keeps_language_tasks_in_modal(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
let fs = FakeFs::new(cx.executor());
|
||||
fs.insert_tree(path!("/dir"), json!({ "main.test": "test" }))
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/dir").as_ref()], cx).await;
|
||||
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
|
||||
language_registry.add(Arc::new(
|
||||
Language::new(
|
||||
LanguageConfig {
|
||||
name: "Test".into(),
|
||||
matcher: LanguageMatcher {
|
||||
path_suffixes: vec!["test".to_string()],
|
||||
..LanguageMatcher::default()
|
||||
},
|
||||
..LanguageConfig::default()
|
||||
},
|
||||
None,
|
||||
)
|
||||
.with_context_provider(Some(Arc::new(
|
||||
ContextProviderWithLspTaskSource::new(ContextProviderWithTasks::new(
|
||||
TaskTemplates(vec![TaskTemplate {
|
||||
label: "Run language task".to_string(),
|
||||
command: "echo".to_string(),
|
||||
args: vec!["language task".to_string()],
|
||||
..TaskTemplate::default()
|
||||
}]),
|
||||
)),
|
||||
))),
|
||||
));
|
||||
let mut fake_servers = language_registry.register_fake_lsp(
|
||||
"Test",
|
||||
FakeLspAdapter {
|
||||
name: TEST_LSP_NAME,
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
|
||||
let (multi_workspace, cx) =
|
||||
cx.add_window_view(|window, cx| MultiWorkspace::test_new(project, window, cx));
|
||||
let workspace =
|
||||
multi_workspace.read_with(cx, |multi_workspace, _| multi_workspace.workspace().clone());
|
||||
let _item = workspace
|
||||
.update_in(cx, |workspace, window, cx| {
|
||||
workspace.open_abs_path(
|
||||
PathBuf::from(path!("/dir/main.test")),
|
||||
OpenOptions {
|
||||
visible: Some(OpenVisible::All),
|
||||
..Default::default()
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
cx.executor().run_until_parked();
|
||||
let fake_server = fake_servers
|
||||
.try_recv()
|
||||
.expect("fake LSP server should have started");
|
||||
use project::lsp_store::lsp_ext_command::Runnables;
|
||||
fake_server
|
||||
.set_request_handler::<Runnables, _, _>(move |_, _| async move { Ok(Vec::new()) });
|
||||
|
||||
let tasks_picker = open_spawn_tasks(&workspace, cx);
|
||||
assert_eq!(
|
||||
task_names(&tasks_picker, cx),
|
||||
vec!["Run language task"],
|
||||
"An empty LSP task response should not suppress language tasks in the modal"
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_language_task_filtering(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
|
@ -1238,6 +1315,32 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
const TEST_LSP_NAME: &str = "test-lsp";
|
||||
|
||||
struct ContextProviderWithLspTaskSource {
|
||||
tasks: ContextProviderWithTasks,
|
||||
}
|
||||
|
||||
impl ContextProviderWithLspTaskSource {
|
||||
fn new(tasks: ContextProviderWithTasks) -> Self {
|
||||
Self { tasks }
|
||||
}
|
||||
}
|
||||
|
||||
impl ContextProvider for ContextProviderWithLspTaskSource {
|
||||
fn associated_tasks(
|
||||
&self,
|
||||
buffer: Option<Entity<Buffer>>,
|
||||
cx: &App,
|
||||
) -> Task<Option<TaskTemplates>> {
|
||||
self.tasks.associated_tasks(buffer, cx)
|
||||
}
|
||||
|
||||
fn lsp_task_source(&self) -> Option<LanguageServerName> {
|
||||
Some(LanguageServerName::new_static(TEST_LSP_NAME))
|
||||
}
|
||||
}
|
||||
|
||||
fn emulate_task_schedule(
|
||||
tasks_picker: Entity<Picker<TasksModalDelegate>>,
|
||||
project: &Entity<Project>,
|
||||
|
|
|
|||
Loading…
Reference in a new issue