@@ -41,7 +41,7 @@ use mappings::mouse::{
use collections::{HashMap, VecDeque};
use futures::StreamExt;
-use pty_info::PtyProcessInfo;
+use pty_info::{ProcessIdGetter, PtyProcessInfo};
use serde::{Deserialize, Serialize};
use settings::Settings;
use smol::channel::{Receiver, Sender};
@@ -340,27 +340,74 @@ pub struct TerminalBuilder {
impl TerminalBuilder {
pub fn new_display_only(
- working_directory: Option<PathBuf>,
cursor_shape: CursorShape,
alternate_scroll: AlternateScroll,
max_scroll_history_lines: Option<usize>,
window_id: u64,
- cx: &App,
) -> Result<TerminalBuilder> {
- Self::new(
- working_directory,
- None,
- Shell::System,
- HashMap::default(),
- cursor_shape,
- alternate_scroll,
- max_scroll_history_lines,
- false,
- window_id,
- None,
- cx,
- Vec::new(),
- )
+ // Create a display-only terminal (no actual PTY).
+ let default_cursor_style = AlacCursorStyle::from(cursor_shape);
+ let scrolling_history = max_scroll_history_lines
+ .unwrap_or(DEFAULT_SCROLL_HISTORY_LINES)
+ .min(MAX_SCROLL_HISTORY_LINES);
+ let config = Config {
+ scrolling_history,
+ default_cursor_style,
+ ..Config::default()
+ };
+
+ let (events_tx, events_rx) = unbounded();
+ let mut term = Term::new(
+ config.clone(),
+ &TerminalBounds::default(),
+ ZedListener(events_tx),
+ );
+
+ if let AlternateScroll::Off = alternate_scroll {
+ term.unset_private_mode(PrivateMode::Named(NamedPrivateMode::AlternateScroll));
+ }
+
+ let term = Arc::new(FairMutex::new(term));
+
+ let terminal = Terminal {
+ task: None,
+ terminal_type: TerminalType::DisplayOnly,
+ completion_tx: None,
+ term,
+ term_config: config,
+ title_override: None,
+ events: VecDeque::with_capacity(10),
+ last_content: Default::default(),
+ last_mouse: None,
+ matches: Vec::new(),
+ selection_head: None,
+ breadcrumb_text: String::new(),
+ scroll_px: px(0.),
+ next_link_id: 0,
+ selection_phase: SelectionPhase::Ended,
+ hyperlink_regex_searches: RegexSearches::new(),
+ vi_mode_enabled: false,
+ is_ssh_terminal: false,
+ last_mouse_move_time: Instant::now(),
+ last_hyperlink_search_position: None,
+ #[cfg(windows)]
+ shell_program: None,
+ activation_script: Vec::new(),
+ template: CopyTemplate {
+ shell: Shell::System,
+ env: HashMap::default(),
+ cursor_shape,
+ alternate_scroll,
+ max_scroll_history_lines,
+ window_id,
+ },
+ child_exited: None,
+ };
+
+ Ok(TerminalBuilder {
+ terminal,
+ events_rx,
+ })
}
pub fn new(
working_directory: Option<PathBuf>,
@@ -533,7 +580,10 @@ impl TerminalBuilder {
let mut terminal = Terminal {
task,
- pty_tx: Notifier(pty_tx),
+ terminal_type: TerminalType::Pty {
+ pty_tx: Notifier(pty_tx),
+ info: pty_info,
+ },
completion_tx,
term,
term_config: config,
@@ -543,12 +593,10 @@ impl TerminalBuilder {
last_mouse: None,
matches: Vec::new(),
selection_head: None,
- pty_info,
breadcrumb_text: String::new(),
scroll_px: px(0.),
next_link_id: 0,
selection_phase: SelectionPhase::Ended,
- // hovered_word: false,
hyperlink_regex_searches: RegexSearches::new(),
vi_mode_enabled: false,
is_ssh_terminal,
@@ -733,8 +781,16 @@ pub enum SelectionPhase {
Ended,
}
+enum TerminalType {
+ Pty {
+ pty_tx: Notifier,
+ info: PtyProcessInfo,
+ },
+ DisplayOnly,
+}
+
pub struct Terminal {
- pty_tx: Notifier,
+ terminal_type: TerminalType,
completion_tx: Option<Sender<Option<ExitStatus>>>,
term: Arc<FairMutex<Term<ZedListener>>>,
term_config: Config,
@@ -745,7 +801,6 @@ pub struct Terminal {
pub last_content: TerminalContent,
pub selection_head: Option<AlacPoint>,
pub breadcrumb_text: String,
- pub pty_info: PtyProcessInfo,
title_override: Option<SharedString>,
scroll_px: Pixels,
next_link_id: usize,
@@ -862,8 +917,10 @@ impl Terminal {
AlacTermEvent::Wakeup => {
cx.emit(Event::Wakeup);
- if self.pty_info.has_changed() {
- cx.emit(Event::TitleChanged);
+ if let TerminalType::Pty { info, .. } = &mut self.terminal_type {
+ if info.has_changed() {
+ cx.emit(Event::TitleChanged);
+ }
}
}
AlacTermEvent::ColorRequest(index, format) => {
@@ -905,7 +962,9 @@ impl Terminal {
self.last_content.terminal_bounds = new_bounds;
- self.pty_tx.0.send(Msg::Resize(new_bounds.into())).ok();
+ if let TerminalType::Pty { pty_tx, .. } = &self.terminal_type {
+ pty_tx.0.send(Msg::Resize(new_bounds.into())).ok();
+ }
term.resize(new_bounds);
}
@@ -1288,9 +1347,12 @@ impl Terminal {
}
}
- ///Write the Input payload to the tty.
+ /// Write the Input payload to the PTY, if applicable.
+ /// (This is a no-op for display-only terminals.)
fn write_to_pty(&self, input: impl Into<Cow<'static, [u8]>>) {
- self.pty_tx.notify(input.into());
+ if let TerminalType::Pty { pty_tx, .. } = &self.terminal_type {
+ pty_tx.notify(input.into());
+ }
}
pub fn input(&mut self, input: impl Into<Cow<'static, [u8]>>) {
@@ -1594,7 +1656,7 @@ impl Terminal {
&& let Some(bytes) =
mouse_moved_report(point, e.pressed_button, e.modifiers, self.last_content.mode)
{
- self.pty_tx.notify(bytes);
+ self.write_to_pty(bytes);
}
} else if e.modifiers.secondary() {
self.word_from_position(e.position);
@@ -1701,7 +1763,7 @@ impl Terminal {
if let Some(bytes) =
mouse_button_report(point, e.button, e.modifiers, true, self.last_content.mode)
{
- self.pty_tx.notify(bytes);
+ self.write_to_pty(bytes);
}
} else {
match e.button {
@@ -1760,7 +1822,7 @@ impl Terminal {
if let Some(bytes) =
mouse_button_report(point, e.button, e.modifiers, false, self.last_content.mode)
{
- self.pty_tx.notify(bytes);
+ self.write_to_pty(bytes);
}
} else {
if e.button == MouseButton::Left && setting.copy_on_select {
@@ -1799,7 +1861,7 @@ impl Terminal {
if let Some(scrolls) = scroll_report(point, scroll_lines, e, self.last_content.mode)
{
for scroll in scrolls {
- self.pty_tx.notify(scroll);
+ self.write_to_pty(scroll);
}
};
} else if self
@@ -1808,7 +1870,7 @@ impl Terminal {
.contains(TermMode::ALT_SCREEN | TermMode::ALTERNATE_SCROLL)
&& !e.shift
{
- self.pty_tx.notify(alt_scroll(scroll_lines))
+ self.write_to_pty(alt_scroll(scroll_lines));
} else if scroll_lines != 0 {
let scroll = AlacScroll::Delta(scroll_lines);
@@ -1879,10 +1941,12 @@ impl Terminal {
/// This does *not* return the working directory of the shell that runs on the
/// remote host, in case Zed is connected to a remote host.
fn client_side_working_directory(&self) -> Option<PathBuf> {
- self.pty_info
- .current
- .as_ref()
- .map(|process| process.cwd.clone())
+ match &self.terminal_type {
+ TerminalType::Pty { info, .. } => {
+ info.current.as_ref().map(|process| process.cwd.clone())
+ }
+ TerminalType::DisplayOnly => None,
+ }
}
pub fn title(&self, truncate: bool) -> String {
@@ -1899,8 +1963,8 @@ impl Terminal {
.title_override
.as_ref()
.map(|title_override| title_override.to_string())
- .unwrap_or_else(|| {
- self.pty_info
+ .unwrap_or_else(|| match &self.terminal_type {
+ TerminalType::Pty { info, .. } => info
.current
.as_ref()
.map(|fpi| {
@@ -1930,7 +1994,8 @@ impl Terminal {
};
format!("{process_file} — {process_name}")
})
- .unwrap_or_else(|| "Terminal".to_string())
+ .unwrap_or_else(|| "Terminal".to_string()),
+ TerminalType::DisplayOnly => "Terminal".to_string(),
}),
}
}
@@ -1939,7 +2004,23 @@ impl Terminal {
if let Some(task) = self.task()
&& task.status == TaskStatus::Running
{
- self.pty_info.kill_current_process();
+ if let TerminalType::Pty { info, .. } = &mut self.terminal_type {
+ info.kill_current_process();
+ }
+ }
+ }
+
+ pub fn pid(&self) -> Option<sysinfo::Pid> {
+ match &self.terminal_type {
+ TerminalType::Pty { info, .. } => info.pid(),
+ TerminalType::DisplayOnly => None,
+ }
+ }
+
+ pub fn pid_getter(&self) -> Option<&ProcessIdGetter> {
+ match &self.terminal_type {
+ TerminalType::Pty { info, .. } => Some(info.pid_getter()),
+ TerminalType::DisplayOnly => None,
}
}
@@ -2134,7 +2215,9 @@ unsafe fn append_text_to_term(term: &mut Term<ZedListener>, text_lines: &[&str])
impl Drop for Terminal {
fn drop(&mut self) {
- self.pty_tx.0.send(Msg::Shutdown).ok();
+ if let TerminalType::Pty { pty_tx, .. } = &self.terminal_type {
+ pty_tx.0.send(Msg::Shutdown).ok();
+ }
}
}