mirror of
https://github.com/nix-community/comma.git
synced 2024-10-05 15:57:55 +03:00
feat: added automatic shell detection
so when you run `, -s <pname>` you'll be sent into the shell you were in, not into bash
This commit is contained in:
parent
5ecd5024b4
commit
9533a9df1c
10
src/main.rs
10
src/main.rs
@ -1,9 +1,10 @@
|
||||
mod index;
|
||||
mod shell;
|
||||
use std::{
|
||||
env,
|
||||
io::Write,
|
||||
os::unix::prelude::CommandExt,
|
||||
process::{Command, ExitCode, Stdio},
|
||||
process::{Command, ExitCode, Stdio, self},
|
||||
};
|
||||
|
||||
use clap::crate_version;
|
||||
@ -52,7 +53,9 @@ fn run_command_or_open_shell(use_channel: bool, choice: &str, command: &str, tra
|
||||
|
||||
if !command.is_empty() {
|
||||
run_cmd.args(["--command", command]);
|
||||
run_cmd.args(trail);
|
||||
if !trail.is_empty() {
|
||||
run_cmd.args(trail);
|
||||
}
|
||||
};
|
||||
|
||||
run_cmd.exec();
|
||||
@ -132,7 +135,8 @@ fn main() -> ExitCode {
|
||||
.args(["-f", "<nixpkgs>", "-iA", choice.rsplit('.').last().unwrap()])
|
||||
.exec();
|
||||
} else if args.shell {
|
||||
run_command_or_open_shell(use_channel, &choice, "", &[String::new()], &args.nixpkgs_flake);
|
||||
let shell_cmd = shell::select_shell_from_pid(process::id()).unwrap_or("bash".into());
|
||||
run_command_or_open_shell(use_channel, &choice, &shell_cmd, &[], &args.nixpkgs_flake);
|
||||
} else {
|
||||
run_command_or_open_shell(use_channel, &choice, command, trail, &args.nixpkgs_flake);
|
||||
}
|
||||
|
66
src/shell.rs
Normal file
66
src/shell.rs
Normal file
@ -0,0 +1,66 @@
|
||||
use std::{error::Error, fs};
|
||||
|
||||
type ResultDyn<T> = Result<T, Box<dyn Error>>;
|
||||
|
||||
const KNOWN_SHELLS: &[&str] = &[
|
||||
"ash", //
|
||||
"bash", //
|
||||
"elvish", //
|
||||
"fish", //
|
||||
"nu", //
|
||||
"pwsh", //
|
||||
"tcsh", //
|
||||
"zsh", //
|
||||
];
|
||||
|
||||
fn get_process_status_field(pid: u32, field: &str) -> ResultDyn<String> {
|
||||
if pid <= 0 {
|
||||
return Err(format!("invalid pid: {pid}").into());
|
||||
};
|
||||
let status_bytes =
|
||||
fs::read(format!("/proc/{pid:?}/status")).map_err(|_| format!("no such pid: {pid:?}"))?;
|
||||
let status_str = String::from_utf8(status_bytes)?;
|
||||
let status_str = status_str
|
||||
.split('\n')
|
||||
.find(|&x| x.starts_with(field))
|
||||
.ok_or_else(|| format!("error parsing /proc/{pid:?}/status"))?;
|
||||
let field_contents = status_str
|
||||
.strip_prefix(&format!("{field}:"))
|
||||
.ok_or_else(|| format!("bad parsing"))?
|
||||
.trim()
|
||||
.to_owned();
|
||||
Ok(field_contents)
|
||||
}
|
||||
|
||||
fn get_parent_pid(pid: u32) -> ResultDyn<u32> {
|
||||
Ok(get_process_status_field(pid, &"PPid")?.parse::<u32>()?)
|
||||
}
|
||||
|
||||
fn get_process_name(pid: u32) -> ResultDyn<String> {
|
||||
Ok(get_process_status_field(pid, &"Name")?)
|
||||
}
|
||||
|
||||
fn get_all_parents_pid(pid: u32) -> ResultDyn<Vec<u32>> {
|
||||
let mut res = Vec::<u32>::new();
|
||||
let mut pid = pid;
|
||||
loop {
|
||||
match get_parent_pid(pid) {
|
||||
Ok(parent_id) if parent_id != 0 => {
|
||||
res.push(parent_id);
|
||||
pid = parent_id;
|
||||
}
|
||||
Ok(_) => return Ok(res),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_shell_from_pid(pid: u32) -> ResultDyn<String> {
|
||||
let parents = get_all_parents_pid(pid)?;
|
||||
let parents_names: Result<Vec<_>, _> =
|
||||
parents.iter().map(|&pid| get_process_name(pid)).collect();
|
||||
let shell = parents_names?
|
||||
.into_iter()
|
||||
.find(|x| KNOWN_SHELLS.contains(&x.as_str()));
|
||||
shell.ok_or("no shell found".into())
|
||||
}
|
Loading…
Reference in New Issue
Block a user