Files
2026-04-17 02:21:00 +05:30

249 lines
8.5 KiB
Python

import sys
import tty
import termios
def syntax_highlight(text, sel_start=None, sel_end=None):
if sel_start is not None and sel_end is not None and sel_start != sel_end:
s = min(sel_start, sel_end)
e = max(sel_start, sel_end)
result = text[:s] + u"\u001b[7m" + text[s:e] + u"\u001b[0m" + text[e:]
stripped = result
return stripped
stripped = text.rstrip()
trailing = len(text) - len(stripped)
if trailing > 0:
return stripped + u"\u001b[41m" + " " * trailing + u"\u001b[0m"
return text
def word_boundary_left(text, index):
i = index
while i > 0 and text[i - 1] == " ":
i -= 1
while i > 0 and text[i - 1] != " ":
i -= 1
return i
def word_boundary_right(text, index):
i = index
while i < len(text) and text[i] == " ":
i += 1
while i < len(text) and text[i] != " ":
i += 1
return i
def render(prompt, prompt_len, text, index, sel_anchor):
sys.stdout.write(u"\u001b[1000D")
sys.stdout.write(u"\u001b[0K")
sys.stdout.write(prompt)
sys.stdout.write(syntax_highlight(text, sel_anchor, index))
sys.stdout.write(u"\u001b[1000D")
target = prompt_len + index
if target > 0:
sys.stdout.write(u"\u001b[" + str(target) + "C")
sys.stdout.flush()
def read_char():
return ord(sys.stdin.read(1))
def command_line():
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
prompt = u"\u001b[32;1m>>> \u001b[0m"
prompt_len = 4
try:
tty.setraw(fd)
while True:
text = ""
index = 0
sel_anchor = None
sys.stdout.write(prompt)
sys.stdout.flush()
while True:
char = read_char()
if char == 3:
sys.stdout.write(u"\r\n")
sys.stdout.flush()
return
elif char == 4:
if not text:
sys.stdout.write(u"\r\n")
sys.stdout.flush()
return
elif char == 1:
index = 0
sel_anchor = None
elif char == 5:
index = len(text)
sel_anchor = None
elif char == 11:
text = text[:index]
sel_anchor = None
elif char == 21:
text = text[index:]
index = 0
sel_anchor = None
elif char == 23:
new_index = word_boundary_left(text, index)
text = text[:new_index] + text[index:]
index = new_index
sel_anchor = None
elif 32 <= char <= 126:
if sel_anchor is not None:
s = min(sel_anchor, index)
e = max(sel_anchor, index)
text = text[:s] + chr(char) + text[e:]
index = s + 1
sel_anchor = None
else:
text = text[:index] + chr(char) + text[index:]
index += 1
elif char in {10, 13}:
sys.stdout.write(u"\u001b[1000D")
sys.stdout.write(u"\u001b[0K")
sys.stdout.write(prompt + text + u"\r\n")
sys.stdout.write(u"\u001b[36m=>\u001b[0m " + text + u"\r\n")
sys.stdout.flush()
sel_anchor = None
break
elif char == 127:
if sel_anchor is not None:
s = min(sel_anchor, index)
e = max(sel_anchor, index)
text = text[:s] + text[e:]
index = s
sel_anchor = None
elif index > 0:
text = text[:index - 1] + text[index:]
index -= 1
elif char == 27:
next1 = read_char()
if next1 == 91:
next2 = read_char()
if next2 == 68:
index = max(0, index - 1)
sel_anchor = None
elif next2 == 67:
index = min(len(text), index + 1)
sel_anchor = None
elif next2 == 65:
pass
elif next2 == 66:
pass
elif next2 == 72:
index = 0
sel_anchor = None
elif next2 == 70:
index = len(text)
sel_anchor = None
elif next2 == 51:
next3 = read_char()
if next3 == 126:
if sel_anchor is not None:
s = min(sel_anchor, index)
e = max(sel_anchor, index)
text = text[:s] + text[e:]
index = s
sel_anchor = None
elif index < len(text):
text = text[:index] + text[index + 1:]
elif next2 == 52:
next3 = read_char()
if next3 == 126:
index = len(text)
sel_anchor = None
elif next2 == 49:
next3 = read_char()
if next3 == 126:
index = 0
sel_anchor = None
elif next3 == 59:
next4 = read_char()
next5 = read_char()
if next4 == 50:
if next5 == 68:
if sel_anchor is None:
sel_anchor = index
index = max(0, index - 1)
elif next5 == 67:
if sel_anchor is None:
sel_anchor = index
index = min(len(text), index + 1)
elif next5 == 72:
if sel_anchor is None:
sel_anchor = index
index = 0
elif next5 == 70:
if sel_anchor is None:
sel_anchor = index
index = len(text)
elif next4 == 53:
if next5 == 68:
index = word_boundary_left(text, index)
sel_anchor = None
elif next5 == 67:
index = word_boundary_right(text, index)
sel_anchor = None
elif next1 == 98:
index = word_boundary_left(text, index)
sel_anchor = None
elif next1 == 102:
index = word_boundary_right(text, index)
sel_anchor = None
elif next1 == 100:
new_index = word_boundary_right(text, index)
text = text[:index] + text[new_index:]
sel_anchor = None
elif next1 == 127:
new_index = word_boundary_left(text, index)
text = text[:new_index] + text[index:]
index = new_index
sel_anchor = None
elif next1 == 98:
index = word_boundary_left(text, index)
render(prompt, prompt_len, text, index, sel_anchor)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
sys.stdout.write(u"\u001b[0m\r\n")
sys.stdout.flush()
command_line()