Files
EvoScientist-Multi/EvoScientist/cli/widgets/skill_browser.py
T
Xi Zhang e8399b7c94 fix(tui): window slash-command completions to terminal height (#362)
* feat(tui): implement completion popup rendering and windowing logic

* feat(tui): enhance completion popup with dynamic row budgeting and CSS adjustments

* Refactor picker widgets to use shared base class for improved code reuse

- Introduced `picker_base.py` to encapsulate common functionality for picker widgets.
- Updated `ModelPickerWidget`, `SkillBrowserWidget`, and `ThreadPickerWidget` to inherit from `PickerWidgetBase`.
- Implemented selection helpers (`first_selectable_index`, `move_selection`) in `picker_base.py` for consistent item navigation.
- Refactored rendering and selection logic in each widget to utilize the new base class methods.
- Added tests for picker functionality to ensure behavior remains consistent post-refactor.
2026-07-16 16:17:58 +01:00

52 lines
1.6 KiB
Python

"""Inline skill browser widget for /evoskills in TUI.
Two-phase keyboard-driven widget built on the shared picker engine
(``picker_base.TagCheckboxBrowserBase``):
Phase 1 — tag picker (arrow keys + Enter to select, or Esc for all)
Phase 2 — skill checkbox (arrow keys to navigate, Space to toggle, Enter to confirm)
Posts ``SkillBrowserWidget.Confirmed`` with selected install sources,
or ``SkillBrowserWidget.Cancelled`` on Esc.
"""
from __future__ import annotations
from typing import Any, ClassVar
from textual.message import Message
from .picker_base import TagCheckboxBrowserBase
class SkillBrowserWidget(TagCheckboxBrowserBase):
"""Inline skill browser — mounts in chat, keyboard-driven."""
_INSTALLED_SUFFIX: ClassVar[str] = " (installed)"
_PHASE2_TITLE: ClassVar[str] = "Select skills to install"
_PHASE2_CONFIRM_LABEL: ClassVar[str] = "install"
class Confirmed(Message):
"""Posted when user confirms skill selection."""
def __init__(self, install_sources: list[str]) -> None:
super().__init__()
self.install_sources = install_sources
class Cancelled(Message):
"""Posted when user cancels."""
def _item_name(self, item: Any) -> str:
return item["name"]
def _item_tags(self, item: Any) -> list[str]:
return item.get("tags", [])
def _item_desc(self, item: Any) -> str:
return item["description"]
def _post_confirmed(self, items: list[Any]) -> None:
self.post_message(self.Confirmed([s["install_source"] for s in items]))
def _post_cancelled(self) -> None:
self.post_message(self.Cancelled())