Proper handling of async responses to peers
This commit is contained in:
parent
218582ced8
commit
d53d92b890
@ -53,7 +53,7 @@ from .session import Session, create_sessions, get_os_window_sizing_data
|
|||||||
from .tabs import (
|
from .tabs import (
|
||||||
SpecialWindow, SpecialWindowInstance, Tab, TabDict, TabManager
|
SpecialWindow, SpecialWindowInstance, Tab, TabDict, TabManager
|
||||||
)
|
)
|
||||||
from .types import _T, SingleKey, WindowSystemMouseEvent, ac
|
from .types import _T, AsyncResponse, SingleKey, WindowSystemMouseEvent, ac
|
||||||
from .typing import PopenType, TypedDict
|
from .typing import PopenType, TypedDict
|
||||||
from .utils import (
|
from .utils import (
|
||||||
func_name, get_editor, get_new_os_window_size, get_primary_selection,
|
func_name, get_editor, get_new_os_window_size, get_primary_selection,
|
||||||
@ -435,7 +435,7 @@ class Boss:
|
|||||||
self.child_monitor.add_child(window.id, window.child.pid, window.child.child_fd, window.screen)
|
self.child_monitor.add_child(window.id, window.child.pid, window.child.child_fd, window.screen)
|
||||||
self.window_id_map[window.id] = window
|
self.window_id_map[window.id] = window
|
||||||
|
|
||||||
def _handle_remote_command(self, cmd: str, window: Optional[Window] = None, peer_id: int = 0) -> Optional[Dict[str, Any]]:
|
def _handle_remote_command(self, cmd: str, window: Optional[Window] = None, peer_id: int = 0) -> Union[Dict[str, Any], None, AsyncResponse]:
|
||||||
from .remote_control import handle_cmd
|
from .remote_control import handle_cmd
|
||||||
response = None
|
response = None
|
||||||
window = window or None
|
window = window or None
|
||||||
@ -491,7 +491,7 @@ class Boss:
|
|||||||
tb = traceback.format_exc()
|
tb = traceback.format_exc()
|
||||||
self.show_error(_('remote_control mapping failed'), tb)
|
self.show_error(_('remote_control mapping failed'), tb)
|
||||||
|
|
||||||
def peer_message_received(self, msg_bytes: bytes, peer_id: int) -> Optional[bytes]:
|
def peer_message_received(self, msg_bytes: bytes, peer_id: int) -> Union[bytes, bool, None]:
|
||||||
cmd_prefix = b'\x1bP@kitty-cmd'
|
cmd_prefix = b'\x1bP@kitty-cmd'
|
||||||
terminator = b'\x1b\\'
|
terminator = b'\x1b\\'
|
||||||
if msg_bytes.startswith(cmd_prefix) and msg_bytes.endswith(terminator):
|
if msg_bytes.startswith(cmd_prefix) and msg_bytes.endswith(terminator):
|
||||||
@ -499,6 +499,8 @@ class Boss:
|
|||||||
response = self._handle_remote_command(cmd, peer_id=peer_id)
|
response = self._handle_remote_command(cmd, peer_id=peer_id)
|
||||||
if response is None:
|
if response is None:
|
||||||
return None
|
return None
|
||||||
|
if isinstance(response, AsyncResponse):
|
||||||
|
return True
|
||||||
from kitty.remote_control import encode_response_for_peer
|
from kitty.remote_control import encode_response_for_peer
|
||||||
return encode_response_for_peer(response)
|
return encode_response_for_peer(response)
|
||||||
|
|
||||||
@ -528,8 +530,7 @@ class Boss:
|
|||||||
|
|
||||||
def handle_remote_cmd(self, cmd: str, window: Optional[Window] = None) -> None:
|
def handle_remote_cmd(self, cmd: str, window: Optional[Window] = None) -> None:
|
||||||
response = self._handle_remote_command(cmd, window)
|
response = self._handle_remote_command(cmd, window)
|
||||||
if response is not None:
|
if response is not None and not isinstance(response, AsyncResponse) and window is not None:
|
||||||
if window is not None:
|
|
||||||
window.send_cmd_response(response)
|
window.send_cmd_response(response)
|
||||||
|
|
||||||
def _cleanup_tab_after_window_removal(self, src_tab: Tab) -> None:
|
def _cleanup_tab_after_window_removal(self, src_tab: Tab) -> None:
|
||||||
|
|||||||
@ -424,7 +424,7 @@ parse_input(ChildMonitor *self) {
|
|||||||
}
|
}
|
||||||
if (resp) {
|
if (resp) {
|
||||||
if (PyBytes_Check(resp)) send_response_to_peer(msg->peer_id, PyBytes_AS_STRING(resp), PyBytes_GET_SIZE(resp));
|
if (PyBytes_Check(resp)) send_response_to_peer(msg->peer_id, PyBytes_AS_STRING(resp), PyBytes_GET_SIZE(resp));
|
||||||
else send_response_to_peer(msg->peer_id, NULL, 0);
|
else if (resp == Py_None) send_response_to_peer(msg->peer_id, NULL, 0);
|
||||||
Py_CLEAR(resp);
|
Py_CLEAR(resp);
|
||||||
} else send_response_to_peer(msg->peer_id, NULL, 0);
|
} else send_response_to_peer(msg->peer_id, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ from typing import (
|
|||||||
from kitty.cli import get_defaults_from_seq, parse_args, parse_option_spec
|
from kitty.cli import get_defaults_from_seq, parse_args, parse_option_spec
|
||||||
from kitty.cli_stub import RCOptions as R
|
from kitty.cli_stub import RCOptions as R
|
||||||
from kitty.constants import appname, list_kitty_resources, running_in_kitty
|
from kitty.constants import appname, list_kitty_resources, running_in_kitty
|
||||||
|
from kitty.types import AsyncResponse
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from kitty.boss import Boss as B
|
from kitty.boss import Boss as B
|
||||||
@ -64,7 +65,7 @@ class PayloadGetter:
|
|||||||
|
|
||||||
no_response = NoResponse()
|
no_response = NoResponse()
|
||||||
payload_get = object()
|
payload_get = object()
|
||||||
ResponseType = Union[bool, str, None, NoResponse]
|
ResponseType = Union[bool, str, None, NoResponse, AsyncResponse]
|
||||||
CmdReturnType = Union[Dict[str, Any], List[Any], Tuple[Any, ...], str, int, float, bool]
|
CmdReturnType = Union[Dict[str, Any], List[Any], Tuple[Any, ...], str, int, float, bool]
|
||||||
CmdGenerator = Iterator[CmdReturnType]
|
CmdGenerator = Iterator[CmdReturnType]
|
||||||
PayloadType = Optional[Union[CmdReturnType, CmdGenerator]]
|
PayloadType = Optional[Union[CmdReturnType, CmdGenerator]]
|
||||||
|
|||||||
@ -3,9 +3,11 @@
|
|||||||
|
|
||||||
from typing import TYPE_CHECKING, Optional
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
|
from kitty.types import AsyncResponse
|
||||||
|
|
||||||
from .base import (
|
from .base import (
|
||||||
MATCH_TAB_OPTION, ArgsType, Boss, PayloadGetType, PayloadType, RCOptions,
|
MATCH_TAB_OPTION, ArgsType, Boss, PayloadGetType, PayloadType, RCOptions,
|
||||||
RemoteCommand, ResponseType, Window, no_response
|
RemoteCommand, ResponseType, Window
|
||||||
)
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -70,7 +72,7 @@ Exclude the currently active window from the list of windows to pick
|
|||||||
wids = set()
|
wids = set()
|
||||||
boss.visual_window_select_action(tab, callback, payload_get('title') or 'Choose window', only_window_ids=wids)
|
boss.visual_window_select_action(tab, callback, payload_get('title') or 'Choose window', only_window_ids=wids)
|
||||||
break
|
break
|
||||||
return no_response
|
return AsyncResponse()
|
||||||
|
|
||||||
def cancel_async_request(self, boss: 'Boss', window: Optional['Window'], payload_get: PayloadGetType) -> None:
|
def cancel_async_request(self, boss: 'Boss', window: Optional['Window'], payload_get: PayloadGetType) -> None:
|
||||||
boss.cancel_current_visual_select()
|
boss.cancel_current_visual_select()
|
||||||
|
|||||||
@ -6,9 +6,9 @@ import os
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
from time import monotonic
|
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from time import monotonic
|
||||||
from typing import (
|
from typing import (
|
||||||
Any, Dict, Generator, Iterable, List, Optional, Tuple, Union, cast
|
Any, Dict, Generator, Iterable, List, Optional, Tuple, Union, cast
|
||||||
)
|
)
|
||||||
@ -21,10 +21,10 @@ from .rc.base import (
|
|||||||
NoResponse, ParsingOfArgsFailed, PayloadGetter, all_command_names,
|
NoResponse, ParsingOfArgsFailed, PayloadGetter, all_command_names,
|
||||||
command_for_name, parse_subcommand_cli
|
command_for_name, parse_subcommand_cli
|
||||||
)
|
)
|
||||||
|
from .types import AsyncResponse
|
||||||
from .typing import BossType, WindowType
|
from .typing import BossType, WindowType
|
||||||
from .utils import TTYIO, parse_address_spec
|
from .utils import TTYIO, parse_address_spec
|
||||||
|
|
||||||
|
|
||||||
active_async_requests: Dict[str, float] = {}
|
active_async_requests: Dict[str, float] = {}
|
||||||
|
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ def encode_response_for_peer(response: Any) -> bytes:
|
|||||||
return b'\x1bP@kitty-cmd' + json.dumps(response).encode('utf-8') + b'\x1b\\'
|
return b'\x1bP@kitty-cmd' + json.dumps(response).encode('utf-8') + b'\x1b\\'
|
||||||
|
|
||||||
|
|
||||||
def handle_cmd(boss: BossType, window: Optional[WindowType], serialized_cmd: str, peer_id: int) -> Optional[Dict[str, Any]]:
|
def handle_cmd(boss: BossType, window: Optional[WindowType], serialized_cmd: str, peer_id: int) -> Union[Dict[str, Any], None, AsyncResponse]:
|
||||||
cmd = json.loads(serialized_cmd)
|
cmd = json.loads(serialized_cmd)
|
||||||
v = cmd['version']
|
v = cmd['version']
|
||||||
no_response = cmd.get('no_response', False)
|
no_response = cmd.get('no_response', False)
|
||||||
@ -63,6 +63,8 @@ def handle_cmd(boss: BossType, window: Optional[WindowType], serialized_cmd: str
|
|||||||
raise
|
raise
|
||||||
if isinstance(ans, NoResponse):
|
if isinstance(ans, NoResponse):
|
||||||
return None
|
return None
|
||||||
|
if isinstance(ans, AsyncResponse):
|
||||||
|
return ans
|
||||||
response: Dict[str, Any] = {'ok': True}
|
response: Dict[str, Any] = {'ok': True}
|
||||||
if ans is not None:
|
if ans is not None:
|
||||||
response['data'] = ans
|
response['data'] = ans
|
||||||
|
|||||||
@ -74,6 +74,10 @@ class WindowSystemMouseEvent(NamedTuple):
|
|||||||
ConvertibleToNumbers = Union[str, bytes, int, float]
|
ConvertibleToNumbers = Union[str, bytes, int, float]
|
||||||
|
|
||||||
|
|
||||||
|
class AsyncResponse:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
class RunOnce(Generic[_T]):
|
class RunOnce(Generic[_T]):
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user