From e2f4103fdce7912a0510830cec51e306eb26a338 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 16 Sep 2024 15:43:36 -0700 Subject: [PATCH] debugger: more hacking, hex editor with full editing now works --- debugger/hexview.go | 101 +++++++++++++++++----------- debugger/main.go | 103 ++-------------------------- debugger/memory/memory.go | 138 ++++++++++++++++++++++++++++++++++++++ debugger/serial/serial.go | 86 ++++++++++++++++++++++++ debugger/ui.go | 126 ++++++++++++++-------------------- go.mod | 2 - go.sum | 18 ++--- log.txt | 11 +++ 8 files changed, 361 insertions(+), 224 deletions(-) create mode 100644 debugger/memory/memory.go create mode 100644 debugger/serial/serial.go create mode 100644 log.txt diff --git a/debugger/hexview.go b/debugger/hexview.go index 83e9ed9..6fb12c4 100644 --- a/debugger/hexview.go +++ b/debugger/hexview.go @@ -6,14 +6,14 @@ import ( "strings" "unicode" + "git.sentinel65x.com/dave/gary/debugger/memory" tea "github.com/charmbracelet/bubbletea" lip "github.com/charmbracelet/lipgloss" "github.com/creachadair/mds/slice" ) -type HexViewUpdateMem struct { - addr int - bytes []byte +type HexViewSetHeight struct { + Height int } type HexView struct { @@ -21,23 +21,23 @@ type HexView struct { ZeroStyle lip.Style HexStyle lip.Style - write func(int, byte) tea.Cmd + mem *memory.Memory + commit func() tea.Cmd + height int firstAddr int // top of viewport - bytes []byte selectedAddr int editing bool editNibble int // 0 or 1 - newByte byte } -func NewHexView(size int, writeByte func(addr int, val byte) tea.Cmd) HexView { +func NewHexView(mem *memory.Memory, commit func() tea.Cmd) HexView { st := lip.NewStyle() ret := HexView{ AddrStyle: st, ZeroStyle: st, HexStyle: st, - write: writeByte, - bytes: make([]byte, size), + mem: mem, + commit: commit, } return ret } @@ -52,12 +52,25 @@ func (m HexView) SelectedAddr() int { return m.selectedAddr } +func (m *HexView) moveSelection(delta int) bool { + newAddr := m.selectedAddr + delta + if newAddr >= 0 && newAddr < m.mem.Len() { + m.selectedAddr = newAddr + return true + } + return false +} + +func (m HexView) VisibleBytes() (start, end int) { + return m.firstAddr, m.firstAddr + (m.height * 16) +} + func (m HexView) addrFormat() string { return fmt.Sprintf("%%%dx", m.addrNibbles()) } func (m HexView) addrNibbles() int { - return int(math.Ceil(math.Log2(float64(len(m.bytes)-1)))) / 4 + return int(math.Ceil(math.Log2(float64(m.mem.Len())*8))) / 4 } func (m HexView) Update(msg tea.Msg) (HexView, tea.Cmd) { @@ -70,31 +83,43 @@ func (m HexView) Update(msg tea.Msg) (HexView, tea.Cmd) { func (m HexView) updateEditMode(msg tea.Msg) (HexView, tea.Cmd) { switch msg := msg.(type) { - case HexViewUpdateMem: - copy(m.bytes[msg.addr:], msg.bytes) + case HexViewSetHeight: + m.height = msg.Height case tea.KeyMsg: switch msg.Type { case tea.KeyLeft: if m.editNibble == 1 { m.editNibble = 0 + } else if m.moveSelection(-1) { + m.editNibble = 1 } case tea.KeyRight: if m.editNibble == 0 { m.editNibble = 1 + } else if m.moveSelection(1) { + m.editNibble = 0 } + case tea.KeyUp: + m.moveSelection(-16) + case tea.KeyDown: + m.moveSelection(16) case tea.KeyEsc: m.editing = false case tea.KeyEnter: m.editing = false - return m, m.write(m.selectedAddr, m.newByte) + return m, m.commit() case tea.KeyRunes: if unicode.In(msg.Runes[0], unicode.ASCII_Hex_Digit) { nibble := hexToNibble(msg.Runes[0]) + prev := m.mem.At(m.selectedAddr).Value if m.editNibble == 0 { - m.newByte = (nibble << 4) + (m.newByte & 0xF) + m.mem.Write(m.selectedAddr, (nibble<<4)+(prev&0xF)) m.editNibble++ } else { - m.newByte = (m.newByte & 0xF0) + nibble + m.mem.Write(m.selectedAddr, (prev&0xF0)+nibble) + if m.moveSelection(1) { + m.editNibble = 0 + } } } } @@ -116,45 +141,37 @@ func hexToNibble(r rune) byte { func (m HexView) updateViewMode(msg tea.Msg) (HexView, tea.Cmd) { switch msg := msg.(type) { - case HexViewUpdateMem: - copy(m.bytes[msg.addr:], msg.bytes) + case HexViewSetHeight: + m.height = msg.Height case tea.KeyMsg: switch msg.String() { case "up": - if m.selectedAddr >= 16 { - m.selectedAddr -= 16 - } + m.moveSelection(-16) case "down": - if m.selectedAddr < len(m.bytes)-16 { - m.selectedAddr += 16 - } + m.moveSelection(16) case "left": - if m.selectedAddr > 0 { - m.selectedAddr-- - } + m.moveSelection(-1) case "right": - if m.selectedAddr < len(m.bytes)-1 { - m.selectedAddr++ - } + m.moveSelection(1) case "pgdown": - // TODO + m.moveSelection(m.height * 16) case "pgup": - // TODO + m.moveSelection(-m.height * 16) case "w": m.editing = true m.editNibble = 0 - m.newByte = m.bytes[m.selectedAddr] } } return m, nil } func (m HexView) View(height int) string { - maxLen := 16 * height - endAddr := min(len(m.bytes), m.firstAddr+maxLen) + startAddr, endAddr := m.VisibleBytes() + bytes := m.mem.Slice(startAddr, endAddr) + var ret strings.Builder addrFormat := m.addrFormat() - for line, bytes := range slice.Chunks(m.bytes[m.firstAddr:endAddr], 16) { + for line, bytes := range slice.Chunks(bytes, 16) { lineAddr := m.firstAddr + (16 * line) ret.WriteString(m.AddrStyle.Render(fmt.Sprintf(addrFormat, lineAddr))) ret.WriteString(" ") @@ -166,22 +183,24 @@ func (m HexView) View(height int) string { ret.WriteByte(' ') } if m.editing && byteAddr == m.selectedAddr { - st := m.HexStyle.Underline(true) + st := m.HexStyle.Bold(true) s1, s2 := st.Reverse(true), st if m.editNibble == 1 { s1, s2 = s2, s1 } - b = m.newByte - ret.WriteString(s1.Render(fmt.Sprintf("%01x", b>>4))) - ret.WriteString(s2.Render(fmt.Sprintf("%01x", b&0xF))) + ret.WriteString(s1.Render(fmt.Sprintf("%01x", b.Value>>4))) + ret.WriteString(s2.Render(fmt.Sprintf("%01x", b.Value&0xF))) } else { st := m.HexStyle if m.selectedAddr == byteAddr { st = m.HexStyle.Reverse(true) - } else if b == 0 { + } else if !b.Valid || b.Value == 0 { st = m.ZeroStyle } - ret.WriteString(st.Render(fmt.Sprintf("%02x", b))) + if b.Changed { + st = st.Underline(true).Bold(true) + } + ret.WriteString(st.Render(b.Hex())) } } ret.WriteByte('\n') diff --git a/debugger/main.go b/debugger/main.go index 3ca8983..dcd1096 100644 --- a/debugger/main.go +++ b/debugger/main.go @@ -1,115 +1,22 @@ package main import ( - "errors" - "fmt" "log" - "sync" - "time" - "go.bug.st/serial" + "git.sentinel65x.com/dave/gary/debugger/memory" + "git.sentinel65x.com/dave/gary/debugger/serial" ) -const portDev = "/dev/ttyUSB0" - func main() { - dbg, err := Open() + dbg, err := serial.Open() if err != nil { log.Fatalf("connecting to debugger: %v", err) } defer dbg.Close() - if err := dbg.Write(0x42, 123); err != nil { - log.Fatalf("writing to memory: %v", err) - } + mem := memory.New(dbg, 768) - if err := UI(dbg); err != nil { + if err := UI(mem); err != nil { log.Fatal(err) } } - -type Debugger struct { - port serial.Port - mu sync.Mutex -} - -func Open() (*Debugger, error) { - mode := &serial.Mode{ - BaudRate: 115_200, - } - port, err := serial.Open(portDev, mode) - if err != nil { - return nil, err - } - - return &Debugger{port: port}, nil -} - -func (d *Debugger) Close() error { - d.mu.Lock() // note, deliberately no unlocking, to poison. - return d.port.Close() -} - -func encode(addr int, write bool, data byte) [4]byte { - writeVal := uint8(0) - if write { - writeVal = 1 - } - var ret [4]byte - ret[3] = data - ret[2] = byte(addr<<1) | writeVal - ret[1] = byte(addr >> 7) - ret[0] = byte(addr >> 15) - return ret -} - -func (d *Debugger) Read(addr int) (byte, error) { - d.mu.Lock() - defer d.mu.Unlock() - if addr >= 2<<17 { - return 0, fmt.Errorf("read %d out of bounds", addr) - } - - packet := encode(addr, false, 0) - //fmt.Printf("Writing: %02x %02x %02x %02x\n", packet[0], packet[1], packet[2], packet[3]) - if _, err := d.port.Write(packet[:]); err != nil { - return 0, err - } - - d.port.SetReadTimeout(2 * time.Second) - - n, err := d.port.Read(packet[:1]) - if err != nil { - return 0, err - } else if n == 0 { - return 0, errors.New("no read") - } - return packet[0], nil -} - -func (d *Debugger) Write(addr int, val byte) error { - d.mu.Lock() - defer d.mu.Unlock() - if addr >= 2<<17 { - return fmt.Errorf("write %d out of bounds", addr) - } - - packet := encode(addr, true, val) - //fmt.Printf("Writing: %02x %02x %02x %02x\n", packet[0], packet[1], packet[2], packet[3]) - if _, err := d.port.Write(packet[:]); err != nil { - return err - } - return nil -} - -func (d *Debugger) Dump(startAddr int, count int) ([]byte, error) { - ret := make([]byte, count) - var err error - for i := range ret { - ret[i], err = d.Read(startAddr + i) - if err != nil { - return nil, err - } - } - return ret, nil -} diff --git a/debugger/memory/memory.go b/debugger/memory/memory.go new file mode 100644 index 0000000..1f8ac61 --- /dev/null +++ b/debugger/memory/memory.go @@ -0,0 +1,138 @@ +package memory + +import ( + "fmt" + "io" + "sync" +) + +type MemoryByte struct { + Value byte + Valid bool + Changed bool +} + +func (b MemoryByte) Hex() string { + if !b.Valid { + return "??" + } + return fmt.Sprintf("%02x", b.Value) +} + +func (b MemoryByte) Dec() string { + if !b.Valid { + return "???" + } + return fmt.Sprintf("%d", b.Value) +} + +func (b MemoryByte) Bin() string { + if !b.Valid { + return "????????" + } + return fmt.Sprintf("%08b", b.Value) +} + +type MemorySrc interface { + io.ReaderAt + io.WriterAt +} + +type Memory struct { + src MemorySrc + + mu sync.Mutex + bytes []MemoryByte + pendingWrites map[int]byte +} + +func New(src MemorySrc, size int) *Memory { + ret := &Memory{ + src: src, + bytes: make([]MemoryByte, size), + pendingWrites: map[int]byte{}, + } + return ret +} + +func (m *Memory) Len() int { + m.mu.Lock() + defer m.mu.Unlock() + return len(m.bytes) +} + +func (m *Memory) Load(start, count int) error { + if m.needsRefresh(start, count) { + return m.Refresh(start, count) + } + return nil +} + +func (m *Memory) needsRefresh(start, count int) bool { + m.mu.Lock() + defer m.mu.Unlock() + for _, b := range m.bytes { + if !b.Valid { + return true + } + } + return false +} + +func (m *Memory) Refresh(start, count int) error { + bs := make([]byte, count) + if _, err := m.src.ReadAt(bs, int64(start)); err != nil { + return err + } + m.mu.Lock() + defer m.mu.Unlock() + for i, v := range bs { + m.bytes[start+i] = MemoryByte{v, true, false} + } + return nil +} + +func (m *Memory) At(addr int) MemoryByte { + m.mu.Lock() + defer m.mu.Unlock() + if addr >= len(m.bytes) { + return MemoryByte{} + } + if v, ok := m.pendingWrites[addr]; ok { + return MemoryByte{v, true, true} + } + return m.bytes[addr] +} + +func (m *Memory) Slice(start, end int) []MemoryByte { + ret := make([]MemoryByte, end-start) + for i := range ret { + ret[i] = m.At(start + i) + } + return ret +} + +func (m *Memory) Write(addr int, val byte) { + m.mu.Lock() + defer m.mu.Unlock() + m.pendingWrites[addr] = val +} + +func (m *Memory) Commit() error { + m.mu.Lock() + defer m.mu.Unlock() + for addr, val := range m.pendingWrites { + if _, err := m.src.WriteAt([]byte{val}, int64(addr)); err != nil { + return err + } + delete(m.pendingWrites, addr) + m.bytes[addr] = MemoryByte{val, true, false} + } + return nil +} + +func (m *Memory) HasPendingWrites() bool { + m.mu.Lock() + defer m.mu.Unlock() + return len(m.pendingWrites) > 0 +} diff --git a/debugger/serial/serial.go b/debugger/serial/serial.go new file mode 100644 index 0000000..351711d --- /dev/null +++ b/debugger/serial/serial.go @@ -0,0 +1,86 @@ +package serial + +import ( + "errors" + "sync" + "time" + + "go.bug.st/serial" +) + +const portDev = "/dev/ttyUSB0" +const maxAddr = 1 << 17 + +type Serial struct { + portMu sync.Mutex + port serial.Port +} + +func Open() (*Serial, error) { + mode := &serial.Mode{ + BaudRate: 115_200, + } + port, err := serial.Open(portDev, mode) + if err != nil { + return nil, err + } + + return &Serial{port: port}, nil +} + +func (d *Serial) Close() error { + d.portMu.Lock() + defer d.portMu.Unlock() + return d.port.Close() +} + +func encode(addr int, write bool, data byte) [4]byte { + writeVal := uint8(0) + if write { + writeVal = 1 + } + var ret [4]byte + ret[3] = data + ret[2] = byte(addr<<1) | writeVal + ret[1] = byte(addr >> 7) + ret[0] = byte(addr >> 15) + return ret +} + +func (d *Serial) ReadAt(bs []byte, off int64) (int, error) { + d.portMu.Lock() + defer d.portMu.Unlock() + if off+int64(len(bs)) >= maxAddr { + return 0, errors.New("OOB read") + } + for i := range bs { + packet := encode(int(off)+i, false, 0) + if _, err := d.port.Write(packet[:]); err != nil { + return i, err + } + d.port.SetReadTimeout(2 * time.Second) + n, err := d.port.Read(packet[:1]) + if err != nil { + return i, err + } else if n == 0 { + return i, errors.New("short read") + } + bs[i] = packet[0] + } + return len(bs), nil +} + +func (d *Serial) WriteAt(bs []byte, off int64) (int, error) { + d.portMu.Lock() + defer d.portMu.Unlock() + if off+int64(len(bs)) >= maxAddr { + return 0, errors.New("OOB write") + } + for i, v := range bs { + packet := encode(int(off)+i, true, v) + if _, err := d.port.Write(packet[:]); err != nil { + return i, err + } + } + return len(bs), nil +} diff --git a/debugger/ui.go b/debugger/ui.go index ddb8691..d0c20d1 100644 --- a/debugger/ui.go +++ b/debugger/ui.go @@ -2,15 +2,26 @@ package main import ( "fmt" - "strings" - "unicode" + "log" + "git.sentinel65x.com/dave/gary/debugger/memory" tea "github.com/charmbracelet/bubbletea" lip "github.com/charmbracelet/lipgloss" ) -func UI(dbg *Debugger) error { - p := tea.NewProgram(initialModel(dbg)) //failed{0, 0, true}, tea.WithAltScreen()) +func UI(mem *memory.Memory) error { + initial := debugger{ + width: 0, + height: 0, + mem: mem, + bottomMsg: "Loading...", + } + initial.hex = NewHexView(mem, initial.commitWrites) + initial.hex.AddrStyle = text + initial.hex.ZeroStyle = faintText + initial.hex.HexStyle = text + + p := tea.NewProgram(initial) if _, err := p.Run(); err != nil { return err } @@ -27,6 +38,10 @@ var ( BorderBackground(slate) ) +type msgMemoryChanged struct { + start, count int +} + type msgErr struct { err error } @@ -38,29 +53,34 @@ type msgUpdateStatus struct { type debugger struct { width int height int - dbg *Debugger + mem *memory.Memory hex HexView lastErr error bottomMsg string } -func initialModel(dbg *Debugger) debugger { - ret := debugger{ - width: 0, - height: 0, - dbg: dbg, - bottomMsg: "", - } - hex := NewHexView(128*1024, ret.writeByte) - hex.AddrStyle = text - hex.ZeroStyle = faintText - hex.HexStyle = text - ret.hex = hex - return ret +func (m debugger) Init() tea.Cmd { + return tea.Sequence( + m.readFullMemory(), + staticMsg(msgUpdateStatus{"Initial load complete."}), + ) } -func (m debugger) Init() tea.Cmd { - return m.dumpMemory(0x200) +func (m debugger) readFullMemory() tea.Cmd { + var ret []tea.Cmd + for i := 0; i < m.mem.Len(); i += 128 { + ret = append(ret, m.readMemory(i, 128)) + } + return tea.Sequence(ret...) +} + +func (m debugger) readMemory(start, count int) tea.Cmd { + return func() tea.Msg { + if err := m.mem.Load(start, count); err != nil { + return msgErr{fmt.Errorf("loading region 0x%x+%x: %w", start, count, err)} + } + return msgMemoryChanged{start, count} + } } func staticMsg(msg tea.Msg) tea.Cmd { @@ -69,49 +89,38 @@ func staticMsg(msg tea.Msg) tea.Cmd { } } -func (m debugger) dumpMemory(count int) tea.Cmd { - var ret []tea.Cmd - for i := 0; i < count; i += 16 { - ret = append(ret, func() tea.Msg { - mem, err := m.dbg.Dump(i, 16) - if err != nil { - return msgErr{err} - } - return HexViewUpdateMem{i, mem} - }) - } - return tea.Sequence(ret...) -} - -func (m debugger) writeByte(addr int, val byte) tea.Cmd { +func (m debugger) commitWrites() tea.Cmd { return tea.Sequence( staticMsg(msgUpdateStatus{"Writing..."}), func() tea.Msg { - if err := m.dbg.Write(addr, val); err != nil { + if err := m.mem.Commit(); err != nil { return msgUpdateStatus{fmt.Sprintf("Write failed: %v", err)} } - return tea.BatchMsg{ - staticMsg(HexViewUpdateMem{addr, []byte{val}}), - staticMsg(msgUpdateStatus{"Written!"}), - } + return msgUpdateStatus{"Writes complete."} }, - m.dumpMemory(0x200), + m.readFullMemory(), ) } func (m debugger) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + log.Printf("msv: %#v", msg) switch msg := msg.(type) { case tea.WindowSizeMsg: m.width = msg.Width m.height = msg.Height + var cmd tea.Cmd + m.hex, cmd = m.hex.Update(HexViewSetHeight{m.height - 6}) // TODO: make less shit + return m, cmd case tea.KeyMsg: switch msg.String() { case "ctrl+c", "q": return m, tea.Quit case "r": - return m, m.dumpMemory(0x200) + start, end := m.hex.VisibleBytes() + return m, m.readMemory(start, end-start) } case msgErr: + log.Print(msg.err) m.lastErr = msg.err return m, nil case msgUpdateStatus: @@ -166,36 +175,3 @@ func (m debugger) View() string { top := lip.JoinVertical(lip.Center, topStatus, hex, bottomStatus) return top } - -func renderByte(b byte, format string) string { - ret := fmt.Sprintf(format, b) - if b == 0 { - return faintText.Render(ret) - } - return text.Render(ret) -} - -func renderBytes(bs []byte, format string, sep string) string { - var s strings.Builder - for i, b := range bs { - s.WriteString(renderByte(b, format)) - if i < len(bs)-1 { - s.WriteString(faintText.Render(sep)) - } - } - return s.String() -} - -func dimZero(s string) string { - allZero := true - for _, r := range s { - if !unicode.IsSpace(r) && r != '0' { - allZero = false - break - } - } - if allZero { - return faintText.Render(s) - } - return text.Render(s) -} diff --git a/go.mod b/go.mod index e27ebfa..440f6c8 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.23 toolchain go1.23.0 require ( - github.com/charmbracelet/bubbles v0.20.0 github.com/charmbracelet/bubbletea v1.1.1 github.com/charmbracelet/lipgloss v0.13.0 github.com/creachadair/mds v0.21.2 @@ -13,7 +12,6 @@ require ( ) require ( - github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/charmbracelet/x/ansi v0.2.3 // indirect github.com/charmbracelet/x/term v0.2.0 // indirect diff --git a/go.sum b/go.sum index 49995f2..9e4963f 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,5 @@ -github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= -github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE= -github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU= github.com/charmbracelet/bubbletea v1.1.1 h1:KJ2/DnmpfqFtDNVTvYZ6zpPFL9iRCRr0qqKOCvppbPY= github.com/charmbracelet/bubbletea v1.1.1/go.mod h1:9Ogk0HrdbHolIKHdjfFpyXJmiCzGwy+FesYkZr7hYU4= github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= @@ -16,16 +12,18 @@ github.com/creachadair/mds v0.21.2 h1:D5130qi/kqmu+gGUQyDNOhrocGQp075ziTCgttxhh3 github.com/creachadair/mds v0.21.2/go.mod h1:1ltMWZd9yXhaHEoZwBialMaviWVUpRPvMwVP7saFAzM= github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0= github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= @@ -34,18 +32,22 @@ github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELU github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= go.bug.st/serial v1.6.2 h1:kn9LRX3sdm+WxWKufMlIRndwGfPWsH1/9lCWXQCasq8= go.bug.st/serial v1.6.2/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY= -golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/log.txt b/log.txt new file mode 100644 index 0000000..ae60d9c --- /dev/null +++ b/log.txt @@ -0,0 +1,11 @@ +2024/09/16 15:45:59 msv: tea.sequenceMsg{(tea.Cmd)(0x50b580), (tea.Cmd)(0x50b380)} +2024/09/16 15:45:59 msv: tea.sequenceMsg{(tea.Cmd)(0x50b5c0), (tea.Cmd)(0x50b5c0), (tea.Cmd)(0x50b5c0), (tea.Cmd)(0x50b5c0), (tea.Cmd)(0x50b5c0), (tea.Cmd)(0x50b5c0)} +2024/09/16 15:45:59 msv: tea.WindowSizeMsg{Width:141, Height:39} +2024/09/16 15:45:59 msv: main.msgUpdateStatus{status:"Initial load complete."} +2024/09/16 15:46:00 msv: main.msgMemoryChanged{start:0, count:128} +2024/09/16 15:46:00 msv: main.msgMemoryChanged{start:128, count:128} +2024/09/16 15:46:00 msv: main.msgMemoryChanged{start:256, count:128} +2024/09/16 15:46:00 msv: main.msgMemoryChanged{start:384, count:128} +2024/09/16 15:46:00 msv: main.msgMemoryChanged{start:512, count:128} +2024/09/16 15:46:00 msv: main.msgMemoryChanged{start:640, count:128} +2024/09/16 15:46:01 msv: tea.KeyMsg{Type:-1, Runes:[]int32{113}, Alt:false, Paste:false}