just-cli 0.2.0__tar.gz → 0.3.0__tar.gz

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 (143) hide show
  1. just_cli-0.3.0/.claude/settings.local.json +7 -0
  2. just_cli-0.3.0/.claude/skills/textual/README.md +139 -0
  3. just_cli-0.3.0/.claude/skills/textual/SKILL.md +447 -0
  4. just_cli-0.3.0/.claude/skills/textual/guide.md +1064 -0
  5. just_cli-0.3.0/.claude/skills/textual/quick-reference.md +920 -0
  6. {just_cli-0.2.0 → just_cli-0.3.0}/.gitignore +4 -2
  7. just_cli-0.3.0/AGENTS.md +69 -0
  8. just_cli-0.3.0/Dockerfile +22 -0
  9. {just_cli-0.2.0 → just_cli-0.3.0}/PKG-INFO +4 -2
  10. {just_cli-0.2.0 → just_cli-0.3.0}/README.md +1 -1
  11. {just_cli-0.2.0 → just_cli-0.3.0}/pyproject.toml +33 -28
  12. just_cli-0.3.0/scripts/system/mac/proxy/proxy.sh +136 -0
  13. {just_cli-0.2.0 → just_cli-0.3.0}/scripts/system/windows/proxy/proxy.bat +0 -0
  14. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/__init__.py +12 -6
  15. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/cli.py +105 -105
  16. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/commands/download.py +67 -67
  17. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/commands/ext/__init__.py +23 -23
  18. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/commands/ext/add.py +101 -101
  19. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/commands/ext/edit.py +1 -7
  20. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/commands/ext/list.py +154 -154
  21. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/commands/ext/remove.py +1 -5
  22. just_cli-0.3.0/src/just/commands/install.py +89 -0
  23. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/commands/linux.py +213 -213
  24. just_cli-0.3.0/src/just/commands/note.py +12 -0
  25. just_cli-0.3.0/src/just/commands/workspace.py +21 -0
  26. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/config/utils.py +117 -94
  27. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/extension/generator.py +4 -14
  28. just_cli-0.3.0/src/just/core/installer/AGENTS.md +70 -0
  29. just_cli-0.3.0/src/just/core/installer/__init__.py +23 -0
  30. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/installer/decorator.py +19 -15
  31. just_cli-0.3.0/src/just/core/installer/install_package.py +143 -0
  32. just_cli-0.3.0/src/just/core/installer/installers/__init__.py +20 -0
  33. just_cli-0.3.0/src/just/core/installer/installers/binary_release.py +307 -0
  34. just_cli-0.3.0/src/just/core/installer/installers/remote_script.py +291 -0
  35. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/installer/package_info.py +3 -1
  36. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/installer/source/__init__.py +5 -3
  37. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/installer/source/base.py +2 -1
  38. just_cli-0.3.0/src/just/core/installer/utils.py +98 -0
  39. just_cli-0.3.0/src/just/installers/AGENTS.md +72 -0
  40. just_cli-0.3.0/src/just/installers/brew/installer.py +18 -0
  41. just_cli-0.3.0/src/just/installers/claude-code/installer.py +21 -0
  42. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/installers/cloudflare/installer.py +7 -3
  43. just_cli-0.3.0/src/just/installers/edit/installer.py +31 -0
  44. just_cli-0.3.0/src/just/installers/gh/__init__.py +1 -0
  45. just_cli-0.3.0/src/just/installers/gh/installer.py +49 -0
  46. just_cli-0.3.0/src/just/installers/miniconda3/installer.py +33 -0
  47. just_cli-0.3.0/src/just/installers/mssh/installer.py +14 -0
  48. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/installers/nvm/installer.py +29 -31
  49. just_cli-0.3.0/src/just/installers/openclaw/installer.py +24 -0
  50. just_cli-0.3.0/src/just/installers/opencode/installer.py +20 -0
  51. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/installers/qodercli/installer.py +14 -14
  52. just_cli-0.3.0/src/just/installers/tailscale/__init__.py +0 -0
  53. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/installers/tailscale/installer.py +18 -15
  54. just_cli-0.3.0/src/just/installers/uv/__init__.py +1 -0
  55. just_cli-0.3.0/src/just/installers/uv/installer.py +30 -0
  56. just_cli-0.3.0/src/just/tui/__init__.py +5 -0
  57. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/tui/extension.py +657 -657
  58. just_cli-0.3.0/src/just/tui/note.py +339 -0
  59. just_cli-0.3.0/src/just/tui/workspace.py +244 -0
  60. just_cli-0.3.0/src/just/utils/AGENTS.md +44 -0
  61. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/__init__.py +36 -36
  62. just_cli-0.3.0/src/just/utils/docker_utils.py +123 -0
  63. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/download_utils.py +551 -550
  64. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/env_utils.py +26 -0
  65. just_cli-0.3.0/src/just/utils/note_utils.py +205 -0
  66. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/progress.py +456 -456
  67. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/system_probe.py +8 -0
  68. just_cli-0.3.0/src/just/utils/typer_utils.py +62 -0
  69. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/user_interaction.py +24 -24
  70. just_cli-0.3.0/tests/AGENTS.md +54 -0
  71. just_cli-0.3.0/tests/test_bash_script_installer.py +240 -0
  72. {just_cli-0.2.0 → just_cli-0.3.0}/tests/test_download.py +130 -130
  73. {just_cli-0.2.0 → just_cli-0.3.0}/tests/test_extension/README.md +20 -17
  74. {just_cli-0.2.0 → just_cli-0.3.0}/tests/test_extension/test_ext.py +36 -36
  75. just_cli-0.3.0/tests/test_extension/test_extension_add.py +0 -0
  76. just_cli-0.3.0/tests/test_installer_e2e.py +141 -0
  77. {just_cli-0.2.0 → just_cli-0.3.0}/uv.lock +105 -10
  78. just_cli-0.2.0/src/just/commands/install.py +0 -36
  79. just_cli-0.2.0/src/just/core/installer/__init__.py +0 -10
  80. just_cli-0.2.0/src/just/core/installer/binary.py +0 -148
  81. just_cli-0.2.0/src/just/core/installer/install_package.py +0 -48
  82. just_cli-0.2.0/src/just/core/installer/simple_release.py +0 -296
  83. just_cli-0.2.0/src/just/installers/edit/installer.py +0 -23
  84. just_cli-0.2.0/src/just/tui/__init__.py +0 -4
  85. just_cli-0.2.0/src/just/utils/typer_utils.py +0 -35
  86. just_cli-0.2.0/tests/Dockerfile +0 -23
  87. just_cli-0.2.0/tests/test_installer.py +0 -166
  88. just_cli-0.2.0/tokenizer.json +0 -1424063
  89. {just_cli-0.2.0 → just_cli-0.3.0}/.github/workflows/publish.yml +0 -0
  90. {just_cli-0.2.0 → just_cli-0.3.0}/docs/extension_guide.md +0 -0
  91. {just_cli-0.2.0 → just_cli-0.3.0}/docs/images/editor_demo.png +0 -0
  92. {just_cli-0.2.0 → just_cli-0.3.0}/docs/images/viewer_demo.png +0 -0
  93. {just_cli-0.2.0 → just_cli-0.3.0}/scripts/system/linux/proxy/proxy.sh +0 -0
  94. {just_cli-0.2.0 → just_cli-0.3.0}/scripts/system/windows/proxy/proxy.ps1 +0 -0
  95. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/commands/__init__.py +0 -0
  96. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/commands/edit.py +0 -0
  97. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/commands/extract.py +0 -0
  98. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/commands/tunnel.py +0 -0
  99. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/commands/view.py +0 -0
  100. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/__init__.py +0 -0
  101. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/config/__init__.py +0 -0
  102. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/config/config.py +0 -0
  103. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/extension/__init__.py +0 -0
  104. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/extension/parser.py +0 -0
  105. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/extension/utils.py +0 -0
  106. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/extension/validator.py +0 -0
  107. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/installer/source/http.py +0 -0
  108. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/installer/source/local.py +0 -0
  109. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/system_probe/__init__.py +0 -0
  110. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/system_probe/system_info.py +0 -0
  111. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/core/system_probe/system_probe.py +0 -0
  112. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/installers/__init__.py +0 -0
  113. {just_cli-0.2.0/src/just/installers/docker → just_cli-0.3.0/src/just/installers/claude-code}/__init__.py +0 -0
  114. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/installers/cloudflare/__init__.py +0 -0
  115. {just_cli-0.2.0/src/just/installers/edit → just_cli-0.3.0/src/just/installers/docker}/__init__.py +0 -0
  116. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/installers/docker/installer.py +0 -0
  117. {just_cli-0.2.0/src/just/installers/nvm → just_cli-0.3.0/src/just/installers/edit}/__init__.py +0 -0
  118. {just_cli-0.2.0/src/just/installers/qodercli → just_cli-0.3.0/src/just/installers/mssh}/__init__.py +0 -0
  119. {just_cli-0.2.0/src/just/installers/tailscale → just_cli-0.3.0/src/just/installers/nvm}/__init__.py +0 -0
  120. /just_cli-0.2.0/tests/test_extension/test_extension_add.py → /just_cli-0.3.0/src/just/installers/qodercli/__init__.py +0 -0
  121. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/tui/editor.py +0 -0
  122. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/tui/markdown.py +0 -0
  123. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/archive/__init__.py +0 -0
  124. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/archive/compression_handler.py +0 -0
  125. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/archive/extractor.py +0 -0
  126. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/archive/format_detect.py +0 -0
  127. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/archive/sevenzip_handler.py +0 -0
  128. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/archive/tar_handler.py +0 -0
  129. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/archive/zip_handler.py +0 -0
  130. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/echo_utils.py +0 -0
  131. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/file_utils.py +0 -0
  132. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/format_utils.py +0 -0
  133. {just_cli-0.2.0 → just_cli-0.3.0}/src/just/utils/shell_utils.py +0 -0
  134. {just_cli-0.2.0 → just_cli-0.3.0}/tests/requirements.txt +0 -0
  135. {just_cli-0.2.0 → just_cli-0.3.0}/tests/run_tests.py +0 -0
  136. {just_cli-0.2.0 → just_cli-0.3.0}/tests/test_archive_extraction.py +0 -0
  137. {just_cli-0.2.0 → just_cli-0.3.0}/tests/test_extension.py +0 -0
  138. {just_cli-0.2.0 → just_cli-0.3.0}/tests/test_file_utils.py +0 -0
  139. {just_cli-0.2.0 → just_cli-0.3.0}/tests/test_init.py +0 -0
  140. {just_cli-0.2.0 → just_cli-0.3.0}/tests/test_linux_commands.py +0 -0
  141. {just_cli-0.2.0 → just_cli-0.3.0}/tests/test_progress_utils.py +0 -0
  142. {just_cli-0.2.0 → just_cli-0.3.0}/tests/test_system_probe.py +0 -0
  143. {just_cli-0.2.0 → just_cli-0.3.0}/tests/testing.py +0 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "mcp__web-search-prime__web_search_prime"
5
+ ]
6
+ }
7
+ }
@@ -0,0 +1,139 @@
1
+ # Textual Skill
2
+
3
+ Expert guidance for building TUI (Text User Interface) applications with the Textual framework.
4
+
5
+ ## Overview
6
+
7
+ This skill provides comprehensive knowledge about building terminal user interfaces with Textual, a modern Python framework by Textualize.io. It covers:
8
+
9
+ - **Core Concepts**: App architecture, screens, widgets, reactive programming, CSS styling
10
+ - **Best Practices**: Design patterns, code organization, performance optimization
11
+ - **Testing**: Testing strategies with pytest and Pilot
12
+ - **Debugging**: Development console, logging, visual debugging
13
+ - **Common Patterns**: Ready-to-use code templates and examples
14
+ - **Error Prevention**: Common pitfalls and how to avoid them
15
+
16
+ ## Files
17
+
18
+ - **SKILL.md**: Main skill definition with invocation triggers and high-level guidance
19
+ - **quick-reference.md**: Concise cheat sheets, templates, and quick lookups
20
+ - **guide.md**: Comprehensive architectural guide with detailed explanations
21
+ - **README.md**: This file - skill documentation
22
+
23
+ ## When This Skill is Invoked
24
+
25
+ Claude will automatically use this skill when you:
26
+
27
+ - Ask about building TUI applications
28
+ - Mention the Textual framework
29
+ - Need help with widgets, screens, or layouts
30
+ - Have questions about CSS styling (TCSS)
31
+ - Want to implement reactive programming
32
+ - Need testing guidance for Textual apps
33
+ - Encounter errors with Textual code
34
+ - Ask about TUI design patterns
35
+
36
+ ## Usage Examples
37
+
38
+ **Basic Questions:**
39
+ - "How do I create a Textual app?"
40
+ - "What's the best way to organize a Textual project?"
41
+ - "How do I test Textual applications?"
42
+
43
+ **Specific Features:**
44
+ - "How do I create a modal dialog in Textual?"
45
+ - "What's the difference between reactive and var?"
46
+ - "How do I make a widget focusable?"
47
+
48
+ **Debugging:**
49
+ - "Why isn't my reactive attribute updating the UI?"
50
+ - "My test is failing - what am I doing wrong?"
51
+ - "How do I debug a Textual app?"
52
+
53
+ **Design & Architecture:**
54
+ - "What's the best state management approach for my Textual app?"
55
+ - "Should I use composition or inheritance for my widgets?"
56
+ - "How do I implement the 'attributes down, messages up' pattern?"
57
+
58
+ ## Key Concepts Covered
59
+
60
+ ### Architecture
61
+ - Event-driven message queue system
62
+ - DOM-like widget hierarchy
63
+ - Screen navigation and modes
64
+ - Widget lifecycle methods
65
+
66
+ ### Reactive Programming
67
+ - Reactive attributes with auto-refresh
68
+ - Validation and watch methods
69
+ - Computed properties
70
+ - Data binding between widgets
71
+ - Recompose for dynamic layouts
72
+
73
+ ### CSS Styling (TCSS)
74
+ - Selector types and specificity
75
+ - Layout with docking and FR units
76
+ - Theme system with semantic colors
77
+ - Pseudo-classes and nesting
78
+ - Live reload during development
79
+
80
+ ### Testing
81
+ - pytest with async support
82
+ - Pilot for simulating interactions
83
+ - Snapshot testing (optional)
84
+ - Common testing patterns
85
+ - Best practices and pitfalls
86
+
87
+ ### Best Practices
88
+ - "Attributes down, messages up" pattern
89
+ - Composition over inheritance
90
+ - Single responsibility principle
91
+ - Separation of UI and business logic
92
+ - Performance optimization
93
+ - Accessibility considerations
94
+
95
+ ## Quick Start
96
+
97
+ To build a minimal Textual app:
98
+
99
+ ```python
100
+ from textual.app import App, ComposeResult
101
+ from textual.widgets import Header, Footer, Static
102
+
103
+ class MyApp(App):
104
+ def compose(self) -> ComposeResult:
105
+ yield Header()
106
+ yield Static("Hello, Textual!")
107
+ yield Footer()
108
+
109
+ if __name__ == "__main__":
110
+ MyApp().run()
111
+ ```
112
+
113
+ Run with:
114
+ ```bash
115
+ python my_app.py
116
+ ```
117
+
118
+ Or use development mode for live reload:
119
+ ```bash
120
+ textual run --dev my_app.py
121
+ ```
122
+
123
+ ## Resources
124
+
125
+ - **Official Documentation**: https://textual.textualize.io
126
+ - **GitHub**: https://github.com/Textualize/textual
127
+ - **Discord**: Join the Textual Discord for community support
128
+
129
+ ## Skill Maintenance
130
+
131
+ This skill is based on the Textual documentation and best practices as of January 2025. The framework is actively developed, so refer to the official documentation for the latest features and changes.
132
+
133
+ ### Original Source Files
134
+
135
+ This skill was created from:
136
+ - `textual-quick-reference.md` - Quick reference templates
137
+ - `textual-guide.md` - Comprehensive framework guide
138
+
139
+ These files can be updated and the skill regenerated if needed.
@@ -0,0 +1,447 @@
1
+ ---
2
+ name: textual
3
+ description: Expert guidance for building TUI (Text User Interface) applications with the Textual framework. Invoke when user asks about Textual development, TUI apps, widgets, screens, CSS styling, reactive programming, or testing Textual applications.
4
+ ---
5
+
6
+ # Textual - Python TUI Framework Expert
7
+
8
+ You are an expert in building Text User Interface (TUI) applications using **Textual**, a modern Python framework for creating sophisticated terminal applications. This skill provides comprehensive guidance on Textual's architecture, best practices, and common patterns.
9
+
10
+ ## What is Textual?
11
+
12
+ Textual is a TUI framework by Textualize.io that enables developers to build:
13
+
14
+ - Beautiful, responsive terminal applications
15
+ - Rich, interactive command-line tools
16
+ - Cross-platform TUIs with modern UX patterns
17
+ - Applications with CSS-like styling and reactive programming
18
+
19
+ ## When to Use This Skill
20
+
21
+ Invoke this skill when the user:
22
+
23
+ - Wants to build or modify a TUI application
24
+ - Asks about Textual framework features
25
+ - Needs help with widgets, screens, or layouts
26
+ - Has questions about CSS styling in Textual
27
+ - Wants to implement reactive programming patterns
28
+ - Needs testing guidance for Textual apps
29
+ - Encounters errors or issues with Textual code
30
+ - Asks about TUI design patterns or best practices
31
+
32
+ ## Core Concepts
33
+
34
+ ### Application Architecture
35
+
36
+ Textual applications follow an **event-driven architecture**:
37
+
38
+ - The `App` class is the entry point and foundation
39
+ - **Screens** contain widgets and occupy the full terminal
40
+ - **Widgets** are reusable UI components managing rectangular regions
41
+ - **Messages** enable communication between components
42
+ - **CSS (TCSS)** provides styling separate from logic
43
+
44
+ ### Key Components
45
+
46
+ **App Class:**
47
+ - Entry point via `app.run()`
48
+ - Manages screens, modes, and global state
49
+ - Handles key bindings and actions
50
+ - Configures CSS via `CSS_PATH` or inline `CSS`
51
+
52
+ **Screens:**
53
+ - Full-terminal containers for widgets
54
+ - Support push/pop navigation stack
55
+ - Can be modal for dialogs
56
+ - Define their own key bindings and CSS
57
+
58
+ **Widgets:**
59
+ - Rectangular UI components
60
+ - Support composition via `compose()`
61
+ - Handle events via `on_*` methods
62
+ - Can be focused and styled with CSS
63
+
64
+ ### Reactive Programming
65
+
66
+ Textual's reactive system automatically updates the UI when data changes:
67
+
68
+ ```python
69
+ from textual.reactive import reactive
70
+
71
+ class Counter(Widget):
72
+ count = reactive(0) # Auto-refreshes on change
73
+
74
+ def render(self) -> str:
75
+ return f"Count: {self.count}"
76
+ ```
77
+
78
+ Features:
79
+ - **Validation**: `validate_<attr>()` methods constrain values
80
+ - **Watchers**: `watch_<attr>()` methods react to changes
81
+ - **Computed properties**: `compute_<attr>()` for derived values
82
+ - **Recompose**: Rebuild widget tree when data changes
83
+
84
+ ### CSS Styling (TCSS)
85
+
86
+ Textual uses CSS-like syntax for styling:
87
+
88
+ ```css
89
+ Button {
90
+ background: $primary;
91
+ margin: 1;
92
+ }
93
+
94
+ #submit-button {
95
+ background: $success;
96
+ }
97
+
98
+ .danger {
99
+ background: $error;
100
+ }
101
+ ```
102
+
103
+ Benefits:
104
+ - Separation of concerns (style vs logic)
105
+ - Live reload during development
106
+ - Theme system with semantic colors
107
+ - Responsive layout with FR units
108
+
109
+ ## Common Patterns
110
+
111
+ ### Basic App Template
112
+
113
+ ```python
114
+ from textual.app import App, ComposeResult
115
+ from textual.widgets import Header, Footer, Static
116
+
117
+ class MyApp(App):
118
+ CSS_PATH = "app.tcss"
119
+
120
+ def compose(self) -> ComposeResult:
121
+ yield Header()
122
+ yield Static("Hello, Textual!")
123
+ yield Footer()
124
+
125
+ def on_mount(self) -> None:
126
+ """Called after app starts."""
127
+ pass
128
+
129
+ if __name__ == "__main__":
130
+ MyApp().run()
131
+ ```
132
+
133
+ ### Widget Communication
134
+
135
+ Follow **"Attributes down, messages up"**:
136
+
137
+ ```python
138
+ # Parent sets child attributes (down)
139
+ child.value = 10
140
+
141
+ # Child posts messages to parent (up)
142
+ class ChildWidget(Widget):
143
+ class Updated(Message):
144
+ def __init__(self, value: int) -> None:
145
+ super().__init__()
146
+ self.value = value
147
+
148
+ def update_value(self) -> None:
149
+ self.post_message(self.Updated(self.value))
150
+
151
+ # Parent handles child messages
152
+ class ParentWidget(Widget):
153
+ def on_child_widget_updated(self, message: ChildWidget.Updated) -> None:
154
+ self.log(f"Child updated: {message.value}")
155
+ ```
156
+
157
+ ### Testing Pattern
158
+
159
+ ```python
160
+ import pytest
161
+ from my_app import MyApp
162
+
163
+ @pytest.mark.asyncio
164
+ async def test_button_click():
165
+ app = MyApp()
166
+ async with app.run_test() as pilot:
167
+ # Simulate user interaction
168
+ await pilot.click("#submit-button")
169
+
170
+ # CRITICAL: Wait for message processing
171
+ await pilot.pause()
172
+
173
+ # Assert state changed
174
+ result = app.query_one("#status")
175
+ assert "Success" in str(result.renderable)
176
+ ```
177
+
178
+ ## Best Practices
179
+
180
+ ### Design Process
181
+
182
+ 1. **Sketch First**: Draw UI layout on paper before coding
183
+ 2. **Work Outside-In**: Implement fixed elements (header/footer) first, then flexible content
184
+ 3. **Use Docking**: Fix elements with `dock: top/bottom/left/right`
185
+ 4. **FR Units**: Use `1fr` for flexible sizing that fills available space
186
+ 5. **Container Widgets**: Leverage `Vertical`, `Horizontal`, `Grid` for layouts
187
+
188
+ ### Code Organization
189
+
190
+ **Prefer composition over inheritance:**
191
+
192
+ ```python
193
+ # Good: Compose from smaller widgets
194
+ class UserCard(Widget):
195
+ def compose(self) -> ComposeResult:
196
+ with Vertical():
197
+ yield Avatar()
198
+ yield UserName()
199
+ yield UserEmail()
200
+ ```
201
+
202
+ **Separate concerns:**
203
+
204
+ ```python
205
+ # UI in widgets/
206
+ class UserPanel(Widget):
207
+ def __init__(self) -> None:
208
+ super().__init__()
209
+ self.service = UserService() # Business logic
210
+
211
+ # Business logic in business_logic/
212
+ class UserService:
213
+ async def fetch_user(self, user_id: int) -> User:
214
+ # API calls, data processing
215
+ pass
216
+ ```
217
+
218
+ **External CSS for apps:**
219
+
220
+ ```python
221
+ class MyApp(App):
222
+ CSS_PATH = "app.tcss" # Enables live reload
223
+ ```
224
+
225
+ ### Performance
226
+
227
+ 1. **Target 60fps** for smooth terminal rendering
228
+ 2. **Use `Static` widget** for cached rendering
229
+ 3. **Cache expensive operations** with `@lru_cache`
230
+ 4. **Use immutable objects** for data structures
231
+ 5. **Workers for async operations** to avoid blocking UI
232
+
233
+ ### Accessibility
234
+
235
+ - Full keyboard navigation support
236
+ - Set `can_focus = True` on interactive widgets
237
+ - Provide meaningful key bindings
238
+ - Use semantic color variables (`$primary`, `$error`)
239
+ - Test with different terminal sizes
240
+
241
+ ## Common Errors & Solutions
242
+
243
+ ### 1. Forgetting async/await
244
+
245
+ ```python
246
+ # WRONG
247
+ def on_button_pressed(self):
248
+ self.mount(Widget())
249
+
250
+ # RIGHT
251
+ async def on_button_pressed(self):
252
+ await self.mount(Widget())
253
+ ```
254
+
255
+ ### 2. Missing pilot.pause() in tests
256
+
257
+ ```python
258
+ # WRONG - race condition
259
+ async def test_feature():
260
+ await pilot.click("#button")
261
+ assert app.query_one("#status").text == "Done"
262
+
263
+ # RIGHT
264
+ async def test_feature():
265
+ await pilot.click("#button")
266
+ await pilot.pause() # Wait for processing
267
+ assert app.query_one("#status").text == "Done"
268
+ ```
269
+
270
+ ### 3. Modifying reactives in __init__
271
+
272
+ ```python
273
+ # WRONG - triggers watchers too early
274
+ def __init__(self):
275
+ super().__init__()
276
+ self.count = 10
277
+
278
+ # RIGHT - use set_reactive or on_mount
279
+ def __init__(self):
280
+ super().__init__()
281
+ self.set_reactive(MyWidget.count, 10)
282
+ ```
283
+
284
+ ### 4. Blocking the event loop
285
+
286
+ ```python
287
+ # WRONG
288
+ def on_button_pressed(self):
289
+ response = requests.get("https://api.example.com") # Blocks UI!
290
+
291
+ # RIGHT - use workers
292
+ from textual.worker import work
293
+
294
+ @work(exclusive=True)
295
+ async def on_button_pressed(self):
296
+ response = await httpx.get("https://api.example.com")
297
+ ```
298
+
299
+ ## Development Tools
300
+
301
+ ### Development Console
302
+
303
+ Terminal 1:
304
+ ```bash
305
+ textual console
306
+ ```
307
+
308
+ Terminal 2:
309
+ ```bash
310
+ textual run --dev my_app.py
311
+ ```
312
+
313
+ In code:
314
+ ```python
315
+ from textual import log
316
+ log("Debug message", locals())
317
+ ```
318
+
319
+ ### Screenshots & Live Editing
320
+
321
+ ```bash
322
+ # Screenshot after 5 seconds
323
+ textual run --screenshot 5 my_app.py
324
+
325
+ # Dev mode with live CSS reload
326
+ textual run --dev my_app.py
327
+ ```
328
+
329
+ ## Project Structure
330
+
331
+ **Medium/Large Apps:**
332
+
333
+ ```
334
+ project/
335
+ ├── src/
336
+ │ ├── app.py # Main App class
337
+ │ ├── screens/
338
+ │ │ ├── main_screen.py
339
+ │ │ └── settings_screen.py
340
+ │ ├── widgets/
341
+ │ │ ├── status_bar.py
342
+ │ │ └── data_grid.py
343
+ │ └── business_logic/
344
+ │ ├── models.py
345
+ │ └── services.py
346
+ ├── static/
347
+ │ └── app.tcss # External CSS
348
+ ├── tests/
349
+ │ ├── test_app.py
350
+ │ └── test_widgets/
351
+ └── pyproject.toml
352
+ ```
353
+
354
+ ## Instructions for Assistance
355
+
356
+ When helping users with Textual:
357
+
358
+ 1. **Assess Context**: Understand their app structure and goals
359
+ 2. **Check Basics**: Verify imports, async/await, and lifecycle methods
360
+ 3. **Provide Examples**: Show concrete, runnable code
361
+ 4. **Explain Patterns**: Describe why a pattern is recommended
362
+ 5. **Test Guidance**: Include testing code when implementing features
363
+ 6. **Debug Support**: Use console logging and visual debugging tips
364
+ 7. **Best Practices**: Suggest improvements for maintainability
365
+
366
+ Always consider:
367
+ - App complexity (simple vs multi-screen)
368
+ - State management needs (local vs global)
369
+ - Performance requirements
370
+ - Testing strategy
371
+ - Code organization and maintainability
372
+
373
+ ## Additional Resources
374
+
375
+ For detailed reference information:
376
+
377
+ - **[quick-reference.md](quick-reference.md)**: Concise templates, patterns, and cheat sheets
378
+ - **[guide.md](guide.md)**: Comprehensive architecture, design principles, and best practices
379
+ - **Official Documentation**: https://textual.textualize.io
380
+
381
+ ## Quick Reference Highlights
382
+
383
+ ### Useful Built-in Widgets
384
+
385
+ **Input & Selection:**
386
+ - `Button`, `Checkbox`, `Input`, `RadioButton`, `Select`, `Switch`, `TextArea`
387
+
388
+ **Display:**
389
+ - `Label`, `Static`, `Pretty`, `Markdown`, `MarkdownViewer`
390
+
391
+ **Data:**
392
+ - `DataTable`, `ListView`, `Tree`, `DirectoryTree`
393
+
394
+ **Containers:**
395
+ - `Header`, `Footer`, `Tabs`, `TabbedContent`, `Vertical`, `Horizontal`, `Grid`
396
+
397
+ ### Key Lifecycle Methods
398
+
399
+ ```python
400
+ def __init__(self) -> None:
401
+ """Widget created - don't modify reactives here."""
402
+ super().__init__()
403
+
404
+ def compose(self) -> ComposeResult:
405
+ """Build child widgets."""
406
+ yield ChildWidget()
407
+
408
+ def on_mount(self) -> None:
409
+ """After mounted - safe to modify reactives."""
410
+ self.set_interval(1, self.update)
411
+
412
+ def on_unmount(self) -> None:
413
+ """Before removal - cleanup resources."""
414
+ pass
415
+ ```
416
+
417
+ ### Common CSS Patterns
418
+
419
+ ```css
420
+ /* Docking */
421
+ #header { dock: top; height: 3; }
422
+ #sidebar { dock: left; width: 30; }
423
+
424
+ /* Flexible sizing */
425
+ #content { width: 1fr; height: 1fr; }
426
+
427
+ /* Grid layout */
428
+ #container {
429
+ layout: grid;
430
+ grid-size: 3 2;
431
+ grid-columns: 1fr 2fr 1fr;
432
+ }
433
+
434
+ /* Theme colors */
435
+ Button {
436
+ background: $primary;
437
+ color: $text;
438
+ }
439
+
440
+ Button:hover {
441
+ background: $primary-lighten-1;
442
+ }
443
+ ```
444
+
445
+ ## Summary
446
+
447
+ This skill provides expert-level guidance for building Textual applications. Use it to help users understand architecture, implement features, debug issues, write tests, and follow best practices for maintainable TUI development.