Added support for TSV files

This uses a similar parser as CSV files, except configured for tabs.
Have also fixed the configured parser to ignore column counts.
This commit is contained in:
Leon Mika 2022-06-03 10:29:06 +10:00
parent 82face0010
commit 975955236f
3 changed files with 52 additions and 16 deletions

View file

@ -15,10 +15,14 @@ go get github.com/lmika/ted
## Usage
```
ted <csvfile>
ted [FLAGS] FILE
```
Can either be a new CSV file, or an existing CSV file.
Flags:
- `-c <codec>` the format that the file is in. Either `csv` or `tsv` files are supported. Default is `csv`
File can either be a new file, or an existing file.
TED is similar to Vim in that it is modal. After opening a file, the editor starts off in view mode, which permits navigating around.

22
main.go
View file

@ -1,13 +1,14 @@
package main
import (
"github.com/lmika/ted/ui"
"flag"
"fmt"
"github.com/lmika/ted/ui"
"os"
)
func main() {
var flagCodec = flag.String("c", "csv", "file codec to use")
flag.Parse()
if flag.NArg() == 0 {
fmt.Fprintln(os.Stderr, "usage: ted FILENAME")
@ -20,8 +21,14 @@ func main() {
}
defer uiManager.Close()
codecBuilder, hasCodec := codecModelSourceBuilders[*flagCodec]
if !hasCodec {
fmt.Fprintf(os.Stderr, "unrecognised codec: %v", *flagCodec)
os.Exit(1)
}
frame := NewFrame(uiManager)
session := NewSession(uiManager, frame, CsvFileModelSource{flag.Arg(0)})
session := NewSession(uiManager, frame, codecBuilder(flag.Arg(0)))
session.LoadFromSource()
uiManager.SetRootComponent(frame.RootComponent())
@ -29,3 +36,14 @@ func main() {
uiManager.Loop()
}
type codecModelSourceBuilder func(filename string) ModelSource
var codecModelSourceBuilders = map[string]codecModelSourceBuilder{
"csv": func(filename string) ModelSource {
return NewCsvFileModelSource(filename, CsvFileModelSourceOptions{Comma: ','})
},
"tsv": func(filename string) ModelSource {
return NewCsvFileModelSource(filename, CsvFileModelSourceOptions{Comma: '\t'})
},
}

View file

@ -1,10 +1,10 @@
package main
import (
"path/filepath"
"os"
"encoding/csv"
"io"
"os"
"path/filepath"
)
// ModelSource is a source of models. At a minimum, it must be able to read models.
@ -26,22 +26,34 @@ type WritableModelSource interface {
// A model source backed by a CSV file
type CsvFileModelSource struct {
Filename string
filename string
options CsvFileModelSourceOptions
}
type CsvFileModelSourceOptions struct {
Comma rune
}
func NewCsvFileModelSource(filename string, options CsvFileModelSourceOptions) CsvFileModelSource {
return CsvFileModelSource{
filename: filename,
options: options,
}
}
// Describes the source
func (s CsvFileModelSource) String() string {
return filepath.Base(s.Filename)
return filepath.Base(s.filename)
}
// Read the model from the given source
func (s CsvFileModelSource) Read() (Model, error) {
// Check if the file exists. If not, return an empty model
if _, err := os.Stat(s.Filename); os.IsNotExist(err) {
if _, err := os.Stat(s.filename); os.IsNotExist(err) {
return NewSingleCellStdModel(), nil
}
f, err := os.Open(s.Filename)
f, err := os.Open(s.filename)
if err != nil {
return nil, err
}
@ -49,12 +61,13 @@ func (s CsvFileModelSource) Read() (Model, error) {
model := new(StdModel)
r := csv.NewReader(f)
r.Comma = s.options.Comma
r.FieldsPerRecord = -1
for {
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
} else if err != nil {
return nil, err
}
@ -66,12 +79,13 @@ func (s CsvFileModelSource) Read() (Model, error) {
}
func (s CsvFileModelSource) Write(m Model) error {
f, err := os.Create(s.Filename)
f, err := os.Create(s.filename)
if err != nil {
return err
}
w := csv.NewWriter(f)
w.Comma = s.options.Comma
rows, cols := m.Dimensions()