Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add cellwidths option #6289 #6290

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use std::path::{Path, PathBuf};
use std::sync::atomic::Ordering;
use std::time::Duration;
use termwiz::hyperlink;
use termwiz::cell::CellWidth;
use termwiz::surface::CursorShape;
use wezterm_bidi::ParagraphDirectionHint;
use wezterm_config_derive::ConfigMeta;
Expand Down Expand Up @@ -813,6 +814,9 @@ pub struct Config {
#[dynamic(default)]
pub treat_east_asian_ambiguous_width_as_wide: bool,

#[dynamic(default)]
pub cellwidths: Option<Vec<CellWidth>>,

#[dynamic(default = "default_true")]
pub allow_download_protocols: bool,

Expand Down
2 changes: 2 additions & 0 deletions config/src/terminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use crate::{configuration, ConfigHandle, NewlineCanon};
use std::sync::Mutex;
use termwiz::cell::UnicodeVersion;
use termwiz::cell::setcellwidths;
use wezterm_term::color::ColorPalette;
use wezterm_term::config::BidiMode;

Expand Down Expand Up @@ -105,6 +106,7 @@ impl wezterm_term::TerminalConfiguration for TermConfig {
UnicodeVersion {
version: config.unicode_version,
ambiguous_are_wide: config.treat_east_asian_ambiguous_width_as_wide,
cellwidths: setcellwidths(config.cellwidths.clone()),
}
}

Expand Down
1 change: 1 addition & 0 deletions term/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ pub trait TerminalConfiguration: Downcast + std::fmt::Debug + Send + Sync {
UnicodeVersion {
version: 9,
ambiguous_are_wide: false,
cellwidths: None,
}
}

Expand Down
4 changes: 2 additions & 2 deletions term/src/terminalstate/performer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ impl<'a> Performer<'a> {
for g in Graphemes::new(text) {
let g = self.remap_grapheme(g);

let print_width = grapheme_column_width(g, Some(self.unicode_version));
let print_width = grapheme_column_width(g, Some(self.unicode_version.clone()));
if print_width == 0 {
// We got a zero-width grapheme.
// We used to force them into a cell to guarantee that we
Expand Down Expand Up @@ -816,7 +816,7 @@ impl<'a> Performer<'a> {
self.unicode_version.version = n;
}
ITermProprietary::UnicodeVersion(ITermUnicodeVersionOp::Push(label)) => {
let vers = self.unicode_version;
let vers = self.unicode_version.clone();
self.unicode_version_stack
.push(UnicodeVersionStackEntry { vers, label });
}
Expand Down
46 changes: 39 additions & 7 deletions termwiz/src/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use std::hash::{Hash, Hasher};
use std::mem;
use std::sync::Arc;
use wezterm_dynamic::{FromDynamic, ToDynamic};
use std::collections::HashMap;

#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
Expand Down Expand Up @@ -881,17 +882,40 @@ impl Cell {
}
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, FromDynamic, ToDynamic)]
pub struct CellWidth {
pub first: u32,
pub last: u32,
pub width: u8,
}

pub fn setcellwidths(cellwidths: Option<Vec<CellWidth>>) -> Option<HashMap<u32, u8>> {
if let Some(ref cellwidths) = cellwidths {
let mut map: HashMap<u32, u8> = HashMap::new();
for cellwidth in cellwidths {
for i in cellwidth.first..cellwidth.last+1 {
map.insert(i, cellwidth.width);
}
}
return Some(map);
} else {
return None;
}
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct UnicodeVersion {
pub version: u8,
pub ambiguous_are_wide: bool,
pub cellwidths: Option<HashMap<u32, u8>>,
}

impl UnicodeVersion {
pub const fn new(version: u8) -> Self {
Self {
version,
ambiguous_are_wide: false,
cellwidths: None,
}
}

Expand All @@ -911,6 +935,16 @@ impl UnicodeVersion {
}
}

#[inline]
fn wcwidth(&self, c: char) -> usize {
if let Some(ref cellwidths) = self.cellwidths {
if let Some(width) = cellwidths.get(&(c as u32)) {
return (*width).into()
}
}
self.width(WCWIDTH_TABLE.classify(c))
}

#[inline]
pub fn idx(&self) -> usize {
(if self.version > 9 { 2 } else { 0 }) | (if self.ambiguous_are_wide { 1 } else { 0 })
Expand All @@ -920,6 +954,7 @@ impl UnicodeVersion {
pub const LATEST_UNICODE_VERSION: UnicodeVersion = UnicodeVersion {
version: 14,
ambiguous_are_wide: false,
cellwidths: None,
};

/// Returns the number of cells visually occupied by a sequence
Expand All @@ -928,7 +963,7 @@ pub const LATEST_UNICODE_VERSION: UnicodeVersion = UnicodeVersion {
/// and sums up the length.
pub fn unicode_column_width(s: &str, version: Option<UnicodeVersion>) -> usize {
Graphemes::new(s)
.map(|g| grapheme_column_width(g, version))
.map(|g| grapheme_column_width(g, version.clone()))
.sum()
}

Expand Down Expand Up @@ -977,13 +1012,11 @@ pub fn grapheme_column_width(s: &str, version: Option<UnicodeVersion>) -> usize
// cannot be a sequence with a variation selector, so we don't
// need to requested `Presentation` for it.
if s.len() == 1 {
let c = WCWIDTH_TABLE.classify(s.as_bytes()[0] as char);
return version.width(c);
return version.wcwidth(s.as_bytes()[0] as char);
}

// Slow path: `s.chars()` will dominate and pull up the minimum
// runtime to ~20ns

if version.version >= 14 {
// Lookup the grapheme to see if the presentation of
// the grapheme forces the width. We can bypass
Expand All @@ -999,8 +1032,7 @@ pub fn grapheme_column_width(s: &str, version: Option<UnicodeVersion>) -> usize
// Otherwise, classify and sum up
let mut width = 0;
for c in s.chars() {
let c = WCWIDTH_TABLE.classify(c);
width += version.width(c);
width += version.wcwidth(c);
}

width.min(2)
Expand Down
2 changes: 1 addition & 1 deletion termwiz/src/surface/line/line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ impl Line {
let mut cells = Vec::new();

for sub in Graphemes::new(s) {
let cell = Cell::new_grapheme(sub, attrs.clone(), unicode_version);
let cell = Cell::new_grapheme(sub, attrs.clone(), unicode_version.clone());
let width = cell.width();
cells.push(cell);
for _ in 1..width {
Expand Down
2 changes: 2 additions & 0 deletions wezterm-gui/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use wezterm_font::FontConfiguration;
use wezterm_gui_subcommands::*;
use wezterm_mux_server_impl::update_mux_domains;
use wezterm_toast_notification::*;
use termwiz::cell::setcellwidths;

mod colorease;
mod commands;
Expand Down Expand Up @@ -886,6 +887,7 @@ pub fn run_ls_fonts(config: config::ConfigHandle, cmd: &LsFontsCommand) -> anyho
let unicode_version = UnicodeVersion {
version: config.unicode_version,
ambiguous_are_wide: config.treat_east_asian_ambiguous_width_as_wide,
cellwidths: setcellwidths(config.cellwidths.clone()),
};

let text = match (&cmd.text, &cmd.codepoints) {
Expand Down