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
|
## 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.
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/lmika/ted/ui"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/lmika/ted/ui"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
var flagCodec = flag.String("c", "csv", "file codec to use")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if flag.NArg() == 0 {
|
if flag.NArg() == 0 {
|
||||||
fmt.Fprintln(os.Stderr, "usage: ted FILENAME")
|
fmt.Fprintln(os.Stderr, "usage: ted FILENAME")
|
||||||
|
|
@ -20,8 +21,14 @@ func main() {
|
||||||
}
|
}
|
||||||
defer uiManager.Close()
|
defer uiManager.Close()
|
||||||
|
|
||||||
|
codecBuilder, hasCodec := codecModelSourceBuilders[*flagCodec]
|
||||||
|
if !hasCodec {
|
||||||
|
fmt.Fprintf(os.Stderr, "unrecognised codec: %v", *flagCodec)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
frame := NewFrame(uiManager)
|
frame := NewFrame(uiManager)
|
||||||
session := NewSession(uiManager, frame, CsvFileModelSource{flag.Arg(0)})
|
session := NewSession(uiManager, frame, codecBuilder(flag.Arg(0)))
|
||||||
session.LoadFromSource()
|
session.LoadFromSource()
|
||||||
|
|
||||||
uiManager.SetRootComponent(frame.RootComponent())
|
uiManager.SetRootComponent(frame.RootComponent())
|
||||||
|
|
@ -29,3 +36,14 @@ func main() {
|
||||||
|
|
||||||
uiManager.Loop()
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
|
||||||
"os"
|
|
||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ModelSource is a source of models. At a minimum, it must be able to read models.
|
// 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
|
// A model source backed by a CSV file
|
||||||
type CsvFileModelSource struct {
|
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
|
// Describes the source
|
||||||
func (s CsvFileModelSource) String() string {
|
func (s CsvFileModelSource) String() string {
|
||||||
return filepath.Base(s.Filename)
|
return filepath.Base(s.filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the model from the given source
|
// Read the model from the given source
|
||||||
func (s CsvFileModelSource) Read() (Model, error) {
|
func (s CsvFileModelSource) Read() (Model, error) {
|
||||||
// Check if the file exists. If not, return an empty model
|
// 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
|
return NewSingleCellStdModel(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := os.Open(s.Filename)
|
f, err := os.Open(s.filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -49,12 +61,13 @@ func (s CsvFileModelSource) Read() (Model, error) {
|
||||||
|
|
||||||
model := new(StdModel)
|
model := new(StdModel)
|
||||||
r := csv.NewReader(f)
|
r := csv.NewReader(f)
|
||||||
|
r.Comma = s.options.Comma
|
||||||
|
r.FieldsPerRecord = -1
|
||||||
for {
|
for {
|
||||||
record, err := r.Read()
|
record, err := r.Read()
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
}
|
} else if err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,19 +79,20 @@ func (s CsvFileModelSource) Read() (Model, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s CsvFileModelSource) Write(m Model) error {
|
func (s CsvFileModelSource) Write(m Model) error {
|
||||||
f, err := os.Create(s.Filename)
|
f, err := os.Create(s.filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
w := csv.NewWriter(f)
|
w := csv.NewWriter(f)
|
||||||
|
w.Comma = s.options.Comma
|
||||||
|
|
||||||
rows, cols := m.Dimensions()
|
rows, cols := m.Dimensions()
|
||||||
|
|
||||||
for r := 0; r < rows; r++ {
|
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++ {
|
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 {
|
if err := w.Write(record); err != nil {
|
||||||
f.Close()
|
f.Close()
|
||||||
|
|
@ -93,4 +107,4 @@ func (s CsvFileModelSource) Write(m Model) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return f.Close()
|
return f.Close()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue