try waiting for confirmation from the terminal - works somewhat, but messes with input
This commit is contained in:
parent
a0376ae9a4
commit
8f3b63efc4
85
kitty.py
85
kitty.py
@ -1,21 +1,19 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
from base64 import standard_b64encode
|
||||||
|
from enum import Enum
|
||||||
|
import array
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import fcntl
|
||||||
|
import mmap
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
|
import select
|
||||||
import sys
|
import sys
|
||||||
import termios
|
import termios
|
||||||
import tty
|
import tty
|
||||||
from base64 import standard_b64encode
|
|
||||||
import array
|
|
||||||
import fcntl
|
|
||||||
|
|
||||||
import zlib
|
import zlib
|
||||||
|
|
||||||
|
|
||||||
import mmap
|
|
||||||
import os
|
|
||||||
import select
|
|
||||||
from enum import Enum
|
|
||||||
|
|
||||||
SHM_NAME = "/kitty-shm-frame"
|
SHM_NAME = "/kitty-shm-frame"
|
||||||
|
|
||||||
|
|
||||||
@ -24,6 +22,9 @@ class Kitty_Format(Enum):
|
|||||||
RGBA = 32
|
RGBA = 32
|
||||||
PNG = 100
|
PNG = 100
|
||||||
|
|
||||||
|
class TerminalProtocolError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
async def draw_to_terminal(
|
async def draw_to_terminal(
|
||||||
buffer,
|
buffer,
|
||||||
@ -36,11 +37,11 @@ async def draw_to_terminal(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Display an image in the terminal."""
|
"""Display an image in the terminal."""
|
||||||
if (pixel_format != Kitty_Format.PNG or use_shm) and (width is None or height is None):
|
if (pixel_format != Kitty_Format.PNG or use_shm) and (width is None or height is None):
|
||||||
raise ValueError(
|
raise TerminalProtocolError(
|
||||||
"shm transfer or using image formats other than PNG and require height and width"
|
"shm transfer or using image formats other than PNG and require height and width"
|
||||||
)
|
)
|
||||||
|
|
||||||
kwargs = {"a": "T", "i": image_num, "f": pixel_format.value, "t": "s" if use_shm else "d", "q": 2}
|
kwargs = {"a": "T", "i": image_num, "f": pixel_format.value, "t": "s" if use_shm else "d"}
|
||||||
|
|
||||||
if width:
|
if width:
|
||||||
kwargs["s"] = width
|
kwargs["s"] = width
|
||||||
@ -59,7 +60,7 @@ async def draw_to_terminal(
|
|||||||
# set shm name as payload
|
# set shm name as payload
|
||||||
data = SHM_NAME
|
data = SHM_NAME
|
||||||
|
|
||||||
await _write_chunked(**kwargs, data=data)
|
await _write_chunked(**kwargs, data=data, wait_for_ok=True)
|
||||||
await asyncio.sleep(0.001)
|
await asyncio.sleep(0.001)
|
||||||
|
|
||||||
|
|
||||||
@ -113,7 +114,7 @@ async def get_terminal_cell_size() -> tuple[int, int]:
|
|||||||
v_pix, h_pix = map(int, match.groups())
|
v_pix, h_pix = map(int, match.groups())
|
||||||
return v_pix, h_pix
|
return v_pix, h_pix
|
||||||
print(reply)
|
print(reply)
|
||||||
raise ValueError("Failed to parse terminal cell size response")
|
raise TerminalProtocolError("Failed to parse terminal cell size response")
|
||||||
|
|
||||||
|
|
||||||
async def get_terminal_size_pixel() -> tuple[int, int]:
|
async def get_terminal_size_pixel() -> tuple[int, int]:
|
||||||
@ -124,7 +125,7 @@ async def get_terminal_size_pixel() -> tuple[int, int]:
|
|||||||
if match:
|
if match:
|
||||||
height, width = map(int, match.groups())
|
height, width = map(int, match.groups())
|
||||||
return height, width
|
return height, width
|
||||||
raise ValueError("Failed to parse terminal pixel size response")
|
raise TerminalProtocolError("Failed to parse terminal pixel size response")
|
||||||
|
|
||||||
|
|
||||||
def get_terminal_size() -> tuple[int, int]:
|
def get_terminal_size() -> tuple[int, int]:
|
||||||
@ -148,19 +149,59 @@ def _serialize_gr_command(**cmd) -> bytes:
|
|||||||
return b"".join(ans)
|
return b"".join(ans)
|
||||||
|
|
||||||
|
|
||||||
async def _write_chunked(**cmd) -> None:
|
#async def _write_chunked(**cmd) -> None:
|
||||||
|
# if cmd["t"] == "s":
|
||||||
|
# data = standard_b64encode(bytes(cmd.pop("data"), "utf-8"))
|
||||||
|
# else:
|
||||||
|
# data = standard_b64encode(cmd.pop("data"))
|
||||||
|
# while data:
|
||||||
|
# chunk, data = data[:4096], data[4096:]
|
||||||
|
# m = 1 if data else 0
|
||||||
|
# payload = _serialize_gr_command(payload=chunk, m=m, **cmd)
|
||||||
|
# sys.stdout.buffer.write(payload)
|
||||||
|
# sys.stdout.flush()
|
||||||
|
# cmd.clear()
|
||||||
|
|
||||||
|
async def _write_chunked(wait_for_ok: bool = True, **cmd) -> None:
|
||||||
|
image_id = cmd['i']
|
||||||
if cmd["t"] == "s":
|
if cmd["t"] == "s":
|
||||||
data = standard_b64encode(bytes(cmd.pop("data"), "utf-8"))
|
data = standard_b64encode(bytes(cmd.pop("data"), "utf-8"))
|
||||||
else:
|
else:
|
||||||
data = standard_b64encode(cmd.pop("data"))
|
data = standard_b64encode(cmd.pop("data"))
|
||||||
while data:
|
|
||||||
chunk, data = data[:4096], data[4096:]
|
|
||||||
m = 1 if data else 0
|
|
||||||
payload = _serialize_gr_command(payload=chunk, m=m, **cmd)
|
|
||||||
sys.stdout.buffer.write(payload)
|
|
||||||
sys.stdout.flush()
|
|
||||||
cmd.clear()
|
|
||||||
|
|
||||||
|
fd = sys.stdin.fileno()
|
||||||
|
old_settings = termios.tcgetattr(fd)
|
||||||
|
tty.setraw(fd)
|
||||||
|
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
|
|
||||||
|
try:
|
||||||
|
while data:
|
||||||
|
chunk, data = data[:4096], data[4096:]
|
||||||
|
m = 1 if data else 0
|
||||||
|
payload = _serialize_gr_command(payload=chunk, m=m, **cmd)
|
||||||
|
sys.stdout.buffer.write(payload)
|
||||||
|
sys.stdout.flush()
|
||||||
|
cmd.clear()
|
||||||
|
|
||||||
|
if wait_for_ok:
|
||||||
|
# Wait for terminal to confirm OK response
|
||||||
|
response = os.read(fd, 1024).decode("utf-8", "ignore")
|
||||||
|
if not response.startswith(f"\033_Gi={image_id};OK"):
|
||||||
|
return
|
||||||
|
#raise RuntimeError(f"Unexpected response: {repr(response)}")
|
||||||
|
#return response.startswith("\033_GOK")
|
||||||
|
# def _read_ok():
|
||||||
|
# response = ""
|
||||||
|
# while not response.endswith("\033\\"):
|
||||||
|
# response += sys.stdin.read(1)
|
||||||
|
# return response
|
||||||
|
|
||||||
|
# response = await loop.run_in_executor(None, _read_ok)
|
||||||
|
# if not response.startswith(f"\033_Gi={image_id};OK"):
|
||||||
|
# raise RuntimeError(f"Unexpected response: {repr(response)}")
|
||||||
|
finally:
|
||||||
|
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||||
|
|
||||||
def hide_cursor() -> None:
|
def hide_cursor() -> None:
|
||||||
"""Tell the terminal to hide the cursor."""
|
"""Tell the terminal to hide the cursor."""
|
||||||
|
Loading…
Reference in New Issue
Block a user