feat(selectors): complete contracts

This commit is contained in:
Benexl
2025-08-11 23:57:34 +03:00
parent 17f1744025
commit 03fd8c0bf8
4 changed files with 84 additions and 30 deletions

View File

@@ -31,6 +31,7 @@ class BaseSelector(ABC):
"""
pass
@abstractmethod
def choose_multiple(
self,
prompt: str,
@@ -50,29 +51,7 @@ class BaseSelector(ABC):
Returns:
A list of the chosen items.
"""
# Default implementation: single selection in a loop
selected = []
remaining_choices = choices.copy()
while remaining_choices:
choice = self.choose(
f"{prompt} (Select multiple, empty to finish)",
remaining_choices + ["[DONE] Finish selection"],
preview=preview,
)
if not choice or choice == "[DONE] Finish selection":
break
selected.append(choice)
remaining_choices.remove(choice)
if not self.confirm(
f"Selected: {', '.join(selected)}. Continue selecting?", default=True
):
break
return selected
pass
@abstractmethod
def confirm(self, prompt: str, *, default: bool = False) -> bool:

View File

@@ -141,3 +141,16 @@ class FzfSelector(BaseSelector):
if result.returncode != 0:
return None
return result.stdout.strip()
if __name__ == "__main__":
config = FzfConfig()
selector = FzfSelector(config)
choice = selector.ask("Hello dev :)")
print(choice)
choice = selector.confirm("Hello dev :)")
print(choice)
choice = selector.choose_multiple("What comes first", ["a", "b"])
print(choice)
choice = selector.choose("What comes first", ["a", "b"])
print(choice)

View File

@@ -20,4 +20,27 @@ class InquirerSelector(BaseSelector):
return Confirm.ask(prompt, default=default)
def ask(self, prompt, *, default=None):
return Prompt.ask(prompt=prompt, default=default or "")
return Prompt.ask(prompt=prompt, default=default or None)
def choose_multiple(
self, prompt: str, choices: list[str], preview: str | None = None
) -> list[str]:
return FuzzyPrompt(
message=prompt,
choices=choices,
height="100%",
multiselect=True,
border=True,
).execute()
if __name__ == "__main__":
selector = InquirerSelector()
choice = selector.ask("Hello dev :)")
print(choice)
choice = selector.confirm("Hello dev :)")
print(choice)
choice = selector.choose_multiple("What comes first", ["a", "b"])
print(choice)
choice = selector.choose("What comes first", ["a", "b"])
print(choice)

View File

@@ -37,11 +37,50 @@ class RofiSelector(BaseSelector):
return choice
def confirm(self, prompt, *, default=False):
# Maps directly to your existing `confirm` method
# ... (logic from your `Rofi.confirm` method) ...
pass
choices = ["Yes", "No"]
default_choice = "Yes" if default else "No"
result = self.choose(prompt, choices, header=f"Default: {default_choice}")
return result == "Yes"
def ask(self, prompt, *, default=None):
# Maps directly to your existing `ask` method
# ... (logic from your `Rofi.ask` method) ...
pass
return self.choose(prompt, [])
def choose_multiple(
self, prompt: str, choices: list[str], preview: str | None = None
) -> list[str]:
rofi_input = "\n".join(choices)
args = [
self.executable,
"-no-config",
"-theme",
self.config.theme_main,
"-multi-select",
"-p",
prompt,
"-i",
"-dmenu",
]
result = subprocess.run(
args,
input=rofi_input,
stdout=subprocess.PIPE,
text=True,
)
if result:
choice = result.stdout.strip()
return choice.split()
return []
if __name__ == "__main__":
config = RofiConfig()
selector = RofiSelector(config)
choice = selector.ask("Hello dev :)")
print(choice)
choice = selector.confirm("Hello dev :)")
print(choice)
choice = selector.choose_multiple("What comes first", ["a", "b"])
print(choice)
choice = selector.choose("What comes first", ["a", "b"])
print(choice)