#!/usr/bin/env python3 """Multi-line input reader. C-j inserts newline, C-m (Enter) submits.""" import sys, tty, termios, os, signal def readchar(fd): """Read a single UTF-8 character from fd in raw mode.""" b = os.read(fd, 1) if not b: return b if b[0] < 0x80: return b # determine continuation bytes from leading byte n = 1 if b[0] & 0xe0 == 0xc0: n = 1 elif b[0] & 0xf0 == 0xe0: n = 2 elif b[0] & 0xf8 == 0xf0: n = 3 rest = os.read(fd, n) return b + rest def main(): prompt = sys.argv[1] if len(sys.argv) > 1 else '> ' cont = sys.argv[2] if len(sys.argv) > 2 else '. ' fd = sys.stdin.fileno() old = termios.tcgetattr(fd) lines = [''] cur = 0 # current line index def redraw_current(): p = prompt if cur == 0 else cont sys.stderr.write('\r\033[K' + p + lines[cur]) sys.stderr.flush() sys.stderr.write(prompt) sys.stderr.flush() try: tty.setraw(fd) while True: ch = readchar(fd) if not ch: break b = ch[0] if b == 0x0d: # C-m / Enter -> submit sys.stderr.write('\r\n') sys.stderr.flush() break elif b == 0x0a: # C-j -> newline sys.stderr.write('\r\n') cur += 1 lines.insert(cur, '') redraw_current() elif b == 0x03: # C-c sys.stderr.write('\r\n') sys.stderr.flush() termios.tcsetattr(fd, termios.TCSADRAIN, old) os.kill(os.getpid(), signal.SIGINT) elif b == 0x04: # C-d if not any(lines): sys.stderr.write('\r\n') sys.stderr.flush() termios.tcsetattr(fd, termios.TCSADRAIN, old) sys.exit(1) else: sys.stderr.write('\r\n') sys.stderr.flush() break elif b in (0x7f, 0x08): # backspace if lines[cur]: lines[cur] = lines[cur][:-1] redraw_current() elif cur > 0: prev = lines[cur - 1] lines.pop(cur) cur -= 1 lines[cur] = prev sys.stderr.write('\033[A') redraw_current() elif b == 0x15: # C-u: kill line lines[cur] = '' redraw_current() elif b == 0x17: # C-w: kill word l = lines[cur].rstrip() i = l.rfind(' ') lines[cur] = l[:i+1] if i >= 0 else '' redraw_current() elif b == 0x1b: # escape sequence - consume and ignore os.read(fd, 2) elif b >= 0x20: s = ch.decode('utf-8', errors='replace') lines[cur] += s sys.stderr.write(s) sys.stderr.flush() finally: termios.tcsetattr(fd, termios.TCSADRAIN, old) text = '\n'.join(lines) if not text: sys.exit(1) sys.stdout.write(text) if __name__ == '__main__': main()