about summary refs log tree commit diff stats
path: root/src/client.nim
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2022-09-12 00:30:21 +0200
committerbptato <nincsnevem662@gmail.com>2022-09-12 00:30:21 +0200
commit51ea622d58bfca19212fac1800cfb033bb85ec39 (patch)
treeb75891690f67b190c60584751f2a30c96f342fdc /src/client.nim
parente38402dfa1bbc33db6b9d9736517eb45533d595c (diff)
downloadchawan-51ea622d58bfca19212fac1800cfb033bb85ec39.tar.gz
Add JS binding generation
Diffstat (limited to 'src/client.nim')
-rw-r--r--src/client.nim564
1 files changed, 0 insertions, 564 deletions
diff --git a/src/client.nim b/src/client.nim
deleted file mode 100644
index eb48a30a..00000000
--- a/src/client.nim
+++ /dev/null
@@ -1,564 +0,0 @@
-import options
-import os
-import streams
-import terminal
-import unicode
-
-import css/sheet
-import config/config
-import io/buffer
-import io/cell
-import io/lineedit
-import io/loader
-import io/request
-import io/term
-import js/javascript
-import js/regex
-import types/url
-import utils/twtstr
-
-type
-  Client* = ref ClientObj
-  ClientObj = object
-    buffer: Buffer
-    feednext: bool
-    s: string
-    iserror: bool
-    errormessage: string
-    userstyle: CSSStylesheet
-    loader: FileLoader
-    jsrt: JSRuntime
-    jsctx: JSContext
-    regex: Option[Regex]
-    revsearch: bool
-    needsauth: bool
-    redirecturl: Option[Url]
-
-  ActionError = object of IOError
-  LoadError = object of ActionError
-  InterruptError = object of LoadError
-
-proc statusMode(client: Client) =
-  print(HVP(client.buffer.height + 1, 1))
-  print(EL())
-
-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
-
-proc `=destroy`(client: var ClientObj) =
-  if client.jsctx != nil:
-    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
-  var global = ctx.getGlobalObject()
-  let console = newJSObject(result.jsctx)
-  console.setFunctionProperty("log", js_console_log)
-  global.setProperty("console", console)
-  free(global)
-
-proc loadError(s: string) =
-  raise newException(LoadError, s)
-
-proc actionError(s: string) =
-  raise newException(ActionError, s)
-
-proc interruptError() =
-  raise newException(InterruptError, "Interrupted")
-
-proc addBuffer(client: Client) =
-  if client.buffer == nil:
-    client.buffer = newBuffer()
-  else:
-    let oldnext = client.buffer.next
-    client.buffer.next = newBuffer()
-    if oldnext != nil:
-      oldnext.prev = client.buffer.next
-    client.buffer.next.prev = client.buffer
-    client.buffer.next.next = oldnext
-    client.buffer = client.buffer.next
-  client.buffer.loader = client.loader
-  client.buffer.userstyle = client.userstyle
-  client.buffer.markcolor = gconfig.markcolor
-
-proc prevBuffer(client: Client) =
-  if client.buffer.prev != nil:
-    client.buffer = client.buffer.prev
-    client.buffer.redraw = true
-
-proc nextBuffer(client: Client) =
-  if client.buffer.next != nil:
-    client.buffer = client.buffer.next
-    client.buffer.redraw = true
-
-proc discardBuffer(buffer: Buffer) =
-  if buffer.next != nil:
-    if buffer.sourcepair != nil:
-      buffer.sourcepair.sourcepair = nil
-    buffer.next.prev = buffer.prev
-    buffer.redraw = true
-  elif buffer.prev != nil:
-    if buffer.sourcepair != nil:
-      buffer.sourcepair.sourcepair = nil
-    buffer.prev.next = buffer.next
-    buffer.redraw = true
-
-proc discardBuffer(client: Client) =
-  if client.buffer.next != nil:
-    if client.buffer.sourcepair != nil:
-      client.buffer.sourcepair.sourcepair = nil
-    client.buffer.next.prev = client.buffer.prev
-    client.buffer = client.buffer.next
-    client.buffer.redraw = true
-  elif client.buffer.prev != nil:
-    if client.buffer.sourcepair != nil:
-      client.buffer.sourcepair.sourcepair = nil
-    client.buffer.prev.next = client.buffer.next
-    client.buffer = client.buffer.prev
-    client.buffer.redraw = true
-  else:
-    actionError("Can't discard last buffer!")
-
-proc setupBuffer(client: Client) =
-  let buffer = client.buffer
-  buffer.load()
-  buffer.render()
-  buffer.gotoAnchor()
-  buffer.redraw = true
-
-proc dupeBuffer(client: Client, location = none(Url)) =
-  let prev = client.buffer
-  client.addBuffer()
-  client.buffer.contenttype = prev.contenttype
-  client.buffer.ispipe = prev.ispipe
-  client.buffer.istream = newStringStream(prev.source)
-  if location.issome:
-    client.buffer.location = location.get
-  else:
-    client.buffer.location = prev.location
-  client.buffer.document = prev.document
-  client.setupBuffer()
-
-proc readPipe(client: Client, ctype: string) =
-  client.addBuffer()
-  client.buffer.contenttype = if ctype != "": ctype else: "text/plain"
-  client.buffer.ispipe = true
-  client.buffer.istream = newFileStream(stdin)
-  const url = parseUrl("file://-").get
-  client.buffer.location = url
-  client.buffer.load()
-  #TODO is this portable at all?
-  if reopen(stdin, "/dev/tty", fmReadWrite):
-    client.setupBuffer()
-  else:
-    client.buffer.drawBuffer()
-
-# Load request in a new buffer.
-var g_client: Client
-proc gotoUrl(client: Client, request: Request, prevurl = none(Url), force = false, ctype = "") =
-  setControlCHook(proc() {.noconv.} =
-    raise newException(InterruptError, "Interrupted"))
-  if force or prevurl.isnone or not prevurl.get.equals(request.url, true) or
-      prevurl.get.equals(request.url) or request.httpmethod != HTTP_GET:
-    let page = client.loader.doRequest(request)
-    client.needsauth = page.status == 401 # Unauthorized
-    client.redirecturl = page.redirect
-    if page.body != nil:
-      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.contenttype = if ctype != "": ctype else: page.contenttype
-      client.buffer.istream = page.body
-      client.buffer.location = request.url
-      client.setupBuffer()
-    else:
-      loadError("Couldn't load " & $request.url & " (" & $page.res & ")")
-  elif client.buffer != nil and prevurl.issome and prevurl.get.equals(request.url, true):
-    if client.buffer.hasAnchor(request.url.anchor):
-      client.dupeBuffer(request.url.some)
-    else:
-      loadError("Couldn't find anchor " & request.url.anchor)
-
-# Relative gotoUrl: either to prevurl, or if that's none, client.buffer.url.
-proc gotoUrl(client: Client, url: string, prevurl = none(Url), force = false, ctype = "") =
-  var prevurl = prevurl
-  if prevurl.isnone and client.buffer != nil:
-    prevurl = client.buffer.location.some
-  let newurl = parseUrl(url, prevurl)
-  if newurl.isnone:
-    loadError("Invalid URL " & url)
-  client.gotoUrl(newRequest(newurl.get), prevurl, force, ctype)
-
-# When the user has passed a partial URL as an argument, they might've meant
-# either:
-# * file://$PWD/<file>
-# * https://<url>
-# So we attempt to load both, and see what works.
-# (TODO: make this optional)
-proc loadUrl(client: Client, url: string, ctype = "") =
-  let firstparse = parseUrl(url)
-  if firstparse.issome:
-    client.gotoUrl(newRequest(firstparse.get), none(Url), true, ctype)
-  else:
-    let cdir = parseUrl("file://" & getCurrentDir() & DirSep)
-    try:
-      # attempt to load local file
-      client.gotoUrl(url, cdir, true, ctype)
-    except LoadError:
-      try:
-        # attempt to load local file (this time percent encoded)
-        client.gotoUrl(percentEncode(url, LocalPathPercentEncodeSet), cdir, true, ctype)
-      except LoadError:
-        # attempt to load remote page
-        client.gotoUrl("https://" & url, none(Url), true, ctype)
-
-# Reload the page in a new buffer, then kill the previous buffer.
-proc reloadPage(client: Client) =
-  let buf = client.buffer
-  client.gotoUrl(newRequest(client.buffer.location), none(Url), true, client.buffer.contenttype)
-  discardBuffer(buf)
-
-# Open a URL prompt and visit the specified URL.
-proc changeLocation(client: Client) =
-  let buffer = client.buffer
-  var url = buffer.location.serialize(true)
-  client.statusMode()
-  let status = readLine("URL: ", url, buffer.width)
-  if status:
-    client.loadUrl(url)
-
-proc click(client: Client) =
-  let req = client.buffer.click()
-  if req.issome:
-    client.gotoUrl(req.get, client.buffer.location.some)
-
-proc toggleSource*(client: Client) =
-  let buffer = client.buffer
-  if buffer.sourcepair != nil:
-    client.buffer = buffer.sourcepair
-    client.buffer.redraw = true
-  else:
-    client.addBuffer()
-    client.buffer.sourcepair = client.buffer.prev
-    client.buffer.sourcepair.sourcepair = client.buffer
-    client.buffer.source = client.buffer.prev.source
-    client.buffer.streamclosed = true
-    client.buffer.location = client.buffer.sourcepair.location
-    client.buffer.ispipe = client.buffer.sourcepair.ispipe
-    let prevtype = client.buffer.prev.contenttype
-    if prevtype == "text/html":
-      client.buffer.contenttype = "text/plain"
-    else:
-      client.buffer.contenttype = "text/html"
-    client.setupBuffer()
-
-proc command(client: Client) =
-  var iput: string
-  client.statusMode()
-  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'
-      var 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 searchNext(client: Client) =
-  if client.regex.issome:
-    if not client.revsearch:
-      discard client.buffer.cursorNextMatch(client.regex.get)
-    else:
-      discard client.buffer.cursorPrevMatch(client.regex.get)
-
-proc searchPrev(client: Client) =
-  if client.regex.issome:
-    if not client.revsearch:
-      discard client.buffer.cursorPrevMatch(client.regex.get)
-    else:
-      discard client.buffer.cursorNextMatch(client.regex.get)
-
-proc search(client: Client) =
-  client.statusMode()
-  var iput: string
-  let status = readLine("/", iput, client.buffer.width)
-  if status:
-    if iput.len != 0:
-      client.regex = compileSearchRegex(iput)
-    client.revsearch = false
-    client.searchNext()
-
-proc searchBack(client: Client) =
-  client.statusMode()
-  var iput: string
-  let status = readLine("?", iput, client.buffer.width)
-  if status:
-    if iput.len != 0:
-      client.regex = compileSearchRegex(iput)
-    client.revsearch = true
-    client.searchNext()
-
-proc isearch(client: Client) =
-  client.statusMode()
-  var iput: string
-  let cpos = client.buffer.cpos
-  var mark: Mark
-  template del_mark() =
-    if mark != nil:
-      client.buffer.removeMark(mark)
-
-  let status = readLine("/", iput, client.buffer.width, {}, false, (proc(state: var LineState): bool =
-    del_mark
-    let regex = compileSearchRegex($state.news)
-    client.buffer.cpos = cpos
-    if regex.issome:
-      let match = client.buffer.cursorNextMatch(regex.get)
-      if match.success:
-        mark = client.buffer.addMark(match.x, match.y, match.str.width())
-        client.buffer.redraw = true
-        client.buffer.refreshBuffer(true)
-        print(HVP(client.buffer.height + 1, 2))
-        print(SGR())
-      else:
-        del_mark
-        client.buffer.redraw = true
-        client.buffer.refreshBuffer(true)
-        print(HVP(client.buffer.height + 1, 2))
-        print(SGR())
-      return true
-    false
-  ))
-
-  del_mark
-  client.buffer.redraw = true
-  client.buffer.refreshBuffer(true)
-  if status:
-    client.regex = compileSearchRegex(iput)
-  else:
-    client.buffer.cpos = cpos
-
-proc isearchBack(client: Client) =
-  client.statusMode()
-  var iput: string
-  let cpos = client.buffer.cpos
-  var mark: Mark
-  template del_mark() =
-    if mark != nil:
-      client.buffer.removeMark(mark)
-  let status = readLine("?", iput, client.buffer.width, {}, false, (proc(state: var LineState): bool =
-    del_mark
-    let regex = compileSearchRegex($state.news)
-    client.buffer.cpos = cpos
-    if regex.issome:
-      let match = client.buffer.cursorPrevMatch(regex.get)
-      if match.success:
-        mark = client.buffer.addMark(match.x, match.y, match.str.width())
-        client.buffer.redraw = true
-        client.buffer.refreshBuffer(true)
-        print(HVP(client.buffer.height + 1, 2))
-        print(SGR())
-      else:
-        del_mark
-        client.buffer.redraw = true
-        client.buffer.refreshBuffer(true)
-        print(HVP(client.buffer.height + 1, 2))
-        print(SGR())
-      return true
-    false
-  ))
-  del_mark
-  client.buffer.redraw = true
-  if status:
-    client.regex = compileSearchRegex(iput)
-  else:
-    client.buffer.cpos = cpos
-
-proc quit(client: Client) =
-  eraseScreen()
-  print(HVP(0, 0))
-  quit(0)
-
-proc input(client: Client) =
-  let buffer = client.buffer
-  if not client.feednext:
-    client.s = ""
-  else:
-    client.feednext = false
-  let c = getch()
-  client.s &= c
-  let action = getNormalAction(client.s)
-  case action
-  of ACTION_QUIT: client.quit()
-  of ACTION_CURSOR_LEFT: buffer.cursorLeft()
-  of ACTION_CURSOR_DOWN: buffer.cursorDown()
-  of ACTION_CURSOR_UP: buffer.cursorUp()
-  of ACTION_CURSOR_RIGHT: buffer.cursorRight()
-  of ACTION_CURSOR_LINEBEGIN: buffer.cursorLineBegin()
-  of ACTION_CURSOR_LINEEND: buffer.cursorLineEnd()
-  of ACTION_CURSOR_NEXT_WORD: buffer.cursorNextWord()
-  of ACTION_CURSOR_PREV_WORD: buffer.cursorPrevWord()
-  of ACTION_CURSOR_NEXT_LINK: buffer.cursorNextLink()
-  of ACTION_CURSOR_PREV_LINK: buffer.cursorPrevLink()
-  of ACTION_PAGE_DOWN: buffer.pageDown()
-  of ACTION_PAGE_UP: buffer.pageUp()
-  of ACTION_PAGE_RIGHT: buffer.pageRight()
-  of ACTION_PAGE_LEFT: buffer.pageLeft()
-  of ACTION_HALF_PAGE_DOWN: buffer.halfPageDown()
-  of ACTION_HALF_PAGE_UP: buffer.halfPageUp()
-  of ACTION_CURSOR_FIRST_LINE: buffer.cursorFirstLine()
-  of ACTION_CURSOR_LAST_LINE: buffer.cursorLastLine()
-  of ACTION_CURSOR_TOP: buffer.cursorTop()
-  of ACTION_CURSOR_MIDDLE: buffer.cursorMiddle()
-  of ACTION_CURSOR_BOTTOM: buffer.cursorBottom()
-  of ACTION_CURSOR_LEFT_EDGE: buffer.cursorLeftEdge()
-  of ACTION_CURSOR_VERT_MIDDLE: buffer.cursorVertMiddle()
-  of ACTION_CURSOR_RIGHT_EDGE: buffer.cursorRightEdge()
-  of ACTION_CENTER_LINE: buffer.centerLine()
-  of ACTION_SCROLL_DOWN: buffer.scrollDown()
-  of ACTION_SCROLL_UP: buffer.scrollUp()
-  of ACTION_SCROLL_LEFT: buffer.scrollLeft()
-  of ACTION_SCROLL_RIGHT: buffer.scrollRight()
-  of ACTION_CLICK: client.click()
-  of ACTION_CHANGE_LOCATION: client.changeLocation()
-  of ACTION_DUPE_BUFFER: client.dupeBuffer()
-  of ACTION_LINE_INFO: buffer.lineInfo()
-  of ACTION_FEED_NEXT: client.feednext = true
-  of ACTION_RELOAD: client.reloadPage()
-  of ACTION_RESHAPE: buffer.reshape = true
-  of ACTION_REDRAW: buffer.redraw = true
-  of ACTION_TOGGLE_SOURCE: client.toggleSource()
-  of ACTION_PREV_BUFFER: client.prevBuffer()
-  of ACTION_NEXT_BUFFER: client.nextBuffer()
-  of ACTION_DISCARD_BUFFER: client.discardBuffer()
-  of ACTION_COMMAND: client.command()
-  of ACTION_SEARCH: client.search()
-  of ACTION_SEARCH_BACK: client.searchBack()
-  of ACTION_ISEARCH: client.isearch()
-  of ACTION_ISEARCH_BACK: client.isearchBack()
-  of ACTION_SEARCH_NEXT: client.searchNext()
-  of ACTION_SEARCH_PREV: client.searchPrev()
-  else: discard
-
-proc followRedirect(client: Client)
-
-proc checkAuth(client: Client) =
-  if client.needsauth:
-    client.buffer.refreshBuffer()
-    client.statusMode()
-    var username = ""
-    let ustatus = readLine("Username: ", username, client.buffer.width)
-    if not ustatus:
-      client.needsauth = false
-      return
-    client.statusMode()
-    var password = ""
-    let pstatus = readLine("Password: ", password, client.buffer.width, hide = true)
-    if not pstatus:
-      client.needsauth = false
-      return
-    var url = client.buffer.location
-    url.username = username
-    url.password = password
-    var buf = client.buffer
-    client.gotoUrl(newRequest(url), prevurl = some(client.buffer.location))
-    discardBuffer(buf)
-    client.followRedirect()
-
-proc followRedirect(client: Client) =
-  while client.redirecturl.issome:
-    client.statusMode()
-    print("Redirecting to ", $client.redirecturl.get)
-    stdout.flushFile()
-    client.buffer.refreshBuffer(true)
-    var buf = client.buffer
-    let redirecturl = client.redirecturl.get
-    client.redirecturl = none(Url)
-    client.gotoUrl(newRequest(redirecturl), prevurl = some(client.buffer.location))
-    discardBuffer(buf)
-    if client.needsauth:
-      client.checkAuth()
-
-proc inputLoop(client: Client) =
-  while true:
-    g_client = client
-    setControlCHook(proc() {.noconv.} =
-      g_client.buffer.setStatusMessage("Interrupted rendering procedure")
-      g_client.buffer.redraw = true
-      g_client.buffer.reshape = false
-      g_client.inputLoop())
-    client.followRedirect()
-    client.checkAuth()
-    client.buffer.refreshBuffer()
-    if client.needsauth: # Unauthorized
-      client.checkAuth()
-    try:
-      client.input()
-    except ActionError as e:
-      client.buffer.setStatusMessage(e.msg)
-
-proc launchClient*(client: Client, pages: seq[string], ctype: string, dump: bool) =
-  client.userstyle = gconfig.stylesheet.parseStylesheet()
-  if not stdin.isatty:
-    client.readPipe(ctype)
-  try:
-    for page in pages:
-      client.loadUrl(page, ctype)
-  except LoadError as e:
-    eprint e.msg
-    quit(1)
-
-  if stdout.isatty and not dump:
-    when defined(posix):
-      enableRawMode()
-    client.inputLoop()
-  else:
-    var buffer = client.buffer
-    while buffer.next != nil:
-      buffer = buffer.next
-
-    buffer.drawBuffer()
-    while buffer.prev != nil:
-      buffer = buffer.prev
-      buffer.drawBuffer()