1package ui23import (4 "unicode/utf8"56 tea "charm.land/bubbletea/v2"78 "src.rest/cat/012/internal/sheet"9)1011// Vim marks: m{a-z} marks the active cell, `{a-z} goes back to it (on12// its sheet) and '{a-z} to its row, in column A. Jumps (gg, G, H, M, L,13// /, n, N, a mark, a cell or row from the : line) remember where they14// left from, and '' or `` goes back there. A mark stays on its address:15// rows inserted above it don't move it. Marks live with the workbook.1617// mark is a marked cell.18type mark struct {19 sheet *sheet.Sheet20 at sheet.Addr21}2223// jumpMotions are the motions that count as jumps.24var jumpMotions = map[string]bool{"gg": true, "G": true, "H": true, "M": true, "L": true}2526// jumped remembers the active cell before a jump, to go back to with a27// quote typed twice.28func (m *Model) jumped() {29 if m.visual() == visualNone {30 m.vim.back = &mark{sheet: m.sheet, at: m.cur}31 }32}3334// vimArgKey finishes a sequence that takes a name: the register after ",35// the mark after m, ' or `.36func (m *Model) vimArgKey(key string) tea.Cmd {37 v := &m.vim38 prefix := v.keys39 v.keys = ""40 r, size := utf8.DecodeRuneInString(key)41 if size != len(key) {42 r = 0 // a named key, such as "up"43 }44 switch prefix {45 case `"`:46 if !isRegister(r) {47 m.note = `No register "` + key + `: a-z, 0-9, -, " and +`48 v.reset()49 return nil50 }51 v.reg = r // the count typed before it stays, and more may follow52 case "m":53 v.reset()54 m.setMark(r, key)55 default:56 v.reset()57 m.jumpToMark(r, key, prefix == "`")58 }59 return nil60}6162// setMark is m{a-z}.63func (m *Model) setMark(r rune, key string) {64 if r < 'a' || r > 'z' {65 m.note = "Marks are a to z, not " + key66 return67 }68 if m.vim.marks == nil {69 m.vim.marks = map[rune]mark{}70 }71 m.vim.marks[r] = mark{sheet: m.sheet, at: m.cur}72 m.note = "Mark " + key + " at " + m.cur.String() + "; `" + key + " comes back"73}7475// jumpToMark is `{a-z} (the cell) and '{a-z} (its row, in column A);76// after ' or `, back to where the last jump left from. In VISUAL mode it77// moves the selection's corner, on the sheet shown.78func (m *Model) jumpToMark(r rune, key string, exact bool) {79 var to mark80 switch mk, ok := m.vim.marks[r]; {81 case r == '\'' || r == '`':82 if m.vim.back == nil {83 m.note = "No jump to go back from yet"84 return85 }86 to = *m.vim.back87 case ok:88 to = mk89 case r >= 'a' && r <= 'z':90 m.note = "Mark " + key + " isn't set: m" + key + " sets it"91 return92 default:93 m.note = "Marks are a to z, not " + key94 return95 }96 if !to.sheet.Live() {97 m.note = "Mark " + key + " was on a deleted sheet"98 return99 }100 if !exact {101 to.at.Col = 0102 }103 if m.visual() != visualNone {104 if to.sheet != m.sheet {105 m.note = "Mark " + key + " is on " + to.sheet.Name()106 return107 }108 m.ext = clampAddr(to.at)109 m.ext.Row = m.visibleRow(m.ext.Row)110 return111 }112 m.jumped()113 m.showSheet(to.sheet)114 m.clearSelection()115 m.cur = clampAddr(to.at)116 m.cur.Row = m.visibleRow(m.cur.Row)117}