Working codeviewer implemented
This commit is contained in:
14
ui/codeviewer/messages.go
Normal file
14
ui/codeviewer/messages.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package codeviewer
|
||||||
|
|
||||||
|
type ChangeTextMsg struct {
|
||||||
|
Text string
|
||||||
|
}
|
||||||
|
|
||||||
|
type BreakpointMsg struct {
|
||||||
|
Line int
|
||||||
|
Added bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExecutionStoppedMsg struct {
|
||||||
|
Line int
|
||||||
|
}
|
||||||
@@ -15,16 +15,22 @@ type CodeViewer struct {
|
|||||||
lines []string
|
lines []string
|
||||||
|
|
||||||
Width, Height int
|
Width, Height int
|
||||||
cursor int
|
Cursor int
|
||||||
offset int
|
offset int
|
||||||
|
|
||||||
|
breakpoints map[int]struct{}
|
||||||
|
|
||||||
|
currStoppedLine int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCodeViewer(text string) CodeViewer {
|
func NewCodeViewer(text string) CodeViewer {
|
||||||
cv := CodeViewer{
|
cv := CodeViewer{
|
||||||
Width: 0,
|
Width: 0,
|
||||||
Height: 0,
|
Height: 0,
|
||||||
cursor: 0,
|
Cursor: 0,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
|
currStoppedLine: -1,
|
||||||
|
breakpoints: map[int]struct{}{},
|
||||||
}
|
}
|
||||||
|
|
||||||
return cv.colorize(text)
|
return cv.colorize(text)
|
||||||
@@ -38,8 +44,16 @@ func (c CodeViewer) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
return c.handleKeyMsg(msg)
|
return c.handleKeyMsg(msg)
|
||||||
// case tea.WindowSizeMsg:
|
case ChangeTextMsg:
|
||||||
// return c.UpdateWindowSize(msg)
|
c = c.colorize(msg.Text)
|
||||||
|
case BreakpointMsg:
|
||||||
|
if msg.Added {
|
||||||
|
c.breakpoints[msg.Line] = struct{}{}
|
||||||
|
} else {
|
||||||
|
delete(c.breakpoints, msg.Line)
|
||||||
|
}
|
||||||
|
case ExecutionStoppedMsg:
|
||||||
|
c.currStoppedLine = msg.Line
|
||||||
}
|
}
|
||||||
|
|
||||||
return c, nil
|
return c, nil
|
||||||
@@ -48,40 +62,17 @@ func (c CodeViewer) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
func (c CodeViewer) handleKeyMsg(key tea.KeyMsg) (tea.Model, tea.Cmd) {
|
func (c CodeViewer) handleKeyMsg(key tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||||
switch key.String() {
|
switch key.String() {
|
||||||
case "k":
|
case "k":
|
||||||
c.cursor = max(0, c.cursor-1)
|
c.Cursor = max(0, c.Cursor-1)
|
||||||
topThreshold := c.offset + int(float64(c.Height)*0.1)
|
topThreshold := c.offset + int(float64(c.Height)*0.1)
|
||||||
if c.cursor < topThreshold && c.offset > 0 {
|
if c.Cursor < topThreshold && c.offset > 0 {
|
||||||
c.offset -= 1
|
c.offset -= 1
|
||||||
}
|
}
|
||||||
case "j":
|
case "j":
|
||||||
c.cursor = min(len(c.lines)-1, c.cursor+1)
|
c.Cursor = min(len(c.lines)-1, c.Cursor+1)
|
||||||
bottomThreshold := c.offset + int(float64(c.Height)*0.9)
|
bottomThreshold := c.offset + int(float64(c.Height)*0.9)
|
||||||
if c.cursor > bottomThreshold && c.offset < len(c.lines) {
|
if c.Cursor > bottomThreshold && c.offset < len(c.lines) {
|
||||||
c.offset += 1
|
c.offset += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// case "b":
|
|
||||||
// lineNumber := c.cursor + 1
|
|
||||||
//
|
|
||||||
// c.bridge.Breakpoint(m.currentFile, lineNumber)
|
|
||||||
// if file, ok := m.breakpoints[m.currentFile]; ok {
|
|
||||||
// m.breakpoints[m.currentFile] = append(file, lineNumber)
|
|
||||||
// } else {
|
|
||||||
// m.breakpoints[m.currentFile] = []int{
|
|
||||||
// lineNumber,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// case "s":
|
|
||||||
// m.bridge.Step()
|
|
||||||
// case "c":
|
|
||||||
// m.bridge.Continue()
|
|
||||||
// case "r":
|
|
||||||
// m.messages = make([]string, 0)
|
|
||||||
// m.stdoutOutput.SetContent("")
|
|
||||||
// err := m.bridge.Start()
|
|
||||||
// if err != nil {
|
|
||||||
// slog.Error("could not start brige", "error", err)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return c, nil
|
return c, nil
|
||||||
@@ -105,13 +96,22 @@ func (c CodeViewer) View() string {
|
|||||||
|
|
||||||
lines := c.lines[max(0, c.offset):min(c.offset+c.Height, len(c.lines))]
|
lines := c.lines[max(0, c.offset):min(c.offset+c.Height, len(c.lines))]
|
||||||
for i, line := range lines {
|
for i, line := range lines {
|
||||||
|
lineNumber := i + c.offset + 1
|
||||||
breakpoint := " "
|
breakpoint := " "
|
||||||
cursor := " "
|
cursor := " "
|
||||||
executor := " "
|
executor := " "
|
||||||
if c.offset+i == c.cursor {
|
|
||||||
|
if lineNumber == c.Cursor+1 {
|
||||||
cursor = ">"
|
cursor = ">"
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&out, "%-4d%s%s%s %s\n", c.offset+i+1, breakpoint, executor, cursor, line)
|
if _, ok := c.breakpoints[lineNumber]; ok {
|
||||||
|
breakpoint = "O"
|
||||||
|
}
|
||||||
|
if lineNumber == c.currStoppedLine {
|
||||||
|
executor = "@"
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(&out, "%-4d%s%s%s %s\n", lineNumber, breakpoint, executor, cursor, line)
|
||||||
}
|
}
|
||||||
if len(lines)-c.offset < c.Height {
|
if len(lines)-c.offset < c.Height {
|
||||||
for range c.Height - len(lines) {
|
for range c.Height - len(lines) {
|
||||||
|
|||||||
15
ui/model.go
15
ui/model.go
@@ -17,8 +17,7 @@ type Model struct {
|
|||||||
listenBridge chan string
|
listenBridge chan string
|
||||||
listenBridgeExecutionsStopped chan bridge.ExecutionPoint
|
listenBridgeExecutionsStopped chan bridge.ExecutionPoint
|
||||||
|
|
||||||
currLocals map[string]any
|
currLocals map[string]any
|
||||||
currExecutionPoint bridge.ExecutionPoint
|
|
||||||
|
|
||||||
messages []string
|
messages []string
|
||||||
stdoutOutput viewport.Model
|
stdoutOutput viewport.Model
|
||||||
@@ -43,11 +42,7 @@ func NewModel(b *bridge.Bridge, file string, text string) Model {
|
|||||||
listenBridge: c,
|
listenBridge: c,
|
||||||
listenBridgeExecutionsStopped: c2,
|
listenBridgeExecutionsStopped: c2,
|
||||||
|
|
||||||
currLocals: make(map[string]any),
|
currLocals: make(map[string]any),
|
||||||
currExecutionPoint: bridge.ExecutionPoint{
|
|
||||||
File: file,
|
|
||||||
Line: 0,
|
|
||||||
},
|
|
||||||
breakpoints: make(map[string][]int),
|
breakpoints: make(map[string][]int),
|
||||||
messages: make([]string, 0),
|
messages: make([]string, 0),
|
||||||
|
|
||||||
@@ -67,12 +62,14 @@ func ListenBridge(ch <-chan string) tea.Cmd {
|
|||||||
func ListenBridgeExecutionsStopped(ch <-chan bridge.ExecutionPoint) tea.Cmd {
|
func ListenBridgeExecutionsStopped(ch <-chan bridge.ExecutionPoint) tea.Cmd {
|
||||||
return func() tea.Msg {
|
return func() tea.Msg {
|
||||||
msg := <-ch
|
msg := <-ch
|
||||||
return ExecutionStoppedMsg(msg)
|
return codeviewer.ExecutionStoppedMsg{
|
||||||
|
Line: msg.Line,
|
||||||
|
// TODO, WE IGNORE FILE HERE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type LocalsMsg map[string]any
|
type LocalsMsg map[string]any
|
||||||
type ExecutionStoppedMsg bridge.ExecutionPoint
|
|
||||||
type StdoutMsg string
|
type StdoutMsg string
|
||||||
|
|
||||||
func (m Model) Init() tea.Cmd {
|
func (m Model) Init() tea.Cmd {
|
||||||
|
|||||||
33
ui/update.go
33
ui/update.go
@@ -4,7 +4,6 @@ import (
|
|||||||
"log/slog"
|
"log/slog"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.pablu.de/pablu/pybug/internal/bridge"
|
|
||||||
"git.pablu.de/pablu/pybug/ui/codeviewer"
|
"git.pablu.de/pablu/pybug/ui/codeviewer"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
)
|
)
|
||||||
@@ -23,8 +22,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
m.stdoutOutput.SetContent(strings.Join(m.messages, ""))
|
m.stdoutOutput.SetContent(strings.Join(m.messages, ""))
|
||||||
m.stdoutOutput.GotoBottom()
|
m.stdoutOutput.GotoBottom()
|
||||||
return m, ListenBridge(m.listenBridge)
|
return m, ListenBridge(m.listenBridge)
|
||||||
case ExecutionStoppedMsg:
|
case codeviewer.ExecutionStoppedMsg:
|
||||||
m.currExecutionPoint = bridge.ExecutionPoint(msg)
|
|
||||||
return m, tea.Batch(ListenBridgeExecutionsStopped(m.listenBridgeExecutionsStopped), m.GetLocals())
|
return m, tea.Batch(ListenBridgeExecutionsStopped(m.listenBridgeExecutionsStopped), m.GetLocals())
|
||||||
case LocalsMsg:
|
case LocalsMsg:
|
||||||
m.currLocals = map[string]any(msg)
|
m.currLocals = map[string]any(msg)
|
||||||
@@ -71,17 +69,24 @@ func (m Model) HandleKeyMsg(key tea.KeyMsg) (tea.Model, tea.Cmd) {
|
|||||||
switch key.String() {
|
switch key.String() {
|
||||||
case "q", "ctrl+c":
|
case "q", "ctrl+c":
|
||||||
return m, tea.Quit
|
return m, tea.Quit
|
||||||
// case "b":
|
case "b":
|
||||||
// lineNumber := m.cursor + 1
|
lineNumber := m.codeViewer.Cursor + 1
|
||||||
//
|
|
||||||
// m.bridge.Breakpoint(m.currentFile, lineNumber)
|
m.bridge.Breakpoint(m.currentFile, lineNumber)
|
||||||
// if file, ok := m.breakpoints[m.currentFile]; ok {
|
if file, ok := m.breakpoints[m.currentFile]; ok {
|
||||||
// m.breakpoints[m.currentFile] = append(file, lineNumber)
|
m.breakpoints[m.currentFile] = append(file, lineNumber)
|
||||||
// } else {
|
} else {
|
||||||
// m.breakpoints[m.currentFile] = []int{
|
m.breakpoints[m.currentFile] = []int{
|
||||||
// lineNumber,
|
lineNumber,
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
return m, func() tea.Msg {
|
||||||
|
// check if this is in currently viewed file
|
||||||
|
return codeviewer.BreakpointMsg{
|
||||||
|
Added: true,
|
||||||
|
Line: lineNumber,
|
||||||
|
}
|
||||||
|
}
|
||||||
case "s":
|
case "s":
|
||||||
m.bridge.Step()
|
m.bridge.Step()
|
||||||
case "c":
|
case "c":
|
||||||
|
|||||||
Reference in New Issue
Block a user