Core: CommonClient: command history and echo (#3236)
* client: Added command history access with up/down and command echo in common client * client: Changed command echo colour to orange * client: removed star import from typing * client: updated code style to match style guideline * client: adjusted ordering of calling parent constructor in command prompt input constructor * client: Fixed issues identified by beauxq in PR; fixed some typing issues * client: PR comments; replaced command history list with deque
This commit is contained in:
parent
c478e55d7a
commit
2198a70251
|
@ -494,6 +494,11 @@ class CommonContext:
|
||||||
Returned text is sent, or sending is aborted if None is returned."""
|
Returned text is sent, or sending is aborted if None is returned."""
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
def on_ui_command(self, text: str) -> None:
|
||||||
|
"""Gets called by kivy when the user executes a command starting with `/` or `!`.
|
||||||
|
The command processor is still called; this is just intended for command echoing."""
|
||||||
|
self.ui.print_json([{"text": text, "type": "color", "color": "orange"}])
|
||||||
|
|
||||||
def update_permissions(self, permissions: typing.Dict[str, int]):
|
def update_permissions(self, permissions: typing.Dict[str, int]):
|
||||||
for permission_name, permission_flag in permissions.items():
|
for permission_name, permission_flag in permissions.items():
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -198,7 +198,8 @@ class JSONtoTextParser(metaclass=HandlerMeta):
|
||||||
"slateblue": "6D8BE8",
|
"slateblue": "6D8BE8",
|
||||||
"plum": "AF99EF",
|
"plum": "AF99EF",
|
||||||
"salmon": "FA8072",
|
"salmon": "FA8072",
|
||||||
"white": "FFFFFF"
|
"white": "FFFFFF",
|
||||||
|
"orange": "FF7700",
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, ctx):
|
def __init__(self, ctx):
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
plum: "AF99EF" # typically progression item
|
plum: "AF99EF" # typically progression item
|
||||||
salmon: "FA8072" # typically trap item
|
salmon: "FA8072" # typically trap item
|
||||||
white: "FFFFFF" # not used, if you want to change the generic text color change color in Label
|
white: "FFFFFF" # not used, if you want to change the generic text color change color in Label
|
||||||
|
orange: "FF7700" # Used for command echo
|
||||||
<Label>:
|
<Label>:
|
||||||
color: "FFFFFF"
|
color: "FFFFFF"
|
||||||
<TabbedPanel>:
|
<TabbedPanel>:
|
||||||
|
|
62
kvui.py
62
kvui.py
|
@ -3,6 +3,7 @@ import logging
|
||||||
import sys
|
import sys
|
||||||
import typing
|
import typing
|
||||||
import re
|
import re
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
import ctypes
|
import ctypes
|
||||||
|
@ -380,6 +381,57 @@ class ConnectBarTextInput(TextInput):
|
||||||
return super(ConnectBarTextInput, self).insert_text(s, from_undo=from_undo)
|
return super(ConnectBarTextInput, self).insert_text(s, from_undo=from_undo)
|
||||||
|
|
||||||
|
|
||||||
|
def is_command_input(string: str) -> bool:
|
||||||
|
return len(string) > 0 and string[0] in "/!"
|
||||||
|
|
||||||
|
|
||||||
|
class CommandPromptTextInput(TextInput):
|
||||||
|
MAXIMUM_HISTORY_MESSAGES = 50
|
||||||
|
|
||||||
|
def __init__(self, **kwargs) -> None:
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self._command_history_index = -1
|
||||||
|
self._command_history: typing.Deque[str] = deque(maxlen=CommandPromptTextInput.MAXIMUM_HISTORY_MESSAGES)
|
||||||
|
|
||||||
|
def update_history(self, new_entry: str) -> None:
|
||||||
|
self._command_history_index = -1
|
||||||
|
if is_command_input(new_entry):
|
||||||
|
self._command_history.appendleft(new_entry)
|
||||||
|
|
||||||
|
def keyboard_on_key_down(
|
||||||
|
self,
|
||||||
|
window,
|
||||||
|
keycode: typing.Tuple[int, str],
|
||||||
|
text: typing.Optional[str],
|
||||||
|
modifiers: typing.List[str]
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
:param window: The kivy window object
|
||||||
|
:param keycode: A tuple of (keycode, keyname). Keynames are always lowercase
|
||||||
|
:param text: The text printed by this key, not accounting for modifiers, or `None` if no text.
|
||||||
|
Seems to pretty naively interpret the keycode as unicode, so numlock can return odd characters.
|
||||||
|
:param modifiers: A list of string modifiers, like `ctrl` or `numlock`
|
||||||
|
"""
|
||||||
|
if keycode[1] == 'up':
|
||||||
|
self._change_to_history_text_if_available(self._command_history_index + 1)
|
||||||
|
return True
|
||||||
|
if keycode[1] == 'down':
|
||||||
|
self._change_to_history_text_if_available(self._command_history_index - 1)
|
||||||
|
return True
|
||||||
|
return super().keyboard_on_key_down(window, keycode, text, modifiers)
|
||||||
|
|
||||||
|
def _change_to_history_text_if_available(self, new_index: int) -> None:
|
||||||
|
if new_index < -1:
|
||||||
|
return
|
||||||
|
if new_index >= len(self._command_history):
|
||||||
|
return
|
||||||
|
self._command_history_index = new_index
|
||||||
|
if new_index == -1:
|
||||||
|
self.text = ""
|
||||||
|
return
|
||||||
|
self.text = self._command_history[self._command_history_index]
|
||||||
|
|
||||||
|
|
||||||
class MessageBox(Popup):
|
class MessageBox(Popup):
|
||||||
class MessageBoxLabel(Label):
|
class MessageBoxLabel(Label):
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
|
@ -415,7 +467,7 @@ class GameManager(App):
|
||||||
self.commandprocessor = ctx.command_processor(ctx)
|
self.commandprocessor = ctx.command_processor(ctx)
|
||||||
self.icon = r"data/icon.png"
|
self.icon = r"data/icon.png"
|
||||||
self.json_to_kivy_parser = KivyJSONtoTextParser(ctx)
|
self.json_to_kivy_parser = KivyJSONtoTextParser(ctx)
|
||||||
self.log_panels = {}
|
self.log_panels: typing.Dict[str, Widget] = {}
|
||||||
|
|
||||||
# keep track of last used command to autofill on click
|
# keep track of last used command to autofill on click
|
||||||
self.last_autofillable_command = "hint"
|
self.last_autofillable_command = "hint"
|
||||||
|
@ -499,7 +551,7 @@ class GameManager(App):
|
||||||
info_button = Button(size=(dp(100), dp(30)), text="Command:", size_hint_x=None)
|
info_button = Button(size=(dp(100), dp(30)), text="Command:", size_hint_x=None)
|
||||||
info_button.bind(on_release=self.command_button_action)
|
info_button.bind(on_release=self.command_button_action)
|
||||||
bottom_layout.add_widget(info_button)
|
bottom_layout.add_widget(info_button)
|
||||||
self.textinput = TextInput(size_hint_y=None, height=dp(30), multiline=False, write_tab=False)
|
self.textinput = CommandPromptTextInput(size_hint_y=None, height=dp(30), multiline=False, write_tab=False)
|
||||||
self.textinput.bind(on_text_validate=self.on_message)
|
self.textinput.bind(on_text_validate=self.on_message)
|
||||||
self.textinput.text_validate_unfocus = False
|
self.textinput.text_validate_unfocus = False
|
||||||
bottom_layout.add_widget(self.textinput)
|
bottom_layout.add_widget(self.textinput)
|
||||||
|
@ -557,14 +609,18 @@ class GameManager(App):
|
||||||
|
|
||||||
self.ctx.exit_event.set()
|
self.ctx.exit_event.set()
|
||||||
|
|
||||||
def on_message(self, textinput: TextInput):
|
def on_message(self, textinput: CommandPromptTextInput):
|
||||||
try:
|
try:
|
||||||
input_text = textinput.text.strip()
|
input_text = textinput.text.strip()
|
||||||
textinput.text = ""
|
textinput.text = ""
|
||||||
|
textinput.update_history(input_text)
|
||||||
|
|
||||||
if self.ctx.input_requests > 0:
|
if self.ctx.input_requests > 0:
|
||||||
self.ctx.input_requests -= 1
|
self.ctx.input_requests -= 1
|
||||||
self.ctx.input_queue.put_nowait(input_text)
|
self.ctx.input_queue.put_nowait(input_text)
|
||||||
|
elif is_command_input(input_text):
|
||||||
|
self.ctx.on_ui_command(input_text)
|
||||||
|
self.commandprocessor(input_text)
|
||||||
elif input_text:
|
elif input_text:
|
||||||
self.commandprocessor(input_text)
|
self.commandprocessor(input_text)
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,6 @@ class ColouredMessage:
|
||||||
|
|
||||||
class StarcraftClientProcessor(ClientCommandProcessor):
|
class StarcraftClientProcessor(ClientCommandProcessor):
|
||||||
ctx: SC2Context
|
ctx: SC2Context
|
||||||
echo_commands = True
|
|
||||||
|
|
||||||
def formatted_print(self, text: str) -> None:
|
def formatted_print(self, text: str) -> None:
|
||||||
"""Prints with kivy formatting to the GUI, and also prints to command-line and to all logs"""
|
"""Prints with kivy formatting to the GUI, and also prints to command-line and to all logs"""
|
||||||
|
|
Loading…
Reference in New Issue