python: Add task for running modules (#26462)
Closes #26460 I am new to contributing to Zed (and pretty new to Rust in general). I'm not too familiar with code style, guidelines etc. so please feel free to suggest changes/improvements. This PR adds a run icon to Python files that have a "main" function: ```python if __name__ == "__main__": ... ``` In addition to the gutter icon, there is now also an extra task in the command palette "run module". Release Notes: - Added detection for runnable Python modules - Added Python-specific task to run a Python file as a module from inside the project's scope --------- Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
This commit is contained in:
parent
152432f1d9
commit
1574a3a2fd
2 changed files with 51 additions and 1 deletions
|
@ -348,6 +348,10 @@ const PYTHON_TEST_TARGET_TASK_VARIABLE: VariableName =
|
||||||
|
|
||||||
const PYTHON_ACTIVE_TOOLCHAIN_PATH: VariableName =
|
const PYTHON_ACTIVE_TOOLCHAIN_PATH: VariableName =
|
||||||
VariableName::Custom(Cow::Borrowed("PYTHON_ACTIVE_ZED_TOOLCHAIN"));
|
VariableName::Custom(Cow::Borrowed("PYTHON_ACTIVE_ZED_TOOLCHAIN"));
|
||||||
|
|
||||||
|
const PYTHON_MODULE_NAME_TASK_VARIABLE: VariableName =
|
||||||
|
VariableName::Custom(Cow::Borrowed("PYTHON_MODULE_NAME"));
|
||||||
|
|
||||||
impl ContextProvider for PythonContextProvider {
|
impl ContextProvider for PythonContextProvider {
|
||||||
fn build_context(
|
fn build_context(
|
||||||
&self,
|
&self,
|
||||||
|
@ -362,7 +366,9 @@ impl ContextProvider for PythonContextProvider {
|
||||||
TestRunner::PYTEST => self.build_pytest_target(variables),
|
TestRunner::PYTEST => self.build_pytest_target(variables),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let module_target = self.build_module_target(variables);
|
||||||
let worktree_id = location.buffer.read(cx).file().map(|f| f.worktree_id(cx));
|
let worktree_id = location.buffer.read(cx).file().map(|f| f.worktree_id(cx));
|
||||||
|
|
||||||
cx.spawn(async move |cx| {
|
cx.spawn(async move |cx| {
|
||||||
let active_toolchain = if let Some(worktree_id) = worktree_id {
|
let active_toolchain = if let Some(worktree_id) = worktree_id {
|
||||||
toolchains
|
toolchains
|
||||||
|
@ -376,8 +382,12 @@ impl ContextProvider for PythonContextProvider {
|
||||||
String::from("python3")
|
String::from("python3")
|
||||||
};
|
};
|
||||||
let toolchain = (PYTHON_ACTIVE_TOOLCHAIN_PATH, active_toolchain);
|
let toolchain = (PYTHON_ACTIVE_TOOLCHAIN_PATH, active_toolchain);
|
||||||
|
|
||||||
Ok(task::TaskVariables::from_iter(
|
Ok(task::TaskVariables::from_iter(
|
||||||
test_target.into_iter().chain([toolchain]),
|
test_target
|
||||||
|
.into_iter()
|
||||||
|
.chain(module_target.into_iter())
|
||||||
|
.chain([toolchain]),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -407,6 +417,17 @@ impl ContextProvider for PythonContextProvider {
|
||||||
args: vec![VariableName::File.template_value_with_whitespace()],
|
args: vec![VariableName::File.template_value_with_whitespace()],
|
||||||
..TaskTemplate::default()
|
..TaskTemplate::default()
|
||||||
},
|
},
|
||||||
|
// Execute a file as module
|
||||||
|
TaskTemplate {
|
||||||
|
label: format!("run module '{}'", VariableName::File.template_value()),
|
||||||
|
command: PYTHON_ACTIVE_TOOLCHAIN_PATH.template_value(),
|
||||||
|
args: vec![
|
||||||
|
"-m".to_owned(),
|
||||||
|
PYTHON_MODULE_NAME_TASK_VARIABLE.template_value(),
|
||||||
|
],
|
||||||
|
tags: vec!["python-module-main-method".to_owned()],
|
||||||
|
..TaskTemplate::default()
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
tasks.extend(match test_runner {
|
tasks.extend(match test_runner {
|
||||||
|
@ -544,6 +565,19 @@ impl PythonContextProvider {
|
||||||
|
|
||||||
Some((PYTHON_TEST_TARGET_TASK_VARIABLE.clone(), pytest_target_str))
|
Some((PYTHON_TEST_TARGET_TASK_VARIABLE.clone(), pytest_target_str))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_module_target(
|
||||||
|
&self,
|
||||||
|
variables: &task::TaskVariables,
|
||||||
|
) -> Result<(VariableName, String)> {
|
||||||
|
let python_module_name = python_module_name_from_relative_path(
|
||||||
|
variables.get(&VariableName::RelativeFile).unwrap_or(""),
|
||||||
|
);
|
||||||
|
|
||||||
|
let module_target = (PYTHON_MODULE_NAME_TASK_VARIABLE.clone(), python_module_name);
|
||||||
|
|
||||||
|
Ok(module_target)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn python_module_name_from_relative_path(relative_path: &str) -> String {
|
fn python_module_name_from_relative_path(relative_path: &str) -> String {
|
||||||
|
|
|
@ -82,3 +82,19 @@
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
; module main method
|
||||||
|
(
|
||||||
|
(module
|
||||||
|
(if_statement
|
||||||
|
condition: (comparison_operator
|
||||||
|
(identifier) @run @_lhs
|
||||||
|
operators: "=="
|
||||||
|
(string) @_rhs
|
||||||
|
)
|
||||||
|
(#eq? @_lhs "__name__")
|
||||||
|
(#match? @_rhs "^[\"']__main__[\"']$")
|
||||||
|
(#set! tag python-module-main-method)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue