forked from NotAShelf/beer
config: load beer.toml and apply font, geometry, scrollback, word delimiters
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I5008a74307d856f9df472776cb66c8b06a6a6964
This commit is contained in:
parent
9df4e8fb8a
commit
ccc30d1bbd
7 changed files with 324 additions and 29 deletions
121
Cargo.lock
generated
121
Cargo.lock
generated
|
|
@ -41,8 +41,10 @@ dependencies = [
|
|||
"lru",
|
||||
"pound",
|
||||
"rustix",
|
||||
"serde",
|
||||
"smithay-client-toolkit",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"unicode-width",
|
||||
|
|
@ -83,6 +85,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"nix",
|
||||
"polling",
|
||||
"rustix",
|
||||
"slab",
|
||||
|
|
@ -117,6 +120,12 @@ version = "1.0.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "cfg_aliases"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.5.0"
|
||||
|
|
@ -229,6 +238,16 @@ version = "0.5.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
|
|
@ -308,6 +327,18 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.31.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.50.3"
|
||||
|
|
@ -426,6 +457,45 @@ dependencies = [
|
|||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
|
|
@ -523,6 +593,45 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.9.12+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde_core",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_parser",
|
||||
"toml_writer",
|
||||
"winnow 0.7.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.7.5+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.1.2+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
|
||||
dependencies = [
|
||||
"winnow 1.0.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_writer"
|
||||
version = "1.1.1+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.44"
|
||||
|
|
@ -762,6 +871,18 @@ dependencies = [
|
|||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1"
|
||||
|
||||
[[package]]
|
||||
name = "xcursor"
|
||||
version = "0.3.10"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ readme = true
|
|||
|
||||
[dependencies]
|
||||
anyhow = "1.0.102"
|
||||
calloop = "0.14.4"
|
||||
calloop = { version = "0.14.4", features = ["signals"] }
|
||||
calloop-wayland-source = "0.4.1"
|
||||
fontconfig = "0.11.0"
|
||||
freetype-rs = "0.38.0"
|
||||
|
|
@ -22,8 +22,10 @@ rustix = { version = "1.1.4", features = [
|
|||
"stdio",
|
||||
"fs",
|
||||
] }
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
smithay-client-toolkit = "0.20.0"
|
||||
thiserror = "2.0.18"
|
||||
toml = "0.9"
|
||||
tracing = "0.1.44"
|
||||
tracing-subscriber = { version = "0.3.23", features = ["env-filter"] }
|
||||
unicode-width = "0.2.2"
|
||||
|
|
|
|||
131
src/config.rs
Normal file
131
src/config.rs
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
//! User configuration: a TOML file at `$XDG_CONFIG_HOME/beer/beer.toml`
|
||||
//! deserialized into a typed [`Config`]. A missing file uses defaults; a
|
||||
//! malformed one warns and falls back to defaults rather than failing to start.
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Top-level configuration. Unknown keys are ignored so a config written for a
|
||||
/// newer beer still loads.
|
||||
#[derive(Debug, Clone, Default, Deserialize)]
|
||||
#[serde(default, rename_all = "kebab-case")]
|
||||
pub struct Config {
|
||||
pub main: Main,
|
||||
pub scrollback: Scrollback,
|
||||
}
|
||||
|
||||
/// `[main]`: fonts, window geometry, padding, and the terminal name.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(default, rename_all = "kebab-case")]
|
||||
pub struct Main {
|
||||
/// Primary font family, resolved via fontconfig.
|
||||
pub font: String,
|
||||
/// Font size in pixels.
|
||||
pub font_size: u32,
|
||||
/// `TERM` value exported to the child shell.
|
||||
pub term: String,
|
||||
/// Initial size in character cells.
|
||||
pub initial_cols: u16,
|
||||
pub initial_rows: u16,
|
||||
/// Characters that break a word for double-click selection. Empty/unset
|
||||
/// keeps the built-in default.
|
||||
pub word_delimiters: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for Main {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
font: "monospace".to_string(),
|
||||
font_size: 16,
|
||||
term: "beer".to_string(),
|
||||
initial_cols: 80,
|
||||
initial_rows: 24,
|
||||
word_delimiters: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `[scrollback]`: history retention.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(default, rename_all = "kebab-case")]
|
||||
pub struct Scrollback {
|
||||
/// Lines of history retained for the main screen.
|
||||
pub lines: usize,
|
||||
}
|
||||
|
||||
impl Default for Scrollback {
|
||||
fn default() -> Self {
|
||||
Self { lines: 10_000 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Load configuration from `explicit` if given, else the default path.
|
||||
/// Any read/parse failure logs a warning and returns defaults.
|
||||
pub fn load(explicit: Option<&Path>) -> Self {
|
||||
let Some(path) = explicit.map(Path::to_path_buf).or_else(default_path) else {
|
||||
return Self::default();
|
||||
};
|
||||
if !path.exists() {
|
||||
return Self::default();
|
||||
}
|
||||
match std::fs::read_to_string(&path) {
|
||||
Ok(text) => match toml::from_str(&text) {
|
||||
Ok(config) => {
|
||||
tracing::info!("loaded config from {}", path.display());
|
||||
config
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::warn!("config {}: {err}; using defaults", path.display());
|
||||
Self::default()
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
tracing::warn!("read config {}: {err}; using defaults", path.display());
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `$XDG_CONFIG_HOME/beer/beer.toml`, or `~/.config/beer/beer.toml`.
|
||||
fn default_path() -> Option<PathBuf> {
|
||||
if let Some(dir) = std::env::var_os("XDG_CONFIG_HOME").filter(|s| !s.is_empty()) {
|
||||
return Some(PathBuf::from(dir).join("beer/beer.toml"));
|
||||
}
|
||||
let home = std::env::var_os("HOME")?;
|
||||
Some(PathBuf::from(home).join(".config/beer/beer.toml"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn defaults_are_sane() {
|
||||
let c = Config::default();
|
||||
assert_eq!(c.main.font, "monospace");
|
||||
assert_eq!(c.main.font_size, 16);
|
||||
assert_eq!(c.scrollback.lines, 10_000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_partial_config_and_ignores_unknown() {
|
||||
let toml = r##"
|
||||
[main]
|
||||
font = "JetBrains Mono"
|
||||
font-size = 14
|
||||
unknown-key = "tolerated"
|
||||
|
||||
[colors]
|
||||
background = "#000000"
|
||||
"##;
|
||||
let c: Config = toml::from_str(toml).unwrap();
|
||||
assert_eq!(c.main.font, "JetBrains Mono");
|
||||
assert_eq!(c.main.font_size, 14);
|
||||
// Unset keys keep defaults; unknown tables/keys are ignored.
|
||||
assert_eq!(c.main.term, "beer");
|
||||
assert_eq!(c.scrollback.lines, 10_000);
|
||||
}
|
||||
}
|
||||
39
src/grid.rs
39
src/grid.rs
|
|
@ -226,6 +226,10 @@ pub struct Grid {
|
|||
focus_events: bool,
|
||||
/// Active incremental scrollback search, if any.
|
||||
search: Option<SearchState>,
|
||||
/// Characters that break a word for double-click selection.
|
||||
word_delimiters: String,
|
||||
/// History retention cap for the main screen.
|
||||
scrollback_cap: usize,
|
||||
}
|
||||
|
||||
fn default_tabs(cols: usize) -> Vec<bool> {
|
||||
|
|
@ -237,9 +241,9 @@ fn default_tabs(cols: usize) -> Vec<bool> {
|
|||
/// flags select as one unit.
|
||||
const WORD_DELIMITERS: &str = " \t`!@#$%^&*()+=[]{}\\|;'\",<>?";
|
||||
|
||||
/// Whether `c` is part of a word (not whitespace, not a delimiter).
|
||||
fn is_word(c: char) -> bool {
|
||||
!c.is_whitespace() && !WORD_DELIMITERS.contains(c)
|
||||
/// Whether `c` is part of a word (not whitespace, not in `delims`).
|
||||
fn is_word(c: char, delims: &str) -> bool {
|
||||
!c.is_whitespace() && !delims.contains(c)
|
||||
}
|
||||
|
||||
impl Grid {
|
||||
|
|
@ -276,9 +280,27 @@ impl Grid {
|
|||
mouse_encoding: MouseEncoding::X10,
|
||||
focus_events: false,
|
||||
search: None,
|
||||
word_delimiters: WORD_DELIMITERS.to_string(),
|
||||
scrollback_cap: SCROLLBACK_CAP,
|
||||
}
|
||||
}
|
||||
|
||||
/// Override the word-delimiter set; `None` keeps the built-in default.
|
||||
pub fn set_word_delimiters(&mut self, delims: Option<String>) {
|
||||
if let Some(d) = delims {
|
||||
self.word_delimiters = d;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the scrollback retention cap, trimming history if it shrank.
|
||||
pub fn set_scrollback_cap(&mut self, cap: usize) {
|
||||
self.scrollback_cap = cap;
|
||||
while self.scrollback.len() > cap {
|
||||
self.scrollback.pop_front();
|
||||
}
|
||||
self.view_offset = self.view_offset.min(self.scrollback.len());
|
||||
}
|
||||
|
||||
pub fn cols(&self) -> usize {
|
||||
self.cols
|
||||
}
|
||||
|
|
@ -403,7 +425,7 @@ impl Grid {
|
|||
while live.len() < rows {
|
||||
live.push(Line::blank(cols));
|
||||
}
|
||||
while scrollback.len() > SCROLLBACK_CAP {
|
||||
while scrollback.len() > self.scrollback_cap {
|
||||
scrollback.pop_front();
|
||||
}
|
||||
|
||||
|
|
@ -722,7 +744,7 @@ impl Grid {
|
|||
self.scrollback.push_back(line);
|
||||
}
|
||||
let mut evicted = 0;
|
||||
while self.scrollback.len() > SCROLLBACK_CAP {
|
||||
while self.scrollback.len() > self.scrollback_cap {
|
||||
self.scrollback.pop_front();
|
||||
evicted += 1;
|
||||
}
|
||||
|
|
@ -995,17 +1017,18 @@ impl Grid {
|
|||
/// Select the word at an absolute point, breaking on whitespace and the
|
||||
/// default delimiter set.
|
||||
pub fn select_word(&mut self, row: usize, col: usize) {
|
||||
let delims = &self.word_delimiters;
|
||||
let line = self.abs_row(row);
|
||||
if col >= line.len() || !is_word(line[col].c) {
|
||||
if col >= line.len() || !is_word(line[col].c, delims) {
|
||||
self.start_selection(row, col);
|
||||
return;
|
||||
}
|
||||
let mut lo = col;
|
||||
while lo > 0 && is_word(line[lo - 1].c) {
|
||||
while lo > 0 && is_word(line[lo - 1].c, delims) {
|
||||
lo -= 1;
|
||||
}
|
||||
let mut hi = col;
|
||||
while hi + 1 < line.len() && is_word(line[hi + 1].c) {
|
||||
while hi + 1 < line.len() && is_word(line[hi + 1].c, delims) {
|
||||
hi += 1;
|
||||
}
|
||||
self.selection = Some((Point { row, col: lo }, Point { row, col: hi }));
|
||||
|
|
|
|||
10
src/main.rs
10
src/main.rs
|
|
@ -1,5 +1,6 @@
|
|||
//! beer, a fast, software-rendered, Wayland-native terminal emulator.
|
||||
|
||||
mod config;
|
||||
mod font;
|
||||
mod grid;
|
||||
mod input;
|
||||
|
|
@ -8,10 +9,13 @@ mod render;
|
|||
mod vt;
|
||||
mod wayland;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::process::ExitCode;
|
||||
|
||||
use pound::Parse;
|
||||
|
||||
use crate::config::Config;
|
||||
|
||||
/// A fast, software-rendered, Wayland-native terminal emulator.
|
||||
#[derive(Parse)]
|
||||
#[pound(name = "beer", version = "0.0.0")]
|
||||
|
|
@ -19,6 +23,9 @@ struct Cli {
|
|||
/// Run as a daemon hosting multiple windows.
|
||||
#[pound(long)]
|
||||
server: bool,
|
||||
/// Path to a config file (default: $XDG_CONFIG_HOME/beer/beer.toml).
|
||||
#[pound(long)]
|
||||
config: Option<PathBuf>,
|
||||
}
|
||||
|
||||
fn main() -> ExitCode {
|
||||
|
|
@ -51,6 +58,7 @@ fn run(cli: Cli) -> anyhow::Result<ExitCode> {
|
|||
anyhow::bail!("server mode is not implemented yet");
|
||||
}
|
||||
|
||||
let config = Config::load(cli.config.as_deref());
|
||||
tracing::info!("starting beer");
|
||||
wayland::run()
|
||||
wayland::run(config)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ pub struct Pty {
|
|||
|
||||
impl Pty {
|
||||
/// Open a PTY, size it to `cols`x`rows`, and exec the user's login shell on
|
||||
/// the slave end with `TERM=beer`.
|
||||
pub fn spawn(cols: u16, rows: u16) -> anyhow::Result<Self> {
|
||||
/// the slave end with `TERM=term`.
|
||||
pub fn spawn(cols: u16, rows: u16, term: &str) -> anyhow::Result<Self> {
|
||||
let master = openpt(OpenptFlags::RDWR | OpenptFlags::NOCTTY | OpenptFlags::CLOEXEC)
|
||||
.context("open pty master")?;
|
||||
grantpt(&master).context("grantpt")?;
|
||||
|
|
@ -45,7 +45,7 @@ impl Pty {
|
|||
|
||||
let mut cmd = Command::new(&shell);
|
||||
cmd.arg0(&argv0)
|
||||
.env("TERM", "beer")
|
||||
.env("TERM", term)
|
||||
.env_remove("COLUMNS")
|
||||
.env_remove("LINES")
|
||||
.env_remove("TERMCAP")
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ use calloop::timer::{TimeoutAction, Timer};
|
|||
use calloop::{EventLoop, Interest, LoopHandle, Mode, PostAction, RegistrationToken};
|
||||
use calloop_wayland_source::WaylandSource;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::font::Fonts;
|
||||
use crate::grid::{Cell, CursorShape, Grid, MouseProtocol};
|
||||
use crate::pty::Pty;
|
||||
|
|
@ -161,15 +162,12 @@ fn row_snap(grid: &Grid, y: usize, focused: bool, blink_on: bool) -> RowSnap {
|
|||
}
|
||||
}
|
||||
|
||||
/// Default window size in pixels before the compositor suggests one.
|
||||
/// Fallback window size in pixels if the configured geometry yields nothing.
|
||||
const DEFAULT_W: u32 = 800;
|
||||
const DEFAULT_H: u32 = 600;
|
||||
/// Primary font family and pixel size, resolved via fontconfig.
|
||||
const FONT_FAMILY: &str = "monospace";
|
||||
const FONT_SIZE_PX: u32 = 16;
|
||||
|
||||
/// Run a single window until it is closed, returning the shell's exit code.
|
||||
pub fn run() -> anyhow::Result<ExitCode> {
|
||||
pub fn run(config: Config) -> anyhow::Result<ExitCode> {
|
||||
let conn = Connection::connect_to_env().context("connect to Wayland compositor")?;
|
||||
let (globals, event_queue) =
|
||||
registry_queue_init(&conn).context("initialize Wayland registry")?;
|
||||
|
|
@ -197,12 +195,20 @@ pub fn run() -> anyhow::Result<ExitCode> {
|
|||
// First commit with no buffer kicks off the initial configure.
|
||||
window.commit();
|
||||
|
||||
let pool = SlotPool::new(DEFAULT_W as usize * DEFAULT_H as usize * 4, &shm)
|
||||
.context("create shm slot pool")?;
|
||||
|
||||
let fonts = Fonts::new(FONT_FAMILY, FONT_SIZE_PX).context("load font")?;
|
||||
let fonts = Fonts::new(&config.main.font, config.main.font_size).context("load font")?;
|
||||
let renderer = Renderer::new(fonts);
|
||||
|
||||
// Start at the configured cell geometry; the compositor may override it on
|
||||
// the first configure.
|
||||
let m = renderer.metrics();
|
||||
let width = (u32::from(config.main.initial_cols) * m.width).max(1);
|
||||
let height = (u32::from(config.main.initial_rows) * m.height).max(1);
|
||||
let pool = SlotPool::new(
|
||||
(width * height * 4).max(DEFAULT_W * DEFAULT_H) as usize,
|
||||
&shm,
|
||||
)
|
||||
.context("create shm slot pool")?;
|
||||
|
||||
let mut app = App {
|
||||
registry_state: RegistryState::new(&globals),
|
||||
output_state: OutputState::new(&globals, &qh),
|
||||
|
|
@ -239,8 +245,9 @@ pub fn run() -> anyhow::Result<ExitCode> {
|
|||
// startup SIGWINCH storm that makes it reprint its prompt.
|
||||
session: None,
|
||||
title: None,
|
||||
width: DEFAULT_W,
|
||||
height: DEFAULT_H,
|
||||
config,
|
||||
width,
|
||||
height,
|
||||
needs_draw: false,
|
||||
frame_pending: false,
|
||||
frames: Vec::new(),
|
||||
|
|
@ -352,6 +359,8 @@ struct App {
|
|||
session: Option<Session>,
|
||||
/// Last title applied to the toplevel, to avoid redundant requests.
|
||||
title: Option<String>,
|
||||
/// The active user configuration.
|
||||
config: Config,
|
||||
width: u32,
|
||||
height: u32,
|
||||
/// The grid changed and the window wants repainting on the next frame.
|
||||
|
|
@ -379,7 +388,7 @@ impl App {
|
|||
/// Spawn the shell at the current window size and start reading its output.
|
||||
fn spawn_session(&mut self) {
|
||||
let (cols, rows) = grid_size(self.renderer.metrics(), self.width, self.height);
|
||||
let pty = match Pty::spawn(cols, rows) {
|
||||
let pty = match Pty::spawn(cols, rows, &self.config.main.term) {
|
||||
Ok(pty) => pty,
|
||||
Err(err) => {
|
||||
tracing::error!("spawn shell: {err:#}");
|
||||
|
|
@ -428,10 +437,11 @@ impl App {
|
|||
return;
|
||||
}
|
||||
|
||||
self.session = Some(Session {
|
||||
pty,
|
||||
term: Term::new(cols as usize, rows as usize),
|
||||
});
|
||||
let mut term = Term::new(cols as usize, rows as usize);
|
||||
let grid = term.grid_mut();
|
||||
grid.set_word_delimiters(self.config.main.word_delimiters.clone());
|
||||
grid.set_scrollback_cap(self.config.scrollback.lines);
|
||||
self.session = Some(Session { pty, term });
|
||||
}
|
||||
|
||||
/// Handle a key (initial press or repeat): Shift+PageUp/PageDown scroll the
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue