Upgrade alacritty_terminal in hopes to avoid PTY poll failing

We saw stack traces in our #panic channel pop up that failed on this line:

    3330614219/alacritty_terminal/src/event_loop.rs (L323-L324)

With this message:

    thread 'PTY reader' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 9, kind: Uncategorized, message: "Bad file descriptor" }'
    /Users/administrator/.cargo/git/checkouts/alacritty-afea874b09a502a5/3330614/alacritty_terminal/src/event_loop.rs:324

We don't know how to reproduce the error. It doesn't seem related to the number of open PTY handles,
because `openpty` itself didn't fail. We can only assume that something went wrong between
`openpty` and the setup of the polling.

Since Alacritty itself changed its polling mechanism significantly by switching
from `mio` to `polling` (https://github.com/alacritty/alacritty/pull/6846) we upgraded
with the hope that this will fix the bug.

Co-authored-by: Antonio <antonio@zed.dev>
Co-authored-by: Federico <code@fdionisi.me>
Co-authored-by: David <dammerung2718@icloud.com>
Co-authored-by: Bennet <bennetbo@gmx.de>
This commit is contained in:
Thorsten Ball 2024-01-25 16:58:47 +01:00
parent f7a2118b15
commit c4cf5f2b2c
5 changed files with 128 additions and 205 deletions

View file

@ -3,8 +3,6 @@ pub use alacritty_terminal;
pub mod terminal_settings;
use alacritty_terminal::{
ansi::{ClearMode, Handler},
config::{Config, Program, PtyConfig, Scrolling},
event::{Event as AlacTermEvent, EventListener, Notify, WindowSize},
event_loop::{EventLoop, Msg, Notifier},
grid::{Dimensions, Scroll as AlacScroll},
@ -13,11 +11,11 @@ use alacritty_terminal::{
sync::FairMutex,
term::{
cell::Cell,
color::Rgb,
search::{Match, RegexIter, RegexSearch},
RenderableCursor, TermMode,
Config, RenderableCursor, TermMode,
},
tty::{self, setup_env},
tty::{self, setup_env, ToWinsize},
vte::ansi::{ClearMode, Handler, NamedPrivateMode, PrivateMode, Rgb},
Term,
};
use anyhow::{bail, Result};
@ -58,7 +56,6 @@ use gpui::{
};
use crate::mappings::{colors::to_alac_rgb, keys::to_esc_str};
use lazy_static::lazy_static;
actions!(
terminal,
@ -75,15 +72,6 @@ const DEBUG_TERMINAL_HEIGHT: Pixels = px(30.);
const DEBUG_CELL_WIDTH: Pixels = px(5.);
const DEBUG_LINE_HEIGHT: Pixels = px(5.);
lazy_static! {
// Regex Copied from alacritty's ui_config.rs and modified its declaration slightly:
// * avoid Rust-specific escaping.
// * use more strict regex for `file://` protocol matching: original regex has `file:` inside, but we want to avoid matching `some::file::module` strings.
static ref URL_REGEX: RegexSearch = RegexSearch::new(r#"(ipfs:|ipns:|magnet:|mailto:|gemini://|gopher://|https://|http://|news:|file://|git://|ssh:|ftp://)[^\u{0000}-\u{001F}\u{007F}-\u{009F}<>"\s{-}\^⟨⟩`]+"#).unwrap();
static ref WORD_REGEX: RegexSearch = RegexSearch::new(r#"[\w.\[\]:/@\-~]+"#).unwrap();
}
///Upward flowing events, for changing the title and such
#[derive(Clone, Debug)]
pub enum Event {
@ -294,14 +282,18 @@ impl TerminalBuilder {
alternate_scroll: AlternateScroll,
window: AnyWindowHandle,
) -> Result<TerminalBuilder> {
let pty_config = {
let pty_options = {
let alac_shell = match shell.clone() {
Shell::System => None,
Shell::Program(program) => Some(Program::Just(program)),
Shell::WithArguments { program, args } => Some(Program::WithArgs { program, args }),
Shell::Program(program) => {
Some(alacritty_terminal::tty::Shell::new(program, Vec::new()))
}
Shell::WithArguments { program, args } => {
Some(alacritty_terminal::tty::Shell::new(program, args))
}
};
PtyConfig {
alacritty_terminal::tty::Options {
shell: alac_shell,
working_directory: working_directory.clone(),
hold: false,
@ -312,43 +304,38 @@ impl TerminalBuilder {
env.insert("LC_ALL".to_string(), "en_US.UTF-8".to_string());
env.insert("ZED_TERM".to_string(), true.to_string());
let alac_scrolling = Scrolling::default();
// alac_scrolling.set_history((BACK_BUFFER_SIZE * 2) as u32);
let config = Config {
pty_config: pty_config.clone(),
env,
scrolling: alac_scrolling,
scrolling_history: 10000,
..Default::default()
};
setup_env(&config);
setup_env();
//Spawn a task so the Alacritty EventLoop can communicate with us in a view context
//TODO: Remove with a bounded sender which can be dispatched on &self
let (events_tx, events_rx) = unbounded();
//Set up the terminal...
let mut term = Term::new(
&config,
config,
&TerminalSize::default(),
ZedListener(events_tx.clone()),
);
//Start off blinking if we need to
if let Some(TerminalBlink::On) = blink_settings {
term.set_mode(alacritty_terminal::ansi::Mode::BlinkingCursor)
term.set_private_mode(PrivateMode::Named(NamedPrivateMode::BlinkingCursor));
}
//Alacritty defaults to alternate scrolling being on, so we just need to turn it off.
if let AlternateScroll::Off = alternate_scroll {
term.unset_mode(alacritty_terminal::ansi::Mode::AlternateScroll)
term.unset_private_mode(PrivateMode::Named(NamedPrivateMode::AlternateScroll));
}
let term = Arc::new(FairMutex::new(term));
//Setup the pty...
let pty = match tty::new(
&pty_config,
&pty_options,
TerminalSize::default().into(),
window.window_id().as_u64(),
) {
@ -370,13 +357,16 @@ impl TerminalBuilder {
term.clone(),
ZedListener(events_tx.clone()),
pty,
pty_config.hold,
pty_options.hold,
false,
);
//Kick things off
let pty_tx = event_loop.channel();
let _io_thread = event_loop.spawn();
let _io_thread = event_loop.spawn(); // DANGER
let url_regex = RegexSearch::new(r#"(ipfs:|ipns:|magnet:|mailto:|gemini://|gopher://|https://|http://|news:|file://|git://|ssh:|ftp://)[^\u{0000}-\u{001F}\u{007F}-\u{009F}<>"\s{-}\^⟨⟩`]+"#).unwrap();
let word_regex = RegexSearch::new(r#"[\w.\[\]:/@\-~]+"#).unwrap();
let terminal = Terminal {
pty_tx: Notifier(pty_tx),
@ -396,6 +386,8 @@ impl TerminalBuilder {
selection_phase: SelectionPhase::Ended,
cmd_pressed: false,
hovered_word: false,
url_regex,
word_regex,
};
Ok(TerminalBuilder {
@ -514,7 +506,7 @@ impl Default for TerminalContent {
selection_text: Default::default(),
selection: Default::default(),
cursor: RenderableCursor {
shape: alacritty_terminal::ansi::CursorShape::Block,
shape: alacritty_terminal::vte::ansi::CursorShape::Block,
point: AlacPoint::new(Line(0), Column(0)),
},
cursor_char: Default::default(),
@ -550,6 +542,8 @@ pub struct Terminal {
selection_phase: SelectionPhase,
cmd_pressed: bool,
hovered_word: bool,
url_regex: RegexSearch,
word_regex: RegexSearch,
}
impl Terminal {
@ -760,7 +754,7 @@ impl Terminal {
let url_match = min_index..=max_index;
Some((url, true, url_match))
} else if let Some(word_match) = regex_match_at(term, point, &WORD_REGEX) {
} else if let Some(word_match) = regex_match_at(term, point, &mut self.word_regex) {
let maybe_url_or_path =
term.bounds_to_string(*word_match.start(), *word_match.end());
let original_match = word_match.clone();
@ -777,7 +771,7 @@ impl Terminal {
(word_match, maybe_url_or_path)
};
let is_url = match regex_match_at(term, point, &URL_REGEX) {
let is_url = match regex_match_at(term, point, &mut self.url_regex) {
Some(url_match) => {
// `]` is a valid symbol in the `file://` URL, so the regex match will include it
// consider that when ensuring that the URL match is the same as the original word
@ -1275,14 +1269,14 @@ impl Terminal {
pub fn find_matches(
&mut self,
searcher: RegexSearch,
mut searcher: RegexSearch,
cx: &mut ModelContext<Self>,
) -> Task<Vec<RangeInclusive<AlacPoint>>> {
let term = self.term.clone();
cx.background_executor().spawn(async move {
let term = term.lock();
all_search_matches(&term, &searcher).collect()
all_search_matches(&term, &mut searcher).collect()
})
}
@ -1332,7 +1326,7 @@ impl EventEmitter<Event> for Terminal {}
/// Based on alacritty/src/display/hint.rs > regex_match_at
/// Retrieve the match, if the specified point is inside the content matching the regex.
fn regex_match_at<T>(term: &Term<T>, point: AlacPoint, regex: &RegexSearch) -> Option<Match> {
fn regex_match_at<T>(term: &Term<T>, point: AlacPoint, regex: &mut RegexSearch) -> Option<Match> {
visible_regex_match_iter(term, regex).find(|rm| rm.contains(&point))
}
@ -1340,7 +1334,7 @@ fn regex_match_at<T>(term: &Term<T>, point: AlacPoint, regex: &RegexSearch) -> O
/// Iterate over all visible regex matches.
pub fn visible_regex_match_iter<'a, T>(
term: &'a Term<T>,
regex: &'a RegexSearch,
regex: &'a mut RegexSearch,
) -> impl Iterator<Item = Match> + 'a {
let viewport_start = Line(-(term.grid().display_offset() as i32));
let viewport_end = viewport_start + term.bottommost_line();
@ -1362,7 +1356,7 @@ fn make_selection(range: &RangeInclusive<AlacPoint>) -> Selection {
fn all_search_matches<'a, T>(
term: &'a Term<T>,
regex: &'a RegexSearch,
regex: &'a mut RegexSearch,
) -> impl Iterator<Item = Match> + 'a {
let start = AlacPoint::new(term.grid().topmost_line(), Column(0));
let end = AlacPoint::new(term.grid().bottommost_line(), term.grid().last_column());