batrachian-toad 0.5.22__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. batrachian_toad-0.5.22.dist-info/METADATA +197 -0
  2. batrachian_toad-0.5.22.dist-info/RECORD +120 -0
  3. batrachian_toad-0.5.22.dist-info/WHEEL +4 -0
  4. batrachian_toad-0.5.22.dist-info/entry_points.txt +2 -0
  5. batrachian_toad-0.5.22.dist-info/licenses/LICENSE +661 -0
  6. toad/__init__.py +46 -0
  7. toad/__main__.py +4 -0
  8. toad/_loop.py +86 -0
  9. toad/about.py +90 -0
  10. toad/acp/agent.py +671 -0
  11. toad/acp/api.py +47 -0
  12. toad/acp/encode_tool_call_id.py +12 -0
  13. toad/acp/messages.py +138 -0
  14. toad/acp/prompt.py +54 -0
  15. toad/acp/protocol.py +426 -0
  16. toad/agent.py +62 -0
  17. toad/agent_schema.py +70 -0
  18. toad/agents.py +45 -0
  19. toad/ansi/__init__.py +1 -0
  20. toad/ansi/_ansi.py +1612 -0
  21. toad/ansi/_ansi_colors.py +264 -0
  22. toad/ansi/_control_codes.py +37 -0
  23. toad/ansi/_keys.py +251 -0
  24. toad/ansi/_sgr_styles.py +64 -0
  25. toad/ansi/_stream_parser.py +418 -0
  26. toad/answer.py +22 -0
  27. toad/app.py +557 -0
  28. toad/atomic.py +37 -0
  29. toad/cli.py +257 -0
  30. toad/code_analyze.py +28 -0
  31. toad/complete.py +34 -0
  32. toad/constants.py +58 -0
  33. toad/conversation_markdown.py +19 -0
  34. toad/danger.py +371 -0
  35. toad/data/agents/ampcode.com.toml +51 -0
  36. toad/data/agents/augmentcode.com.toml +40 -0
  37. toad/data/agents/claude.com.toml +41 -0
  38. toad/data/agents/docker.com.toml +59 -0
  39. toad/data/agents/geminicli.com.toml +28 -0
  40. toad/data/agents/goose.ai.toml +51 -0
  41. toad/data/agents/inference.huggingface.co.toml +33 -0
  42. toad/data/agents/kimi.com.toml +35 -0
  43. toad/data/agents/openai.com.toml +53 -0
  44. toad/data/agents/opencode.ai.toml +61 -0
  45. toad/data/agents/openhands.dev.toml +44 -0
  46. toad/data/agents/stakpak.dev.toml +61 -0
  47. toad/data/agents/vibe.mistral.ai.toml +27 -0
  48. toad/data/agents/vtcode.dev.toml +62 -0
  49. toad/data/images/frog.png +0 -0
  50. toad/data/sounds/turn-over.wav +0 -0
  51. toad/db.py +5 -0
  52. toad/dec.py +332 -0
  53. toad/directory.py +234 -0
  54. toad/directory_watcher.py +96 -0
  55. toad/fuzzy.py +140 -0
  56. toad/gist.py +2 -0
  57. toad/history.py +138 -0
  58. toad/jsonrpc.py +576 -0
  59. toad/menus.py +14 -0
  60. toad/messages.py +74 -0
  61. toad/option_content.py +51 -0
  62. toad/os.py +0 -0
  63. toad/path_complete.py +145 -0
  64. toad/path_filter.py +124 -0
  65. toad/paths.py +71 -0
  66. toad/pill.py +23 -0
  67. toad/prompt/extract.py +19 -0
  68. toad/prompt/resource.py +68 -0
  69. toad/protocol.py +28 -0
  70. toad/screens/action_modal.py +94 -0
  71. toad/screens/agent_modal.py +172 -0
  72. toad/screens/command_edit_modal.py +58 -0
  73. toad/screens/main.py +192 -0
  74. toad/screens/permissions.py +390 -0
  75. toad/screens/permissions.tcss +72 -0
  76. toad/screens/settings.py +254 -0
  77. toad/screens/settings.tcss +101 -0
  78. toad/screens/store.py +476 -0
  79. toad/screens/store.tcss +261 -0
  80. toad/settings.py +354 -0
  81. toad/settings_schema.py +318 -0
  82. toad/shell.py +263 -0
  83. toad/shell_read.py +42 -0
  84. toad/slash_command.py +34 -0
  85. toad/toad.tcss +752 -0
  86. toad/version.py +80 -0
  87. toad/visuals/columns.py +273 -0
  88. toad/widgets/agent_response.py +79 -0
  89. toad/widgets/agent_thought.py +41 -0
  90. toad/widgets/command_pane.py +224 -0
  91. toad/widgets/condensed_path.py +93 -0
  92. toad/widgets/conversation.py +1626 -0
  93. toad/widgets/danger_warning.py +65 -0
  94. toad/widgets/diff_view.py +709 -0
  95. toad/widgets/flash.py +81 -0
  96. toad/widgets/future_text.py +126 -0
  97. toad/widgets/grid_select.py +223 -0
  98. toad/widgets/highlighted_textarea.py +180 -0
  99. toad/widgets/mandelbrot.py +294 -0
  100. toad/widgets/markdown_note.py +13 -0
  101. toad/widgets/menu.py +147 -0
  102. toad/widgets/non_selectable_label.py +5 -0
  103. toad/widgets/note.py +18 -0
  104. toad/widgets/path_search.py +381 -0
  105. toad/widgets/plan.py +180 -0
  106. toad/widgets/project_directory_tree.py +74 -0
  107. toad/widgets/prompt.py +741 -0
  108. toad/widgets/question.py +337 -0
  109. toad/widgets/shell_result.py +35 -0
  110. toad/widgets/shell_terminal.py +18 -0
  111. toad/widgets/side_bar.py +74 -0
  112. toad/widgets/slash_complete.py +211 -0
  113. toad/widgets/strike_text.py +66 -0
  114. toad/widgets/terminal.py +526 -0
  115. toad/widgets/terminal_tool.py +338 -0
  116. toad/widgets/throbber.py +90 -0
  117. toad/widgets/tool_call.py +303 -0
  118. toad/widgets/user_input.py +23 -0
  119. toad/widgets/version.py +5 -0
  120. toad/widgets/welcome.py +31 -0
@@ -0,0 +1,93 @@
1
+ from functools import lru_cache
2
+ import os.path
3
+ from typing import Iterable
4
+
5
+ from rich.cells import cell_len
6
+ from textual.geometry import Size
7
+ from textual.reactive import reactive
8
+ from textual.content import Content
9
+ from textual.widget import Widget
10
+
11
+
12
+ def radiate_range(total: int) -> Iterable[tuple[int, int]]:
13
+ """Generate pairs of indexes, gradually growing from the center.
14
+
15
+ Args:
16
+ total: Total size of range.
17
+
18
+ Yields:
19
+ Pairs of indexes.
20
+ """
21
+ if not total:
22
+ return
23
+ left = right = total // 2
24
+ yield (left, right)
25
+ while left >= 0 or right < total:
26
+ left -= 1
27
+ if left >= 0:
28
+ yield (left + 1, right)
29
+ right += 1
30
+ if right <= total:
31
+ yield (left + 1, right)
32
+
33
+
34
+ @lru_cache(maxsize=16)
35
+ def condense_path(path: str, width: int, *, prefix: str = "") -> str:
36
+ """Condense a path to fit within the given cell width.
37
+
38
+ Args:
39
+ path: The path to condense.
40
+ width: Maximum cell width.
41
+ prefix: A string to be prepended to the result.
42
+
43
+ Returns:
44
+ A condensed string.
45
+ """
46
+ # TODO: handle OS separators and path issues
47
+ if cell_len(path) <= width:
48
+ return path
49
+ components = path.split("/")
50
+ condensed = components
51
+ trailing_slash = path.endswith("/")
52
+ candidate = prefix + "/".join(condensed)
53
+ if trailing_slash and candidate and not candidate.endswith("/"):
54
+ candidate += "/"
55
+
56
+ for left, right in radiate_range(len(components)):
57
+ if cell_len(candidate) < width:
58
+ return candidate
59
+ condensed = [*components[:left], "…", *components[right:]]
60
+ candidate = prefix + "/".join(condensed)
61
+ if trailing_slash and candidate and not candidate.endswith("/"):
62
+ candidate += "/"
63
+
64
+ return candidate
65
+
66
+
67
+ class CondensedPath(Widget):
68
+ path = reactive("")
69
+ display_path = reactive("")
70
+
71
+ def on_resize(self) -> None:
72
+ self.watch_path(self.path)
73
+
74
+ def watch_path(self, path: str) -> None:
75
+ if not path or not self.size:
76
+ return
77
+ path = os.path.abspath(path)
78
+ self.tooltip = str(path)
79
+ user_root = os.path.abspath(os.path.expanduser("~/"))
80
+ if not user_root.endswith("/"):
81
+ user_root += "/"
82
+ if path.startswith(user_root):
83
+ path = "~/" + path[len(user_root) :]
84
+ self.display_path = path
85
+
86
+ def render(self) -> Content:
87
+ return Content(condense_path(self.display_path, self.size.width))
88
+
89
+ def get_content_width(self, container: Size, viewport: Size) -> int:
90
+ if self.display_path:
91
+ return Content(self.display_path).cell_length
92
+ else:
93
+ return container.width