diff --git a/crates/languages/src/go.rs b/crates/languages/src/go.rs index d3a562b469..85c92323c4 100644 --- a/crates/languages/src/go.rs +++ b/crates/languages/src/go.rs @@ -13,15 +13,17 @@ use settings::Settings; use smol::{fs, process}; use std::{ any::Any, + borrow::Cow, ffi::{OsStr, OsString}, ops::Range, - path::PathBuf, + path::{Path, PathBuf}, str, sync::{ atomic::{AtomicBool, Ordering::SeqCst}, Arc, }, }; +use task::{TaskTemplate, TaskTemplates, TaskVariables, VariableName}; use util::{fs::remove_matching, maybe, ResultExt}; fn server_binary_arguments() -> Vec { @@ -438,6 +440,93 @@ fn adjust_runs( runs } +pub(crate) struct GoContextProvider; + +const GO_PACKAGE_TASK_VARIABLE: VariableName = VariableName::Custom(Cow::Borrowed("GO_PACKAGE")); + +impl ContextProvider for GoContextProvider { + fn build_context( + &self, + worktree_abs_path: Option<&Path>, + location: &Location, + cx: &mut gpui::AppContext, + ) -> Result { + let local_abs_path = location + .buffer + .read(cx) + .file() + .and_then(|file| Some(file.as_local()?.abs_path(cx))); + + Ok( + if let Some(buffer_dir) = local_abs_path + .as_deref() + .and_then(|local_abs_path| local_abs_path.parent()) + { + // Prefer the relative form `./my-nested-package/is-here` over + // absolute path, because it's more readable in the modal, but + // the absolute path also works. + let package_name = worktree_abs_path + .and_then(|worktree_abs_path| buffer_dir.strip_prefix(worktree_abs_path).ok()) + .map(|relative_pkg_dir| { + if relative_pkg_dir.as_os_str().is_empty() { + ".".into() + } else { + format!("./{}", relative_pkg_dir.to_string_lossy()) + } + }) + .unwrap_or_else(|| format!("{}", buffer_dir.to_string_lossy())); + + TaskVariables::from_iter(Some(( + GO_PACKAGE_TASK_VARIABLE.clone(), + package_name.to_string(), + ))) + } else { + TaskVariables::default() + }, + ) + } + + fn associated_tasks(&self) -> Option { + Some(TaskTemplates(vec![ + TaskTemplate { + label: format!( + "go test {} -run {}", + GO_PACKAGE_TASK_VARIABLE.template_value(), + VariableName::Symbol.template_value(), + ), + command: "go".into(), + args: vec![ + "test".into(), + GO_PACKAGE_TASK_VARIABLE.template_value(), + "-run".into(), + VariableName::Symbol.template_value(), + ], + tags: vec!["go-test".to_owned()], + ..TaskTemplate::default() + }, + TaskTemplate { + label: format!("go test {}", GO_PACKAGE_TASK_VARIABLE.template_value()), + command: "go".into(), + args: vec!["test".into(), GO_PACKAGE_TASK_VARIABLE.template_value()], + ..TaskTemplate::default() + }, + TaskTemplate { + label: "go test ./...".into(), + command: "go".into(), + args: vec!["test".into(), "./...".into()], + ..TaskTemplate::default() + }, + TaskTemplate { + label: format!("go run {}", GO_PACKAGE_TASK_VARIABLE.template_value(),), + command: "go".into(), + args: vec!["run".into(), GO_PACKAGE_TASK_VARIABLE.template_value()], + tags: vec!["go-main".to_owned()], + ..TaskTemplate::default() + }, + ])) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/languages/src/go/runnables.scm b/crates/languages/src/go/runnables.scm new file mode 100644 index 0000000000..a412ecd87c --- /dev/null +++ b/crates/languages/src/go/runnables.scm @@ -0,0 +1,9 @@ +( + (function_declaration name: (_) @run + (#match? @run "^Test.*")) +) @go-test + +( + (function_declaration name: (_) @run + (#eq? @run "main")) +) @go-main diff --git a/crates/languages/src/lib.rs b/crates/languages/src/lib.rs index 6927ced42e..726d130035 100644 --- a/crates/languages/src/lib.rs +++ b/crates/languages/src/lib.rs @@ -8,7 +8,10 @@ use smol::stream::StreamExt; use std::{str, sync::Arc}; use util::{asset_str, ResultExt}; -use crate::{bash::bash_task_context, python::python_task_context, rust::RustContextProvider}; +use crate::{ + bash::bash_task_context, go::GoContextProvider, python::python_task_context, + rust::RustContextProvider, +}; mod bash; mod c; @@ -103,7 +106,7 @@ pub fn init( "css", vec![Arc::new(css::CssLspAdapter::new(node_runtime.clone())),] ); - language!("go", vec![Arc::new(go::GoLspAdapter)]); + language!("go", vec![Arc::new(go::GoLspAdapter)], GoContextProvider); language!("gomod"); language!("gowork"); language!(