diff options
author | bptato <nincsnevem662@gmail.com> | 2022-11-27 15:44:42 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2022-11-27 15:44:42 +0100 |
commit | 3a12afa7617f3ccecbbf6b5852da3d6382a412bb (patch) | |
tree | 7596ce7f667b9dabec6ec71c9bd05b9de67feb93 /src/buffer | |
parent | e7f157c792f53cb084e8694ee608f00727432a3d (diff) | |
download | chawan-3a12afa7617f3ccecbbf6b5852da3d6382a412bb.tar.gz |
Fix some regressions, add loading progress bar
Diffstat (limited to 'src/buffer')
-rw-r--r-- | src/buffer/buffer.nim | 201 | ||||
-rw-r--r-- | src/buffer/cell.nim | 44 | ||||
-rw-r--r-- | src/buffer/container.nim | 138 |
3 files changed, 195 insertions, 188 deletions
diff --git a/src/buffer/buffer.nim b/src/buffer/buffer.nim index 458b5b17..a2860952 100644 --- a/src/buffer/buffer.nim +++ b/src/buffer/buffer.nim @@ -44,9 +44,6 @@ type CLICK, FIND_NEXT_LINK, FIND_PREV_LINK, FIND_NEXT_MATCH, FIND_PREV_MATCH, GET_SOURCE, GET_LINES, UPDATE_HOVER, PASS_FD, CONNECT, GOTO_ANCHOR - ContainerCommand* = enum - BUFFER_READY, RESHAPE, FULFILL_PROMISE - BufferMatch* = object success*: bool x*: int @@ -59,14 +56,13 @@ type contenttype: string lines: FlexibleGrid rendered: bool - bsource: BufferSource + source: BufferSource width: int height: int attrs: WindowAttributes document: Document viewport: Viewport prevstyled: StyledNode - reshape: bool location: Url selector: Selector[int] istream: Stream @@ -74,9 +70,9 @@ type available: int pistream: Stream # for input pipe postream: Stream # for output pipe + srenderer: StreamRenderer streamclosed: bool loaded: bool - source: string prevnode: StyledNode loader: FileLoader config: BufferConfig @@ -115,18 +111,24 @@ proc fulfill*(iface: BufferInterface, packetid, len: int) = promise.cb() promise = promise.next +proc hasPromises*(iface: BufferInterface): bool = + return iface.promises.len > 0 + proc then*(promise: EmptyPromise, cb: (proc())): EmptyPromise {.discardable.} = + if promise == nil: return promise.cb = cb promise.next = EmptyPromise() return promise.next proc then*[T](promise: Promise[T], cb: (proc(x: T))): EmptyPromise {.discardable.} = + if promise == nil: return return promise.then(proc() = if promise.stream != nil: promise.stream.sread(promise.res) cb(promise.res)) proc then*[T, U](promise: Promise[T], cb: (proc(x: T): Promise[U])): Promise[U] {.discardable.} = + if promise == nil: return let next = Promise[U]() promise.then(proc(x: T) = let p2 = cb(x) @@ -136,30 +138,6 @@ proc then*[T, U](promise: Promise[T], cb: (proc(x: T): Promise[U])): Promise[U] next.cb())) return next -macro writeCommand(buffer: Buffer, cmd: ContainerCommand, args: varargs[typed]) = - let cmdblock = newStmtList() - var idlist: seq[NimNode] - var i = 0 - for arg in args: - let id = ident("arg_" & $i) - idlist.add(id) - cmdblock.add(quote do: - let `id` = `arg`) - inc i - let lens = ident("lens") - cmdblock.add(quote do: - if `cmd` != BUFFER_READY: return - var `lens` = slen(`cmd`)) - for id in idlist: - cmdblock.add(quote do: `lens` += slen(`id`)) - cmdblock.add(quote do: `buffer`.postream.swrite(`lens`)) - cmdblock.add(quote do: `buffer`.postream.swrite(`cmd`)) - for id in idlist: - cmdblock.add(quote do: - `buffer`.postream.swrite(`id`)) - cmdblock.add(quote do: `buffer`.postream.flush()) - return newBlockStmt(cmdblock) - proc buildInterfaceProc(fun: NimNode): tuple[fun, name: NimNode] = let name = fun[0] # sym let params = fun[3] # formalparams @@ -172,6 +150,7 @@ proc buildInterfaceProc(fun: NimNode): tuple[fun, name: NimNode] = let nup = ident(x) # add this to enums let this2 = newIdentDefs(ident("iface"), ident("BufferInterface")) let thisval = this2[0] + let n = name.strVal body.add(quote do: `thisval`.stream.swrite(BufferCommand.`nup`) `thisval`.stream.swrite(`thisval`.packetid)) @@ -430,6 +409,7 @@ proc gotoAnchor*(buffer: Buffer): tuple[x, y: int] {.proxy.} = let format = line.formats[i] if format.node != nil and anchor in format.node.node: return (format.pos, y) + return (-1, -1) proc do_reshape(buffer: Buffer) = case buffer.contenttype @@ -440,7 +420,8 @@ proc do_reshape(buffer: Buffer) = buffer.lines = ret[0] buffer.prevstyled = ret[1] else: - buffer.lines = renderPlainText(buffer.source) + buffer.lines.renderStream(buffer.srenderer, buffer.available) + buffer.available = 0 proc windowChange*(buffer: Buffer, attrs: WindowAttributes) {.proxy.} = buffer.attrs = attrs @@ -453,6 +434,7 @@ type UpdateHoverResult* = object repaint*: bool proc updateHover*(buffer: Buffer, cursorx, cursory: int): UpdateHoverResult {.proxy.} = + if buffer.lines.len == 0: return var thisnode: StyledNode let i = buffer.lines[cursory].findFormatN(cursorx) - 1 if i >= 0: @@ -465,7 +447,6 @@ proc updateHover*(buffer: Buffer, cursorx, cursory: int): UpdateHoverResult {.pr let elem = Element(styledNode.node) if not elem.hover: elem.hover = true - buffer.reshape = true result.repaint = true let link = thisnode.getLink() @@ -479,8 +460,9 @@ proc updateHover*(buffer: Buffer, cursorx, cursory: int): UpdateHoverResult {.pr let elem = Element(styledNode.node) if elem.hover: elem.hover = false - buffer.reshape = true result.repaint = true + if result.repaint: + buffer.do_reshape() buffer.prevnode = thisnode @@ -517,13 +499,13 @@ proc c_setvbuf(f: File, buf: pointer, mode: cint, size: csize_t): cint {. func getFd(buffer: Buffer): int = if buffer.streamclosed: return -1 - let source = buffer.bsource + let source = buffer.source case source.t of CLONE, LOAD_REQUEST: let istream = SocketStream(buffer.istream) return cast[FileHandle](istream.source.getFd()) of LOAD_PIPE: - return buffer.bsource.fd + return buffer.source.fd type ConnectResult* = tuple[code: int, needsAuth: bool, redirect: Option[URL], contentType: string] @@ -531,7 +513,7 @@ proc setupSource(buffer: Buffer): ConnectResult = if buffer.loaded: result.code = -2 return - let source = buffer.bsource + let source = buffer.source let setct = source.contenttype.isNone if not setct: buffer.contenttype = source.contenttype.get @@ -562,6 +544,7 @@ proc setupSource(buffer: Buffer): ConnectResult = if setct: buffer.contenttype = response.contenttype buffer.istream = response.body + SocketStream(buffer.istream).recvw = true result.needsAuth = response.status == 401 # Unauthorized result.redirect = response.redirect if setct: @@ -569,56 +552,55 @@ proc setupSource(buffer: Buffer): ConnectResult = buffer.selector.registerHandle(cast[int](buffer.getFd()), {Read}, 1) buffer.loaded = true -proc load0(buffer: Buffer): auto = - if buffer.contenttype == "text/html": - if not buffer.streamclosed: - buffer.source = buffer.istream.readAll() - buffer.istream.close() - buffer.istream = newStringStream(buffer.source) - buffer.document = parseHTML5(buffer.istream) - buffer.streamclosed = true - else: - buffer.document = parseHTML5(newStringStream(buffer.source)) - buffer.document.location = buffer.location - buffer.loadResources(buffer.document) - return (true, buffer.document.title) - return (false, "") - proc connect*(buffer: Buffer): ConnectResult {.proxy.} = let code = buffer.setupSource() return code -proc load*(buffer: Buffer): tuple[success: bool, title: string] {.proxy.} = - return buffer.load0() +const BufferSize = 4096 + +proc load*(buffer: Buffer): tuple[atend: bool, lines, bytes: int] {.proxy.} = + var bytes = -1 + if buffer.streamclosed: return (true, buffer.lines.len, bytes) + let op = buffer.sstream.getPosition() + let s = buffer.istream.readStr(BufferSize) + buffer.sstream.setPosition(op + buffer.available) + buffer.sstream.write(s) + buffer.sstream.setPosition(op) + buffer.available += s.len + case buffer.contenttype + of "text/html": + bytes = buffer.available + else: + buffer.do_reshape() + return (buffer.istream.atEnd, buffer.lines.len, bytes) proc render*(buffer: Buffer): int {.proxy.} = buffer.do_reshape() return buffer.lines.len -proc load2(buffer: Buffer) = - case buffer.contenttype - of "text/html": - #assert false, "Not implemented yet..." - discard - else: - # This is incredibly stupid but it works so whatever. - # (We're basically recv'ing single bytes, but nim std/net does buffering - # for us so we should be ok?) - if not buffer.streamclosed: - let c = buffer.istream.readChar() - buffer.source &= c - buffer.do_reshape() - proc finishLoad(buffer: Buffer) = - if buffer.contenttype != "text/html" and not buffer.streamclosed: - if not buffer.istream.atEnd: - let a = buffer.istream.readAll() + if buffer.streamclosed: return + if not buffer.istream.atEnd: + let op = buffer.sstream.getPosition() + buffer.sstream.setPosition(op + buffer.available) + while not buffer.istream.atEnd: + let a = buffer.istream.readStr(BufferSize) buffer.sstream.write(a) buffer.available += a.len - buffer.reshape = true - buffer.selector.unregister(int(buffer.getFd())) - buffer.istream.close() - buffer.streamclosed = true + buffer.sstream.setPosition(op) + case buffer.contenttype + of "text/html": + buffer.sstream.setPosition(0) + buffer.available = 0 + buffer.document = parseHTML5(buffer.sstream) + buffer.document.location = buffer.location + buffer.loadResources(buffer.document) + buffer.do_reshape() + else: + buffer.do_reshape() + buffer.selector.unregister(int(buffer.getFd())) + buffer.istream.close() + buffer.streamclosed = true # https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#constructing-the-form-data-set proc constructEntryList(form: HTMLFormElement, submitter: Element = nil, encoding: string = ""): seq[tuple[name, value: string]] = @@ -788,17 +770,19 @@ proc submitForm(form: HTMLFormElement, submitter: Element): Option[Request] = assert formmethod == FORM_METHOD_POST getActionUrl -template set_focus(e: Element) = +template set_focus(buffer: Buffer, e: Element) = if buffer.document.focus != e: buffer.document.focus = e - buffer.reshape = true + buffer.do_reshape() -template restore_focus = +template restore_focus(buffer: Buffer) = if buffer.document.focus != nil: buffer.document.focus = nil - buffer.reshape = true + buffer.do_reshape() -type ReadSuccessResult* = tuple[open: Option[Request], reshape: bool] +type ReadSuccessResult* = object + open*: Option[Request] + repaint*: bool proc readSuccess*(buffer: Buffer, s: string): ReadSuccessResult {.proxy.} = if buffer.input != nil: @@ -807,8 +791,8 @@ proc readSuccess*(buffer: Buffer, s: string): ReadSuccessResult {.proxy.} = of INPUT_SEARCH: input.value = s input.invalid = true - result.reshape = true - buffer.reshape = true + buffer.do_reshape() + result.repaint = true if input.form != nil: let submitaction = submitForm(input.form, input) if submitaction.isSome: @@ -816,16 +800,16 @@ proc readSuccess*(buffer: Buffer, s: string): ReadSuccessResult {.proxy.} = of INPUT_TEXT, INPUT_PASSWORD: input.value = s input.invalid = true - result.reshape = true - buffer.reshape = true + buffer.do_reshape() + result.repaint = true of INPUT_FILE: let cdir = parseUrl("file://" & getCurrentDir() & DirSep) let path = parseUrl(s, cdir) if path.issome: input.file = path input.invalid = true - result.reshape = true - buffer.reshape = true + buffer.do_reshape() + result.repaint = true else: discard buffer.input = nil @@ -844,9 +828,9 @@ proc click*(buffer: Buffer, cursorx, cursory: int): ClickResult {.proxy.} = if clickable != nil: case clickable.tagType of TAG_SELECT: - set_focus clickable + buffer.set_focus clickable of TAG_A: - restore_focus + buffer.restore_focus let url = parseUrl(HTMLAnchorElement(clickable).href, clickable.document.baseUrl.some) if url.issome: result.open = some(newRequest(url.get, HTTP_GET)) @@ -860,12 +844,12 @@ proc click*(buffer: Buffer, cursorx, cursory: int): ClickResult {.proxy.} = for option in select.options: option.selected = false option.selected = true - restore_focus + buffer.restore_focus else: # focus on select - set_focus select + buffer.set_focus select of TAG_INPUT: - restore_focus + buffer.restore_focus let input = HTMLInputElement(clickable) case input.inputType of INPUT_SEARCH: @@ -894,7 +878,7 @@ proc click*(buffer: Buffer, cursorx, cursory: int): ClickResult {.proxy.} = input.checked = not input.checked input.invalid = true result.repaint = true - buffer.reshape = true + buffer.do_reshape() of INPUT_RADIO: for radio in input.radiogroup: radio.checked = false @@ -902,19 +886,19 @@ proc click*(buffer: Buffer, cursorx, cursory: int): ClickResult {.proxy.} = input.checked = true input.invalid = true result.repaint = true - buffer.reshape = true + buffer.do_reshape() of INPUT_RESET: if input.form != nil: input.form.reset() result.repaint = true - buffer.reshape = true + buffer.do_reshape() of INPUT_SUBMIT, INPUT_BUTTON: if input.form != nil: result.open = submitForm(input.form, input) else: - restore_focus + buffer.restore_focus else: - restore_focus + buffer.restore_focus proc readCanceled*(buffer: Buffer) {.proxy.} = buffer.input = nil @@ -935,15 +919,14 @@ proc getLines*(buffer: Buffer, w: Slice[int]): seq[SimpleFlexibleLine] {.proxy.} proc passFd*(buffer: Buffer) {.proxy.} = let fd = SocketStream(buffer.pistream).recvFileHandle() - buffer.bsource.fd = fd + buffer.source.fd = fd proc getSource*(buffer: Buffer) {.proxy.} = let ssock = initServerSocket() let stream = ssock.acceptSocketStream() - if not buffer.streamclosed: - buffer.source = buffer.istream.readAll() - buffer.streamclosed = true - stream.write(buffer.source) + buffer.finishLoad() + buffer.sstream.setPosition(0) + stream.write(buffer.sstream.readAll()) stream.close() ssock.close() @@ -973,16 +956,14 @@ macro bufferDispatcher(funs: static ProxyMap, buffer: Buffer, cmd: BufferCommand let `rval` = `call`) if rval == nil: stmts.add(quote do: - let len = slen(FULFILL_PROMISE) + slen(`packetid`) + let len = slen(`packetid`) buffer.postream.swrite(len) - buffer.postream.swrite(FULFILL_PROMISE) buffer.postream.swrite(`packetid`) buffer.postream.flush()) else: stmts.add(quote do: - let len = slen(FULFILL_PROMISE) + slen(`packetid`) + slen(`rval`) + let len = slen(`packetid`) + slen(`rval`) buffer.postream.swrite(len) - buffer.postream.swrite(FULFILL_PROMISE) buffer.postream.swrite(`packetid`) buffer.postream.swrite(`rval`) buffer.postream.flush()) @@ -1009,18 +990,11 @@ proc runBuffer(buffer: Buffer, rfd: int) = buffer.readCommand() except IOError: break loop - else: - buffer.load2() if Error in event.events: if event.fd == rfd: break loop elif event.fd == buffer.getFd(): buffer.finishLoad() - if not buffer.alive: - break loop - if buffer.reshape and buffer.document != nil: #TODO null check shouldn't be needed? - buffer.reshape = false - buffer.do_reshape() buffer.pistream.close() buffer.postream.close() buffer.loader.quit() @@ -1035,18 +1009,19 @@ proc launchBuffer*(config: BufferConfig, source: BufferSource, attrs: attrs, config: config, loader: loader, - bsource: source, + source: source, sstream: newStringStream(), viewport: Viewport(window: attrs), width: attrs.width, height: attrs.height - 1 ) buffer.selector = newSelector[int]() + buffer.sstream = newStringStream() + buffer.srenderer = newStreamRenderer(buffer.sstream) let sstream = connectSocketStream(mainproc, false) sstream.swrite(getpid()) buffer.pistream = sstream buffer.postream = sstream - buffer.writeCommand(BUFFER_READY) let rfd = int(sstream.source.getFd()) buffer.selector.registerHandle(rfd, {Read}, 0) buffer.runBuffer(rfd) diff --git a/src/buffer/cell.nim b/src/buffer/cell.nim index 7c6ec00a..d7de064f 100644 --- a/src/buffer/cell.nim +++ b/src/buffer/cell.nim @@ -270,6 +270,50 @@ proc parseAnsiCode*(format: var Format, buf: string, fi: int): int = return i +type + AnsiCodeParseState* = enum + PARSE_START, PARSE_PARAMS, PARSE_INTERM, PARSE_FINAL, PARSE_DONE + + AnsiCodeParser* = object + state*: AnsiCodeParseState + params: string + +proc reset*(parser: var AnsiCodeParser) = + parser.state = PARSE_START + parser.params = "" + +proc parseAnsiCode*(parser: var AnsiCodeParser, format: var Format, c: char): bool = + case parser.state + of PARSE_START: + if 0x40 <= int(c) and int(c) <= 0x5F: + if c != '[': + #C1, TODO? + parser.state = PARSE_DONE + else: + parser.state = PARSE_PARAMS + else: + parser.state = PARSE_DONE + return true + of PARSE_PARAMS: + if 0x30 <= int(c) and int(c) <= 0x3F: + parser.params &= c + else: + parser.state = PARSE_INTERM + return parser.parseAnsiCode(format, c) + of PARSE_INTERM: + if 0x20 <= int(c) and int(c) <= 0x2F: + discard + else: + parser.state = PARSE_FINAL + return parser.parseAnsiCode(format, c) + of PARSE_FINAL: + parser.state = PARSE_DONE + if 0x40 <= int(c) and int(c) <= 0x7E: + format.handleAnsiCode(c, parser.params) + else: + return true + of PARSE_DONE: discard + proc parseAnsiCode*(format: var Format, stream: Stream) = if stream.atEnd(): return var c = stream.readChar() diff --git a/src/buffer/container.nim b/src/buffer/container.nim index f17267c3..58f93f42 100644 --- a/src/buffer/container.nim +++ b/src/buffer/container.nim @@ -80,8 +80,8 @@ type sourcepair*: Container pipeto: Container redraw*: bool - cmdvalid: array[ContainerCommand, bool] needslines*: bool + canceled: bool events*: seq[ContainerEvent] proc newBuffer*(dispatcher: Dispatcher, config: Config, source: BufferSource, title = ""): Container = @@ -99,7 +99,6 @@ proc newBuffer*(dispatcher: Dispatcher, config: Config, source: BufferSource, ti height: attrs.height - 1, contenttype: source.contenttype, title: title ) - result.cmdvalid[BUFFER_READY] = true istream.sread(result.process) result.pos.setx = -1 @@ -566,34 +565,45 @@ proc setLoadInfo(container: Container, msg: string) = container.triggerEvent(STATUS) proc load*(container: Container) = - container.loadinfo = "Connecting to " & $container.source.location + container.setLoadInfo("Connecting to " & $container.source.location & "...") + var onload: (proc(res: tuple[atend: bool, lines, bytes: int])) + onload = (proc(res: tuple[atend: bool, lines, bytes: int]) = + if res.bytes == -1: + container.setLoadInfo("") + elif not res.atend: + container.setLoadInfo(convert_size(res.bytes) & " loaded") + if res.lines > container.numLines: + container.numLines = res.lines + container.triggerEvent(STATUS) + container.requestLines() + if not res.atend and not container.canceled: + discard container.iface.load().then(onload) + elif not container.canceled: + container.iface.gotoAnchor().then(proc(res: tuple[x, y: int]) = + if res.x != -1 and res.y != -1: + container.setCursorXY(res.x, res.y) + ) + ) container.iface.connect().then(proc(res: ConnectResult): auto = - container.code = res.code if res.code != -2: + container.code = res.code if res.code == 0: + container.setLoadInfo("Connected to " & $container.source.location & ". Downloading...") if res.needsAuth: container.triggerEvent(NEEDS_AUTH) if res.redirect.isSome: + container.redirect = res.redirect container.triggerEvent(REDIRECT) if res.contentType != "": container.contenttype = some(res.contentType) - container.setLoadInfo("Downloading " & $container.source.location) return container.iface.load() else: + container.setLoadInfo("") container.triggerEvent(FAIL) - ).then(proc(res: tuple[success: bool, title: string]): auto = - if res.success: - container.title = res.title - container.setLoadInfo("Rendering " & $container.source.location) - return container.iface.render() - ).then(proc(lines: int): auto = - container.numLines = lines - container.setLoadInfo("") - container.needslines = true - return container.iface.gotoAnchor() - ).then(proc(res: tuple[x, y: int]) = - container.setCursorXY(res.x, res.y) - ) + ).then(onload) + +proc cancel*(container: Container) = + container.canceled = true proc findAnchor*(container: Container, anchor: string) = container.iface.findAnchor(anchor).then(proc(found: bool) = @@ -607,14 +617,15 @@ proc readCanceled*(container: Container) = proc readSuccess*(container: Container, s: string) = container.iface.readSuccess(s).then(proc(res: ReadSuccessResult) = - if res.reshape: + if res.repaint: container.needslines = true if res.open.isSome: container.triggerEvent(ContainerEvent(t: OPEN, request: res.open.get))) proc reshape*(container: Container, noreq = false) {.jsfunc.} = container.iface.render().then(proc(lines: int) = - container.numLines = lines) + container.numLines = lines + container.updateCursor()) if not noreq: container.needslines = true @@ -654,69 +665,46 @@ proc windowChange*(container: Container, attrs: WindowAttributes) = container.iface.windowChange(attrs).then(proc() = container.needslines = true) -proc handleCommand(container: Container, cmd: ContainerCommand, len: int): ContainerEvent = - if not container.cmdvalid[cmd] and false or cmd notin {FULFILL_PROMISE, BUFFER_READY}: - let len = len - sizeof(cmd) - #TODO TODO TODO - for i in 0 ..< len: - discard container.istream.readChar() - if cmd != RESHAPE: - return ContainerEvent(t: INVALID_COMMAND) - container.cmdvalid[cmd] = false - case cmd - of BUFFER_READY: - if container.source.t == LOAD_PIPE: - container.iface.passFd() - let s = SocketStream(container.ostream) - s.sendFileHandle(container.source.fd) - discard close(container.source.fd) - container.ostream.flush() - container.load() - of RESHAPE: - container.needslines = true - of FULFILL_PROMISE: - var packetid: int - container.istream.sread(packetid) - container.iface.fulfill(packetid, len - slen(packetid) - slen(FULFILL_PROMISE)) - if container.needslines: - container.requestLines() - container.needslines = false +proc handleCommand(container: Container) = + var packetid, len: int + container.istream.sread(len) + container.istream.sread(packetid) + container.iface.fulfill(packetid, len - slen(packetid)) proc setStream*(container: Container, stream: Stream) = container.istream = stream container.ostream = stream container.iface = newBufferInterface(stream) + if container.source.t == LOAD_PIPE: + container.iface.passFd() + let s = SocketStream(container.ostream) + s.sendFileHandle(container.source.fd) + discard close(container.source.fd) + container.ostream.flush() + container.load() # Synchronously read all lines in the buffer. iterator readLines*(container: Container): SimpleFlexibleLine {.inline.} = - var cmd: ContainerCommand - container.requestLines(0 .. -1) - var len: int - container.istream.sread(len) - container.istream.sread(cmd) - #TODO TODO TODO - #while cmd != SET_LINES: - # discard container.handleCommand(cmd, len) - # container.istream.sread(len) - # container.istream.sread(cmd) - #assert cmd == SET_LINES - var w: Slice[int] - container.istream.sread(container.numLines) - container.istream.sread(w) - var line: SimpleFlexibleLine - for y in 0 ..< w.len: - container.istream.sread(line) - yield line - -proc handleEvent*(container: Container): ContainerEvent = - var len: int - container.istream.sread(len) - var cmd: ContainerCommand - container.istream.sread(cmd) - if cmd > high(ContainerCommand): - return ContainerEvent(t: INVALID_COMMAND) - else: - return container.handleCommand(cmd, len) + while container.iface.hasPromises: + # Spin event loop till container has been loaded + container.handleCommand() + if container.code == 0: + # load succeded + discard container.iface.getLines(0 .. -1) + var plen, len, packetid: int + container.istream.sread(plen) + container.istream.sread(packetid) + container.istream.sread(len) + var line: SimpleFlexibleLine + for y in 0 ..< len: + container.istream.sread(line) + yield line + +proc handleEvent*(container: Container) = + container.handleCommand() + if container.needslines: + container.requestLines() + container.needslines = false proc addContainerModule*(ctx: JSContext) = ctx.registerType(Container, name = "Buffer") |