diff: More work on images
This commit is contained in:
parent
79dcc8c771
commit
2e69b904da
@ -2,9 +2,10 @@
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import shutil
|
||||
import warnings
|
||||
|
||||
from ..tui.images import can_display_images
|
||||
|
||||
|
||||
class ImageSupportWarning(Warning):
|
||||
pass
|
||||
@ -13,8 +14,7 @@ class ImageSupportWarning(Warning):
|
||||
def images_supported():
|
||||
ans = getattr(images_supported, 'ans', None)
|
||||
if ans is None:
|
||||
ans = shutil.which('convert') is not None
|
||||
images_supported.ans = ans
|
||||
images_supported.ans = ans = can_display_images()
|
||||
if not ans:
|
||||
warnings.warn('ImageMagick not found images cannot be displayed', ImageSupportWarning)
|
||||
return ans
|
||||
|
||||
@ -15,6 +15,7 @@ from kitty.key_encoding import (
|
||||
)
|
||||
|
||||
from ..tui.handler import Handler
|
||||
from ..tui.images import ImageManager
|
||||
from ..tui.loop import Loop
|
||||
from .collect import create_collection, data_for_path, set_highlight_data
|
||||
from .config import init_config
|
||||
@ -45,6 +46,8 @@ def generate_diff(collection, context):
|
||||
|
||||
class DiffHandler(Handler):
|
||||
|
||||
image_manager_class = ImageManager
|
||||
|
||||
def __init__(self, args, opts, left, right):
|
||||
self.state = INITIALIZING
|
||||
self.opts = opts
|
||||
|
||||
@ -8,18 +8,25 @@ from kittens.tui.operations import commander
|
||||
|
||||
class Handler:
|
||||
|
||||
def _initialize(self, screen_size, quit_loop, wakeup, start_job):
|
||||
image_manager_class = None
|
||||
|
||||
def _initialize(self, screen_size, quit_loop, wakeup, start_job, image_manager=None):
|
||||
self.screen_size, self.quit_loop = screen_size, quit_loop
|
||||
self.wakeup = wakeup
|
||||
self.start_job = start_job
|
||||
self.cmd = commander(self)
|
||||
self.image_manager = image_manager
|
||||
|
||||
def __enter__(self):
|
||||
if self.image_manager is not None:
|
||||
self.image_manager.__enter__()
|
||||
self.initialize()
|
||||
|
||||
def __exit__(self, *a):
|
||||
del self.write_buf[:]
|
||||
self.finalize()
|
||||
if self.image_manager is not None:
|
||||
self.image_manager.__exit__(*a)
|
||||
|
||||
def initialize(self):
|
||||
pass
|
||||
|
||||
65
kittens/tui/images.py
Normal file
65
kittens/tui/images.py
Normal file
@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import codecs
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
from base64 import standard_b64encode
|
||||
|
||||
from .operations import serialize_gr_command
|
||||
|
||||
try:
|
||||
fsenc = sys.getfilesystemencoding() or 'utf-8'
|
||||
codecs.lookup(fsenc)
|
||||
except Exception:
|
||||
fsenc = 'utf-8'
|
||||
|
||||
|
||||
def can_display_images():
|
||||
ans = getattr(can_display_images, 'ans', None)
|
||||
if ans is None:
|
||||
ans = shutil.which('convert') is not None
|
||||
can_display_images.ans = ans
|
||||
return ans
|
||||
|
||||
|
||||
class ImageManager:
|
||||
|
||||
def __init__(self, handler):
|
||||
self.handler = handler
|
||||
self.sent_ids = set()
|
||||
self.filesystem_ok = None
|
||||
|
||||
def __enter__(self):
|
||||
self.tdir = tempfile.mkdtemp(prefix='kitten-images-')
|
||||
with tempfile.NamedTemporaryFile(dir=self.tdir, delete=False) as f:
|
||||
f.write(b'abcd')
|
||||
self.handler.write(serialize_gr_command(dict(a='q', s=1, v=1, i=1, t='f'), standard_b64encode(f.name.encode(fsenc))))
|
||||
self.sent_ids.add(1)
|
||||
|
||||
def __exit__(self, *a):
|
||||
shutil.rmtree(self.tdir, ignore_errors=True)
|
||||
self.handler.cmd.clear_images_on_screen(delete_data=True)
|
||||
self.delete_all_sent_images()
|
||||
del self.handler
|
||||
|
||||
def delete_all_sent_images(self):
|
||||
for img_id in self.sent_ids:
|
||||
self.handler.write(serialize_gr_command({'a': 'D', 'i': str(img_id)}))
|
||||
self.sent_ids = set()
|
||||
|
||||
def handle_response(self, apc):
|
||||
cdata, payload = apc[1:].partition(';')[::2]
|
||||
control = {}
|
||||
for x in cdata.split(','):
|
||||
k, v = x.partition('=')[::2]
|
||||
control[k] = v
|
||||
try:
|
||||
image_id = int(control.get('i', '0'))
|
||||
except Exception:
|
||||
image_id = 0
|
||||
if image_id == 1:
|
||||
self.filesystem_ok = payload == 'OK'
|
||||
return
|
||||
@ -27,7 +27,6 @@ from kitty.utils import screen_size_function
|
||||
from .handler import Handler
|
||||
from .operations import clear_screen, init_state, reset_state
|
||||
|
||||
|
||||
screen_size = screen_size_function()
|
||||
|
||||
|
||||
@ -271,6 +270,9 @@ class Loop:
|
||||
self.handler.on_eot()
|
||||
return
|
||||
self.handler.on_key(k)
|
||||
elif apc.startswith('G'):
|
||||
if self.handler.image_manager is not None:
|
||||
self.handler.image_manager.handle_response(apc)
|
||||
|
||||
def _write_ready(self, handler):
|
||||
if len(handler.write_buf) > self.iov_limit:
|
||||
@ -359,9 +361,12 @@ class Loop:
|
||||
signal.signal(signal.SIGINT, self._on_sigint)
|
||||
handler.write_buf = []
|
||||
handler._term_manager = term_manager
|
||||
image_manager = None
|
||||
if handler.image_manager_class is not None:
|
||||
image_manager = handler.image_manager_class(handler)
|
||||
keep_going = True
|
||||
try:
|
||||
handler._initialize(screen_size(), self.quit, self.wakeup, self.start_job)
|
||||
handler._initialize(screen_size(), self.quit, self.wakeup, self.start_job, image_manager)
|
||||
with handler:
|
||||
while keep_going:
|
||||
has_data_to_write = bool(handler.write_buf)
|
||||
|
||||
@ -149,6 +149,22 @@ def styled(text, fg=None, bg=None, fg_intense=False, bg_intense=False, italic=No
|
||||
return '\033[{}m{}\033[{}m'.format(';'.join(start), text, ';'.join(end))
|
||||
|
||||
|
||||
def serialize_gr_command(cmd, payload=None):
|
||||
cmd = ','.join('{}={}'.format(k, v) for k, v in cmd.items())
|
||||
ans = []
|
||||
w = ans.append
|
||||
w(b'\033_G'), w(cmd.encode('ascii'))
|
||||
if payload:
|
||||
w(b';')
|
||||
w(payload)
|
||||
w(b'\033\\')
|
||||
return b''.join(ans)
|
||||
|
||||
|
||||
def clear_images_on_screen(delete_data=False) -> str:
|
||||
return serialize_gr_command({'a': 'D' if delete_data else 'd'})
|
||||
|
||||
|
||||
def init_state(alternate_screen=True):
|
||||
ans = (
|
||||
S7C1T + SAVE_CURSOR + SAVE_PRIVATE_MODE_VALUES + reset_mode('LNM') +
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user