diff options
-rw-r--r-- | res/ua.css | 20 | ||||
-rw-r--r-- | src/css/selector.nim | 33 | ||||
-rw-r--r-- | src/css/style.nim | 36 | ||||
-rw-r--r-- | src/css/values.nim | 42 | ||||
-rw-r--r-- | src/html/dom.nim | 96 | ||||
-rw-r--r-- | src/html/parser.nim | 42 | ||||
-rw-r--r-- | src/layout/engine.nim | 32 | ||||
-rw-r--r-- | src/types/enums.nim | 9 | ||||
-rw-r--r-- | src/utils/twtstr.nim | 103 |
9 files changed, 341 insertions, 72 deletions
diff --git a/res/ua.css b/res/ua.css index 3e9d2a08..c44d783d 100644 --- a/res/ua.css +++ b/res/ua.css @@ -16,6 +16,10 @@ textarea, tt, var, font, iframe, u, s, strike, frame, input, img { display: inline-block; } +ol, ul { + margin-left: 3ch; +} + table { display: table; } @@ -100,3 +104,19 @@ sup::before { sub::before { content: '~'; } + +ol { + list-style-type: decimal; +} + +ul { + list-style-type: disc; +} + +:is(ol, ul, menu, dir) ul { + list-style-type: circle; +} + +:is(ol, ul, menu, dir) :is(ol, ul, menu, dir) ul { + list-style-type: square; +} diff --git a/src/css/selector.nim b/src/css/selector.nim index 7cfbf328..13131f80 100644 --- a/src/css/selector.nim +++ b/src/css/selector.nim @@ -48,7 +48,7 @@ type elem*: string of FUNC_SELECTOR: name*: string - fsels*: SelectorList + fsels*: seq[SelectorList] of COMBINATOR_SELECTOR: ct*: CombinatorType csels*: seq[SelectorList] @@ -77,13 +77,14 @@ func getSpecificity(sel: Selector): int = case sel.name of "is": var best = 0 - for child in sel.fsels.sels: + for child in sel.fsels: let s = getSpecificity(child) if s > best: best = s result += best of "not": - result += getSpecificity(sel.fsels) + for child in sel.fsels: + result += getSpecificity(child) else: discard of UNIVERSAL_SELECTOR: discard @@ -129,6 +130,12 @@ proc addSelector(state: var SelectorParser, sel: Selector) = else: state.selectors[^1].add(sel) +proc getLastSel(state: SelectorParser): Selector = + if state.combinator != nil: + return state.combinator.csels[^1].sels[^1] + else: + return state.selectors[^1].sels[^1] + proc addSelectorList(state: var SelectorParser) = if state.combinator != nil: state.selectors[^1].add(state.combinator) @@ -227,22 +234,24 @@ proc parseSelectorSimpleBlock(state: var SelectorParser, cssblock: CSSSimpleBloc state.query = QUERY_DELIM state.addSelector(Selector(t: ATTR_SELECTOR, attr: $csstoken.value, rel: ' ')) of QUERY_VALUE: - state.selectors[^1].sels[^1].value = $csstoken.value + state.getLastSel().value = $csstoken.value break else: discard of CSS_STRING_TOKEN: case state.query of QUERY_VALUE: - state.selectors[^1].sels[^1].value = $csstoken.value + state.getLastSel().value = $csstoken.value break else: discard of CSS_DELIM_TOKEN: case csstoken.rvalue of Rune('~'), Rune('|'), Rune('^'), Rune('$'), Rune('*'): if state.query == QUERY_DELIM: - state.selectors[^1].sels[^1].rel = char(csstoken.rvalue) + state.getLastSel().rel = char(csstoken.rvalue) of Rune('='): if state.query == QUERY_DELIM: + if state.getLastSel().rel == ' ': + state.getLastSel().rel = '=' state.query = QUERY_VALUE else: discard else: discard @@ -257,9 +266,13 @@ proc parseSelectorFunction(state: var SelectorParser, cssfunction: CSSFunction) state.query = QUERY_TYPE else: return var fun = Selector(t: FUNC_SELECTOR, name: $cssfunction.name) - fun.fsels = SelectorList(parent: state.selectors[^1]) state.addSelector(fun) - state.selectors[^1] = fun.fsels + + let osels = state.selectors + let ocomb = state.combinator + state.combinator = nil + state.selectors = newSeq[SelectorList]() + state.addSelectorList() for cval in cssfunction.value: if cval of CSSToken: state.parseSelectorToken(CSSToken(cval)) @@ -267,7 +280,9 @@ proc parseSelectorFunction(state: var SelectorParser, cssfunction: CSSFunction) state.parseSelectorSimpleBlock(CSSSimpleBlock(cval)) elif cval of CSSFunction: state.parseSelectorFunction(CSSFunction(cval)) - state.selectors[^1] = fun.fsels.parent + fun.fsels = state.selectors + state.selectors = osels + state.combinator = ocomb func parseSelectors*(cvals: seq[CSSComponentValue]): seq[SelectorList] = var state = SelectorParser() diff --git a/src/css/style.nim b/src/css/style.nim index e2bf2347..efffb8c6 100644 --- a/src/css/style.nim +++ b/src/css/style.nim @@ -53,6 +53,22 @@ func pseudoElemSelectorMatches(elem: Element, sel: Selector): SelectResult = func selectorsMatch(elem: Element, selectors: SelectorList): SelectResult +func funcSelectorMatches(elem: Element, sel: Selector): SelectResult = + case sel.name + of "not": + for slist in sel.fsels: + let res = elem.selectorsMatch(slist) + if res.success: + return selectres(false) + return selectres(true) + of "is", "where": + for slist in sel.fsels: + let res = elem.selectorsMatch(slist) + if not res.success: + return selectres(false) + return selectres(true) + else: discard + func selectorMatches(elem: Element, sel: Selector): SelectResult = case sel.t of TYPE_SELECTOR: @@ -70,7 +86,7 @@ func selectorMatches(elem: Element, sel: Selector): SelectResult = of UNIVERSAL_SELECTOR: return selectres(true) of FUNC_SELECTOR: - return selectres(false) + return funcSelectorMatches(elem, sel) of COMBINATOR_SELECTOR: #combinator without at least two members makes no sense assert sel.csels.len > 1 @@ -110,7 +126,6 @@ func selectorMatches(elem: Element, sel: Selector): SelectResult = return selectres(false) if not res.success: - eprint "fail", e.tagType return selectres(false) dec i e = e.previousElementSibling @@ -157,12 +172,7 @@ func selectElems(document: Document, sel: Selector): seq[Element] = of PSELEM_SELECTOR: return document.all_elements.filter((elem) => pseudoElemSelectorMatches(elem, sel)) of FUNC_SELECTOR: - case sel.name - of "not": - return document.all_elements.filter((elem) => not selectorsMatch(elem, sel.fsels).psuccess) - of "is", "where": - return document.all_elements.filter((elem) => selectorsMatch(elem, sel.fsels).psuccess) - return newSeq[Element]() + return document.all_elements.filter((elem) => selectorMatches(elem, sel)) of COMBINATOR_SELECTOR: return document.all_elements.filter((elem) => selectorMatches(elem, sel)) @@ -173,15 +183,7 @@ func selectElems(document: Document, selectors: SelectorList): seq[Element] = var i = 1 while i < sellist.len: - if sellist[i].t == FUNC_SELECTOR: - case sellist[i].name - of "not": - result = result.filter((elem) => not selectorsMatch(elem, sellist[i].fsels).psuccess) - of "is", "where": - result = result.filter((elem) => selectorsMatch(elem, sellist[i].fsels).psuccess) - else: discard - else: - result = result.filter((elem) => selectorMatches(elem, sellist[i]).psuccess) + result = result.filter((elem) => selectorMatches(elem, sellist[i]).psuccess) inc i proc querySelector*(document: Document, q: string): seq[Element] = diff --git a/src/css/values.nim b/src/css/values.nim index 7d5d5bc5..b55869f7 100644 --- a/src/css/values.nim +++ b/src/css/values.nim @@ -39,6 +39,8 @@ type textdecoration*: CSSTextDecoration of VALUE_WORD_BREAK: wordbreak*: CSSWordBreak + of VALUE_LIST_STYLE_TYPE: + liststyletype*: CSSListStyleType of VALUE_NONE: discard CSSComputedValues* = ref array[low(CSSPropertyType)..high(CSSPropertyType), CSSComputedValue] @@ -66,6 +68,7 @@ const PropertyNames = { "word-break": PROPERTY_WORD_BREAK, "width": PROPERTY_WIDTH, "height": PROPERTY_HEIGHT, + "list-style-type": PROPERTY_LIST_STYLE_TYPE, }.toTable() const ValueTypes = [ @@ -86,11 +89,13 @@ const ValueTypes = [ PROPERTY_WORD_BREAK: VALUE_WORD_BREAK, PROPERTY_WIDTH: VALUE_LENGTH, PROPERTY_HEIGHT: VALUE_LENGTH, + PROPERTY_LIST_STYLE_TYPE: VALUE_LIST_STYLE_TYPE, ] const InheritedProperties = { PROPERTY_COLOR, PROPERTY_FONT_STYLE, PROPERTY_WHITE_SPACE, - PROPERTY_FONT_WEIGHT, PROPERTY_TEXT_DECORATION, PROPERTY_WORD_BREAK + PROPERTY_FONT_WEIGHT, PROPERTY_TEXT_DECORATION, PROPERTY_WORD_BREAK, + PROPERTY_LIST_STYLE_TYPE } func getPropInheritedArray(): array[low(CSSPropertyType)..high(CSSPropertyType), bool] = @@ -123,6 +128,15 @@ func cells*(l: CSSLength): int = #TODO return int(l.num / 8) +func listMarker*(t: CSSListStyleType, i: int): string = + case t + of LIST_STYLE_TYPE_NONE: return "" + of LIST_STYLE_TYPE_DISC: return "* " + of LIST_STYLE_TYPE_CIRCLE: return "o " + of LIST_STYLE_TYPE_SQUARE: return "O " + of LIST_STYLE_TYPE_DECIMAL: return $i & ". " + of LIST_STYLE_TYPE_JAPANESE_INFORMAL: return japaneseNumber(i) & "、" + func r(c: CSSColor): int = return c.rgba.r @@ -436,8 +450,8 @@ func cssDisplay(d: CSSDeclaration): CSSDisplay = case $tok.value of "block": return DISPLAY_BLOCK of "inline": return DISPLAY_INLINE + of "list-item": return DISPLAY_LIST_ITEM # of "inline-block": return DISPLAY_INLINE_BLOCK - # of "list-item": return DISPLAY_LIST_ITEM # of "table": return DISPLAY_TABLE # of "table-row-group": return DISPLAY_TABLE_ROW_GROUP # of "table-header-group": return DISPLAY_TABLE_HEADER_GROUP @@ -511,6 +525,19 @@ func cssWordBreak(d: CSSDeclaration): CSSWordBreak = of "keep-all": return WORD_BREAK_KEEP_ALL raise newException(CSSValueError, "Invalid text decoration") +func cssListStyleType(d: CSSDeclaration): CSSListStyleType = + if isToken(d): + let tok = getToken(d) + if tok.tokenType == CSS_IDENT_TOKEN: + case $tok.value + of "none": return LIST_STYLE_TYPE_NONE + of "disc": return LIST_STYLE_TYPE_DISC + of "circle": return LIST_STYLE_TYPE_CIRCLE + of "square": return LIST_STYLE_TYPE_SQUARE + of "decimal": return LIST_STYLE_TYPE_DECIMAL + of "japanese-informal": return LIST_STYLE_TYPE_JAPANESE_INFORMAL + raise newException(CSSValueError, "Invalid list style") + func getSpecifiedValue*(d: CSSDeclaration): CSSSpecifiedValue = let name = $d.name let ptype = propertyType(name) @@ -529,6 +556,7 @@ func getSpecifiedValue*(d: CSSDeclaration): CSSSpecifiedValue = result.integer = cssFontWeight(d) of VALUE_TEXT_DECORATION: result.textdecoration = cssTextDecoration(d) of VALUE_WORD_BREAK: result.wordbreak = cssWordBreak(d) + of VALUE_LIST_STYLE_TYPE: result.liststyletype = cssListStyleType(d) of VALUE_NONE: discard except CSSValueError: result.globalValue = VALUE_UNSET @@ -611,6 +639,8 @@ func getComputedValue*(prop: CSSSpecifiedValue, current: CSSComputedValues): CSS return CSSComputedValue(t: prop.t, v: VALUE_TEXT_DECORATION, textdecoration: prop.textdecoration) of VALUE_WORD_BREAK: return CSSComputedValue(t: prop.t, v: VALUE_WORD_BREAK, wordbreak: prop.wordbreak) + of VALUE_LIST_STYLE_TYPE: + return CSSComputedValue(t: prop.t, v: VALUE_LIST_STYLE_TYPE, liststyletype: prop.liststyletype) of VALUE_NONE: return CSSComputedValue(t: prop.t, v: VALUE_NONE) func getComputedValue*(d: CSSDeclaration, current: CSSComputedValues): CSSComputedValue = @@ -629,3 +659,11 @@ proc inheritProperties*(vals: var CSSComputedValues, parent: CSSComputedValues) vals[prop] = getDefault(prop) if inherited(prop) and parent[prop] != nil and vals[prop] == getDefault(prop): vals[prop] = parent[prop] + +func inheritProperties*(parent: CSSComputedValues): CSSComputedValues = + new(result) + for prop in low(CSSPropertyType)..high(CSSPropertyType): + if inherited(prop) and parent[prop] != nil: + result[prop] = parent[prop] + else: + result[prop] = getDefault(prop) diff --git a/src/html/dom.nim b/src/html/dom.nim index f2c98bd0..0c7d385a 100644 --- a/src/html/dom.nim +++ b/src/html/dom.nim @@ -1,5 +1,7 @@ import uri import tables +import options +import strutils import css/values import types/enums @@ -70,40 +72,46 @@ type cssapplied*: bool rendered*: bool - HTMLElement* = ref HTMLElementObj - HTMLElementObj = object of ElementObj + HTMLElement* = ref object of ElementObj - HTMLInputElement* = ref HTMLInputElementObj - HTMLInputElementObj = object of HTMLElementObj + HTMLInputElement* = ref object of HTMLElement itype*: InputType autofocus*: bool required*: bool value*: string size*: int - HTMLAnchorElement* = ref HTMLAnchorElementObj - HTMLAnchorElementObj = object of HTMLElementObj + HTMLAnchorElement* = ref object of HTMLElement href*: string - HTMLSelectElement* = ref HTMLSelectElementObj - HTMLSelectElementObj = object of HTMLElementObj + HTMLSelectElement* = ref object of HTMLElement name*: string value*: string valueSet*: bool - HTMLSpanElement* = ref HTMLSpanElementObj - HTMLSpanElementObj = object of HTMLElementObj + HTMLSpanElement* = ref object of HTMLElement - HTMLOptionElement* = ref HTMLOptionElementObj - HTMLOptionElementObj = object of HTMLElementObj + HTMLOptionElement* = ref object of HTMLElement value*: string - HTMLHeadingElement* = ref HTMLHeadingElementObj - HTMLHeadingElementObj = object of HTMLElementObj + HTMLHeadingElement* = ref object of HTMLElement rank*: uint16 - HTMLBRElement* = ref HTMLBRElementObj - HTMLBRElementObj = object of HTMLElementObj + HTMLBRElement* = ref object of HTMLElement + + HTMLMenuElement* = ref object of HTMLElement + ordinalcounter*: int + + HTMLUListElement* = ref object of HTMLElement + ordinalcounter*: int + + HTMLOListElement* = ref object of HTMLElement + start*: Option[int] + ordinalcounter*: int + + HTMLLIElement* = ref object of HTMLElement + value*: Option[int] + ordinalvalue*: int func firstChild(node: Node): Node = if node.childNodes.len == 0: @@ -191,6 +199,49 @@ func toInputType*(str: string): InputType = of "week": INPUT_WEEK else: INPUT_UNKNOWN +func ancestor(node: Node, tagTypes: set[TagType]): Element = + var elem = node.parentElement + while elem != nil: + if elem.tagType in tagTypes: + return elem + + elem = elem.parentElement + return nil + +func attr*(element: Element, s: string): string = + return element.attributes.getOrDefault(s, "") + +func attri*(element: Element, s: string): Option[int] = + let a = element.attr(s) + try: + return some(parseInt(a)) + except ValueError: + return none(int) + +proc applyOrdinal*(elem: HTMLLIElement) = + let val = elem.attri("value") + if val.issome: + elem.ordinalvalue = val.get + else: + let owner = elem.ancestor({TAG_OL, TAG_UL, TAG_MENU}) + if owner == nil: + elem.ordinalvalue = 1 + else: + case owner.tagType + of TAG_OL: + let ol = HTMLOListElement(owner) + elem.ordinalvalue = ol.ordinalcounter + inc ol.ordinalcounter + of TAG_UL: + let ul = HTMLUListElement(owner) + elem.ordinalvalue = ul.ordinalcounter + inc ul.ordinalcounter + of TAG_MENU: + let menu = HTMLMenuElement(owner) + elem.ordinalvalue = menu.ordinalcounter + inc menu.ordinalcounter + else: discard + func newText*(): Text = new(result) result.nodeType = TEXT_NODE @@ -215,6 +266,16 @@ func newHtmlElement*(tagType: TagType): HTMLElement = result = new(HTMLBRElement) of TAG_SPAN: result = new(HTMLSpanElement) + of TAG_OL: + result = new(HTMLOListElement) + of TAG_UL: + result = new(HTMLUListElement) + HTMLUListElement(result).ordinalcounter = 1 + of TAG_MENU: + result = new(HTMLMenuElement) + HTMLMenuElement(result).ordinalcounter = 1 + of TAG_LI: + result = new(HTMLLIElement) else: result = new(HTMLElement) @@ -235,6 +296,3 @@ func newAttr*(parent: Element, key: string, value: string): Attr = result.ownerElement = parent result.name = key result.value = value - -func attr*(element: Element, s: string): string = - return element.attributes.getOrDefault(s, "") diff --git a/src/html/parser.nim b/src/html/parser.nim index a3a6885d..70b749a6 100644 --- a/src/html/parser.nim +++ b/src/html/parser.nim @@ -3,6 +3,7 @@ import unicode import strutils import tables import json +import options import types/enums import types/tagtypes @@ -250,6 +251,11 @@ proc processDocumentStartElement(state: var HTMLParseState, element: Element, ta HTMLAnchorElement(element).href = element.attr("href") of TAG_OPTION: HTMLOptionElement(element).value = element.attr("href") + of TAG_OL: + HTMLOListElement(element).start = element.attri("start") + HTMLOListElement(element).ordinalcounter = HTMLOListElement(element).start.get(1) + of TAG_LI: + HTMLLIElement(element).value = element.attri("value") of TAG_HTML: add = false of TAG_HEAD: @@ -261,29 +267,27 @@ proc processDocumentStartElement(state: var HTMLParseState, element: Element, ta add = false of TAG_PRE: state.skip_lf = true + of TAG_H1: + HTMLHeadingElement(element).rank = 1 + of TAG_H2: + HTMLHeadingElement(element).rank = 2 + of TAG_H3: + HTMLHeadingElement(element).rank = 3 + of TAG_H4: + HTMLHeadingElement(element).rank = 4 + of TAG_H5: + HTMLHeadingElement(element).rank = 5 + of TAG_H6: + HTMLHeadingElement(element).rank = 6 else: discard if not state.in_body and not (element.tagType in HeadTagTypes): processDocumentBody(state) if state.elementNode.nodeType == ELEMENT_NODE: - case element.tagType - of SelfClosingTagTypes: + if element.tagType in SelfClosingTagTypes: if state.elementNode.tagType == element.tagType: processDocumentEndNode(state) - of TAG_H1: - HTMLHeadingElement(element).rank = 1 - of TAG_H2: - HTMLHeadingElement(element).rank = 2 - of TAG_H3: - HTMLHeadingElement(element).rank = 3 - of TAG_H4: - HTMLHeadingElement(element).rank = 4 - of TAG_H5: - HTMLHeadingElement(element).rank = 5 - of TAG_H6: - HTMLHeadingElement(element).rank = 6 - else: discard if state.elementNode.tagType == TAG_P and element.tagType in PClosingTagTypes: processDocumentEndNode(state) @@ -292,8 +296,12 @@ proc processDocumentStartElement(state: var HTMLParseState, element: Element, ta processDocumentAddNode(state, element) state.elementNode = element - if element.tagType in VoidTagTypes: - processDocumentEndNode(state) + case element.tagType + of VoidTagTypes: + processDocumentEndNode(state) + of TAG_LI: + HTMLLIElement(element).applyOrdinal() #needs to know parent + else: discard proc processDocumentEndElement(state: var HTMLParseState, tag: DOMParsedTag) = if tag.tagid in VoidTagTypes: diff --git a/src/layout/engine.nim b/src/layout/engine.nim index 614fd332..d9987de2 100644 --- a/src/layout/engine.nim +++ b/src/layout/engine.nim @@ -292,7 +292,8 @@ func isBlock(node: Node): bool = if node.nodeType != ELEMENT_NODE: return false let elem = Element(node) - return elem.cssvalues[PROPERTY_DISPLAY].display == DISPLAY_BLOCK + return elem.cssvalues[PROPERTY_DISPLAY].display == DISPLAY_BLOCK or + elem.cssvalues[PROPERTY_DISPLAY].display == DISPLAY_LIST_ITEM func isInline(node: Node): bool = if node.nodeType == TEXT_NODE: @@ -311,6 +312,8 @@ proc processComputedValueBox(state: var LayoutState, parent: CSSBox, values: CSS #CSSBlockBox(result).tag = $elem.tagType of DISPLAY_INLINE: result = newInlineBox(parent, values) + of DISPLAY_LIST_ITEM: + result = state.newBlockBox(parent, values) of DISPLAY_NONE: return nil else: @@ -351,8 +354,7 @@ proc processAnonComputedValues(state: var LayoutState, parent: CSSBox, c: CSSCom if parent.bcontext.has_blocks: if c[PROPERTY_DISPLAY].display == DISPLAY_INLINE: if parent.bcontext.anon_block == nil: - var cssvals: CSSComputedValues - cssvals.inheritProperties(parent.cssvalues) + let cssvals = parent.cssvalues.inheritProperties() parent.bcontext.anon_block = state.newBlockBox(parent, cssvals) state.add(parent.bcontext.anon_block, state.processComputedValueBox(parent.bcontext.anon_block, c)) return true @@ -376,13 +378,17 @@ proc processAnonBlock(state: var LayoutState, parent: CSSBox, c: Node): bool = return false func needsAnonymousBlockBoxes(node: Node): bool = + if not node.isBlock(): + return false if node.nodeType == ELEMENT_NODE: let elem = Element(node) if elem.cssvalues_before != nil: - if elem.cssvalues_before[PROPERTY_DISPLAY].display == DISPLAY_BLOCK: + if elem.cssvalues_before[PROPERTY_DISPLAY].display == DISPLAY_BLOCK or + elem.cssvalues_before[PROPERTY_DISPLAY].display == DISPLAY_LIST_ITEM: return true if elem.cssvalues_after != nil: - if elem.cssvalues_after[PROPERTY_DISPLAY].display == DISPLAY_BLOCK: + if elem.cssvalues_after[PROPERTY_DISPLAY].display == DISPLAY_BLOCK or + elem.cssvalues_after[PROPERTY_DISPLAY].display == DISPLAY_LIST_ITEM: return true for c in node.childNodes: @@ -443,6 +449,20 @@ proc processAfterPseudoElem(state: var LayoutState, parent: CSSBox, node: Node) if box != parent.bcontext.anon_block: state.add(parent, box) +proc processMarker(state: var LayoutState, parent: CSSBox, node: Node) = + if node.nodeType == ELEMENT_NODE: + let elem = Element(node) + if elem.cssvalues[PROPERTY_DISPLAY].display == DISPLAY_LIST_ITEM: + var ordinalvalue = 1 + if elem.tagType == TAG_LI: + ordinalvalue = HTMLLIElement(elem).ordinalvalue + + let text = elem.cssvalues[PROPERTY_LIST_STYLE_TYPE].liststyletype.listMarker(ordinalvalue) + let tlen = text.width() + parent.icontext.fromx -= tlen + let marker = state.processInlineBox(parent, text) + state.add(parent, marker) + proc processNodes(state: var LayoutState, parent: CSSBox, node: Node) = state.nodes.add(node) @@ -450,6 +470,8 @@ proc processNodes(state: var LayoutState, parent: CSSBox, node: Node) = state.processBeforePseudoElem(parent, node) + state.processMarker(parent, node) + for c in node.childNodes: let isanon = state.processAnonBlock(parent, c) if not isanon: diff --git a/src/types/enums.nim b/src/types/enums.nim index aeb53567..028b7557 100644 --- a/src/types/enums.nim +++ b/src/types/enums.nim @@ -61,12 +61,12 @@ type PROPERTY_MARGIN_BOTTOM, PROPERTY_FONT_STYLE, PROPERTY_DISPLAY, PROPERTY_CONTENT, PROPERTY_WHITE_SPACE, PROPERTY_FONT_WEIGHT, PROPERTY_TEXT_DECORATION, PROPERTY_WORD_BREAK, PROPERTY_WIDTH, - PROPERTY_HEIGHT + PROPERTY_HEIGHT, PROPERTY_LIST_STYLE_TYPE CSSValueType* = enum VALUE_NONE, VALUE_LENGTH, VALUE_COLOR, VALUE_CONTENT, VALUE_DISPLAY, VALUE_FONT_STYLE, VALUE_WHITE_SPACE, VALUE_INTEGER, VALUE_TEXT_DECORATION, - VALUE_WORD_BREAK + VALUE_WORD_BREAK, VALUE_LIST_STYLE_TYPE CSSGlobalValueType* = enum VALUE_NOGLOBAL, VALUE_INITIAL, VALUE_INHERIT, VALUE_REVERT, VALUE_UNSET @@ -95,3 +95,8 @@ type CSSWordBreak* = enum WORD_BREAK_NORMAL, WORD_BREAK_BREAK_ALL, WORD_BREAK_KEEP_ALL + + CSSListStyleType* = enum + LIST_STYLE_TYPE_NONE, LIST_STYLE_TYPE_DISC, LIST_STYLE_TYPE_CIRCLE, + LIST_STYLE_TYPE_SQUARE, LIST_STYLE_TYPE_DECIMAL, + LIST_STYLE_TYPE_JAPANESE_INFORMAL diff --git a/src/utils/twtstr.nim b/src/utils/twtstr.nim index 5bd25247..a75c936f 100644 --- a/src/utils/twtstr.nim +++ b/src/utils/twtstr.nim @@ -5,6 +5,7 @@ import tables import json import os import math +import sugar when defined(posix): import posix @@ -189,6 +190,106 @@ func skipBlanks*(buf: string, at: int): int = while result < buf.len and buf[result].isWhitespace(): inc result +#TODO +func japaneseNumber*(i: int): string = + if i == 0: + return "〇" + var n = i + if i < 0: + result &= "ス" + n *= -1 + + let o = n + + var ss: seq[string] + var d = 0 + var mark = false + var res = false + while n > 0: + let m = n mod 10 + + if m != 0: + case d + of 1: ss.add("十") + of 2: ss.add("百") + of 3: ss.add("千") + of 4: + ss.add("万") + ss.add("一") + of 5: + ss.add("万") + ss.add("十") + of 6: + ss.add("万") + ss.add("百") + of 7: + ss.add("万") + ss.add("千") + ss.add("一") + of 8: + ss.add("億") + ss.add("一") + of 9: + ss.add("億") + ss.add("十") + else: discard + case m + of 0: + inc d + n = n div 10 + mark = true + of 1: + if o == n: + ss.add("一") + of 2: ss.add("二") + of 3: ss.add("三") + of 4: ss.add("四") + of 5: ss.add("五") + of 6: ss.add("六") + of 7: ss.add("七") + of 8: ss.add("八") + of 9: ss.add("九") + else: discard + n -= m + + n = ss.len - 1 + while n >= 0: + result &= ss[n] + dec n + +func parseInt32*(s: string): int = + var sign = 1 + var t = 1 + var integer: int = 0 + var e: int = 0 + + var i = 0 + if i < s.len and s[i] == '-': + sign = -1 + inc i + elif i < s.len and s[i] == '+': + inc i + + while i < s.len and isDigit(s[i]): + integer *= 10 + integer += decValue(s[i]) + inc i + + if i < s.len and (s[i] == 'e' or s[i] == 'E'): + inc i + if i < s.len and s[i] == '-': + t = -1 + inc i + elif i < s.len and s[i] == '+': + inc i + + while i < s.len and isDigit(s[i]): + e *= 10 + e += decValue(s[i]) + inc i + + return sign * integer * 10 ^ (t * e) + func parseInt64*(s: string): int64 = var sign = 1 var t = 1 @@ -220,7 +321,7 @@ func parseInt64*(s: string): int64 = e += decValue(s[i]) inc i - return sign * integer * 10 ^ t * e + return sign * integer * 10 ^ (t * e) func parseFloat64*(s: string): float64 = var sign = 1 |