diff options
| author | Kujtim Hoxha <[email protected]> | 2025-03-27 22:35:48 +0100 |
|---|---|---|
| committer | Kujtim Hoxha <[email protected]> | 2025-04-01 13:38:54 +0200 |
| commit | afd9ad0560d76c2a6d161dad52553b10ff428905 (patch) | |
| tree | 69f78b05ff0d7952cd3e3c9332f001e66abb2faf /internal/tui/components/dialog | |
| parent | 904061c243f70696bfe781e97bf4e392e6954d07 (diff) | |
| download | opencode-afd9ad0560d76c2a6d161dad52553b10ff428905.tar.gz opencode-afd9ad0560d76c2a6d161dad52553b10ff428905.zip | |
rework llm
Diffstat (limited to 'internal/tui/components/dialog')
| -rw-r--r-- | internal/tui/components/dialog/permission.go | 185 | ||||
| -rw-r--r-- | internal/tui/components/dialog/quit.go | 23 |
2 files changed, 144 insertions, 64 deletions
diff --git a/internal/tui/components/dialog/permission.go b/internal/tui/components/dialog/permission.go index f7581330a..7dcca9bae 100644 --- a/internal/tui/components/dialog/permission.go +++ b/internal/tui/components/dialog/permission.go @@ -1,9 +1,14 @@ package dialog import ( + "fmt" + "github.com/charmbracelet/bubbles/key" + "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/glamour" "github.com/charmbracelet/lipgloss" + "github.com/kujtimiihoxha/termai/internal/llm/tools" "github.com/kujtimiihoxha/termai/internal/permission" "github.com/kujtimiihoxha/termai/internal/tui/components/core" "github.com/kujtimiihoxha/termai/internal/tui/layout" @@ -28,12 +33,6 @@ type PermissionResponseMsg struct { Action PermissionAction } -// Width and height constants for the dialog -var ( - permissionWidth = 60 - permissionHeight = 10 -) - // PermissionDialog interface for permission dialog component type PermissionDialog interface { tea.Model @@ -41,13 +40,28 @@ type PermissionDialog interface { layout.Bindings } +type keyMap struct { + ChangeFocus key.Binding +} + +var keyMapValue = keyMap{ + ChangeFocus: key.NewBinding( + key.WithKeys("tab"), + key.WithHelp("tab", "change focus"), + ), +} + // permissionDialogCmp is the implementation of PermissionDialog type permissionDialogCmp struct { - form *huh.Form - content string - width int - height int - permission permission.PermissionRequest + form *huh.Form + width int + height int + permission permission.PermissionRequest + windowSize tea.WindowSizeMsg + r *glamour.TermRenderer + contentViewPort viewport.Model + isViewportFocus bool + selectOption *huh.Select[string] } func (p *permissionDialogCmp) Init() tea.Cmd { @@ -57,41 +71,101 @@ func (p *permissionDialogCmp) Init() tea.Cmd { func (p *permissionDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmds []tea.Cmd - // Process the form - form, cmd := p.form.Update(msg) - if f, ok := form.(*huh.Form); ok { - p.form = f - cmds = append(cmds, cmd) + switch msg := msg.(type) { + case tea.WindowSizeMsg: + p.windowSize = msg + case tea.KeyMsg: + if key.Matches(msg, keyMapValue.ChangeFocus) { + p.isViewportFocus = !p.isViewportFocus + if p.isViewportFocus { + p.selectOption.Blur() + } else { + p.selectOption.Focus() + } + return p, nil + } } - if p.form.State == huh.StateCompleted { - // Get the selected action - action := p.form.GetString("action") - - // Close the dialog and return the response - return p, tea.Batch( - util.CmdHandler(core.DialogCloseMsg{}), - util.CmdHandler(PermissionResponseMsg{Action: PermissionAction(action), Permission: p.permission}), - ) + if p.isViewportFocus { + viewPort, cmd := p.contentViewPort.Update(msg) + p.contentViewPort = viewPort + cmds = append(cmds, cmd) + } else { + form, cmd := p.form.Update(msg) + if f, ok := form.(*huh.Form); ok { + p.form = f + cmds = append(cmds, cmd) + } + + if p.form.State == huh.StateCompleted { + // Get the selected action + action := p.form.GetString("action") + + // Close the dialog and return the response + return p, tea.Batch( + util.CmdHandler(core.DialogCloseMsg{}), + util.CmdHandler(PermissionResponseMsg{Action: PermissionAction(action), Permission: p.permission}), + ) + } } - return p, tea.Batch(cmds...) } -func (p *permissionDialogCmp) View() string { - contentStyle := lipgloss.NewStyle(). - Width(p.width). - Padding(1, 0). - Foreground(styles.Text). - Align(lipgloss.Center) +func (p *permissionDialogCmp) render() string { + form := p.form.View() + keyStyle := lipgloss.NewStyle().Bold(true).Foreground(styles.Rosewater) + valueStyle := lipgloss.NewStyle().Foreground(styles.Peach) + + headerParts := []string{ + lipgloss.JoinHorizontal(lipgloss.Left, keyStyle.Render("Tool:"), " ", valueStyle.Render(p.permission.ToolName)), + " ", + lipgloss.JoinHorizontal(lipgloss.Left, keyStyle.Render("Path:"), " ", valueStyle.Render(p.permission.Path)), + " ", + } + r, _ := glamour.NewTermRenderer( + glamour.WithStyles(styles.CatppuccinMarkdownStyle()), + glamour.WithWordWrap(p.width-10), + glamour.WithEmoji(), + ) + content := "" + switch p.permission.ToolName { + case tools.BashToolName: + pr := p.permission.Params.(tools.BashPermissionsParams) + headerParts = append(headerParts, keyStyle.Render("Command:")) + content, _ = r.Render(fmt.Sprintf("```bash\n%s\n```", pr.Command)) + case tools.EditToolName: + pr := p.permission.Params.(tools.EditPermissionsParams) + headerParts = append(headerParts, keyStyle.Render("Update:")) + content, _ = r.Render(fmt.Sprintf("```diff\n%s\n```", pr.Diff)) + case tools.WriteToolName: + pr := p.permission.Params.(tools.WritePermissionsParams) + headerParts = append(headerParts, keyStyle.Render("Content:")) + content, _ = r.Render(fmt.Sprintf("```diff\n%s\n```", pr.Content)) + default: + content, _ = r.Render(p.permission.Description) + } + headerContent := lipgloss.NewStyle().Padding(0, 1).Render(lipgloss.JoinVertical(lipgloss.Left, headerParts...)) + p.contentViewPort.Width = p.width - 2 - 2 + p.contentViewPort.Height = p.height - lipgloss.Height(headerContent) - lipgloss.Height(form) - 2 - 2 - 1 + p.contentViewPort.SetContent(content) + contentBorder := lipgloss.RoundedBorder() + if p.isViewportFocus { + contentBorder = lipgloss.DoubleBorder() + } + cotentStyle := lipgloss.NewStyle().MarginTop(1).Padding(0, 1).Border(contentBorder).BorderForeground(styles.Flamingo) return lipgloss.JoinVertical( - lipgloss.Center, - contentStyle.Render(p.content), - p.form.View(), + lipgloss.Top, + headerContent, + cotentStyle.Render(p.contentViewPort.View()), + form, ) } +func (p *permissionDialogCmp) View() string { + return p.render() +} + func (p *permissionDialogCmp) GetSize() (int, int) { return p.width, p.height } @@ -99,13 +173,14 @@ func (p *permissionDialogCmp) GetSize() (int, int) { func (p *permissionDialogCmp) SetSize(width int, height int) { p.width = width p.height = height + p.form = p.form.WithWidth(width) } func (p *permissionDialogCmp) BindingKeys() []key.Binding { return p.form.KeyBinds() } -func newPermissionDialogCmp(permission permission.PermissionRequest, content string) PermissionDialog { +func newPermissionDialogCmp(permission permission.PermissionRequest) PermissionDialog { // Create a note field for displaying the content // Create select field for the permission options @@ -116,14 +191,13 @@ func newPermissionDialogCmp(permission permission.PermissionRequest, content str huh.NewOption("Allow for this session", string(PermissionAllowForSession)), huh.NewOption("Deny", string(PermissionDeny)), ). - Title("Permission Request") + Title("Select an action") // Apply theme theme := styles.HuhTheme() // Setup form width and height form := huh.NewForm(huh.NewGroup(selectOption)). - WithWidth(permissionWidth - 2). WithShowHelp(false). WithTheme(theme). WithShowErrors(false) @@ -132,25 +206,22 @@ func newPermissionDialogCmp(permission permission.PermissionRequest, content str selectOption.Focus() return &permissionDialogCmp{ - permission: permission, - form: form, - content: content, - width: permissionWidth, - height: permissionHeight, + permission: permission, + form: form, + selectOption: selectOption, } } // NewPermissionDialogCmd creates a new permission dialog command -func NewPermissionDialogCmd(permission permission.PermissionRequest, content string) tea.Cmd { - permDialog := newPermissionDialogCmp(permission, content) +func NewPermissionDialogCmd(permission permission.PermissionRequest) tea.Cmd { + permDialog := newPermissionDialogCmp(permission) // Create the dialog layout dialogPane := layout.NewSinglePane( permDialog.(*permissionDialogCmp), - layout.WithSignlePaneSize(permissionWidth+2, permissionHeight+2), layout.WithSinglePaneBordered(true), layout.WithSinglePaneFocusable(true), - layout.WithSinglePaneActiveColor(styles.Blue), + layout.WithSinglePaneActiveColor(styles.Warning), layout.WithSignlePaneBorderText(map[layout.BorderPosition]string{ layout.TopMiddleBorder: " Permission Required ", }), @@ -158,10 +229,24 @@ func NewPermissionDialogCmd(permission permission.PermissionRequest, content str // Focus the dialog dialogPane.Focus() - + widthRatio := 0.7 + heightRatio := 0.6 + minWidth := 100 + minHeight := 30 + + switch permission.ToolName { + case tools.BashToolName: + widthRatio = 0.5 + heightRatio = 0.3 + minWidth = 80 + minHeight = 20 + } // Return the dialog command return util.CmdHandler(core.DialogMsg{ - Content: dialogPane, + Content: dialogPane, + WidthRatio: widthRatio, + HeightRatio: heightRatio, + MinWidth: minWidth, + MinHeight: minHeight, }) } - diff --git a/internal/tui/components/dialog/quit.go b/internal/tui/components/dialog/quit.go index e73550ab5..60c1fc0d2 100644 --- a/internal/tui/components/dialog/quit.go +++ b/internal/tui/components/dialog/quit.go @@ -3,7 +3,6 @@ package dialog import ( "github.com/charmbracelet/bubbles/key" tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" "github.com/kujtimiihoxha/termai/internal/tui/components/core" "github.com/kujtimiihoxha/termai/internal/tui/layout" "github.com/kujtimiihoxha/termai/internal/tui/styles" @@ -14,11 +13,6 @@ import ( const question = "Are you sure you want to quit?" -var ( - width = lipgloss.Width(question) + 6 - height = 3 -) - type QuitDialog interface { tea.Model layout.Sizeable @@ -37,8 +31,6 @@ func (q *quitDialogCmp) Init() tea.Cmd { func (q *quitDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmds []tea.Cmd - - // Process the form form, cmd := q.form.Update(msg) if f, ok := form.(*huh.Form); ok { q.form = f @@ -67,6 +59,7 @@ func (q *quitDialogCmp) GetSize() (int, int) { func (q *quitDialogCmp) SetSize(width int, height int) { q.width = width q.height = height + q.form = q.form.WithWidth(width).WithHeight(height) } func (q *quitDialogCmp) BindingKeys() []key.Binding { @@ -84,28 +77,30 @@ func newQuitDialogCmp() QuitDialog { theme.Focused.FocusedButton = theme.Focused.FocusedButton.Background(styles.Warning) theme.Blurred.FocusedButton = theme.Blurred.FocusedButton.Background(styles.Warning) form := huh.NewForm(huh.NewGroup(confirm)). - WithWidth(width). - WithHeight(height). WithShowHelp(false). + WithWidth(0). + WithHeight(0). WithTheme(theme). WithShowErrors(false) confirm.Focus() return &quitDialogCmp{ - form: form, - width: width, + form: form, } } func NewQuitDialogCmd() tea.Cmd { content := layout.NewSinglePane( newQuitDialogCmp().(*quitDialogCmp), - layout.WithSignlePaneSize(width+2, height+2), layout.WithSinglePaneBordered(true), layout.WithSinglePaneFocusable(true), layout.WithSinglePaneActiveColor(styles.Warning), ) content.Focus() return util.CmdHandler(core.DialogMsg{ - Content: content, + Content: content, + WidthRatio: 0.2, + HeightRatio: 0.1, + MinWidth: 40, + MinHeight: 5, }) } |
