about summary refs log tree commit diff stats
path: root/src/types
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2023-09-14 01:41:47 +0200
committerbptato <nincsnevem662@gmail.com>2023-09-14 02:01:21 +0200
commitc1b8338045716b25d664c0b8dd91eac0cb76480e (patch)
treea9c0a6763f180c2b6dd380aa880253ffc7685d85 /src/types
parentdb0798acccbedcef4b16737f6be0cf7388cc0528 (diff)
downloadchawan-c1b8338045716b25d664c0b8dd91eac0cb76480e.tar.gz
move around more modules
* ips -> io/
* loader related stuff -> loader/
* tempfile -> extern/
* buffer, forkserver -> server/
* lineedit, window -> display/
* cell -> types/
* opt -> types/
Diffstat (limited to 'src/types')
-rw-r--r--src/types/buffersource.nim2
-rw-r--r--src/types/cell.nim298
-rw-r--r--src/types/cookie.nim2
-rw-r--r--src/types/opt.nim109
4 files changed, 409 insertions, 2 deletions
diff --git a/src/types/buffersource.nim b/src/types/buffersource.nim
index a5e3e21f..97126ed1 100644
--- a/src/types/buffersource.nim
+++ b/src/types/buffersource.nim
@@ -3,7 +3,7 @@ import options
 when defined(posix):
   import posix
 
-import io/request
+import loader/request
 import types/url
 
 import chakasu/charset
diff --git a/src/types/cell.nim b/src/types/cell.nim
new file mode 100644
index 00000000..87148389
--- /dev/null
+++ b/src/types/cell.nim
@@ -0,0 +1,298 @@
+import options
+import tables
+
+import css/stylednode
+import types/color
+import utils/twtstr
+
+type
+  FormatFlags* = enum
+    FLAG_BOLD
+    FLAG_ITALIC
+    FLAG_UNDERLINE
+    FLAG_REVERSE
+    FLAG_STRIKE
+    FLAG_OVERLINE
+    FLAG_BLINK
+
+  Format* = object
+    fgcolor*: CellColor
+    bgcolor*: CellColor
+    flags*: set[FormatFlags]
+
+  # A FormatCell *starts* a new terminal formatting context.
+  # If no FormatCell exists before a given cell, the default formatting is used.
+  FormatCell* = object
+    format*: Format
+    pos*: int
+    node*: StyledNode
+
+  SimpleFormatCell* = object
+    format*: Format
+    pos*: int
+
+  FlexibleLine* = object
+    str*: string
+    formats*: seq[FormatCell]
+
+  SimpleFlexibleLine* = object
+    str*: string
+    formats*: seq[SimpleFormatCell]
+
+  FlexibleGrid* = seq[FlexibleLine]
+
+  SimpleFlexibleGrid* = seq[SimpleFlexibleLine]
+
+  FixedCell* = object
+    str*: string
+    format*: Format
+
+  FixedGrid* = object
+    width*, height*: int
+    cells*: seq[FixedCell]
+
+proc `[]=`*(grid: var FixedGrid, i: int, cell: FixedCell) = grid.cells[i] = cell
+proc `[]=`*(grid: var FixedGrid, i: BackwardsIndex, cell: FixedCell) = grid.cells[i] = cell
+proc `[]`*(grid: var FixedGrid, i: int): var FixedCell = grid.cells[i]
+proc `[]`*(grid: var FixedGrid, i: BackwardsIndex): var FixedCell = grid.cells[i]
+proc `[]`*(grid: FixedGrid, i: int): FixedCell = grid.cells[i]
+proc `[]`*(grid: FixedGrid, i: BackwardsIndex): FixedCell = grid.cells[i]
+iterator items*(grid: FixedGrid): FixedCell {.inline.} =
+  for cell in grid.cells: yield cell
+proc len*(grid: FixedGrid): int = grid.cells.len
+proc high*(grid: FixedGrid): int = grid.cells.high
+
+const FormatCodes*: array[FormatFlags, tuple[s, e: uint8]] = [
+  FLAG_BOLD: (1u8, 22u8),
+  FLAG_ITALIC: (3u8, 23u8),
+  FLAG_UNDERLINE: (4u8, 24u8),
+  FLAG_REVERSE: (7u8, 27u8),
+  FLAG_STRIKE: (9u8, 29u8),
+  FLAG_OVERLINE: (53u8, 55u8),
+  FLAG_BLINK: (5u8, 25u8),
+]
+
+const FormatCodeMap = block:
+  var res: Table[uint8, tuple[flag: FormatFlags, reverse: bool]]
+  for x in FormatFlags:
+    res[FormatCodes[x][0]] = (x, false)
+    res[FormatCodes[x][1]] = (x, true)
+  res
+
+template flag_template(format: Format, val: bool, flag: FormatFlags) =
+  if val: format.flags.incl(flag)
+  else: format.flags.excl(flag)
+
+template `italic=`*(f: var Format, b: bool) = flag_template f, b, FLAG_ITALIC
+template `bold=`*(f: var Format, b: bool) = flag_template f, b, FLAG_BOLD
+template `underline=`*(f: var Format, b: bool) = flag_template f, b, FLAG_UNDERLINE
+template `reverse=`*(f: var Format, b: bool) = flag_template f, b, FLAG_REVERSE
+template `strike=`*(f: var Format, b: bool) = flag_template f, b, FLAG_STRIKE
+template `overline=`*(f: var Format, b: bool) = flag_template f, b, FLAG_OVERLINE
+template `blink=`*(f: var Format, b: bool) = flag_template f, b, FLAG_BLINK
+
+func newFixedGrid*(w: int, h: int = 1): FixedGrid =
+  return FixedGrid(width: w, height: h, cells: newSeq[FixedCell](w * h))
+
+func width*(line: FlexibleLine): int =
+  return line.str.width()
+
+func width*(cell: FixedCell): int =
+  return cell.str.width()
+
+func newFormat*(): Format =
+  return Format(fgcolor: defaultColor, bgcolor: defaultColor)
+
+# Get the first format cell after pos, if any.
+func findFormatN*(line: FlexibleLine|SimpleFlexibleLine, pos: int): int =
+  var i = 0
+  while i < line.formats.len:
+    if line.formats[i].pos > pos:
+      break
+    inc i 
+  return i
+
+func findFormat*(line: FlexibleLine, pos: int): FormatCell =
+  let i = line.findFormatN(pos) - 1
+  if i != -1:
+    result = line.formats[i]
+  else:
+    result.pos = -1
+
+func findFormat*(line: SimpleFlexibleLine, pos: int): SimpleFormatCell =
+  let i = line.findFormatN(pos) - 1
+  if i != -1:
+    result = line.formats[i]
+  else:
+    result.pos = -1
+
+func findNextFormat*(line: FlexibleLine, pos: int): FormatCell =
+  let i = line.findFormatN(pos)
+  if i < line.formats.len:
+    result = line.formats[i]
+  else:
+    result.pos = -1
+
+func findNextFormat*(line: SimpleFlexibleLine, pos: int): SimpleFormatCell =
+  let i = line.findFormatN(pos)
+  if i < line.formats.len:
+    result = line.formats[i]
+  else:
+    result.pos = -1
+
+proc addLine*(grid: var FlexibleGrid) =
+  grid.add(FlexibleLine())
+
+proc insertFormat*(line: var FlexibleLine, pos, i: int, format: Format, node: StyledNode = nil) =
+  line.formats.insert(FormatCell(format: format, node: node, pos: pos), i)
+
+proc addFormat*(line: var FlexibleLine, pos: int, format: Format, node: StyledNode = nil) =
+  line.formats.add(FormatCell(format: format, node: node, pos: pos))
+
+# https://www.ecma-international.org/wp-content/uploads/ECMA-48_5th_edition_june_1991.pdf
+type
+  AnsiCodeParseState* = enum
+    PARSE_START, PARSE_PARAMS, PARSE_INTERM, PARSE_FINAL, PARSE_DONE
+
+  AnsiCodeParser* = object
+    state*: AnsiCodeParseState
+    params: string
+
+proc getParam(parser: AnsiCodeParser, i: var int, colon = false): string =
+  while i < parser.params.len and
+      not (parser.params[i] == ';' or colon and parser.params[i] == ':'):
+    result &= parser.params[i]
+    inc i
+  if i < parser.params.len:
+    inc i
+
+template getParamU8(parser: AnsiCodeParser, i: var int,
+    colon = false): uint8 =
+  if i >= parser.params.len:
+    return false
+  let u = parseUInt8(parser.getParam(i))
+  if u.isNone:
+    return false
+  u.get
+
+proc parseSGRDefColor(parser: AnsiCodeParser, format: var Format,
+    i: var int, isfg: bool): bool =
+  let u = parser.getParamU8(i, colon = true)
+  template set_color(c: CellColor) =
+    if isfg:
+      format.fgcolor = c
+    else:
+      format.bgcolor = c
+  if u == 2:
+    let param0 = parser.getParamU8(i, colon = true)
+    if i < parser.params.len:
+      let r = param0
+      let g = parser.getParamU8(i, colon = true)
+      let b = parser.getParamU8(i, colon = true)
+      set_color cellColor(rgb(r, g, b))
+    else:
+      set_color cellColor(gray(param0))
+  elif u == 5:
+    let param0 = parser.getParamU8(i, colon = true)
+    if param0 in 0u8..7u8:
+      set_color cellColor(ANSIColor(param0))
+    elif param0 in 8u8..15u8:
+      format.bold = true
+      set_color cellColor(ANSIColor(param0 - 8))
+    elif param0 in 16u8..255u8:
+      set_color cellColor(EightBitColor(param0))
+  else:
+    return false
+
+proc parseSGRColor(parser: AnsiCodeParser, format: var Format,
+    i: var int, u: uint8): bool =
+  if u in 30u8..37u8:
+    format.fgcolor = cellColor(ANSIColor(u - 30))
+  elif u == 38:
+    return parser.parseSGRDefColor(format, i, isfg = true)
+  elif u == 39:
+    format.fgcolor = defaultColor
+  elif u in 40u8..47u8:
+    format.bgcolor = cellColor(ANSIColor(u - 40))
+  elif u == 48:
+    return parser.parseSGRDefColor(format, i, isfg = false)
+  elif u == 49:
+    format.bgcolor = defaultColor
+  elif u in 90u8..97u8:
+    format.fgcolor = cellColor(ANSIColor(u - 90u8))
+    format.bold = true
+  elif u in 100u8..107u8:
+    format.bgcolor = cellColor(ANSIColor(u - 90u8))
+    format.bold = true
+  else:
+    return false
+  return true
+
+proc parseSGRAspect(parser: AnsiCodeParser, format: var Format,
+    i: var int): bool =
+  let u = parser.getParamU8(i)
+  if u in FormatCodeMap:
+    let entry = FormatCodeMap[u]
+    if entry.reverse:
+      format.flags.excl(entry.flag)
+    else:
+      format.flags.incl(entry.flag)
+    return true
+  elif u == 0:
+    format = newFormat()
+    return true
+  else:
+    return parser.parseSGRColor(format, i, u)
+
+proc parseSGR(parser: AnsiCodeParser, format: var Format) =
+  if parser.params.len == 0:
+    format = newFormat()
+  else:
+    var i = 0
+    while i < parser.params.len:
+      if not parser.parseSGRAspect(format, i):
+        break
+
+proc parseControlFunction(parser: var AnsiCodeParser, format: var Format,
+    f: char) =
+  case f
+  of 'm':
+    parser.parseSGR(format)
+  else: discard # unknown
+
+proc reset*(parser: var AnsiCodeParser) =
+  parser.state = PARSE_START
+  parser.params = ""
+
+proc parseAnsiCode*(parser: var AnsiCodeParser, format: var Format,
+    c: char): bool =
+  case parser.state
+  of PARSE_START:
+    if 0x40 <= int(c) and int(c) <= 0x5F:
+      if c != '[':
+        #C1, TODO?
+        parser.state = PARSE_DONE
+      else:
+        parser.state = PARSE_PARAMS
+    else:
+      parser.state = PARSE_DONE
+      return true
+  of PARSE_PARAMS:
+    if 0x30 <= int(c) and int(c) <= 0x3F:
+      parser.params &= c
+    else:
+      parser.state = PARSE_INTERM
+      return parser.parseAnsiCode(format, c)
+  of PARSE_INTERM:
+    if 0x20 <= int(c) and int(c) <= 0x2F:
+      discard
+    else:
+      parser.state = PARSE_FINAL
+      return parser.parseAnsiCode(format, c)
+  of PARSE_FINAL:
+    parser.state = PARSE_DONE
+    if 0x40 <= int(c) and int(c) <= 0x7E:
+      parser.parseControlFunction(format, c)
+    else:
+      return true
+  of PARSE_DONE: discard
diff --git a/src/types/cookie.nim b/src/types/cookie.nim
index 141b62e5..6d7ab79a 100644
--- a/src/types/cookie.nim
+++ b/src/types/cookie.nim
@@ -6,7 +6,7 @@ import js/error
 import js/javascript
 import js/regex
 import types/url
-import utils/opt
+import types/opt
 import utils/twtstr
 
 type
diff --git a/src/types/opt.nim b/src/types/opt.nim
new file mode 100644
index 00000000..cdf69633
--- /dev/null
+++ b/src/types/opt.nim
@@ -0,0 +1,109 @@
+# Inspired by nim-results.
+
+type
+  Result*[T, E] = object
+    when E is void and T is void: # weirdness
+      has*: bool
+    elif E is void and not (T is void): # opt
+      case has*: bool
+      of true:
+        val*: T
+      else:
+        discard
+    elif not (E is void) and T is void: # err
+      case has*: bool
+      of true:
+        discard
+      else:
+        ex*: E
+    else: # result
+      case has*: bool
+      of true:
+        val*: T
+      else:
+        ex*: E
+
+  Opt*[T] = Result[T, void]
+
+  Err*[E] = Result[void, E]
+
+template ok*[E](t: type Err[E]): Err[E] =
+  Err[E](has: true)
+
+template ok*[T, E](t: type Result[T, E], x: T): Result[T, E] =
+  Result[T, E](val: x, has: true)
+
+template ok*[T](x: T): auto =
+  ok(typeof(result), x)
+
+template ok*(): auto =
+  ok(typeof(result))
+
+template ok*[T, E](res: var Result[T, E], x: T) =
+  res = Result[T, E](has: true, val: x)
+
+template ok*[E](res: var Result[void, E]) =
+  res = Result[void, E](has: true)
+
+template err*[T, E](t: type Result[T, E], e: E): Result[T, E] =
+  Result[T, E](has: false, ex: e)
+
+template err*[T](t: type Result[T, ref object]): auto =
+  t(has: false, ex: nil)
+
+template err*[T](t: type Result[T, void]): Result[T, void] =
+  Result[T, void](has: false)
+
+template err*(): auto =
+  err(typeof(result))
+
+template err*[T, E](res: var Result[T, E], e: E) =
+  res = Result[T, E](has: false, ex: e)
+
+template err*[T, E](res: var Result[T, E]) =
+  res = Result[T, E](has: false)
+
+template err*[E](e: E): auto =
+  err(typeof(result), e)
+
+template opt*[T](v: T): auto =
+  ok(Opt[T], v)
+
+template opt*(t: typedesc): auto =
+  err(Result[t, void])
+
+template opt*[T, E: not void](r: Result[T, E]): Opt[T] =
+  if r.isOk:
+    Opt[T].ok(r.get)
+  else:
+    Opt[T].err()
+
+template isOk*(res: Result): bool = res.has
+template isErr*(res: Result): bool = not res.has
+template isSome*(res: Result): bool = res.isOk
+template isNone*(res: Result): bool = res.isErr
+func get*[T, E](res: Result[T, E]): T {.inline.} = res.val
+func get*[T, E](res: var Result[T, E]): var T = res.val
+func get*[T, E](res: Result[T, E], v: T): T =
+  if res.has:
+    res.val
+  else:
+    v
+func error*[T, E](res: Result[T, E]): E {.inline.} = res.ex
+template valType*[T, E](res: type Result[T, E]): auto = T
+template errType*[T, E](res: type Result[T, E]): auto = E
+
+template `?`*[T, E](res: Result[T, E]): auto =
+  let x = res # for when res is a funcall
+  if x.has:
+    when not (T is void):
+      x.get
+    else:
+      discard
+  else:
+    when typeof(result) is Result[T, E]:
+      return x
+    elif not (E is void) and typeof(result).errType is E:
+      return err(x.error)
+    else:
+      return err()