Compare commits
2 Commits
18cd13fa92
...
9520f75399
Author | SHA1 | Date |
---|---|---|
sloum | 9520f75399 | |
sloum | 9e090de845 |
13
cell.go
13
cell.go
|
@ -62,14 +62,23 @@ func (c *cell) ToggleMod(mod int) {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *cell) Edit(row, col int) {
|
||||
func (c *cell) Edit(row, col int, text bool) {
|
||||
line, err := GetLine(fmt.Sprintf("\033[2KUpdate %c%d: \033[?25h", col+64, row))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if len(line) == 0 {
|
||||
return
|
||||
}
|
||||
fmt.Print("\033[?25l")
|
||||
line = strings.TrimSpace(line)
|
||||
c.Update(line)
|
||||
if text {
|
||||
line = fmt.Sprintf("\"%s\"", line)
|
||||
}
|
||||
updated := c.Update(line)
|
||||
if updated {
|
||||
modified = true
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cell) Update(val string) bool {
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func LoadCsv(path string, tab bool) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Unable to open file %q", path)
|
||||
os.Exit(1)
|
||||
}
|
||||
wb = makeWorkbook(path)
|
||||
wb.sheets = make([]sheet, 0, 1)
|
||||
s := makeSheet("")
|
||||
s.cols = 0
|
||||
reader := csv.NewReader(f)
|
||||
if tab {
|
||||
reader.Comma = '\t'
|
||||
}
|
||||
for {
|
||||
record, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Err: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
if s.cols == 0 {
|
||||
s.cols = len(record)
|
||||
s.cells = make([][]cell, 0, 10)
|
||||
}
|
||||
r := make([]cell, len(record))
|
||||
for i := range record {
|
||||
_, err := strconv.Atoi(record[i])
|
||||
if err != nil {
|
||||
record[i] = fmt.Sprintf("\"%s\"", record[i])
|
||||
}
|
||||
r[i].Update(record[i])
|
||||
}
|
||||
s.cells = append(s.cells, r)
|
||||
}
|
||||
s.rows = len(s.cells)
|
||||
wb.sheets = append(wb.sheets, s)
|
||||
}
|
||||
|
||||
func WriteCsv(path string, tab bool) {
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
// TODO report error
|
||||
panic(err.Error())
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
writer := csv.NewWriter(f)
|
||||
if tab {
|
||||
writer.Comma = '\t'
|
||||
}
|
||||
|
||||
for _, row := range wb.sheets[wb.sheet].cells {
|
||||
r := make([]string, len(row))
|
||||
for i, cell := range row {
|
||||
r[i] = cell.mask
|
||||
}
|
||||
if err := writer.Write(r); err != nil {
|
||||
// TODO report error
|
||||
}
|
||||
}
|
||||
writer.Flush()
|
||||
if err := writer.Error(); err != nil {
|
||||
// TODO report error
|
||||
panic(err.Error())
|
||||
}
|
||||
}
|
||||
|
21
files.go
21
files.go
|
@ -15,6 +15,7 @@ const (
|
|||
Row rune = 30
|
||||
Field rune = 31
|
||||
End rune = 3
|
||||
ModSep rune = 26
|
||||
)
|
||||
|
||||
func WriteFile(path string) {
|
||||
|
@ -40,6 +41,13 @@ func writeSheet(f *os.File, sh sheet) {
|
|||
o.WriteRune(Row)
|
||||
for c, cell := range row {
|
||||
o.WriteString(cell.rawVal)
|
||||
o.WriteRune(26)
|
||||
modstr := make([]string, len(cell.mods))
|
||||
for _, modint := range cell.mods {
|
||||
ms := strconv.Itoa(modint)
|
||||
modstr = append(modstr, ms)
|
||||
}
|
||||
o.WriteString(strings.Join(modstr, ","))
|
||||
if c < len(row) - 1 {
|
||||
o.WriteRune(Field)
|
||||
}
|
||||
|
@ -49,7 +57,6 @@ func writeSheet(f *os.File, sh sheet) {
|
|||
}
|
||||
|
||||
func LoadFile(path string) {
|
||||
path = ExpandedAbsFilepath(path)
|
||||
fbytes, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
fmt.Fprint(os.Stderr, "Unable to read file\n")
|
||||
|
@ -83,8 +90,18 @@ func LoadFile(path string) {
|
|||
fields := strings.Split(row, fmt.Sprintf("%c", Field))
|
||||
s.cells[i] = make([]cell, s.cols)
|
||||
for x, field := range fields {
|
||||
rawValModSep := strings.Split(field, fmt.Sprintf("%c", ModSep))
|
||||
c := cell{}
|
||||
c.Update(field)
|
||||
c.Update(rawValModSep[0])
|
||||
if len(rawValModSep) > 1 {
|
||||
for _, mod := range strings.Split(rawValModSep[1], ",") {
|
||||
modint, err := strconv.Atoi(mod)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
c.ToggleMod(modint)
|
||||
}
|
||||
}
|
||||
s.cells[i][x] = c
|
||||
}
|
||||
}
|
||||
|
|
62
main.go
62
main.go
|
@ -4,6 +4,7 @@ import (
|
|||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -20,6 +21,7 @@ const (
|
|||
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]+$`)
|
||||
var modified bool = false
|
||||
|
||||
type point struct {
|
||||
row int
|
||||
|
@ -31,15 +33,51 @@ func runCommand(elems []string) {
|
|||
return
|
||||
}
|
||||
switch elems[0] {
|
||||
case "save":
|
||||
case "write", "w":
|
||||
if len(elems) >= 2 {
|
||||
WriteFile(strings.Join(elems[1:], " "))
|
||||
path := ExpandedAbsFilepath(strings.Join(elems[1:], " "))
|
||||
WriteFile(path)
|
||||
} else {
|
||||
WriteFile(wb.path)
|
||||
path := wb.path
|
||||
ext := filepath.Ext(path)
|
||||
if ext != ".tss" {
|
||||
path = path[:len(path)-len(ext)] + ".tss"
|
||||
}
|
||||
WriteFile(path)
|
||||
}
|
||||
case "trim":
|
||||
modified = false
|
||||
case "write-csv", "wc":
|
||||
if len(elems) >= 2 {
|
||||
path := ExpandedAbsFilepath(strings.Join(elems[1:], " "))
|
||||
WriteCsv(path, false)
|
||||
} else {
|
||||
path := wb.path
|
||||
ext := filepath.Ext(path)
|
||||
if ext != ".csv" {
|
||||
path = path[:len(path)-len(ext)] + ".csv"
|
||||
}
|
||||
WriteCsv(path, false)
|
||||
}
|
||||
case "write-tsv", "wt":
|
||||
if len(elems) >= 2 {
|
||||
path := ExpandedAbsFilepath(strings.Join(elems[1:], " "))
|
||||
WriteCsv(path, true)
|
||||
} else {
|
||||
path := wb.path
|
||||
ext := filepath.Ext(path)
|
||||
if ext != ".tsv" {
|
||||
path = path[:len(path)-len(ext)] + ".tsv"
|
||||
}
|
||||
WriteCsv(path, true)
|
||||
}
|
||||
case "trim", "t":
|
||||
wb.sheets[wb.sheet].TrimSheet()
|
||||
fmt.Print("\033[2J") // Clear the screen
|
||||
case "recalculate", "r":
|
||||
wb.sheets[wb.sheet].Recalculate()
|
||||
default:
|
||||
// TODO report error
|
||||
panic("Invalid command")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,10 +96,12 @@ func GetLine(prefix string) (string, error) {
|
|||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
fmt.Print(prefix)
|
||||
fmt.Print("\033[?25h")
|
||||
text, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fmt.Print("\033[?25l")
|
||||
|
||||
return text[:len(text)-1], nil
|
||||
}
|
||||
|
@ -121,7 +161,19 @@ func IsFunc(val string) bool {
|
|||
func main() {
|
||||
args := os.Args
|
||||
if len(args) > 1 {
|
||||
LoadFile(args[1])
|
||||
path := ExpandedAbsFilepath(args[1])
|
||||
ext := strings.ToLower(filepath.Ext(path))
|
||||
switch ext {
|
||||
case ".tss":
|
||||
LoadFile(path)
|
||||
case ".csv":
|
||||
LoadCsv(path, false)
|
||||
case ".tsv":
|
||||
LoadCsv(path, true)
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "Unknown file type %q", ext)
|
||||
os.Exit(1)
|
||||
}
|
||||
wb.sheets[wb.sheet].Recalculate()
|
||||
} else {
|
||||
wb = makeWorkbook("blank.tss")
|
||||
|
|
17
workbook.go
17
workbook.go
|
@ -16,6 +16,7 @@ const (
|
|||
Quit rune = 'Q'
|
||||
Edit rune = '\n'
|
||||
EditAlt rune = ' '
|
||||
EditText rune = '"'
|
||||
Del rune = 'd'
|
||||
Com rune = ':'
|
||||
ZoomIn rune = '+'
|
||||
|
@ -63,11 +64,23 @@ func (w *workbook) Run() {
|
|||
case Left, Right, Up, Down, ToTop, RowStart, ToBottom, RowEnd:
|
||||
w.sheets[w.sheet].moveSelection(input, w.termRows)
|
||||
case Quit:
|
||||
if modified {
|
||||
fmt.Print("There are unsaved changes. Quit? [y/n]")
|
||||
answer := Getch()
|
||||
if answer == 'n' || answer == 'N' {
|
||||
continue
|
||||
}
|
||||
fmt.Print("\n")
|
||||
}
|
||||
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)
|
||||
case Edit, EditAlt, EditText:
|
||||
quote := false
|
||||
if input == EditText {
|
||||
quote = true
|
||||
}
|
||||
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, quote)
|
||||
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{}
|
||||
|
|
Loading…
Reference in New Issue