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:
parent
82face0010
commit
975955236f
|
|
@ -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
22
main.go
|
|
@ -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'})
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,19 +79,20 @@ 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()
|
||||
|
||||
for r := 0; r < rows; r++ {
|
||||
record := make([]string, cols) // Reuse the record slice
|
||||
record := make([]string, cols) // Reuse the record slice
|
||||
for c := 0; c < cols; c++ {
|
||||
record[c] = m.CellValue(r, c)
|
||||
record[c] = m.CellValue(r, c)
|
||||
}
|
||||
if err := w.Write(record); err != nil {
|
||||
f.Close()
|
||||
|
|
@ -93,4 +107,4 @@ func (s CsvFileModelSource) Write(m Model) error {
|
|||
}
|
||||
|
||||
return f.Close()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue