about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-06-03 20:29:10 +0200
committerbptato <nincsnevem662@gmail.com>2024-06-03 20:29:10 +0200
commit3e12a95ab34e120fb958ba0eeebaada5def7cd11 (patch)
treeff46a2d73d32c2a2a72df82801483dc7fd0134a2
parent5acbab703ba074e20dbc0ce729d9f57f467901e0 (diff)
downloadchawan-3e12a95ab34e120fb958ba0eeebaada5def7cd11.tar.gz
js: improve jsregex interface
It's easier to just use nested seqs here.

(This also fixes reverse-search highlighting the last capture group
instead of the whole match.)
-rw-r--r--adapter/protocol/man.nim134
-rw-r--r--src/js/jsregex.nim29
-rw-r--r--src/server/buffer.nim26
3 files changed, 88 insertions, 101 deletions
diff --git a/adapter/protocol/man.nim b/adapter/protocol/man.nim
index a5b7dab9..4d6de03f 100644
--- a/adapter/protocol/man.nim
+++ b/adapter/protocol/man.nim
@@ -94,13 +94,11 @@ proc isCommand(paths: seq[string]; name, s: string): bool =
       return true
   false
 
-iterator myCaptures(captures: var seq[RegexCapture]; target: int;
-    offset: var int): RegexCapture =
-  for cap in captures.mitems:
-    if cap.i == target:
-      cap.s += offset
-      cap.e += offset
-      yield cap
+iterator myCaptures(res: var RegexResult; i, offset: int): RegexCapture =
+  for cap in res.captures.mitems:
+    cap[i].s += offset
+    cap[i].e += offset
+    yield cap[i]
 
 proc readErrorMsg(efile: File; line: var string): string =
   var msg = ""
@@ -176,70 +174,64 @@ proc processManpage(ofile, efile: File; header, keyword: string) =
     var fileRes = fileRe.exec(line)
     var includeRes = includeRe.exec(line)
     var manRes = manRe.exec(line)
-    if linkRes.success:
-      for cap in linkRes.captures.myCaptures(0, offset):
-        let s = line[cap.s..<cap.e]
-        let link = "<a href='" & s & "'>" & s & "</a>"
-        line[cap.s..<cap.e] = link
-        offset += link.len - (cap.e - cap.s)
-    if mailRes.success:
-      for cap in mailRes.captures.myCaptures(2, offset):
-        let s = line[cap.s..<cap.e]
-        let link = "<a href='mailto:" & s & "'>" & s & "</a>"
-        line[cap.s..<cap.e] = link
-        offset += link.len - (cap.e - cap.s)
-    if fileRes.success:
-      for cap in fileRes.captures.myCaptures(0, offset):
-        let s = line[cap.s..<cap.e]
-        let target = s.expandTilde()
-        if not fileExists(target) and not symlinkExists(target) and
-            not dirExists(target):
-          continue
-        let name = target.afterLast('/')
-        let link = if paths.isCommand(name, target):
-          "<a href='man:" & name & "'>" & s & "</a>"
-        else:
-          "<a href='file:" & target & "'>" & s & "</a>"
-        line[cap.s..<cap.e] = link
-        offset += link.len - (cap.e - cap.s)
-    if includeRes.success:
-      for cap in includeRes.captures.myCaptures(2, offset):
-        let s = line[cap.s..<cap.e]
-        const includePaths = [
-          "/usr/include/",
-          "/usr/local/include/",
-          "/usr/X11R6/include/",
-          "/usr/X11/include/",
-          "/usr/X/include/",
-          "/usr/include/X11/"
-        ]
-        for path in includePaths:
-          let file = path & s
-          if fileExists(file):
-            let link = "<a href='file:" & file & "'>" & s & "</a>"
-            line[cap.s..<cap.e] = link
-            offset += link.len - (cap.e - cap.s)
-            break
-    if manRes.success:
-      for j, cap in manRes.captures.mpairs:
-        if cap.i == 0:
-          cap.s += offset
-          cap.e += offset
-          var manCap = manRes.captures[j + 2]
-          manCap.s += offset
-          manCap.e += offset
-          var secCap = manRes.captures[j + 4]
-          secCap.s += offset
-          secCap.e += offset
-          let man = line[manCap.s..<manCap.e]
-          # ignore footers like MYPAGE(1)
-          # (just to be safe, we also check if it's in paths too)
-          if man == ignoreMan and not paths.isCommand(man.afterLast('/'), man):
-            continue
-          let cat = man & line[secCap.s..<secCap.e]
-          let link = "<a href='man:" & cat & "'>" & man & "</a>"
-          line[manCap.s..<manCap.e] = link
-          offset += link.len - (manCap.e - manCap.s)
+    for cap in linkRes.myCaptures(0, offset):
+      let s = line[cap.s..<cap.e]
+      let link = "<a href='" & s & "'>" & s & "</a>"
+      line[cap.s..<cap.e] = link
+      offset += link.len - (cap.e - cap.s)
+    for cap in mailRes.myCaptures(2, offset):
+      let s = line[cap.s..<cap.e]
+      let link = "<a href='mailto:" & s & "'>" & s & "</a>"
+      line[cap.s..<cap.e] = link
+      offset += link.len - (cap.e - cap.s)
+    for cap in fileRes.myCaptures(0, offset):
+      let s = line[cap.s..<cap.e]
+      let target = s.expandTilde()
+      if not fileExists(target) and not symlinkExists(target) and
+          not dirExists(target):
+        continue
+      let name = target.afterLast('/')
+      let link = if paths.isCommand(name, target):
+        "<a href='man:" & name & "'>" & s & "</a>"
+      else:
+        "<a href='file:" & target & "'>" & s & "</a>"
+      line[cap.s..<cap.e] = link
+      offset += link.len - (cap.e - cap.s)
+    for cap in includeRes.myCaptures(2, offset):
+      let s = line[cap.s..<cap.e]
+      const includePaths = [
+        "/usr/include/",
+        "/usr/local/include/",
+        "/usr/X11R6/include/",
+        "/usr/X11/include/",
+        "/usr/X/include/",
+        "/usr/include/X11/"
+      ]
+      for path in includePaths:
+        let file = path & s
+        if fileExists(file):
+          let link = "<a href='file:" & file & "'>" & s & "</a>"
+          line[cap.s..<cap.e] = link
+          offset += link.len - (cap.e - cap.s)
+          break
+    for cap in manRes.captures.mitems:
+      cap[0].s += offset
+      cap[0].e += offset
+      var manCap = cap[2]
+      manCap.s += offset
+      manCap.e += offset
+      var secCap = cap[4]
+      secCap.s += offset
+      secCap.e += offset
+      let man = line[manCap.s..<manCap.e]
+      # ignore footers like MYPAGE(1)
+      # (just to be safe, we also check if it's in paths too)
+      if man == ignoreMan and not paths.isCommand(man.afterLast('/'), man):
+        continue
+      let cat = man & line[secCap.s..<secCap.e]
+      let link = "<a href='man:" & cat & "'>" & man & "</a>"
+      line[manCap.s..<manCap.e] = link
+      offset += link.len - (manCap.e - manCap.s)
     stdout.write(line & '\n')
   ofile.close()
   efile.close()
diff --git a/src/js/jsregex.nim b/src/js/jsregex.nim
index f24633d1..9fb09872 100644
--- a/src/js/jsregex.nim
+++ b/src/js/jsregex.nim
@@ -10,23 +10,19 @@ export LREFlags
 type
   Regex* = object
     bytecode: seq[uint8]
-    buf: string
+    when defined(debug):
+      buf: string
 
-  RegexCapture* = tuple # start, end, index
+  RegexCapture* = tuple # start, end
     s, e: int
-    i: int32
 
   RegexResult* = object
     success*: bool
-    captures*: seq[RegexCapture]
+    captures*: seq[seq[RegexCapture]]
 
-  RegexReplace* = object
-    regex: Regex
-    rule: string
-    global: bool
-
-func `$`*(regex: Regex): string =
-  regex.buf
+when defined(debug):
+  func `$`*(regex: Regex): string =
+    regex.buf
 
 # this is hardcoded into quickjs, so we must override it here.
 proc lre_realloc(opaque, p: pointer; size: csize_t): pointer {.exportc.} =
@@ -43,10 +39,9 @@ proc compileRegex*(buf: string; flags: LREFlags = {}): Result[Regex, string] =
   var bcseq = newSeqUninitialized[uint8](plen)
   copyMem(addr bcseq[0], bytecode, plen)
   dealloc(bytecode)
-  let regex = Regex(
-    buf: buf,
-    bytecode: bcseq
-  )
+  var regex = Regex(bytecode: bcseq)
+  when defined(debug):
+    regex.buf = buf
   return ok(regex)
 
 func countBackslashes(buf: string; i: int): int =
@@ -133,13 +128,15 @@ proc exec*(regex: Regex; str: string; start = 0; length = -1; nocaps = false):
     result.success = true
     if captureCount == 0 or nocaps:
       break
+    var caps: seq[RegexCapture] = @[]
     let cstrAddress = cast[int](cstr)
     let ps = start
     start = capture[1] - cstrAddress
     for i in 0 ..< captureCount:
       let s = capture[i * 2] - cstrAddress
       let e = capture[i * 2 + 1] - cstrAddress
-      result.captures.add((s, e, i))
+      caps.add((s, e))
+    result.captures.add(caps)
     if LRE_FLAG_GLOBAL notin flags:
       break
     if start >= str.len:
diff --git a/src/server/buffer.nim b/src/server/buffer.nim
index 6b214b4e..9a141135 100644
--- a/src/server/buffer.nim
+++ b/src/server/buffer.nim
@@ -594,8 +594,8 @@ proc findPrevMatch*(buffer: Buffer; regex: Regex; cursorx, cursory: int;
   let b = buffer.cursorBytes(y, cursorx)
   let res = regex.exec(buffer.lines[y].str, 0, b)
   var numfound = 0
-  if res.success and res.captures.len > 0:
-    let cap = res.captures[^1]
+  if res.captures.len > 0:
+    let cap = res.captures[^1][0]
     let x = buffer.lines[y].str.width(0, cap.s)
     let str = buffer.lines[y].str.substr(cap.s, cap.e - 1)
     inc numfound
@@ -609,8 +609,8 @@ proc findPrevMatch*(buffer: Buffer; regex: Regex; cursorx, cursory: int;
       else:
         break
     let res = regex.exec(buffer.lines[y].str)
-    if res.success and res.captures.len > 0:
-      let cap = res.captures[^1]
+    if res.captures.len > 0:
+      let cap = res.captures[^1][0]
       let x = buffer.lines[y].str.width(0, cap.s)
       let str = buffer.lines[y].str.substr(cap.s, cap.e - 1)
       inc numfound
@@ -628,7 +628,7 @@ proc findNextMatch*(buffer: Buffer; regex: Regex; cursorx, cursory: int;
   let res = regex.exec(buffer.lines[y].str, b, buffer.lines[y].str.len)
   var numfound = 0
   if res.success and res.captures.len > 0:
-    let cap = res.captures[0]
+    let cap = res.captures[0][0]
     let x = buffer.lines[y].str.width(0, cap.s)
     let str = buffer.lines[y].str.substr(cap.s, cap.e - 1)
     inc numfound
@@ -643,7 +643,7 @@ proc findNextMatch*(buffer: Buffer; regex: Regex; cursorx, cursory: int;
         break
     let res = regex.exec(buffer.lines[y].str)
     if res.success and res.captures.len > 0:
-      let cap = res.captures[0]
+      let cap = res.captures[0][0]
       let x = buffer.lines[y].str.width(0, cap.s)
       let str = buffer.lines[y].str.substr(cap.s, cap.e - 1)
       inc numfound
@@ -1779,10 +1779,8 @@ proc markURL*(buffer: Buffer; schemes: seq[string]) {.proxy.} =
           var data = ""
           var j = 0
           for cap in res.captures.mitems:
-            if cap.i != 0:
-              continue
-            let capLen = cap.e - cap.s
-            while j < cap.s:
+            let capLen = cap[0].e - cap[0].s
+            while j < cap[0].s:
               case (let c = text.data[j]; c)
               of '<':
                 data &= "&lt;"
@@ -1802,13 +1800,13 @@ proc markURL*(buffer: Buffer; schemes: seq[string]) {.proxy.} =
               else:
                 data &= c
               inc j
-            cap.s += offset
-            cap.e += offset
+            cap[0].s += offset
+            cap[0].e += offset
             let s = text.data[j ..< j + capLen]
             let news = "<a href=\"" & s & "\">" & s.htmlEscape() & "</a>"
             data &= news
-            j += cap.e - cap.s
-            offset += news.len - (cap.e - cap.s)
+            j += cap[0].e - cap[0].s
+            offset += news.len - (cap[0].e - cap[0].s)
           while j < text.data.len:
             case (let c = text.data[j]; c)
             of '<': data &= "&lt;"