From 014579d557c9a7b31c71d55acf844ebb31aca140 Mon Sep 17 00:00:00 2001 From: "bobo.yang" Date: Thu, 14 Nov 2024 18:45:59 +0800 Subject: [PATCH 1/3] feat: Add MultiSelect widget to chatmark library - Implement MultiSelect class in widgets.py - Update __init__.py to export MultiSelect - Add support for multiple option selection with checkboxes --- lib/chatmark/__init__.py | 3 +- lib/chatmark/widgets.py | 88 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/lib/chatmark/__init__.py b/lib/chatmark/__init__.py index d78551f..07e0b93 100644 --- a/lib/chatmark/__init__.py +++ b/lib/chatmark/__init__.py @@ -1,6 +1,6 @@ from .form import Form from .step import Step -from .widgets import Button, Checkbox, Radio, TextEditor +from .widgets import Button, Checkbox, Radio, TextEditor, MultiSelect __all__ = [ "Checkbox", @@ -9,4 +9,5 @@ "Button", "Form", "Step", + "MultiSelect", ] diff --git a/lib/chatmark/widgets.py b/lib/chatmark/widgets.py index a8c1d90..120d421 100644 --- a/lib/chatmark/widgets.py +++ b/lib/chatmark/widgets.py @@ -162,6 +162,94 @@ def _parse_response(self, response: Dict): self._selections = selections +class multiSelect(Widget): + """ + ChatMark syntax: + ```chatmark + Which files would you like to commit? I've suggested a few. + > {x}(file1) devchat/engine/prompter.py + > {x}(file2) devchat/prompt.py + > {}(file3) tests/test_cli_prompt.py + ``` + + Response: + ```yaml + file1: checked + file3: checked + ``` + """ + + def __init__( + self, + options: List[str], + check_states: Optional[List[bool]] = None, + title: Optional[str] = None, + submit_button_name: str = "Submit", + cancel_button_name: str = "Cancel", + ): + """ + options: options to be selected + check_states: initial check states of options, default to all False + title: title of the widget + """ + super().__init__(submit_button_name, cancel_button_name) + + if check_states is not None: + assert len(options) == len(check_states) + else: + check_states = [False for _ in options] + + self._options = options + self._states = check_states + self._title = title + + self._selections: Optional[List[int]] = None + + @property + def selections(self) -> Optional[List[int]]: + """ + Get the indices of selected options + """ + return self._selections + + @property + def options(self) -> List[str]: + """ + Get the options + """ + return self._options + + def _in_chatmark(self) -> str: + """ + Generate ChatMark syntax for checkbox options + Use the index of option to generate id/key + """ + lines = [] + + if self._title: + lines.append(self._title) + + for idx, (option, state) in enumerate(zip(self._options, self._states)): + mark = "{x}" if state else "{}" + key = self.gen_id(self._id_prefix, idx) + lines.append(f"> {mark}({key}) {option}") + + text = "\n".join(lines) + return text + + def _parse_response(self, response: Dict): + selections = [] + for key, value in response.items(): + prefix, index = self.parse_id(key) + # check if the prefix is the same as the widget's + if prefix != self._id_prefix: + continue + + if value == "checked": + selections.append(index) + + self._selections = selections + class TextEditor(Widget): """ From b8e2a0bef87123dbaf9a4d3e74f10be0d94931a9 Mon Sep 17 00:00:00 2001 From: "bobo.yang" Date: Thu, 14 Nov 2024 18:58:35 +0800 Subject: [PATCH 2/3] feat: Refactor MultiSelect to inherit from Checkbox - Rename multiSelect class to MultiSelect for consistency - Inherit MultiSelect from Checkbox to reduce code duplication - Remove redundant properties and methods in MultiSelect class --- lib/chatmark/widgets.py | 42 ++--------------------------------------- 1 file changed, 2 insertions(+), 40 deletions(-) diff --git a/lib/chatmark/widgets.py b/lib/chatmark/widgets.py index 120d421..eade0f6 100644 --- a/lib/chatmark/widgets.py +++ b/lib/chatmark/widgets.py @@ -162,7 +162,7 @@ def _parse_response(self, response: Dict): self._selections = selections -class multiSelect(Widget): +class MultiSelect(Checkbox): """ ChatMark syntax: ```chatmark @@ -192,32 +192,7 @@ def __init__( check_states: initial check states of options, default to all False title: title of the widget """ - super().__init__(submit_button_name, cancel_button_name) - - if check_states is not None: - assert len(options) == len(check_states) - else: - check_states = [False for _ in options] - - self._options = options - self._states = check_states - self._title = title - - self._selections: Optional[List[int]] = None - - @property - def selections(self) -> Optional[List[int]]: - """ - Get the indices of selected options - """ - return self._selections - - @property - def options(self) -> List[str]: - """ - Get the options - """ - return self._options + super().__init__(options, check_states, title, submit_button_name, cancel_button_name) def _in_chatmark(self) -> str: """ @@ -237,19 +212,6 @@ def _in_chatmark(self) -> str: text = "\n".join(lines) return text - def _parse_response(self, response: Dict): - selections = [] - for key, value in response.items(): - prefix, index = self.parse_id(key) - # check if the prefix is the same as the widget's - if prefix != self._id_prefix: - continue - - if value == "checked": - selections.append(index) - - self._selections = selections - class TextEditor(Widget): """ From 5da21b00d511336e7fb2aab7581f7e139c1df816 Mon Sep 17 00:00:00 2001 From: "bobo.yang" Date: Thu, 14 Nov 2024 19:03:47 +0800 Subject: [PATCH 3/3] feat: Add MultiSelect widget and update imports - Implement MultiSelect widget inheriting from Checkbox - Update import order in __init__.py for consistency - Prepare groundwork for multi-select dropdown functionality --- lib/chatmark/__init__.py | 2 +- lib/chatmark/widgets.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/chatmark/__init__.py b/lib/chatmark/__init__.py index 07e0b93..5f1adff 100644 --- a/lib/chatmark/__init__.py +++ b/lib/chatmark/__init__.py @@ -1,6 +1,6 @@ from .form import Form from .step import Step -from .widgets import Button, Checkbox, Radio, TextEditor, MultiSelect +from .widgets import Button, Checkbox, MultiSelect, Radio, TextEditor __all__ = [ "Checkbox", diff --git a/lib/chatmark/widgets.py b/lib/chatmark/widgets.py index eade0f6..30777a0 100644 --- a/lib/chatmark/widgets.py +++ b/lib/chatmark/widgets.py @@ -162,6 +162,7 @@ def _parse_response(self, response: Dict): self._selections = selections + class MultiSelect(Checkbox): """ ChatMark syntax: