about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2021-11-12 16:55:53 +0100
committerbptato <nincsnevem662@gmail.com>2021-11-12 16:55:53 +0100
commit7108754641cefb3f01af8e29aae11695d94e980c (patch)
treec191a33745da13d31131fa8186bcfbe58ff69488
parentfcd3a5b204e15fdfc739fd04975977d288e892e0 (diff)
downloadchawan-7108754641cefb3f01af8e29aae11695d94e980c.tar.gz
Colors, italic, bold, read from pipe
-rw-r--r--makefile2
-rw-r--r--res/default.css6
-rw-r--r--src/css/style.nim36
-rw-r--r--src/html/dom.nim30
-rw-r--r--src/html/parser.nim11
-rw-r--r--src/io/buffer.nim48
-rw-r--r--src/layout/box.nim5
-rw-r--r--src/layout/layout.nim25
-rw-r--r--src/main.nim37
-rw-r--r--src/types/enums.nim22
-rw-r--r--src/types/tagtypes.nim21
-rw-r--r--src/utils/eprint.nim36
12 files changed, 203 insertions, 76 deletions
diff --git a/makefile b/makefile
index 8ee91b18..456e9e0d 100644
--- a/makefile
+++ b/makefile
@@ -5,7 +5,7 @@ FILES = src/main.nim
 debug:
 	$(NIMC) $(FLAGS) $(FILES)
 release:
-	$(NIMC) $(FLAGS) -d:release -d:strip -d:lto $(FILES)
+	$(NIMC) $(FLAGS) -d:release -d:strip -d:ssl -d:lto $(FILES)
 install:
 	cp twt /usr/local/bin/
 clean:
diff --git a/res/default.css b/res/default.css
index c0a62f90..113b7ba5 100644
--- a/res/default.css
+++ b/res/default.css
@@ -14,10 +14,14 @@ pre {
 	white-space: pre;
 }
 
+a {
+	color: yellow;
+}
+
 a, abbr, b, bdo, button, cite, code, del, dfn, em, font, i, img, ins,
 iframe, kbd, label, map, object, q, samp, select, small, span, strong
 {
-	display: inline
+	display: inline;
 }
 
 sub, sup, textarea, tt, var, font, iframe, u, s, strike, frame, input, img {
diff --git a/src/css/style.nim b/src/css/style.nim
index 9db9813e..88a5d008 100644
--- a/src/css/style.nim
+++ b/src/css/style.nim
@@ -5,6 +5,7 @@ import tables
 import utils/twtstr
 import types/enums
 import css/parser
+import types/color
 
 type
   CSSLength* = object
@@ -31,6 +32,8 @@ type
       content*: seq[Rune]
     of VALUE_WHITESPACE:
       whitespace*: WhitespaceType
+    of VALUE_INTEGER:
+      integer*: int
     of VALUE_NONE: discard
 
   CSSComputedValues* = array[low(CSSRuleType)..high(CSSRuleType), CSSComputedValue]
@@ -51,6 +54,7 @@ const ValueTypes = {
   RULE_DISPLAY: VALUE_DISPLAY,
   RULE_CONTENT: VALUE_CONTENT,
   RULE_WHITESPACE: VALUE_WHITESPACE,
+  RULE_FONT_WEIGHT: VALUE_INTEGER,
 }.toTable()
 
 func getValueType*(rule: CSSRuleType): CSSValueType =
@@ -133,7 +137,6 @@ func cssColor*(d: CSSDeclaration): CSSColor =
           return defaultColor
       of CSS_IDENT_TOKEN:
         let s = tok.value
-        eprint "ident", s
         if $s in colors:
           return colors[$s]
         else:
@@ -158,11 +161,9 @@ func cssColor*(d: CSSDeclaration): CSSColor =
         return (uint8(r), uint8(g), uint8(b), 0x00u8)
       of "rgba":
         if f.value.len != 4:
-          eprint "too few args"
           return defaultColor
         for c in f.value:
           if c != CSS_NUMBER_TOKEN:
-            eprint "not number"
             return defaultColor
         let r = CSSToken(f.value[0]).nvalue
         let g = CSSToken(f.value[1]).nvalue
@@ -170,11 +171,15 @@ func cssColor*(d: CSSDeclaration): CSSColor =
         let a = CSSToken(f.value[3]).nvalue
         return (uint8(r), uint8(g), uint8(b), uint8(a))
       else:
-        eprint "not rgba"
         return defaultColor
 
   return defaultColor
 
+func cellColor*(color: CSSColor): CellColor =
+  #TODO better would be to store color names and return term colors on demand
+  #option)
+  return CellColor(rgb: true, rgbcolor: (r: color.r, g: color.g, b: color.b))
+
 func cssLength(d: CSSDeclaration): CSSLength =
   if d.value.len > 0 and d.value[0] of CSSToken:
     let tok = CSSToken(d.value[0])
@@ -253,6 +258,23 @@ func cssWhiteSpace(d: CSSDeclaration): WhitespaceType =
       else: return WHITESPACE_NORMAL
   return WHITESPACE_NORMAL
 
+#TODO
+func cssFontWeight(d: CSSDeclaration): int =
+  if isToken(d):
+    let tok = getToken(d)
+    if tok.tokenType == CSS_IDENT_TOKEN:
+      case $tok.value
+      of "normal": return 400
+      of "bold": return 700
+      of "lighter": return 400
+      of "bolder": return 700
+      else: return 400
+
+    elif tok.tokenType == CSS_NUMBER_TOKEN:
+      return int(tok.nvalue)
+
+  return 400
+
 func getSpecifiedValue*(d: CSSDeclaration): CSSSpecifiedValue =
   case $d.name
   of "color":
@@ -268,13 +290,15 @@ func getSpecifiedValue*(d: CSSDeclaration): CSSSpecifiedValue =
   of "margin-right":
     return CSSSpecifiedValue(t: RULE_MARGIN_RIGHT, v: VALUE_LENGTH, length: cssLength(d))
   of "font-style":
-    return CSSSpecifiedValue(t: RULE_FONT_STYLE, v: VALUE_FONT_STYLE, fontStyle: cssFontStyle(d))
+    return CSSSpecifiedValue(t: RULE_FONT_STYLE, v: VALUE_FONT_STYLE, fontstyle: cssFontStyle(d))
   of "display":
     return CSSSpecifiedValue(t: RULE_DISPLAY, v: VALUE_DISPLAY, display: cssDisplay(d))
   of "content":
     return CSSSpecifiedValue(t: RULE_CONTENT, v: VALUE_CONTENT, content: cssString(d))
   of "white-space":
     return CSSSpecifiedValue(t: RULE_WHITESPACE, v: VALUE_WHITESPACE, whitespace: cssWhiteSpace(d))
+  of "font-weight":
+    return CSSSpecifiedValue(t: RULE_FONT_WEIGHT, v: VALUE_INTEGER, integer: cssFontWeight(d))
 
 func getInitialColor*(t: CSSRuleType): CSSColor =
   case t
@@ -312,6 +336,8 @@ func getComputedValue*(rule: CSSSpecifiedValue, parent: CSSValues): CSSComputedV
     return CSSComputedValue(t: rule.t, v: VALUE_CONTENT, content: rule.content)
   of VALUE_WHITESPACE:
     return CSSComputedValue(t: rule.t, v: VALUE_WHITESPACE, whitespace: rule.whitespace)
+  of VALUE_INTEGER:
+    return CSSComputedValue(t: rule.t, v: VALUE_INTEGER, integer: rule.integer)
   of VALUE_NONE: return CSSComputedValue(t: rule.t, v: VALUE_NONE)
 
 func getComputedValue*(d: CSSDeclaration, parent: CSSValues): CSSComputedValue =
diff --git a/src/html/dom.nim b/src/html/dom.nim
index 92d8cf1b..4e296b0c 100644
--- a/src/html/dom.nim
+++ b/src/html/dom.nim
@@ -443,16 +443,33 @@ proc applyRules*(document: Document, rules: CSSStylesheet): seq[tuple[e:Element,
             else:
               elem.applyProperty(decl, pseudo)
 
-    for child in elem.children:
+    var i = elem.children.len - 1
+    while i >= 0:
+      let child = elem.children[i]
       stack.add(child)
+      dec i
 
 proc applyAuthorRules*(document: Document): seq[tuple[e:Element,d:CSSDeclaration]] =
   var stack: seq[Element]
   var embedded_rules: seq[ParsedStylesheet]
 
-  stack.add(document.root)
+  stack.add(document.head)
+  var rules_head = ""
+
+  for child in document.head.children:
+    if child.tagType == TAG_STYLE:
+      for ct in child.childNodes:
+        if ct.nodeType == TEXT_NODE:
+          rules_head &= Text(ct).data
+
+  
+  stack.setLen(0)
+
+  stack.add(document.body)
 
-  #let parsed = rules.value.map((x) => (sels: parseSelectors(x.prelude), oblock: x.oblock))
+  if rules_head.len > 0:
+    let parsed = parseCSS(newStringStream(rules_head)).value.map((x) => (sels: parseSelectors(x.prelude), oblock: x.oblock))
+    embedded_rules.add(parsed)
 
   while stack.len > 0:
     let elem = stack.pop()
@@ -481,8 +498,11 @@ proc applyAuthorRules*(document: Document): seq[tuple[e:Element,d:CSSDeclaration
             else:
               elem.applyProperty(decl, pseudo)
 
-    for child in elem.children:
+    var i = elem.children.len - 1
+    while i >= 0:
+      let child = elem.children[i]
       stack.add(child)
+      dec i
 
     if rules_local.len > 0:
       discard embedded_rules.pop()
@@ -490,6 +510,8 @@ proc applyAuthorRules*(document: Document): seq[tuple[e:Element,d:CSSDeclaration
 proc applyStylesheets*(document: Document) =
   let important_ua = document.applyRules(stylesheet)
   let important_author = document.applyAuthorRules()
+  for rule in important_author:
+    rule.e.applyProperty(rule.d)
   for rule in important_ua:
     rule.e.applyProperty(rule.d)
 
diff --git a/src/html/parser.nim b/src/html/parser.nim
index eed5baa7..68295dbe 100644
--- a/src/html/parser.nim
+++ b/src/html/parser.nim
@@ -225,8 +225,6 @@ proc processDocumentEndNode(state: var HTMLParseState) =
   state.elementNode = state.elementNode.parentElement
 
 proc processDocumentText(state: var HTMLParseState) =
-  if state.textNode != nil and state.textNode.data.len > 0:
-    processDocumentBody(state)
   if state.textNode == nil:
     state.textNode = newText()
     processDocumentAddNode(state, state.textNode)
@@ -264,11 +262,16 @@ proc processDocumentStartElement(state: var HTMLParseState, element: Element, ta
     add = false
   of TAG_HEAD:
     add = false
+    state.in_body = false
+    if state.elementNode.ownerDocument != nil:
+      state.elementNode = state.elementNode.ownerDocument.head
   of TAG_BODY:
     add = false
-    processDocumentBody(state)
   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:
@@ -302,7 +305,7 @@ proc processDocumentEndElement(state: var HTMLParseState, tag: DOMParsedTag) =
   if tag.tagid in VoidTagTypes:
     return
   if tag.tagid == TAG_HEAD:
-    state.in_body = true
+    processDocumentBody(state)
     return
   if tag.tagid == TAG_BODY:
     return
diff --git a/src/io/buffer.nim b/src/io/buffer.nim
index 9775a267..47148363 100644
--- a/src/io/buffer.nim
+++ b/src/io/buffer.nim
@@ -6,6 +6,7 @@ import unicode
 
 import types/color
 import types/enums
+import css/style
 import utils/twtstr
 import html/dom
 import layout/box
@@ -75,6 +76,31 @@ func generateFullOutput*(buffer: Buffer): seq[string] =
       result.add(s)
       x = 0
       s = ""
+
+    s &= "\e[0m"
+    if cell.fgcolor != defaultColor:
+      var color = cell.fgcolor
+      if color.rgb:
+        let rgb = color.rgbcolor
+        s &= "\e[38;2;" & $rgb.r & ";" & $rgb.g & ";" & $rgb.b & "m"
+      else:
+        s &= "\e[" & $color.color & "m"
+
+    if cell.bgcolor != defaultColor:
+      var color = cell.bgcolor
+      if color.rgb:
+        let rgb = color.rgbcolor
+        s &= "\e[48;2;" & $rgb.r & ";" & $rgb.g & ";" & $rgb.b & "m"
+      else:
+        s &= "\e[" & $color.color & "m"
+
+    if cell.bold:
+      s &= "\e[1m"
+    if cell.italic:
+      s &= "\e[3m"
+    if cell.underline:
+      s &= "\e[4m"
+
     s &= $cell.runes
     inc x
 
@@ -306,7 +332,6 @@ proc cursorRight*(buffer: Buffer) =
       inc buffer.cursorx
 
 proc cursorLeft*(buffer: Buffer) =
-  eprint "??", buffer.currentCellOrigin(), buffer.fromx
   let cellorigin = buffer.fromx + buffer.currentCellOrigin()
   let lw = buffer.currentLineWidth()
   if buffer.fromx > buffer.cursorx:
@@ -524,6 +549,14 @@ proc setLine*(buffer: Buffer, x: int, y: int, line: FlexibleLine) =
     buffer.lines[y].add(line[i])
     inc i
 
+func cellFromLine(line: CSSRowBox, i: int): FlexibleCell =
+  result.rune = line.runes[i]
+  result.fgcolor = line.color.cellColor()
+  if line.fontstyle in { FONT_STYLE_ITALIC, FONT_STYLE_OBLIQUE }:
+    result.italic = true
+  if line.fontweight > 500:
+    result.bold = true
+
 proc setRowBox(buffer: Buffer, line: CSSRowBox) =
   let x = line.x
   let y = line.y
@@ -547,7 +580,7 @@ proc setRowBox(buffer: Buffer, line: CSSRowBox) =
     inc nx
 
   while j < line.runes.len:
-    buffer.lines[y].add(FlexibleCell(rune: line.runes[j]))
+    buffer.lines[y].add(line.cellFromLine(j))
     nx += line.runes[j].width()
     inc j
 
@@ -601,6 +634,11 @@ proc refreshDisplay*(buffer: Buffer) =
       if line[i].rune.width() == 0 and j != 0:
         inc n
       buffer.display[dls + j - n].runes.add(line[i].rune)
+      buffer.display[dls + j - n].fgcolor = line[i].fgcolor
+      buffer.display[dls + j - n].bgcolor = line[i].bgcolor
+      buffer.display[dls + j - n].italic = line[i].italic
+      buffer.display[dls + j - n].bold = line[i].bold
+      buffer.display[dls + j - n].underline = line[i].underline
       j += line[i].rune.width()
       inc i
 
@@ -694,14 +732,14 @@ proc displayBufferSwapOutput(buffer: Buffer) =
       let color = inst.color
       if inst.color.rgb:
         let rgb = color.rgbcolor
-        print("\e38;2" & $rgb.r & ";" & $rgb.b & ";" & $rgb.g)
+        print("\e[38;2;" & $rgb.r & ";" & $rgb.g & ";" & $rgb.b & "m")
       else:
         print("\e[" & $color.color & "m")
     of DRAW_BGCOLOR:
       let color = inst.color
       if inst.color.rgb:
         let rgb = color.rgbcolor
-        print("\e48;2" & $rgb.r & ";" & $rgb.b & ";" & $rgb.g)
+        print("\e[48;2;" & $rgb.r & ";" & $rgb.g & ";" & $rgb.b & "m")
       else:
         print("\e[" & $color.color & "m")
     of DRAW_STYLE:
@@ -750,6 +788,8 @@ proc inputLoop(attrs: TermAttributes, buffer: Buffer): bool =
       s = ""
     else:
       feedNext = false
+
+
     let c = getch()
     s &= c
     let action = getNormalAction(s)
diff --git a/src/layout/box.nim b/src/layout/box.nim
index f36823ae..21c56afa 100644
--- a/src/layout/box.nim
+++ b/src/layout/box.nim
@@ -21,6 +21,7 @@ type
     children*: seq[CSSBox]
     context*: InlineContext
     bcontext*: BlockContext
+    cssvalues*: CSSComputedValues
 
   InlineContext* = ref object
     context*: FormatContextType
@@ -30,7 +31,6 @@ type
     marginy*: int
     conty*: bool
     whitespace*: bool
-    cssvalues*: CSSComputedValues
 
   BlockContext* = ref object
     context*: FormatContextType
@@ -42,6 +42,9 @@ type
     y*: int
     width*: int
     height*: int
+    color*: CSSColor
+    fontstyle*: CSSFontStyle
+    fontweight*: int
     runes*: seq[Rune]
 
   CSSInlineBox* = ref CSSInlineBoxObj
diff --git a/src/layout/layout.nim b/src/layout/layout.nim
index 4f73f53c..234e54f0 100644
--- a/src/layout/layout.nim
+++ b/src/layout/layout.nim
@@ -16,7 +16,7 @@ func newContext*(box: CSSBox): InlineContext =
 
 func newBlockBox*(parent: CSSBox, vals: CSSComputedValues): CSSBlockBox =
   new(result)
-  result.bcontext = parent.bcontext #TODO make this something like state or something
+  result.bcontext = parent.bcontext #TODO statify
   result.x = parent.x
   if parent.context.conty:
     inc parent.height
@@ -34,9 +34,9 @@ func newBlockBox*(parent: CSSBox, vals: CSSComputedValues): CSSBlockBox =
   result.context = newContext(parent)
   eprint "inc to", result.y
   result.context.fromy = result.y
-  result.context.cssvalues = vals
+  result.cssvalues = vals
 
-func newInlineBox*(parent: CSSBox): CSSInlineBox =
+func newInlineBox*(parent: CSSBox, vals: CSSComputedValues): CSSInlineBox =
   assert parent != nil
   new(result)
   result.x = parent.x
@@ -45,9 +45,16 @@ func newInlineBox*(parent: CSSBox): CSSInlineBox =
   result.width = parent.width
   result.context = parent.context
   result.bcontext = parent.bcontext
+  result.cssvalues = vals
   if result.context == nil:
     result.context = newContext(parent)
 
+#TODO there should be actual inline contexts to store these stuff
+proc setup(rowbox: var CSSRowBox, cssvalues: CSSComputedValues) =
+  rowbox.color = cssvalues[RULE_COLOR].color
+  rowbox.fontstyle = cssvalues[RULE_FONT_STYLE].fontstyle
+  rowbox.fontweight = cssvalues[RULE_FONT_WEIGHT].integer
+
 proc inlineWrap(ibox: var CSSInlineBox, rowi: var int, fromx: var int, rowbox: var CSSRowBox) =
   ibox.content.add(rowbox)
   inc rowi
@@ -55,7 +62,9 @@ proc inlineWrap(ibox: var CSSInlineBox, rowi: var int, fromx: var int, rowbox: v
   ibox.context.whitespace = true
   ibox.context.conty = true
   rowbox = CSSRowBox(x: ibox.x, y: ibox.y + rowi)
+  rowbox.setup(ibox.cssvalues)
 
+#TODO statify
 proc processInlineBox(parent: CSSBox, str: string): CSSBox =
   var ibox: CSSInlineBox
   var use_parent = false
@@ -63,7 +72,7 @@ proc processInlineBox(parent: CSSBox, str: string): CSSBox =
     ibox = CSSInlineBox(parent)
     use_parent = true
   else:
-    ibox = newInlineBox(parent)
+    ibox = newInlineBox(parent, parent.cssvalues)
 
   if str.len == 0:
     return
@@ -72,6 +81,7 @@ proc processInlineBox(parent: CSSBox, str: string): CSSBox =
   var rowi = 0
   var fromx = ibox.context.fromx
   var rowbox = CSSRowBox(x: fromx, y: ibox.context.fromy)
+  rowbox.setup(ibox.cssvalues)
   var r: Rune
   while i < str.len:
     fastRuneAt(str, i, r)
@@ -81,7 +91,7 @@ proc processInlineBox(parent: CSSBox, str: string): CSSBox =
       if ibox.context.whitespace:
         continue
       else:
-        let wsr = ibox.context.cssvalues[RULE_WHITESPACE].whitespace
+        let wsr = ibox.cssvalues[RULE_WHITESPACE].whitespace
 
         case wsr
         of WHITESPACE_NORMAL, WHITESPACE_NOWRAP:
@@ -122,8 +132,7 @@ proc processElemBox(parent: CSSBox, elem: Element): CSSBox =
     result = newBlockBox(parent, elem.cssvalues)
     CSSBlockBox(result).tag = $elem.tagType
   of DISPLAY_INLINE:
-    result = newInlineBox(parent)
-    result.context.cssvalues = elem.cssvalues
+    result = newInlineBox(parent, elem.cssvalues)
   of DISPLAY_NONE:
     return nil
   else:
@@ -140,7 +149,7 @@ proc add(parent: var CSSBox, box: CSSBox) =
       eprint "inc a"
       inc box.context.fromy
       box.context.conty = false
-    let mbot = box.context.cssvalues[RULE_MARGIN_BOTTOM].length.cells()
+    let mbot = box.cssvalues[RULE_MARGIN_BOTTOM].length.cells()
     eprint "inc b", mbot
     box.context.fromy += mbot
     box.bcontext.marginy = mbot
diff --git a/src/main.nim b/src/main.nim
index 4515147f..c208375a 100644
--- a/src/main.nim
+++ b/src/main.nim
@@ -2,6 +2,7 @@ import httpClient
 import uri
 import os
 import streams
+import terminal
 
 import html/parser
 import html/dom
@@ -33,22 +34,36 @@ proc getPageUri(uri: Uri): Stream =
 
 var buffers: seq[Buffer]
 
+proc die() =
+  eprint "Invalid parameters. Usage:\ntwt <url>"
+  quit(1)
+
 proc main*() =
-  if paramCount() != 1:
-    eprint "Invalid parameters. Usage:\ntwt <url>"
-    quit(1)
-  readConfig()
   let attrs = getTermAttributes()
   let buffer = newBuffer(attrs)
-  let uri = parseUri(paramStr(1))
   buffers.add(buffer)
-  buffer.source = getPageUri(uri).readAll() #TODO get rid of this
+
+  var lastUri: Uri
+  if paramCount() < 1:
+    if not isatty(stdin):
+      try:
+        while true:
+          buffer.source &= stdin.readChar()
+      except EOFError:
+        #TODO handle failure (also, is this even portable at all?)
+        discard reopen(stdin, "/dev/tty", fmReadWrite);
+    else:
+      die()
+    buffer.setLocation(lastUri)
+  else: 
+    lastUri = parseUri(paramStr(1))
+    buffer.source = getPageUri(lastUri).readAll() #TODO get rid of this
+
+  buffer.setLocation(lastUri)
   buffer.document = parseHtml(newStringStream(buffer.source))
-  buffer.setLocation(uri)
   buffer.document.applyStylesheets()
   buffer.alignBoxes()
   buffer.renderDocument()
-  var lastUri = uri
   while displayPage(attrs, buffer):
     buffer.setStatusMessage("Loading...")
     var newUri = buffer.location
@@ -56,10 +71,12 @@ proc main*() =
     newUri.anchor = ""
     if $lastUri != $newUri:
       buffer.clearBuffer()
-      if uri.scheme == "" and uri.path == "" and uri.anchor != "":
+      if lastUri.scheme == "" and lastUri.path == "" and lastUri.anchor != "":
         discard
       else:
         buffer.document = parseHtml(getPageUri(buffer.location))
-      buffer.renderPlainText(getPageUri(uri).readAll())
+      buffer.renderPlainText(getPageUri(lastUri).readAll())
     lastUri = newUri
+
+readConfig()
 main()
diff --git a/src/types/enums.nim b/src/types/enums.nim
index 914a4dc2..c43a7ad7 100644
--- a/src/types/enums.nim
+++ b/src/types/enums.nim
@@ -73,33 +73,17 @@ type
   CSSRuleType* = enum
     RULE_ALL, RULE_COLOR, RULE_MARGIN, RULE_MARGIN_TOP, RULE_MARGIN_LEFT,
     RULE_MARGIN_RIGHT, RULE_MARGIN_BOTTOM, RULE_FONT_STYLE, RULE_DISPLAY,
-    RULE_CONTENT, RULE_WHITESPACE
+    RULE_CONTENT, RULE_WHITESPACE, RULE_FONT_WEIGHT
 
   CSSGlobalValueType* = enum
     VALUE_INITIAL, VALUE_INHERIT, VALUE_REVERT, VALUE_UNSET
 
   CSSValueType* = enum
-    VALUE_NONE, VALUE_LENGTH, VALUE_COLOR, VALUE_CONTENT, VALUE_DISPLAY, VALUE_FONT_STYLE, VALUE_WHITESPACE
+    VALUE_NONE, VALUE_LENGTH, VALUE_COLOR, VALUE_CONTENT, VALUE_DISPLAY,
+    VALUE_FONT_STYLE, VALUE_WHITESPACE, VALUE_INTEGER
 
   DrawInstructionType* = enum
     DRAW_TEXT, DRAW_GOTO, DRAW_FGCOLOR, DRAW_BGCOLOR, DRAW_STYLE, DRAW_RESET
 
   FormatContextType* = enum
     CONTEXT_BLOCK, CONTEXT_INLINE
-
-const SelfClosingTagTypes* = {
-  TAG_LI, TAG_P
-}
-
-const VoidTagTypes* = {
-  TAG_AREA, TAG_BASE, TAG_BR, TAG_COL, TAG_FRAME, TAG_HR, TAG_IMG, TAG_INPUT,
-  TAG_SOURCE, TAG_TRACK, TAG_LINK, TAG_META, TAG_PARAM, TAG_WBR, TAG_HR
-}
-
-const PClosingTagTypes* = {
-  TAG_ADDRESS, TAG_ARTICLE, TAG_ASIDE, TAG_BLOCKQUOTE, TAG_DETAILS, TAG_DIV,
-  TAG_DL, TAG_FIELDSET, TAG_FIGCAPTION, TAG_FIGURE, TAG_FOOTER, TAG_FORM,
-  TAG_H1, TAG_H2, TAG_H3, TAG_H4, TAG_H5, TAG_H6, TAG_HEADER, TAG_HGROUP,
-  TAG_HR, TAG_MAIN, TAG_MENU, TAG_NAV, TAG_OL, TAG_P, TAG_PRE, TAG_SECTION,
-  TAG_TABLE, TAG_UL
-}
diff --git a/src/types/tagtypes.nim b/src/types/tagtypes.nim
index 34111570..14121db0 100644
--- a/src/types/tagtypes.nim
+++ b/src/types/tagtypes.nim
@@ -28,3 +28,24 @@ func inputType*(s: string): InputType =
     return inputTypeMap[s]
   else:
     return INPUT_UNKNOWN
+
+const SelfClosingTagTypes* = {
+  TAG_LI, TAG_P
+}
+
+const VoidTagTypes* = {
+  TAG_AREA, TAG_BASE, TAG_BR, TAG_COL, TAG_FRAME, TAG_HR, TAG_IMG, TAG_INPUT,
+  TAG_SOURCE, TAG_TRACK, TAG_LINK, TAG_META, TAG_PARAM, TAG_WBR, TAG_HR
+}
+
+const PClosingTagTypes* = {
+  TAG_ADDRESS, TAG_ARTICLE, TAG_ASIDE, TAG_BLOCKQUOTE, TAG_DETAILS, TAG_DIV,
+  TAG_DL, TAG_FIELDSET, TAG_FIGCAPTION, TAG_FIGURE, TAG_FOOTER, TAG_FORM,
+  TAG_H1, TAG_H2, TAG_H3, TAG_H4, TAG_H5, TAG_H6, TAG_HEADER, TAG_HGROUP,
+  TAG_HR, TAG_MAIN, TAG_MENU, TAG_NAV, TAG_OL, TAG_P, TAG_PRE, TAG_SECTION,
+  TAG_TABLE, TAG_UL
+}
+
+const HeadTagTypes* = {
+  TAG_BASE, TAG_LINK, TAG_META, TAG_TITLE, TAG_NOSCRIPT, TAG_SCRIPT, TAG_NOFRAMES, TAG_STYLE, TAG_HEAD
+}
diff --git a/src/utils/eprint.nim b/src/utils/eprint.nim
index eba5f51f..d13fcf91 100644
--- a/src/utils/eprint.nim
+++ b/src/utils/eprint.nim
@@ -1,27 +1,25 @@
 {.used.}
 
 template eprint*(s: varargs[string, `$`]) = {.cast(noSideEffect).}:
-  if not defined(release):
-    var a = false
-    for x in s:
-      if not a:
-        a = true
-      else:
-        stderr.write(' ')
-      stderr.write(x)
-    stderr.write('\n')
+  var a = false
+  for x in s:
+    if not a:
+      a = true
+    else:
+      stderr.write(' ')
+    stderr.write(x)
+  stderr.write('\n')
 
 template eecho*(s: varargs[string, `$`]) = {.cast(noSideEffect).}:
-  if not defined(release):
-    var a = false
-    var o = ""
-    for x in s:
-      if not a:
-        a = true
-      else:
-        o &= ' '
-      o &= x
-    echo o
+  var a = false
+  var o = ""
+  for x in s:
+    if not a:
+      a = true
+    else:
+      o &= ' '
+    o &= x
+  echo o
 
 template print*(s: varargs[string, `$`]) =
   for x in s: