141 lines
3.8 KiB
Python
141 lines
3.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Template generator for Bubble Tea TUIs.
|
|
Generates code scaffolding and boilerplate.
|
|
"""
|
|
|
|
from typing import List, Dict
|
|
|
|
|
|
def generate_model_struct(components: List[str], archetype: str) -> str:
|
|
"""Generate model struct with components."""
|
|
component_fields = {
|
|
'viewport': ' viewport viewport.Model',
|
|
'textinput': ' textInput textinput.Model',
|
|
'textarea': ' textArea textarea.Model',
|
|
'table': ' table table.Model',
|
|
'list': ' list list.Model',
|
|
'progress': ' progress progress.Model',
|
|
'spinner': ' spinner spinner.Model'
|
|
}
|
|
|
|
fields = []
|
|
for comp in components:
|
|
if comp in component_fields:
|
|
fields.append(component_fields[comp])
|
|
|
|
# Add common fields
|
|
fields.extend([
|
|
' width int',
|
|
' height int',
|
|
' ready bool'
|
|
])
|
|
|
|
return f"""type model struct {{
|
|
{chr(10).join(fields)}
|
|
}}"""
|
|
|
|
|
|
def generate_init_function(components: List[str]) -> str:
|
|
"""Generate Init() function."""
|
|
inits = []
|
|
for comp in components:
|
|
if comp == 'viewport':
|
|
inits.append(' m.viewport = viewport.New(80, 20)')
|
|
elif comp == 'textinput':
|
|
inits.append(' m.textInput = textinput.New()')
|
|
inits.append(' m.textInput.Focus()')
|
|
elif comp == 'spinner':
|
|
inits.append(' m.spinner = spinner.New()')
|
|
inits.append(' m.spinner.Spinner = spinner.Dot')
|
|
elif comp == 'progress':
|
|
inits.append(' m.progress = progress.New(progress.WithDefaultGradient())')
|
|
|
|
init_cmds = ', '.join([f'{c}.Init()' for c in components if c != 'viewport'])
|
|
|
|
return f"""func (m model) Init() tea.Cmd {{
|
|
{chr(10).join(inits) if inits else ' // Initialize components'}
|
|
return tea.Batch({init_cmds if init_cmds else 'nil'})
|
|
}}"""
|
|
|
|
|
|
def generate_update_skeleton(interactions: Dict) -> str:
|
|
"""Generate Update() skeleton."""
|
|
return """func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
switch msg := msg.(type) {
|
|
case tea.KeyMsg:
|
|
switch msg.String() {
|
|
case "ctrl+c", "q":
|
|
return m, tea.Quit
|
|
}
|
|
|
|
case tea.WindowSizeMsg:
|
|
m.width = msg.Width
|
|
m.height = msg.Height
|
|
m.ready = true
|
|
}
|
|
|
|
// Update components
|
|
// TODO: Add component update logic
|
|
|
|
return m, nil
|
|
}"""
|
|
|
|
|
|
def generate_view_skeleton(components: List[str]) -> str:
|
|
"""Generate View() skeleton."""
|
|
renders = []
|
|
for comp in components:
|
|
renders.append(f' // Render {comp}')
|
|
renders.append(f' // views = append(views, m.{comp}.View())')
|
|
|
|
return f"""func (m model) View() string {{
|
|
if !m.ready {{
|
|
return "Loading..."
|
|
}}
|
|
|
|
var views []string
|
|
|
|
{chr(10).join(renders)}
|
|
|
|
return lipgloss.JoinVertical(lipgloss.Left, views...)
|
|
}}"""
|
|
|
|
|
|
def generate_main_go(components: List[str], archetype: str) -> str:
|
|
"""Generate complete main.go scaffold."""
|
|
imports = ['github.com/charmbracelet/bubbletea']
|
|
|
|
if 'viewport' in components:
|
|
imports.append('github.com/charmbracelet/bubbles/viewport')
|
|
if 'textinput' in components:
|
|
imports.append('github.com/charmbracelet/bubbles/textinput')
|
|
if any(c in components for c in ['table', 'list', 'spinner', 'progress']):
|
|
imports.append('github.com/charmbracelet/bubbles/' + components[0])
|
|
|
|
imports.append('github.com/charmbracelet/lipgloss')
|
|
|
|
import_block = '\n '.join(f'"{imp}"' for imp in imports)
|
|
|
|
return f"""package main
|
|
|
|
import (
|
|
{import_block}
|
|
)
|
|
|
|
{generate_model_struct(components, archetype)}
|
|
|
|
{generate_init_function(components)}
|
|
|
|
{generate_update_skeleton({})}
|
|
|
|
{generate_view_skeleton(components)}
|
|
|
|
func main() {{
|
|
p := tea.NewProgram(model{{}}, tea.WithAltScreen())
|
|
if _, err := p.Run(); err != nil {{
|
|
panic(err)
|
|
}}
|
|
}}
|
|
"""
|