cat / 012
clone

a spreadsheet for the terminal: lotus 1-2-3 looks, google sheets keys and formulas, one go binary

cat/module-path
012 / internal / ui / vimregs.go
vimregs.go 3.0K
1package ui23import (4 tea "charm.land/bubbletea/v2"56 "src.rest/cat/012/internal/sheet"7)89// Vim registers. The unnamed register is the clipboard Ctrl+V pastes, so10// y, d and x in vim keys and Ctrl+C share it. A register named with "11// before an operator ("ayy, "bx, "ap) holds a copy of its own:12//13// - "a to "z: named, kept until written again;14// - "0: the last copy made without naming a register;15// - "1 to "9: the last rows deleted (dd, cc, V d), newest in "1;16// - "-: the last cells deleted (x, s, v d);17// - "+: the system clipboard, written with OSC 52 as every copy is,18// and read back from the terminal for "+p;19// - "": the unnamed register itself.20//21// Registers live with the workbook, as the clipboard does.2223// vimRegister is what a vim register holds: cells, or whole rows that24// paste as new rows.25type vimRegister struct {26 clip *sheet.Clip27 sheet *sheet.Sheet // where it was copied from28 rows bool29}3031// isRegister reports whether r names a register.32func isRegister(r rune) bool {33 return r >= 'a' && r <= 'z' || r >= '0' && r <= '9' || r == '-' || r == '"' || r == '+'34}3536// storeRegister puts what an operator just copied (the clipboard) in the37// register it named, or when it named none, in "0 for a copy, "1 for38// deleted rows (moving "1 to "8 along to "2 to "9) and "- for deleted39// cells.40func (m *Model) storeRegister(deleted bool) {41 v := &m.vim42 r := vimRegister{clip: m.copied.clip, sheet: m.copied.sheet, rows: m.rowsCopied()}43 if v.regs == nil {44 v.regs = map[rune]vimRegister{}45 }46 switch name := v.reg; {47 case name >= 'a' && name <= 'z', name >= '0' && name <= '9', name == '-':48 v.regs[name] = r49 case name == '+' || name == '"':50 // The clipboard and the system clipboard have it already.51 case !deleted:52 v.regs['0'] = r53 case r.rows:54 for i := '9'; i > '1'; i-- {55 v.regs[i] = v.regs[i-1]56 }57 v.regs['1'] = r58 default:59 v.regs['-'] = r60 }61}6263// fromRegister runs put, a paste of the clipboard, with the register64// named with " in the clipboard's place, leaving the clipboard as it was.65// "+ asks the terminal for the system clipboard, which is pasted when it66// answers (pasteClipboard).67func (m *Model) fromRegister(put func() tea.Cmd) tea.Cmd {68 name := m.vim.reg69 switch name {70 case 0, '"':71 return put()72 case '+':73 m.vim.clipPaste = true74 return tea.ReadClipboard75 }76 r, ok := m.vim.regs[name]77 if !ok || r.clip == nil {78 m.note = `Register "` + string(name) + ` is empty`79 return nil80 }81 saved, savedRows := m.copied, m.vim.rows82 m.copied = clipboard{clip: r.clip, sheet: r.sheet}83 m.vim.rows = nil84 if r.rows {85 m.vim.rows = r.clip86 }87 cmd := put()88 m.copied, m.vim.rows = saved, savedRows89 return cmd90}9192// pasteClipboard pastes the system clipboard's text, read for "+p, at93// the active cell: a block of cells for tab-separated or multi-line94// text, as a terminal paste, or one value entered in the cell.95func (m *Model) pasteClipboard(text string) {96 m.vim.clipPaste = false97 if m.mode != modeReady || text == "" {98 return99 }100 m.handlePaste(text)101 if m.mode == modeEnter {102 m.commit()103 }104}