diff options
author | bptato <nincsnevem662@gmail.com> | 2021-08-10 15:19:32 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2021-08-10 15:19:32 +0200 |
commit | a5f7da0428fdb74d9691cd6d589047478f422898 (patch) | |
tree | 0bbea58202a8f509c83378a4b57bbe419131c7d5 | |
parent | 3d24875924b088e5d771e4b901f692659c5281c0 (diff) | |
download | chawan-a5f7da0428fdb74d9691cd6d589047478f422898.tar.gz |
Some refactoring
-rw-r--r-- | res/config | 24 | ||||
-rw-r--r-- | res/default.css | 19 | ||||
-rw-r--r-- | src/css/box.nim | 35 | ||||
-rw-r--r-- | src/css/cssparser.nim | 5 | ||||
-rw-r--r-- | src/html/dom.nim | 36 | ||||
-rw-r--r-- | src/html/renderer.nim | 82 | ||||
-rw-r--r-- | src/io/buffer.nim | 55 | ||||
-rw-r--r-- | src/io/cell.nim | 34 | ||||
-rw-r--r-- | src/main.nim | 5 |
9 files changed, 178 insertions, 117 deletions
diff --git a/res/config b/res/config index 9fce379b..8e7eb7f1 100644 --- a/res/config +++ b/res/config @@ -79,6 +79,18 @@ comp i' í comp o' ó comp u' ú +COMP A: Ä +COMP O: Ö +COMP U: Ü +COMP U" Ű +COMP O" Ő + +COMP A' Á +COMP E' É +COMP I' Í +COMP O' Ó +COMP U' Ú + comp sS ß comp n~ ñ @@ -442,6 +454,18 @@ comp TTI ッティ comp DI ディ comp DDI ッディ +comp KKYA ッキャ +comp KKYU ッキュ +comp KKYO ッキョ + +comp SSHA ッシャ +comp SSHU ッシュ +comp SSHO ッショ + +comp CCHA ッチャ +comp CCHU ッチュ +comp CCHO ッチョ + comp SHE シェ comp SSHE ッシェ diff --git a/res/default.css b/res/default.css index 02f0683a..6a176492 100644 --- a/res/default.css +++ b/res/default.css @@ -14,15 +14,26 @@ br { } a, abbr, b, bdo, button, cite, code, del, dfn, em, font, i, img, ins, -input, iframe, kbd, label, map, object, q, samp, select, small, span, strong, -sub, sup, textarea, tt, var, font, iframe, u, s, strike, frame, img, input { - display: inline; +iframe, kbd, label, map, object, q, samp, select, small, span, strong +{ + display: inline } -i { +sub, sup, textarea, tt, var, font, iframe, u, s, strike, frame, input, img { + display: inline-block; +} + +i, em { font-style: italic; } +b, strong { + font-weight: bold; +} + +u, ins { + text-decoration: underline; + col { display: table-column; } diff --git a/src/css/box.nim b/src/css/box.nim index 3b74380a..0994dca0 100644 --- a/src/css/box.nim +++ b/src/css/box.nim @@ -1,6 +1,7 @@ import unicode import utils/twtstr +import io/cell type CSSRect* = object @@ -20,7 +21,7 @@ type CSSInlineBox* = ref CSSInlineBoxObj CSSInlineBoxObj = object of CSSBox - nextpart: CSSInlineBox + nextpart*: CSSInlineBox CSSBlockBox* = ref CSSBlockBoxObj CSSBlockBoxObj = object of CSSBox @@ -36,35 +37,3 @@ proc `+=`(a: var CSSRect, b: CSSRect) = func size*(box: CSSBox): tuple[w: int, h: int] = return (box.innerEdge.x2 - box.innerEdge.x1, box.innerEdge.y2 - box.innerEdge.x1) - -func boxesForText*(text: seq[Rune], width: int, height: int, lx: int, x: int, y: int): seq[CSSInlineBox] = - result.add(CSSInlineBox()) - var w = x - var sx = x - var sy = y - var i = 0 - while i < text.len and sy < height: - let cw = text[i].width() - if w + cw > width: - result[^1].innerEdge.x1 = sx - result[^1].innerEdge.x2 = sx + w - result[^1].innerEdge.y1 = sy - result[^1].innerEdge.y2 = sy + 1 - sx = lx - inc sy - w = 0 - - result[^2].nextpart = result[^1] - result.add(CSSInlineBox()) - - result[^1].content &= text[i] - w += cw - inc i - - if result.len > 1: - result[^2].nextpart = result[^1] - if w > 0: - result[^1].innerEdge.x1 = sx - result[^1].innerEdge.x2 = sx + w - result[^1].innerEdge.y1 = sy - result[^1].innerEdge.y2 = sy + 1 diff --git a/src/css/cssparser.nim b/src/css/cssparser.nim index afbdf413..fac1bce8 100644 --- a/src/css/cssparser.nim +++ b/src/css/cssparser.nim @@ -1,6 +1,5 @@ -# CSS tokenizer and parser. The tokenizer is a mess, and may or may not work -# correctly. The parser should work, though the outputted object model is -# questionable at best. +# CSS tokenizer and parser. It kinda works, though certain less specific +# details of the specification might have been implemented incorrectly. import unicode import streams diff --git a/src/html/dom.nim b/src/html/dom.nim index c7d3a650..dde6525f 100644 --- a/src/html/dom.nim +++ b/src/html/dom.nim @@ -11,7 +11,6 @@ import algorithm import css/style import css/cssparser import css/selector -import css/box import types/enums import utils/twtstr @@ -89,7 +88,6 @@ type attributes*: Table[string, Attr] style*: CSS2Properties cssvalues*: seq[CSSComputedValue] - box*: CSSBox HTMLElement* = ref HTMLElementObj HTMLElementObj = object of ElementObj @@ -478,39 +476,6 @@ proc applyRules*(document: Document, rules: CSSStylesheet): seq[tuple[e:Element, for child in elem.children: stack.add(child) -proc generateBox*(elem: Element, x: int, y: int, w: int, h: int) = - let display = elem.cssvalues.getValue(RULE_DISPLAY) - if display.t == RULE_DISPLAY: - if display.display == DISPLAY_NONE: - return - var box = new(CSSBlockBox) - box.innerEdge.x1 = x - box.innerEdge.y1 = y - - var lx = x - var rx = x - var ry = y - for child in elem.childNodes: - if child.nodeType == ELEMENT_NODE: - let elem = Element(child) - elem.generateBox(rx, ry, w, h) - if elem.box != nil: - box.innerEdge.x2 += elem.box.size().w - box.innerEdge.y2 += elem.box.size().h - rx = x - lx = x - ry += elem.box.size().h - box.children.add(elem.box) - elif child.nodeType == TEXT_NODE: - let text = Text(child) - let runes = text.data.toRunes() - let boxes = boxesForText(runes, w, h, lx, rx, ry) - for child in boxes: - box.children.add(child) - box.innerEdge.y2 += child.size().h - ry += child.size().h - lx = boxes[^1].innerEdge.x2 - elem.box = box proc applyDefaultStylesheet*(document: Document) = let important = document.applyRules(stylesheet) @@ -518,4 +483,3 @@ proc applyDefaultStylesheet*(document: Document) = rule.e.style.applyProperty(rule.d) rule.e.cssvalues.add(getComputedValue(rule.d)) - document.root.generateBox(0, 0, 80, 24) diff --git a/src/html/renderer.nim b/src/html/renderer.nim new file mode 100644 index 00000000..6b63cf29 --- /dev/null +++ b/src/html/renderer.nim @@ -0,0 +1,82 @@ +import unicode + +import types/enums +import html/dom +import css/box +import css/style +import io/buffer +import utils/twtstr + +func boxesForText*(text: seq[Rune], width: int, height: int, lx: int, x: int, y: int): seq[CSSInlineBox] = + result.add(CSSInlineBox()) + var w = x + var sx = x + var sy = y + var i = 0 + while i < text.len and sy < height: + let cw = text[i].width() + if w + cw > width: + result[^1].innerEdge.x2 = sx + w + result[^1].innerEdge.y2 = sy + 1 + sx = lx + inc sy + w = 0 + + result[^2].nextpart = result[^1] + result.add(CSSInlineBox()) + result[^1].innerEdge.x1 = sx + result[^1].innerEdge.y1 = sy + + result[^1].content &= text[i] + w += cw + inc i + + result[^1].innerEdge.y1 = sy + if result.len > 1: + result[^2].nextpart = result[^1] + if w > 0: + result[^1].innerEdge.x1 = sx + result[^1].innerEdge.y1 = sy + result[^1].innerEdge.x2 = sx + w + result[^1].innerEdge.y2 = sy + 1 + +proc generateBox(elem: Element, x: int, y: int, w: int, h: int, fromx: int = x): CSSBox = + let display = elem.cssvalues.getValue(RULE_DISPLAY) + if display.t == RULE_DISPLAY: + if display.display == DISPLAY_NONE: + return nil + new(result) + result.innerEdge.x1 = x + result.innerEdge.y1 = y + + var anonBoxes = false + for child in elem.children: + let rule = child.cssvalues.getValue(RULE_DISPLAY) + if rule.t == RULE_DISPLAY and rule.display == DISPLAY_BLOCK: + anonBoxes = true + break + var lx = fromx + var rx = x + var ry = y + for child in elem.childNodes: + if child.nodeType == ELEMENT_NODE: + let elem = Element(child) + let nbox = elem.generateBox(rx, ry, w, h) + if nbox != nil: + result.innerEdge.x2 = min(max(nbox.size().w, result.innerEdge.x2), w) + result.innerEdge.y2 = min(result.innerEdge.y2 + nbox.size().h, w) + rx = x + ry += nbox.size().h + result.children.add(nbox) + elif child.nodeType == TEXT_NODE: + let text = Text(child) + let runes = text.data.toRunes() + let boxes = boxesForText(runes, w, h, lx, rx, ry) + for child in boxes: + result.children.add(child) + result.innerEdge.y2 += child.size().h + ry += child.size().h + lx = boxes[^1].innerEdge.x2 + +proc alignBoxes*(buffer: Buffer) = + buffer.rootbox = buffer.document.root.generateBox(0, 0, buffer.width, buffer.height) diff --git a/src/io/buffer.nim b/src/io/buffer.nim index 6288bf88..637fc87b 100644 --- a/src/io/buffer.nim +++ b/src/io/buffer.nim @@ -13,25 +13,9 @@ import css/box import config/config import io/term import io/lineedit +import io/cell type - Cell = object of RootObj - fgcolor*: CellColor - bgcolor*: CellColor - italic: bool - bold: bool - underline: bool - - BufferCell = object of Cell - rune*: Rune - - BufferRow = seq[BufferCell] - - DisplayCell = object of Cell - runes*: seq[Rune] - - DisplayRow = seq[DisplayCell] - DrawInstruction = object case t: DrawInstructionType of DRAW_TEXT: @@ -51,10 +35,10 @@ type Buffer* = ref BufferObj BufferObj = object title*: string - lines*: seq[BufferRow] - display*: DisplayRow - prevdisplay*: DisplayRow - statusmsg*: DisplayRow + lines*: FlexibleGrid + display*: FixedGrid + prevdisplay*: FixedGrid + statusmsg*: FixedGrid hovertext*: string width*: int height*: int @@ -75,6 +59,7 @@ type location*: Uri source*: string #TODO showsource*: bool + rootbox*: CSSBox func newBuffer*(attrs: TermAttributes): Buffer = new(result) @@ -82,9 +67,9 @@ func newBuffer*(attrs: TermAttributes): Buffer = result.height = attrs.termHeight - 1 result.attrs = attrs - result.display = newSeq[DisplayCell](result.width * result.height) - result.prevdisplay = newSeq[DisplayCell](result.width * result.height) - result.statusmsg = newSeq[DisplayCell](result.width) + result.display = newSeq[FixedCell](result.width * result.height) + result.prevdisplay = newSeq[FixedCell](result.width * result.height) + result.statusmsg = newSeq[FixedCell](result.width) func generateFullOutput*(buffer: Buffer): seq[string] = var x = 0 @@ -192,7 +177,7 @@ func numLines*(buffer: Buffer): int = buffer.lines.len func lastVisibleLine*(buffer: Buffer): int = min(buffer.fromy + buffer.height, buffer.numLines - 1) -func width(line: seq[BufferCell]): int = +func width(line: seq[FlexibleCell]): int = for c in line: result += c.rune.width() @@ -553,21 +538,11 @@ proc refreshTermAttrs*(buffer: Buffer): bool = return true return false -proc setText*(buffer: Buffer, x: int, y: int, text: seq[Rune]) = - while buffer.lines.len <= y: - buffer.lines.add(newSeq[BufferCell]()) - - while buffer.lines[y].len < x + text.len: - buffer.lines[y].add(BufferCell()) - - var i = 0 - while i < text.len: - buffer.lines[y][i].rune = text[i] - inc i +proc setText*(buffer: Buffer, x: int, y: int, text: seq[Rune]) = buffer.lines.setText(x, y, text) proc reshape*(buffer: Buffer) = - buffer.display = newSeq[DisplayCell](buffer.width * buffer.height) - buffer.statusmsg = newSeq[DisplayCell](buffer.width) + buffer.display = newSeq[FixedCell](buffer.width * buffer.height) + buffer.statusmsg = newSeq[FixedCell](buffer.width) proc clearDisplay*(buffer: Buffer) = var i = 0 @@ -620,8 +595,10 @@ proc renderPlainText*(buffer: Buffer, text: string) = proc renderDocument*(buffer: Buffer) = buffer.clearText() + if buffer.rootbox == nil: + return var stack: seq[CSSBox] - stack.add(buffer.document.root.box) + stack.add(buffer.rootbox) while stack.len > 0: let box = stack.pop() buffer.setText(box.innerEdge.x1, box.innerEdge.y1, box.content) diff --git a/src/io/cell.nim b/src/io/cell.nim new file mode 100644 index 00000000..d4a55b14 --- /dev/null +++ b/src/io/cell.nim @@ -0,0 +1,34 @@ +import unicode + +import types/color + +type + Cell* = object of RootObj + fgcolor*: CellColor + bgcolor*: CellColor + italic*: bool + bold*: bool + underline*: bool + + FlexibleCell* = object of Cell + rune*: Rune + + FlexibleGrid* = seq[seq[FlexibleCell]] + + FixedCell* = object of Cell + runes*: seq[Rune] + + FixedGrid* = seq[FixedCell] + +proc setText*(grid: var FlexibleGrid, x: int, y: int, text: seq[Rune]) = + while grid.len <= y: + grid.add(newSeq[FlexibleCell]()) + + while grid[y].len < x + text.len: + grid[y].add(FlexibleCell()) + + var i = 0 + while i < text.len: + grid[y][i].rune = text[i] + inc i + diff --git a/src/main.nim b/src/main.nim index 4ce11f79..b1345ce2 100644 --- a/src/main.nim +++ b/src/main.nim @@ -5,6 +5,7 @@ import streams import html/parser import html/dom +import html/renderer import io/buffer import io/term import config/config @@ -32,7 +33,6 @@ proc getPageUri(uri: Uri): Stream = var buffers: seq[Buffer] - proc main*() = if paramCount() != 1: eprint "Invalid parameters. Usage:\ntwt <url>" @@ -42,10 +42,11 @@ proc main*() = let buffer = newBuffer(attrs) let uri = parseUri(paramStr(1)) buffers.add(buffer) - buffer.source = getPageUri(uri).readAll() #TODO buffer.renderPlainText(getPageUri(uri).readAll()) + buffer.source = getPageUri(uri).readAll() #TODO get rid of this buffer.document = parseHtml(newStringStream(buffer.source)) buffer.setLocation(uri) buffer.document.applyDefaultStylesheet() + buffer.alignBoxes() buffer.renderDocument() var lastUri = uri while displayPage(attrs, buffer): |