mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-29 08:02:12 +03:00
Add process info to terminal so that we can show the active process in the terminal tab title
Co-Authored-By: Mikayla Maki <mikayla@zed.dev>
This commit is contained in:
parent
7cbabc386f
commit
7497edaec2
21
Cargo.lock
generated
21
Cargo.lock
generated
@ -3251,6 +3251,15 @@ dependencies = [
|
|||||||
"minimal-lexical",
|
"minimal-lexical",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ntapi"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint"
|
name = "num-bigint"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
@ -3812,6 +3821,17 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "procinfo"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/zed-industries/wezterm?rev=40a7dbf93542fbe4178c2e4b4bd438126a6432b9#40a7dbf93542fbe4178c2e4b4bd438126a6432b9"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"ntapi",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "project"
|
name = "project"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -5358,6 +5378,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"mio-extras",
|
"mio-extras",
|
||||||
"ordered-float",
|
"ordered-float",
|
||||||
|
"procinfo",
|
||||||
"project",
|
"project",
|
||||||
"settings",
|
"settings",
|
||||||
"shellexpand",
|
"shellexpand",
|
||||||
|
@ -8,7 +8,8 @@ path = "src/terminal.rs"
|
|||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
alacritty_terminal = { git = "https://github.com/zed-industries/alacritty", rev = "4e1f0c6177975a040b37f942dfb0e723e46a9971"}
|
alacritty_terminal = { git = "https://github.com/zed-industries/alacritty", rev = "4e1f0c6177975a040b37f942dfb0e723e46a9971" }
|
||||||
|
procinfo = { git = "https://github.com/zed-industries/wezterm", rev = "40a7dbf93542fbe4178c2e4b4bd438126a6432b9", default-features = false }
|
||||||
editor = { path = "../editor" }
|
editor = { path = "../editor" }
|
||||||
util = { path = "../util" }
|
util = { path = "../util" }
|
||||||
gpui = { path = "../gpui" }
|
gpui = { path = "../gpui" }
|
||||||
|
@ -34,11 +34,14 @@ use mappings::mouse::{
|
|||||||
};
|
};
|
||||||
use modal::deploy_modal;
|
use modal::deploy_modal;
|
||||||
|
|
||||||
|
use procinfo::LocalProcessInfo;
|
||||||
use settings::{AlternateScroll, Settings, Shell, TerminalBlink};
|
use settings::{AlternateScroll, Settings, Shell, TerminalBlink};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, VecDeque},
|
collections::{HashMap, VecDeque},
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
ops::{Deref, RangeInclusive, Sub},
|
ops::{Deref, RangeInclusive, Sub},
|
||||||
|
os::unix::prelude::AsRawFd,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
@ -347,19 +350,8 @@ impl TerminalBuilder {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let shell_txt = {
|
let fd = pty.file().as_raw_fd();
|
||||||
match shell {
|
let shell_pid = pty.child().id();
|
||||||
Some(Shell::System) | None => {
|
|
||||||
let mut buf = [0; 1024];
|
|
||||||
let pw = alacritty_unix::get_pw_entry(&mut buf).unwrap();
|
|
||||||
pw.shell.to_string()
|
|
||||||
}
|
|
||||||
Some(Shell::Program(program)) => program,
|
|
||||||
Some(Shell::WithArguments { program, args }) => {
|
|
||||||
format!("{} {}", program, args.join(" "))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//And connect them together
|
//And connect them together
|
||||||
let event_loop = EventLoop::new(
|
let event_loop = EventLoop::new(
|
||||||
@ -378,8 +370,6 @@ impl TerminalBuilder {
|
|||||||
pty_tx: Notifier(pty_tx),
|
pty_tx: Notifier(pty_tx),
|
||||||
term,
|
term,
|
||||||
events: VecDeque::with_capacity(10), //Should never get this high.
|
events: VecDeque::with_capacity(10), //Should never get this high.
|
||||||
title: shell_txt.clone(),
|
|
||||||
default_title: shell_txt,
|
|
||||||
last_content: Default::default(),
|
last_content: Default::default(),
|
||||||
cur_size: initial_size,
|
cur_size: initial_size,
|
||||||
last_mouse: None,
|
last_mouse: None,
|
||||||
@ -387,6 +377,10 @@ impl TerminalBuilder {
|
|||||||
last_synced: Instant::now(),
|
last_synced: Instant::now(),
|
||||||
sync_task: None,
|
sync_task: None,
|
||||||
selection_head: None,
|
selection_head: None,
|
||||||
|
shell_fd: fd as u32,
|
||||||
|
shell_pid,
|
||||||
|
foreground_process_info: None,
|
||||||
|
breadcrumb_text: String::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(TerminalBuilder {
|
Ok(TerminalBuilder {
|
||||||
@ -495,8 +489,6 @@ pub struct Terminal {
|
|||||||
pty_tx: Notifier,
|
pty_tx: Notifier,
|
||||||
term: Arc<FairMutex<Term<ZedListener>>>,
|
term: Arc<FairMutex<Term<ZedListener>>>,
|
||||||
events: VecDeque<InternalEvent>,
|
events: VecDeque<InternalEvent>,
|
||||||
default_title: String,
|
|
||||||
title: String,
|
|
||||||
last_mouse: Option<(Point, AlacDirection)>,
|
last_mouse: Option<(Point, AlacDirection)>,
|
||||||
pub matches: Vec<RangeInclusive<Point>>,
|
pub matches: Vec<RangeInclusive<Point>>,
|
||||||
cur_size: TerminalSize,
|
cur_size: TerminalSize,
|
||||||
@ -504,18 +496,20 @@ pub struct Terminal {
|
|||||||
last_synced: Instant,
|
last_synced: Instant,
|
||||||
sync_task: Option<Task<()>>,
|
sync_task: Option<Task<()>>,
|
||||||
selection_head: Option<Point>,
|
selection_head: Option<Point>,
|
||||||
|
breadcrumb_text: String,
|
||||||
|
shell_pid: u32,
|
||||||
|
shell_fd: u32,
|
||||||
|
foreground_process_info: Option<LocalProcessInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Terminal {
|
impl Terminal {
|
||||||
fn process_event(&mut self, event: &AlacTermEvent, cx: &mut ModelContext<Self>) {
|
fn process_event(&mut self, event: &AlacTermEvent, cx: &mut ModelContext<Self>) {
|
||||||
match event {
|
match event {
|
||||||
AlacTermEvent::Title(title) => {
|
AlacTermEvent::Title(title) => {
|
||||||
self.title = title.to_string();
|
self.breadcrumb_text = title.to_string();
|
||||||
cx.emit(Event::TitleChanged);
|
|
||||||
}
|
}
|
||||||
AlacTermEvent::ResetTitle => {
|
AlacTermEvent::ResetTitle => {
|
||||||
self.title = self.default_title.clone();
|
self.breadcrumb_text = String::new();
|
||||||
cx.emit(Event::TitleChanged);
|
|
||||||
}
|
}
|
||||||
AlacTermEvent::ClipboardStore(_, data) => {
|
AlacTermEvent::ClipboardStore(_, data) => {
|
||||||
cx.write_to_clipboard(ClipboardItem::new(data.to_string()))
|
cx.write_to_clipboard(ClipboardItem::new(data.to_string()))
|
||||||
@ -705,11 +699,24 @@ impl Terminal {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
//Note that this ordering matters for event processing
|
//Note that the ordering of events matters for event processing
|
||||||
while let Some(e) = self.events.pop_front() {
|
while let Some(e) = self.events.pop_front() {
|
||||||
self.process_terminal_event(&e, &mut terminal, cx)
|
self.process_terminal_event(&e, &mut terminal, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(process_info) = self.compute_process_info() {
|
||||||
|
let should_emit_title_changed = self
|
||||||
|
.foreground_process_info
|
||||||
|
.as_ref()
|
||||||
|
.map(|old_info| {
|
||||||
|
process_info.cwd != old_info.cwd || process_info.name != old_info.name
|
||||||
|
})
|
||||||
|
.unwrap_or(true);
|
||||||
|
if should_emit_title_changed {
|
||||||
|
cx.emit(Event::TitleChanged)
|
||||||
|
}
|
||||||
|
self.foreground_process_info = Some(process_info.clone());
|
||||||
|
}
|
||||||
self.last_content = Self::make_content(&terminal);
|
self.last_content = Self::make_content(&terminal);
|
||||||
self.last_synced = Instant::now();
|
self.last_synced = Instant::now();
|
||||||
}
|
}
|
||||||
@ -953,6 +960,14 @@ impl Terminal {
|
|||||||
make_search_matches(&term, &searcher).collect()
|
make_search_matches(&term, &searcher).collect()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compute_process_info(&self) -> Option<LocalProcessInfo> {
|
||||||
|
let mut pid = unsafe { libc::tcgetpgrp(self.shell_fd as i32) };
|
||||||
|
if pid < 0 {
|
||||||
|
pid = self.shell_pid as i32;
|
||||||
|
}
|
||||||
|
LocalProcessInfo::with_root_pid(pid as u32)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Terminal {
|
impl Drop for Terminal {
|
||||||
|
@ -238,9 +238,23 @@ impl Item for TerminalContainer {
|
|||||||
cx: &gpui::AppContext,
|
cx: &gpui::AppContext,
|
||||||
) -> ElementBox {
|
) -> ElementBox {
|
||||||
let title = match &self.content {
|
let title = match &self.content {
|
||||||
TerminalContainerContent::Connected(connected) => {
|
TerminalContainerContent::Connected(connected) => connected
|
||||||
connected.read(cx).handle().read(cx).title.to_string()
|
.read(cx)
|
||||||
}
|
.handle()
|
||||||
|
.read(cx)
|
||||||
|
.foreground_process_info
|
||||||
|
.as_ref()
|
||||||
|
.map(|fpi| {
|
||||||
|
format!(
|
||||||
|
"{} - {}",
|
||||||
|
fpi.cwd
|
||||||
|
.file_name()
|
||||||
|
.map(|name| name.to_string_lossy().to_string())
|
||||||
|
.unwrap_or_default(),
|
||||||
|
fpi.name,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| "Terminal".to_string()),
|
||||||
TerminalContainerContent::Error(_) => "Terminal".to_string(),
|
TerminalContainerContent::Error(_) => "Terminal".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user