about summary refs log tree commit diff stats
path: root/src/io/cell.nim
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2021-11-13 11:17:40 +0100
committerbptato <nincsnevem662@gmail.com>2021-11-13 11:17:40 +0100
commita6099512e42cc95cf6276ab784afd70febdd43b7 (patch)
treedef2061199d9f119a3176858e331ba376c89e2c5 /src/io/cell.nim
parentc141a3cea17f32f526853cd4085ae4cc80c4fed6 (diff)
downloadchawan-a6099512e42cc95cf6276ab784afd70febdd43b7.tar.gz
Parse ansi escape codes when displaying plain text
Diffstat (limited to 'src/io/cell.nim')
-rw-r--r--src/io/cell.nim182
1 files changed, 128 insertions, 54 deletions
diff --git a/src/io/cell.nim b/src/io/cell.nim
index 133b88d6..67b7361c 100644
--- a/src/io/cell.nim
+++ b/src/io/cell.nim
@@ -1,4 +1,7 @@
 import unicode
+import strutils
+import sequtils
+import sugar
 
 import types/color
 import utils/twtstr
@@ -28,6 +31,16 @@ type
 
   FixedGrid* = seq[FixedCell]
 
+func newFixedGrid*(w: int, h: int = 1): FixedGrid =
+  return newSeq[FixedCell](w * h)
+
+func width*(line: FlexibleLine): int =
+  for c in line:
+    result += c.rune.width()
+
+func newFormatting*(): Formatting =
+  return Formatting(fgcolor: defaultColor, bgcolor: defaultColor)
+
 proc setText*(grid: var FlexibleGrid, x: int, y: int, text: seq[Rune]) =
   while grid.len <= y:
     grid.add(newSeq[FlexibleCell]())
@@ -40,15 +53,121 @@ proc setText*(grid: var FlexibleGrid, x: int, y: int, text: seq[Rune]) =
     grid[y][i].rune = text[i]
     inc i
 
-func newFixedGrid*(w: int, h: int = 1): FixedGrid =
-  return newSeq[FixedCell](w * h)
-
-func width*(line: FlexibleLine): int =
-  for c in line:
-    result += c.rune.width()
-
-func newFormatting*(): Formatting =
-  return Formatting(fgcolor: defaultColor, bgcolor: defaultColor)
+template inc_check(i: int) =
+  inc i
+  if i >= buf.len:
+    return i
+
+proc parseAnsiCode*(formatting: var Formatting, buf: string, fi: int): int =
+  var i = fi
+  if buf[i] != '\e':
+    return i
+
+  inc_check i
+  if 0x40 <= int(buf[i]) and int(buf[i]) <= 0x5F:
+    if buf[i] != '[':
+      #C1, TODO?
+      return
+    inc_check i
+
+  let sp = i
+  #parameter bytes
+  while 0x30 <= int(buf[i]) and int(buf[i]) <= 0x3F:
+    inc_check i
+  let params = buf.substr(sp, i - 1)
+
+  let si = i
+  #intermediate bytes
+  while 0x20 <= int(buf[i]) and int(buf[i]) <= 0x2F:
+    inc_check i
+  let interm = buf.substr(si, i)
+
+  let final = buf[i]
+  #final byte
+  if 0x40 <= int(buf[i]) and int(buf[i]) <= 0x7E:
+    inc_check i
+
+  case final
+  of 'm':
+    if params.len == 0:
+      formatting = newFormatting()
+    else:
+      let sparams = params.split(';')
+      try:
+        let ip = sparams.map((x) => parseInt(x))
+        var pi = 0
+        while pi < ip.len:
+          case ip[pi]
+          of 0:
+            formatting = newFormatting()
+          of 1:
+            formatting.bold = true
+          of 3:
+            formatting.italic = true
+          of 4:
+            formatting.underline = true
+          of 9:
+            formatting.strike = true
+          of 22:
+            formatting.bold = false
+          of 23:
+            formatting.italic = false
+          of 29:
+            formatting.strike = false
+          of 30..37:
+            formatting.fgcolor = CellColor(rgb: false, color: uint8(ip[pi]))
+          of 38:
+            inc pi
+            if pi < ip.len:
+              if ip[pi] == 2:
+                inc pi
+                if pi + 2 < ip.len:
+                  let r = uint8(ip[pi])
+                  inc pi
+                  let g = uint8(ip[pi])
+                  inc pi
+                  let b = uint8(ip[pi])
+                  formatting.fgcolor = CellColor(rgb: true, rgbcolor: (r: r, g: g, b: b))
+              else:
+                #TODO
+                inc pi
+                continue
+            else:
+              break
+          of 39:
+            formatting.fgcolor = defaultColor
+          of 40..47:
+            formatting.bgcolor = CellColor(rgb: false, color: uint8(ip[0]))
+          of 48:
+            inc pi
+            if pi < ip.len:
+              if ip[pi] == 2:
+                inc pi
+                if pi + 2 < ip.len:
+                  let r = uint8(ip[pi])
+                  inc pi
+                  let g = uint8(ip[pi])
+                  inc pi
+                  let b = uint8(ip[pi])
+                  formatting.bgcolor = CellColor(rgb: true, rgbcolor: (r: r, g: g, b: b))
+              else:
+                #TODO
+                inc pi
+                continue
+            else:
+              break
+          of 49:
+            formatting.bgcolor = defaultColor
+          of 53:
+            formatting.overline = true
+          of 55:
+            formatting.overline = false
+          else: discard
+          inc pi
+      except ValueError: discard
+  else: discard
+
+  return i
 
 proc processFormatting*(formatting: var Formatting, cellf: Formatting): string =
     if formatting.bold and not cellf.bold:
@@ -96,48 +215,3 @@ proc processFormatting*(formatting: var Formatting, cellf: Formatting): string =
       result &= SGR(53)
 
     formatting = cellf
-    if formatting.bold and not cellf.bold:
-      result &= SGR(22)
-    if formatting.italic and not cellf.italic:
-      result &= SGR(23)
-    if formatting.underline and not cellf.underline:
-      result &= SGR(24)
-    if formatting.strike and not cellf.strike:
-      result &= SGR(29)
-    if formatting.overline and not cellf.overline:
-      result &= SGR(55)
-
-    if cellf.fgcolor != formatting.fgcolor:
-      var color = cellf.fgcolor
-      if color.rgb:
-        let rgb = color.rgbcolor
-        result &= SGR(38, 2, rgb.r, rgb.g, rgb.b)
-      elif color == defaultColor:
-        result &= SGR()
-        formatting = newFormatting()
-      else:
-        result &= SGR(color.color)
-
-    if cellf.bgcolor != formatting.bgcolor:
-      var color = cellf.bgcolor
-      if color.rgb:
-        let rgb = color.rgbcolor
-        result &= SGR(48, 2, rgb.r, rgb.g, rgb.b)
-      elif color == defaultColor:
-        result &= SGR()
-        formatting = newFormatting()
-      else:
-        result &= SGR(color.color)
-
-    if not formatting.bold and cellf.bold:
-      result &= SGR(1)
-    if not formatting.italic and cellf.italic:
-      result &= SGR(3)
-    if not formatting.underline and cellf.underline:
-      result &= SGR(4)
-    if not formatting.strike and cellf.strike:
-      result &= SGR(9)
-    if not formatting.overline and cellf.overline:
-      result &= SGR(53)
-
-    formatting = cellf