From 31162225df672187e4b73423ac2f4bc25937fd3f Mon Sep 17 00:00:00 2001 From: bptato Date: Wed, 7 Dec 2022 19:02:56 +0100 Subject: Add multiple text-decoration, overline emulation --- res/config.toml | 2 ++ src/config/config.nim | 29 ++++++++++++++++++----------- src/css/values.nim | 24 ++++++++++++------------ src/display/term.nim | 22 +++++++++++++++++++++- src/layout/box.nim | 2 +- src/render/renderdocument.nim | 9 ++++----- 6 files changed, 58 insertions(+), 30 deletions(-) diff --git a/res/config.toml b/res/config.toml index 6115303b..fa641f25 100644 --- a/res/config.toml +++ b/res/config.toml @@ -5,6 +5,8 @@ editor = "vi %s +%d" [display] color-mode = "auto" format-mode = "auto" +no-format-mode = ["overline"] +emulate-overline = true alt-screen = "auto" highlight-color = "cyan" double-width-ambiguous = false diff --git a/src/config/config.nim b/src/config/config.nim index 941f8c54..19cf9a8a 100644 --- a/src/config/config.nim +++ b/src/config/config.nim @@ -37,12 +37,14 @@ type headless*: bool colormode*: Option[ColorMode] formatmode*: Option[FormatMode] + noformatmode*: FormatMode altscreen*: Option[bool] mincontrast*: float editor*: string tmpdir*: string siteconf: seq[StaticSiteConfig] forceclear*: bool + emulateoverline*: bool BufferConfig* = object userstyle*: string @@ -170,6 +172,18 @@ proc parseConfig(config: Config, dir: string, t: TomlValue) = of "inline": config.stylesheet &= v.s of "display": + template get_format_mode(v: TomlValue): FormatMode = + var mode: FormatMode + for vv in v.a: + case vv.s + of "bold": mode.incl(FLAG_BOLD) + of "italic": mode.incl(FLAG_ITALIC) + of "underline": mode.incl(FLAG_UNDERLINE) + of "reverse": mode.incl(FLAG_REVERSE) + of "strike": mode.incl(FLAG_STRIKE) + of "overline": mode.incl(FLAG_OVERLINE) + of "blink": mode.incl(FLAG_BLINK) + mode for k, v in v: case k of "alt-screen": @@ -188,17 +202,9 @@ proc parseConfig(config: Config, dir: string, t: TomlValue) = if v.vt == VALUE_STRING and v.s == "auto": config.formatmode = none(FormatMode) elif v.vt == VALUE_ARRAY: - var mode: FormatMode - for v in v.a: - case v.s - of "bold": mode.incl(FLAG_BOLD) - of "italic": mode.incl(FLAG_ITALIC) - of "underline": mode.incl(FLAG_UNDERLINE) - of "reverse": mode.incl(FLAG_REVERSE) - of "strike": mode.incl(FLAG_STRIKE) - of "overline": mode.incl(FLAG_OVERLINE) - of "blink": mode.incl(FLAG_BLINK) - config.formatmode = some(mode) + config.formatmode = some(get_format_mode v) + of "no-format-mode": + config.noformatmode = get_format_mode v of "highlight-color": config.hlcolor = parseRGBAColor(v.s).get of "double-width-ambiguous": @@ -209,6 +215,7 @@ proc parseConfig(config: Config, dir: string, t: TomlValue) = else: config.mincontrast = float(v.f) of "force-clear": config.forceclear = v.b + of "emulate-overline": config.emulateoverline = v.b of "external": for k, v in v: case k diff --git a/src/css/values.nim b/src/css/values.nim index 848bd7d0..304eada5 100644 --- a/src/css/values.nim +++ b/src/css/values.nim @@ -121,7 +121,7 @@ type of VALUE_INTEGER: integer*: int of VALUE_TEXT_DECORATION: - textdecoration*: CSSTextDecoration + textdecoration*: set[CSSTextDecoration] of VALUE_WORD_BREAK: wordbreak*: CSSWordBreak of VALUE_LIST_STYLE_TYPE: @@ -538,17 +538,17 @@ func cssFontWeight(d: CSSDeclaration): int = raise newException(CSSValueError, "Invalid font weight") -func cssTextDecoration(d: CSSDeclaration): CSSTextDecoration = - if isToken(d): - let tok = getToken(d) - if tok.tokenType == CSS_IDENT_TOKEN: - case tok.value - of "none": return TEXT_DECORATION_NONE - of "underline": return TEXT_DECORATION_UNDERLINE - of "overline": return TEXT_DECORATION_OVERLINE - of "line-through": return TEXT_DECORATION_LINE_THROUGH - of "blink": return TEXT_DECORATION_BLINK - raise newException(CSSValueError, "Invalid text decoration") +func cssTextDecoration(d: CSSDeclaration): set[CSSTextDecoration] = + for tok in d.value: + if tok of CSSToken: + let tok = CSSToken(tok) + if tok.tokenType == CSS_IDENT_TOKEN: + case tok.value + of "none": result.incl(TEXT_DECORATION_NONE) + of "underline": result.incl(TEXT_DECORATION_UNDERLINE) + of "overline": result.incl(TEXT_DECORATION_OVERLINE) + of "line-through": result.incl(TEXT_DECORATION_LINE_THROUGH) + of "blink": result.incl(TEXT_DECORATION_BLINK) func cssWordBreak(d: CSSDeclaration): CSSWordBreak = if isToken(d): diff --git a/src/display/term.nim b/src/display/term.nim index eb061d99..beb84a4c 100644 --- a/src/display/term.nim +++ b/src/display/term.nim @@ -332,10 +332,27 @@ proc hideCursor*(term: Terminal) = proc showCursor*(term: Terminal) = term.outfile.showCursor() +func emulateOverline(term: Terminal): bool = + term.config.emulateoverline and FLAG_OVERLINE notin term.formatmode and + FLAG_UNDERLINE in term.formatmode + proc writeGrid*(term: Terminal, grid: FixedGrid, x = 0, y = 0) = for ly in y ..< y + grid.height: for lx in x ..< x + grid.width: - term.canvas[ly * term.canvas.width + lx] = grid[(ly - y) * grid.width + (lx - x)] + let i = ly * term.canvas.width + lx + term.canvas[i] = grid[(ly - y) * grid.width + (lx - x)] + if i >= term.canvas.width and FLAG_OVERLINE in term.canvas[i].format.flags and term.emulateOverline: + let w = grid[(ly - y) * grid.width + (lx - x)].width() + let s = i - term.canvas.width + var j = s + while j < term.canvas.len and j < s + w: + let cell = addr term.canvas[j] + cell.format.flags.incl(FLAG_UNDERLINE) + if cell.str == "": + cell.str = " " + if cell.str == " ": + cell.format.fgcolor = grid[(ly - y) * grid.width + (lx - x)].format.fgcolor + j += cell[].width() proc outputGrid*(term: Terminal) = term.outfile.write(term.resetFormat()) @@ -449,6 +466,9 @@ proc detectTermAttributes(term: Terminal) = of "24bit", "truecolor": term.colormode = TRUE_COLOR if term.config.formatmode.isSome: term.formatmode = term.config.formatmode.get + for fm in FormatFlags: + if fm in term.config.noformatmode: + term.formatmode.excl(fm) if term.config.altscreen.isSome: term.smcup = term.config.altscreen.get term.mincontrast = term.config.mincontrast diff --git a/src/layout/box.nim b/src/layout/box.nim index 3a8dc41c..4a0b0fcd 100644 --- a/src/layout/box.nim +++ b/src/layout/box.nim @@ -74,7 +74,7 @@ type ComputedFormat* = ref object fontstyle*: CSSFontStyle fontweight*: int - textdecoration*: CSSTextDecoration + textdecoration*: set[CSSTextDecoration] color*: RGBAColor node*: StyledNode diff --git a/src/render/renderdocument.nim b/src/render/renderdocument.nim index 0315f6b7..2a938acc 100644 --- a/src/render/renderdocument.nim +++ b/src/render/renderdocument.nim @@ -19,14 +19,13 @@ func formatFromWord(computed: ComputedFormat): Format = result.italic = true if computed.fontweight > 500: result.bold = true - case computed.textdecoration - of TEXT_DECORATION_UNDERLINE: + if TEXT_DECORATION_UNDERLINE in computed.textdecoration: result.underline = true - of TEXT_DECORATION_OVERLINE: + if TEXT_DECORATION_OVERLINE in computed.textdecoration: result.overline = true - of TEXT_DECORATION_LINE_THROUGH: + if TEXT_DECORATION_LINE_THROUGH in computed.textdecoration: result.strike = true - of TEXT_DECORATION_BLINK: + if TEXT_DECORATION_BLINK in computed.textdecoration: result.blink = true else: discard -- cgit 1.4.1-2-gfad0