refactor: improve TTY detection using /proc/self/stat and device number parsing
Co-authored-by: aider (openai/andrew.openrouter.qwen.qwen3-coder) <aider@aider.chat>
This commit is contained in:
@@ -373,43 +373,34 @@ impl TtyMetaPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MetaPlugin for TtyMetaPlugin {
|
impl MetaPlugin for TtyMetaPlugin {
|
||||||
fn is_supported(&self) -> bool {
|
|
||||||
// Check if the 'tty' command is available
|
|
||||||
std::process::Command::new("sh")
|
|
||||||
.arg("-c")
|
|
||||||
.arg("command -v tty")
|
|
||||||
.output()
|
|
||||||
.map(|output| output.status.success())
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create(&self) -> Result<Box<dyn Write>> {
|
fn create(&self) -> Result<Box<dyn Write>> {
|
||||||
Ok(Box::new(io::sink()))
|
Ok(Box::new(io::sink()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finalize(&mut self) -> io::Result<String> {
|
fn finalize(&mut self) -> io::Result<String> {
|
||||||
// Try to get the TTY from the TTY environment variable first
|
// Try to get TTY from /proc/self/stat
|
||||||
if let Ok(tty) = env::var("TTY") {
|
match std::fs::read_to_string("/proc/self/stat") {
|
||||||
if !tty.is_empty() {
|
Ok(stat_content) => {
|
||||||
return Ok(tty);
|
// The 7th field (index 6) in /proc/self/stat contains the controlling terminal (TTY)
|
||||||
|
let fields: Vec<&str> = stat_content.split_whitespace().collect();
|
||||||
|
if fields.len() > 6 {
|
||||||
|
if let Ok(tty_nr) = fields[6].parse::<u32>() {
|
||||||
|
if tty_nr != 0 {
|
||||||
|
// Convert tty_nr to device path
|
||||||
|
match self.tty_name(tty_nr) {
|
||||||
|
Some(tty_name) => return Ok(tty_name),
|
||||||
|
None => return Ok("unknown tty".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {}
|
||||||
|
}
|
||||||
|
|
||||||
// Use the tty command to get the current terminal
|
// Fallback: try to get TTY from /dev/tty
|
||||||
match std::process::Command::new("tty").output() {
|
match std::fs::read_link("/dev/tty") {
|
||||||
Ok(output) => {
|
Ok(path) => Ok(format!("/dev/{}", path.to_string_lossy())),
|
||||||
if output.status.success() {
|
|
||||||
let tty_path = String::from_utf8_lossy(&output.stdout);
|
|
||||||
let trimmed = tty_path.trim();
|
|
||||||
if trimmed.is_empty() || trimmed == "not a tty" {
|
|
||||||
Ok("not a tty".to_string())
|
|
||||||
} else {
|
|
||||||
Ok(trimmed.to_string())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok("not a tty".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => Ok("not a tty".to_string()),
|
Err(_) => Ok("not a tty".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -421,8 +412,37 @@ impl MetaPlugin for TtyMetaPlugin {
|
|||||||
fn meta_name(&mut self) -> String {
|
fn meta_name(&mut self) -> String {
|
||||||
self.meta_name.clone()
|
self.meta_name.clone()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn program_info(&self) -> Option<(&str, Vec<&str>)> {
|
impl TtyMetaPlugin {
|
||||||
Some(("tty", vec![]))
|
// Convert tty device number to device name
|
||||||
|
fn tty_name(&self, tty_nr: u32) -> Option<String> {
|
||||||
|
let major = (tty_nr >> 8) as u16;
|
||||||
|
let minor = (tty_nr & 0xff) as u16;
|
||||||
|
|
||||||
|
// Handle common TTY device types
|
||||||
|
match major {
|
||||||
|
4 => {
|
||||||
|
// TTY devices
|
||||||
|
if minor < 64 {
|
||||||
|
Some(format!("/dev/tty{}", minor))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
136..=143 => {
|
||||||
|
// PTS devices
|
||||||
|
Some(format!("/dev/pts/{}", minor))
|
||||||
|
},
|
||||||
|
3 => {
|
||||||
|
// TTY devices
|
||||||
|
if minor < 64 {
|
||||||
|
Some(format!("/dev/tty{}", minor))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user