#![allow(clippy::format_collect)] use crate::{ Event, git_store::{GitStoreEvent, RepositoryEvent, StatusEntry}, task_inventory::TaskContexts, task_store::TaskSettingsLocation, *,};use async_trait::async_trait;use buffer_diff::{ BufferDiffEvent, CALCULATE_DIFF_TASK, DiffHunkSecondaryStatus, DiffHunkStatus, DiffHunkStatusKind, assert_hunks,};use fs::FakeFs;use futures::{StreamExt, future};use git::{ GitHostingProviderRegistry, repository::{RepoPath, repo_path}, status::{StatusCode, TrackedStatus},};use git2::RepositoryInitOptions;use gpui::{App, BackgroundExecutor, SemanticVersion, UpdateGlobal};use itertools::Itertools;use language::{ Diagnostic, DiagnosticEntry, DiagnosticEntryRef, DiagnosticSet, DiagnosticSourceKind, DiskState, FakeLspAdapter, LanguageConfig, LanguageMatcher, LanguageName, LineEnding, ManifestName, ManifestProvider, ManifestQuery, OffsetRangeExt, Point, ToPoint, ToolchainList, ToolchainLister, language_settings::{LanguageSettingsContent, language_settings}, tree_sitter_rust, tree_sitter_typescript,};use lsp::{ DiagnosticSeverity, DocumentChanges, FileOperationFilter, NumberOrString, TextDocumentEdit, Uri, WillRenameFiles, notification::DidRenameFiles,};use parking_lot::Mutex;use paths::{config_dir, global_gitignore_path, tasks_file};use postage::stream::Stream as _;use pretty_assertions::{assert_eq, assert_matches};use rand::{Rng as _, rngs::StdRng};use serde_json::json;#[cfg(not(windows))]use std::os;use std::{ env, mem, num::NonZeroU32, ops::Range, str::FromStr, sync::{Arc, OnceLock}, task::Poll,};use task::{ResolvedTask, ShellKind, TaskContext};use unindent::Unindent as _;use util::{ TryFutureExt as _, assert_set_eq, maybe, path, paths::PathMatcher, rel_path::rel_path, test::{TempTree, marked_text_offsets}, uri,};use worktree::WorktreeModelHandle as _; #[gpui::test]async fn test_block_via_channel(cx: &mut gpui::TestAppContext) { cx.executor().allow_parking(); let (tx, mut rx) = futures::channel::mpsc::unbounded(); let _thread = std::thread::spawn(move || { #[cfg(not(target_os = "windows"))] std::fs::metadata("/tmp").unwrap(); #[cfg(target_os = "windows")] std::fs::metadata("C:/Windows").unwrap(); std::thread::sleep(Duration::from_millis(1000)); tx.unbounded_send(1).unwrap(); }); rx.next().await.unwrap();} #[gpui::test]async fn test_block_via_smol(cx: &mut gpui::TestAppContext) { cx.executor().allow_parking(); let io_task = smol::unblock(move || { println!("sleeping on thread {:?}", std::thread::current().id()); std::thread::sleep(Duration::from_millis(10)); 1 }); let task = cx.foreground_executor().spawn(async move { io_task.await; }); task.await;} // NOTE:// While POSIX symbolic links are somewhat supported on Windows, they are an opt in by the user, and thus// we assume that they are not supported out of the box.#[cfg(not(windows))]#[gpui::test]async fn test_symlinks(cx: &mut gpui::TestAppContext) { init_test(cx); cx.executor().allow_parking(); let dir = TempTree::new(json!({ "root": { "apple": "", "banana": { "carrot": { "date": "", "endive": "", } }, "fennel": { "grape": "", } } })); let root_link_path = dir.path().join("root_link"); os::unix::fs::symlink(dir.path().join("root"), &root_link_path).unwrap(); os::unix::fs::symlink( dir.path().join("root/fennel"), dir.path().join("root/finnochio"), ) .unwrap(); let project = Project::test( Arc::new(RealFs::new(None, cx.executor())), [root_link_path.as_ref()], cx, ) .await; project.update(cx, |project, cx| { let tree = project.worktrees(cx).next().unwrap().read(cx); assert_eq!(tree.file_count(), 5); assert_eq!( tree.entry_for_path(rel_path("fennel/grape")).unwrap().inode, tree.entry_for_path(rel_path("finnochio/grape")) .unwrap() .inode ); });} #[gpui::test]async fn test_editorconfig_support(cx: &mut gpui::TestAppContext) { init_test(cx); let dir = TempTree::new(json!({ ".editorconfig": r#" root = true [*.rs] indent_style = tab indent_size = 3 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true max_line_length = 120 [*.js] tab_width = 10 max_line_length = off "#, ".zed": { "settings.json": r#"{ "tab_size": 8, "hard_tabs": false, "ensure_final_newline_on_save": false, "remove_trailing_whitespace_on_save": false, "preferred_line_length": 64, "soft_wrap": "editor_width", }"#, }, "a.rs": "fn a() {\n A\n}", "b": { ".editorconfig": r#" [*.rs] indent_size = 2 max_line_length = off, "#, "b.rs": "fn b() {\n B\n}", }, "c.js": "def c\n C\nend", "README.json": "tabs are better\n", })); let path = dir.path(); let fs = FakeFs::new(cx.executor()); fs.insert_tree_from_real_fs(path, path).await; let project = Project::test(fs, [path], cx).await; let language_registry = project.read_with(cx, |project, _| project.languages().clone()); language_registry.add(js_lang()); language_registry.add(json_lang()); language_registry.add(rust_lang()); let worktree = project.update(cx, |project, cx| project.worktrees(cx).next().unwrap()); cx.executor().run_until_parked(); cx.update(|cx| { let tree = worktree.read(cx); let settings_for = |path: &str| { let file_entry = tree.entry_for_path(rel_path(path)).unwrap().clone(); let file = File::for_entry(file_entry, worktree.clone()); let file_language = project .read(cx) .languages() .load_language_for_file_path(file.path.as_std_path()); let file_language = cx .background_executor() .block(file_language) .expect("Failed to get file language"); let file = file as _; language_settings(Some(file_language.name()), Some(&file), cx).into_owned() }; let settings_a = settings_for("a.rs"); let settings_b = settings_for("b/b.rs"); let settings_c = settings_for("c.js"); let settings_readme = settings_for("README.json"); // .editorconfig overrides .zed/settings assert_eq!(Some(settings_a.tab_size), NonZeroU32::new(3)); assert_eq!(settings_a.hard_tabs, true); assert_eq!(settings_a.ensure_final_newline_on_save, true); assert_eq!(settings_a.remove_trailing_whitespace_on_save, true); assert_eq!(settings_a.preferred_line_length, 120); // .editorconfig in b/ overrides .editorconfig in root assert_eq!(Some(settings_b.tab_size), NonZeroU32::new(2)); // "indent_size" is not set, so "tab_width" is used assert_eq!(Some(settings_c.tab_size), NonZeroU32::new(10)); // When max_line_length is "off", default to .zed/settings.json assert_eq!(settings_b.preferred_line_length, 64); assert_eq!(settings_c.preferred_line_length, 64); // README.md should not be affected by .editorconfig's globe "*.rs" assert_eq!(Some(settings_readme.tab_size), NonZeroU32::new(8)); });} #[gpui::test]async fn test_git_provider_project_setting(cx: &mut gpui::TestAppContext) { init_test(cx); cx.update(|cx| { GitHostingProviderRegistry::default_global(cx); git_hosting_providers::init(cx); }); let fs = FakeFs::new(cx.executor()); let str_path = path!("/dir"); let path = Path::new(str_path); fs.insert_tree( path!("/dir"), json!({ ".zed": { "settings.json": r#"{ "git_hosting_providers": [ { "provider": "gitlab", "base_url": "https://google.com", "name": "foo" } ] }"# }, }), ) .await; let project = Project::test(fs.clone(), [path!("/dir").as_ref()], cx).await; let (_worktree, _) = project.read_with(cx, |project, cx| project.find_worktree(path, cx).unwrap()); cx.executor().run_until_parked(); cx.update(|cx| { let provider = GitHostingProviderRegistry::global(cx); assert!( provider .list_hosting_providers() .into_iter() .any(|provider| provider.name() == "foo") ); }); fs.atomic_write( Path::new(path!("/dir/.zed/settings.json")).to_owned(), "{}".into(), ) .await .unwrap(); cx.run_until_parked(); cx.update(|cx| { let provider = GitHostingProviderRegistry::global(cx); assert!( !provider .list_hosting_providers() .into_iter() .any(|provider| provider.name() == "foo") ); });} #[gpui::test]async fn test_managing_project_specific_settings(cx: &mut gpui::TestAppContext) { init_test(cx); TaskStore::init(None); let fs = FakeFs::new(cx.executor()); fs.insert_tree( path!("/dir"), json!({ ".zed": { "settings.json": r#"{ "tab_size": 8 }"#, "tasks.json": r#"[{ "label": "cargo check all", "command": "cargo", "args": ["check", "--all"] },]"#, }, "a": { "a.rs": "fn a() {\n A\n}" }, "b": { ".zed": { "settings.json": r#"{ "tab_size": 2 }"#, "tasks.json": r#"[{ "label": "cargo check", "command": "cargo", "args": ["check"] },]"#, }, "b.rs": "fn b() {\n B\n}" } }), ) .await; let project = Project::test(fs.clone(), [path!("/dir").as_ref()], cx).await; let worktree = project.update(cx, |project, cx| project.worktrees(cx).next().unwrap()); cx.executor().run_until_parked(); let worktree_id = cx.update(|cx| { project.update(cx, |project, cx| { project.worktrees(cx).next().unwrap().read(cx).id() }) }); let mut task_contexts = TaskContexts::default(); task_contexts.active_worktree_context = Some((worktree_id, TaskContext::default())); let task_contexts = Arc::new(task_contexts); let topmost_local_task_source_kind = TaskSourceKind::Worktree { id: worktree_id, directory_in_worktree: rel_path(".zed").into(), id_base: "local worktree tasks from directory \".zed\"".into(), }; let all_tasks = cx .update(|cx| { let tree = worktree.read(cx); let file_a = File::for_entry( tree.entry_for_path(rel_path("a/a.rs")).unwrap().clone(), worktree.clone(), ) as _; let settings_a = language_settings(None, Some(&file_a), cx); let file_b = File::for_entry( tree.entry_for_path(rel_path("b/b.rs")).unwrap().clone(), worktree.clone(), ) as _; let settings_b = language_settings(None, Some(&file_b), cx); assert_eq!(settings_a.tab_size.get(), 8); assert_eq!(settings_b.tab_size.get(), 2); get_all_tasks(&project, task_contexts.clone(), cx) }) .await .into_iter() .map(|(source_kind, task)| { let resolved = task.resolved; ( source_kind, task.resolved_label, resolved.args, resolved.env, ) }) .collect::<Vec<_>>(); assert_eq!( all_tasks, vec![ ( TaskSourceKind::Worktree { id: worktree_id, directory_in_worktree: rel_path("b/.zed").into(), id_base: "local worktree tasks from directory \"b/.zed\"".into() }, "cargo check".to_string(), vec!["check".to_string()], HashMap::default(), ), ( topmost_local_task_source_kind.clone(), "cargo check all".to_string(), vec!["check".to_string(), "--all".to_string()], HashMap::default(), ), ] ); let (_, resolved_task) = cx .update(|cx| get_all_tasks(&project, task_contexts.clone(), cx)) .await .into_iter() .find(|(source_kind, _)| source_kind == &topmost_local_task_source_kind) .expect("should have one global task"); project.update(cx, |project, cx| { let task_inventory = project .task_store .read(cx) .task_inventory() .cloned() .unwrap(); task_inventory.update(cx, |inventory, _| { inventory.task_scheduled(topmost_local_task_source_kind.clone(), resolved_task); inventory .update_file_based_tasks( TaskSettingsLocation::Global(tasks_file()), Some( &json!([{ "label": "cargo check unstable", "command": "cargo", "args": [ "check", "--all", "--all-targets" ], "env": { "RUSTFLAGS": "-Zunstable-options" } }]) .to_string(), ), ) .unwrap(); }); }); cx.run_until_parked(); let all_tasks = cx .update(|cx| get_all_tasks(&project, task_contexts.clone(), cx)) .await .into_iter() .map(|(source_kind, task)| { let resolved = task.resolved; ( source_kind, task.resolved_label, resolved.args, resolved.env, ) }) .collect::<Vec<_>>(); assert_eq!( all_tasks, vec![ ( topmost_local_task_source_kind.clone(), "cargo check all".to_string(), vec!["check".to_string(), "--all".to_string()], HashMap::default(), ), ( TaskSourceKind::Worktree { id: worktree_id, directory_in_worktree: rel_path("b/.zed").into(), id_base: "local worktree tasks from directory \"b/.zed\"".into() }, "cargo check".to_string(), vec!["check".to_string()], HashMap::default(), ), ( TaskSourceKind::AbsPath { abs_path: paths::tasks_file().clone(), id_base: "global tasks.json".into(), }, "cargo check unstable".to_string(), vec![ "check".to_string(),Lines 1–500 of 10043. Load more
#![allow(clippy::format_collect)] use crate::{ Event, git_store::{GitStoreEvent, RepositoryEvent, StatusEntry}, task_inventory::TaskContexts, task_store::TaskSettingsLocation, *, }; use async_trait::async_trait; use buffer_diff::{ BufferDiffEvent, CALCULATE_DIFF_TASK, DiffHunkSecondaryStatus, DiffHunkStatus, DiffHunkStatusKind, assert_hunks, }; use fs::FakeFs; use futures::{StreamExt, future}; use git::{ GitHostingProviderRegistry, repository::{RepoPath, repo_path}, status::{StatusCode, TrackedStatus}, }; use git2::RepositoryInitOptions; use gpui::{App, BackgroundExecutor, SemanticVersion, UpdateGlobal}; use itertools::Itertools; use language::{ Diagnostic, DiagnosticEntry, DiagnosticEntryRef, DiagnosticSet, DiagnosticSourceKind, DiskState, FakeLspAdapter, LanguageConfig, LanguageMatcher, LanguageName, LineEnding, ManifestName, ManifestProvider, ManifestQuery, OffsetRangeExt, Point, ToPoint, ToolchainList, ToolchainLister, language_settings::{LanguageSettingsContent, language_settings}, tree_sitter_rust, tree_sitter_typescript, }; use lsp::{ DiagnosticSeverity, DocumentChanges, FileOperationFilter, NumberOrString, TextDocumentEdit, Uri, WillRenameFiles, notification::DidRenameFiles, }; use parking_lot::Mutex; use paths::{config_dir, global_gitignore_path, tasks_file}; use postage::stream::Stream as _; use pretty_assertions::{assert_eq, assert_matches}; use rand::{Rng as _, rngs::StdRng}; use serde_json::json; #[cfg(not(windows))] use std::os; use std::{ env, mem, num::NonZeroU32, ops::Range, str::FromStr, sync::{Arc, OnceLock}, task::Poll, }; use task::{ResolvedTask, ShellKind, TaskContext}; use unindent::Unindent as _; use util::{ TryFutureExt as _, assert_set_eq, maybe, path, paths::PathMatcher, rel_path::rel_path, test::{TempTree, marked_text_offsets}, uri, }; use worktree::WorktreeModelHandle as _; #[gpui::test] async fn test_block_via_channel(cx: &mut gpui::TestAppContext) { cx.executor().allow_parking(); let (tx, mut rx) = futures::channel::mpsc::unbounded(); let _thread = std::thread::spawn(move || { #[cfg(not(target_os = "windows"))] std::fs::metadata("/tmp").unwrap(); #[cfg(target_os = "windows")] std::fs::metadata("C:/Windows").unwrap(); std::thread::sleep(Duration::from_millis(1000)); tx.unbounded_send(1).unwrap(); }); rx.next().await.unwrap(); } #[gpui::test] async fn test_block_via_smol(cx: &mut gpui::TestAppContext) { cx.executor().allow_parking(); let io_task = smol::unblock(move || { println!("sleeping on thread {:?}", std::thread::current().id()); std::thread::sleep(Duration::from_millis(10)); 1 }); let task = cx.foreground_executor().spawn(async move { io_task.await; }); task.await; } // NOTE: // While POSIX symbolic links are somewhat supported on Windows, they are an opt in by the user, and thus // we assume that they are not supported out of the box. #[cfg(not(windows))] #[gpui::test] async fn test_symlinks(cx: &mut gpui::TestAppContext) { init_test(cx); cx.executor().allow_parking(); let dir = TempTree::new(json!({ "root": { "apple": "", "banana": { "carrot": { "date": "", "endive": "", } }, "fennel": { "grape": "", } } })); let root_link_path = dir.path().join("root_link"); os::unix::fs::symlink(dir.path().join("root"), &root_link_path).unwrap(); os::unix::fs::symlink( dir.path().join("root/fennel"), dir.path().join("root/finnochio"), ) .unwrap(); let project = Project::test( Arc::new(RealFs::new(None, cx.executor())), [root_link_path.as_ref()], cx, ) .await; project.update(cx, |project, cx| { let tree = project.worktrees(cx).next().unwrap().read(cx); assert_eq!(tree.file_count(), 5); assert_eq!( tree.entry_for_path(rel_path("fennel/grape")).unwrap().inode, tree.entry_for_path(rel_path("finnochio/grape")) .unwrap() .inode ); }); } #[gpui::test] async fn test_editorconfig_support(cx: &mut gpui::TestAppContext) { init_test(cx); let dir = TempTree::new(json!({ ".editorconfig": r#" root = true [*.rs] indent_style = tab indent_size = 3 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true max_line_length = 120 [*.js] tab_width = 10 max_line_length = off "#, ".zed": { "settings.json": r#"{ "tab_size": 8, "hard_tabs": false, "ensure_final_newline_on_save": false, "remove_trailing_whitespace_on_save": false, "preferred_line_length": 64, "soft_wrap": "editor_width", }"#, }, "a.rs": "fn a() {\n A\n}", "b": { ".editorconfig": r#" [*.rs] indent_size = 2 max_line_length = off, "#, "b.rs": "fn b() {\n B\n}", }, "c.js": "def c\n C\nend", "README.json": "tabs are better\n", })); let path = dir.path(); let fs = FakeFs::new(cx.executor()); fs.insert_tree_from_real_fs(path, path).await; let project = Project::test(fs, [path], cx).await; let language_registry = project.read_with(cx, |project, _| project.languages().clone()); language_registry.add(js_lang()); language_registry.add(json_lang()); language_registry.add(rust_lang()); let worktree = project.update(cx, |project, cx| project.worktrees(cx).next().unwrap()); cx.executor().run_until_parked(); cx.update(|cx| { let tree = worktree.read(cx); let settings_for = |path: &str| { let file_entry = tree.entry_for_path(rel_path(path)).unwrap().clone(); let file = File::for_entry(file_entry, worktree.clone()); let file_language = project .read(cx) .languages() .load_language_for_file_path(file.path.as_std_path()); let file_language = cx .background_executor() .block(file_language) .expect("Failed to get file language"); let file = file as _; language_settings(Some(file_language.name()), Some(&file), cx).into_owned() }; let settings_a = settings_for("a.rs"); let settings_b = settings_for("b/b.rs"); let settings_c = settings_for("c.js"); let settings_readme = settings_for("README.json"); // .editorconfig overrides .zed/settings assert_eq!(Some(settings_a.tab_size), NonZeroU32::new(3)); assert_eq!(settings_a.hard_tabs, true); assert_eq!(settings_a.ensure_final_newline_on_save, true); assert_eq!(settings_a.remove_trailing_whitespace_on_save, true); assert_eq!(settings_a.preferred_line_length, 120); // .editorconfig in b/ overrides .editorconfig in root assert_eq!(Some(settings_b.tab_size), NonZeroU32::new(2)); // "indent_size" is not set, so "tab_width" is used assert_eq!(Some(settings_c.tab_size), NonZeroU32::new(10)); // When max_line_length is "off", default to .zed/settings.json assert_eq!(settings_b.preferred_line_length, 64); assert_eq!(settings_c.preferred_line_length, 64); // README.md should not be affected by .editorconfig's globe "*.rs" assert_eq!(Some(settings_readme.tab_size), NonZeroU32::new(8)); }); } #[gpui::test] async fn test_git_provider_project_setting(cx: &mut gpui::TestAppContext) { init_test(cx); cx.update(|cx| { GitHostingProviderRegistry::default_global(cx); git_hosting_providers::init(cx); }); let fs = FakeFs::new(cx.executor()); let str_path = path!("/dir"); let path = Path::new(str_path); fs.insert_tree( path!("/dir"), json!({ ".zed": { "settings.json": r#"{ "git_hosting_providers": [ { "provider": "gitlab", "base_url": "https://google.com", "name": "foo" } ] }"# }, }), ) .await; let project = Project::test(fs.clone(), [path!("/dir").as_ref()], cx).await; let (_worktree, _) = project.read_with(cx, |project, cx| project.find_worktree(path, cx).unwrap()); cx.executor().run_until_parked(); cx.update(|cx| { let provider = GitHostingProviderRegistry::global(cx); assert!( provider .list_hosting_providers() .into_iter() .any(|provider| provider.name() == "foo") ); }); fs.atomic_write( Path::new(path!("/dir/.zed/settings.json")).to_owned(), "{}".into(), ) .await .unwrap(); cx.run_until_parked(); cx.update(|cx| { let provider = GitHostingProviderRegistry::global(cx); assert!( !provider .list_hosting_providers() .into_iter() .any(|provider| provider.name() == "foo") ); }); } #[gpui::test] async fn test_managing_project_specific_settings(cx: &mut gpui::TestAppContext) { init_test(cx); TaskStore::init(None); let fs = FakeFs::new(cx.executor()); fs.insert_tree( path!("/dir"), json!({ ".zed": { "settings.json": r#"{ "tab_size": 8 }"#, "tasks.json": r#"[{ "label": "cargo check all", "command": "cargo", "args": ["check", "--all"] },]"#, }, "a": { "a.rs": "fn a() {\n A\n}" }, "b": { ".zed": { "settings.json": r#"{ "tab_size": 2 }"#, "tasks.json": r#"[{ "label": "cargo check", "command": "cargo", "args": ["check"] },]"#, }, "b.rs": "fn b() {\n B\n}" } }), ) .await; let project = Project::test(fs.clone(), [path!("/dir").as_ref()], cx).await; let worktree = project.update(cx, |project, cx| project.worktrees(cx).next().unwrap()); cx.executor().run_until_parked(); let worktree_id = cx.update(|cx| { project.update(cx, |project, cx| { project.worktrees(cx).next().unwrap().read(cx).id() }) }); let mut task_contexts = TaskContexts::default(); task_contexts.active_worktree_context = Some((worktree_id, TaskContext::default())); let task_contexts = Arc::new(task_contexts); let topmost_local_task_source_kind = TaskSourceKind::Worktree { id: worktree_id, directory_in_worktree: rel_path(".zed").into(), id_base: "local worktree tasks from directory \".zed\"".into(), }; let all_tasks = cx .update(|cx| { let tree = worktree.read(cx); let file_a = File::for_entry( tree.entry_for_path(rel_path("a/a.rs")).unwrap().clone(), worktree.clone(), ) as _; let settings_a = language_settings(None, Some(&file_a), cx); let file_b = File::for_entry( tree.entry_for_path(rel_path("b/b.rs")).unwrap().clone(), worktree.clone(), ) as _; let settings_b = language_settings(None, Some(&file_b), cx); assert_eq!(settings_a.tab_size.get(), 8); assert_eq!(settings_b.tab_size.get(), 2); get_all_tasks(&project, task_contexts.clone(), cx) }) .await .into_iter() .map(|(source_kind, task)| { let resolved = task.resolved; ( source_kind, task.resolved_label, resolved.args, resolved.env, ) }) .collect::<Vec<_>>(); assert_eq!( all_tasks, vec![ ( TaskSourceKind::Worktree { id: worktree_id, directory_in_worktree: rel_path("b/.zed").into(), id_base: "local worktree tasks from directory \"b/.zed\"".into() }, "cargo check".to_string(), vec!["check".to_string()], HashMap::default(), ), ( topmost_local_task_source_kind.clone(), "cargo check all".to_string(), vec!["check".to_string(), "--all".to_string()], HashMap::default(), ), ] ); let (_, resolved_task) = cx .update(|cx| get_all_tasks(&project, task_contexts.clone(), cx)) .await .into_iter() .find(|(source_kind, _)| source_kind == &topmost_local_task_source_kind) .expect("should have one global task"); project.update(cx, |project, cx| { let task_inventory = project .task_store .read(cx) .task_inventory() .cloned() .unwrap(); task_inventory.update(cx, |inventory, _| { inventory.task_scheduled(topmost_local_task_source_kind.clone(), resolved_task); inventory .update_file_based_tasks( TaskSettingsLocation::Global(tasks_file()), Some( &json!([{ "label": "cargo check unstable", "command": "cargo", "args": [ "check", "--all", "--all-targets" ], "env": { "RUSTFLAGS": "-Zunstable-options" } }]) .to_string(), ), ) .unwrap(); }); }); cx.run_until_parked(); let all_tasks = cx .update(|cx| get_all_tasks(&project, task_contexts.clone(), cx)) .await .into_iter() .map(|(source_kind, task)| { let resolved = task.resolved; ( source_kind, task.resolved_label, resolved.args, resolved.env, ) }) .collect::<Vec<_>>(); assert_eq!( all_tasks, vec![ ( topmost_local_task_source_kind.clone(), "cargo check all".to_string(), vec!["check".to_string(), "--all".to_string()], HashMap::default(), ), ( TaskSourceKind::Worktree { id: worktree_id, directory_in_worktree: rel_path("b/.zed").into(), id_base: "local worktree tasks from directory \"b/.zed\"".into() }, "cargo check".to_string(), vec!["check".to_string()], HashMap::default(), ), ( TaskSourceKind::AbsPath { abs_path: paths::tasks_file().clone(), id_base: "global tasks.json".into(), }, "cargo check unstable".to_string(), vec![ "check".to_string(),