Split into category packages; module github.com/ZacharyZhang-NY/MujicaUI
This commit is contained in:
1822 files changed
+24568
-21314
No files matched your search
@@ -0,0 +1,141 @@
|
||||
package code
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"path"
|
||||
|
||||
"github.com/egoist/mygo/ui"
|
||||
|
||||
"github.com/ZacharyZhang-NY/MujicaUI/core"
|
||||
"github.com/ZacharyZhang-NY/MujicaUI/icons"
|
||||
)
|
||||
|
||||
// StackFrame is one call of a thread's stack, innermost first.
|
||||
type StackFrame struct {
|
||||
ID, Name, File string
|
||||
Line int
|
||||
}
|
||||
|
||||
// DebugThread is a thread and its stack.
|
||||
type DebugThread struct {
|
||||
ID, Name string
|
||||
Frames []StackFrame
|
||||
}
|
||||
|
||||
// CallStackState is the current frame and folded threads.
|
||||
type CallStackState struct {
|
||||
// Current is the chosen frame's ID.
|
||||
Current string
|
||||
// Collapsed holds folded thread IDs.
|
||||
Collapsed ui.Selection[string]
|
||||
rows ui.ListState
|
||||
selected int
|
||||
flat []callRow
|
||||
seen string
|
||||
folds int
|
||||
started bool
|
||||
}
|
||||
|
||||
type callRow struct{ thread, frame int }
|
||||
|
||||
// CallStackOptions configure a CallStack.
|
||||
type CallStackOptions struct {
|
||||
Disabled bool
|
||||
}
|
||||
|
||||
// CallStack lists frames by thread; choosing sets Current.
|
||||
func CallStack(c *ui.Context, threads []DebugThread, s *CallStackState, opts CallStackOptions) core.ChoiceResult {
|
||||
if s == nil {
|
||||
panic("mujica: CallStack needs a state")
|
||||
}
|
||||
s.flat = s.flat[:0]
|
||||
at := -1
|
||||
for ti, t := range threads {
|
||||
s.flat = append(s.flat, callRow{ti, -1})
|
||||
if s.Collapsed.Has(t.ID) {
|
||||
continue
|
||||
}
|
||||
for fi, f := range t.Frames {
|
||||
if f.ID == s.Current {
|
||||
at = len(s.flat)
|
||||
}
|
||||
s.flat = append(s.flat, callRow{ti, fi})
|
||||
}
|
||||
}
|
||||
// Choose the row again after outside changes.
|
||||
if !s.started || s.seen != s.Current || s.folds != s.Collapsed.Len() || s.selected >= len(s.flat) {
|
||||
s.started, s.seen, s.selected, s.folds = true, s.Current, at, s.Collapsed.Len()
|
||||
}
|
||||
d := core.Density(c)
|
||||
var res core.ChoiceResult
|
||||
res.Element = CodePanel(c).Disabled(opts.Disabled)
|
||||
disabled := res.Element.IsDisabled()
|
||||
res.Element.Children(func() {
|
||||
if len(threads) == 0 {
|
||||
CodeCaption(c, core.Msg(c, "call_stack.empty")).Padding(d.Unit() * 4)
|
||||
return
|
||||
}
|
||||
was := s.selected
|
||||
s.rows.Selected = &s.selected
|
||||
s.rows.Key = func(i int) any { return s.flat[i] }
|
||||
s.rows.Label = func(i int) string { return callLabel(threads, s.flat[i]) }
|
||||
list := CodeRows(c, &s.rows, len(s.flat), func(i int) { callRowView(c, threads, s, s.flat[i], disabled) })
|
||||
if disabled {
|
||||
s.selected = was
|
||||
return
|
||||
}
|
||||
if s.selected < 0 || s.selected >= len(s.flat) {
|
||||
return
|
||||
}
|
||||
r := s.flat[s.selected]
|
||||
t := threads[r.thread]
|
||||
switch {
|
||||
case r.frame >= 0 && s.selected != was:
|
||||
s.Current = t.Frames[r.frame].ID
|
||||
s.seen, res = s.Current, core.NewChoiceResult(res.Element, true)
|
||||
slog.Debug("mujica: call_stack frame", "thread", t.ID, "depth", r.frame)
|
||||
case r.frame < 0 && (list.Submitted() ||
|
||||
!s.Collapsed.Has(t.ID) && list.Shortcut(0, ui.KeyLeft) || s.Collapsed.Has(t.ID) && list.Shortcut(0, ui.KeyRight)):
|
||||
callFold(s, t.ID)
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
func callFold(s *CallStackState, id string) {
|
||||
if s.Collapsed.Has(id) {
|
||||
s.Collapsed.Remove(id)
|
||||
} else {
|
||||
s.Collapsed.Add(id)
|
||||
}
|
||||
slog.Debug("mujica: call_stack fold", "thread", id, "folded", s.Collapsed.Has(id))
|
||||
}
|
||||
|
||||
func callLabel(threads []DebugThread, r callRow) string {
|
||||
t := threads[r.thread]
|
||||
if r.frame < 0 {
|
||||
return t.Name
|
||||
}
|
||||
f := t.Frames[r.frame]
|
||||
return fmt.Sprintf("%s %s:%d", f.Name, path.Base(f.File), f.Line)
|
||||
}
|
||||
|
||||
func callRowView(c *ui.Context, threads []DebugThread, s *CallStackState, r callRow, disabled bool) {
|
||||
t := threads[r.thread]
|
||||
if r.frame < 0 {
|
||||
chev, key := "chevron-down", "search_panel.fold"
|
||||
if s.Collapsed.Has(t.ID) {
|
||||
chev, key = "chevron-right", "search_panel.unfold"
|
||||
}
|
||||
if core.IconAction(c, icons.Must(chev), fmt.Sprintf(core.Msg(c, key), t.Name)).Clicked() && !disabled {
|
||||
callFold(s, t.ID)
|
||||
}
|
||||
ui.Text(c, t.Name).FontWeight(600).SingleLine().Grow(1).MinWidth(0)
|
||||
CodeCaption(c, fmt.Sprintf(core.Msg(c, "call_stack.frames"), len(t.Frames))).Shrink(0)
|
||||
return
|
||||
}
|
||||
f := t.Frames[r.frame]
|
||||
CodeMono(c, f.Name).Grow(1).MinWidth(0).Margin(0, 0, 0, 20)
|
||||
CodeCaption(c, fmt.Sprintf("%s:%d", path.Base(f.File), f.Line)).Shrink(0)
|
||||
}
|
||||
Reference in new issue
Block a user