Files
MujicaUI/examples/gallery/pages_code.go
T

248 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"fmt"
"strings"
"time"
"github.com/egoist/mygo/ui"
"github.com/ZacharyZhang-NY/MujicaUI/code"
"github.com/ZacharyZhang-NY/MujicaUI/core"
"github.com/ZacharyZhang-NY/MujicaUI/input"
)
const codeCategory = "Terminal & Code"
var codePages = []page{
{ID: "321", Name: "Terminal", ZhName: "终端", Category: codeCategory, Demo: codeTerminalDemo, Code: codeTerminalCode,
Keys: "Focused: keys and text go to the PTY; Ctrl+letters send control codes; Cmd+C/V (Ctrl+Shift+C/V elsewhere) copy and paste; Shift+PageUp/PageDown scroll back; drag selects."},
{ID: "322", Name: "TerminalTabs", ZhName: "终端标签", Category: codeCategory, Demo: codeTerminalTabsDemo, Code: codeTerminalTabsCode,
Keys: "Left/Right, Home/End switch tabs; F2 or double-click renames (Enter saves, Escape cancels); Delete closes, asking first while a process runs."},
{ID: "323", Name: "TerminalSearch", ZhName: "终端搜索", Category: codeCategory, Demo: codeTerminalSearchDemo, Code: codeTerminalSearchCode,
Keys: "Enter / Shift+Enter go to the next / previous match; Cmd+G (F3 elsewhere) too."},
{ID: "324", Name: "CommandHistory", ZhName: "命令历史", Category: codeCategory, Demo: codeCommandHistoryDemo, Code: codeCommandHistoryCode,
Keys: "Up/Down choose; Enter or double-click replays; typing in the list jumps by command."},
{ID: "325", Name: "LogViewer", ZhName: "日志查看器", Category: codeCategory, Demo: codeLogViewerDemo, Code: codeLogViewerCode,
Keys: "Space toggles a level or Follow; arrows, PageUp/PageDown, Home/End scroll the log."},
{ID: "326", Name: "ProcessList", ZhName: "进程列表", Category: codeCategory, Demo: codeProcessListDemo, Code: codeProcessListCode,
Keys: "Up/Down choose; Delete ends the chosen process after confirming; click a header to sort, again to reverse."},
{ID: "327", Name: "CodeViewer", ZhName: "代码查看器", Category: codeCategory, Demo: codeCodeViewerDemo, Code: codeCodeViewerCode,
Keys: "Up/Down move the current line; Shift extends; Cmd/Ctrl+C copies; Left folds, Right unfolds."},
{ID: "328", Name: "Minimap", ZhName: "代码缩略图", Category: codeCategory, Demo: codeMinimapDemo, Code: codeMinimapCode,
Keys: "Up/Down move a line, PageUp/PageDown a screen, Home/End to the ends; click or drag jumps."},
{ID: "329", Name: "FindWidget", ZhName: "查找替换", Category: codeCategory, Demo: codeFindWidgetDemo, Code: codeFindWidgetCode,
Keys: "Enter / Shift+Enter next / previous match; Enter in the replace field replaces the current match."},
{ID: "330", Name: "SearchPanel", ZhName: "多文件搜索", Category: codeCategory, Demo: codeSearchPanelDemo, Code: codeSearchPanelCode,
Keys: "Up/Down choose; Enter opens a match or folds a file; Left folds, Right unfolds a file."},
{ID: "331", Name: "ProblemsPanel", ZhName: "问题面板", Category: codeCategory, Demo: codeProblemsDemo, Code: codeProblemsPanelCode,
Keys: "Space toggles a severity; Up/Down choose; Enter opens a problem or folds a file; Left/Right fold and unfold."},
{ID: "332", Name: "OutputPanel", ZhName: "输出面板", Category: codeCategory, Demo: codeOutputDemo, Code: codeOutputPanelCode,
Keys: "Tab reaches the channel menu, Follow and Clear; arrows choose a channel in the open menu."},
{ID: "333", Name: "SymbolOutline", ZhName: "符号大纲", Category: codeCategory, Demo: codeSymbolDemo, Code: codeSymbolOutlineCode,
Keys: "Up/Down move; Right opens, Left closes; Enter or double-click jumps; typing jumps by name."},
{ID: "334", Name: "CompletionMenu", ZhName: "补全菜单", Category: codeCategory, Demo: codeCompletionDemo, Code: codeCompletionMenuCode,
Keys: "While typing: Down/Up move, Tab or Enter accepts, Escape closes; the editor keeps the focus."},
{ID: "335", Name: "DebugToolbar", ZhName: "调试工具栏", Category: codeCategory, Demo: codeDebugDemo, Code: codeDebugToolbarCode,
Keys: "F5 continue, F6 pause, F10 step over, F11 step into, Shift+F11 step out, Cmd/Ctrl+Shift+F5 restart, Shift+F5 stop; Left/Right inside the toolbar."},
{ID: "336", Name: "BreakpointList", ZhName: "断点列表", Category: codeCategory, Demo: codeBreakpointDemo, Code: codeBreakpointListCode,
Keys: "Space toggles; Enter on a location opens it; the condition field saves with Enter, cancels with Escape."},
{ID: "337", Name: "CallStack", ZhName: "调用栈", Category: codeCategory, Demo: codeCallStackDemo, Code: codeCallStackCode,
Keys: "Up/Down choose a frame; Enter folds a thread; Left/Right fold and unfold."},
{ID: "338", Name: "VariablesPanel", ZhName: "变量面板", Category: codeCategory, Demo: codeVariablesDemo, Code: codeVariablesPanelCode,
Keys: "Up/Down move; Right opens, Left closes; Enter, F2 or double-click edits a leaf; Enter saves, Escape cancels."},
{ID: "339", Name: "HexViewer", ZhName: "十六进制查看器", Category: codeCategory, Demo: codeHexDemo, Code: codeHexViewerCode,
Keys: "Arrows move by byte and row; Shift extends; Home/End go to the row ends; Cmd/Ctrl+C copies hex."},
{ID: "340", Name: "Flamegraph", ZhName: "火焰图", Category: codeCategory, Demo: codeFlamegraphDemo, Code: codeFlamegraphCode,
Keys: "Up parent, Down first child, Left/Right siblings; Enter zooms in, Escape zooms out; the readout is announced."},
}
// codeDemoCheck is a switch that logs its changes.
func codeDemoCheck(c *ui.Context, v *bool, label string, log func(string)) {
if input.Switch(c, v, label, input.SwitchOptions{}).Changed() {
log(fmt.Sprintf("%s: %v", label, *v))
}
}
func codeDemoControls(c *ui.Context, fn func()) {
ui.Row(c).Gap(16).Wrap().AlignItems(ui.Center).Margin(0, 0, 16, 0).Children(fn)
}
func codeTerminalDemo(c *ui.Context, log func(string)) {
type state struct {
term code.TerminalState
line string
disabled bool
}
s := ui.Local(c.Root(), "321", func() *state {
s := &state{}
s.term.Write("Welcome to the \x1b[1;35mcourt\x1b[0m shell. Type and press Enter.\r\n$ ")
return s
})
st := *s
codeDemoControls(c, func() {
codeDemoCheck(c, &st.disabled, "Disabled", log)
if input.Button(c, "Clear screen", input.ButtonOptions{Variant: input.Secondary}).Clicked() {
st.term.Write("\x1b[2J\x1b[H$ ")
log("clear screen")
}
})
// A tiny echo shell stands in for the PTY.
code.Terminal(c, &st.term, code.TerminalOptions{Disabled: st.disabled,
Input: func(data string) {
log(fmt.Sprintf("input %q", data))
for _, r := range data {
switch r {
case '\r':
st.term.Write("\r\n" + codeShell(st.line) + "$ ")
st.line = ""
case 0x7f:
if st.line != "" {
st.line = st.line[:len(st.line)-1]
st.term.Write("\b \b")
}
default:
if r >= ' ' {
st.line += string(r)
st.term.Write(string(r))
}
}
}
},
Resized: func(cols, rows int) { log(fmt.Sprintf("resized %d×%d", cols, rows)) },
}).Size(640, 260)
}
// codeShell answers a few commands for the demo terminal.
func codeShell(line string) string {
switch f := strings.Fields(line); {
case len(f) == 0:
return ""
case f[0] == "ls":
return "\x1b[34mchronicles\x1b[0m decrees.txt \x1b[32mseal.sh\x1b[0m\r\n"
case f[0] == "echo":
return strings.Join(f[1:], " ") + "\r\n"
case f[0] == "date":
return time.Now().Format(time.RFC1123) + "\r\n"
}
return "\x1b[31m" + line + ": command not found\x1b[0m\r\n"
}
func codeTerminalTabsDemo(c *ui.Context, log func(string)) {
type state struct {
tabs []code.TerminalTab
active string
next int
disabled bool
}
s := ui.Local(c.Root(), "322", func() *state {
return &state{tabs: []code.TerminalTab{{ID: "1", Title: "zsh"}, {ID: "2", Title: "build", Busy: true}, {ID: "3", Title: "logs"}}, active: "1", next: 4}
})
st := *s
codeDemoControls(c, func() {
codeDemoCheck(c, &st.disabled, "Disabled", log)
if input.Button(c, "New terminal", input.ButtonOptions{Variant: input.Secondary}).Clicked() {
id := fmt.Sprint(st.next)
st.next++
st.tabs = append(st.tabs, code.TerminalTab{ID: id, Title: "shell " + id})
st.active = id
log("new " + id)
}
})
r := code.TerminalTabs(c, &st.tabs, &st.active, code.TerminalTabsOptions{Disabled: st.disabled}, func(id string) {
ui.Text(c, "Terminal "+id+" content").TextColor(core.Tokens(c).TextMuted)
})
r.Element.Width(560)
if r.Changed {
log("active " + st.active)
}
if r.Renamed != "" {
log("renamed " + r.Renamed)
}
if r.Closed != "" {
log("closed " + r.Closed)
}
}
func codeTerminalSearchDemo(c *ui.Context, log func(string)) {
type state struct {
term code.TerminalState
search code.TerminalSearchState
disabled bool
}
s := ui.Local(c.Root(), "323", func() *state {
s := &state{}
for i := range 60 {
if i%9 == 4 {
s.term.Write(fmt.Sprintf("[%02d] \x1b[31merror\x1b[0m: seal %d missing\r\n", i, i))
} else {
s.term.Write(fmt.Sprintf("[%02d] ledger page %d copied\r\n", i, i))
}
}
return s
})
st := *s
codeDemoControls(c, func() { codeDemoCheck(c, &st.disabled, "Disabled", log) })
ui.Column(c).Width(600).Gap(8).Children(func() {
if code.TerminalSearch(c, &st.term, &st.search, code.TerminalSearchOptions{Disabled: st.disabled}).Changed() {
log(fmt.Sprintf("query %q, match %d", st.search.Query, st.search.Current+1))
}
code.Terminal(c, &st.term, code.TerminalOptions{}).Height(220)
})
}
func codeCommandHistoryDemo(c *ui.Context, log func(string)) {
type state struct {
entries []code.HistoryEntry
s code.CommandHistoryState
disabled bool
}
s := ui.Local(c.Root(), "324", func() *state {
at := time.Date(2026, 10, 5, 9, 0, 0, 0, time.UTC)
var e []code.HistoryEntry
for i, cmd := range []string{"git pull", "go build ./...", "go test ./...", "make seal", "ls -la", "git status"} {
e = append(e, code.HistoryEntry{Command: cmd, Time: at.Add(time.Duration(i) * time.Minute)})
}
e[3].ExitCode = 2
return &state{entries: e}
})
st := *s
codeDemoControls(c, func() { codeDemoCheck(c, &st.disabled, "Disabled", log) })
r := code.CommandHistory(c, st.entries, &st.s, code.CommandHistoryOptions{Disabled: st.disabled})
r.Element.Size(480, 300)
if r.Replayed != nil {
log("replay " + r.Replayed.Command)
st.entries = append(st.entries, code.HistoryEntry{Command: r.Replayed.Command, Time: time.Now()})
}
}
func codeLogViewerDemo(c *ui.Context, log func(string)) {
type state struct {
lines []code.LogLine
s code.LogViewerState
disabled bool
}
s := ui.Local(c.Root(), "325", func() *state {
at := time.Date(2026, 10, 5, 9, 0, 0, 0, time.UTC)
lines := make([]code.LogLine, 100_000)
words := []string{"ledger synced", "seal applied", "herald dispatched", "archive rotated"}
for i := range lines {
lines[i] = code.LogLine{Time: at.Add(time.Duration(i) * time.Second), Level: code.LogLevel(i % 7 % 4), Text: fmt.Sprintf("%s #%d", words[i%4], i)}
}
return &state{lines: lines}
})
st := *s
codeDemoControls(c, func() {
codeDemoCheck(c, &st.disabled, "Disabled", log)
if input.Button(c, "Append line", input.ButtonOptions{Variant: input.Secondary}).Clicked() {
st.lines = append(st.lines, code.LogLine{Time: time.Now(), Level: code.LogWarn, Text: fmt.Sprintf("late seal #%d", len(st.lines))})
log("append")
}
})
r := code.LogViewer(c, st.lines, &st.s, code.LogViewerOptions{Disabled: st.disabled})
r.Element.Size(720, 360)
if r.Changed() {
log(fmt.Sprintf("hidden %v, follow %v", st.s.Hidden, st.s.Follow))
}
}