diff options
author | bptato <nincsnevem662@gmail.com> | 2025-02-05 20:25:53 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2025-02-05 20:41:58 +0100 |
commit | 03b1412771dd1d03676ec546b12432c352b88e4e (patch) | |
tree | de7ecc004f8a62af43e14cd3110758066a103d29 /src/local | |
parent | 7f6cc3dc7d7f1c46dc56c7432244fca57a63a732 (diff) | |
download | chawan-03b1412771dd1d03676ec546b12432c352b88e4e.tar.gz |
pager: catch SIGINT for interrupt handler
Significantly more efficient in long running commands (as the context switch is gone). For many commands in quick succession... it replaces the fcntl with a tcsetattr, so I guess it's the same?
Diffstat (limited to 'src/local')
-rw-r--r-- | src/local/pager.nim | 21 | ||||
-rw-r--r-- | src/local/term.nim | 44 |
2 files changed, 21 insertions, 44 deletions
diff --git a/src/local/pager.nim b/src/local/pager.nim index ca85b5df..c804fcd3 100644 --- a/src/local/pager.nim +++ b/src/local/pager.nim @@ -411,18 +411,8 @@ proc loadJSModule(ctx: JSContext; moduleName: cstringConst; opaque: pointer): return nil proc interruptHandler(rt: JSRuntime; opaque: pointer): cint {.cdecl.} = - let pager = cast[Pager](opaque) - if pager.console != nil and pager.term.istream != nil: - try: - var buf = [char(0)] - let n = pager.term.istream.recvData(buf) - if n == 1 and buf[0] == char(3): #C-c - pager.term.resetInputBuffer() - return 1 - pager.term.bufferInputChar(buf[0]) - except ErrorAgain: - discard - return 0 + result = cint(term.sigintCaught) + term.sigintCaught = false proc evalJSFree(opaque: RootRef; src, filename: string) = let pager = Pager(opaque) @@ -445,7 +435,7 @@ proc newPager*(config: Config; forkserver: ForkServer; ctx: JSContext; ) pager.timeouts = newTimeoutState(pager.jsctx, evalJSFree, pager) JS_SetModuleLoaderFunc(pager.jsrt, normalizeModuleName, loadJSModule, nil) - JS_SetInterruptHandler(pager.jsrt, interruptHandler, cast[pointer](pager)) + JS_SetInterruptHandler(pager.jsrt, interruptHandler, nil) let clientConfig = LoaderClientConfig( defaultHeaders: newHeaders(pager.config.network.defaultHeaders), proxy: pager.config.network.proxy, @@ -511,7 +501,7 @@ proc runJSJobs(pager: Pager) = pager.quit(0) proc evalJS(pager: Pager; src, filename: string; module = false): JSValue = - pager.term.unblockStdin() + pager.term.catchSigint() let flags = if module: JS_EVAL_TYPE_MODULE else: @@ -520,13 +510,13 @@ proc evalJS(pager: Pager; src, filename: string; module = false): JSValue = pager.inEval = true result = pager.jsctx.eval(src, filename, flags) pager.inEval = false - pager.term.restoreStdin() if pager.exitCode != -1: # if we are in a nested eval, then just wait until we are not. if not wasInEval: pager.quit(pager.exitCode) else: pager.runJSJobs() + pager.term.respectSigint() proc evalActionJS(pager: Pager; action: string): JSValue = if action.startsWith("cmd."): @@ -735,7 +725,6 @@ proc handleCommandInput(pager: Pager; c: char): EmptyPromise = proc input(pager: Pager): EmptyPromise = var p: EmptyPromise = nil - pager.term.restoreStdin() var buf = "" while true: let c = pager.term.readChar() diff --git a/src/local/term.nim b/src/local/term.nim index 444f742b..f428d626 100644 --- a/src/local/term.nim +++ b/src/local/term.nim @@ -130,9 +130,8 @@ type cleared: bool smcup: bool setTitle: bool - stdinUnblocked: bool - stdinWasUnblocked: bool origTermios: Termios + newTermios: Termios defaultBackground: RGBColor defaultForeground: RGBColor ibuf: array[256, char] # buffer for chars when we can't process them @@ -269,18 +268,6 @@ proc readChar*(term: Terminal): char = result = term.ibuf[term.ibufn] inc term.ibufn -proc bufferInputChar*(term: Terminal; c: char) = - if term.ibufn == term.ibuf.len: - return # can't help it, sorry :P - term.ibuf[term.ibufn] = c - inc term.ibufn - if term.ibufn >= term.ibufLen: - term.ibufLen = term.ibufn - -proc resetInputBuffer*(term: Terminal) = - term.ibufn = 0 - term.ibufLen = 0 - proc hasBuffer*(term: Terminal): bool = return term.ibufn < term.ibufLen @@ -1009,23 +996,30 @@ proc disableRawMode(term: Terminal) = discard tcSetAttr(term.istream.fd, TCSAFLUSH, addr term.origTermios) proc enableRawMode(term: Terminal) = + #TODO check errors discard tcGetAttr(term.istream.fd, addr term.origTermios) var raw = term.origTermios raw.c_iflag = raw.c_iflag and not (BRKINT or ICRNL or INPCK or ISTRIP or IXON) raw.c_oflag = raw.c_oflag and not (OPOST) raw.c_cflag = raw.c_cflag or CS8 raw.c_lflag = raw.c_lflag and not (ECHO or ICANON or ISIG or IEXTEN) + term.newTermios = raw discard tcSetAttr(term.istream.fd, TCSAFLUSH, addr raw) -proc unblockStdin*(term: Terminal) = - if term.isatty(): - term.istream.setBlocking(false) - term.stdinUnblocked = true +# This is checked in the SIGINT handler, set in main.nim. +var sigintCaught* {.global.} = false +var acceptSigint* {.global.} = false + +proc catchSigint*(term: Terminal) = + term.newTermios.c_lflag = term.newTermios.c_lflag or ISIG + acceptSigint = true + discard tcSetAttr(term.istream.fd, TCSAFLUSH, addr term.newTermios) -proc restoreStdin*(term: Terminal) = - if term.stdinUnblocked: - term.istream.setBlocking(true) - term.stdinUnblocked = false +proc respectSigint*(term: Terminal) = + sigintCaught = false + acceptSigint = false + term.newTermios.c_lflag = term.newTermios.c_lflag and not ISIG + discard tcSetAttr(term.istream.fd, TCSAFLUSH, addr term.newTermios) proc quit*(term: Terminal) = if term.isatty(): @@ -1045,9 +1039,6 @@ proc quit*(term: Terminal) = term.write(XTPOPTITLE) term.showCursor() term.clearCanvas() - if term.stdinUnblocked: - term.restoreStdin() - term.stdinWasUnblocked = true term.flush() when TermcapFound: @@ -1515,9 +1506,6 @@ proc start*(term: Terminal; istream: PosixStream): TermStartResult = proc restart*(term: Terminal) = if term.isatty(): term.enableRawMode() - if term.stdinWasUnblocked: - term.unblockStdin() - term.stdinWasUnblocked = false term.initScreen() const ANSIColorMap = [ |