aboutsummaryrefslogtreecommitdiff
path: root/alacritty/src/config/cursor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty/src/config/cursor.rs')
-rw-r--r--alacritty/src/config/cursor.rs156
1 files changed, 156 insertions, 0 deletions
diff --git a/alacritty/src/config/cursor.rs b/alacritty/src/config/cursor.rs
new file mode 100644
index 00000000..dc205b4b
--- /dev/null
+++ b/alacritty/src/config/cursor.rs
@@ -0,0 +1,156 @@
+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,
+ }
+ }
+}