@@ 9,14 9,17 @@
package main
import (
+ "bytes"
"fmt"
"os"
"os/exec"
"git.src.quest/~skye/tamma/styles"
"git.src.quest/~skye/tamma/types"
+ "github.com/charmbracelet/bubbles/help"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/list"
+ "github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"gopkg.in/yaml.v3"
@@ 27,21 30,29 @@ type state int
const (
targetSelect state = iota
actionSelect
+ viewOutput
)
type model struct {
- width int
- height int
- err string
- state state
- targetList list.Model
- selectedTarget types.TargetItem
- actionList list.Model
- selectedAction types.ActionItem
- actionListKeys *types.ActionListKeyMap
+ width int
+ height int
+ err string
+ out string
+ state state
+ targetList list.Model
+ selectedTarget types.TargetItem
+ actionList list.Model
+ selectedAction types.ActionItem
+ actionListKeys *types.ActionListKeyMap
+ outputViewport viewport.Model
+ outputViewportKeys *types.OutputViewportKeyMap
+ outputHelp help.Model
}
-type execFinishedMsg struct{ err error }
+type execFinishedMsg struct {
+ err error
+ out bytes.Buffer
+}
func (m model) Init() tea.Cmd {
return nil
@@ 73,8 84,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.err = err.Error()
} else {
c := exec.Command("sh", "-c", execString)
+ var out bytes.Buffer
+ c.Stdout = &out
return m, tea.ExecProcess(c, func(err error) tea.Msg {
- return execFinishedMsg{err}
+ return execFinishedMsg{err, out}
})
}
}
@@ 88,6 101,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.actionList.ResetSelected()
m.state = targetSelect
}
+ case viewOutput:
+ m.state = actionSelect
}
case "c":
switch m.state {
@@ 109,8 124,15 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
}
}
+ case "o":
+ switch m.state {
+ case actionSelect:
+ m.state = viewOutput
+ }
}
case execFinishedMsg:
+ m.out = string(msg.out.Bytes())
+ m.outputViewport.SetContent(m.out)
if msg.err != nil {
m.err = msg.err.Error()
}
@@ 125,6 147,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
m.actionList, cmd = m.actionList.Update(msg)
return m, cmd
+ case viewOutput:
+ var cmd tea.Cmd
+ m.outputViewport, cmd = m.outputViewport.Update(msg)
+ return m, cmd
}
return m, nil
@@ 153,6 179,13 @@ func (m model) View() string {
}
msg += styles.ActionExecString.Width(tlw).SetString(execString).String()
}
+ case viewOutput:
+ m.outputViewport.Height = m.height - 20
+ m.outputViewport.Width = m.width - 2
+ msg += m.outputViewport.View()
+ msg += "\n\npager-like keys apply, plus the following:\n"
+ msg += m.outputHelp.View(m.outputViewportKeys)
+ msg += "\n"
}
if m.err != "" {
@@ 229,22 262,33 @@ func main() {
return []key.Binding{
actionListKeys.Back,
actionListKeys.CopyCommand,
+ actionListKeys.ViewOutput,
}
}
actionList.AdditionalFullHelpKeys = func() []key.Binding {
return []key.Binding{
actionListKeys.Back,
actionListKeys.CopyCommand,
+ actionListKeys.ViewOutput,
}
}
actionList.Styles.Title = styles.ListTitle
actionList.Styles.PaginationStyle = styles.ListPaginaton
+ outputViewport := viewport.New(20, 20)
+ outputViewport.SetHorizontalStep(6) // 6 will be default in bubbles v2
+ outputViewport.Style = styles.ViewportStyle
+ outputViewportKeys := types.NewOutputViewportKeyMap()
+ outputHelp := help.New()
+
p := tea.NewProgram(model{
- state: targetSelect,
- targetList: targetList,
- actionList: actionList,
- actionListKeys: actionListKeys,
+ state: targetSelect,
+ targetList: targetList,
+ actionList: actionList,
+ actionListKeys: actionListKeys,
+ outputViewport: outputViewport,
+ outputViewportKeys: outputViewportKeys,
+ outputHelp: outputHelp,
}, tea.WithAltScreen())
if _, err := p.Run(); err != nil {
fmt.Printf("An error occured while running: %v\n", err)
@@ 30,6 30,7 @@ func NewTargetListKeyMap() *TargetListKeyMap {
type ActionListKeyMap struct {
Back key.Binding
CopyCommand key.Binding
+ ViewOutput key.Binding
}
// NewActionListKeyMap returns a new ActionListKeyMap.
@@ 43,5 44,38 @@ func NewActionListKeyMap() *ActionListKeyMap {
key.WithKeys("c"),
key.WithHelp("c", "copy cmd"),
),
+ ViewOutput: key.NewBinding(
+ key.WithKeys("o"),
+ key.WithHelp("o", "view output"),
+ ),
+ }
+}
+
+// OutputViewportKeyMap defines key bindings for the output viewport.
+type OutputViewportKeyMap struct {
+ Back key.Binding
+}
+
+// NewOutputViewportKeyMap returns a new OutputViewportKeyMap.
+func NewOutputViewportKeyMap() *OutputViewportKeyMap {
+ return &OutputViewportKeyMap{
+ Back: key.NewBinding(
+ key.WithKeys("q"),
+ key.WithHelp("q", "back"),
+ ),
+ }
+}
+
+// ShortHelp returns keybindings to be shown in the mini help view. It's part
+// of the key.Map interface.
+func (k OutputViewportKeyMap) ShortHelp() []key.Binding {
+ return []key.Binding{k.Back}
+}
+
+// FullHelp returns keybindings for the expanded help view. It's part of the
+// key.Map interface.
+func (k OutputViewportKeyMap) FullHelp() [][]key.Binding {
+ return [][]key.Binding{
+ {k.Back},
}
}