Detailed changes
@@ -19,6 +19,13 @@
"JavaScript": {
"tab_size": 2,
"formatter": "prettier"
+ },
+ "Rust": {
+ "tasks": {
+ "variables": {
+ "RUST_DEFAULT_PACKAGE_RUN": "zed"
+ }
+ }
}
},
"formatter": "auto",
@@ -128,7 +128,14 @@
// The default number of lines to expand excerpts in the multibuffer by.
"expand_excerpt_lines": 3,
// Globs to match against file paths to determine if a file is private.
- "private_files": ["**/.env*", "**/*.pem", "**/*.key", "**/*.cert", "**/*.crt", "**/secrets.yml"],
+ "private_files": [
+ "**/.env*",
+ "**/*.pem",
+ "**/*.key",
+ "**/*.cert",
+ "**/*.crt",
+ "**/secrets.yml"
+ ],
// Whether to use additional LSP queries to format (and amend) the code after
// every "trigger" symbol input, defined by LSP server capabilities.
"use_on_type_format": true,
@@ -666,6 +673,10 @@
// "max_scroll_history_lines": 10000,
},
"code_actions_on_format": {},
+ /// Settings related to running tasks.
+ "tasks": {
+ "variables": {}
+ },
// An object whose keys are language names, and whose values
// are arrays of filenames or extensions of files that should
// use those languages.
@@ -8469,13 +8469,14 @@ impl Editor {
runnable: &mut Runnable,
cx: &WindowContext<'_>,
) -> Vec<(TaskSourceKind, TaskTemplate)> {
- let (inventory, worktree_id) = project.read_with(cx, |project, cx| {
- let worktree_id = project
+ let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
+ let (worktree_id, file) = project
.buffer_for_id(runnable.buffer)
.and_then(|buffer| buffer.read(cx).file())
- .map(|file| WorktreeId::from_usize(file.worktree_id()));
+ .map(|file| (WorktreeId::from_usize(file.worktree_id()), file.clone()))
+ .unzip();
- (project.task_inventory().clone(), worktree_id)
+ (project.task_inventory().clone(), worktree_id, file)
});
let inventory = inventory.read(cx);
@@ -8485,7 +8486,12 @@ impl Editor {
.flat_map(|tag| {
let tag = tag.0.clone();
inventory
- .list_tasks(Some(runnable.language.clone()), worktree_id)
+ .list_tasks(
+ file.clone(),
+ Some(runnable.language.clone()),
+ worktree_id,
+ cx,
+ )
.into_iter()
.filter(move |(_, template)| {
template.tags.iter().any(|source_tag| source_tag == &tag)
@@ -120,6 +120,8 @@ pub struct LanguageSettings {
pub code_actions_on_format: HashMap<String, bool>,
/// Whether to perform linked edits
pub linked_edits: bool,
+ /// Task configuration for this language.
+ pub tasks: LanguageTaskConfig,
}
impl LanguageSettings {
@@ -340,6 +342,10 @@ pub struct LanguageSettingsContent {
///
/// Default: true
pub linked_edits: Option<bool>,
+ /// Task configuration for this language.
+ ///
+ /// Default: {}
+ pub tasks: Option<LanguageTaskConfig>,
}
/// The contents of the inline completion settings.
@@ -546,6 +552,13 @@ fn scroll_debounce_ms() -> u64 {
50
}
+/// The task settings for a particular language.
+#[derive(Debug, Clone, Deserialize, PartialEq, Serialize, JsonSchema)]
+pub struct LanguageTaskConfig {
+ /// Extra task variables to set for a particular language.
+ pub variables: HashMap<String, String>,
+}
+
impl InlayHintSettings {
/// Returns the kinds of inlay hints that are enabled based on the settings.
pub fn enabled_inlay_hint_kinds(&self) -> HashSet<Option<InlayHintKind>> {
@@ -823,6 +836,7 @@ fn merge_settings(settings: &mut LanguageSettings, src: &LanguageSettingsContent
src.code_actions_on_format.clone(),
);
merge(&mut settings.linked_edits, src.linked_edits);
+ merge(&mut settings.tasks, src.tasks.clone());
merge(
&mut settings.preferred_line_length,
@@ -1,4 +1,4 @@
-use std::ops::Range;
+use std::{ops::Range, sync::Arc};
use crate::{Location, Runnable};
@@ -31,7 +31,11 @@ pub trait ContextProvider: Send + Sync {
}
/// Provides all tasks, associated with the current language.
- fn associated_tasks(&self) -> Option<TaskTemplates> {
+ fn associated_tasks(
+ &self,
+ _: Option<Arc<dyn crate::File>>,
+ _cx: &AppContext,
+ ) -> Option<TaskTemplates> {
None
}
}
@@ -1,7 +1,7 @@
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use futures::StreamExt;
-use gpui::{AsyncAppContext, Task};
+use gpui::{AppContext, AsyncAppContext, Task};
use http::github::latest_github_release;
pub use language::*;
use lazy_static::lazy_static;
@@ -501,7 +501,11 @@ impl ContextProvider for GoContextProvider {
))
}
- fn associated_tasks(&self) -> Option<TaskTemplates> {
+ fn associated_tasks(
+ &self,
+ _: Option<Arc<dyn language::File>>,
+ _: &AppContext,
+ ) -> Option<TaskTemplates> {
Some(TaskTemplates(vec![
TaskTemplate {
label: format!(
@@ -1,5 +1,6 @@
use anyhow::Result;
use async_trait::async_trait;
+use gpui::AppContext;
use language::{ContextProvider, LanguageServerName, LspAdapter, LspAdapterDelegate};
use lsp::LanguageServerBinary;
use node_runtime::NodeRuntime;
@@ -220,7 +221,11 @@ impl ContextProvider for PythonContextProvider {
Ok(task::TaskVariables::from_iter([unittest_target]))
}
- fn associated_tasks(&self) -> Option<TaskTemplates> {
+ fn associated_tasks(
+ &self,
+ _: Option<Arc<dyn language::File>>,
+ _: &AppContext,
+ ) -> Option<TaskTemplates> {
Some(TaskTemplates(vec![
TaskTemplate {
label: "execute selection".to_owned(),
@@ -2,9 +2,10 @@ use anyhow::{anyhow, bail, Context, Result};
use async_compression::futures::bufread::GzipDecoder;
use async_trait::async_trait;
use futures::{io::BufReader, StreamExt};
-use gpui::AsyncAppContext;
+use gpui::{AppContext, AsyncAppContext};
use http::github::{latest_github_release, GitHubLspBinaryVersion};
pub use language::*;
+use language_settings::all_language_settings;
use lazy_static::lazy_static;
use lsp::LanguageServerBinary;
use project::project_settings::{BinarySettings, ProjectSettings};
@@ -407,7 +408,22 @@ impl ContextProvider for RustContextProvider {
Ok(TaskVariables::default())
}
- fn associated_tasks(&self) -> Option<TaskTemplates> {
+ fn associated_tasks(
+ &self,
+ file: Option<Arc<dyn language::File>>,
+ cx: &AppContext,
+ ) -> Option<TaskTemplates> {
+ const DEFAULT_RUN_NAME_STR: &'static str = "RUST_DEFAULT_PACKAGE_RUN";
+ let package_to_run = all_language_settings(file.as_ref(), cx)
+ .language(Some("Rust"))
+ .tasks
+ .variables
+ .get(DEFAULT_RUN_NAME_STR);
+ let run_task_args = if let Some(package_to_run) = package_to_run {
+ vec!["run".into(), "-p".into(), package_to_run.clone()]
+ } else {
+ vec!["run".into()]
+ };
Some(TaskTemplates(vec![
TaskTemplate {
label: format!(
@@ -501,7 +517,7 @@ impl ContextProvider for RustContextProvider {
TaskTemplate {
label: "cargo run".into(),
command: "cargo".into(),
- args: vec!["run".into()],
+ args: run_task_args,
cwd: Some("$ZED_DIRNAME".to_owned()),
..TaskTemplate::default()
},
@@ -10861,12 +10861,19 @@ impl Project {
cx: &mut ModelContext<Self>,
) -> Task<Result<Vec<(TaskSourceKind, TaskTemplate)>>> {
if self.is_local() {
- let language = location
- .and_then(|location| location.buffer.read(cx).language_at(location.range.start));
+ let (file, language) = location
+ .map(|location| {
+ let buffer = location.buffer.read(cx);
+ (
+ buffer.file().cloned(),
+ buffer.language_at(location.range.start),
+ )
+ })
+ .unwrap_or_default();
Task::ready(Ok(self
.task_inventory()
.read(cx)
- .list_tasks(language, worktree)))
+ .list_tasks(file, language, worktree, cx)))
} else if let Some(project_id) = self
.remote_id()
.filter(|_| self.ssh_connection_string(cx).is_some())
@@ -15,7 +15,7 @@ use futures::{
};
use gpui::{AppContext, Context, Model, ModelContext, Task};
use itertools::Itertools;
-use language::{ContextProvider, Language, Location};
+use language::{ContextProvider, File, Language, Location};
use task::{
static_source::StaticSource, ResolvedTask, TaskContext, TaskId, TaskTemplate, TaskTemplates,
TaskVariables, VariableName,
@@ -155,14 +155,16 @@ impl Inventory {
/// returns all task templates with their source kinds, in no specific order.
pub fn list_tasks(
&self,
+ file: Option<Arc<dyn File>>,
language: Option<Arc<Language>>,
worktree: Option<WorktreeId>,
+ cx: &AppContext,
) -> Vec<(TaskSourceKind, TaskTemplate)> {
let task_source_kind = language.as_ref().map(|language| TaskSourceKind::Language {
name: language.name(),
});
let language_tasks = language
- .and_then(|language| language.context_provider()?.associated_tasks())
+ .and_then(|language| language.context_provider()?.associated_tasks(file, cx))
.into_iter()
.flat_map(|tasks| tasks.0.into_iter())
.flat_map(|task| Some((task_source_kind.as_ref()?, task)));
@@ -207,8 +209,11 @@ impl Inventory {
let task_source_kind = language.as_ref().map(|language| TaskSourceKind::Language {
name: language.name(),
});
+ let file = location
+ .as_ref()
+ .and_then(|location| location.buffer.read(cx).file().cloned());
let language_tasks = language
- .and_then(|language| language.context_provider()?.associated_tasks())
+ .and_then(|language| language.context_provider()?.associated_tasks(file, cx))
.into_iter()
.flat_map(|tasks| tasks.0.into_iter())
.flat_map(|task| Some((task_source_kind.as_ref()?, task)));
@@ -471,9 +476,9 @@ mod test_inventory {
worktree: Option<WorktreeId>,
cx: &mut TestAppContext,
) -> Vec<String> {
- inventory.update(cx, |inventory, _| {
+ inventory.update(cx, |inventory, cx| {
inventory
- .list_tasks(None, worktree)
+ .list_tasks(None, None, worktree, cx)
.into_iter()
.map(|(_, task)| task.label)
.sorted()
@@ -486,9 +491,9 @@ mod test_inventory {
task_name: &str,
cx: &mut TestAppContext,
) {
- inventory.update(cx, |inventory, _| {
+ inventory.update(cx, |inventory, cx| {
let (task_source_kind, task) = inventory
- .list_tasks(None, None)
+ .list_tasks(None, None, None, cx)
.into_iter()
.find(|(_, task)| task.label == task_name)
.unwrap_or_else(|| panic!("Failed to find task with name {task_name}"));
@@ -639,7 +644,11 @@ impl ContextProviderWithTasks {
}
impl ContextProvider for ContextProviderWithTasks {
- fn associated_tasks(&self) -> Option<TaskTemplates> {
+ fn associated_tasks(
+ &self,
+ _: Option<Arc<dyn language::File>>,
+ _: &AppContext,
+ ) -> Option<TaskTemplates> {
Some(self.templates.clone())
}
}