Add full disk access checks and settings
Add background themes and custom images Add shell command logging toggle Add UTF-8 locale guarantee for PTY Add Claude hook settings injection Add hotkey system for GUI Add glass panel styling Add search disabled state for agent panels Add zoom toggle command Add device report filtering Add entitlements for notarization Update version to 0.1.27
This commit is contained in:
@@ -4,7 +4,7 @@ use alacritty_terminal::event::{Event, EventListener};
|
||||
use alacritty_terminal::grid::Dimensions;
|
||||
use alacritty_terminal::index::{Column, Line, Point};
|
||||
use alacritty_terminal::term::{Config, Term};
|
||||
use alacritty_terminal::vte::ansi::Processor;
|
||||
use alacritty_terminal::vte::ansi::{NamedColor, Processor, Rgb};
|
||||
|
||||
/// Fixed-size terminal dimensions for the daemon-side grid.
|
||||
#[derive(Clone, Copy)]
|
||||
@@ -25,25 +25,53 @@ impl Dimensions for GridSize {
|
||||
}
|
||||
}
|
||||
|
||||
/// One escape sequence the terminal model wants written back to the PTY in
|
||||
/// response to a query: either a ready-made byte reply (DA/DSR/etc.) or a color
|
||||
/// report whose value must be resolved from the term's palette at drain time.
|
||||
enum Reply {
|
||||
Bytes(Vec<u8>),
|
||||
Color(usize, Arc<dyn Fn(Rgb) -> String + Send + Sync>),
|
||||
}
|
||||
|
||||
/// Collects the escape sequences the terminal model wants written back to the PTY
|
||||
/// (Primary/Secondary Device Attributes, DSR cursor/status reports, etc.). Programs
|
||||
/// like fish block on these replies at startup; with a void listener they hang ~2s
|
||||
/// and then warn ("could not read response to Primary Device Attribute query").
|
||||
/// (Primary/Secondary Device Attributes, DSR cursor/status reports, OSC color
|
||||
/// queries, etc.). Programs like fish, yazi and vim block on these replies at
|
||||
/// startup; with a void listener they hang ~2s and then warn ("could not read
|
||||
/// response to Primary Device Attribute query") or render with the wrong theme.
|
||||
///
|
||||
/// The daemon is the authoritative responder for the PTY — the GUI's xterm.js is
|
||||
/// display-only and must NOT echo its own replies back (its duplicate arrives an
|
||||
/// IPC roundtrip late and gets typed into the shell as literal gibberish).
|
||||
#[derive(Clone, Default)]
|
||||
pub struct ReplyCollector {
|
||||
buf: Arc<Mutex<Vec<u8>>>,
|
||||
buf: Arc<Mutex<Vec<Reply>>>,
|
||||
}
|
||||
|
||||
impl EventListener for ReplyCollector {
|
||||
fn send_event(&self, event: Event) {
|
||||
if let Event::PtyWrite(text) = event {
|
||||
if let Ok(mut b) = self.buf.lock() {
|
||||
b.extend_from_slice(text.as_bytes());
|
||||
}
|
||||
let reply = match event {
|
||||
Event::PtyWrite(text) => Reply::Bytes(text.into_bytes()),
|
||||
// OSC 10/11/12 color query — alacritty defers the value to the embedder
|
||||
// (us) via a formatter; resolve it against the palette in take_replies.
|
||||
Event::ColorRequest(index, fmt) => Reply::Color(index, fmt),
|
||||
_ => return,
|
||||
};
|
||||
if let Ok(mut b) = self.buf.lock() {
|
||||
b.push(reply);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fallback palette colors when a program queries one the term has not had set
|
||||
/// explicitly. Matches the GUI's default theme so OSC 11 (background) reports a
|
||||
/// dark color and light/dark detection in TUIs stays correct.
|
||||
fn default_color(index: usize) -> Rgb {
|
||||
if index == NamedColor::Background as usize { Rgb { r: 0x0a, g: 0x0d, b: 0x12 } }
|
||||
else if index == NamedColor::Foreground as usize { Rgb { r: 0xe6, g: 0xed, b: 0xf3 } }
|
||||
else if index == NamedColor::Cursor as usize { Rgb { r: 0xe6, g: 0xed, b: 0xf3 } }
|
||||
else { Rgb { r: 0x80, g: 0x80, b: 0x80 } }
|
||||
}
|
||||
|
||||
/// Owns an alacritty terminal model and feeds raw PTY bytes into it.
|
||||
pub struct GridSurface {
|
||||
term: Term<ReplyCollector>,
|
||||
@@ -68,10 +96,21 @@ impl GridSurface {
|
||||
/// far. The caller must write these back to the PTY for query-driven programs
|
||||
/// (fish, vim, etc.) to proceed without timing out.
|
||||
pub fn take_replies(&mut self) -> Vec<u8> {
|
||||
match self.replies.buf.lock() {
|
||||
Ok(mut b) => std::mem::take(&mut *b),
|
||||
Err(_) => Vec::new(),
|
||||
let replies = {
|
||||
let Ok(mut b) = self.replies.buf.lock() else { return Vec::new(); };
|
||||
std::mem::take(&mut *b)
|
||||
};
|
||||
let mut out = Vec::new();
|
||||
for reply in replies {
|
||||
match reply {
|
||||
Reply::Bytes(bytes) => out.extend_from_slice(&bytes),
|
||||
Reply::Color(index, fmt) => {
|
||||
let rgb = self.term.colors()[index].unwrap_or_else(|| default_color(index));
|
||||
out.extend_from_slice(fmt(rgb).as_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, cols: u16, rows: u16) {
|
||||
@@ -141,4 +180,15 @@ mod tests {
|
||||
// Replies are drained, not duplicated.
|
||||
assert!(g.take_replies().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn osc_background_color_query_gets_a_reply() {
|
||||
// yazi/vim send OSC 11 ("\x1b]11;?\x07") to detect the background color and
|
||||
// block on the reply; the daemon must answer it authoritatively.
|
||||
let mut g = GridSurface::new(20, 5);
|
||||
g.feed(b"\x1b]11;?\x07");
|
||||
let reply = String::from_utf8(g.take_replies()).unwrap();
|
||||
assert!(reply.starts_with("\x1b]11;rgb:"), "expected an OSC 11 reply, got {reply:?}");
|
||||
assert!(g.take_replies().is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user