about summary refs log tree commit diff stats
path: root/src/local
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2025-02-11 16:17:09 +0100
committerbptato <nincsnevem662@gmail.com>2025-02-26 19:58:08 +0100
commit55ffd92756faa3b60e3472404025a18509e0fce2 (patch)
tree5ce18a089ad3c657a3270000d01f64f7b5717b6a /src/local
parent7ba1c5de335468f77d891b31ab5d0536f1addd25 (diff)
downloadchawan-55ffd92756faa3b60e3472404025a18509e0fce2.tar.gz
dynstream: remove exceptions
Now we just pass down the value of n and check errno, plus
readDataLoop/writeDataLoop returns a bool indicating whether it failed.
For now this seems to work OK, but maybe I'll add a better abstraction
in the future.

EOFError is still used for handling failed packets; this is brittle,
and should be replaced once we have a proper buffering mechanism for
them.  (That will also let us kill BufStream.)

Unrelated: this also fixes a bug in buffer with cacheId.
Diffstat (limited to 'src/local')
-rw-r--r--src/local/container.nim24
-rw-r--r--src/local/pager.nim73
-rw-r--r--src/local/term.nim14
3 files changed, 60 insertions, 51 deletions
diff --git a/src/local/container.nim b/src/local/container.nim
index 0039197d..980e95bc 100644
--- a/src/local/container.nim
+++ b/src/local/container.nim
@@ -1596,7 +1596,7 @@ proc readCanceled*(container: Container) =
 proc readSuccess*(container: Container; s: string; fd: cint = -1) =
   let p = container.iface.readSuccess(s, fd != -1)
   if fd != -1:
-    container.iface.stream.sflush()
+    doAssert container.iface.stream.flush()
     container.iface.stream.source.withPacketWriter w:
       w.sendAux.add(fd)
   p.then(proc(res: Request) =
@@ -1707,11 +1707,14 @@ func hoverImage(container: Container): string {.jsfget.} =
 func hoverCachedImage(container: Container): string {.jsfget.} =
   return container.hoverText[htCachedImage]
 
-proc handleCommand(container: Container) =
+# Returns false on I/O error.
+proc handleCommand(container: Container): bool =
   var packet {.noinit.}: array[3, int] # 0 len, 1 auxLen, 2 packetid
-  container.iface.stream.recvDataLoop(addr packet[0], sizeof(packet))
+  if not container.iface.stream.readDataLoop(addr packet[0], sizeof(packet)):
+    return false
   assert packet[1] == 0 # no ancillary data possible for BufStream
   container.iface.resolve(packet[2], packet[0] - sizeof(packet[2]), packet[1])
+  return true
 
 proc startLoad(container: Container) =
   if container.config.headless == hmFalse:
@@ -1755,7 +1758,9 @@ proc onReadLine(container: Container; w: Slice[int];
     return newResolvedPromise()
 
 # Synchronously read all lines in the buffer.
-proc readLines*(container: Container; handle: proc(line: SimpleFlexibleLine)) =
+# Returns false on I/O error.
+proc readLines*(container: Container; handle: proc(line: SimpleFlexibleLine)):
+    bool =
   # load succeded
   let w = 0 .. 23
   container.iface.getLines(w).then(proc(res: GetLinesResult): EmptyPromise =
@@ -1772,7 +1777,9 @@ proc readLines*(container: Container; handle: proc(line: SimpleFlexibleLine)) =
   )
   while container.iface.hasPromises:
     # fulfill all promises
-    container.handleCommand()
+    if not container.handleCommand():
+      return false
+  return true
 
 proc drawLines*(container: Container; display: var FixedGrid; hlcolor: CellColor) =
   let bgcolor = container.bgcolor
@@ -1864,11 +1871,14 @@ func findCachedImage*(container: Container; image: PosBitmap;
       return it
   return nil
 
-proc handleEvent*(container: Container) =
-  container.handleCommand()
+# Returns false on I/O error.
+proc handleEvent*(container: Container): bool =
+  if not container.handleCommand():
+    return false
   if container.needslines:
     container.requestLines()
     container.needslines = false
+  return true
 
 proc addContainerModule*(ctx: JSContext) =
   ctx.registerType(Highlight)
diff --git a/src/local/pager.nim b/src/local/pager.nim
index 457cde8d..ca067c3d 100644
--- a/src/local/pager.nim
+++ b/src/local/pager.nim
@@ -968,9 +968,9 @@ proc drawBufferAdvance(s: openArray[char]; bgcolor: CellColor; oi, ox: var int;
   ox = x
   return move(ls)
 
-proc drawBuffer*(pager: Pager; container: Container; ofile: File) =
+proc drawBuffer*(pager: Pager; container: Container; ofile: File): bool =
   var format = Format()
-  container.readLines(proc(line: SimpleFlexibleLine) =
+  let res = container.readLines(proc(line: SimpleFlexibleLine) =
     var x = 0
     var w = -1
     var i = 0
@@ -997,6 +997,7 @@ proc drawBuffer*(pager: Pager; container: Container; ofile: File) =
     ofile.writeLine(s)
   )
   ofile.flushFile()
+  res
 
 proc redraw(pager: Pager) {.jsfunc.} =
   pager.term.clearCanvas()
@@ -2431,10 +2432,13 @@ proc writeToFile(istream: PosixStream; outpath: string): bool =
     return false
   var buffer {.noinit.}: array[4096, uint8]
   while true:
-    let n = istream.recvData(buffer)
+    let n = istream.readData(buffer)
+    if n < 0:
+      return false
     if n == 0:
       break
-    ps.sendDataLoop(buffer.toOpenArray(0, n - 1))
+    if not ps.writeDataLoop(buffer.toOpenArray(0, n - 1)):
+      break
   ps.sclose()
   true
 
@@ -3020,8 +3024,7 @@ proc openMenu(pager: Pager; x = -1; y = -1) {.jsfunc.} =
   pager.menu = newSelect(options, -1, x, y, pager.bufWidth, pager.bufHeight,
     menuFinish, pager)
 
-proc handleEvent0(pager: Pager; container: Container; event: ContainerEvent):
-    bool =
+proc handleEvent0(pager: Pager; container: Container; event: ContainerEvent) =
   case event.t
   of cetLoaded:
     dec pager.numload
@@ -3101,23 +3104,18 @@ proc handleEvent0(pager: Pager; container: Container; event: ContainerEvent):
               pager.refreshAllowed.incl($url)
               pager.metaRefresh(container, n, url)
           )
-  return true
 
 proc handleEvents(pager: Pager; container: Container) =
   while (let event = container.popEvent(); event != nil):
-    if not pager.handleEvent0(container, event):
-      break
+    pager.handleEvent0(container, event)
 
 proc handleEvents(pager: Pager) =
   if pager.container != nil:
     pager.handleEvents(pager.container)
 
 proc handleEvent(pager: Pager; container: Container) =
-  try:
-    container.handleEvent()
+  if container.handleEvent():
     pager.handleEvents(container)
-  except IOError:
-    discard
 
 proc runCommand(pager: Pager) =
   if pager.scommand != "":
@@ -3152,30 +3150,27 @@ proc handleStderr(pager: Pager) =
   let estream = pager.forkserver.estream
   var hadlf = true
   while true:
-    try:
-      let n = estream.recvData(buffer)
-      if n == 0:
-        break
-      var i = 0
-      while i < n:
-        var j = n
-        var found = false
-        for k in i ..< n:
-          if buffer[k] == '\n':
-            j = k + 1
-            found = true
-            break
-        if hadlf:
-          pager.console.err.write(prefix)
-        if j - i > 0:
-          pager.console.err.write(buffer.toOpenArray(i, j - 1))
-        i = j
-        hadlf = found
-    except ErrorAgain:
+    let n = estream.readData(buffer)
+    if n <= 0:
       break
+    var i = 0
+    while i < n:
+      var j = n
+      var found = false
+      for k in i ..< n:
+        if buffer[k] == '\n':
+          j = k + 1
+          found = true
+          break
+      if hadlf:
+        pager.console.err.write(prefix)
+      if j - i > 0:
+        pager.console.err.write(buffer.toOpenArray(i, j - 1))
+      i = j
+      hadlf = found
   if not hadlf:
     pager.console.err.write('\n')
-  pager.console.err.sflush()
+  discard pager.console.err.flush()
 
 proc handleRead(pager: Pager; fd: int) =
   if pager.term.istream != nil and fd == pager.term.istream.fd:
@@ -3250,10 +3245,7 @@ proc setupSigwinch(pager: Pager): PosixStream =
   gwriter = writer
   onSignal SIGWINCH:
     discard sig
-    try:
-      gwriter.sendDataLoop([0u8])
-    except ErrorAgain:
-      discard
+    discard gwriter.writeData([0u8])
   let reader = newPosixStream(pipefd[0])
   reader.setCloseOnExec()
   reader.setBlocking(false)
@@ -3333,10 +3325,9 @@ proc headlessLoop(pager: Pager) =
 proc dumpBuffers(pager: Pager) =
   pager.headlessLoop()
   for container in pager.containers:
-    try:
-      pager.drawBuffer(container, stdout)
+    if pager.drawBuffer(container, stdout):
       pager.handleEvents(container)
-    except IOError:
+    else:
       pager.console.error("Error in buffer", $container.url)
       # check for errors
       pager.handleRead(pager.forkserver.estream.fd)
diff --git a/src/local/term.nim b/src/local/term.nim
index 3aff214d..236599f2 100644
--- a/src/local/term.nim
+++ b/src/local/term.nim
@@ -245,9 +245,14 @@ when TermcapFound:
   func cap(term: Terminal; c: TermcapCap): lent string =
     return term.tc.caps[c]
 
+proc write0(term: Terminal; buffer: openArray[char]) =
+  if not term.ostream.writeDataLoop(buffer):
+    stderr.writeLine("Error writing to stdout")
+    quit(1)
+
 proc flush*(term: Terminal) =
   if term.obufLen > 0:
-    term.ostream.sendDataLoop(term.obuf.toOpenArray(0, term.obufLen - 1))
+    term.write0(term.obuf.toOpenArray(0, term.obufLen - 1))
     term.obufLen = 0
 
 proc write(term: Terminal; s: openArray[char]) =
@@ -255,7 +260,7 @@ proc write(term: Terminal; s: openArray[char]) =
     if s.len + term.obufLen > term.obuf.len:
       term.flush()
     if s.len > term.obuf.len:
-      term.ostream.sendDataLoop(s)
+      term.write0(s)
     else:
       copyMem(addr term.obuf[term.obufLen], unsafeAddr s[0], s.len)
       term.obufLen += s.len
@@ -263,7 +268,10 @@ proc write(term: Terminal; s: openArray[char]) =
 proc readChar*(term: Terminal): char =
   if term.ibufn == term.ibufLen:
     term.ibufn = 0
-    term.ibufLen = term.istream.recvData(term.ibuf)
+    term.ibufLen = term.istream.readData(term.ibuf)
+    if term.ibufLen == -1:
+      stderr.writeLine("Error reading from stdin")
+      quit(1)
   result = term.ibuf[term.ibufn]
   inc term.ibufn