Initial, working but only with viewport height adjusted a little bit
This commit is contained in:
57
ui/model.go
Normal file
57
ui/model.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"git.pablu.de/pablu/pybug/internal/bridge"
|
||||
"github.com/charmbracelet/bubbles/viewport"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
type Model struct {
|
||||
currentFile string
|
||||
cursor int
|
||||
text string
|
||||
width int
|
||||
height int
|
||||
lineCount int
|
||||
bridge *bridge.Bridge
|
||||
|
||||
listenBridge chan string
|
||||
|
||||
messages []string
|
||||
viewport viewport.Model
|
||||
|
||||
breakpoints map[string][]int
|
||||
}
|
||||
|
||||
func NewModel(b *bridge.Bridge, file string, text string) Model {
|
||||
c := b.Subscribe()
|
||||
|
||||
vp := viewport.New(0, 0)
|
||||
|
||||
return Model{
|
||||
currentFile: file,
|
||||
text: text,
|
||||
cursor: 0,
|
||||
lineCount: len(strings.Split(text, "\n")),
|
||||
bridge: b,
|
||||
breakpoints: make(map[string][]int),
|
||||
listenBridge: c,
|
||||
messages: make([]string, 0),
|
||||
viewport: vp,
|
||||
}
|
||||
}
|
||||
|
||||
func ListenBridge(ch <-chan string) tea.Cmd {
|
||||
return func() tea.Msg {
|
||||
msg := <-ch
|
||||
return StdoutMsg(msg)
|
||||
}
|
||||
}
|
||||
|
||||
type StdoutMsg string
|
||||
|
||||
func (m Model) Init() tea.Cmd {
|
||||
return ListenBridge(m.listenBridge)
|
||||
}
|
||||
21
ui/program.go
Normal file
21
ui/program.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"git.pablu.de/pablu/pybug/internal/bridge"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
func Run(bridge *bridge.Bridge) error {
|
||||
buf, err := os.ReadFile("test.py")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m := NewModel(bridge, "test.py", string(buf))
|
||||
|
||||
p := tea.NewProgram(m, tea.WithAltScreen())
|
||||
_, err = p.Run()
|
||||
return err
|
||||
}
|
||||
50
ui/update.go
Normal file
50
ui/update.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
return m.HandleKeyMsg(msg)
|
||||
case tea.WindowSizeMsg:
|
||||
m.width = msg.Width
|
||||
m.height = msg.Height
|
||||
case StdoutMsg:
|
||||
m.messages = append(m.messages, string(msg))
|
||||
return m, ListenBridge(m.listenBridge)
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m Model) HandleKeyMsg(key tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
switch key.String() {
|
||||
case "q", "ctrl+c":
|
||||
return m, tea.Quit
|
||||
case "k":
|
||||
m.cursor = clamp(0, m.height, m.cursor-1)
|
||||
case "j":
|
||||
m.cursor = clamp(0, min(m.height, m.lineCount-1), m.cursor+1)
|
||||
case "b":
|
||||
m.bridge.Breakpoint(m.currentFile, m.cursor)
|
||||
if file, ok := m.breakpoints[m.currentFile]; ok {
|
||||
m.breakpoints[m.currentFile] = append(file, m.cursor+1)
|
||||
} else {
|
||||
m.breakpoints[m.currentFile] = []int{
|
||||
m.cursor + 1,
|
||||
}
|
||||
}
|
||||
case "c":
|
||||
m.bridge.Continue()
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func clamp(minimum, maximum, val int) int {
|
||||
val = max(minimum, val)
|
||||
val = min(maximum, val)
|
||||
return val
|
||||
}
|
||||
56
ui/view.go
Normal file
56
ui/view.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/chroma/v2/formatters"
|
||||
"github.com/alecthomas/chroma/v2/lexers"
|
||||
"github.com/alecthomas/chroma/v2/styles"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
var panelStyle = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
|
||||
|
||||
func (m Model) View() string {
|
||||
var buf bytes.Buffer
|
||||
lexer := lexers.Get("python")
|
||||
style := styles.Get("monokai")
|
||||
formatter := formatters.Get("terminal16m")
|
||||
|
||||
iterator, _ := lexer.Tokenise(nil, m.text)
|
||||
formatter.Format(&buf, style, iterator)
|
||||
|
||||
var out strings.Builder
|
||||
|
||||
lines := strings.Split(buf.String(), "\n")
|
||||
breakpoints := m.breakpoints[m.currentFile]
|
||||
|
||||
for i, line := range lines {
|
||||
breakpoint := " "
|
||||
cursor := " "
|
||||
|
||||
if slices.Contains(breakpoints, i+1) {
|
||||
breakpoint = "O"
|
||||
}
|
||||
|
||||
if i == m.cursor {
|
||||
cursor = ">"
|
||||
}
|
||||
fmt.Fprintf(&out, "%-4d%s%s %s\n", i+1, breakpoint, cursor, line)
|
||||
}
|
||||
|
||||
frameW, frameH := panelStyle.GetFrameSize()
|
||||
topHeight := m.height * 70 / 100
|
||||
|
||||
code := panelStyle.Width(m.width - frameW).Height(topHeight - frameH).Render(out.String())
|
||||
m.viewport.Height = m.height - (topHeight + frameH)
|
||||
m.viewport.Width = m.width - frameW
|
||||
m.viewport.SetContent(strings.Join(m.messages, ""))
|
||||
m.viewport.GotoBottom()
|
||||
output := panelStyle.Width(m.viewport.Width).Height(m.viewport.Height).Render(m.viewport.View())
|
||||
|
||||
return lipgloss.JoinVertical(lipgloss.Top, code, output)
|
||||
}
|
||||
Reference in New Issue
Block a user