z_mirror/pesticide

git clone https://git.raiguard.me/z_mirror/pesticide

Caleb HeuerUpdate Go module for Codeberg388f8ba

trunk
4.9 KiB196 linesraw
1package ui
2
3import (
4	"fmt"
5
6	tea "github.com/charmbracelet/bubbletea"
7	"github.com/google/go-dap"
8	"codeberg.org/raiguard/pesticide/adapter"
9	"codeberg.org/raiguard/pesticide/command"
10)
11
12func (m *Model) handleCommand(cmd command.Command) tea.Cmd {
13	switch cmd := cmd.(type) {
14	case command.Backtrace:
15		return m.handleBacktraceCommand(cmd)
16	case command.Break:
17		return m.handleBreakCommand(cmd)
18	case command.Continue:
19		return m.handleContinueCommand(cmd)
20	case command.Down:
21		return m.handleStackFrameCommand(-int(cmd))
22	case command.Evaluate:
23		return m.handleEvaluateCommand(cmd)
24	case command.Launch:
25		return m.handleLaunchCommand(cmd)
26	case command.Next:
27		return m.handleNextCommand(cmd)
28	case command.Pause:
29		return m.handlePauseCommand(cmd)
30	case command.Quit:
31		return m.handleQuitCommand(cmd)
32	case command.Step:
33		return m.handleStepCommand(cmd)
34	case command.StepOut:
35		return m.handleStepOutCommand(cmd)
36	case command.Up:
37		return m.handleStackFrameCommand(int(cmd))
38	}
39	return nil
40}
41
42func (m *Model) handleBacktraceCommand(cmd command.Backtrace) tea.Cmd {
43	a := m.focusedAdapter
44	if a == nil {
45		return tea.Println("No adapter in focus")
46	}
47	var output string
48	for _, frame := range a.StackFrames[a.FocusedThread] {
49		output += fmt.Sprintf("%s:%d\n", frame.Source.Path, frame.Line)
50	}
51	return tea.Printf("%s", output)
52}
53
54func (m *Model) handleBreakCommand(cmd command.Break) tea.Cmd {
55	a := m.focusedAdapter
56	if a == nil {
57		return tea.Println("No adapter in focus")
58	}
59	if _, ok := a.Breakpoints[cmd.File]; !ok {
60		a.Breakpoints[cmd.File] = []dap.SourceBreakpoint{}
61	}
62	// TODO: Deduplicate
63	a.Breakpoints[cmd.File] = append(a.Breakpoints[cmd.File], dap.SourceBreakpoint{Line: cmd.Line})
64	m.sendSetBreakpointsRequest(a)
65	return nil
66}
67
68func (m *Model) handleContinueCommand(cmd command.Continue) tea.Cmd {
69	a := m.focusedAdapter
70	if a == nil {
71		return tea.Println("No adapter in focus")
72	}
73	a.Send(&dap.ContinueRequest{Request: a.NewRequest("continue")})
74	return nil
75}
76
77func (m *Model) handleEvaluateCommand(cmd command.Evaluate) tea.Cmd {
78	a := m.focusedAdapter
79	if a == nil {
80		return tea.Println("No adapter in focus")
81	}
82	if a.State != adapter.Stopped {
83		return tea.Println("Cannot evaluate expressions while running")
84	}
85	a.Send(&dap.EvaluateRequest{
86		Request: a.NewRequest("evaluate"),
87		Arguments: dap.EvaluateArguments{
88			Expression: cmd.Expr,
89			FrameId:    a.FocusedStackFrame.Id,
90			Context:    "repl",
91		},
92	})
93	return nil
94}
95
96func (m *Model) handleLaunchCommand(cmd command.Launch) tea.Cmd {
97	adapterConfig, ok := m.config.Adapters[cmd.Name]
98	if !ok {
99		return tea.Printf("Unknown debug adapter %s", cmd.Name)
100	}
101	a, err := adapter.New(adapterConfig)
102	if err != nil {
103		return tea.Println(err)
104	}
105	m.adapters[a.ID] = a
106	m.focusedAdapter = a
107	a.Send(&dap.InitializeRequest{
108		Request: a.NewRequest("initialize"),
109		Arguments: dap.InitializeRequestArguments{
110			ClientID:        "pesticide",
111			ClientName:      "Pesticide",
112			Locale:          "en-US",
113			PathFormat:      "path",
114			LinesStartAt1:   true,
115			ColumnsStartAt1: true,
116		},
117	})
118	return func() tea.Msg { return a.Receive() }
119}
120
121func (m *Model) handlePauseCommand(cmd command.Pause) tea.Cmd {
122	a := m.focusedAdapter
123	if a == nil {
124		return tea.Println("No adapter in focus")
125	}
126	a.Send(&dap.PauseRequest{
127		Request: a.NewRequest("pause"),
128	})
129	return nil
130
131}
132
133func (m *Model) handleQuitCommand(cmd command.Quit) tea.Cmd {
134	a := m.focusedAdapter
135	if a == nil {
136		// TODO: Clean up unfocused adapters
137		return tea.Quit
138	}
139	// TODO: Store whether terminate has been sent and send disconnect in that case
140	if a.Capabilities.SupportsTerminateRequest {
141		a.Send(&dap.TerminateRequest{Request: a.NewRequest("terminate")})
142	} else {
143		a.Send(&dap.DisconnectRequest{
144			Request: a.NewRequest("disconnect"),
145			Arguments: &dap.DisconnectArguments{
146				TerminateDebuggee: true,
147			},
148		})
149		// TODO: Force-remove the adapter from the adapters list
150	}
151	return nil
152}
153
154func (m *Model) handleStackFrameCommand(delta int) tea.Cmd {
155	a := m.focusedAdapter
156	if a == nil {
157		return tea.Println("No adapter in focus")
158	}
159	return m.travelStackFrame(a, delta)
160}
161
162func (m *Model) handleStepCommand(cmd command.Step) tea.Cmd {
163	a := m.focusedAdapter
164	if a == nil {
165		return tea.Println("No adapter in focus")
166	}
167	a.Send(&dap.StepInRequest{
168		Request:   a.NewRequest("stepIn"),
169		Arguments: dap.StepInArguments{ThreadId: a.FocusedThread},
170	})
171	return nil
172}
173
174func (m *Model) handleStepOutCommand(cmd command.StepOut) tea.Cmd {
175	a := m.focusedAdapter
176	if a == nil {
177		return tea.Println("No adapter in focus")
178	}
179	a.Send(&dap.StepOutRequest{
180		Request:   a.NewRequest("stepOut"),
181		Arguments: dap.StepOutArguments{ThreadId: a.FocusedThread},
182	})
183	return nil
184}
185
186func (m *Model) handleNextCommand(cmd command.Next) tea.Cmd {
187	a := m.focusedAdapter
188	if a == nil {
189		return tea.Println("No adapter in focus")
190	}
191	a.Send(&dap.NextRequest{
192		Request:   a.NewRequest("next"),
193		Arguments: dap.NextArguments{ThreadId: a.FocusedThread},
194	})
195	return nil
196}