diff --git a/src/components/Segment.js b/src/components/Segment.js index 4602e9ef..4cf0bbe3 100644 --- a/src/components/Segment.js +++ b/src/components/Segment.js @@ -1,20 +1,36 @@ export default (props) => { + const codePoint = () => { + if (props.text.length == 1) { + const cp = props.text.codePointAt(0); + + if ((cp >= 0x2580 && cp <= 0x2595) || cp == 0xe0b0 || cp == 0xe0b2) { + return cp; + } + } + }; + + const text = () => (codePoint() ? " " : props.text); + return ( - {props.text} + {text()} ); }; -function className(attrs, extraClass) { +function className(attrs, codePoint, extraClass) { const fgClass = colorClass(attrs.get("fg"), attrs.get("bold"), "fg-"); const bgClass = colorClass(attrs.get("bg"), attrs.get("blink"), "bg-"); let cls = extraClass ?? ""; + if (codePoint !== undefined) { + cls += ` cp-${codePoint.toString(16)}`; + } + if (fgClass) { cls += " " + fgClass; } @@ -60,12 +76,13 @@ function colorClass(color, intense, prefix) { } } -function style(attrs, offset, terminalCols) { +function style(attrs, offset, textLen, charWidth, terminalCols) { const fg = attrs.get("fg"); const bg = attrs.get("bg"); let style = { left: `${(100 * offset) / terminalCols}%`, + width: `${textLen * charWidth + 0.01}ch`, }; if (typeof fg === "string") { diff --git a/src/components/Terminal.js b/src/components/Terminal.js index a8928ca0..8de1a751 100644 --- a/src/components/Terminal.js +++ b/src/components/Terminal.js @@ -11,6 +11,7 @@ export default (props) => { "font-size": `${(props.scale || 1.0) * 100}%`, "font-family": props.fontFamily, "line-height": `${lineHeight()}em`, + "--term-line-height": lineHeight(), }; }); diff --git a/src/less/partials/_terminal.less b/src/less/partials/_terminal.less index 7e22aa7d..18ffe9a4 100644 --- a/src/less/partials/_terminal.less +++ b/src/less/partials/_terminal.less @@ -33,6 +33,174 @@ pre.ap-terminal { color: var(--bg); background-color: var(--fg); } + + // upper half block + .cp-2580 { + border-top: calc(0.5em * var(--term-line-height)) solid var(--fg); + box-sizing: border-box; + width: 1.01ch; + } + + // lower one eighth block + .cp-2581 { + border-bottom: calc(0.125em * var(--term-line-height)) solid var(--fg); + box-sizing: border-box; + width: 1.01ch; + } + + // lower one quarter block + .cp-2582 { + border-bottom: calc(0.25em * var(--term-line-height)) solid var(--fg); + box-sizing: border-box; + width: 1.01ch; + } + + // lower three eighths block + .cp-2583 { + border-bottom: calc(0.375em * var(--term-line-height)) solid var(--fg); + box-sizing: border-box; + width: 1.01ch; + } + + // lower half block + .cp-2584 { + border-bottom: calc(0.5em * var(--term-line-height)) solid var(--fg); + box-sizing: border-box; + width: 1.01ch; + } + + // lower five eighths block + .cp-2585 { + border-bottom: calc(0.625em * var(--term-line-height)) solid var(--fg); + box-sizing: border-box; + width: 1.01ch; + } + + // lower three quarters block + .cp-2586 { + border-bottom: calc(0.75em * var(--term-line-height)) solid var(--fg); + box-sizing: border-box; + width: 1.01ch; + } + + // lower seven eighths block + .cp-2587 { + border-bottom: calc(0.875em * var(--term-line-height)) solid var(--fg); + box-sizing: border-box; + width: 1.01ch; + } + + // full block + .cp-2588 { + background-color: var(--fg); + width: 1.01ch; + } + + // left seven eighths block + .cp-2589 { + border-left: 0.875ch solid var(--fg); + box-sizing: border-box; + width: 1ch; + } + + // left three quarters block + .cp-258a { + border-left: 0.75ch solid var(--fg); + box-sizing: border-box; + width: 1ch; + } + + // left five eighths block + .cp-258b { + border-left: 0.625ch solid var(--fg); + box-sizing: border-box; + width: 1ch; + } + + // left half block + .cp-258c { + border-left: 0.5ch solid var(--fg); + box-sizing: border-box; + width: 1ch; + } + + // left three eighths block + .cp-258d { + border-left: 0.375ch solid var(--fg); + box-sizing: border-box; + width: 1ch; + } + + // left one quarter block + .cp-258e { + border-left: 0.25ch solid var(--fg); + box-sizing: border-box; + width: 1ch; + } + + // left one eighth block + .cp-258f { + border-left: 0.125ch solid var(--fg); + box-sizing: border-box; + width: 1ch; + } + + // right half block + .cp-2590 { + border-right: 0.5ch solid var(--fg); + box-sizing: border-box; + width: 1ch; + } + + // light shade (░) + .cp-2591 { + background-color: color-mix(in srgb, var(--fg) 25%, var(--bg)); + width: 1.01ch; + } + + // medium shade (▒) + .cp-2592 { + background-color: color-mix(in srgb, var(--fg) 50%, var(--bg)); + width: 1.01ch; + } + + // dark shade (▓) + .cp-2593 { + background-color: color-mix(in srgb, var(--fg) 75%, var(--bg)); + width: 1.01ch; + } + + // upper one eighth block + .cp-2594 { + border-top: calc(0.125em * var(--term-line-height)) solid var(--fg); + box-sizing: border-box; + width: 1.01ch; + } + + // right one eighth block + .cp-2595 { + border-right: 0.125ch solid var(--fg); + box-sizing: border-box; + width: 1ch; + } + + // powerline right full triangle + .cp-e0b0 { + border-left: 1.0ch solid var(--fg); + border-top: calc(0.5em * var(--term-line-height)) solid transparent; + border-bottom: calc(0.5em * var(--term-line-height)) solid transparent; + box-sizing: border-box; + width: 1.01ch; + } + + // powerline left full triangle + .cp-e0b2 { + border-right: 1.0ch solid var(--fg); + border-top: calc(0.5em * var(--term-line-height)) solid transparent; + border-bottom: calc(0.5em * var(--term-line-height)) solid transparent; + box-sizing: border-box; + width: 1.01ch; + } } &.ap-cursor-on .ap-line .ap-cursor { diff --git a/src/vt/Cargo.lock b/src/vt/Cargo.lock index 0fae4154..c1c82f7d 100644 --- a/src/vt/Cargo.lock +++ b/src/vt/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "avt" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75abd5104739a34dd6d3e3d4ab8a6d8811d8c8c25a1c2762ffbe0652ffdb8da3" +checksum = "8f453ce6fa1e0820846a95d8b16eb09eeb96e138f31f336b03af5b3fcaa291cc" dependencies = [ "rgb", "serde", diff --git a/src/vt/Cargo.toml b/src/vt/Cargo.toml index 53d9af5b..7e21685c 100644 --- a/src/vt/Cargo.toml +++ b/src/vt/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["cdylib", "rlib"] # default = ["console_error_panic_hook"] [dependencies] -avt = "0.10.1" +avt = "0.10.2" getrandom = { version = "0.2", features = ["js"] } rand = "^0.8" serde-wasm-bindgen = "0.4.5" diff --git a/src/vt/src/lib.rs b/src/vt/src/lib.rs index 21a60516..5151b448 100644 --- a/src/vt/src/lib.rs +++ b/src/vt/src/lib.rs @@ -4,7 +4,9 @@ use std::ops::RangeInclusive; use wasm_bindgen::prelude::*; const BOX_DRAWING_RANGE: RangeInclusive = '\u{2500}'..='\u{257f}'; +const BLOCK_ELEMENTS_RANGE: RangeInclusive = '\u{2580}'..='\u{2595}'; const BRAILLE_PATTERNS_RANGE: RangeInclusive = '\u{2800}'..='\u{28ff}'; +const POWERLINE_TRIANGLES_RANGE: RangeInclusive = '\u{e0b0}'..='\u{e0b3}'; #[wasm_bindgen] pub struct VtWrapper { @@ -45,7 +47,13 @@ impl VtWrapper { let line: Vec<_> = self .vt .line(l) - .group(|c| BOX_DRAWING_RANGE.contains(c) || BRAILLE_PATTERNS_RANGE.contains(c)) + .group(|c, w| { + w > 1 + || BOX_DRAWING_RANGE.contains(c) + || BRAILLE_PATTERNS_RANGE.contains(c) + || BLOCK_ELEMENTS_RANGE.contains(c) + || POWERLINE_TRIANGLES_RANGE.contains(c) + }) .collect(); serde_wasm_bindgen::to_value(&line).unwrap()