mirror of
https://github.com/rust-lang/rustlings.git
synced 2026-05-15 17:58:44 +00:00
Check if editor program exists before choosing it
This commit is contained in:
parent
695f927893
commit
b5fbf59c0c
@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Automatically open the current file if Rustlings is running in a VS Code terminal
|
||||||
|
- Automatically open the current file with `$EDITOR` in a new pane if Rustlings is running in [Zellij](https://zellij.dev)
|
||||||
|
- New argument `--edit-cmd` to communicate with an editor running in a different process to open the current exercise
|
||||||
- Show the file link of the current exercise when running `rustlings hint` and `rustlings reset`
|
- Show the file link of the current exercise when running `rustlings hint` and `rustlings reset`
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@ -69,6 +69,7 @@ impl AppState {
|
|||||||
exercise_infos: Vec<ExerciseInfo>,
|
exercise_infos: Vec<ExerciseInfo>,
|
||||||
final_message: &'static str,
|
final_message: &'static str,
|
||||||
editor: Option<Editor>,
|
editor: Option<Editor>,
|
||||||
|
vs_code_term: bool,
|
||||||
) -> Result<(Self, StateFileStatus)> {
|
) -> Result<(Self, StateFileStatus)> {
|
||||||
let cmd_runner = CmdRunner::build()?;
|
let cmd_runner = CmdRunner::build()?;
|
||||||
let mut state_file = OpenOptions::new()
|
let mut state_file = OpenOptions::new()
|
||||||
@ -178,7 +179,7 @@ impl AppState {
|
|||||||
official_exercises: !Path::new("info.toml").exists(),
|
official_exercises: !Path::new("info.toml").exists(),
|
||||||
cmd_runner,
|
cmd_runner,
|
||||||
// VS Code has its own file link handling
|
// VS Code has its own file link handling
|
||||||
emit_file_links: !matches!(editor, Some(Editor::VSCode)),
|
emit_file_links: !vs_code_term,
|
||||||
editor,
|
editor,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
|
borrow::Cow,
|
||||||
env,
|
env,
|
||||||
process::{Command, Stdio},
|
process::{Command, Stdio},
|
||||||
thread::{self, JoinHandle},
|
thread::{self, JoinHandle},
|
||||||
@ -28,16 +29,29 @@ fn run_cmd(cmd: &mut Command) -> Result<Vec<u8>> {
|
|||||||
Ok(output.stdout)
|
Ok(output.stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn program_exists(program: &str) -> bool {
|
||||||
|
Command::new(program)
|
||||||
|
.arg("--version")
|
||||||
|
.stdin(Stdio::null())
|
||||||
|
.stdout(Stdio::null())
|
||||||
|
.stderr(Stdio::null())
|
||||||
|
.status()
|
||||||
|
.is_ok_and(|status| status.success())
|
||||||
|
}
|
||||||
|
|
||||||
pub enum Editor {
|
pub enum Editor {
|
||||||
VSCode,
|
Cmd(Cow<'static, str>, Vec<String>),
|
||||||
Cmd(String, Vec<String>),
|
|
||||||
Zellij(Option<(String, u32, usize)>),
|
Zellij(Option<(String, u32, usize)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Editor {
|
impl Editor {
|
||||||
pub fn new(cmd: Option<String>) -> Result<Option<Self>> {
|
pub fn new(cmd: Option<String>, vs_code_term: bool) -> Result<Option<Self>> {
|
||||||
if env::var_os("TERM_PROGRAM").is_some_and(|v| v == "vscode") {
|
if vs_code_term {
|
||||||
return Ok(Some(Self::VSCode));
|
for program in ["code", "codium"] {
|
||||||
|
if program_exists(program) {
|
||||||
|
return Ok(Some(Self::Cmd(Cow::Borrowed(program), Vec::new())));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(cmd) = cmd {
|
if let Some(cmd) = cmd {
|
||||||
@ -47,10 +61,10 @@ impl Editor {
|
|||||||
if shlex.had_error {
|
if shlex.had_error {
|
||||||
bail!("Failed to parse the command in `--edit-cmd`");
|
bail!("Failed to parse the command in `--edit-cmd`");
|
||||||
}
|
}
|
||||||
return Ok(Some(Self::Cmd(program, args)));
|
return Ok(Some(Self::Cmd(Cow::Owned(program), args)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if env::var_os("ZELLIJ").is_some() {
|
if env::var_os("ZELLIJ").is_some() && program_exists("zellij") {
|
||||||
return Ok(Some(Self::Zellij(None)));
|
return Ok(Some(Self::Zellij(None)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,11 +79,8 @@ impl Editor {
|
|||||||
let handle = thread::Builder::new()
|
let handle = thread::Builder::new()
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
match &mut self {
|
match &mut self {
|
||||||
Editor::VSCode => {
|
|
||||||
run_cmd(Command::new("code").arg(exercise_path))?;
|
|
||||||
}
|
|
||||||
Editor::Cmd(program, args) => {
|
Editor::Cmd(program, args) => {
|
||||||
run_cmd(Command::new(program).args(args).arg(exercise_path))?;
|
run_cmd(Command::new(&**program).args(args).arg(exercise_path))?;
|
||||||
}
|
}
|
||||||
Editor::Zellij(open_pane) => {
|
Editor::Zellij(open_pane) => {
|
||||||
if let Some((pane_id_str, pane_id, open_exercise_ind)) = open_pane {
|
if let Some((pane_id_str, pane_id, open_exercise_ind)) = open_pane {
|
||||||
@ -105,7 +116,7 @@ impl Editor {
|
|||||||
|
|
||||||
pub fn close(&mut self) -> Result<()> {
|
pub fn close(&mut self) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Editor::VSCode | Editor::Cmd(_, _) => (),
|
Editor::Cmd(_, _) => (),
|
||||||
Editor::Zellij(open_pane) => {
|
Editor::Zellij(open_pane) => {
|
||||||
if let Some((pane_id_str, _, _)) = open_pane.take() {
|
if let Some((pane_id_str, _, _)) = open_pane.take() {
|
||||||
zellij::close_pane(&pane_id_str)?;
|
zellij::close_pane(&pane_id_str)?;
|
||||||
|
|||||||
@ -2,6 +2,7 @@ use anyhow::{Context, Result, bail};
|
|||||||
use app_state::StateFileStatus;
|
use app_state::StateFileStatus;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use std::{
|
use std::{
|
||||||
|
env,
|
||||||
io::{self, IsTerminal, Write},
|
io::{self, IsTerminal, Write},
|
||||||
path::Path,
|
path::Path,
|
||||||
process::ExitCode,
|
process::ExitCode,
|
||||||
@ -60,11 +61,13 @@ fn main() -> Result<ExitCode> {
|
|||||||
bail!(FORMAT_VERSION_HIGHER_ERR);
|
bail!(FORMAT_VERSION_HIGHER_ERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
let editor = Editor::new(args.edit_cmd)?;
|
let vs_code_term = env::var_os("TERM_PROGRAM").is_some_and(|v| v == "vscode");
|
||||||
|
let editor = Editor::new(args.edit_cmd, vs_code_term)?;
|
||||||
let (mut app_state, state_file_status) = AppState::new(
|
let (mut app_state, state_file_status) = AppState::new(
|
||||||
info_file.exercises,
|
info_file.exercises,
|
||||||
info_file.final_message.unwrap_or_default(),
|
info_file.final_message.unwrap_or_default(),
|
||||||
editor,
|
editor,
|
||||||
|
vs_code_term,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Show the welcome message if the state file doesn't exist yet.
|
// Show the welcome message if the state file doesn't exist yet.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user