From 592d128ef6fbd3a8de140946ba62986d2be6023d Mon Sep 17 00:00:00 2001 From: kolo Date: Wed, 9 Apr 2025 12:16:30 +0300 Subject: [PATCH] work on autocomplete --- argenta/app/autocompleter/__init__.py | 4 ++ argenta/app/autocompleter/models.py | 58 +++++++++++++++++++++++ argenta/app/models.py | 2 + mock/local_test.py | 68 ++++++++++++++++++++++----- 4 files changed, 120 insertions(+), 12 deletions(-) create mode 100644 argenta/app/autocompleter/__init__.py create mode 100644 argenta/app/autocompleter/models.py diff --git a/argenta/app/autocompleter/__init__.py b/argenta/app/autocompleter/__init__.py new file mode 100644 index 0000000..b8c1eb3 --- /dev/null +++ b/argenta/app/autocompleter/__init__.py @@ -0,0 +1,4 @@ +__all__ = ["Autocompleter"] + + +from argenta.app.autocompleter.models import Autocompleter diff --git a/argenta/app/autocompleter/models.py b/argenta/app/autocompleter/models.py new file mode 100644 index 0000000..9e52bb7 --- /dev/null +++ b/argenta/app/autocompleter/models.py @@ -0,0 +1,58 @@ +import readline +import os + + + +class Autocompleter: + def __init__(self, history_filename: str = './completer.hist', autocomplete_button: str = 'tab'): + self.history_filename = history_filename + self.autocomplete_button = autocomplete_button + self.matches = [] + + def complete(self, text, state): + if state == 0: + history_values = self.get_history_items() + if text: + self.matches = sorted(h for h in history_values if h and h.startswith(text)) + else: + self.matches = [] + try: + response = self.matches[state] + except IndexError: + response = None + return response + + def initial_setup(self): + if os.path.exists(self.history_filename): + readline.read_history_file(self.history_filename) + readline.set_completer(self.complete) + readline.parse_and_bind(f'{self.autocomplete_button}: complete') + + def write_command_to_history(self): + readline.write_history_file(self.history_filename) + + @staticmethod + def get_history_items(): + return [readline.get_history_item(i) for i in range(1, readline.get_current_history_length() + 1)] + + + +def inputting(): + autocompleter = Autocompleter() + autocompleter.initial_setup() + print(f'Максимальная длина файла истории: {readline.get_history_length()}') + print(f'История запуска:{autocompleter.get_history_items()}') + while True: + line = input('\n!("stop" to quit) Ввод текста: => ') + if line == 'stop': + print(f'Конец записи истории: {autocompleter.get_history_items()}') + autocompleter.write_command_to_history() + break + + +inputting() + + + + + diff --git a/argenta/app/models.py b/argenta/app/models.py index a51527a..4f9853c 100644 --- a/argenta/app/models.py +++ b/argenta/app/models.py @@ -8,6 +8,7 @@ import re from argenta.command.models import Command, InputCommand from argenta.router import Router from argenta.router.defaults import system_router +from argenta.app.autocompleter import Autocompleter from argenta.app.dividing_line.models import StaticDividingLine, DynamicDividingLine from argenta.command.exceptions import (UnprocessedInputFlagException, RepeatedInputFlagsException, @@ -33,6 +34,7 @@ class AppInit: dividing_line: StaticDividingLine | DynamicDividingLine = StaticDividingLine(), repeat_command_groups: bool = True, full_override_system_messages: bool = False, + autocompleter: Autocompleter = Autocompleter(), print_func: Callable[[str], None] = Console().print) -> None: self._prompt = prompt self._print_func = print_func diff --git a/mock/local_test.py b/mock/local_test.py index 4402a57..d136cd3 100644 --- a/mock/local_test.py +++ b/mock/local_test.py @@ -1,14 +1,58 @@ -from contextlib import redirect_stdout -import io -import string +import readline +import os + +HISTORY_FILENAME = 'completer.hist' -while True: - with redirect_stdout(io.StringIO()) as f: - a = input() - print(a) - res = f.getvalue() - res = ''.join([x for x in res if x in string.printable]) - print('-'*len(res)) - print(res.strip('\n')) - print('-'*len(res)) +def get_history_items(): + return [readline.get_history_item(i) for i in range(1, readline.get_current_history_length() + 1)] + + +class HistoryCompleter: + + def __init__(self): + self.matches = [] + return + + def complete(self, text, state): + response = None + if state == 0: + history_values = get_history_items() + if text: + self.matches = sorted(h + for h in history_values + if h and h.startswith(text)) + else: + self.matches = [] + try: + response = self.matches[state] + except IndexError: + response = None + return response + + +def inputing(): + if os.path.exists(HISTORY_FILENAME): + readline.read_history_file(HISTORY_FILENAME) + print(f'Максимальная длина файла истории: {readline.get_history_length()}') + print(f'История запуска:{get_history_items()}') + try: + while True: + line = input('!("stop" to quit) Ввод текста: => ') + if line == 'stop': + break + if line: + print(f'Добавление "{line}" в файл истории.') + finally: + print(f'Конец записи истории: {get_history_items()}') + readline.write_history_file(HISTORY_FILENAME) + + +# Регистрация класса 'HistoryCompleter' +readline.set_completer(HistoryCompleter().complete) + +# Регистрация клавиши `tab` для автодополнения +readline.parse_and_bind('tab: complete') + +# Запрос текста +inputing() \ No newline at end of file