about summary refs log tree commit diff stats
path: root/src/local/client.nim
diff options
context:
space:
mode:
Diffstat (limited to 'src/local/client.nim')
-rw-r--r--src/local/client.nim140
1 files changed, 26 insertions, 114 deletions
diff --git a/src/local/client.nim b/src/local/client.nim
index 8b16339f..7c5fabb9 100644
--- a/src/local/client.nim
+++ b/src/local/client.nim
@@ -61,7 +61,6 @@ type
     consoleWrapper: ConsoleWrapper
     fdmap: Table[int, Container]
     feednext: bool
-    ibuf: string
     jsctx: JSContext
     jsrt: JSRuntime
     pager {.jsget.}: Pager
@@ -87,15 +86,8 @@ template loader(client: Client): FileLoader =
 template forkserver(client: Client): ForkServer =
   client.pager.forkserver
 
-proc readChar(client: Client): char =
-  if client.ibuf == "":
-    try:
-      return client.pager.infile.readChar()
-    except EOFError:
-      quit(1)
-  else:
-    result = client.ibuf[0]
-    client.ibuf.delete(0..0)
+template readChar(client: Client): char =
+  client.pager.term.readChar()
 
 proc finalize(client: Client) {.jsfin.} =
   if client.jsctx != nil:
@@ -110,14 +102,15 @@ proc fetch[T: Request|string](client: Client, req: T,
 
 proc interruptHandler(rt: JSRuntime, opaque: pointer): cint {.cdecl.} =
   let client = cast[Client](opaque)
-  if client.console == nil or client.pager.infile == nil: return
+  if client.console == nil or client.pager.term.istream == nil:
+    return 0
   try:
-    let c = client.pager.infile.readChar()
+    let c = client.pager.term.istream.sreadChar()
     if c == char(3): #C-c
-      client.ibuf = ""
+      client.pager.term.ibuf = ""
       return 1
     else:
-      client.ibuf &= c
+      client.pager.term.ibuf &= c
   except IOError:
     discard
   return 0
@@ -212,83 +205,6 @@ proc evalAction(client: Client, action: string, arg0: int32): EmptyPromise =
   JS_FreeValue(ctx, ret)
   return p
 
-type
-  MouseInputType = enum
-    mitPress = "press", mitRelease = "release", mitMove = "move"
-
-  MouseInputMod = enum
-    mimShift = "shift", mimCtrl = "ctrl", mimMeta = "meta"
-
-  MouseInputButton = enum
-    mibLeft = (1, "left")
-    mibMiddle = (2, "middle")
-    mibRight = (3, "right")
-    mibWheelUp = (4, "wheelUp")
-    mibWheelDown = (5, "wheelDown")
-    mibWheelLeft = (6, "wheelLeft")
-    mibWheelRight = (7, "wheelRight")
-    mibThumbInner = (8, "thumbInner")
-    mibThumbTip = (9, "thumbTip")
-    mibButton10 = (10, "button10")
-    mibButton11 = (11, "button11")
-
-  MouseInput = object
-    t: MouseInputType
-    button: MouseInputButton
-    mods: set[MouseInputMod]
-    col: int
-    row: int
-
-proc parseMouseInput(client: Client): Opt[MouseInput] =
-  template fail =
-    return err()
-  var btn = 0
-  while (let c = client.readChar(); c != ';'):
-    let n = decValue(c)
-    if n == -1:
-      fail
-    btn *= 10
-    btn += n
-  var mods: set[MouseInputMod] = {}
-  if (btn and 4) != 0:
-    mods.incl(mimShift)
-  if (btn and 8) != 0:
-    mods.incl(mimCtrl)
-  if (btn and 16) != 0:
-    mods.incl(mimMeta)
-  var px = 0
-  while (let c = client.readChar(); c != ';'):
-    let n = decValue(c)
-    if n == -1:
-      fail
-    px *= 10
-    px += n
-  var py = 0
-  var c: char
-  while (c = client.readChar(); c notin {'m', 'M'}):
-    let n = decValue(c)
-    if n == -1:
-      fail
-    py *= 10
-    py += n
-  var t = if c == 'M': mitPress else: mitRelease
-  if (btn and 32) != 0:
-    t = mitMove
-  var button = (btn and 3) + 1
-  if (btn and 64) != 0:
-    button += 3
-  if (btn and 128) != 0:
-    button += 7
-  if button notin int(MouseInputButton.low)..int(MouseInputButton.high):
-    return err()
-  ok(MouseInput(
-    t: t,
-    mods: mods,
-    button: MouseInputButton(button),
-    col: px - 1,
-    row: py - 1
-  ))
-
 # The maximum number we are willing to accept.
 # This should be fine for 32-bit signed ints (which precnum currently is).
 # We can always increase it further (e.g. by switching to uint32, uint64...) if
@@ -315,7 +231,7 @@ proc handleCommandInput(client: Client, c: char): EmptyPromise =
     return p
   if client.config.input.use_mouse:
     if client.pager.inputBuffer == "\e[<":
-      let input = client.parseMouseInput()
+      let input = client.pager.term.parseMouseInput()
       if input.isSome:
         let input = input.get
         let container = client.pager.container
@@ -516,11 +432,8 @@ proc acceptBuffers(client: Client) =
     pager.handleEvents(container)
   pager.procmap.setLen(0)
 
-proc c_setvbuf(f: File, buf: pointer, mode: cint, size: csize_t): cint {.
-  importc: "setvbuf", header: "<stdio.h>", tags: [].}
-
 proc handleRead(client: Client; fd: int) =
-  if client.pager.infile != nil and fd == client.pager.infile.getFileHandle():
+  if client.pager.term.istream != nil and fd == client.pager.term.istream.fd:
     client.input().then(proc() =
       client.handlePagerEvents()
     )
@@ -583,7 +496,7 @@ proc flushConsole*(client: Client) {.jsfunc.} =
   client.handleRead(client.forkserver.estream.fd)
 
 proc handleError(client: Client, fd: int) =
-  if client.pager.infile != nil and fd == client.pager.infile.getFileHandle():
+  if client.pager.term.istream != nil and fd == client.pager.term.istream.fd:
     #TODO do something here...
     stderr.write("Error in tty\n")
     quit(1)
@@ -616,8 +529,7 @@ proc handleError(client: Client, fd: int) =
 
 proc inputLoop(client: Client) =
   let selector = client.selector
-  discard c_setvbuf(client.pager.infile, nil, IONBF, 0)
-  selector.registerHandle(int(client.pager.infile.getFileHandle()), {Read}, 0)
+  selector.registerHandle(int(client.pager.term.istream.fd), {Read}, 0)
   let sigwinch = selector.registerSignal(int(SIGWINCH), 0)
   while true:
     let events = client.selector.select(-1)
@@ -775,18 +687,19 @@ proc dumpBuffers(client: Client) =
   stdout.close()
 
 proc launchClient*(client: Client; pages: seq[string];
-    contentType: Option[string]; cs: Charset; dump: bool;
-    warnings: seq[string]) =
-  var infile: File
+    contentType: Option[string]; cs: Charset; dump: bool) =
+  var istream: PosixStream
   var dump = dump
   if not dump:
     if stdin.isatty():
-      infile = stdin
-    if stdout.isatty():
-      if infile == nil:
-        dump = not open(infile, "/dev/tty", fmRead)
-    else:
-      dump = true
+      istream = newPosixStream(stdin.getFileHandle())
+    if istream == nil:
+      if stdout.isatty():
+        istream = newPosixStream("/dev/tty", O_RDONLY, 0)
+        if istream == nil:
+          dump = true
+      else:
+        dump = true
   let selector = newSelector[int]()
   let efd = int(client.forkserver.estream.fd)
   selector.registerHandle(efd, {Read}, 0)
@@ -794,15 +707,14 @@ proc launchClient*(client: Client; pages: seq[string];
     selector.registerHandle(fd, {Read}, 0)
   client.loader.unregisterFun = proc(fd: int) =
     selector.unregister(fd)
-  client.pager.launchPager(infile, selector)
-  client.pager.alerts.add(warnings)
+  client.pager.launchPager(istream, selector)
   let clearFun = proc() =
     client.clearConsole()
   let showFun = proc() =
     client.showConsole()
   let hideFun = proc() =
     client.hideConsole()
-  client.consoleWrapper = addConsole(client.pager, interactive = infile != nil,
+  client.consoleWrapper = client.pager.addConsole(interactive = istream != nil,
     clearFun, showFun, hideFun)
   #TODO passing console.err here makes it impossible to change it later. maybe
   # better associate it with jsctx
@@ -883,12 +795,12 @@ proc addJSModules(client: Client, ctx: JSContext) =
 func getClient(client: Client): Client {.jsfget: "client".} =
   return client
 
-proc newClient*(config: Config; forkserver: ForkServer; jsctx: JSContext):
-    Client =
+proc newClient*(config: Config; forkserver: ForkServer; jsctx: JSContext;
+    warnings: seq[string]): Client =
   setControlCHook(proc() {.noconv.} = quit(1))
   let jsrt = JS_GetRuntime(jsctx)
   JS_SetModuleLoaderFunc(jsrt, normalizeModuleName, clientLoadJSModule, nil)
-  let pager = newPager(config, forkserver, jsctx)
+  let pager = newPager(config, forkserver, jsctx, warnings)
   let loader = forkserver.newFileLoader(LoaderConfig(
     urimethodmap: config.external.urimethodmap,
     w3mCGICompat: config.external.w3m_cgi_compat,