about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2021-12-20 20:11:31 +0100
committerbptato <nincsnevem662@gmail.com>2021-12-20 20:11:38 +0100
commitbbb14729f8b0c612f79ba96566d0118fc8c2290d (patch)
tree6c686d8f40ca37255dcf550bf653e244d7105247 /src
parentcbcdafaf3fab6129c8c387bc352bd1f17f663684 (diff)
downloadchawan-bbb14729f8b0c612f79ba96566d0118fc8c2290d.tar.gz
Add client for buffer control
Diffstat (limited to 'src')
-rw-r--r--src/client.nim173
-rw-r--r--src/io/buffer.nim161
-rw-r--r--src/main.nim76
3 files changed, 221 insertions, 189 deletions
diff --git a/src/client.nim b/src/client.nim
new file mode 100644
index 00000000..41962288
--- /dev/null
+++ b/src/client.nim
@@ -0,0 +1,173 @@
+import httpclient
+import streams
+import uri
+import terminal
+
+import io/buffer
+import io/lineedit
+import config/config
+import html/parser
+import utils/twtstr
+
+type
+  Client* = ref object
+    http: HttpClient
+    buffers: seq[Buffer]
+    prevuri: Uri
+    feednext: bool
+    s: string
+
+proc loadRemotePage*(client: Client, url: string): string =
+  return client.http.getContent(url)
+
+proc loadLocalPage*(url: string): string =
+  return readFile(url)
+
+proc getRemotePage*(client: Client, url: string): Stream =
+  return client.http.get(url).bodyStream
+
+proc getLocalPage*(url: string): Stream =
+  return newFileStream(url, fmRead)
+
+proc getPageUri(client: Client, uri: Uri): Stream =
+  var moduri = uri
+  moduri.anchor = ""
+  if uri.scheme == "" or uri.scheme == "file":
+    return getLocalPage($moduri)
+  else:
+    return client.getRemotePage($moduri)
+
+proc die() =
+  eprint "Invalid parameters. Usage:\ntwt <url>"
+  quit(1)
+
+proc newClient*(): Client =
+  new(result)
+  result.http = newHttpClient()
+
+proc addBuffer(client: Client) =
+  client.buffers.add(newBuffer())
+
+func buffer(client: Client): Buffer =
+  return client.buffers[^1]
+
+proc setupBuffer*(client: Client) =
+  let buffer = client.buffer
+  buffer.setLocation(client.prevuri)
+  buffer.document = parseHtml(newStringStream(client.buffer.source))
+  buffer.render()
+  buffer.gotoAnchor()
+  buffer.redraw = true
+
+proc readPipe(client: Client) =
+  if not stdin.isatty:
+    client.buffer.showsource = true
+    try:
+      while true:
+        client.buffer.source &= stdin.readChar()
+    except EOFError:
+      #TODO handle failure (also, is this even portable at all?)
+      discard reopen(stdin, "/dev/tty", fmReadWrite);
+  else:
+    die()
+  client.setupBuffer()
+
+proc gotoURL(client: Client, url: string) =
+  var newuri = parseUri(url)
+  let newanchor = newuri.anchor
+  let prevanchor = client.prevuri.anchor
+  client.prevuri.anchor = ""
+  newuri.anchor = ""
+  let prevs = $client.prevuri
+  let news = $newuri
+  client.prevuri.anchor = prevanchor
+  newuri.anchor = newanchor
+  if news != "":
+    client.addBuffer()
+    client.buffer.source = client.getPageUri(newuri).readAll() #TODO
+  elif prevanchor != newanchor:
+    let psource = client.buffer.source
+    client.addBuffer()
+    client.buffer.source = psource
+
+  client.prevuri = newuri
+  client.setupBuffer()
+
+proc changeLocation(client: Client) =
+  let buffer = client.buffer
+  var url = $buffer.location
+  print(HVP(buffer.height + 1, 1))
+  print(EL())
+  let status = readLine("URL: ", url, buffer.width)
+  if status:
+    client.gotoURL(url)
+
+proc click(client: Client) =
+  let s = client.buffer.click()
+  if s != "":
+    client.gotoURL(s)
+
+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:
+    eraseScreen()
+    print(HVP(0, 0))
+    quit(0)
+  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_LINE_INFO: buffer.lineInfo()
+  of ACTION_FEED_NEXT: client.feednext = true
+  of ACTION_RELOAD: client.gotoURL($buffer.location)
+  of ACTION_RESHAPE: buffer.reshape = true
+  of ACTION_REDRAW: buffer.redraw = true
+  of ACTION_TOGGLE_SOURCE: buffer.toggleSource()
+  else: discard
+
+proc launchClient*(client: Client, params: seq[string]) =
+  client.addBuffer()
+
+  if params.len < 1:
+    client.readPipe()
+  else: 
+    client.gotoURL(params[0])
+
+  while true:
+    client.buffer.refreshBuffer()
+    client.input()
diff --git a/src/io/buffer.nim b/src/io/buffer.nim
index 922d45ac..3180aa2b 100644
--- a/src/io/buffer.nim
+++ b/src/io/buffer.nim
@@ -14,7 +14,6 @@ import layout/box
 import layout/engine
 import config/config
 import io/term
-import io/lineedit
 import io/cell
 
 type
@@ -37,17 +36,19 @@ type
     document*: Document
     redraw*: bool
     reshape*: bool
+    nostatus*: bool
     location*: Uri
+    target*: string
     source*: string
     showsource*: bool
     rootbox*: CSSBox
     prevnodes*: seq[Node]
 
-func newBuffer*(attrs: TermAttributes): Buffer =
+proc newBuffer*(): Buffer =
   new(result)
-  result.width = attrs.width
-  result.height = attrs.height - 1
-  result.attrs = attrs
+  result.attrs = getTermAttributes()
+  result.width = result.attrs.width
+  result.height = result.attrs.height - 1
 
   result.display = newFixedGrid(result.width, result.height)
   result.prevdisplay = newFixedGrid(result.width, result.height)
@@ -677,8 +678,8 @@ proc scrollLeft*(buffer: Buffer) =
       buffer.cursorLeft()
     buffer.redraw = true
 
-proc gotoAnchor*(buffer: Buffer, id: string) =
-  let anchor = buffer.document.getElementById(id)
+proc gotoAnchor*(buffer: Buffer) =
+  let anchor = buffer.document.getElementById(buffer.location.anchor)
   if anchor == nil: return
   for y in 0..(buffer.numLines - 1):
     let line = buffer.lines[y]
@@ -881,13 +882,13 @@ proc renderDocument*(buffer: Buffer) =
       dec i
   buffer.updateCursor()
 
-proc reshapeBuffer*(buffer: Buffer) =
+proc render*(buffer: Buffer) =
   if buffer.showsource:
     buffer.renderPlainText(buffer.source)
   else:
     buffer.renderDocument()
 
-proc cursorBufferPos(buffer: Buffer) =
+proc cursorBufferPos*(buffer: Buffer) =
   let x = max(buffer.cursorx - buffer.fromx, 0)
   let y = buffer.cursory - buffer.fromy
   print(HVP(y + 1, x + 1))
@@ -913,127 +914,57 @@ proc statusMsgForBuffer(buffer: Buffer) =
     msg &= " " & buffer.hovertext
   buffer.setStatusMessage(msg.ansiStyle(styleReverse).ansiReset())
 
+proc lineInfo*(buffer: Buffer) =
+    buffer.setStatusMessage("line " & $(buffer.cursory + 1) & "/" & $buffer.numLines & " col " & $(buffer.cursorx + 1) & "/" & $buffer.currentLineWidth() & " cell width: " & $buffer.currentDisplayCell().width())
+    buffer.nostatus = true
+
 proc displayBufferSwapOutput(buffer: Buffer) =
   print(buffer.generateSwapOutput())
 
 proc displayBuffer(buffer: Buffer) =
   print(buffer.generateFullOutput())
 
-proc displayStatusMessage(buffer: Buffer) =
+proc displayStatusMessage*(buffer: Buffer) =
   print(HVP(buffer.height + 1, 1))
   print(SGR())
   print(buffer.generateStatusMessage())
   print(EL())
 
-proc inputLoop(attrs: TermAttributes, buffer: Buffer): bool =
-  var s = ""
-  var feedNext = false
-  while true:
+proc toggleSource*(buffer: Buffer) =
+  buffer.showsource = not buffer.showsource
+  buffer.reshape = true
+  buffer.redraw = true
+
+proc click*(buffer: Buffer): string =
+  let link = buffer.getCursorLink()
+  if link != nil:
+    if link.tagType == TAG_A:
+      return HTMLAnchorElement(link).href
+  return ""
+
+proc refreshBuffer*(buffer: Buffer) =
+  stdout.hideCursor()
+
+  if buffer.refreshTermAttrs():
+    buffer.redraw = true
+    buffer.reshape = true
+
+  if buffer.redraw:
+    buffer.refreshDisplay()
+    buffer.displayBuffer()
     buffer.redraw = false
-    buffer.displayStatusMessage()
-    stdout.showCursor()
-    buffer.cursorBufferPos()
-    if not feedNext:
-      s = ""
-    else:
-      feedNext = false
-
-    let c = getch()
-    s &= c
-    let action = getNormalAction(s)
-    var nostatus = false
-    case action
-    of ACTION_QUIT:
-      eraseScreen()
-      print(HVP(0, 0))
-      return false
-    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:
-      discard
-    of ACTION_CHANGE_LOCATION:
-      var url = $buffer.location
-
-      print(HVP(buffer.height + 1, 1))
-      print(EL())
-      let status = readLine("URL: ", url, buffer.width)
-      if status:
-        buffer.setLocation(parseUri(url))
-        return true
-    of ACTION_LINE_INFO:
-      buffer.setStatusMessage("line " & $(buffer.cursory + 1) & "/" & $buffer.numLines & " col " & $(buffer.cursorx + 1) & "/" & $buffer.currentLineWidth() & " cell width: " & $buffer.currentDisplayCell().width())
-      nostatus = true
-    of ACTION_FEED_NEXT:
-      feedNext = true
-    of ACTION_RELOAD: return true
-    of ACTION_RESHAPE:
-      buffer.reshape = true
-    of ACTION_REDRAW: buffer.redraw = true
-    of ACTION_TOGGLE_SOURCE:
-      buffer.showsource = not buffer.showsource
-      buffer.reshape = true
-      buffer.redraw = true
-    else: discard
-    stdout.hideCursor()
-
-    if buffer.refreshTermAttrs():
-      buffer.redraw = true
-      buffer.reshape = true
-
-    if buffer.redraw:
-      buffer.refreshDisplay()
-      buffer.displayBuffer()
-      buffer.redraw = false
-
-    buffer.updateHover()
-    if buffer.reshape:
-      buffer.reshapeBuffer()
-      buffer.reshape = false
-      buffer.refreshDisplay()
-      buffer.displayBufferSwapOutput()
-
-    if not nostatus:
-      buffer.statusMsgForBuffer()
-    else:
-      nostatus = false
 
-proc displayPage*(attrs: TermAttributes, buffer: Buffer): bool =
-  eprint buffer.location.anchor
-  buffer.gotoAnchor(buffer.location.anchor)
-  buffer.refreshDisplay()
-  buffer.displayBuffer()
   buffer.updateHover()
   if buffer.reshape:
-    buffer.reshapeBuffer()
+    buffer.render()
     buffer.reshape = false
     buffer.refreshDisplay()
     buffer.displayBufferSwapOutput()
-  buffer.statusMsgForBuffer()
-  return inputLoop(attrs, buffer)
+
+  if not buffer.nostatus:
+    buffer.statusMsgForBuffer()
+  else:
+    buffer.nostatus = false
+  buffer.displayStatusMessage()
+  buffer.cursorBufferPos()
+  stdout.showCursor()
diff --git a/src/main.nim b/src/main.nim
index 1bb8cf1e..5e783e53 100644
--- a/src/main.nim
+++ b/src/main.nim
@@ -1,83 +1,11 @@
-import httpclient
-import uri
 import os
-import streams
-import terminal
 when defined(profile):
   import nimprof
 
-import html/parser
-import io/buffer
-import io/term
+import client
 import config/config
 import utils/twtstr
 
-let clientInstance = newHttpClient()
-proc loadRemotePage*(url: string): string =
-  return clientInstance.getContent(url)
-
-proc loadLocalPage*(url: string): string =
-  return readFile(url)
-
-proc getRemotePage*(url: string): Stream =
-  return clientInstance.get(url).bodyStream
-
-proc getLocalPage*(url: string): Stream =
-  return newFileStream(url, fmRead)
-
-proc getPageUri(uri: Uri): Stream =
-  var moduri = uri
-  moduri.anchor = ""
-  if uri.scheme == "" or uri.scheme == "file":
-    return getLocalPage($moduri)
-  else:
-    return getRemotePage($moduri)
-
-var buffers: seq[Buffer]
-
-proc die() =
-  eprint "Invalid parameters. Usage:\ntwt <url>"
-  quit(1)
-
-proc main*() =
-  let attrs = getTermAttributes()
-  let buffer = newBuffer(attrs)
-  buffers.add(buffer)
-
-  var lastUri: Uri
-  if paramCount() < 1:
-    if not isatty(stdin):
-      buffer.showsource = true
-      try:
-        while true:
-          buffer.source &= stdin.readChar()
-      except EOFError:
-        #TODO handle failure (also, is this even portable at all?)
-        discard reopen(stdin, "/dev/tty", fmReadWrite);
-    else:
-      die()
-    buffer.setLocation(lastUri)
-  else: 
-    lastUri = parseUri(paramStr(1))
-    buffer.source = getPageUri(lastUri).readAll() #TODO get rid of this
-
-  buffer.setLocation(lastUri)
-  buffer.document = parseHtml(newStringStream(buffer.source))
-  buffer.renderDocument()
-  while displayPage(attrs, buffer):
-    buffer.setStatusMessage("Loading...")
-    var newUri = buffer.location
-    lastUri.anchor = ""
-    newUri.anchor = ""
-    if $lastUri != $newUri:
-      buffer.clearBuffer()
-      if lastUri.scheme == "" and lastUri.path == "" and lastUri.anchor != "":
-        discard
-      else:
-        buffer.document = parseHtml(getPageUri(buffer.location))
-      buffer.renderPlainText(getPageUri(lastUri).readAll())
-    lastUri = newUri
-
 readConfig()
 width_table = makewidthtable(gconfig.ambiguous_double)
-main()
+newClient().launchClient(commandLineParams())