This commit is contained in:
Kovid Goyal
2021-07-28 15:12:59 +05:30
parent acdc41bd03
commit 6f265f448d
2 changed files with 60 additions and 297 deletions

View File

@@ -757,7 +757,7 @@ Key Value Default Description
**Keys for animation frame composition**
-----------------------------------------------------------
``c`` Positive integer ``0`` The 1-based frame number of the frame whose image data serves as the base data
``c`` Positive integer ``0`` The 1-based frame number of the frame whose image data serves as the overlaid data
``r`` Positive integer ``0`` The 1-based frame number of the frame that is being edited.
``x`` Positive integer ``0`` The left edge (in pixels) of the destination rectangle
``y`` Positive integer ``0`` The top edge (in pixels) of the destination rectangle

View File

@@ -11,8 +11,8 @@ from contextlib import suppress
from enum import IntEnum
from itertools import count
from typing import (
Any, Callable, DefaultDict, Deque, Dict, Iterator, List, Optional,
Sequence, Tuple, Union
Any, Callable, ClassVar, DefaultDict, Deque, Dict, Generic, Iterator, List,
Optional, Sequence, Tuple, Type, TypeVar, Union, cast
)
from kitty.conf.utils import positive_float, positive_int
@@ -299,310 +299,75 @@ def can_display_images() -> bool:
ImageKey = Tuple[str, int, int]
SentImageKey = Tuple[int, int, int]
T = TypeVar('T')
class Alias(Generic[T]):
currently_processing: ClassVar[str] = ''
def __init__(self, defval: T) -> None:
self.name = ''
self.defval = defval
def __get__(self, instance: Optional['GraphicsCommand'], cls: Optional[Type['GraphicsCommand']] = None) -> T:
if instance is None:
return self.defval
return cast(T, instance._actual_values.get(self.name, self.defval))
def __set__(self, instance: 'GraphicsCommand', val: T) -> None:
if val == self.defval:
instance._actual_values.pop(self.name, None)
else:
instance._actual_values[self.name] = val
def __set_name__(self, owner: Type['GraphicsCommand'], name: str) -> None:
if len(name) == 1:
Alias.currently_processing = name
self.name = Alias.currently_processing
class GraphicsCommand:
a: GRT_a = 't' # action
q: int = 0 # suppress responses
f: GRT_f = 32 # image data format
t: GRT_t = 'd' # transmission medium
s: int = 0 # sent image width
v: int = 0 # sent image height
S: int = 0 # size of data to read from file
O: int = 0 # offset of data to read from file
i: int = 0 # image id
I: int = 0 # image number
p: int = 0 # placement id
o: Optional[GRT_o] = None # type of compression
m: GRT_m = 0 # 0 or 1 whether there is more chunked data
x: int = 0 # left edge of image area to display
y: int = 0 # top edge of image area to display
w: int = 0 # image width to display
h: int = 0 # image height to display
X: int = 0 # X-offset within cell
Y: int = 0 # Y-offset within cell
c: int = 0 # number of cols to display image over
r: int = 0 # number of rows to display image over
z: int = 0 # z-index
C: GRT_C = 0 # cursor movement policy/composition mode
d: GRT_d = 'a' # what to delete
@property
def action(self) -> GRT_a:
return self.a
@action.setter
def action(self, val: GRT_a) -> None:
self.a = val
@property
def transmission_type(self) -> GRT_t:
return self.t
@transmission_type.setter
def transmission_type(self, val: GRT_t) -> None:
self.t = val
@property
def compressed(self) -> Optional[GRT_o]:
return self.o
@compressed.setter
def compressed(self, val: Optional[GRT_o]) -> None:
self.o = val
@property
def delete_action(self) -> Optional[GRT_d]:
return self.d
@delete_action.setter
def delete_action(self, val: GRT_d) -> None:
self.d = val
@delete_action.setter
def delete_action(self, val: GRT_d) -> None:
self.d = val
@property
def format(self) -> GRT_f:
return self.f
@format.setter
def format(self, val: GRT_f) -> None:
self.f = val
@property
def more(self) -> GRT_m:
return self.m
@more.setter
def more(self, val: GRT_m) -> None:
self.m = val
@property
def image_id(self) -> int:
return self.i
@image_id.setter
def image_id(self, val: int) -> None:
self.i = val
@property
def image_number(self) -> int:
return self.I
@image_number.setter
def image_number(self, val: int) -> None:
self.I = val # noqa
@property
def placement_id(self) -> int:
return self.p
@placement_id.setter
def placement_id(self, val: int) -> None:
self.p = val
@property
def data_size(self) -> int:
return self.S
@data_size.setter
def data_size(self, val: int) -> None:
self.S = val
@property
def data_offset(self) -> int:
return self.O
@data_offset.setter
def data_offset(self, val: int) -> None:
self.O = val # noqa
@property
def quiet(self) -> int:
return self.q
@quiet.setter
def quiet(self, val: int) -> None:
self.q = val
@property
def width(self) -> int:
return self.w
@width.setter
def width(self, val: int) -> None:
self.w = val
@property
def height(self) -> int:
return self.h
@height.setter
def height(self, val: int) -> None:
self.h = val
@property
def left_edge(self) -> int:
return self.x
@left_edge.setter
def left_edge(self, val: int) -> None:
self.x = val
@property
def top_edge(self) -> int:
return self.y
@top_edge.setter
def top_edge(self, val: int) -> None:
self.y = val
@property
def cursor_movement(self) -> GRT_C:
return self.C
@cursor_movement.setter
def cursor_movement(self, val: GRT_C) -> None:
self.C = val
@property
def compose_mode(self) -> GRT_C:
return self.C
@compose_mode.setter
def compose_mode(self, val: GRT_C) -> None:
self.C = val
@property
def cell_x_offset(self) -> int:
return self.X
@cell_x_offset.setter
def cell_x_offset(self, val: int) -> None:
self.X = val
@property
def blend_mode(self) -> int:
return self.X
@blend_mode.setter
def blend_mode(self, val: int) -> None:
self.X = val
@property
def cell_y_offset(self) -> int:
return self.Y
@cell_y_offset.setter
def cell_y_offset(self, val: int) -> None:
self.Y = val
@property
def bgcolor(self) -> int:
return self.Y
@bgcolor.setter
def bgcolor(self, val: int) -> None:
self.Y = val
@property
def data_width(self) -> int:
return self.s
@data_width.setter
def data_width(self, val: int) -> None:
self.s = val
@property
def animation_state(self) -> int:
return self.s
@animation_state.setter
def animation_state(self, val: int) -> None:
self.s = val
@property
def data_height(self) -> int:
return self.v
@data_height.setter
def data_height(self, val: int) -> None:
self.v = val
@property
def loop_count(self) -> int:
return self.v
@loop_count.setter
def loop_count(self, val: int) -> None:
self.v = val
@property
def num_lines(self) -> int:
return self.r
@num_lines.setter
def num_lines(self, val: int) -> None:
self.r = val
@property
def frame_number(self) -> int:
return self.r
@frame_number.setter
def frame_number(self, val: int) -> None:
self.r = val
@property
def num_cells(self) -> int:
return self.c
@num_cells.setter
def num_cells(self, val: int) -> None:
self.c = val
@property
def other_frame_number(self) -> int:
return self.c
@other_frame_number.setter
def other_frame_number(self, val: int) -> None:
self.c = val
@property
def z_index(self) -> int:
return self.z
@z_index.setter
def z_index(self, val: int) -> None:
self.z = val
@property
def gap(self) -> int:
return self.z
@gap.setter
def gap(self, val: int) -> None:
self.z = val
a = action = Alias(cast(GRT_a, 't'))
q = quiet = Alias(0)
f = format = Alias(32)
t = transmission_type = Alias(cast(GRT_t, 'd'))
s = data_width = animation_state = Alias(0)
v = data_height = loop_count = Alias(0)
S = data_size = Alias(0)
O = data_offset = Alias(0) # noqa
i = image_id = Alias(0)
I = image_number = Alias(0) # noqa
p = placement_id = Alias(0)
o = compression = Alias(cast(Optional[GRT_o], None))
m = more = Alias(cast(GRT_m, 0))
x = left_edge = Alias(0)
y = top_edge = Alias(0)
w = width = Alias(0)
h = height = Alias(0)
X = cell_x_offset = blend_mode = Alias(0)
Y = cell_y_offset = bgcolor = Alias(0)
c = columns = other_frame_number = Alias(0)
r = rows = frame_number = Alias(0)
z = z_index = gap = Alias(0)
C = cursor_movement = compose_mode = Alias(cast(GRT_C, 0))
d = delete_action = Alias(cast(GRT_d, 'a'))
def __init__(self) -> None:
self._actual_values: Dict[str, Any] = {}
def __repr__(self) -> str:
return self.serialize().decode('ascii').replace('\033', '^]')
def clone(self) -> 'GraphicsCommand':
ans = GraphicsCommand()
for k in GraphicsCommand.__annotations__:
setattr(ans, k, getattr(self, k))
ans._actual_values = self._actual_values.copy()
return ans
def serialize(self, payload: Union[bytes, str] = b'') -> bytes:
items = []
for k in GraphicsCommand.__annotations__:
val: Union[str, None, int] = getattr(self, k)
defval: Union[str, None, int] = getattr(GraphicsCommand, k)
if val != defval and val is not None:
items.append('{}={}'.format(k, val))
for k, val in self._actual_values.items():
items.append('{}={}'.format(k, val))
ans: List[bytes] = []
w = ans.append
@@ -617,9 +382,7 @@ class GraphicsCommand:
return b''.join(ans)
def clear(self) -> None:
for k in GraphicsCommand.__annotations__:
defval: Union[str, None, int] = getattr(GraphicsCommand, k)
setattr(self, k, defval)
self._actual_values = {}
def iter_transmission_chunks(self, data: Optional[bytes] = None, level: int = -1, compression_threshold: int = 1024) -> Iterator[bytes]:
if data is None: