From 9533a9df1cbbe8e0c25d6ad61ca3c5bb12deda81 Mon Sep 17 00:00:00 2001 From: heinwol Date: Thu, 30 Nov 2023 11:34:33 +0300 Subject: [PATCH 1/4] feat: added automatic shell detection so when you run `, -s ` you'll be sent into the shell you were in, not into bash --- src/main.rs | 10 +++++--- src/shell.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 src/shell.rs diff --git a/src/main.rs b/src/main.rs index c88a90a..d9a8d19 100644 --- a/src/main.rs +++ b/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", "", "-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); } diff --git a/src/shell.rs b/src/shell.rs new file mode 100644 index 0000000..0519aad --- /dev/null +++ b/src/shell.rs @@ -0,0 +1,66 @@ +use std::{error::Error, fs}; + +type ResultDyn = Result>; + +const KNOWN_SHELLS: &[&str] = &[ + "ash", // + "bash", // + "elvish", // + "fish", // + "nu", // + "pwsh", // + "tcsh", // + "zsh", // +]; + +fn get_process_status_field(pid: u32, field: &str) -> ResultDyn { + 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 { + Ok(get_process_status_field(pid, &"PPid")?.parse::()?) +} + +fn get_process_name(pid: u32) -> ResultDyn { + Ok(get_process_status_field(pid, &"Name")?) +} + +fn get_all_parents_pid(pid: u32) -> ResultDyn> { + let mut res = Vec::::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 { + let parents = get_all_parents_pid(pid)?; + let parents_names: Result, _> = + 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()) +} From b4ba996deb0eb48da26ac1c91c92370df7a02a61 Mon Sep 17 00:00:00 2001 From: Artturin Date: Wed, 27 Dec 2023 18:51:29 +0200 Subject: [PATCH 2/4] check clippy --- flake.nix | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/flake.nix b/flake.nix index ae15927..7b3375a 100644 --- a/flake.nix +++ b/flake.nix @@ -32,6 +32,13 @@ ln -s $out/bin/comma $out/bin/, ''; }; + checkInputs = [ pkgs.rustPackages.clippy ]; + doCheck = true; + cargoTestCommands = x: + x ++ [ + ''cargo clippy --all --all-features --tests -- \ + -D warnings || true'' + ]; }; in utils.lib.eachDefaultSystem From 804d794dcb103317afdb2abd263996f15019393b Mon Sep 17 00:00:00 2001 From: Artturin Date: Wed, 27 Dec 2023 18:57:39 +0200 Subject: [PATCH 3/4] fix clippy pid <= removed https://rust-lang.github.io/rust-clippy/master/index.html#/absurd_extreme_comparisons --- src/index.rs | 4 ++-- src/shell.rs | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/index.rs b/src/index.rs index 48f7cef..7c39683 100644 --- a/src/index.rs +++ b/src/index.rs @@ -1,6 +1,6 @@ use std::{ os::unix::prelude::CommandExt, - path::PathBuf, + path::{PathBuf, Path}, process::Command, time::{Duration, SystemTime}, }; @@ -37,7 +37,7 @@ fn get_database_file() -> PathBuf { } /// Test whether the database is more than 30 days old -fn is_database_old(database_file: &std::path::PathBuf) -> bool { +fn is_database_old(database_file: &Path) -> bool { let Ok(metadata) = database_file.metadata() else { return false; }; diff --git a/src/shell.rs b/src/shell.rs index 0519aad..359ddfd 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -14,9 +14,6 @@ const KNOWN_SHELLS: &[&str] = &[ ]; fn get_process_status_field(pid: u32, field: &str) -> ResultDyn { - 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)?; @@ -26,18 +23,18 @@ fn get_process_status_field(pid: u32, field: &str) -> ResultDyn { .ok_or_else(|| format!("error parsing /proc/{pid:?}/status"))?; let field_contents = status_str .strip_prefix(&format!("{field}:")) - .ok_or_else(|| format!("bad parsing"))? + .ok_or_else(|| "bad parsing".to_string())? .trim() .to_owned(); Ok(field_contents) } fn get_parent_pid(pid: u32) -> ResultDyn { - Ok(get_process_status_field(pid, &"PPid")?.parse::()?) + Ok(get_process_status_field(pid, "PPid")?.parse::()?) } fn get_process_name(pid: u32) -> ResultDyn { - Ok(get_process_status_field(pid, &"Name")?) + get_process_status_field(pid, "Name") } fn get_all_parents_pid(pid: u32) -> ResultDyn> { From c51f7def961596f75acb79e1aa098b84e2cd00d4 Mon Sep 17 00:00:00 2001 From: Artturin Date: Wed, 27 Dec 2023 18:57:58 +0200 Subject: [PATCH 4/4] cargo fmt --- src/index.rs | 2 +- src/main.rs | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/index.rs b/src/index.rs index 7c39683..47b16a9 100644 --- a/src/index.rs +++ b/src/index.rs @@ -1,6 +1,6 @@ use std::{ os::unix::prelude::CommandExt, - path::{PathBuf, Path}, + path::{Path, PathBuf}, process::Command, time::{Duration, SystemTime}, }; diff --git a/src/main.rs b/src/main.rs index d9a8d19..9974e5f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ use std::{ env, io::Write, os::unix::prelude::CommandExt, - process::{Command, ExitCode, Stdio, self}, + process::{self, Command, ExitCode, Stdio}, }; use clap::crate_version; @@ -36,7 +36,13 @@ fn pick(picker: &str, derivations: &[&str]) -> Option { ) } -fn run_command_or_open_shell(use_channel: bool, choice: &str, command: &str, trail: &[String], nixpkgs_flake: &str) { +fn run_command_or_open_shell( + use_channel: bool, + choice: &str, + command: &str, + trail: &[String], + nixpkgs_flake: &str, +) { let mut run_cmd = Command::new("nix"); run_cmd.args([