diff options
author | bptato <nincsnevem662@gmail.com> | 2021-12-20 20:11:31 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2021-12-20 20:11:38 +0100 |
commit | bbb14729f8b0c612f79ba96566d0118fc8c2290d (patch) | |
tree | 6c686d8f40ca37255dcf550bf653e244d7105247 /src | |
parent | cbcdafaf3fab6129c8c387bc352bd1f17f663684 (diff) | |
download | chawan-bbb14729f8b0c612f79ba96566d0118fc8c2290d.tar.gz |
Add client for buffer control
Diffstat (limited to 'src')
-rw-r--r-- | src/client.nim | 173 | ||||
-rw-r--r-- | src/io/buffer.nim | 161 | ||||
-rw-r--r-- | src/main.nim | 76 |
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()) |