How Alacritty Controls Cursor Styles and Blinking Behavior: A Technical Deep Dive
Alacritty controls cursor styles and blinking behavior through a three-stage pipeline that parses configuration from alacritty.yml, resolves the effective cursor style at runtime in Processor::update_cursor_blinking, and renders GPU-accelerated geometry via the display module.
The alacritty/alacritty repository implements cursor management as a coordinated system between user preferences, terminal state, and event-driven animations. Understanding how cursor styles and blinking behavior are controlled requires examining the configuration structs, the runtime decision logic in the event processor, and the final rendering path that generates visible cursor rectangles.
Configuration Model and User Settings
Cursor customization begins in alacritty/src/config/cursor.rs, where the Cursor struct defines all user-configurable properties. These values are deserialized from alacritty.yml into the running application's UiConfig.
Core Configuration Fields
The Cursor struct (lines 18-36) exposes these primary fields:
- style: A
ConfigCursorStyledefining the default shape and blinking mode (default:Block) - vi_mode_style: An optional override applied when the terminal enters VI mode
- unfocused_hollow: Boolean flag rendering a hollow block when the window loses focus (default:
true) - thickness: A percentage (0.0–1.0) controlling cursor line width (default:
0.15) - blink_interval: Milliseconds for a single on/off blink cycle (default:
750) - blink_timeout: Seconds before blinking pauses;
0disables the pause (default:5)
ConfigCursorStyle Enum
The ConfigCursorStyle enum (lines 76-84) distinguishes between simple shapes and shapes with explicit blinking overrides:
pub enum ConfigCursorStyle {
Shape(CursorShape),
WithBlinking {
shape: CursorShape,
blinking: CursorBlinking,
},
}
CursorShape variants include Block, Underline, Beam, and Hidden. The CursorBlinking enum provides four control levels:
- Never: Forces blinking off regardless of terminal state
- Off: Follows the terminal's native blinking flag (off by default)
- On: Follows the terminal's native blinking flag (on by default)
- Always: Forces blinking on regardless of terminal state
Runtime Style Resolution
The effective cursor style is computed dynamically in alacritty/src/event.rs within Processor::update_cursor_blinking (lines 1617-1645). This method reconciles configuration defaults with transient states like VI mode, IME composition, and window focus.
The Resolution Algorithm
When the event loop prepares to redraw, Alacritty executes this priority chain:
- Base selection: Start with
config.cursor.style - VI mode override: If VI mode is active and
vi_mode_styleis set, substitute the base style - Terminal query: Inspect the terminal's native cursor style via
self.terminal.cursor_style().blinking - Blinking resolution:
- If the config specifies
NeverorAlways, use that override - Otherwise, inherit the terminal's native blinking flag
- If the config specifies
- Constraint masking: Enable blinking only if (VI mode OR SHOW_CURSOR mode) is active AND no IME preedit is in progress
- Timer scheduling: If blinking is enabled and the window is focused, schedule
BlinkCursorandBlinkTimeoutevents; otherwise, cancel timers and force visibility
The blink_interval value determines the BlinkCursor timer frequency, while blink_timeout controls an optional BlinkTimeout timer that pauses blinking after the specified duration to reduce CPU usage.
Rendering Pipeline
Once the effective style is determined, the display module handles actual pixel generation and visibility toggling.
Shape Selection
In alacritty/src/display/content.rs, the Content::new function (lines 51-62) selects the final shape to render:
- Returns
CursorShape::Hiddenif the terminal reports a hidden cursor or during IME pre-edit - Renders
HollowBlockwhen the window is unfocused andunfocused_hollowis enabled - Otherwise, uses the shape reported by the terminal state machine
Geometry Generation
The display::cursor::IntoRects trait (lines 29-86 in alacritty/src/display/cursor.rs) converts the abstract cursor into GPU-ready RenderRect primitives:
- Beam: Single vertical rectangle using
thicknesspercentage of cell width - Underline: Single horizontal rectangle at the cell bottom
- Block: Filled rectangle covering the entire cell
- HollowBlock: Four perimeter rectangles forming an unfilled box
Blink Toggling
The scheduler in Processor::schedule_blinking (lines 47-53) toggles the display.cursor_hidden boolean on each BlinkCursor event. During the next frame, Content::new checks this flag and treats the cursor as hidden when true, creating the visible blinking effect without regenerating geometry.
Practical Configuration Examples
Customizing alacritty.yml
To configure a blinking beam cursor that pauses after 10 seconds, with a block cursor for VI mode:
cursor:
style:
shape: Beam
blinking: On
vi_mode_style:
shape: Block
blinking: Always
thickness: 0.20
blink_interval: 500
blink_timeout: 10
unfocused_hollow: true
Accessing Cursor State in Rust
When integrating with Alacritty's internals, access resolved cursor properties through UiConfig:
use alacritty::config::UiConfig;
use std::rc::Rc;
fn inspect_cursor(config: &Rc<UiConfig>) {
let style = config.cursor.style();
let vi_override = config.cursor.vi_mode_style();
let thickness = config.cursor.thickness();
let blink_ms = config.cursor.blink_interval();
println!("Base style: {:?}, VI override: {:?}", style, vi_override);
}
These methods are defined in alacritty/src/config/cursor.rs (lines 41-63).
Triggering Blink Updates
After a configuration reload, emit a cursor blinking change event to reset timers:
use alacritty::event::Event;
use alacritty::event::EventType;
let event = Event::new(EventType::CursorBlinkingChange, None);
processor.event_queue.push(event);
This mirrors the implementation in alacritty/src/window_context.rs (lines 28-33).
Key Source Files
The cursor control system spans these critical files in the alacritty/alacritty repository:
alacritty/src/config/cursor.rs: DefinesCursor,ConfigCursorStyle, andCursorBlinkingenums with serde deserialization logicalacritty/src/event.rs: ContainsProcessor::update_cursor_blinkingand timer scheduling for cursor visibility togglingalacritty/src/window_context.rs: Initializes cursor blinking on startup and handles configuration reload eventsalacritty/src/display/content.rs: Implements shape selection logic including VI mode, focus state, and hidden checksalacritty/src/display/cursor.rs: Generates GPU rectangles for each cursor shape with thickness calculationsalacritty/src/config/ui_config.rs: Root configuration struct holding thecursor: Cursorfield
Summary
- Cursor styles and blinking behavior in Alacritty are defined by the
Cursorstruct inalacritty/src/config/cursor.rs, which supports three shapes and four blinking control levels. - Runtime resolution occurs in
Processor::update_cursor_blinking(event.rs), which reconciles configuration defaults with VI mode state, terminal flags, and IME status. - Blinking animation is driven by scheduled timers (
BlinkCursor,BlinkTimeout) that toggle thecursor_hiddendisplay flag between frames. - GPU rendering converts the final resolved style into rectangles via
IntoRectsindisplay/cursor.rs, respecting the configuredthicknesspercentage. - Window focus triggers the hollow block visualization when
unfocused_hollowis enabled, handled during shape selection indisplay/content.rs.
Frequently Asked Questions
How do I disable cursor blinking completely in Alacritty?
Set the blinking field to Never in your alacritty.yml cursor configuration. This forces the cursor to remain visible regardless of terminal application requests or VI mode state. According to the source code in alacritty/src/config/cursor.rs, the Never variant of CursorBlinking acts as an override that suppresses all blinking timers.
Why does my cursor stop blinking after a few seconds?
This is controlled by the blink_timeout configuration option, which defaults to 5 seconds. When the timeout elapses, Alacritty's event processor (in alacritty/src/event.rs) cancels the BlinkCursor timer and leaves the cursor visible to save CPU cycles. Set blink_timeout: 0 to disable this behavior and blink indefinitely.
Does VI mode use a different cursor style automatically?
Only if you explicitly configure vi_mode_style in alacritty.yml. If this field is None (the default), VI mode inherits the base style configuration. When provided, Alacritty's display content logic (in alacritty/src/display/content.rs) checks the VI mode state and switches to the override style immediately upon mode entry.
What controls the cursor thickness in Alacritty?
The thickness field in the cursor configuration accepts a percentage value between 0.0 and 1.0, defaulting to 0.15 (15% of the cell width or height). During rendering in alacritty/src/display/cursor.rs, this percentage is multiplied by the character cell dimensions to calculate the actual pixel width of beam and underline cursors, or the border width of hollow blocks.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →