xiaohongshu
xiaohongshu
alacritty-terminal
Terminal emulation library from Alacritty for VT100/xterm compatible terminal embedding
Full skill instructions
alacritty_terminal is the terminal emulation library extracted from the Alacritty GPU-accelerated terminal emulator. Script-kit-gpui uses version 0.25 (matching Zed's version) to provide full VT100/xterm/ANSI terminal emulation.
PTY Output --> VTE Parser --> Term Grid --> Render
| |
v v
Escape Seq Cell Storage
Processing (scrollback)
The library handles:
The main terminal type, generic over an EventListener:
use alacritty_terminal::term::{Term, Config as TermConfig};
use alacritty_terminal::event::EventListener;
// Create a terminal with event listener
let config = TermConfig {
scrolling_history: 10_000, // scrollback lines
..TermConfig::default()
};
let term: Term<EventProxy> = Term::new(config, &size, event_proxy);
Key fields:
is_focused: bool - Controls cursor appearanceselection: Option<Selection> - Current text selectionvi_mode_cursor: ViModeCursor - Vi mode cursor positionKey methods:
grid() / grid_mut() - Access the underlying gridresize(size) - Resize terminal dimensionsscroll_display(Scroll) - Scroll the viewportselection_to_string() - Get selected textmode() - Get current terminal modes (TermMode)renderable_content() - Get content optimized for renderingOptimized storage for terminal content:
use alacritty_terminal::grid::{Grid, Dimensions, Scroll};
use alacritty_terminal::index::{Line, Column, Point};
let grid = term.grid();
// Access by Line (row)
let row = &grid[Line(0)]; // First visible row
// Access by Point (row + column)
let cell = &grid[Point::new(Line(0), Column(5))];
// Cursor position
let cursor_point = grid.cursor.point;
Scroll enum variants:
use alacritty_terminal::grid::Scroll;
Scroll::Delta(i32) // Relative scroll by lines
Scroll::PageUp // Scroll one page up
Scroll::PageDown // Scroll one page down
Scroll::Top // Scroll to top of history
Scroll::Bottom // Scroll to bottom (latest)
use alacritty_terminal::term::cell::{Cell, Flags};
use vte::ansi::Color;
// Cell fields
let cell: &Cell = &grid[point];
cell.c // char - the character
cell.fg // Color - foreground color
cell.bg // Color - background color
cell.flags // Flags - attributes (bold, italic, etc.)
cell.hyperlink() // Option<&Hyperlink>
Cell Flags (bitflags):
use alacritty_terminal::term::cell::Flags;
Flags::BOLD
Flags::ITALIC
Flags::UNDERLINE
Flags::DOUBLE_UNDERLINE
Flags::UNDERCURL
Flags::DOTTED_UNDERLINE
Flags::DASHED_UNDERLINE
Flags::STRIKEOUT
Flags::INVERSE // Swap fg/bg
Flags::HIDDEN
Flags::DIM
Flags::WIDE_CHAR // Part of wide character
Flags::WIDE_CHAR_SPACER // Spacer after wide char
use alacritty_terminal::index::{Line, Column, Point, Direction};
// Line uses i32 (can be negative for scrollback)
let line = Line(0); // First visible line
let scrollback = Line(-100); // 100 lines into scrollback
// Column uses usize
let col = Column(10);
// Point combines both
let point = Point::new(Line(0), Column(5));
// Or use AlacPoint alias for disambiguation
let point = AlacPoint::new(Line(0), Column(5));
// Direction for navigation/selection
Direction::Left
Direction::Right
use alacritty_terminal::selection::{Selection, SelectionType};
use alacritty_terminal::index::{Point, Direction};
// Create selection
let selection = Selection::new(
SelectionType::Simple, // Normal character selection
point, // Starting point
Direction::Left, // Initial direction
);
// Selection types
SelectionType::Simple // Character-by-character
SelectionType::Semantic // Word selection (double-click)
SelectionType::Lines // Line selection (triple-click)
SelectionType::Block // Block/rectangular selection
// Update selection endpoint
selection.update(new_point, Direction::Right);
// Get selection range for a term
if let Some(range) = selection.to_range(&term) {
for point in range.iter() {
// Process selected points
}
}
use alacritty_terminal::event::{Event, EventListener};
struct MyEventProxy { /* ... */ }
impl EventListener for MyEventProxy {
fn send_event(&self, event: Event) {
match event {
Event::Bell => { /* Terminal bell */ }
Event::Title(title) => { /* Window title change */ }
Event::ResetTitle => { /* Reset title */ }
Event::Exit => { /* Terminal requested exit */ }
Event::ChildExit(code) => { /* Child process exited */ }
Event::Wakeup => { /* New content available */ }
Event::PtyWrite(text) => { /* Data to write to PTY */ }
Event::MouseCursorDirty => { /* Cursor changed */ }
Event::CursorBlinkingChange => { /* Blink state changed */ }
Event::ClipboardStore(clipboard, data) => { /* Store to clipboard */ }
Event::ClipboardLoad(clipboard, format) => { /* Load from clipboard */ }
Event::ColorRequest(index, format) => { /* Query color */ }
Event::TextAreaSizeRequest(format) => { /* Query size */ }
}
}
}
use alacritty_terminal::term::TermMode;
let mode = term.mode();
// Check modes
mode.contains(TermMode::BRACKETED_PASTE) // Wrap paste in escape sequences
mode.contains(TermMode::SHOW_CURSOR) // Cursor visible
mode.contains(TermMode::APP_CURSOR) // Application cursor keys
mode.contains(TermMode::APP_KEYPAD) // Application keypad mode
mode.contains(TermMode::MOUSE_REPORT_CLICK) // Mouse click reporting
mode.contains(TermMode::ALT_SCREEN) // Alternate screen buffer
// From src/terminal/alacritty.rs
use alacritty_terminal::term::{Term, Config as TermConfig};
use vte::ansi::Processor;
struct TerminalState {
term: Term<EventProxy>,
processor: Processor,
}
impl TerminalState {
fn new(config: TermConfig, size: &TerminalSize, event_proxy: EventProxy) -> Self {
Self {
term: Term::new(config, size, event_proxy),
processor: Processor::new(),
}
}
// Process PTY output through VTE parser
fn process_bytes(&mut self, bytes: &[u8]) {
self.processor.advance(&mut self.term, bytes);
}
}
Required for Term::new() and Term::resize():
use alacritty_terminal::grid::Dimensions;
struct TerminalSize {
cols: usize,
rows: usize,
}
impl Dimensions for TerminalSize {
fn total_lines(&self) -> usize { self.rows }
fn screen_lines(&self) -> usize { self.rows }
fn columns(&self) -> usize { self.cols }
}
// Iterate visible lines
for line_idx in 0..term.screen_lines() {
let row = &grid[Line(line_idx as i32)];
for col_idx in 0..term.columns() {
let cell = &row[Column(col_idx)];
// Get character
let c = cell.c;
// Resolve colors
let fg = resolve_color(&cell.fg, theme);
let bg = resolve_color(&cell.bg, theme);
// Check attributes
if cell.flags.contains(Flags::BOLD) { /* ... */ }
if cell.flags.contains(Flags::WIDE_CHAR) { /* ... */ }
}
}
Colors can be Named, Indexed (0-255), or Spec (direct RGB):
use vte::ansi::{Color, NamedColor, Rgb};
fn resolve_color(color: &Color, theme: &Theme) -> Rgb {
match color {
Color::Named(named) => match named {
NamedColor::Foreground => theme.foreground,
NamedColor::Background => theme.background,
NamedColor::Black => theme.ansi[0],
NamedColor::Red => theme.ansi[1],
// ... etc for all 16 ANSI colors
NamedColor::BrightBlack => theme.ansi[8],
// ... etc for bright variants
},
Color::Indexed(idx) => resolve_indexed(*idx, theme),
Color::Spec(rgb) => *rgb,
}
}
fn resolve_indexed(idx: u8, theme: &Theme) -> Rgb {
match idx {
0..=15 => theme.ansi[idx as usize],
16..=231 => {
// 6x6x6 color cube
let idx = idx - 16;
let r = (idx / 36) % 6;
let g = (idx / 6) % 6;
let b = idx % 6;
let to_val = |v| if v == 0 { 0 } else { 55 + v * 40 };
Rgb { r: to_val(r), g: to_val(g), b: to_val(b) }
}
232..=255 => {
// Grayscale ramp
let gray = 8 + (idx - 232) * 10;
Rgb { r: gray, g: gray, b: gray }
}
}
}
use alacritty_terminal::grid::Scroll;
// Scroll by lines
term.scroll_display(Scroll::Delta(-5)); // Up 5 lines
term.scroll_display(Scroll::Delta(5)); // Down 5 lines
// Page scroll
term.scroll_display(Scroll::PageUp);
term.scroll_display(Scroll::PageDown);
// Jump to ends
term.scroll_display(Scroll::Top); // Top of scrollback
term.scroll_display(Scroll::Bottom); // Latest output
// Get current scroll position
let offset = term.grid().display_offset(); // 0 = at bottom
use alacritty_terminal::selection::{Selection, SelectionType};
use alacritty_terminal::index::{Point, Line, Column, Direction};
// Start selection on mouse down
fn start_selection(term: &mut Term<T>, col: usize, row: usize) {
let point = Point::new(Line(row as i32), Column(col));
term.selection = Some(Selection::new(
SelectionType::Simple,
point,
Direction::Left,
));
}
// Double-click for word selection
fn start_word_selection(term: &mut Term<T>, col: usize, row: usize) {
let point = Point::new(Line(row as i32), Column(col));
term.selection = Some(Selection::new(
SelectionType::Semantic, // Word boundaries
point,
Direction::Left,
));
}
// Update on mouse drag
fn update_selection(term: &mut Term<T>, col: usize, row: usize) {
if let Some(ref mut sel) = term.selection {
let point = Point::new(Line(row as i32), Column(col));
sel.update(point, Direction::Right);
}
}
// Get selected text
fn get_selection(term: &Term<T>) -> Option<String> {
term.selection_to_string()
}
// Clear selection
term.selection = None;
// Check if bracketed paste is enabled
if term.mode().contains(TermMode::BRACKETED_PASTE) {
// Wrap pasted text in escape sequences
let wrapped = format!("\x1b[200~{}\x1b[201~", text);
pty.write_all(wrapped.as_bytes())?;
} else {
pty.write_all(text.as_bytes())?;
}
// WRONG: Using usize directly
let row = &grid[5]; // Won't compile - needs Line type
// CORRECT: Use Line wrapper
let row = &grid[Line(5)];
// WRONG: Assuming all cells are single-width
for col in 0..width {
render_cell(&grid[Line(row)][Column(col)]);
}
// CORRECT: Check for wide char spacers
for col in 0..width {
let cell = &grid[Line(row)][Column(col)];
if cell.flags.contains(Flags::WIDE_CHAR_SPACER) {
continue; // Skip spacer cells
}
let width = if cell.flags.contains(Flags::WIDE_CHAR) { 2 } else { 1 };
render_cell(cell, width);
}
// WRONG: Writing to term directly won't parse escape sequences
term.input("Hello"); // This method doesn't exist!
// CORRECT: Use VTE processor to parse PTY output
let mut processor = Processor::new();
processor.advance(&mut term, pty_bytes);
// WRONG: Blocking I/O with lock held
let mut state = terminal_state.lock().unwrap();
let bytes = pty.read_blocking(&mut buffer)?; // Blocks!
state.process_bytes(&bytes);
// CORRECT: Read in background, process with brief lock
// Background thread:
let bytes = pty.read_blocking(&mut buffer)?;
tx.send(bytes)?;
// Main thread:
while let Ok(bytes) = rx.try_recv() {
let mut state = terminal_state.lock().unwrap();
state.process_bytes(&bytes);
} // Lock released quickly
// WRONG: Assuming lines are always positive
let line = row as i32; // May need negative for scrollback
// CORRECT: Account for display offset
let display_offset = grid.display_offset() as i32;
let line = Line(row as i32 - display_offset);
vte (0.13) - Virtual Terminal Emulator parser
vte::ansi::Processor - Parses escape sequencesvte::ansi::Color, Rgb, NamedColor - Color typesvte::ansi::Handler - Trait implemented by Termsrc/terminal/alacritty.rsxiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience