Initial commit of mostly working spreadsheet program
This commit is contained in:
commit
db0c8a1403
|
@ -0,0 +1,2 @@
|
|||
tally
|
||||
*.tss
|
|
@ -0,0 +1,191 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type cell struct {
|
||||
kind int // Enum for the type of cell
|
||||
rawVal string // A raw string of the value
|
||||
num float64 // A quick reference field for the current value
|
||||
expr []string // Fields representing an expression
|
||||
mask string // What the user sees
|
||||
mods []int // Enums of modifiers on the cell
|
||||
}
|
||||
|
||||
func (c cell) String(width int, selected bool) string {
|
||||
mods := ""
|
||||
if selected {
|
||||
mods += "\033[7m"
|
||||
}
|
||||
return fmt.Sprintf("%s%*.*s\033[0m", mods, width, width, c.mask)
|
||||
}
|
||||
|
||||
func (c *cell) Edit(row, col int) {
|
||||
line, err := GetLine(fmt.Sprintf("\033[2KUpdate %c%d: \033[?25h", col+64, row))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Print("\033[?25l")
|
||||
line = strings.TrimSpace(line)
|
||||
c.Update(line)
|
||||
}
|
||||
|
||||
func (c *cell) Update(val string) bool {
|
||||
if val == c.rawVal || len(val) == 0 {
|
||||
// If nothing was changed or the change is empty just return
|
||||
return false
|
||||
}
|
||||
c.rawVal = val
|
||||
num, err := strconv.ParseFloat(val, 64)
|
||||
if err == nil {
|
||||
c.kind = Number
|
||||
c.num = num
|
||||
c.mask = strconv.FormatFloat(num, 'f', -1, 64)
|
||||
} else if strings.HasPrefix(val, "\"") && strings.HasSuffix(val, "\"") {
|
||||
c.kind = Text
|
||||
c.mask = strings.Replace(val[1:len(val)-1], "\\_", " ", -1)
|
||||
} else {
|
||||
c.kind = Expr
|
||||
c.expr = strings.Fields(val)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *cell) Calculate() {
|
||||
if c.kind != Expr {
|
||||
return
|
||||
}
|
||||
if len(c.expr) < 2 {
|
||||
c.mask = "#Err"
|
||||
return
|
||||
}
|
||||
insideString := false
|
||||
s := makeStack()
|
||||
|
||||
for _, v := range c.expr {
|
||||
if IsAddr(v) {
|
||||
c, err := GetCell(Addr2Point(v))
|
||||
if err != nil {
|
||||
c.mask = "#Err"
|
||||
return
|
||||
}
|
||||
if c.kind == Text {
|
||||
v = c.rawVal
|
||||
} else {
|
||||
v = c.mask
|
||||
}
|
||||
} else if IsRange(v) {
|
||||
// TODO Apply range
|
||||
}
|
||||
|
||||
if s.ptr >= 0 && s.text {
|
||||
c.mask = "#Err"
|
||||
return
|
||||
}
|
||||
|
||||
switch true {
|
||||
case strings.HasPrefix(v, "\""):
|
||||
if s.ptr >= 0 {
|
||||
c.mask = "#Err"
|
||||
return
|
||||
}
|
||||
if !strings.HasSuffix(v, "\"") {
|
||||
insideString = true
|
||||
}
|
||||
s.str.WriteString(strings.Replace(v, "\"", "", -1))
|
||||
s.text = true
|
||||
case insideString:
|
||||
if s.ptr >= 0 {
|
||||
c.mask = "#Err"
|
||||
return
|
||||
}
|
||||
if strings.HasSuffix(v, "\"") {
|
||||
insideString = false
|
||||
v = strings.Replace(v, "\"", "", -1)
|
||||
}
|
||||
s.str.WriteRune(' ')
|
||||
s.str.WriteString(v)
|
||||
case IsFunc(v):
|
||||
if s.text {
|
||||
c.mask = "#Err"
|
||||
return
|
||||
} else if v == "+" {
|
||||
s.Add()
|
||||
} else if v == "-" {
|
||||
s.Subtract()
|
||||
} else if v == "/" {
|
||||
s.Divide()
|
||||
} else if v == "*" {
|
||||
s.Multiply()
|
||||
}
|
||||
default:
|
||||
v, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
c.mask = "#Err"
|
||||
return
|
||||
}
|
||||
s.Push(v)
|
||||
}
|
||||
}
|
||||
|
||||
if s.text {
|
||||
c.mask = strings.Replace(s.str.String(), "\\_", " ", -1)
|
||||
} else if s.ptr == 0 {
|
||||
c.mask = strconv.FormatFloat(s.data[0], 'f', -1, 64)
|
||||
} else {
|
||||
c.mask = "Err"
|
||||
}
|
||||
}
|
||||
|
||||
type stack struct {
|
||||
data [100]float64
|
||||
ptr int
|
||||
text bool
|
||||
str strings.Builder
|
||||
}
|
||||
|
||||
func makeStack() stack {
|
||||
return stack{data: [100]float64{}, ptr: -1, text: false}
|
||||
}
|
||||
|
||||
func (s *stack) Push(v float64) {
|
||||
if s.ptr >= 99 {
|
||||
panic("Stack overflow")
|
||||
}
|
||||
s.ptr++
|
||||
s.data[s.ptr] = v
|
||||
}
|
||||
|
||||
func (s *stack) Pop() float64 {
|
||||
if s.ptr < 0 {
|
||||
panic("Stack underflow")
|
||||
}
|
||||
s.ptr--
|
||||
return s.data[s.ptr+1]
|
||||
}
|
||||
|
||||
func (s *stack) Add() {
|
||||
if s.text {
|
||||
val := strconv.FormatFloat(s.Pop(), 'f', -1, 64)
|
||||
s.str.WriteString(val)
|
||||
} else {
|
||||
s.Push(s.Pop() + s.Pop())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stack) Subtract() {
|
||||
second := s.Pop()
|
||||
s.Push(s.Pop() - second)
|
||||
}
|
||||
|
||||
func (s *stack) Multiply() {
|
||||
s.Push(s.Pop() * s.Pop())
|
||||
}
|
||||
|
||||
func (s *stack) Divide() {
|
||||
second := s.Pop()
|
||||
s.Push(s.Pop() / second)
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"tildegit.org/sloum/spreadsheet/termios"
|
||||
)
|
||||
|
||||
const (
|
||||
Empty int = iota
|
||||
Text
|
||||
Number
|
||||
Expr
|
||||
|
||||
Bold
|
||||
Italic
|
||||
)
|
||||
|
||||
var wb workbook
|
||||
var reAddr *regexp.Regexp = regexp.MustCompile(`^[A-Z][0-9]+$`)
|
||||
var reAddrRange *regexp.Regexp = regexp.MustCompile(`^[A-Z][0-9]+:[A-Z][0-9]+$`)
|
||||
|
||||
type point struct {
|
||||
row int
|
||||
col int
|
||||
}
|
||||
|
||||
func runCommand(elems []string) {
|
||||
|
||||
}
|
||||
|
||||
func Getch() rune {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
char, _, err := reader.ReadRune()
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return char
|
||||
}
|
||||
|
||||
func GetLine(prefix string) (string, error) {
|
||||
defer termios.SetCharMode()
|
||||
termios.SetLineMode()
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
fmt.Print(prefix)
|
||||
text, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return text[:len(text)-1], nil
|
||||
}
|
||||
|
||||
func DigitCount(num int) int {
|
||||
counter := 0
|
||||
for ; num > 0; num /= 10 {
|
||||
counter++
|
||||
}
|
||||
return counter
|
||||
}
|
||||
|
||||
func GetCell(p point) (cell, error) {
|
||||
if p.row > wb.sheets[wb.sheet].rows || p.col > wb.sheets[wb.sheet].cols {
|
||||
return cell{}, fmt.Errorf("Invalid reference")
|
||||
}
|
||||
return wb.sheets[wb.sheet].cells[p.row][p.col], nil
|
||||
}
|
||||
|
||||
func Addr2Point(addr string) point {
|
||||
p := point{}
|
||||
p.col = int(addr[0]) - 65
|
||||
p.row, _ = strconv.Atoi(addr[1:])
|
||||
p.row--
|
||||
return p
|
||||
}
|
||||
|
||||
func Point2Addr(p point) string {
|
||||
var s strings.Builder
|
||||
s.WriteRune(rune(p.col) + 65)
|
||||
s.WriteString(strconv.Itoa(p.row+1))
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func ApplyPointDiff(p1, p2 point) point {
|
||||
return point{row: p2.row - p1.row, col: p2.col - p1.col}
|
||||
}
|
||||
|
||||
func IsAddr(addr string) bool {
|
||||
return reAddr.MatchString(addr)
|
||||
}
|
||||
|
||||
func IsRange(addr string) bool {
|
||||
return reAddrRange.MatchString(addr)
|
||||
}
|
||||
|
||||
func IsFunc(val string) bool {
|
||||
switch strings.ToUpper(val) {
|
||||
case "+", "-", "/", "*", "^", "MIN", "MAX", "SQRT",
|
||||
"ROUND", "SUBSTR", "UPPER", "LOWER", "SUM":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
wb = makeWorkbook("test.qsh")
|
||||
wb.Run()
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
- Sheets can have any number of rows
|
||||
- Sheets have a max number of cols (26)
|
||||
- Text and Float are the only types
|
||||
- Expressions are forth style: A2 B3 + C2 A2 - +
|
||||
- Ranges work via ':', for example: A2:C6 +
|
||||
|
||||
- Available expression functions: +, - . \*, /, POW, MIN, MAX, SQRT, ROUND, SUBSTR, UPPER, LOWER, CAPITAL, SUM
|
||||
|
||||
|
||||
TODO:
|
||||
- Write expression parser
|
||||
- Add methods for running expressions
|
||||
- Figure out relative reference logic (when you copy/paste an expression)
|
||||
- File save/save-as, custom format?
|
||||
- File load: custom format, csv
|
||||
- Ability to add/remove/rename sheets
|
||||
- Improve TUI
|
||||
- Make manpage
|
||||
- Make Makefile
|
|
@ -0,0 +1,221 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type sheet struct {
|
||||
name string
|
||||
selection point
|
||||
cells [][]cell
|
||||
cols int
|
||||
rows int
|
||||
zoom int
|
||||
rowOff int
|
||||
colOff int
|
||||
yankBuff cell
|
||||
yankPoint point
|
||||
}
|
||||
|
||||
func (s sheet) Draw(termCols, termRows int) {
|
||||
var selected bool
|
||||
rowDigits := DigitCount(len(s.cells))
|
||||
width := (termCols - rowDigits) / s.zoom
|
||||
if width * s.zoom + rowDigits + 1 > termCols {
|
||||
width -= 1
|
||||
}
|
||||
|
||||
// Print column header
|
||||
fmt.Printf("%s ", strings.Repeat(" ", rowDigits))
|
||||
for i := s.colOff+1; i <= s.colOff + s.zoom; i++ {
|
||||
if i > s.cols {
|
||||
break
|
||||
}
|
||||
pre := "\033[7m"
|
||||
if i == s.selection.col {
|
||||
pre = ""
|
||||
}
|
||||
fmt.Printf("%s%-*c\033[0m", pre, width, i+64)
|
||||
}
|
||||
fmt.Print("\n")
|
||||
|
||||
// Print Rows
|
||||
for row, r := range s.cells[s.rowOff:] {
|
||||
if row >= termRows-5 {
|
||||
break
|
||||
}
|
||||
mod := "\033[7m"
|
||||
if row + s.rowOff == s.selection.row-1 {
|
||||
mod = ""
|
||||
}
|
||||
fmt.Printf("%s%-*d \033[0m", mod, rowDigits, row+1+s.rowOff)
|
||||
|
||||
// Print Cells
|
||||
for col, cell := range r[s.colOff:] {
|
||||
if col >= s.zoom {
|
||||
break
|
||||
}
|
||||
selected = false
|
||||
if s.selection.row-1 == row + s.rowOff && s.selection.col-1 == col + s.colOff {
|
||||
selected = true
|
||||
}
|
||||
fmt.Printf(cell.String(width, selected))
|
||||
}
|
||||
fmt.Print("\n\033[2K")
|
||||
}
|
||||
}
|
||||
|
||||
func (s sheet) CurrentValue(raw bool) string {
|
||||
if raw {
|
||||
return s.cells[s.selection.row-1][s.selection.col-1].rawVal
|
||||
}
|
||||
return s.cells[s.selection.row-1][s.selection.col-1].mask
|
||||
}
|
||||
|
||||
func (s *sheet) Recalculate() {
|
||||
for row, _ := range s.cells {
|
||||
for col, _ := range s.cells[row] {
|
||||
// TODO do this concurrently
|
||||
s.cells[row][col].Calculate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sheet) AddRows(count int) {
|
||||
for ;count > 0; count-- {
|
||||
s.cells = append(s.cells, make([]cell, s.cols))
|
||||
s.rows++
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sheet) AddCols(count int) {
|
||||
for ;count > 0; count-- {
|
||||
for i, _ := range s.cells {
|
||||
s.cells[i] = append(s.cells[i], cell{})
|
||||
}
|
||||
s.cols++
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sheet) Yank() {
|
||||
c := s.cells[s.selection.row-1][s.selection.col-1]
|
||||
s.yankBuff = cell{}
|
||||
s.yankBuff.kind = c.kind
|
||||
s.yankBuff.rawVal = c.rawVal
|
||||
s.yankBuff.num = c.num
|
||||
s.yankBuff.mask = c.mask
|
||||
s.yankBuff.expr = append(s.yankBuff.expr, c.expr...)
|
||||
s.yankBuff.mods = append(s.yankBuff.mods, c.mods...)
|
||||
s.yankPoint = point{row: s.selection.row-1, col: s.selection.col-1}
|
||||
}
|
||||
|
||||
func (s *sheet) Paste() {
|
||||
c := cell{}
|
||||
c.kind = s.yankBuff.kind
|
||||
c.rawVal = s.yankBuff.rawVal
|
||||
c.num = s.yankBuff.num
|
||||
c.mask = s.yankBuff.mask
|
||||
c.expr = append(c.expr, s.yankBuff.expr...)
|
||||
c.mods = append(c.mods, s.yankBuff.mods...)
|
||||
s.cells[s.selection.row-1][s.selection.col-1] = c
|
||||
}
|
||||
|
||||
func (s *sheet) PasteRelative() {
|
||||
c := cell{}
|
||||
c.kind = s.yankBuff.kind
|
||||
c.rawVal = s.yankBuff.rawVal
|
||||
c.num = s.yankBuff.num
|
||||
c.mask = s.yankBuff.mask
|
||||
c.expr = append(c.expr, s.yankBuff.expr...)
|
||||
c.mods = append(c.mods, s.yankBuff.mods...)
|
||||
if c.kind == Expr {
|
||||
for i, v := range c.expr {
|
||||
if IsAddr(v) {
|
||||
refPoint := Addr2Point(v)
|
||||
diff := point{row: s.yankPoint.row-s.selection.row+1, col: s.yankPoint.col-s.selection.col+1}
|
||||
diffApply := point{row: refPoint.row-diff.row, col: refPoint.col-diff.col}
|
||||
p2a := Point2Addr(diffApply)
|
||||
c.expr[i] = p2a
|
||||
}
|
||||
}
|
||||
c.rawVal = strings.Join(c.expr, " ")
|
||||
}
|
||||
s.cells[s.selection.row-1][s.selection.col-1] = c
|
||||
}
|
||||
|
||||
func (s *sheet) moveSelection(dir rune, termRows int) {
|
||||
switch dir {
|
||||
case Left:
|
||||
if s.selection.col > 1 {
|
||||
s.selection.col--
|
||||
}
|
||||
if s.selection.col <= s.colOff {
|
||||
s.colOff--
|
||||
}
|
||||
case Right:
|
||||
s.selection.col++
|
||||
if s.selection.col > s.cols && s.selection.col < 27 {
|
||||
s.AddCols(1)
|
||||
}
|
||||
if s.selection.col > s.colOff + s.zoom && s.cols > s.zoom {
|
||||
s.colOff++
|
||||
}
|
||||
if s.selection.col > 26 {
|
||||
s.selection.col = 26
|
||||
}
|
||||
case Up:
|
||||
if s.selection.row > 1 {
|
||||
s.selection.row--
|
||||
}
|
||||
if s.selection.row <= s.rowOff {
|
||||
s.rowOff--
|
||||
}
|
||||
case Down:
|
||||
s.selection.row++
|
||||
if s.selection.row > s.rows {
|
||||
s.AddRows(1)
|
||||
}
|
||||
if s.selection.row > s.rowOff + termRows - 5 && s.rows > termRows - 5 {
|
||||
s.rowOff++
|
||||
}
|
||||
case RowStart:
|
||||
s.selection.col = 1
|
||||
s.colOff = 0
|
||||
case ToTop:
|
||||
s.selection.row = 1
|
||||
s.rowOff = 0
|
||||
case RowEnd:
|
||||
s.selection.col = s.cols
|
||||
s.colOff = s.cols - s.zoom
|
||||
if s.colOff < 0 {
|
||||
s.colOff = 0
|
||||
}
|
||||
case ToBottom:
|
||||
s.selection.row = s.rows
|
||||
s.rowOff = s.rows - termRows + 5
|
||||
if s.rowOff < 0 {
|
||||
s.rowOff = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sheet) ZoomIn() {
|
||||
if s.zoom == 1 {
|
||||
return
|
||||
}
|
||||
s.zoom-- // Zooming in reduces number of cols viewed
|
||||
}
|
||||
|
||||
func (s *sheet) ZoomOut() {
|
||||
s.zoom++ // Zooming out increases number of cols viewed
|
||||
}
|
||||
|
||||
func makeSheet(name string) sheet {
|
||||
if name == "" {
|
||||
name = "Sheet1"
|
||||
}
|
||||
row := make([][]cell,1, 26)
|
||||
row[0] = make([]cell, 1, 26)
|
||||
return sheet{name, point{1,1}, row, 1, 1, 6, 0, 0, cell{}, point{}}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// +build linux
|
||||
|
||||
package termios
|
||||
|
||||
import "syscall"
|
||||
|
||||
const (
|
||||
getTermiosIoctl = syscall.TCGETS
|
||||
setTermiosIoctl = syscall.TCSETS
|
||||
)
|
|
@ -0,0 +1,10 @@
|
|||
// +build !linux
|
||||
|
||||
package termios
|
||||
|
||||
import "syscall"
|
||||
|
||||
const (
|
||||
getTermiosIoctl = syscall.TIOCGETA
|
||||
setTermiosIoctl = syscall.TIOCSETAF
|
||||
)
|
|
@ -0,0 +1,65 @@
|
|||
package termios
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type winsize struct {
|
||||
Row uint16
|
||||
Col uint16
|
||||
Xpixel uint16
|
||||
Ypixel uint16
|
||||
}
|
||||
|
||||
var fd = os.Stdin.Fd()
|
||||
var initial = getTermios()
|
||||
|
||||
func ioctl(fd, request, argp uintptr) error {
|
||||
if _, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, request, argp); e != 0 {
|
||||
return e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetWindowSize() (int, int) {
|
||||
var value winsize
|
||||
ioctl(fd, syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&value)))
|
||||
return int(value.Col), int(value.Row)
|
||||
}
|
||||
|
||||
func getTermios() syscall.Termios {
|
||||
var value syscall.Termios
|
||||
err := ioctl(fd, getTermiosIoctl, uintptr(unsafe.Pointer(&value)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func setTermios(termios syscall.Termios) {
|
||||
err := ioctl(fd, setTermiosIoctl, uintptr(unsafe.Pointer(&termios)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
runtime.KeepAlive(termios)
|
||||
}
|
||||
|
||||
func SetCharMode() {
|
||||
t := getTermios()
|
||||
t.Lflag = t.Lflag ^ syscall.ICANON
|
||||
t.Lflag = t.Lflag ^ syscall.ECHO
|
||||
setTermios(t)
|
||||
}
|
||||
|
||||
func SetLineMode() {
|
||||
var t = getTermios()
|
||||
t.Lflag = t.Lflag | (syscall.ICANON | syscall.ECHO)
|
||||
setTermios(t)
|
||||
}
|
||||
|
||||
func Restore() {
|
||||
setTermios(initial)
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"tildegit.org/sloum/spreadsheet/termios"
|
||||
)
|
||||
|
||||
const (
|
||||
Left rune = 'h'
|
||||
Right rune = 'l'
|
||||
Up rune = 'k'
|
||||
Down rune = 'j'
|
||||
Quit rune = 'Q'
|
||||
Edit rune = '\n'
|
||||
EditAlt rune = ' '
|
||||
Del rune = 'd'
|
||||
Com rune = ':'
|
||||
ZoomIn rune = '+'
|
||||
ZoomOut rune = '-'
|
||||
Yank rune = 'y'
|
||||
Paste rune = 'p'
|
||||
PasteRelative rune = 'P'
|
||||
ToTop rune = 'g'
|
||||
ToBottom rune = 'G'
|
||||
RowStart rune = '^'
|
||||
RowEnd rune = '$'
|
||||
)
|
||||
|
||||
type workbook struct {
|
||||
name string
|
||||
path string
|
||||
sheets []sheet
|
||||
sheet int
|
||||
termRows int
|
||||
termCols int
|
||||
}
|
||||
|
||||
func (w workbook) Draw() {
|
||||
fmt.Print("\033[0;0H")
|
||||
fmt.Printf("FILE: \033[1m%-*.*s\033[0m\n", w.termCols-6, w.termCols-6, w.path)
|
||||
fmt.Printf("EXPR: %-*.*s\n",
|
||||
w.termCols-6, w.termCols-6,
|
||||
w.sheets[w.sheet].CurrentValue(true))
|
||||
w.sheets[w.sheet].Draw(w.termCols,w.termRows)
|
||||
}
|
||||
|
||||
func (w *workbook) Run() {
|
||||
defer termios.Restore()
|
||||
termios.SetCharMode()
|
||||
fmt.Print("\033[?25l\033[2J")
|
||||
var input rune
|
||||
for {
|
||||
w.Draw()
|
||||
input = Getch()
|
||||
switch input {
|
||||
case Left, Right, Up, Down, ToTop, RowStart, ToBottom, RowEnd:
|
||||
w.sheets[w.sheet].moveSelection(input, w.termRows)
|
||||
case Quit:
|
||||
termios.Restore()
|
||||
fmt.Print("\033[?25h")
|
||||
os.Exit(0)
|
||||
case Edit, EditAlt:
|
||||
w.sheets[w.sheet].cells[w.sheets[w.sheet].selection.row-1][w.sheets[w.sheet].selection.col-1].Edit(w.sheets[w.sheet].selection.row, w.sheets[w.sheet].selection.col)
|
||||
w.sheets[w.sheet].Recalculate()
|
||||
case Del:
|
||||
w.sheets[w.sheet].cells[w.sheets[w.sheet].selection.row-1][w.sheets[w.sheet].selection.col-1] = cell{}
|
||||
w.sheets[w.sheet].Recalculate()
|
||||
case Com:
|
||||
line, err := GetLine(":")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
runCommand(strings.Fields(line))
|
||||
case ZoomIn:
|
||||
w.sheets[w.sheet].ZoomIn()
|
||||
fmt.Print("\033[2J")
|
||||
case ZoomOut:
|
||||
w.sheets[w.sheet].ZoomOut()
|
||||
fmt.Print("\033[2J")
|
||||
case Yank:
|
||||
w.sheets[w.sheet].Yank()
|
||||
case Paste:
|
||||
w.sheets[w.sheet].Paste()
|
||||
w.sheets[w.sheet].Recalculate()
|
||||
case PasteRelative:
|
||||
w.sheets[w.sheet].PasteRelative()
|
||||
w.sheets[w.sheet].Recalculate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeWorkbook(path string) workbook {
|
||||
// TODO parse path and get file name
|
||||
// set name of strict to the filename
|
||||
// or untitled.qsh if no filename; set
|
||||
// path to the full path
|
||||
cols, rows := termios.GetWindowSize()
|
||||
sh := makeSheet("Sheet1")
|
||||
wb = workbook{path, path, make([]sheet,1), 0, rows, cols}
|
||||
wb.sheets[0] = sh
|
||||
return wb
|
||||
}
|
||||
|
||||
func (w workbook) header() string {
|
||||
return fmt.Sprintf("\033[1;7m %s \033[0m %s\n",w.name, w.sheets[w.sheet].name)
|
||||
}
|
||||
|
Loading…
Reference in New Issue