alacritty/alacritty/src/config/cursor.rs

157 lines
4.0 KiB
Rust

use std::cmp;
use std::time::Duration;
use serde::Deserialize;
use alacritty_config_derive::{ConfigDeserialize, SerdeReplace};
use alacritty_terminal::vte::ansi::{CursorShape as VteCursorShape, CursorStyle as VteCursorStyle};
use crate::config::ui_config::Percentage;
/// The minimum blink interval value in milliseconds.
const MIN_BLINK_INTERVAL: u64 = 10;
/// The minimum number of blinks before pausing.
const MIN_BLINK_CYCLES_BEFORE_PAUSE: u64 = 1;
#[derive(ConfigDeserialize, Copy, Clone, Debug, PartialEq)]
pub struct Cursor {
pub style: ConfigCursorStyle,
pub vi_mode_style: Option<ConfigCursorStyle>,
pub unfocused_hollow: bool,
thickness: Percentage,
blink_interval: u64,
blink_timeout: u8,
}
impl Default for Cursor {
fn default() -> Self {
Self {
thickness: Percentage::new(0.15),
unfocused_hollow: true,
blink_interval: 750,
blink_timeout: 5,
style: Default::default(),
vi_mode_style: Default::default(),
}
}
}
impl Cursor {
#[inline]
pub fn thickness(self) -> f32 {
self.thickness.as_f32()
}
#[inline]
pub fn style(self) -> VteCursorStyle {
self.style.into()
}
#[inline]
pub fn vi_mode_style(self) -> Option<VteCursorStyle> {
self.vi_mode_style.map(Into::into)
}
#[inline]
pub fn blink_interval(self) -> u64 {
cmp::max(self.blink_interval, MIN_BLINK_INTERVAL)
}
#[inline]
pub fn blink_timeout(self) -> Duration {
if self.blink_timeout == 0 {
Duration::ZERO
} else {
cmp::max(
// Show/hide is what we consider a cycle, so multiply by `2`.
Duration::from_millis(self.blink_interval * 2 * MIN_BLINK_CYCLES_BEFORE_PAUSE),
Duration::from_secs(self.blink_timeout as u64),
)
}
}
}
#[derive(SerdeReplace, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
#[serde(untagged, deny_unknown_fields)]
pub enum ConfigCursorStyle {
Shape(CursorShape),
WithBlinking {
#[serde(default)]
shape: CursorShape,
#[serde(default)]
blinking: CursorBlinking,
},
}
impl Default for ConfigCursorStyle {
fn default() -> Self {
Self::Shape(CursorShape::default())
}
}
impl ConfigCursorStyle {
/// Check if blinking is force enabled/disabled.
pub fn blinking_override(&self) -> Option<bool> {
match self {
Self::Shape(_) => None,
Self::WithBlinking { blinking, .. } => blinking.blinking_override(),
}
}
}
impl From<ConfigCursorStyle> for VteCursorStyle {
fn from(config_style: ConfigCursorStyle) -> Self {
match config_style {
ConfigCursorStyle::Shape(shape) => Self { shape: shape.into(), blinking: false },
ConfigCursorStyle::WithBlinking { shape, blinking } => {
Self { shape: shape.into(), blinking: blinking.into() }
},
}
}
}
#[derive(ConfigDeserialize, Default, Debug, Copy, Clone, PartialEq, Eq)]
pub enum CursorBlinking {
Never,
#[default]
Off,
On,
Always,
}
impl CursorBlinking {
fn blinking_override(&self) -> Option<bool> {
match self {
Self::Never => Some(false),
Self::Off | Self::On => None,
Self::Always => Some(true),
}
}
}
impl From<CursorBlinking> for bool {
fn from(blinking: CursorBlinking) -> bool {
blinking == CursorBlinking::On || blinking == CursorBlinking::Always
}
}
#[derive(ConfigDeserialize, Debug, Default, Eq, PartialEq, Copy, Clone, Hash)]
pub enum CursorShape {
#[default]
Block,
Underline,
Beam,
}
impl From<CursorShape> for VteCursorShape {
fn from(value: CursorShape) -> Self {
match value {
CursorShape::Block => VteCursorShape::Block,
CursorShape::Underline => VteCursorShape::Underline,
CursorShape::Beam => VteCursorShape::Beam,
}
}
}