diff options
-rw-r--r-- | src/client.nim | 6 | ||||
-rw-r--r-- | src/css/sheet.nim | 3 | ||||
-rw-r--r-- | src/io/buffer.nim | 155 | ||||
-rw-r--r-- | src/layout/engine.nim | 5 | ||||
-rw-r--r-- | src/render/renderdocument.nim | 87 | ||||
-rw-r--r-- | src/render/rendertext.nim | 40 |
6 files changed, 151 insertions, 145 deletions
diff --git a/src/client.nim b/src/client.nim index e9d8ef17..896dd46c 100644 --- a/src/client.nim +++ b/src/client.nim @@ -1,13 +1,14 @@ import httpclient import streams -import uri import terminal +import uri import io/buffer import io/lineedit import config/config import html/parser import utils/twtstr +import css/sheet #import types/url type @@ -16,6 +17,7 @@ type buffer: Buffer feednext: bool s: string + userstyle: CSSStylesheet proc die() = eprint "Invalid parameters. Usage:\ntwt <url>" @@ -78,6 +80,7 @@ proc discardBuffer(client: Client) = proc setupBuffer(client: Client) = let buffer = client.buffer + buffer.userstyle = client.userstyle buffer.document = parseHtml(newStringStream(buffer.source)) buffer.render() buffer.gotoAnchor() @@ -218,6 +221,7 @@ proc input(client: Client) = else: discard proc launchClient*(client: Client, params: seq[string]) = + client.userstyle = gconfig.stylesheet.parseStylesheet() client.buffer = newBuffer() if params.len < 1: client.readPipe() diff --git a/src/css/sheet.nim b/src/css/sheet.nim index 4db068f3..c79dcd2a 100644 --- a/src/css/sheet.nim +++ b/src/css/sheet.nim @@ -44,3 +44,6 @@ proc parseStylesheet*(s: Stream): CSSStylesheet = #result.add(CSSAtRule(v).parseAtRule()) else: result.addRule(v) + +proc parseStylesheet*(s: string): CSSStylesheet = + return newStringStream(s).parseStylesheet() diff --git a/src/io/buffer.nim b/src/io/buffer.nim index 98b20091..35325ff7 100644 --- a/src/io/buffer.nim +++ b/src/io/buffer.nim @@ -1,25 +1,21 @@ +import os import terminal import uri -import strutils import unicode -import streams -import os -import css/values import css/cascade import css/sheet -import utils/twtstr import html/dom import html/tags -import layout/box -import layout/engine -import config/config import io/term import io/cell +import layout/box +import render/renderdocument +import render/rendertext +import utils/twtstr type - Buffer* = ref BufferObj - BufferObj = object + Buffer* = ref object title*: string lines*: FlexibleGrid display*: FixedGrid @@ -47,6 +43,7 @@ type sourcepair*: Buffer prev*: Buffer next* {.cursor.}: Buffer + userstyle*: CSSStylesheet proc newBuffer*(): Buffer = new(result) @@ -58,7 +55,7 @@ proc newBuffer*(): Buffer = result.prevdisplay = newFixedGrid(result.width, result.height) result.statusmsg = newFixedGrid(result.width) -func generateFullOutput*(buffer: Buffer): string = +func generateFullOutput(buffer: Buffer): string = var x = 0 var w = 0 var formatting = newFormatting() @@ -244,10 +241,6 @@ func hasAnchor*(buffer: Buffer, anchor: string): bool = proc addLine(buffer: Buffer) = buffer.lines.addLine() -proc clearText(buffer: Buffer) = - buffer.lines.setLen(0) - buffer.addLine() - proc clearDisplay(buffer: Buffer) = buffer.prevdisplay = buffer.display buffer.display = newFixedGrid(buffer.width, buffer.height) @@ -693,63 +686,6 @@ proc refreshTermAttrs*(buffer: Buffer): bool = return true return false -func formatFromLine(line: CSSRowBox): Formatting = - result.fgcolor = line.color.cellColor() - if line.fontstyle in { FONT_STYLE_ITALIC, FONT_STYLE_OBLIQUE }: - result.italic_on - if line.fontweight > 500: - result.bold_on - if line.textdecoration == TEXT_DECORATION_UNDERLINE: - result.underline_on - if line.textdecoration == TEXT_DECORATION_OVERLINE: - result.overline_on - if line.textdecoration == TEXT_DECORATION_LINE_THROUGH: - result.strike_on - -proc setRowBox(buffer: Buffer, line: CSSRowBox) = - var r: Rune - - var x = line.x - var i = 0 - while x < 0: - fastRuneAt(line.str, i, r) - x += r.width() - let linestr = line.str.substr(i) - i = 0 - - let y = line.y - - while buffer.lines.len <= y: - buffer.addLine() - - var cx = 0 - while cx < x and i < buffer.lines[y].str.len: - fastRuneAt(buffer.lines[y].str, i, r) - cx += r.width() - - let ostr = buffer.lines[y].str.substr(i) - let oformats = buffer.lines[y].formats.subformats(i) - buffer.lines[y].setLen(i) - - buffer.lines.addFormat(y, i, line.formatFromLine(), line.nodes) - - var nx = cx - if nx < x: - buffer.lines[y].str &= ' '.repeat(x - nx) - nx = x - - buffer.lines[y].str &= linestr - nx += linestr.width() - - i = 0 - while cx < nx and i < ostr.len: - fastRuneAt(ostr, i, r) - cx += r.width() - - if i < ostr.len: - let oline = FlexibleLine(str: ostr.substr(i), formats: oformats.subformats(i)) - buffer.lines[y].add(oline) - proc updateCursor(buffer: Buffer) = if buffer.fromy > buffer.lastVisibleLine - 1: buffer.fromy = 0 @@ -811,81 +747,12 @@ proc updateHover(buffer: Buffer) = elem.refreshStyle() buffer.prevnodes = nodes -proc renderPlainText*(buffer: Buffer, text: string) = - var format = newFormatting() - template add_format() = - if af: - af = false - buffer.lines.addFormat(y, buffer.lines[y].str.len, format) - - buffer.clearText() - var i = 0 - var x = 0 - var y = 0 - var af = false - while i < text.len: - if text[i] == '\n': - if i != text.len - 1: - add_format - buffer.addLine() - inc y - x = 0 - inc i - elif text[i] == '\r': - inc i - elif text[i] == '\t': - add_format - for i in 0..8: - buffer.lines[^1].str &= ' ' - inc i - elif text[i] == '\e': - i = format.parseAnsiCode(text, i) - af = true - elif text[i].isControlChar(): - add_format - buffer.lines[y].str &= '^' & text[i].getControlLetter() - inc i - else: - add_format - buffer.lines[y].str &= text[i] - inc i - buffer.updateCursor() - - -const css = staticRead"res/ua.css" -let ua_stylesheet = newStringStream(css).parseStylesheet() - -#TODO refactor -var ss_init = false -var user_stylesheet: CSSStylesheet -proc renderDocument(buffer: Buffer) = - buffer.clearText() - - if not ss_init: - user_stylesheet = newStringStream(gconfig.stylesheet).parseStylesheet() - ss_init = true - - buffer.document.applyStylesheets(ua_stylesheet, user_stylesheet) - buffer.rootbox = buffer.document.alignBoxes(buffer.attrs) - var stack: seq[CSSBox] - stack.add(buffer.rootbox) - while stack.len > 0: - let box = stack.pop() - if box of CSSBlockBox: - for line in box.icontext.rows: - buffer.setRowBox(line) - - var i = box.children.len - 1 - while i >= 0: - stack.add(box.children[i]) - dec i - buffer.updateCursor() - proc render*(buffer: Buffer) = if buffer.showsource: - buffer.renderPlainText(buffer.source) + buffer.lines = renderPlainText(buffer.source) else: - buffer.renderDocument() + buffer.lines = renderDocument(buffer.document, buffer.attrs, buffer.userstyle) + buffer.updateCursor() proc cursorBufferPos(buffer: Buffer) = let x = max(buffer.cursorx - buffer.fromx, 0) diff --git a/src/layout/engine.nim b/src/layout/engine.nim index 42067ace..bea3371d 100644 --- a/src/layout/engine.nim +++ b/src/layout/engine.nim @@ -496,3 +496,8 @@ proc alignBoxes*(document: Document, term: TermAttributes): CSSBox = state.nodes.add(document.root) state.processElemChildren(rootbox, document.root) return rootbox + +proc alignBoxes2*(document: Document, term: TermAttributes): CSSBlockBox = + result = CSSBlockBox() + result.bcontext = BlockContext() + result.bcontext.content.add(CSSInlineBox()) diff --git a/src/render/renderdocument.nim b/src/render/renderdocument.nim new file mode 100644 index 00000000..c3ad6cfe --- /dev/null +++ b/src/render/renderdocument.nim @@ -0,0 +1,87 @@ +import strutils +import unicode + +import css/cascade +import css/sheet +import css/values +import html/dom +import io/cell +import io/term +import layout/box +import layout/engine +import utils/twtstr + +func formatFromLine(line: CSSRowBox): Formatting = + result.fgcolor = line.color.cellColor() + if line.fontstyle in { FONT_STYLE_ITALIC, FONT_STYLE_OBLIQUE }: + result.italic_on + if line.fontweight > 500: + result.bold_on + if line.textdecoration == TEXT_DECORATION_UNDERLINE: + result.underline_on + if line.textdecoration == TEXT_DECORATION_OVERLINE: + result.overline_on + if line.textdecoration == TEXT_DECORATION_LINE_THROUGH: + result.strike_on + +proc setRowBox(lines: var FlexibleGrid, line: CSSRowBox) = + var r: Rune + + var x = line.x + var i = 0 + while x < 0: + fastRuneAt(line.str, i, r) + x += r.width() + let linestr = line.str.substr(i) + i = 0 + + let y = line.y + + while lines.len <= y: + lines.addLine() + + var cx = 0 + while cx < x and i < lines[y].str.len: + fastRuneAt(lines[y].str, i, r) + cx += r.width() + + let ostr = lines[y].str.substr(i) + let oformats = lines[y].formats.subformats(i) + lines[y].setLen(i) + + lines.addFormat(y, i, line.formatFromLine(), line.nodes) + + var nx = cx + if nx < x: + lines[y].str &= ' '.repeat(x - nx) + nx = x + + lines[y].str &= linestr + nx += linestr.width() + + i = 0 + while cx < nx and i < ostr.len: + fastRuneAt(ostr, i, r) + cx += r.width() + + if i < ostr.len: + let oline = FlexibleLine(str: ostr.substr(i), formats: oformats.subformats(i)) + lines[y].add(oline) + +const css = staticRead"res/ua.css" +let uastyle = css.parseStylesheet() +proc renderDocument*(document: Document, attrs: TermAttributes, userstyle: CSSStylesheet): FlexibleGrid = + document.applyStylesheets(uastyle, userstyle) + let rootbox = document.alignBoxes(attrs) + var stack: seq[CSSBox] + stack.add(rootbox) + while stack.len > 0: + let box = stack.pop() + if box of CSSBlockBox: + for line in box.icontext.rows: + result.setRowBox(line) + + var i = box.children.len - 1 + while i >= 0: + stack.add(box.children[i]) + dec i diff --git a/src/render/rendertext.nim b/src/render/rendertext.nim new file mode 100644 index 00000000..a421f509 --- /dev/null +++ b/src/render/rendertext.nim @@ -0,0 +1,40 @@ +import io/cell +import utils/twtstr + +proc renderPlainText*(text: string): FlexibleGrid = + var format = newFormatting() + template add_format() = + if af: + af = false + result.addFormat(y, result[y].str.len, format) + + var i = 0 + var x = 0 + var y = 0 + var af = false + while i < text.len: + if text[i] == '\n': + if i != text.len - 1: + add_format + result.addLine() + inc y + x = 0 + inc i + elif text[i] == '\r': + inc i + elif text[i] == '\t': + add_format + for i in 0..8: + result[^1].str &= ' ' + inc i + elif text[i] == '\e': + i = format.parseAnsiCode(text, i) + af = true + elif text[i].isControlChar(): + add_format + result[y].str &= '^' & text[i].getControlLetter() + inc i + else: + add_format + result[y].str &= text[i] + inc i |