diff --git a/src/smarttools/tool.py b/src/smarttools/tool.py index 5d3edda..68148a8 100644 --- a/src/smarttools/tool.py +++ b/src/smarttools/tool.py @@ -154,10 +154,6 @@ class Tool: return variables -# Legacy support - map old ToolInput to new ToolArgument -ToolInput = ToolArgument - - def get_tools_dir() -> Path: """Get the tools directory, creating it if needed.""" TOOLS_DIR.mkdir(parents=True, exist_ok=True) diff --git a/src/smarttools/ui_urwid.py b/src/smarttools/ui_urwid.py index e6d4d22..7f44ed1 100644 --- a/src/smarttools/ui_urwid.py +++ b/src/smarttools/ui_urwid.py @@ -150,7 +150,13 @@ class ToolListBox(urwid.ListBox): class TabCyclePile(urwid.Pile): - """A Pile that uses Tab/Shift-Tab to cycle between specific positions.""" + """A Pile that uses Tab/Shift-Tab to cycle between specific positions. + + Args: + widget_list: List of widgets (same as urwid.Pile) + tab_positions: List of indices in the pile that Tab should cycle between. + Default is [0] (only first position). + """ def __init__(self, widget_list, tab_positions=None): super().__init__(widget_list) @@ -184,7 +190,18 @@ class TabPassEdit(urwid.Edit): class DOSScrollBar(urwid.WidgetWrap): - """A DOS-style scrollbar with arrow buttons at top and bottom.""" + """A DOS-style scrollbar with arrow buttons at top and bottom. + + Renders a scrollbar on the right side of the wrapped widget with: + - ▲ arrow at top (click to scroll up) + - ░ track with █ thumb showing scroll position + - ▼ arrow at bottom (click to scroll down) + + Click zones (expanded to last 2 columns for easier clicking): + - Top 25%: scroll up 3 lines + - Bottom 25%: scroll down 3 lines + - Middle: page up/down based on which half clicked + """ def __init__(self, widget): self._wrapped = widget @@ -1038,7 +1055,6 @@ class SmartToolsUI: def _edit_argument_at(self, idx): """Edit argument at index.""" - arg = self._current_tool.arguments[idx] self._do_edit_argument(idx) def _edit_step_at(self, idx): @@ -1091,26 +1107,6 @@ class SmartToolsUI: dialog = Dialog("Add Argument", body, [("OK", on_ok), ("Cancel", on_cancel)]) self.show_overlay(dialog, width=50, height=14) - def _edit_argument_dialog(self, idx): - """Show edit/delete argument dialog.""" - arg = self._current_tool.arguments[idx] - - def on_edit(_): - self.close_overlay() - self._do_edit_argument(idx) - - def on_delete(_): - self._current_tool.arguments.pop(idx) - self.close_overlay() - self._show_tool_builder() - - def on_cancel(_): - self.close_overlay() - - body = urwid.Text(f"Argument: {arg.flag} -> {{{arg.variable}}}") - dialog = Dialog("Edit Argument", body, [("Edit", on_edit), ("Delete", on_delete), ("Cancel", on_cancel)]) - self.show_overlay(dialog, width=50, height=10) - def _do_edit_argument(self, idx): """Edit an existing argument.""" # Save current field values before showing dialog @@ -1661,30 +1657,6 @@ Return ONLY the modified Python code, no explanations or markdown fencing.""" dialog = Dialog(title, body, [("OK", on_ok), ("Cancel", on_cancel)]) self.show_overlay(dialog, width=70, height=24) - def _edit_step_dialog(self, idx): - """Show edit/delete step dialog.""" - step = self._current_tool.steps[idx] - step_type = "Prompt" if isinstance(step, PromptStep) else "Code" - - def on_edit(_): - self.close_overlay() - if isinstance(step, PromptStep): - self._add_prompt_dialog(step, idx) - else: - self._add_code_dialog(step, idx) - - def on_delete(_): - self._current_tool.steps.pop(idx) - self.close_overlay() - self._show_tool_builder() - - def on_cancel(_): - self.close_overlay() - - body = urwid.Text(f"Step {idx+1}: {step_type}") - dialog = Dialog("Edit Step", body, [("Edit", on_edit), ("Delete", on_delete), ("Cancel", on_cancel)]) - self.show_overlay(dialog, width=45, height=10) - def _on_save_tool(self, _): """Save the tool.""" tool = self._current_tool @@ -1721,84 +1693,6 @@ Return ONLY the modified Python code, no explanations or markdown fencing.""" """Cancel tool editing.""" self.show_main_menu() - # ==================== Tool Selection ==================== - - def select_edit_tool(self): - """Select a tool to edit.""" - tools = list_tools() - if not tools: - self.message_box("Edit Tool", "No tools found.") - return - - def on_select(name): - self.close_overlay() - tool = load_tool(name) - if tool: - self.tool_builder(tool) - - def on_cancel(_): - self.close_overlay() - - items = [] - for name in tools: - item = SelectableText(f" {name} ", value=name, on_select=on_select) - items.append(item) - - listbox = urwid.ListBox(urwid.SimpleFocusListWalker(items)) - dialog = Dialog("Select Tool to Edit", listbox, [("Cancel", on_cancel)]) - self.show_overlay(dialog, width=50, height=min(len(tools) + 8, 20)) - - def select_delete_tool(self): - """Select a tool to delete.""" - tools = list_tools() - if not tools: - self.message_box("Delete Tool", "No tools found.") - return - - def on_select(name): - self.close_overlay() - def do_delete(): - delete_tool(name) - self.message_box("Deleted", f"Tool '{name}' deleted.") - self.yes_no("Confirm", f"Delete tool '{name}'?", on_yes=do_delete) - - def on_cancel(_): - self.close_overlay() - - items = [] - for name in tools: - item = SelectableText(f" {name} ", value=name, on_select=on_select) - items.append(item) - - listbox = urwid.ListBox(urwid.SimpleFocusListWalker(items)) - dialog = Dialog("Select Tool to Delete", listbox, [("Cancel", on_cancel)]) - self.show_overlay(dialog, width=50, height=min(len(tools) + 8, 20)) - - def select_test_tool(self): - """Select a tool to test.""" - tools = list_tools() - if not tools: - self.message_box("Test Tool", "No tools found.") - return - - def on_select(name): - self.close_overlay() - tool = load_tool(name) - if tool: - self._test_tool(tool) - - def on_cancel(_): - self.close_overlay() - - items = [] - for name in tools: - item = SelectableText(f" {name} ", value=name, on_select=on_select) - items.append(item) - - listbox = urwid.ListBox(urwid.SimpleFocusListWalker(items)) - dialog = Dialog("Select Tool to Test", listbox, [("Cancel", on_cancel)]) - self.show_overlay(dialog, width=50, height=min(len(tools) + 8, 20)) - def _test_tool(self, tool): """Test a tool with mock input.""" def on_input(text): @@ -1817,20 +1711,6 @@ Return ONLY the modified Python code, no explanations or markdown fencing.""" self.input_dialog("Test Input", "Enter test input", "Hello world", on_input) - def show_tools_list(self): - """Show list of all tools.""" - tools = list_tools() - if not tools: - self.message_box("Tools", "No tools found.") - return - - text = "" - for name in tools: - tool = load_tool(name) - if tool: - text += f"{name}: {tool.description or 'No description'}\n" - - self.message_box("Available Tools", text.strip()) # ==================== Provider Management ====================