aboutsummaryrefslogtreecommitdiff
path: root/alacritty_terminal
diff options
context:
space:
mode:
authorKirill Chibisov <contact@kchibisov.com>2023-11-10 18:16:22 +0400
committerGitHub <noreply@github.com>2023-11-10 18:16:22 +0400
commit5060f8eeb864e8c304fbad9588bdd882db942356 (patch)
treeb615ded19e6ac545b495f716e2a22ecd903332af /alacritty_terminal
parent3ffd6c8f26f9788466b9ba95659b8de970a10f08 (diff)
downloadalacritty-5060f8eeb864e8c304fbad9588bdd882db942356.tar.gz
alacritty-5060f8eeb864e8c304fbad9588bdd882db942356.zip
Remove `alacritty_config` from alacritty_terminal
There's no need to force alacritty's user configuration on other users of the crate, thus provide the options actually used by alacritty_terminal itself.
Diffstat (limited to 'alacritty_terminal')
-rw-r--r--alacritty_terminal/Cargo.toml16
-rw-r--r--alacritty_terminal/src/ansi.rs60
-rw-r--r--alacritty_terminal/src/config/mod.rs263
-rw-r--r--alacritty_terminal/src/config/scrolling.rs58
-rw-r--r--alacritty_terminal/src/event.rs2
-rw-r--r--alacritty_terminal/src/event_loop.rs3
-rw-r--r--alacritty_terminal/src/grid/mod.rs10
-rw-r--r--alacritty_terminal/src/grid/row.rs4
-rw-r--r--alacritty_terminal/src/grid/storage.rs4
-rw-r--r--alacritty_terminal/src/index.rs24
-rw-r--r--alacritty_terminal/src/lib.rs3
-rw-r--r--alacritty_terminal/src/selection.rs7
-rw-r--r--alacritty_terminal/src/term/cell.rs19
-rw-r--r--alacritty_terminal/src/term/color.rs202
-rw-r--r--alacritty_terminal/src/term/mod.rs177
-rw-r--r--alacritty_terminal/src/term/search.rs8
-rw-r--r--alacritty_terminal/src/tty/mod.rs41
-rw-r--r--alacritty_terminal/src/tty/unix.rs9
-rw-r--r--alacritty_terminal/src/tty/windows/conpty.rs4
-rw-r--r--alacritty_terminal/src/tty/windows/mod.rs13
-rw-r--r--alacritty_terminal/src/vi_mode.rs13
-rw-r--r--alacritty_terminal/tests/ref.rs11
22 files changed, 213 insertions, 738 deletions
diff --git a/alacritty_terminal/Cargo.toml b/alacritty_terminal/Cargo.toml
index a0bdac49..a7762b1e 100644
--- a/alacritty_terminal/Cargo.toml
+++ b/alacritty_terminal/Cargo.toml
@@ -9,28 +9,22 @@ homepage = "https://github.com/alacritty/alacritty"
edition = "2021"
rust-version = "1.70.0"
-[dependencies.alacritty_config_derive]
-path = "../alacritty_config_derive"
-version = "0.2.2-dev"
-
-[dependencies.alacritty_config]
-path = "../alacritty_config"
-version = "0.1.2-dev"
+[features]
+default = ["serde"]
+serde = ["dep:serde", "bitflags/serde", "vte/serde"]
[dependencies]
base64 = "0.21.3"
-bitflags = { version = "2.2.1", features = ["serde"] }
+bitflags = "2.4.1"
home = "0.5.5"
libc = "0.2"
log = "0.4"
parking_lot = "0.12.0"
polling = "3.0.0"
regex-automata = "0.3.6"
-serde = { version = "1", features = ["derive", "rc"] }
-serde_yaml = "0.9.25"
-toml = "0.8.2"
unicode-width = "0.1"
vte = { version = "0.12.0", default-features = false, features = ["ansi", "serde"] }
+serde = { version = "1", features = ["derive", "rc"], optional = true }
[target.'cfg(unix)'.dependencies]
rustix-openpty = "0.1.1"
diff --git a/alacritty_terminal/src/ansi.rs b/alacritty_terminal/src/ansi.rs
deleted file mode 100644
index 694520bd..00000000
--- a/alacritty_terminal/src/ansi.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-//! ANSI Terminal Stream Parsing.
-
-pub use vte::ansi::*;
-
-#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
-pub struct CursorShapeShim(CursorShape);
-
-impl Default for CursorShapeShim {
- fn default() -> CursorShapeShim {
- CursorShapeShim(CursorShape::Block)
- }
-}
-
-impl From<CursorShapeShim> for CursorShape {
- fn from(value: CursorShapeShim) -> Self {
- value.0
- }
-}
-
-struct CursorShapeVisitor;
-
-impl<'de> serde::de::Visitor<'de> for CursorShapeVisitor {
- type Value = CursorShapeShim;
-
- fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- formatter.write_str("one of `Block`, `Underline`, `Beam`")
- }
-
- fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
- where
- E: serde::de::Error,
- {
- match s.to_lowercase().as_str() {
- "block" => Ok(CursorShapeShim(CursorShape::Block)),
- "underline" => Ok(CursorShapeShim(CursorShape::Underline)),
- "beam" => Ok(CursorShapeShim(CursorShape::Beam)),
- _ => Err(E::custom(format!(
- "unknown variant `{0}`, expected {1}",
- s, "one of `Block`, `Underline`, `Beam`"
- ))),
- }
- }
-}
-
-impl<'de> serde::Deserialize<'de> for CursorShapeShim {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: serde::Deserializer<'de>,
- {
- deserializer.deserialize_str(CursorShapeVisitor)
- }
-}
-
-impl alacritty_config::SerdeReplace for CursorShapeShim {
- fn replace(&mut self, value: toml::Value) -> Result<(), Box<dyn std::error::Error>> {
- *self = serde::Deserialize::deserialize(value)?;
-
- Ok(())
- }
-}
diff --git a/alacritty_terminal/src/config/mod.rs b/alacritty_terminal/src/config/mod.rs
deleted file mode 100644
index d713e67b..00000000
--- a/alacritty_terminal/src/config/mod.rs
+++ /dev/null
@@ -1,263 +0,0 @@
-use std::cmp;
-use std::collections::HashMap;
-use std::path::PathBuf;
-
-use serde::Deserialize;
-
-use alacritty_config_derive::{ConfigDeserialize, SerdeReplace};
-
-mod scrolling;
-
-use crate::ansi::{CursorShapeShim, CursorStyle};
-
-pub use crate::config::scrolling::{Scrolling, MAX_SCROLLBACK_LINES};
-
-/// Logging target for config error messages.
-pub const LOG_TARGET_CONFIG: &str = "alacritty_config_derive";
-
-const MIN_BLINK_INTERVAL: u64 = 10;
-
-/// Top-level config type.
-#[derive(ConfigDeserialize, Clone, Debug, PartialEq, Default)]
-pub struct Config {
- /// TERM env variable.
- pub env: HashMap<String, String>,
-
- pub selection: Selection,
-
- /// How much scrolling history to keep.
- pub scrolling: Scrolling,
-
- /// Cursor configuration.
- pub cursor: Cursor,
-
- /// Terminal specific settings.
- pub terminal: Terminal,
-
- #[config(flatten)]
- pub pty_config: PtyConfig,
-}
-
-#[derive(ConfigDeserialize, Clone, Debug, PartialEq, Eq, Default)]
-pub struct Terminal {
- // OSC 52 handling (clipboard handling).
- pub osc52: Osc52,
-}
-
-#[derive(ConfigDeserialize, Clone, Debug, PartialEq, Eq, Default)]
-pub enum Osc52 {
- /// The handling of the escape sequence is disabled.
- Disabled,
- /// Only copy sequence is accepted.
- ///
- /// This option is the default as a compromise between entirely
- /// disabling it (the most secure) and allowing `paste` (the less secure).
- #[default]
- OnlyCopy,
- /// Only paste sequence is accepted.
- OnlyPaste,
- /// Both are accepted.
- CopyPaste,
-}
-
-#[derive(ConfigDeserialize, Clone, Debug, PartialEq, Eq, Default)]
-pub struct PtyConfig {
- /// Path to a shell program to run on startup.
- pub shell: Option<Program>,
-
- /// Shell startup directory.
- pub working_directory: Option<PathBuf>,
-
- /// Remain open after child process exits.
- #[config(skip)]
- pub hold: bool,
-}
-
-impl PtyConfig {
- pub fn new() -> Self {
- Default::default()
- }
-}
-
-#[derive(ConfigDeserialize, Clone, Debug, PartialEq, Eq)]
-pub struct Selection {
- pub semantic_escape_chars: String,
- pub save_to_clipboard: bool,
-}
-
-impl Default for Selection {
- fn default() -> Self {
- Self {
- semantic_escape_chars: String::from(",│`|:\"' ()[]{}<>\t"),
- save_to_clipboard: Default::default(),
- }
- }
-}
-
-#[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(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) -> CursorStyle {
- self.style.into()
- }
-
- #[inline]
- pub fn vi_mode_style(self) -> Option<CursorStyle> {
- self.vi_mode_style.map(From::from)
- }
-
- #[inline]
- pub fn blink_interval(self) -> u64 {
- cmp::max(self.blink_interval, MIN_BLINK_INTERVAL)
- }
-
- #[inline]
- pub fn blink_timeout(self) -> u64 {
- const MILLIS_IN_SECOND: u64 = 1000;
- match self.blink_timeout {
- 0 => 0,
- blink_timeout => {
- cmp::max(self.blink_interval * 5 / MILLIS_IN_SECOND, blink_timeout as u64)
- },
- }
- }
-}
-
-#[derive(SerdeReplace, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
-#[serde(untagged, deny_unknown_fields)]
-pub enum ConfigCursorStyle {
- Shape(CursorShapeShim),
- WithBlinking {
- #[serde(default)]
- shape: CursorShapeShim,
- #[serde(default)]
- blinking: CursorBlinking,
- },
-}
-
-impl Default for ConfigCursorStyle {
- fn default() -> Self {
- Self::Shape(CursorShapeShim::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 CursorStyle {
- 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(Deserialize, Debug, Clone, PartialEq, Eq)]
-#[serde(untagged, deny_unknown_fields)]
-pub enum Program {
- Just(String),
- WithArgs {
- program: String,
- #[serde(default)]
- args: Vec<String>,
- },
-}
-
-impl Program {
- pub fn program(&self) -> &str {
- match self {
- Program::Just(program) => program,
- Program::WithArgs { program, .. } => program,
- }
- }
-
- pub fn args(&self) -> &[String] {
- match self {
- Program::Just(_) => &[],
- Program::WithArgs { args, .. } => args,
- }
- }
-}
-
-/// Wrapper around f32 that represents a percentage value between 0.0 and 1.0.
-#[derive(SerdeReplace, Deserialize, Clone, Copy, Debug, PartialEq)]
-pub struct Percentage(f32);
-
-impl Default for Percentage {
- fn default() -> Self {
- Percentage(1.0)
- }
-}
-
-impl Percentage {
- pub fn new(value: f32) -> Self {
- Percentage(value.clamp(0., 1.))
- }
-
- pub fn as_f32(self) -> f32 {
- self.0
- }
-}
diff --git a/alacritty_terminal/src/config/scrolling.rs b/alacritty_terminal/src/config/scrolling.rs
deleted file mode 100644
index 7ff306a9..00000000
--- a/alacritty_terminal/src/config/scrolling.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-use serde::de::Error as SerdeError;
-use serde::{Deserialize, Deserializer};
-
-use alacritty_config_derive::{ConfigDeserialize, SerdeReplace};
-
-/// Maximum scrollback amount configurable.
-pub const MAX_SCROLLBACK_LINES: u32 = 100_000;
-
-/// Struct for scrolling related settings.
-#[derive(ConfigDeserialize, Copy, Clone, Debug, PartialEq, Eq)]
-pub struct Scrolling {
- pub multiplier: u8,
-
- history: ScrollingHistory,
-}
-
-impl Default for Scrolling {
- fn default() -> Self {
- Self { multiplier: 3, history: Default::default() }
- }
-}
-
-impl Scrolling {
- pub fn history(self) -> u32 {
- self.history.0
- }
-
- // Update the history size, used in ref tests.
- pub fn set_history(&mut self, history: u32) {
- self.history = ScrollingHistory(history);
- }
-}
-
-#[derive(SerdeReplace, Copy, Clone, Debug, PartialEq, Eq)]
-struct ScrollingHistory(u32);
-
-impl Default for ScrollingHistory {
- fn default() -> Self {
- Self(10_000)
- }
-}
-
-impl<'de> Deserialize<'de> for ScrollingHistory {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: Deserializer<'de>,
- {
- let lines = u32::deserialize(deserializer)?;
-
- if lines > MAX_SCROLLBACK_LINES {
- Err(SerdeError::custom(format!(
- "exceeded maximum scrolling history ({lines}/{MAX_SCROLLBACK_LINES})"
- )))
- } else {
- Ok(Self(lines))
- }
- }
-}
diff --git a/alacritty_terminal/src/event.rs b/alacritty_terminal/src/event.rs
index 5849eb1e..caa1e9d6 100644
--- a/alacritty_terminal/src/event.rs
+++ b/alacritty_terminal/src/event.rs
@@ -2,8 +2,8 @@ use std::borrow::Cow;
use std::fmt::{self, Debug, Formatter};
use std::sync::Arc;
-use crate::term::color::Rgb;
use crate::term::ClipboardType;
+use crate::vte::ansi::Rgb;
/// Terminal event.
///
diff --git a/alacritty_terminal/src/event_loop.rs b/alacritty_terminal/src/event_loop.rs
index de22e49d..9b089313 100644
--- a/alacritty_terminal/src/event_loop.rs
+++ b/alacritty_terminal/src/event_loop.rs
@@ -17,7 +17,8 @@ use polling::{Event as PollingEvent, Events, PollMode};
use crate::event::{self, Event, EventListener, WindowSize};
use crate::sync::FairMutex;
use crate::term::Term;
-use crate::{ansi, thread, tty};
+use crate::vte::ansi;
+use crate::{thread, tty};
/// Max bytes to read from the PTY before forced terminal synchronization.
pub(crate) const READ_BUFFER_SIZE: usize = 0x10_0000;
diff --git a/alacritty_terminal/src/grid/mod.rs b/alacritty_terminal/src/grid/mod.rs
index 232201ec..8fdde0a4 100644
--- a/alacritty_terminal/src/grid/mod.rs
+++ b/alacritty_terminal/src/grid/mod.rs
@@ -3,11 +3,12 @@
use std::cmp::{max, min};
use std::ops::{Bound, Deref, Index, IndexMut, Range, RangeBounds};
+#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
-use crate::ansi::{CharsetIndex, StandardCharset};
use crate::index::{Column, Line, Point};
use crate::term::cell::{Flags, ResetDiscriminant};
+use crate::vte::ansi::{CharsetIndex, StandardCharset};
pub mod resize;
mod row;
@@ -104,14 +105,15 @@ pub enum Scroll {
/// ^
/// columns
/// ```
-#[derive(Serialize, Deserialize, Clone, Debug)]
+#[derive(Clone, Debug)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Grid<T> {
/// Current cursor for writing data.
- #[serde(skip)]
+ #[cfg_attr(feature = "serde", serde(skip))]
pub cursor: Cursor<T>,
/// Last saved cursor.
- #[serde(skip)]
+ #[cfg_attr(feature = "serde", serde(skip))]
pub saved_cursor: Cursor<T>,
/// Lines in the grid. Each row holds a list of cells corresponding to the
diff --git a/alacritty_terminal/src/grid/row.rs b/alacritty_terminal/src/grid/row.rs
index 2a92a78c..951ef093 100644
--- a/alacritty_terminal/src/grid/row.rs
+++ b/alacritty_terminal/src/grid/row.rs
@@ -4,6 +4,7 @@ use std::cmp::{max, min};
use std::ops::{Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo, RangeToInclusive};
use std::{ptr, slice};
+#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::grid::GridCell;
@@ -11,7 +12,8 @@ use crate::index::Column;
use crate::term::cell::ResetDiscriminant;
/// A row in the grid.
-#[derive(Serialize, Deserialize, Default, Clone, Debug)]
+#[derive(Default, Clone, Debug)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Row<T> {
inner: Vec<T>,
diff --git a/alacritty_terminal/src/grid/storage.rs b/alacritty_terminal/src/grid/storage.rs
index 8e270d2d..d5709d14 100644
--- a/alacritty_terminal/src/grid/storage.rs
+++ b/alacritty_terminal/src/grid/storage.rs
@@ -3,6 +3,7 @@ use std::mem;
use std::mem::MaybeUninit;
use std::ops::{Index, IndexMut};
+#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use super::Row;
@@ -27,7 +28,8 @@ const MAX_CACHE_SIZE: usize = 1_000;
/// [`slice::rotate_left`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rotate_left
/// [`Deref`]: std::ops::Deref
/// [`zero`]: #structfield.zero
-#[derive(Serialize, Deserialize, Clone, Debug)]
+#[derive(Clone, Debug)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Storage<T> {
inner: Vec<Row<T>>,
diff --git a/alacritty_terminal/src/index.rs b/alacritty_terminal/src/index.rs
index 9464b8d8..dd7faa7b 100644
--- a/alacritty_terminal/src/index.rs
+++ b/alacritty_terminal/src/index.rs
@@ -5,10 +5,9 @@ use std::cmp::{max, min, Ord, Ordering};
use std::fmt;
use std::ops::{Add, AddAssign, Deref, Sub, SubAssign};
+#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
-use alacritty_config_derive::SerdeReplace;
-
use crate::grid::Dimensions;
/// The side of a cell.
@@ -46,7 +45,8 @@ pub enum Boundary {
}
/// Index in the grid using row, column notation.
-#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default, Eq, PartialEq)]
+#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Point<L = Line, C = Column> {
pub line: L,
pub column: C,
@@ -131,7 +131,8 @@ impl<L: Ord, C: Ord> Ord for Point<L, C> {
/// A line.
///
/// Newtype to avoid passing values incorrectly.
-#[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq, Default, Ord, PartialOrd)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Ord, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Line(pub i32);
impl Line {
@@ -224,19 +225,8 @@ impl PartialEq<usize> for Line {
/// A column.
///
/// Newtype to avoid passing values incorrectly.
-#[derive(
- SerdeReplace,
- Serialize,
- Deserialize,
- Debug,
- Copy,
- Clone,
- Eq,
- PartialEq,
- Default,
- Ord,
- PartialOrd,
-)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Ord, PartialOrd)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Column(pub usize);
impl fmt::Display for Column {
diff --git a/alacritty_terminal/src/lib.rs b/alacritty_terminal/src/lib.rs
index c1ba3690..7e4e68b1 100644
--- a/alacritty_terminal/src/lib.rs
+++ b/alacritty_terminal/src/lib.rs
@@ -4,8 +4,6 @@
#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use)]
#![cfg_attr(feature = "cargo-clippy", deny(warnings))]
-pub mod ansi;
-pub mod config;
pub mod event;
pub mod event_loop;
pub mod grid;
@@ -19,3 +17,4 @@ pub mod vi_mode;
pub use crate::grid::Grid;
pub use crate::term::Term;
+pub use vte;
diff --git a/alacritty_terminal/src/selection.rs b/alacritty_terminal/src/selection.rs
index 1536724c..31b7b309 100644
--- a/alacritty_terminal/src/selection.rs
+++ b/alacritty_terminal/src/selection.rs
@@ -9,11 +9,11 @@ use std::cmp::min;
use std::mem;
use std::ops::{Bound, Range, RangeBounds};
-use crate::ansi::CursorShape;
use crate::grid::{Dimensions, GridCell, Indexed};
use crate::index::{Boundary, Column, Line, Point, Side};
use crate::term::cell::{Cell, Flags};
use crate::term::Term;
+use crate::vte::ansi::CursorShape;
/// A Point and side within that point.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -395,14 +395,13 @@ impl Selection {
mod tests {
use super::*;
- use crate::config::Config;
use crate::index::{Column, Point, Side};
use crate::term::test::TermSize;
- use crate::term::Term;
+ use crate::term::{Config, Term};
fn term(height: usize, width: usize) -> Term<()> {
let size = TermSize::new(width, height);
- Term::new(&Config::default(), &size, ())
+ Term::new(Config::default(), &size, ())
}
/// Test case of single cell selection.
diff --git a/alacritty_terminal/src/term/cell.rs b/alacritty_terminal/src/term/cell.rs
index 927687fb..81dc1e3a 100644
--- a/alacritty_terminal/src/term/cell.rs
+++ b/alacritty_terminal/src/term/cell.rs
@@ -2,15 +2,16 @@ use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
use bitflags::bitflags;
+#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
-use vte::ansi::Hyperlink as VteHyperlink;
-use crate::ansi::{Color, NamedColor};
use crate::grid::{self, GridCell};
use crate::index::Column;
+use crate::vte::ansi::{Color, Hyperlink as VteHyperlink, NamedColor};
bitflags! {
- #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Flags: u16 {
const INVERSE = 0b0000_0000_0000_0001;
const BOLD = 0b0000_0000_0000_0010;
@@ -38,7 +39,8 @@ bitflags! {
/// Counter for hyperlinks without explicit ID.
static HYPERLINK_ID_SUFFIX: AtomicU32 = AtomicU32::new(0);
-#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Hyperlink {
inner: Arc<HyperlinkInner>,
}
@@ -70,7 +72,8 @@ impl From<Hyperlink> for VteHyperlink {
}
}
-#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash)]
+#[derive(Debug, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
struct HyperlinkInner {
/// Identifier for the given hyperlink.
id: String,
@@ -117,7 +120,8 @@ impl ResetDiscriminant<Color> for Cell {
/// This storage is reserved for cell attributes which are rarely set. This allows reducing the
/// allocation required ahead of time for every cell, with some additional overhead when the extra
/// storage is actually required.
-#[derive(Serialize, Deserialize, Default, Debug, Clone, Eq, PartialEq)]
+#[derive(Default, Debug, Clone, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct CellExtra {
zerowidth: Vec<char>,
@@ -127,7 +131,8 @@ pub struct CellExtra {
}
/// Content and attributes of a single cell in the terminal grid.
-#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Cell {
pub c: char,
pub fg: Color,
diff --git a/alacritty_terminal/src/term/color.rs b/alacritty_terminal/src/term/color.rs
index b4bdba3a..66753deb 100644
--- a/alacritty_terminal/src/term/color.rs
+++ b/alacritty_terminal/src/term/color.rs
@@ -1,208 +1,10 @@
-use std::fmt::{self, Display, Formatter};
-use std::ops::{Add, Deref, Index, IndexMut, Mul};
-use std::str::FromStr;
+use std::ops::{Index, IndexMut};
-use serde::de::{Error as _, Visitor};
-use serde::{Deserialize, Deserializer, Serialize};
-use serde_yaml::Value;
-
-use alacritty_config_derive::SerdeReplace;
-
-use vte::ansi::Rgb as VteRgb;
-
-use crate::ansi::NamedColor;
+use crate::vte::ansi::{NamedColor, Rgb};
/// Number of terminal colors.
pub const COUNT: usize = 269;
-#[derive(SerdeReplace, Debug, Eq, PartialEq, Copy, Clone, Default, Serialize)]
-pub struct Rgb(VteRgb);
-
-impl Rgb {
- #[inline]
- pub const fn new(r: u8, g: u8, b: u8) -> Self {
- Self(VteRgb { r, g, b })
- }
-
- #[inline]
- pub fn as_tuple(self) -> (u8, u8, u8) {
- (self.0.r, self.0.g, self.0.b)
- }
-}
-
-impl From<VteRgb> for Rgb {
- fn from(value: VteRgb) -> Self {
- Self(value)
- }
-}
-
-impl Deref for Rgb {
- type Target = VteRgb;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-
-impl Mul<f32> for Rgb {
- type Output = Rgb;
-
- fn mul(self, rhs: f32) -> Self::Output {
- Rgb(self.0 * rhs)
- }
-}
-
-impl Add<Rgb> for Rgb {
- type Output = Rgb;
-
- fn add(self, rhs: Rgb) -> Self::Output {
- Rgb(self.0 + rhs.0)
- }
-}
-
-/// Deserialize an Rgb from a hex string.
-///
-/// This is *not* the deserialize impl for Rgb since we want a symmetric
-/// serialize/deserialize impl for ref tests.
-impl<'de> Deserialize<'de> for Rgb {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: Deserializer<'de>,
- {
- struct RgbVisitor;
-
- // Used for deserializing reftests.
- #[derive(Deserialize)]
- struct RgbDerivedDeser {
- r: u8,
- g: u8,
- b: u8,
- }
-
- impl<'a> Visitor<'a> for RgbVisitor {
- type Value = Rgb;
-
- fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
- f.write_str("hex color like #ff00ff")
- }
-
- fn visit_str<E>(self, value: &str) -> Result<Rgb, E>
- where
- E: serde::de::Error,
- {
- Rgb::from_str(value).map_err(|_| {
- E::custom(format!(
- "failed to parse rgb color {value}; expected hex color like #ff00ff"
- ))
- })
- }
- }
-
- // Return an error if the syntax is incorrect.
- let value = Value::deserialize(deserializer)?;
-
- // Attempt to deserialize from struct form.
- if let Ok(RgbDerivedDeser { r, g, b }) = RgbDerivedDeser::deserialize(value.clone()) {
- return Ok(Rgb::new(r, g, b));
- }
-
- // Deserialize from hex notation (either 0xff00ff or #ff00ff).
- value.deserialize_str(RgbVisitor).map_err(D::Error::custom)
- }
-}
-
-impl Display for Rgb {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- write!(f, "#{:02x}{:02x}{:02x}", self.r, self.g, self.b)
- }
-}
-
-impl FromStr for Rgb {
- type Err = ();
-
- fn from_str(s: &str) -> Result<Rgb, ()> {
- let chars = if s.starts_with("0x") && s.len() == 8 {
- &s[2..]
- } else if s.starts_with('#') && s.len() == 7 {
- &s[1..]
- } else {
- return Err(());
- };
-
- match u32::from_str_radix(chars, 16) {
- Ok(mut color) => {
- let b = (color & 0xff) as u8;
- color >>= 8;
- let g = (color & 0xff) as u8;
- color >>= 8;
- let r = color as u8;
- Ok(Rgb::new(r, g, b))
- },
- Err(_) => Err(()),
- }
- }
-}
-
-/// RGB color optionally referencing the cell's foreground or background.
-#[derive(SerdeReplace, Copy, Clone, Debug, PartialEq, Eq)]
-pub enum CellRgb {
- CellForeground,
- CellBackground,
- Rgb(Rgb),
-}
-
-impl CellRgb {
- pub fn color(self, foreground: Rgb, background: Rgb) -> Rgb {
- match self {
- Self::CellForeground => foreground,
- Self::CellBackground => background,
- Self::Rgb(rgb) => rgb,
- }
- }
-}
-
-impl Default for CellRgb {
- fn default() -> Self {
- Self::Rgb(Rgb::default())
- }
-}
-
-impl<'de> Deserialize<'de> for CellRgb {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: Deserializer<'de>,
- {
- const EXPECTING: &str = "CellForeground, CellBackground, or hex color like #ff00ff";
-
- struct CellRgbVisitor;
- impl<'a> Visitor<'a> for CellRgbVisitor {
- type Value = CellRgb;
-
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str(EXPECTING)
- }
-
- fn visit_str<E>(self, value: &str) -> Result<CellRgb, E>
- where
- E: serde::de::Error,
- {
- // Attempt to deserialize as enum constants.
- match value {
- "CellForeground" => return Ok(CellRgb::CellForeground),
- "CellBackground" => return Ok(CellRgb::CellBackground),
- _ => (),
- }
-
- Rgb::from_str(value).map(CellRgb::Rgb).map_err(|_| {
- E::custom(format!("failed to parse color {value}; expected {EXPECTING}"))
- })
- }
- }
-
- deserializer.deserialize_str(CellRgbVisitor).map_err(D::Error::custom)
- }
-}
-
/// Array of indexed colors.
///
/// | Indices | Description |
diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs
index b2f4ea61..622ec5f8 100644
--- a/alacritty_terminal/src/term/mod.rs
+++ b/alacritty_terminal/src/term/mod.rs
@@ -4,17 +4,15 @@ use std::ops::{Index, IndexMut, Range};
use std::sync::Arc;
use std::{cmp, mem, ptr, slice, str};
+#[cfg(feature = "serde")]
+use serde::{Deserialize, Serialize};
+
use base64::engine::general_purpose::STANDARD as Base64;
use base64::Engine;
use bitflags::bitflags;
use log::{debug, trace};
use unicode_width::UnicodeWidthChar;
-use vte::ansi::{Hyperlink as VteHyperlink, Rgb as VteRgb};
-use crate::ansi::{
- self, Attr, CharsetIndex, Color, CursorShape, CursorStyle, Handler, NamedColor, StandardCharset,
-};
-use crate::config::{Config, Osc52, Terminal};
use crate::event::{Event, EventListener};
use crate::grid::{Dimensions, Grid, GridIterator, Scroll};
use crate::index::{self, Boundary, Column, Direction, Line, Point, Side};
@@ -22,6 +20,10 @@ use crate::selection::{Selection, SelectionRange, SelectionType};
use crate::term::cell::{Cell, Flags, LineLength};
use crate::term::color::Colors;
use crate::vi_mode::{ViModeCursor, ViMotion};
+use crate::vte::ansi::{
+ self, Attr, CharsetIndex, Color, CursorShape, CursorStyle, Handler, Hyperlink, NamedColor, Rgb,
+ StandardCharset,
+};
pub mod cell;
pub mod color;
@@ -38,6 +40,9 @@ pub const MIN_SCREEN_LINES: usize = 1;
/// Max size of the window title stack.
const TITLE_STACK_MAX_DEPTH: usize = 4096;
+/// Default semantic escape characters.
+pub const SEMANTIC_ESCAPE_CHARS: &str = ",│`|:\"' ()[]{}<>\t";
+
/// Default tab interval, corresponding to terminfo `it` value.
const INITIAL_TABSTOPS: usize = 8;
@@ -280,20 +285,12 @@ pub struct Term<T> {
/// Range going from top to bottom of the terminal, indexed from the top of the viewport.
scroll_region: Range<Line>,
- semantic_escape_chars: String,
-
/// Modified terminal colors.
colors: Colors,
/// Current style of the cursor.
cursor_style: Option<CursorStyle>,
- /// Default style for resetting the cursor.
- default_cursor_style: CursorStyle,
-
- /// Style of the vi mode cursor.
- vi_mode_cursor_style: Option<CursorStyle>,
-
/// Proxy for sending events to the event loop.
event_proxy: T,
@@ -308,7 +305,58 @@ pub struct Term<T> {
damage: TermDamageState,
/// Config directly for the terminal.
- config: Terminal,
+ config: Config,
+}
+
+/// Configuration options for the [`Term`].
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Config {
+ /// The maximum amount of scrolling history.
+ pub scrolling_history: usize,
+
+ /// Default cursor style to reset the cursor to.
+ pub default_cursor_style: CursorStyle,
+
+ /// Cursor style for Vi mode.
+ pub vi_mode_cursor_style: Option<CursorStyle>,
+
+ /// The characters which terminate semantic selection.
+ ///
+ /// The default value is [`SEMANTIC_ESCAPE_CHARS`].
+ pub semantic_escape_chars: String,
+
+ /// OSC52 support mode.
+ pub osc52: Osc52,
+}
+
+impl Default for Config {
+ fn default() -> Self {
+ Self {
+ scrolling_history: 10000,
+ semantic_escape_chars: SEMANTIC_ESCAPE_CHARS.to_owned(),
+ default_cursor_style: Default::default(),
+ vi_mode_cursor_style: Default::default(),
+ osc52: Default::default(),
+ }
+ }
+}
+
+/// OSC 52 behavior.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "lowercase"))]
+pub enum Osc52 {
+ /// The handling of the escape sequence is disabled.
+ Disabled,
+ /// Only copy sequence is accepted.
+ ///
+ /// This option is the default as a compromise between entirely
+ /// disabling it (the most secure) and allowing `paste` (the less secure).
+ #[default]
+ OnlyCopy,
+ /// Only paste sequence is accepted.
+ OnlyPaste,
+ /// Both are accepted.
+ CopyPaste,
}
impl<T> Term<T> {
@@ -334,11 +382,11 @@ impl<T> Term<T> {
}
}
- pub fn new<D: Dimensions>(config: &Config, dimensions: &D, event_proxy: T) -> Term<T> {
+ pub fn new<D: Dimensions>(options: Config, dimensions: &D, event_proxy: T) -> Term<T> {
let num_cols = dimensions.columns();
let num_lines = dimensions.screen_lines();
- let history_size = config.scrolling.history() as usize;
+ let history_size = options.scrolling_history;
let grid = Grid::new(num_lines, num_cols, history_size);
let alt = Grid::new(num_lines, num_cols, 0);
@@ -358,17 +406,14 @@ impl<T> Term<T> {
mode: Default::default(),
scroll_region,
colors: color::Colors::default(),
- semantic_escape_chars: config.selection.semantic_escape_chars.to_owned(),
cursor_style: None,
- default_cursor_style: config.cursor.style(),
- vi_mode_cursor_style: config.cursor.vi_mode_style(),
event_proxy,
is_focused: true,
title: None,
title_stack: Vec::new(),
selection: None,
damage,
- config: config.terminal.clone(),
+ config: options,
}
}
@@ -446,13 +491,12 @@ impl<T> Term<T> {
self.damage.damage_line(line, left, right);
}
- pub fn update_config(&mut self, config: &Config)
+ /// Set new options for the [`Term`].
+ pub fn set_options(&mut self, options: Config)
where
T: EventListener,
{
- self.semantic_escape_chars = config.selection.semantic_escape_chars.to_owned();
- self.default_cursor_style = config.cursor.style();
- self.vi_mode_cursor_style = config.cursor.vi_mode_style();
+ self.config = options;
let title_event = match &self.title {
Some(title) => Event::Title(title.clone()),
@@ -462,13 +506,11 @@ impl<T> Term<T> {
self.event_proxy.send_event(title_event);
if self.mode.contains(TermMode::ALT_SCREEN) {
- self.inactive_grid.update_history(config.scrolling.history() as usize);
+ self.inactive_grid.update_history(self.config.scrolling_history);
} else {
- self.grid.update_history(config.scrolling.history() as usize);
+ self.grid.update_history(self.config.scrolling_history);
}
- self.config = config.terminal.clone();
-
// Damage everything on config updates.
self.mark_fully_damaged();
}
@@ -870,7 +912,7 @@ impl<T> Term<T> {
#[inline]
pub fn semantic_escape_chars(&self) -> &str {
- &self.semantic_escape_chars
+ &self.config.semantic_escape_chars
}
/// Active terminal cursor style.
@@ -878,10 +920,10 @@ impl<T> Term<T> {
/// While vi mode is active, this will automatically return the vi mode cursor style.
#[inline]
pub fn cursor_style(&self) -> CursorStyle {
- let cursor_style = self.cursor_style.unwrap_or(self.default_cursor_style);
+ let cursor_style = self.cursor_style.unwrap_or(self.config.default_cursor_style);
if self.mode.contains(TermMode::VI) {
- self.vi_mode_cursor_style.unwrap_or(cursor_style)
+ self.config.vi_mode_cursor_style.unwrap_or(cursor_style)
} else {
cursor_style
}
@@ -1501,11 +1543,9 @@ impl<T: EventListener> Handler for Term<T> {
/// Set the indexed color value.
#[inline]
- fn set_color(&mut self, index: usize, color: VteRgb) {
+ fn set_color(&mut self, index: usize, color: Rgb) {
trace!("Setting color[{}] = {:?}", index, color);
- let color = color.into();
-
// Damage terminal if the color changed and it's not the cursor.
if index != NamedColor::Cursor as usize && self.colors[index] != Some(color) {
self.mark_fully_damaged();
@@ -1713,7 +1753,7 @@ impl<T: EventListener> Handler for Term<T> {
}
#[inline]
- fn set_hyperlink(&mut self, hyperlink: Option<VteHyperlink>) {
+ fn set_hyperlink(&mut self, hyperlink: Option<Hyperlink>) {
trace!("Setting hyperlink: {:?}", hyperlink);
self.grid.cursor.template.set_hyperlink(hyperlink.map(|e| e.into()));
}
@@ -1818,7 +1858,7 @@ impl<T: EventListener> Handler for Term<T> {
ansi::Mode::ColumnMode => self.deccolm(),
ansi::Mode::Insert => self.mode.insert(TermMode::INSERT),
ansi::Mode::BlinkingCursor => {
- let style = self.cursor_style.get_or_insert(self.default_cursor_style);
+ let style = self.cursor_style.get_or_insert(self.config.default_cursor_style);
style.blinking = true;
self.event_proxy.send_event(Event::CursorBlinkingChange);
},
@@ -1863,7 +1903,7 @@ impl<T: EventListener> Handler for Term<T> {
self.mark_fully_damaged();
},
ansi::Mode::BlinkingCursor => {
- let style = self.cursor_style.get_or_insert(self.default_cursor_style);
+ let style = self.cursor_style.get_or_insert(self.config.default_cursor_style);
style.blinking = false;
self.event_proxy.send_event(Event::CursorBlinkingChange);
},
@@ -1932,7 +1972,7 @@ impl<T: EventListener> Handler for Term<T> {
fn set_cursor_shape(&mut self, shape: CursorShape) {
trace!("Setting cursor shape {:?}", shape);
- let style = self.cursor_style.get_or_insert(self.default_cursor_style);
+ let style = self.cursor_style.get_or_insert(self.config.default_cursor_style);
style.shape = shape;
}
@@ -2118,14 +2158,14 @@ impl<'a> RenderableContent<'a> {
pub mod test {
use super::*;
+ #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use unicode_width::UnicodeWidthChar;
- use crate::config::Config;
use crate::event::VoidListener;
use crate::index::Column;
- #[derive(Serialize, Deserialize)]
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TermSize {
pub columns: usize,
pub screen_lines: usize,
@@ -2180,7 +2220,7 @@ pub mod test {
// Create terminal with the appropriate dimensions.
let size = TermSize::new(num_cols, lines.len());
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
// Fill terminal with content.
for (line, text) in lines.iter().enumerate() {
@@ -2214,19 +2254,18 @@ mod tests {
use std::mem;
- use crate::ansi::{self, CharsetIndex, Handler, StandardCharset};
- use crate::config::Config;
use crate::event::VoidListener;
use crate::grid::{Grid, Scroll};
use crate::index::{Column, Point, Side};
use crate::selection::{Selection, SelectionType};
use crate::term::cell::{Cell, Flags};
use crate::term::test::TermSize;
+ use crate::vte::ansi::{self, CharsetIndex, Handler, StandardCharset};
#[test]
fn scroll_display_page_up() {
let size = TermSize::new(5, 10);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
// Create 11 lines of scrollback.
for _ in 0..20 {
@@ -2252,7 +2291,7 @@ mod tests {
#[test]
fn scroll_display_page_down() {
let size = TermSize::new(5, 10);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
// Create 11 lines of scrollback.
for _ in 0..20 {
@@ -2282,7 +2321,7 @@ mod tests {
#[test]
fn simple_selection_works() {
let size = TermSize::new(5, 5);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
let grid = term.grid_mut();
for i in 0..4 {
if i == 1 {
@@ -2328,7 +2367,7 @@ mod tests {
#[test]
fn semantic_selection_works() {
let size = TermSize::new(5, 3);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
let mut grid: Grid<Cell> = Grid::new(3, 5, 0);
for i in 0..5 {
for j in 0..2 {
@@ -2343,7 +2382,7 @@ mod tests {
let mut escape_chars = String::from("\"");
mem::swap(&mut term.grid, &mut grid);
- mem::swap(&mut term.semantic_escape_chars, &mut escape_chars);
+ mem::swap(&mut term.config.semantic_escape_chars, &mut escape_chars);
{
term.selection = Some(Selection::new(
@@ -2376,7 +2415,7 @@ mod tests {
#[test]
fn line_selection_works() {
let size = TermSize::new(5, 1);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
let mut grid: Grid<Cell> = Grid::new(1, 5, 0);
for i in 0..5 {
grid[Line(0)][Column(i)].c = 'a';
@@ -2397,7 +2436,7 @@ mod tests {
#[test]
fn block_selection_works() {
let size = TermSize::new(5, 5);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
let grid = term.grid_mut();
for i in 1..4 {
grid[Line(i)][Column(0)].c = '"';
@@ -2453,7 +2492,7 @@ mod tests {
#[test]
fn input_line_drawing_character() {
let size = TermSize::new(7, 17);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
let cursor = Point::new(Line(0), Column(0));
term.configure_charset(CharsetIndex::G0, StandardCharset::SpecialCharacterAndLineDrawing);
term.input('a');
@@ -2464,7 +2503,7 @@ mod tests {
#[test]
fn clearing_viewport_keeps_history_position() {
let size = TermSize::new(10, 20);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
// Create 10 lines of scrollback.
for _ in 0..29 {
@@ -2485,7 +2524,7 @@ mod tests {
#[test]
fn clearing_viewport_with_vi_mode_keeps_history_position() {
let size = TermSize::new(10, 20);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
// Create 10 lines of scrollback.
for _ in 0..29 {
@@ -2511,7 +2550,7 @@ mod tests {
#[test]
fn clearing_scrollback_resets_display_offset() {
let size = TermSize::new(10, 20);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
// Create 10 lines of scrollback.
for _ in 0..29 {
@@ -2532,7 +2571,7 @@ mod tests {
#[test]
fn clearing_scrollback_sets_vi_cursor_into_viewport() {
let size = TermSize::new(10, 20);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
// Create 10 lines of scrollback.
for _ in 0..29 {
@@ -2558,7 +2597,7 @@ mod tests {
#[test]
fn clear_saved_lines() {
let size = TermSize::new(7, 17);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
// Add one line of scrollback.
term.grid.scroll_up(&(Line(0)..Line(1)), 1);
@@ -2580,7 +2619,7 @@ mod tests {
#[test]
fn vi_cursor_keep_pos_on_scrollback_buffer() {
let size = TermSize::new(5, 10);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
// Create 11 lines of scrollback.
for _ in 0..20 {
@@ -2600,7 +2639,7 @@ mod tests {
#[test]
fn grow_lines_updates_active_cursor_pos() {
let mut size = TermSize::new(100, 10);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
// Create 10 lines of scrollback.
for _ in 0..19 {
@@ -2620,7 +2659,7 @@ mod tests {
#[test]
fn grow_lines_updates_inactive_cursor_pos() {
let mut size = TermSize::new(100, 10);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
// Create 10 lines of scrollback.
for _ in 0..19 {
@@ -2646,7 +2685,7 @@ mod tests {
#[test]
fn shrink_lines_updates_active_cursor_pos() {
let mut size = TermSize::new(100, 10);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
// Create 10 lines of scrollback.
for _ in 0..19 {
@@ -2666,7 +2705,7 @@ mod tests {
#[test]
fn shrink_lines_updates_inactive_cursor_pos() {
let mut size = TermSize::new(100, 10);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
// Create 10 lines of scrollback.
for _ in 0..19 {
@@ -2692,7 +2731,7 @@ mod tests {
#[test]
fn damage_public_usage() {
let size = TermSize::new(10, 10);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
// Reset terminal for partial damage tests since it's initialized as fully damaged.
term.reset_damage();
@@ -2785,7 +2824,7 @@ mod tests {
#[test]
fn damage_cursor_movements() {
let size = TermSize::new(10, 10);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
let num_cols = term.columns();
// Reset terminal for partial damage tests since it's initialized as fully damaged.
term.reset_damage();
@@ -2883,7 +2922,7 @@ mod tests {
#[test]
fn full_damage() {
let size = TermSize::new(100, 10);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
assert!(term.damage.is_fully_damaged);
for _ in 0..20 {
@@ -2904,7 +2943,7 @@ mod tests {
assert!(!term.damage.is_fully_damaged);
term.reset_damage();
- term.update_config(&Config::default());
+ term.set_options(Config::default());
assert!(term.damage.is_fully_damaged);
term.reset_damage();
@@ -2930,12 +2969,12 @@ mod tests {
term.reset_damage();
let color_index = 257;
- term.set_color(color_index, VteRgb::default());
+ term.set_color(color_index, Rgb::default());
assert!(term.damage.is_fully_damaged);
term.reset_damage();
// Setting the same color once again shouldn't trigger full damage.
- term.set_color(color_index, VteRgb::default());
+ term.set_color(color_index, Rgb::default());
assert!(!term.damage.is_fully_damaged);
term.reset_color(color_index);
@@ -2943,7 +2982,7 @@ mod tests {
term.reset_damage();
// We shouldn't trigger fully damage when cursor gets update.
- term.set_color(NamedColor::Cursor as usize, VteRgb::default());
+ term.set_color(NamedColor::Cursor as usize, Rgb::default());
assert!(!term.damage.is_fully_damaged);
// However requesting terminal damage should mark terminal as fully damaged in `Insert`
@@ -2969,7 +3008,7 @@ mod tests {
#[test]
fn window_title() {
let size = TermSize::new(7, 17);
- let mut term = Term::new(&Config::default(), &size, VoidListener);
+ let mut term = Term::new(Config::default(), &size, VoidListener);
// Title None by default.
assert_eq!(term.title, None);
diff --git a/alacritty_terminal/src/term/search.rs b/alacritty_terminal/src/term/search.rs
index 8e329255..9e900b8a 100644
--- a/alacritty_terminal/src/term/search.rs
+++ b/alacritty_terminal/src/term/search.rs
@@ -515,7 +515,7 @@ impl<T> Term<T> {
/// Find left end of semantic block.
#[must_use]
pub fn semantic_search_left(&self, point: Point) -> Point {
- match self.inline_search_left(point, &self.semantic_escape_chars) {
+ match self.inline_search_left(point, self.semantic_escape_chars()) {
Ok(point) => self.grid.iter_from(point).next().map_or(point, |cell| cell.point),
Err(point) => point,
}
@@ -524,7 +524,7 @@ impl<T> Term<T> {
/// Find right end of semantic block.
#[must_use]
pub fn semantic_search_right(&self, point: Point) -> Point {
- match self.inline_search_right(point, &self.semantic_escape_chars) {
+ match self.inline_search_right(point, self.semantic_escape_chars()) {
Ok(point) => self.grid.iter_from(point).prev().map_or(point, |cell| cell.point),
Err(point) => point,
}
@@ -676,9 +676,9 @@ impl<'a, T> Iterator for RegexIter<'a, T> {
mod tests {
use super::*;
- use crate::config::Config;
use crate::index::{Column, Line};
use crate::term::test::{mock_term, TermSize};
+ use crate::term::Config;
#[test]
fn regex_right() {
@@ -1052,7 +1052,7 @@ mod tests {
#[test]
fn wide_without_spacer() {
let size = TermSize::new(2, 2);
- let mut term = Term::new(&Config::default(), &size, ());
+ let mut term = Term::new(Config::default(), &size, ());
term.grid[Line(0)][Column(0)].c = 'x';
term.grid[Line(0)][Column(1)].c = '字';
term.grid[Line(0)][Column(1)].flags = Flags::WIDE_CHAR;
diff --git a/alacritty_terminal/src/tty/mod.rs b/alacritty_terminal/src/tty/mod.rs
index 315f008c..d1bb023c 100644
--- a/alacritty_terminal/src/tty/mod.rs
+++ b/alacritty_terminal/src/tty/mod.rs
@@ -4,8 +4,6 @@ use std::path::PathBuf;
use std::sync::Arc;
use std::{env, io};
-use crate::config::Config;
-
use polling::{Event, PollMode, Poller};
#[cfg(not(windows))]
@@ -18,8 +16,38 @@ pub mod windows;
#[cfg(windows)]
pub use self::windows::*;
+/// Configuration for the `Pty` interface.
+#[derive(Clone, Debug, PartialEq, Eq, Default)]
+pub struct Options {
+ /// Shell options.
+ ///
+ /// [`None`] will use the default shell.
+ pub shell: Option<Shell>,
+
+ /// Shell startup directory.
+ pub working_directory: Option<PathBuf>,
+
+ /// Remain open after child process exits.
+ pub hold: bool,
+}
+
+/// Shell options.
+#[derive(Clone, Debug, PartialEq, Eq, Default)]
+pub struct Shell {
+ /// Path to a shell program to run on startup.
+ pub(crate) program: String,
+ /// Arguments passed to shell.
+ pub(crate) args: Vec<String>,
+}
+
+impl Shell {
+ pub fn new(program: String, args: Vec<String>) -> Self {
+ Self { program, args }
+ }
+}
+
/// This trait defines the behaviour needed to read and/or write to a stream.
-/// It defines an abstraction over mio's interface in order to allow either one
+/// It defines an abstraction over polling's interface in order to allow either one
/// read/write object or a separate read and write object.
pub trait EventedReadWrite {
type Reader: io::Read;
@@ -56,7 +84,7 @@ pub trait EventedPty: EventedReadWrite {
}
/// Setup environment variables.
-pub fn setup_env(config: &Config) {
+pub fn setup_env() {
// Default to 'alacritty' terminfo if it is available, otherwise
// default to 'xterm-256color'. May be overridden by user's config
// below.
@@ -69,11 +97,6 @@ pub fn setup_env(config: &Config) {
// Prevent child processes from inheriting startup notification env.
env::remove_var("DESKTOP_STARTUP_ID");
env::remove_var("XDG_ACTIVATION_TOKEN");
-
- // Set env vars from config.
- for (key, value) in config.env.iter() {
- env::set_var(key, value);
- }
}
/// Check if a terminfo entry exists on the system.
diff --git a/alacritty_terminal/src/tty/unix.rs b/alacritty_terminal/src/tty/unix.rs
index 6b543437..2b4f8e54 100644
--- a/alacritty_terminal/src/tty/unix.rs
+++ b/alacritty_terminal/src/tty/unix.rs
@@ -22,9 +22,8 @@ use rustix_openpty::rustix::termios::{self, InputModes, OptionalActions};
use signal_hook::consts as sigconsts;
use signal_hook::low_level::pipe as signal_pipe;
-use crate::config::PtyConfig;
use crate::event::{OnResize, WindowSize};
-use crate::tty::{ChildEvent, EventedPty, EventedReadWrite};
+use crate::tty::{ChildEvent, EventedPty, EventedReadWrite, Options};
// Interest in PTY read/writes.
pub(crate) const PTY_READ_WRITE_TOKEN: usize = 0;
@@ -194,7 +193,7 @@ fn default_shell_command(shell: &str, user: &str) -> Command {
}
/// Create a new TTY and return a handle to interact with it.
-pub fn new(config: &PtyConfig, window_size: WindowSize, window_id: u64) -> Result<Pty> {
+pub fn new(config: &Options, window_size: WindowSize, window_id: u64) -> Result<Pty> {
let (master, slave) = make_pty(window_size.to_winsize())?;
let master_fd = master.as_raw_fd();
let slave_fd = slave.as_raw_fd();
@@ -209,8 +208,8 @@ pub fn new(config: &PtyConfig, window_size: WindowSize, window_id: u64) -> Resul
let user = ShellUser::from_env()?;
let mut builder = if let Some(shell) = config.shell.as_ref() {
- let mut cmd = Command::new(shell.program());
- cmd.args(shell.args());
+ let mut cmd = Command::new(&shell.program);
+ cmd.args(shell.args.as_slice());
cmd
} else {
default_shell_command(&user.shell, &user.user)
diff --git a/alacritty_terminal/src/tty/windows/conpty.rs b/alacritty_terminal/src/tty/windows/conpty.rs
index 12189371..9731b4f0 100644
--- a/alacritty_terminal/src/tty/windows/conpty.rs
+++ b/alacritty_terminal/src/tty/windows/conpty.rs
@@ -17,11 +17,11 @@ use windows_sys::Win32::System::Threading::{
STARTF_USESTDHANDLES, STARTUPINFOEXW, STARTUPINFOW,
};
-use crate::config::PtyConfig;
use crate::event::{OnResize, WindowSize};
use crate::tty::windows::blocking::{UnblockedReader, UnblockedWriter};
use crate::tty::windows::child::ChildExitWatcher;
use crate::tty::windows::{cmdline, win32_string, Pty};
+use crate::tty::Options;
const PIPE_CAPACITY: usize = crate::event_loop::READ_BUFFER_SIZE;
@@ -104,7 +104,7 @@ impl Drop for Conpty {
// The ConPTY handle can be sent between threads.
unsafe impl Send for Conpty {}
-pub fn new(config: &PtyConfig, window_size: WindowSize) -> Option<Pty> {
+pub fn new(config: &Options, window_size: WindowSize) -> Option<Pty> {
let api = ConptyApi::new();
let mut pty_handle: HPCON = 0;
diff --git a/alacritty_terminal/src/tty/windows/mod.rs b/alacritty_terminal/src/tty/windows/mod.rs
index 080f6e83..cbd803f1 100644
--- a/alacritty_terminal/src/tty/windows/mod.rs
+++ b/alacritty_terminal/src/tty/windows/mod.rs
@@ -5,10 +5,9 @@ use std::os::windows::ffi::OsStrExt;
use std::sync::mpsc::TryRecvError;
use std::sync::Arc;
-use crate::config::{Program, PtyConfig};
use crate::event::{OnResize, WindowSize};
use crate::tty::windows::child::ChildExitWatcher;
-use crate::tty::{ChildEvent, EventedPty, EventedReadWrite};
+use crate::tty::{ChildEvent, EventedPty, EventedReadWrite, Options, Shell};
mod blocking;
mod child;
@@ -34,7 +33,7 @@ pub struct Pty {
child_watcher: ChildExitWatcher,
}
-pub fn new(config: &PtyConfig, window_size: WindowSize, _window_id: u64) -> Result<Pty> {
+pub fn new(config: &Options, window_size: WindowSize, _window_id: u64) -> Result<Pty> {
conpty::new(config, window_size)
.ok_or_else(|| Error::new(ErrorKind::Other, "failed to spawn conpty"))
}
@@ -123,12 +122,12 @@ impl OnResize for Pty {
}
}
-fn cmdline(config: &PtyConfig) -> String {
- let default_shell = Program::Just("powershell".to_owned());
+fn cmdline(config: &Options) -> String {
+ let default_shell = Shell::new("powershell".to_owned(), Vec::new());
let shell = config.shell.as_ref().unwrap_or(&default_shell);
- once(shell.program())
- .chain(shell.args().iter().map(|a| a.as_ref()))
+ once(shell.program.as_str())
+ .chain(shell.args.iter().map(|s| s.as_str()))
.collect::<Vec<_>>()
.join(" ")
}
diff --git a/alacritty_terminal/src/vi_mode.rs b/alacritty_terminal/src/vi_mode.rs
index d4f66d9e..7065544e 100644
--- a/alacritty_terminal/src/vi_mode.rs
+++ b/alacritty_terminal/src/vi_mode.rs
@@ -1,6 +1,7 @@
use std::cmp::min;
-use alacritty_config_derive::ConfigDeserialize;
+#[cfg(feature = "serde")]
+use serde::{Deserialize, Serialize};
use crate::event::EventListener;
use crate::grid::{Dimensions, GridCell};
@@ -9,7 +10,8 @@ use crate::term::cell::Flags;
use crate::term::Term;
/// Possible vi mode motion movements.
-#[derive(ConfigDeserialize, Debug, Copy, Clone, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "lowercase"))]
pub enum ViMotion {
/// Move up.
Up,
@@ -379,16 +381,15 @@ fn is_boundary<T>(term: &Term<T>, point: Point, direction: Direction) -> bool {
mod tests {
use super::*;
- use crate::ansi::Handler;
- use crate::config::Config;
use crate::event::VoidListener;
use crate::index::{Column, Line};
use crate::term::test::TermSize;
- use crate::term::Term;
+ use crate::term::{Config, Term};
+ use crate::vte::ansi::Handler;
fn term() -> Term<VoidListener> {
let size = TermSize::new(20, 20);
- Term::new(&Config::default(), &size, VoidListener)
+ Term::new(Config::default(), &size, VoidListener)
}
#[test]
diff --git a/alacritty_terminal/tests/ref.rs b/alacritty_terminal/tests/ref.rs
index 48704fb8..4f8bc74a 100644
--- a/alacritty_terminal/tests/ref.rs
+++ b/alacritty_terminal/tests/ref.rs
@@ -5,14 +5,13 @@ use std::fs::{self, File};
use std::io::Read;
use std::path::Path;
-use alacritty_terminal::ansi;
-use alacritty_terminal::config::Config;
use alacritty_terminal::event::{Event, EventListener};
use alacritty_terminal::grid::{Dimensions, Grid};
use alacritty_terminal::index::{Column, Line};
use alacritty_terminal::term::cell::Cell;
use alacritty_terminal::term::test::TermSize;
-use alacritty_terminal::term::Term;
+use alacritty_terminal::term::{Config, Term};
+use alacritty_terminal::vte::ansi;
macro_rules! ref_tests {
($($name:ident)*) => {
@@ -105,10 +104,10 @@ fn ref_test(dir: &Path) {
let grid: Grid<Cell> = json::from_str(&serialized_grid).unwrap();
let ref_config: RefConfig = json::from_str(&serialized_cfg).unwrap();
- let mut config = Config::default();
- config.scrolling.set_history(ref_config.history_size);
+ let mut options = Config::default();
+ options.scrolling_history = ref_config.history_size as usize;
- let mut terminal = Term::new(&config, &size, Mock);
+ let mut terminal = Term::new(options, &size, Mock);
let mut parser: ansi::Processor = ansi::Processor::new();
for byte in recording {