feat: port GTK version fallbacks, helpgen, bench modes, CLI leftovers
- apprt-gtk: Ghostty's runtime+build-time version gating (at_least) with cargo features adw_1_3/adw_1_4/adw_1_5/gtk_4_16 (default on) and the fallbacks for older libraries: MessageDialog (adw < 1.5), clipboard dialog without SwitchRow, pre-Banner debug warning and child-exited widgets, the old about dialog, GTK 4.16 CSS error source bytes. The minimum stays GTK 4.14 / libadwaita 1.5 (Ghostty's floor). The root build links with -z lazy so version-gated symbols don't keep older libraries from loading. - ghostty-helpgen (port of helpgen.zig) generates CLI action help and keybinding action docs from doc comments at build time, replacing the checked-in help/*.txt; +help and +list-actions --docs stay byte-identical to Ghostty 1.3.1. - ghostty-bench: libc wcwidth mode and separate simd/table and uucode/table code paths like Zig. - ghostty-cli: Windows branches of edit-config, list-colors, list-keybinds and boo; ssh-cache DiskCache flock locking (no-op on Windows, as in Zig) with an exclusivity test. Test Plan: - cargo test --workspace - diff <(cargo run -q -- +list-actions --docs) \ <(ghostty +list-actions --docs)
This commit is contained in:
1 parent
020beb2d75
commit
4787565397
51 files changed
+2426
-1621
No files matched your search
@@ -19,5 +19,36 @@ ghostty-unicode.workspace = true
|
||||
ghostty-vt.workspace = true
|
||||
log = "0.4.34"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
# Not `workspace = true`: this crate needs a single audited FFI call (libc
|
||||
# `wcwidth`) so `unsafe_code` is `deny` (locally allowed) instead of `forbid`.
|
||||
[lints.rust]
|
||||
unsafe_code = "deny"
|
||||
|
||||
[lints.clippy]
|
||||
pedantic = { level = "warn", priority = -1 }
|
||||
todo = "warn"
|
||||
unwrap_used = "warn"
|
||||
# Porting a low-level terminal emulator involves a lot of intentional
|
||||
# numeric casts and long state-machine functions; these pedantic lints are
|
||||
# noise for this codebase.
|
||||
cast_possible_truncation = "allow"
|
||||
cast_possible_wrap = "allow"
|
||||
cast_sign_loss = "allow"
|
||||
cast_precision_loss = "allow"
|
||||
cast_lossless = "allow"
|
||||
module_name_repetitions = "allow"
|
||||
too_many_lines = "allow"
|
||||
missing_errors_doc = "allow"
|
||||
missing_panics_doc = "allow"
|
||||
similar_names = "allow"
|
||||
struct_excessive_bools = "allow"
|
||||
fn_params_excessive_bools = "allow"
|
||||
match_same_arms = "allow"
|
||||
unreadable_literal = "allow"
|
||||
many_single_char_names = "allow"
|
||||
doc_markdown = "allow"
|
||||
must_use_candidate = "allow"
|
||||
return_self_not_must_use = "allow"
|
||||
used_underscore_binding = "allow"
|
||||
large_stack_arrays = "allow"
|
||||
inline_always = "allow"
|
||||
@@ -285,6 +285,43 @@ fn decode_each(d: &mut Utf8Decoder, chunk: &[u8], mut func: impl FnMut(u32)) {
|
||||
}
|
||||
}
|
||||
|
||||
/// libc `wcwidth` (`extern "c" fn wcwidth(c: u32) c_int`).
|
||||
#[cfg(unix)]
|
||||
#[allow(unsafe_code)]
|
||||
mod libc_wcwidth {
|
||||
unsafe extern "C" {
|
||||
fn wcwidth(c: u32) -> i32;
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
#[inline]
|
||||
pub fn call(cp: u32) -> i32 {
|
||||
// SAFETY: `wcwidth` is a pure libc function taking a plain integer
|
||||
// (wchar_t) and returning an int; no pointers or preconditions.
|
||||
unsafe { wcwidth(cp) }
|
||||
}
|
||||
}
|
||||
|
||||
/// The `table` mode: generated two-stage lookup (`unicode.table.get(cp).width`),
|
||||
/// with the same `<= 0xFF` shortcut as terminal.zig.
|
||||
#[inline]
|
||||
fn width_table(
|
||||
table: &ghostty_unicode::lut::Tables<'_, ghostty_unicode::Properties>,
|
||||
cp: u32,
|
||||
) -> i32 {
|
||||
if cp <= 0xFF {
|
||||
1
|
||||
} else {
|
||||
i32::from(table.get(cp).width)
|
||||
}
|
||||
}
|
||||
|
||||
/// `simd.codepointWidth` (scalar port of the highway implementation).
|
||||
#[must_use]
|
||||
pub fn simd_width(cp: u32) -> i32 {
|
||||
i32::from(crate::simd_width::codepoint_width(cp))
|
||||
}
|
||||
|
||||
impl Benchmark for CodepointWidth {
|
||||
fn setup(&mut self) -> Result {
|
||||
self.data.open()
|
||||
@@ -298,19 +335,37 @@ impl Benchmark for CodepointWidth {
|
||||
match self.mode {
|
||||
WidthMode::Noop => Ok(()),
|
||||
WidthMode::Wcwidth => {
|
||||
// libc wcwidth needs FFI, which this workspace forbids.
|
||||
log::warn!("wcwidth mode is not available in the Rust port");
|
||||
Ok(())
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let mut d = Utf8Decoder::new();
|
||||
self.data.for_each_chunk(|chunk| {
|
||||
decode_each(&mut d, chunk, |cp| {
|
||||
black_box(libc_wcwidth::call(cp));
|
||||
});
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
#[cfg(not(unix))]
|
||||
{
|
||||
log::warn!("wcwidth is not available on this platform");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
// The Rust port has no separate SIMD width function: both use
|
||||
// the lookup table.
|
||||
WidthMode::Simd | WidthMode::Table => {
|
||||
WidthMode::Simd => {
|
||||
let mut d = Utf8Decoder::new();
|
||||
self.data.for_each_chunk(|chunk| {
|
||||
decode_each(&mut d, chunk, |cp| {
|
||||
black_box(simd_width(cp));
|
||||
});
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
WidthMode::Table => {
|
||||
let mut d = Utf8Decoder::new();
|
||||
let table = ghostty_unicode::table();
|
||||
self.data.for_each_chunk(|chunk| {
|
||||
decode_each(&mut d, chunk, |cp| {
|
||||
// Same trick as terminal.rs.
|
||||
black_box(if cp <= 0xFF { 1 } else { table.get(cp).width });
|
||||
black_box(width_table(&table, cp));
|
||||
});
|
||||
Ok(())
|
||||
})
|
||||
@@ -375,19 +430,57 @@ impl Benchmark for GraphemeBreak {
|
||||
// ---------------------------------------------------------------------------
|
||||
// is-symbol
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SymbolMode {
|
||||
/// uucode implementation (computed from general category + block).
|
||||
Uucode,
|
||||
/// Ghostty's table-based approach.
|
||||
Table,
|
||||
}
|
||||
|
||||
pub struct IsSymbol {
|
||||
data: Data,
|
||||
mode: SymbolMode,
|
||||
}
|
||||
|
||||
/// Computed `is_symbol` (`computeIsSymbol` in uucode_config.zig): private
|
||||
/// use (general category Co) or one of the symbol blocks, evaluated directly
|
||||
/// from the ranges rather than via the generated table.
|
||||
#[must_use]
|
||||
pub fn is_symbol_computed(cp: u32) -> bool {
|
||||
matches!(
|
||||
cp,
|
||||
// general_category == other_private_use
|
||||
0xE000..=0xF8FF | 0xF_0000..=0xF_FFFD | 0x10_0000..=0x10_FFFD
|
||||
// arrows
|
||||
| 0x2190..=0x21FF
|
||||
// dingbats
|
||||
| 0x2700..=0x27BF
|
||||
// emoticons
|
||||
| 0x1F600..=0x1F64F
|
||||
// miscellaneous_symbols
|
||||
| 0x2600..=0x26FF
|
||||
// enclosed_alphanumerics
|
||||
| 0x2460..=0x24FF
|
||||
// enclosed_alphanumeric_supplement
|
||||
| 0x1F100..=0x1F1FF
|
||||
// miscellaneous_symbols_and_pictographs
|
||||
| 0x1F300..=0x1F5FF
|
||||
// transport_and_map_symbols
|
||||
| 0x1F680..=0x1F6FF
|
||||
)
|
||||
}
|
||||
|
||||
impl IsSymbol {
|
||||
pub fn create(args: &mut Args) -> std::result::Result<Self, String> {
|
||||
// Modes `uucode` and `table` both use the generated table here.
|
||||
match args.take_opt_string("mode")?.as_deref() {
|
||||
None | Some("uucode" | "table") => {}
|
||||
let mode = match args.take_opt_string("mode")?.as_deref() {
|
||||
None | Some("uucode") => SymbolMode::Uucode,
|
||||
Some("table") => SymbolMode::Table,
|
||||
Some(m) => return Err(format!("invalid value for --mode: {m}")),
|
||||
}
|
||||
};
|
||||
Ok(IsSymbol {
|
||||
data: Data::new(args.take_opt_string("data")?),
|
||||
mode,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -403,13 +496,23 @@ impl Benchmark for IsSymbol {
|
||||
|
||||
fn step(&mut self) -> Result {
|
||||
let mut d = Utf8Decoder::new();
|
||||
let table = ghostty_unicode::symbols_table::table();
|
||||
self.data.for_each_chunk(|chunk| {
|
||||
decode_each(&mut d, chunk, |cp| {
|
||||
black_box(table.get(cp));
|
||||
});
|
||||
Ok(())
|
||||
})
|
||||
match self.mode {
|
||||
SymbolMode::Uucode => self.data.for_each_chunk(|chunk| {
|
||||
decode_each(&mut d, chunk, |cp| {
|
||||
black_box(is_symbol_computed(cp));
|
||||
});
|
||||
Ok(())
|
||||
}),
|
||||
SymbolMode::Table => {
|
||||
let table = ghostty_unicode::symbols_table::table();
|
||||
self.data.for_each_chunk(|chunk| {
|
||||
decode_each(&mut d, chunk, |cp| {
|
||||
black_box(table.get(cp));
|
||||
});
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -564,3 +667,86 @@ pub fn main_action(action: &str, mut args: Args) -> std::result::Result<RunResul
|
||||
_ => Err(format!("invalid action: +{action}")),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn run(action: &str, mode: &str, data: &std::path::Path) -> Result {
|
||||
let mut args = Args::parse([
|
||||
format!("+{action}"),
|
||||
format!("--mode={mode}"),
|
||||
format!("--data={}", data.display()),
|
||||
])
|
||||
.unwrap();
|
||||
match action {
|
||||
"codepoint-width" => crate::benchmark::run(
|
||||
&mut CodepointWidth::create(&mut args).unwrap(),
|
||||
crate::benchmark::RunMode::Once,
|
||||
),
|
||||
_ => crate::benchmark::run(
|
||||
&mut IsSymbol::create(&mut args).unwrap(),
|
||||
crate::benchmark::RunMode::Once,
|
||||
),
|
||||
}
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
fn sample_file(tag: &str) -> std::path::PathBuf {
|
||||
let p =
|
||||
std::env::temp_dir().join(format!("ghostty-bench-{tag}-{}.txt", std::process::id()));
|
||||
std::fs::write(
|
||||
&p,
|
||||
"hello \u{4e00}\u{1f600}\u{301}\u{e000} world \u{2190}\n",
|
||||
)
|
||||
.unwrap();
|
||||
p
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn codepoint_width_all_modes_run() {
|
||||
let p = sample_file("cw");
|
||||
for m in ["noop", "wcwidth", "simd", "table"] {
|
||||
run("codepoint-width", m, &p).unwrap();
|
||||
}
|
||||
let mut args = Args::parse(["--mode=bogus".to_owned()]).unwrap();
|
||||
assert!(CodepointWidth::create(&mut args).is_err());
|
||||
let _ = std::fs::remove_file(p);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_symbol_modes_run() {
|
||||
let p = sample_file("sym");
|
||||
for m in ["uucode", "table"] {
|
||||
run("is-symbol", m, &p).unwrap();
|
||||
}
|
||||
let _ = std::fs::remove_file(p);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_symbol_computed_matches_table() {
|
||||
let t = ghostty_unicode::symbols_table::table();
|
||||
for cp in 0..=0x11_0000u32 {
|
||||
assert_eq!(is_symbol_computed(cp), t.get(cp), "cp={cp:x}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simd_matches_table_on_samples() {
|
||||
let t = ghostty_unicode::table();
|
||||
for cp in [
|
||||
0x61, 0x100, 0x3400, 0x2E3A, 0x1F1E6, 0x4E00, 0xF900, 0x1F600, 0x20000, 0x30000, 0x301,
|
||||
0x200B, 0x200D, 0xFE0F, 0x20DD, 0xE0100, 0xE0001, 0x1160, 0xAC00,
|
||||
] {
|
||||
assert_eq!(simd_width(cp), width_table(&t, cp), "cp={cp:x}");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn wcwidth_ascii() {
|
||||
// The C locale is in effect (no setlocale, like Zig): ASCII only.
|
||||
assert_eq!(libc_wcwidth::call(u32::from(b'a')), 1);
|
||||
assert_eq!(libc_wcwidth::call(0), 0);
|
||||
}
|
||||
}
|
||||
@@ -10,4 +10,5 @@
|
||||
pub mod args;
|
||||
pub mod benches;
|
||||
pub mod benchmark;
|
||||
mod simd_width;
|
||||
pub mod synthetic;
|
||||
@@ -0,0 +1,616 @@
|
||||
//! Scalar port of `src/simd/codepoint_width.cpp` (the highway SIMD
|
||||
//! implementation behind `simd.codepointWidth`). The C++ tests N inclusive
|
||||
//! `[gte, lte]` ranges per vector op; here each range table is scanned
|
||||
//! sequentially, with identical tables and precedence order.
|
||||
//!
|
||||
//! The range tables are copied verbatim from the C++ source (the trailing
|
||||
//! zero padding used for vector alignment is dropped).
|
||||
|
||||
const EAW_16: &[(u32, u32)] = &[
|
||||
(0x3000, 0x3000),
|
||||
(0xff01, 0xff60),
|
||||
(0xffe0, 0xffe6),
|
||||
(0x1100, 0x115f),
|
||||
(0x231a, 0x231b),
|
||||
(0x2329, 0x2329),
|
||||
(0x232a, 0x232a),
|
||||
(0x23e9, 0x23ec),
|
||||
(0x23f0, 0x23f0),
|
||||
(0x23f3, 0x23f3),
|
||||
(0x25fd, 0x25fe),
|
||||
(0x2614, 0x2615),
|
||||
(0x2648, 0x2653),
|
||||
(0x267f, 0x267f),
|
||||
(0x2693, 0x2693),
|
||||
(0x26a1, 0x26a1),
|
||||
(0x26aa, 0x26ab),
|
||||
(0x26bd, 0x26be),
|
||||
(0x26c4, 0x26c5),
|
||||
(0x26ce, 0x26ce),
|
||||
(0x26d4, 0x26d4),
|
||||
(0x26ea, 0x26ea),
|
||||
(0x26f2, 0x26f3),
|
||||
(0x26f5, 0x26f5),
|
||||
(0x26fa, 0x26fa),
|
||||
(0x26fd, 0x26fd),
|
||||
(0x2705, 0x2705),
|
||||
(0x270a, 0x270b),
|
||||
(0x2728, 0x2728),
|
||||
(0x274c, 0x274c),
|
||||
(0x274e, 0x274e),
|
||||
(0x2753, 0x2755),
|
||||
(0x2757, 0x2757),
|
||||
(0x2795, 0x2797),
|
||||
(0x27b0, 0x27b0),
|
||||
(0x27bf, 0x27bf),
|
||||
(0x2b1b, 0x2b1c),
|
||||
(0x2b50, 0x2b50),
|
||||
(0x2b55, 0x2b55),
|
||||
(0x2e80, 0x2e99),
|
||||
(0x2e9b, 0x2ef3),
|
||||
(0x2f00, 0x2fd5),
|
||||
(0x2ff0, 0x2ffb),
|
||||
(0x3001, 0x3029),
|
||||
(0x302e, 0x303e),
|
||||
(0x3041, 0x3096),
|
||||
(0x309b, 0x309c),
|
||||
(0x309d, 0x309e),
|
||||
(0x309f, 0x309f),
|
||||
(0x30a0, 0x30a0),
|
||||
(0x30a1, 0x30fa),
|
||||
(0x30fb, 0x30fb),
|
||||
(0x30fc, 0x30fe),
|
||||
(0x30ff, 0x30ff),
|
||||
(0x3105, 0x312f),
|
||||
(0x3131, 0x318e),
|
||||
(0x3190, 0x3191),
|
||||
(0x3192, 0x3195),
|
||||
(0x3196, 0x319f),
|
||||
(0x31a0, 0x31bf),
|
||||
(0x31c0, 0x31e3),
|
||||
(0x31f0, 0x31ff),
|
||||
(0x3200, 0x321e),
|
||||
(0x3220, 0x3229),
|
||||
(0x322a, 0x3247),
|
||||
(0x3250, 0x3250),
|
||||
(0x3251, 0x325f),
|
||||
(0x3260, 0x327f),
|
||||
(0x3280, 0x3289),
|
||||
(0x328a, 0x32b0),
|
||||
(0x32b1, 0x32bf),
|
||||
(0x32c0, 0x33ff),
|
||||
(0x3400, 0x4bdf),
|
||||
(0x4e00, 0xa014),
|
||||
(0xa015, 0xa015),
|
||||
(0xa016, 0xa48c),
|
||||
(0xa490, 0xa4c6),
|
||||
(0xa960, 0xa97c),
|
||||
(0xac00, 0xd7a3),
|
||||
(0xf900, 0xfa6d),
|
||||
(0xfa70, 0xfad9),
|
||||
(0xfe10, 0xfe19),
|
||||
(0xfe30, 0xfe52),
|
||||
(0xfe54, 0xfe66),
|
||||
(0xfe68, 0xfe6b),
|
||||
];
|
||||
|
||||
const EAW_32: &[(u32, u32)] = &[
|
||||
(0x16fe0, 0x16fe3),
|
||||
(0x16ff0, 0x16ff1),
|
||||
(0x17000, 0x187f7),
|
||||
(0x18800, 0x18cd5),
|
||||
(0x18d00, 0x18d08),
|
||||
(0x1aff0, 0x1aff3),
|
||||
(0x1aff5, 0x1affb),
|
||||
(0x1affd, 0x1affe),
|
||||
(0x1b000, 0x1b122),
|
||||
(0x1b132, 0x1b132),
|
||||
(0x1b150, 0x1b152),
|
||||
(0x1b155, 0x1b155),
|
||||
(0x1b164, 0x1b167),
|
||||
(0x1b170, 0x1b2fb),
|
||||
(0x1f004, 0x1f004),
|
||||
(0x1f0cf, 0x1f0cf),
|
||||
(0x1f18e, 0x1f18e),
|
||||
(0x1f191, 0x1f19a),
|
||||
(0x1f200, 0x1f202),
|
||||
(0x1f210, 0x1f23b),
|
||||
(0x1f240, 0x1f248),
|
||||
(0x1f250, 0x1f251),
|
||||
(0x1f260, 0x1f265),
|
||||
(0x1f300, 0x1f320),
|
||||
(0x1f32d, 0x1f335),
|
||||
(0x1f337, 0x1f37c),
|
||||
(0x1f37e, 0x1f393),
|
||||
(0x1f3a0, 0x1f3ca),
|
||||
(0x1f3cf, 0x1f3d3),
|
||||
(0x1f3e0, 0x1f3f0),
|
||||
(0x1f3f4, 0x1f3f4),
|
||||
(0x1f3f8, 0x1f3fa),
|
||||
(0x1f3fb, 0x1f3ff),
|
||||
(0x1f400, 0x1f43e),
|
||||
(0x1f440, 0x1f440),
|
||||
(0x1f442, 0x1f4fc),
|
||||
(0x1f4ff, 0x1f53d),
|
||||
(0x1f54b, 0x1f54e),
|
||||
(0x1f550, 0x1f567),
|
||||
(0x1f57a, 0x1f57a),
|
||||
(0x1f595, 0x1f596),
|
||||
(0x1f5a4, 0x1f5a4),
|
||||
(0x1f5fb, 0x1f64f),
|
||||
(0x1f680, 0x1f6c5),
|
||||
(0x1f6cc, 0x1f6cc),
|
||||
(0x1f6d0, 0x1f6d2),
|
||||
(0x1f6d5, 0x1f6d7),
|
||||
(0x1f6dc, 0x1f6df),
|
||||
(0x1f6eb, 0x1f6ec),
|
||||
(0x1f6f4, 0x1f6fc),
|
||||
(0x1f7e0, 0x1f7eb),
|
||||
(0x1f7f0, 0x1f7f0),
|
||||
(0x1f90c, 0x1f93a),
|
||||
(0x1f93c, 0x1f945),
|
||||
(0x1f947, 0x1f9ff),
|
||||
(0x1fa70, 0x1fa7c),
|
||||
(0x1fa80, 0x1fa88),
|
||||
(0x1fa90, 0x1fabd),
|
||||
(0x1fabf, 0x1fac5),
|
||||
(0x1face, 0x1fadb),
|
||||
(0x1fae0, 0x1fae8),
|
||||
(0x1faf0, 0x1faf8),
|
||||
(0x20000, 0x2a6df),
|
||||
(0x2a700, 0x2b739),
|
||||
(0x2b740, 0x2b81d),
|
||||
(0x2b820, 0x2cea1),
|
||||
(0x2ceb0, 0x2ebe0),
|
||||
(0x2f800, 0x2fa1d),
|
||||
(0x30000, 0x3134a),
|
||||
(0x31350, 0x323af),
|
||||
];
|
||||
|
||||
const ZERO_16: &[(u32, u32)] = &[
|
||||
(0xad, 0xad),
|
||||
(0x70f, 0x70f),
|
||||
(0x890, 0x891),
|
||||
(0x180e, 0x180e),
|
||||
(0x200b, 0x200f),
|
||||
(0x202a, 0x202e),
|
||||
(0x2060, 0x2064),
|
||||
(0x2066, 0x206f),
|
||||
(0xfeff, 0xfeff),
|
||||
(0xfff9, 0xfffb),
|
||||
(0x488, 0x489),
|
||||
(0x1abe, 0x1abe),
|
||||
(0x20dd, 0x20e0),
|
||||
(0x20e2, 0x20e4),
|
||||
(0xa670, 0xa672),
|
||||
];
|
||||
|
||||
const ZERO_32: &[(u32, u32)] = &[
|
||||
(0x110bd, 0x110bd),
|
||||
(0x110cd, 0x110cd),
|
||||
(0x13430, 0x1343f),
|
||||
(0x1bca0, 0x1bca3),
|
||||
(0x1d173, 0x1d17a),
|
||||
(0xe0001, 0xe0001),
|
||||
(0xe0020, 0xe007f),
|
||||
];
|
||||
|
||||
const NSM_16: &[(u32, u32)] = &[
|
||||
(0x300, 0x36f),
|
||||
(0x483, 0x487),
|
||||
(0x591, 0x5bd),
|
||||
(0x5bf, 0x5bf),
|
||||
(0x5c1, 0x5c2),
|
||||
(0x5c4, 0x5c5),
|
||||
(0x5c7, 0x5c7),
|
||||
(0x610, 0x61a),
|
||||
(0x64b, 0x65f),
|
||||
(0x670, 0x670),
|
||||
(0x6d6, 0x6dc),
|
||||
(0x6df, 0x6e4),
|
||||
(0x6e7, 0x6e8),
|
||||
(0x6ea, 0x6ed),
|
||||
(0x711, 0x711),
|
||||
(0x730, 0x74a),
|
||||
(0x7a6, 0x7b0),
|
||||
(0x7eb, 0x7f3),
|
||||
(0x7fd, 0x7fd),
|
||||
(0x816, 0x819),
|
||||
(0x81b, 0x823),
|
||||
(0x825, 0x827),
|
||||
(0x829, 0x82d),
|
||||
(0x859, 0x85b),
|
||||
(0x898, 0x89f),
|
||||
(0x8ca, 0x8e1),
|
||||
(0x8e3, 0x902),
|
||||
(0x93a, 0x93a),
|
||||
(0x93c, 0x93c),
|
||||
(0x941, 0x948),
|
||||
(0x94d, 0x94d),
|
||||
(0x951, 0x957),
|
||||
(0x962, 0x963),
|
||||
(0x981, 0x981),
|
||||
(0x9bc, 0x9bc),
|
||||
(0x9c1, 0x9c4),
|
||||
(0x9cd, 0x9cd),
|
||||
(0x9e2, 0x9e3),
|
||||
(0x9fe, 0x9fe),
|
||||
(0xa01, 0xa02),
|
||||
(0xa3c, 0xa3c),
|
||||
(0xa41, 0xa42),
|
||||
(0xa47, 0xa48),
|
||||
(0xa4b, 0xa4d),
|
||||
(0xa51, 0xa51),
|
||||
(0xa70, 0xa71),
|
||||
(0xa75, 0xa75),
|
||||
(0xa81, 0xa82),
|
||||
(0xabc, 0xabc),
|
||||
(0xac1, 0xac5),
|
||||
(0xac7, 0xac8),
|
||||
(0xacd, 0xacd),
|
||||
(0xae2, 0xae3),
|
||||
(0xafa, 0xaff),
|
||||
(0xb01, 0xb01),
|
||||
(0xb3c, 0xb3c),
|
||||
(0xb3f, 0xb3f),
|
||||
(0xb41, 0xb44),
|
||||
(0xb4d, 0xb4d),
|
||||
(0xb55, 0xb56),
|
||||
(0xb62, 0xb63),
|
||||
(0xb82, 0xb82),
|
||||
(0xbc0, 0xbc0),
|
||||
(0xbcd, 0xbcd),
|
||||
(0xc00, 0xc00),
|
||||
(0xc04, 0xc04),
|
||||
(0xc3c, 0xc3c),
|
||||
(0xc3e, 0xc40),
|
||||
(0xc46, 0xc48),
|
||||
(0xc4a, 0xc4d),
|
||||
(0xc55, 0xc56),
|
||||
(0xc62, 0xc63),
|
||||
(0xc81, 0xc81),
|
||||
(0xcbc, 0xcbc),
|
||||
(0xcbf, 0xcbf),
|
||||
(0xcc6, 0xcc6),
|
||||
(0xccc, 0xccd),
|
||||
(0xce2, 0xce3),
|
||||
(0xd00, 0xd01),
|
||||
(0xd3b, 0xd3c),
|
||||
(0xd41, 0xd44),
|
||||
(0xd4d, 0xd4d),
|
||||
(0xd62, 0xd63),
|
||||
(0xd81, 0xd81),
|
||||
(0xdca, 0xdca),
|
||||
(0xdd2, 0xdd4),
|
||||
(0xdd6, 0xdd6),
|
||||
(0xe31, 0xe31),
|
||||
(0xe34, 0xe3a),
|
||||
(0xe47, 0xe4e),
|
||||
(0xeb1, 0xeb1),
|
||||
(0xeb4, 0xebc),
|
||||
(0xec8, 0xece),
|
||||
(0xf18, 0xf19),
|
||||
(0xf35, 0xf35),
|
||||
(0xf37, 0xf37),
|
||||
(0xf39, 0xf39),
|
||||
(0xf71, 0xf7e),
|
||||
(0xf80, 0xf84),
|
||||
(0xf86, 0xf87),
|
||||
(0xf8d, 0xf97),
|
||||
(0xf99, 0xfbc),
|
||||
(0xfc6, 0xfc6),
|
||||
(0x102d, 0x1030),
|
||||
(0x1032, 0x1037),
|
||||
(0x1039, 0x103a),
|
||||
(0x103d, 0x103e),
|
||||
(0x1058, 0x1059),
|
||||
(0x105e, 0x1060),
|
||||
(0x1071, 0x1074),
|
||||
(0x1082, 0x1082),
|
||||
(0x1085, 0x1086),
|
||||
(0x108d, 0x108d),
|
||||
(0x109d, 0x109d),
|
||||
(0x135d, 0x135f),
|
||||
(0x1712, 0x1714),
|
||||
(0x1732, 0x1733),
|
||||
(0x1752, 0x1753),
|
||||
(0x1772, 0x1773),
|
||||
(0x17b4, 0x17b5),
|
||||
(0x17b7, 0x17bd),
|
||||
(0x17c6, 0x17c6),
|
||||
(0x17c9, 0x17d3),
|
||||
(0x17dd, 0x17dd),
|
||||
(0x180b, 0x180d),
|
||||
(0x180f, 0x180f),
|
||||
(0x1885, 0x1886),
|
||||
(0x18a9, 0x18a9),
|
||||
(0x1920, 0x1922),
|
||||
(0x1927, 0x1928),
|
||||
(0x1932, 0x1932),
|
||||
(0x1939, 0x193b),
|
||||
(0x1a17, 0x1a18),
|
||||
(0x1a1b, 0x1a1b),
|
||||
(0x1a56, 0x1a56),
|
||||
(0x1a58, 0x1a5e),
|
||||
(0x1a60, 0x1a60),
|
||||
(0x1a62, 0x1a62),
|
||||
(0x1a65, 0x1a6c),
|
||||
(0x1a73, 0x1a7c),
|
||||
(0x1a7f, 0x1a7f),
|
||||
(0x1ab0, 0x1abd),
|
||||
(0x1abf, 0x1ace),
|
||||
(0x1b00, 0x1b03),
|
||||
(0x1b34, 0x1b34),
|
||||
(0x1b36, 0x1b3a),
|
||||
(0x1b3c, 0x1b3c),
|
||||
(0x1b42, 0x1b42),
|
||||
(0x1b6b, 0x1b73),
|
||||
(0x1b80, 0x1b81),
|
||||
(0x1ba2, 0x1ba5),
|
||||
(0x1ba8, 0x1ba9),
|
||||
(0x1bab, 0x1bad),
|
||||
(0x1be6, 0x1be6),
|
||||
(0x1be8, 0x1be9),
|
||||
(0x1bed, 0x1bed),
|
||||
(0x1bef, 0x1bf1),
|
||||
(0x1c2c, 0x1c33),
|
||||
(0x1c36, 0x1c37),
|
||||
(0x1cd0, 0x1cd2),
|
||||
(0x1cd4, 0x1ce0),
|
||||
(0x1ce2, 0x1ce8),
|
||||
(0x1ced, 0x1ced),
|
||||
(0x1cf4, 0x1cf4),
|
||||
(0x1cf8, 0x1cf9),
|
||||
(0x1dc0, 0x1dff),
|
||||
(0x20d0, 0x20dc),
|
||||
(0x20e1, 0x20e1),
|
||||
(0x20e5, 0x20f0),
|
||||
(0x2cef, 0x2cf1),
|
||||
(0x2d7f, 0x2d7f),
|
||||
(0x2de0, 0x2dff),
|
||||
(0x302a, 0x302d),
|
||||
(0x3099, 0x309a),
|
||||
(0xa66f, 0xa66f),
|
||||
(0xa674, 0xa67d),
|
||||
(0xa69e, 0xa69f),
|
||||
(0xa6f0, 0xa6f1),
|
||||
(0xa802, 0xa802),
|
||||
(0xa806, 0xa806),
|
||||
(0xa80b, 0xa80b),
|
||||
(0xa825, 0xa826),
|
||||
(0xa82c, 0xa82c),
|
||||
(0xa8c4, 0xa8c5),
|
||||
(0xa8e0, 0xa8f1),
|
||||
(0xa8ff, 0xa8ff),
|
||||
(0xa926, 0xa92d),
|
||||
(0xa947, 0xa951),
|
||||
(0xa980, 0xa982),
|
||||
(0xa9b3, 0xa9b3),
|
||||
(0xa9b6, 0xa9b9),
|
||||
(0xa9bc, 0xa9bd),
|
||||
(0xa9e5, 0xa9e5),
|
||||
(0xaa29, 0xaa2e),
|
||||
(0xaa31, 0xaa32),
|
||||
(0xaa35, 0xaa36),
|
||||
(0xaa43, 0xaa43),
|
||||
(0xaa4c, 0xaa4c),
|
||||
(0xaa7c, 0xaa7c),
|
||||
(0xaab0, 0xaab0),
|
||||
(0xaab2, 0xaab4),
|
||||
(0xaab7, 0xaab8),
|
||||
(0xaabe, 0xaabf),
|
||||
(0xaac1, 0xaac1),
|
||||
(0xaaec, 0xaaed),
|
||||
(0xaaf6, 0xaaf6),
|
||||
(0xabe5, 0xabe5),
|
||||
(0xabe8, 0xabe8),
|
||||
(0xabed, 0xabed),
|
||||
(0xfb1e, 0xfb1e),
|
||||
(0xfe00, 0xfe0f),
|
||||
(0xfe20, 0xfe2f),
|
||||
];
|
||||
|
||||
const NSM_32: &[(u32, u32)] = &[
|
||||
(0x101fd, 0x101fd),
|
||||
(0x102e0, 0x102e0),
|
||||
(0x10376, 0x1037a),
|
||||
(0x10a01, 0x10a03),
|
||||
(0x10a05, 0x10a06),
|
||||
(0x10a0c, 0x10a0f),
|
||||
(0x10a38, 0x10a3a),
|
||||
(0x10a3f, 0x10a3f),
|
||||
(0x10ae5, 0x10ae6),
|
||||
(0x10d24, 0x10d27),
|
||||
(0x10eab, 0x10eac),
|
||||
(0x10efd, 0x10eff),
|
||||
(0x10f46, 0x10f50),
|
||||
(0x10f82, 0x10f85),
|
||||
(0x11001, 0x11001),
|
||||
(0x11038, 0x11046),
|
||||
(0x11070, 0x11070),
|
||||
(0x11073, 0x11074),
|
||||
(0x1107f, 0x11081),
|
||||
(0x110b3, 0x110b6),
|
||||
(0x110b9, 0x110ba),
|
||||
(0x110c2, 0x110c2),
|
||||
(0x11100, 0x11102),
|
||||
(0x11127, 0x1112b),
|
||||
(0x1112d, 0x11134),
|
||||
(0x11173, 0x11173),
|
||||
(0x11180, 0x11181),
|
||||
(0x111b6, 0x111be),
|
||||
(0x111c9, 0x111cc),
|
||||
(0x111cf, 0x111cf),
|
||||
(0x1122f, 0x11231),
|
||||
(0x11234, 0x11234),
|
||||
(0x11236, 0x11237),
|
||||
(0x1123e, 0x1123e),
|
||||
(0x11241, 0x11241),
|
||||
(0x112df, 0x112df),
|
||||
(0x112e3, 0x112ea),
|
||||
(0x11300, 0x11301),
|
||||
(0x1133b, 0x1133c),
|
||||
(0x11340, 0x11340),
|
||||
(0x11366, 0x1136c),
|
||||
(0x11370, 0x11374),
|
||||
(0x11438, 0x1143f),
|
||||
(0x11442, 0x11444),
|
||||
(0x11446, 0x11446),
|
||||
(0x1145e, 0x1145e),
|
||||
(0x114b3, 0x114b8),
|
||||
(0x114ba, 0x114ba),
|
||||
(0x114bf, 0x114c0),
|
||||
(0x114c2, 0x114c3),
|
||||
(0x115b2, 0x115b5),
|
||||
(0x115bc, 0x115bd),
|
||||
(0x115bf, 0x115c0),
|
||||
(0x115dc, 0x115dd),
|
||||
(0x11633, 0x1163a),
|
||||
(0x1163d, 0x1163d),
|
||||
(0x1163f, 0x11640),
|
||||
(0x116ab, 0x116ab),
|
||||
(0x116ad, 0x116ad),
|
||||
(0x116b0, 0x116b5),
|
||||
(0x116b7, 0x116b7),
|
||||
(0x1171d, 0x1171f),
|
||||
(0x11722, 0x11725),
|
||||
(0x11727, 0x1172b),
|
||||
(0x1182f, 0x11837),
|
||||
(0x11839, 0x1183a),
|
||||
(0x1193b, 0x1193c),
|
||||
(0x1193e, 0x1193e),
|
||||
(0x11943, 0x11943),
|
||||
(0x119d4, 0x119d7),
|
||||
(0x119da, 0x119db),
|
||||
(0x119e0, 0x119e0),
|
||||
(0x11a01, 0x11a0a),
|
||||
(0x11a33, 0x11a38),
|
||||
(0x11a3b, 0x11a3e),
|
||||
(0x11a47, 0x11a47),
|
||||
(0x11a51, 0x11a56),
|
||||
(0x11a59, 0x11a5b),
|
||||
(0x11a8a, 0x11a96),
|
||||
(0x11a98, 0x11a99),
|
||||
(0x11c30, 0x11c36),
|
||||
(0x11c38, 0x11c3d),
|
||||
(0x11c3f, 0x11c3f),
|
||||
(0x11c92, 0x11ca7),
|
||||
(0x11caa, 0x11cb0),
|
||||
(0x11cb2, 0x11cb3),
|
||||
(0x11cb5, 0x11cb6),
|
||||
(0x11d31, 0x11d36),
|
||||
(0x11d3a, 0x11d3a),
|
||||
(0x11d3c, 0x11d3d),
|
||||
(0x11d3f, 0x11d45),
|
||||
(0x11d47, 0x11d47),
|
||||
(0x11d90, 0x11d91),
|
||||
(0x11d95, 0x11d95),
|
||||
(0x11d97, 0x11d97),
|
||||
(0x11ef3, 0x11ef4),
|
||||
(0x11f00, 0x11f01),
|
||||
(0x11f36, 0x11f3a),
|
||||
(0x11f40, 0x11f40),
|
||||
(0x11f42, 0x11f42),
|
||||
(0x13440, 0x13440),
|
||||
(0x13447, 0x13455),
|
||||
(0x16af0, 0x16af4),
|
||||
(0x16b30, 0x16b36),
|
||||
(0x16f4f, 0x16f4f),
|
||||
(0x16f8f, 0x16f92),
|
||||
(0x16fe4, 0x16fe4),
|
||||
(0x1bc9d, 0x1bc9e),
|
||||
(0x1cf00, 0x1cf2d),
|
||||
(0x1cf30, 0x1cf46),
|
||||
(0x1d167, 0x1d169),
|
||||
(0x1d17b, 0x1d182),
|
||||
(0x1d185, 0x1d18b),
|
||||
(0x1d1aa, 0x1d1ad),
|
||||
(0x1d242, 0x1d244),
|
||||
(0x1da00, 0x1da36),
|
||||
(0x1da3b, 0x1da6c),
|
||||
(0x1da75, 0x1da75),
|
||||
(0x1da84, 0x1da84),
|
||||
(0x1da9b, 0x1da9f),
|
||||
(0x1daa1, 0x1daaf),
|
||||
(0x1e000, 0x1e006),
|
||||
(0x1e008, 0x1e018),
|
||||
(0x1e01b, 0x1e021),
|
||||
(0x1e023, 0x1e024),
|
||||
(0x1e026, 0x1e02a),
|
||||
(0x1e08f, 0x1e08f),
|
||||
(0x1e130, 0x1e136),
|
||||
(0x1e2ae, 0x1e2ae),
|
||||
(0x1e2ec, 0x1e2ef),
|
||||
(0x1e4ec, 0x1e4ef),
|
||||
(0x1e8d0, 0x1e8d6),
|
||||
(0x1e944, 0x1e94a),
|
||||
(0xe0100, 0xe01ef),
|
||||
];
|
||||
|
||||
#[inline]
|
||||
fn in_ranges(ranges: &[(u32, u32)], cp: u32) -> bool {
|
||||
ranges.iter().any(|&(lo, hi)| cp >= lo && cp <= hi)
|
||||
}
|
||||
|
||||
/// 16-bit leading ranges. Index >= 5 is zero width, otherwise wide. (2E3B is
|
||||
/// technically width 3, but we clamp to 2.)
|
||||
const LEAD_16: &[(u32, u32)] = &[
|
||||
(0x2E3A, 0x2E3A),
|
||||
(0x3400, 0x4DBF),
|
||||
(0x4E00, 0x9FFF),
|
||||
(0xF900, 0xFAFF),
|
||||
(0x2E3B, 0x2E3B),
|
||||
(0x1160, 0x11FF),
|
||||
(0x2060, 0x206F),
|
||||
(0xFFF0, 0xFFF8),
|
||||
];
|
||||
const LEAD_32_WIDE: &[(u32, u32)] = &[(0x1f1e6, 0x1f1ff), (0x20000, 0x2FFFD), (0x30000, 0x3FFFD)];
|
||||
const LEAD_32_ZERO: &[(u32, u32)] = &[(0xE0000, 0xE0FFF)];
|
||||
|
||||
fn width16(cp: u32) -> i8 {
|
||||
if let Some(i) = LEAD_16.iter().position(|&(lo, hi)| cp >= lo && cp <= hi) {
|
||||
return if i >= 5 { 0 } else { 2 };
|
||||
}
|
||||
if in_ranges(ZERO_16, cp) {
|
||||
return 0;
|
||||
}
|
||||
if in_ranges(EAW_16, cp) {
|
||||
return 2;
|
||||
}
|
||||
if in_ranges(NSM_16, cp) {
|
||||
return 0;
|
||||
}
|
||||
1
|
||||
}
|
||||
|
||||
fn width32(cp: u32) -> i8 {
|
||||
if in_ranges(LEAD_32_WIDE, cp) {
|
||||
return 2;
|
||||
}
|
||||
if in_ranges(LEAD_32_ZERO, cp) {
|
||||
return 0;
|
||||
}
|
||||
if in_ranges(ZERO_32, cp) {
|
||||
return 0;
|
||||
}
|
||||
if in_ranges(EAW_32, cp) {
|
||||
return 2;
|
||||
}
|
||||
if in_ranges(NSM_32, cp) {
|
||||
return 0;
|
||||
}
|
||||
1
|
||||
}
|
||||
|
||||
/// `simd.codepointWidth`. Control characters are not special-cased: input
|
||||
/// `<= 0xFF` is always width 1.
|
||||
#[must_use]
|
||||
pub fn codepoint_width(cp: u32) -> i8 {
|
||||
if cp <= 0xFF {
|
||||
1
|
||||
} else if cp <= 0xFFFF {
|
||||
width16(cp)
|
||||
} else {
|
||||
width32(cp)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user