mirror of
https://github.com/Manoj-HV30/Mini-command-line-interface.git
synced 2026-05-16 19:35:24 +00:00
249 lines
8.5 KiB
Python
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()
|