go: Add runnables (#12110)

This adds support for runnables to Go.

It adds the following tasks:

- `go test $ZED_GO_PACKAGE -run $ZED_SYMBOL`
- `go test $ZED_GO_PACKAGE`
- `go test ./...`
- `go run $ZED_GO_PACKAGE` if it has a `main` function

Release Notes:

- Added built-in Go runnables and tasks that allow users to run Go test
functions, test packages, or run `main` functions.

Demo:



https://github.com/zed-industries/zed/assets/1185253/a6271d80-faf4-466a-bf63-efbec8fe6c35




https://github.com/zed-industries/zed/assets/1185253/92f2b616-7501-463d-b613-1ec1084ae0cd
This commit is contained in:
Thorsten Ball 2024-05-22 07:18:49 +02:00 committed by GitHub
parent e5b9e2044e
commit 8168ec2a28
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 104 additions and 3 deletions

View File

@ -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<OsString> {
@ -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<TaskVariables> {
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<TaskTemplates> {
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::*;

View File

@ -0,0 +1,9 @@
(
(function_declaration name: (_) @run
(#match? @run "^Test.*"))
) @go-test
(
(function_declaration name: (_) @run
(#eq? @run "main"))
) @go-main

View File

@ -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!(