Skip to content

Commit

Permalink
feat: Add MultiSelect widget to chatmark library
Browse files Browse the repository at this point in the history
- Implement MultiSelect class in widgets.py
- Update __init__.py to export MultiSelect
- Add support for multiple option selection with checkboxes
  • Loading branch information
yangbobo2021 committed Nov 14, 2024
1 parent 6d34ceb commit 014579d
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 1 deletion.
3 changes: 2 additions & 1 deletion lib/chatmark/__init__.py
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -9,4 +9,5 @@
"Button",
"Form",
"Step",
"MultiSelect",
]
88 changes: 88 additions & 0 deletions lib/chatmark/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
"""
Expand Down

0 comments on commit 014579d

Please sign in to comment.