diff options
author | bptato <nincsnevem662@gmail.com> | 2022-07-22 19:52:31 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2022-07-22 19:52:31 +0200 |
commit | 6f7bcc54ab03bc31be309352c73fd8d8153f9c91 (patch) | |
tree | dc4fd8a80ccc8a5a8f7c5a567fcbf80c3e66eccb /src/client.nim | |
parent | c69a8ab7576e2053afc5dfcee5c7152a07c31230 (diff) | |
download | chawan-6f7bcc54ab03bc31be309352c73fd8d8153f9c91.tar.gz |
Add search function
Uses libregexp from QuickJS. Incremental search is quite hacky for now, but overall it seems to work OK.
Diffstat (limited to 'src/client.nim')
-rw-r--r-- | src/client.nim | 118 |
1 files changed, 108 insertions, 10 deletions
diff --git a/src/client.nim b/src/client.nim index 8eb63b33..d8f6e2e7 100644 --- a/src/client.nim +++ b/src/client.nim @@ -2,6 +2,7 @@ import options import os import streams import terminal +import unicode import css/sheet import config/config @@ -9,6 +10,7 @@ import io/buffer import io/lineedit import io/loader import js/javascript +import js/regex import types/url import utils/twtstr @@ -24,11 +26,17 @@ type loader: FileLoader jsrt: JSRuntime jsctx: JSContext + regex: Option[Regex] + revsearch: bool 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: @@ -42,12 +50,8 @@ proc js_console_log(ctx: JSContext, this: JSValue, argc: int, argv: ptr JSValue) 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) @@ -59,7 +63,7 @@ proc newClient*(): Client = let ctx = rt.newJSContext() result.jsrt = rt result.jsctx = ctx - let global = ctx.getGlobalObject() + var global = ctx.getGlobalObject() let console = newJSObject(result.jsctx) console.setFunctionProperty("log", js_console_log) global.setProperty("console", console) @@ -127,6 +131,8 @@ proc readPipe(client: Client, ctype: string) = 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): @@ -196,8 +202,7 @@ proc reloadPage(client: Client) = proc changeLocation(client: Client) = let buffer = client.buffer var url = buffer.location.serialize(true) - print(HVP(buffer.height + 1, 1)) - print(EL()) + client.statusMode() let status = readLine("URL: ", url, buffer.width) if status: client.loadUrl(url) @@ -229,8 +234,7 @@ proc toggleSource*(client: Client) = proc command(client: Client) = var iput: string - print(HVP(client.buffer.height + 1, 1)) - print(EL()) + 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) @@ -240,7 +244,7 @@ proc command(client: Client) = let str = ex.toString() if str.issome: opaque.err &= str.get & '\n' - let stack = ex.getProperty("stack") + var stack = ex.getProperty("stack") if not stack.isUndefined(): let str = stack.toString() if str.issome: @@ -262,6 +266,94 @@ proc command(client: Client) = 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 + let status = readLine("/", iput, client.buffer.width, {}, (proc(state: var LineState): bool = + client.buffer.marks.setLen(0) + let regex = compileSearchRegex($state.news) + client.buffer.cpos = cpos + if regex.issome: + let match = client.buffer.cursorNextMatch(regex.get) + if match.success: + client.buffer.addMark(match.x, match.y, match.str) + let nos = client.buffer.nostatus + client.buffer.redraw = true + client.buffer.refreshBuffer(true) + print(HVP(client.buffer.height + 1, 2)) + else: + client.buffer.marks.setLen(0) + return true + false + )) + client.buffer.marks.setLen(0) + client.buffer.redraw = 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 + let status = readLine("?", iput, client.buffer.width, {}, (proc(state: var LineState): bool = + client.buffer.marks.setLen(0) + let regex = compileSearchRegex($state.news) + client.buffer.cpos = cpos + if regex.issome: + let match = client.buffer.cursorPrevMatch(regex.get) + if match.success: + client.buffer.addMark(match.x, match.y, match.str) + let nos = client.buffer.nostatus + client.buffer.redraw = true + client.buffer.refreshBuffer(true) + print(HVP(client.buffer.height + 1, 2)) + return true + false + )) + client.buffer.marks.setLen(0) + client.buffer.redraw = true + if status: + client.regex = compileSearchRegex(iput) + else: + client.buffer.cpos = cpos + proc quit(client: Client) = eraseScreen() print(HVP(0, 0)) @@ -319,6 +411,12 @@ proc input(client: Client) = 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 inputLoop(client: Client) = |