about summary refs log tree commit diff stats
path: root/src/client.nim
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2022-07-13 21:52:51 +0200
committerbptato <nincsnevem662@gmail.com>2022-07-13 22:56:28 +0200
commite780de79f0193a67a74b834c9bfbf2e0ef8e3c03 (patch)
tree727ef914f75fff8dc5cf49be05cc14bf26bb806e /src/client.nim
parent2f0ea08df1e6884da51ea510cc352395e853cfc0 (diff)
downloadchawan-e780de79f0193a67a74b834c9bfbf2e0ef8e3c03.tar.gz
Initial QuickJS integration
Diffstat (limited to 'src/client.nim')
-rw-r--r--src/client.nim79
1 files changed, 75 insertions, 4 deletions
diff --git a/src/client.nim b/src/client.nim
index 66cd0c41..16e30b00 100644
--- a/src/client.nim
+++ b/src/client.nim
@@ -1,18 +1,20 @@
-import streams
-import terminal
 import options
 import os
+import streams
+import terminal
 
 import css/sheet
 import config/config
 import io/buffer
 import io/lineedit
 import io/loader
+import js/javascript
 import types/url
 import utils/twtstr
 
 type
-  Client* = ref object
+  Client* = ref ClientObj
+  ClientObj = object
     buffer: Buffer
     feednext: bool
     s: string
@@ -20,14 +22,48 @@ type
     errormessage: string
     userstyle: CSSStylesheet
     loader: FileLoader
+    jsrt: JSRuntime
+    jsctx: JSContext
 
   ActionError = object of IOError
   LoadError = object of ActionError
   InterruptError = object of LoadError
 
+proc js_console_log(ctx: JSContext, this: JSValue, argc: int, argv: ptr JSValue): JSValue {.cdecl.} =
+  let opaque = ctx.getOpaque()
+  for i in 0..<argc:
+    let arg = getJSObject(ctx, argv, i)
+    if i != 0:
+      opaque.err &= ' '
+    let str = arg.toString()
+    if str.isnone:
+      return JS_EXCEPTION
+    opaque.err &= str.get
+  opaque.err &= '\n'
+  return JS_UNDEFINED
+
+# Probably never called, but just in case...
+proc `=destroy`(client: var ClientObj) =
+  if client.jsctx != nil:
+    let opaque = client.jsctx.getOpaque()
+    if opaque != nil:
+      dealloc(opaque)
+    free(client.jsctx)
+  if client.jsrt != nil:
+    free(client.jsrt)
+
 proc newClient*(): Client =
   new(result)
   result.loader = newFileLoader()
+  let rt = newJSRuntime()
+  let ctx = rt.newJSContext()
+  result.jsrt = rt
+  result.jsctx = ctx
+  let global = ctx.getGlobalObject()
+  let console = newJSObject(result.jsctx)
+  console.setFunctionProperty("log", js_console_log)
+  console.setProperty("console", console)
+  free(global)
 
 proc loadError(s: string) =
   raise newException(LoadError, s)
@@ -118,7 +154,6 @@ proc gotoUrl(client: Client, url: Url, click = none(ClickAction), prevurl = none
             interruptError())
         client.buffer.istream = page.s
         client.buffer.contenttype = if ctype != "": ctype else: page.contenttype
-        client.buffer.streamclosed = false
       else:
         loadError("Couldn't load " & $url)
     except IOError, OSError:
@@ -192,6 +227,41 @@ proc toggleSource*(client: Client) =
       client.buffer.contenttype = "text/html"
     client.setupBuffer()
 
+proc command(client: Client) =
+  var iput: string
+  print(HVP(client.buffer.height + 1, 1))
+  print(EL())
+  let status = readLine("COMMAND: ", iput, client.buffer.width)
+  if status and iput.len > 0:
+    let ret = client.jsctx.eval(iput, "<stdin>", JS_EVAL_TYPE_GLOBAL)
+    let opaque = client.jsctx.getOpaque()
+    if ret.isException():
+      let ex = client.jsctx.getException()
+      let str = ex.toString()
+      if str.issome:
+        opaque.err &= str.get & '\n'
+      let stack = ex.getProperty("stack")
+      if not stack.isUndefined():
+        let str = stack.toString()
+        if str.issome:
+          opaque.err &= str.get & '\n'
+      free(stack)
+      free(ex)
+    else:
+      let str = ret.toString()
+      if str.issome:
+        opaque.err &= str.get & '\n'
+    free(ret)
+    client.addBuffer()
+    g_client = client
+    setControlCHook(proc() {.noconv.} =
+      if g_client.buffer.prev != nil or g_client.buffer.next != nil:
+        g_client.discardBuffer()
+      interruptError())
+    client.buffer.istream = newStringStream(opaque.err)
+    client.buffer.contenttype = "text/plain"
+    client.setupBuffer()
+
 proc quit(client: Client) =
   eraseScreen()
   print(HVP(0, 0))
@@ -248,6 +318,7 @@ proc input(client: Client) =
   of ACTION_PREV_BUFFER: client.prevBuffer()
   of ACTION_NEXT_BUFFER: client.nextBuffer()
   of ACTION_DISCARD_BUFFER: client.discardBuffer()
+  of ACTION_COMMAND: client.command()
   else: discard
 
 proc inputLoop(client: Client) =