Created
March 5, 2023 13:35
-
-
Save TruncatedDinoSour/e2034cf470f268596235a5c88ffcd048 to your computer and use it in GitHub Desktop.
concept for GNU BASH syntax highlighing in python using linux procFS by Ari Archer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding: utf-8 -*- | |
"""concept for GNU BASH syntax highlighing in python | |
author : Ari Archer <[email protected]> / <https://ari-web.xyz/> | |
license : GPLv3 | |
this concept works ... almost, theres a problem, we need to somehow | |
take ownership of the stdin fd, but we cannot, the reason we need to take | |
ownership or priority over that fd is to make sure were the only ones reading | |
it and not giving bash a chance to steal a byte, currently bash sometimes, | |
especially if youre writing fast, steals a read() from us meaning we miss a byte. | |
this script use the linux procFS | |
theres also an issue with ansi, but its not as important as of now, the script is | |
also quite messy, but i dont have the motivation to fix it rn, so deal with it | |
if you feel like it -- comment with ideas | |
stuff i tried so far : | |
- using LD_PRELOAD to overwrite the read() syscall | |
- making always return 0 | |
- redirecting it to a FIFO | |
- closing it | |
- using os.write / read | |
- using C++ | |
- using C""" | |
import distutils.spawn | |
import os | |
import signal | |
import sys | |
from warnings import filterwarnings as filter_warnings | |
FDS: list[int] = [] | |
def open_fd(fd: int, mode: int) -> int: | |
nfd: int = os.open( | |
f"/proc/{sys.argv[1]}/fd/{fd}", os.O_RDWR | os.O_CREAT, mode=mode | |
) | |
FDS.append(nfd) | |
return nfd | |
def cleanup_fds() -> None: | |
for fd in FDS: | |
os.close(fd) | |
def interpret_backspace(string: str) -> str: | |
new_string: str = "" | |
for char in string: | |
if char == "\x7f": | |
new_string = new_string[:-1] | |
else: | |
new_string += char | |
return new_string | |
def highlight_line(line: str) -> str: | |
if not line: | |
return "" | |
line_cmd: str = line.split(maxsplit=1)[0] | |
return f"\033[{31 + bool(distutils.spawn.find_executable(line_cmd))}m{line_cmd}\033[0m{line.removeprefix(line_cmd)}" | |
def logread(fd: int) -> bytes: | |
print("reading ...") | |
return os.read(fd, 1) | |
def main() -> int: | |
"""entry / main function""" | |
if len(sys.argv) < 2: | |
print( | |
"no target bash PID supplied, you can get it by running `echo $$` in your target bash shell instance" | |
) | |
return 1 | |
stdin, stderr = open_fd(0, 0o400), open_fd(2, 0o200) | |
out = open(f"/tmp/{sys.argv[1]}.bash", "w", buffering=1) | |
out.write("") | |
out.flush() | |
while os.fstat(stdin): | |
s: bytes = b"" | |
c: bytes = b"" | |
os.write(stderr, b"\033[s") | |
while (c := logread(stdin)) not in b"\r\n": | |
print(f"{c = }; {s = }") | |
s = interpret_backspace((s + c).decode()).encode() | |
os.write(stderr, ("\033[u\033[K" + highlight_line(s.decode())).encode()) | |
print("newline", repr(c)) | |
os.write(stderr, b"\n") | |
if s: | |
out.seek(0) | |
out.write(s.decode()) | |
out.flush() | |
print("running", s) | |
os.kill(int(sys.argv[1]), signal.SIGINT) | |
cleanup_fds() | |
out.close() | |
return 0 | |
if __name__ == "__main__": | |
assert main.__annotations__.get("return") is int, "main() should return an integer" | |
filter_warnings("error", category=Warning) | |
raise SystemExit(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
export PROMPT_COMMAND="source /tmp/$$.bash"
if youre using this, if you alrd have it set --export PROMPT_COMMAND="$PROMPT_COMMAND; source /tmp/$$.bash"