Allowed open-right to work on all columns
Previously it only worked on the right-most column. Also bounded this command to "O" (this might change).
This commit is contained in:
parent
975955236f
commit
5424a6b927
|
|
@ -187,11 +187,7 @@ func (cm *CommandMapping) RegisterViewCommands() {
|
||||||
grid := ctx.Frame().Grid()
|
grid := ctx.Frame().Grid()
|
||||||
cellX, _ := grid.CellPosition()
|
cellX, _ := grid.CellPosition()
|
||||||
|
|
||||||
height, width := ctx.ModelVC().Model().Dimensions()
|
return ctx.ModelVC().OpenRight(cellX)
|
||||||
if cellX == width-1 {
|
|
||||||
return ctx.ModelVC().Resize(height, width+1)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
|
|
||||||
cm.Define("open-down", "Inserts a row below the curser", "", func(ctx *CommandContext) error {
|
cm.Define("open-down", "Inserts a row below the curser", "", func(ctx *CommandContext) error {
|
||||||
|
|
@ -277,7 +273,7 @@ func (cm *CommandMapping) RegisterViewCommands() {
|
||||||
|
|
||||||
cm.Define("enter-command", "Enter command", "", func(ctx *CommandContext) error {
|
cm.Define("enter-command", "Enter command", "", func(ctx *CommandContext) error {
|
||||||
ctx.Frame().Prompt(PromptOptions{
|
ctx.Frame().Prompt(PromptOptions{
|
||||||
Prompt: ":",
|
Prompt: ":",
|
||||||
CancelOnEmptyBackspace: true,
|
CancelOnEmptyBackspace: true,
|
||||||
}, func(res string) error {
|
}, func(res string) error {
|
||||||
return cm.Eval(ctx, res)
|
return cm.Eval(ctx, res)
|
||||||
|
|
@ -407,6 +403,7 @@ func (cm *CommandMapping) RegisterViewKeyBindings() {
|
||||||
|
|
||||||
cm.MapKey('a', cm.Command("append"))
|
cm.MapKey('a', cm.Command("append"))
|
||||||
|
|
||||||
|
cm.MapKey('O', cm.Command("open-right"))
|
||||||
cm.MapKey('D', cm.Command("delete-row"))
|
cm.MapKey('D', cm.Command("delete-row"))
|
||||||
|
|
||||||
cm.MapKey('/', cm.Command("search"))
|
cm.MapKey('/', cm.Command("search"))
|
||||||
|
|
|
||||||
1
go.mod
1
go.mod
|
|
@ -7,4 +7,5 @@ require (
|
||||||
github.com/lmika/shellwords v0.0.0-20140714114018-ce258dd729fe
|
github.com/lmika/shellwords v0.0.0-20140714114018-ce258dd729fe
|
||||||
github.com/mattn/go-runewidth v0.0.10 // indirect
|
github.com/mattn/go-runewidth v0.0.10 // indirect
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
|
github.com/stretchr/testify v1.7.5 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
15
go.sum
15
go.sum
|
|
@ -1,3 +1,6 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
||||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||||
github.com/gdamore/tcell v1.4.0 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU=
|
github.com/gdamore/tcell v1.4.0 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU=
|
||||||
|
|
@ -9,11 +12,23 @@ github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i
|
||||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
|
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
|
||||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
|
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
|
||||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q=
|
||||||
|
github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756 h1:9nuHUbU8dRnRRfj9KjWUVrJeoexdbeMjttk6Oh1rD10=
|
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756 h1:9nuHUbU8dRnRRfj9KjWUVrJeoexdbeMjttk6Oh1rD10=
|
||||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
||||||
12
stdmodel.go
12
stdmodel.go
|
|
@ -14,12 +14,20 @@ type StdModel struct {
|
||||||
//
|
//
|
||||||
func NewSingleCellStdModel() *StdModel {
|
func NewSingleCellStdModel() *StdModel {
|
||||||
sm := new(StdModel)
|
sm := new(StdModel)
|
||||||
sm.appendStr([]string { "" })
|
sm.appendStr([]string{""})
|
||||||
sm.dirty = false
|
sm.dirty = false
|
||||||
|
|
||||||
return sm
|
return sm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewStdModelFromSlice(str [][]string) *StdModel {
|
||||||
|
sm := new(StdModel)
|
||||||
|
for _, r := range str {
|
||||||
|
sm.appendStr(r)
|
||||||
|
}
|
||||||
|
return sm
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The dimensions of the model (height, width).
|
* The dimensions of the model (height, width).
|
||||||
*/
|
*/
|
||||||
|
|
@ -73,7 +81,7 @@ func (sm *StdModel) SetCellValue(r, c int, value string) {
|
||||||
func (sm *StdModel) appendStr(row []string) {
|
func (sm *StdModel) appendStr(row []string) {
|
||||||
if len(sm.Cells) == 0 {
|
if len(sm.Cells) == 0 {
|
||||||
cells := sm.strSliceToCell(row, len(row))
|
cells := sm.strSliceToCell(row, len(row))
|
||||||
sm.Cells = [][]Cell{ cells }
|
sm.Cells = [][]Cell{cells}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
37
viewmodel.go
37
viewmodel.go
|
|
@ -44,7 +44,9 @@ func (gvm *ModelViewCtrl) SetRowAttrs(row int, newAttrs SliceAttr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gvm *ModelViewCtrl) SetColAttrs(col int, newAttrs SliceAttr) {
|
func (gvm *ModelViewCtrl) SetColAttrs(col int, newAttrs SliceAttr) {
|
||||||
gvm.colAttrs[col] = newAttrs
|
if col >= 0 && col < len(gvm.colAttrs) {
|
||||||
|
gvm.colAttrs[col] = newAttrs
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gvm *ModelViewCtrl) SetCellValue(r, c int, newValue string) error {
|
func (gvm *ModelViewCtrl) SetCellValue(r, c int, newValue string) error {
|
||||||
|
|
@ -69,6 +71,39 @@ func (gvm *ModelViewCtrl) Resize(newRow, newCol int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gvm *ModelViewCtrl) OpenRight(col int) error {
|
||||||
|
if col < 0 {
|
||||||
|
return errors.New("col out of bound")
|
||||||
|
}
|
||||||
|
return gvm.insertColumn(col + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gvm *ModelViewCtrl) insertColumn(col int) error {
|
||||||
|
rwModel, isRWModel := gvm.model.(RWModel)
|
||||||
|
if !isRWModel {
|
||||||
|
return ErrModelReadOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
dr, dc := rwModel.Dimensions()
|
||||||
|
if col < 0 || col > dc {
|
||||||
|
return errors.New("col out of bound")
|
||||||
|
}
|
||||||
|
|
||||||
|
rwModel.Resize(dr, dc+1)
|
||||||
|
|
||||||
|
for c := dc; c >= col; c-- {
|
||||||
|
for r := 0; r < dr; r++ {
|
||||||
|
if c == col {
|
||||||
|
rwModel.SetCellValue(r, c, "")
|
||||||
|
} else {
|
||||||
|
rwModel.SetCellValue(r, c, rwModel.CellValue(r, c-1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Deletes a row of a model
|
// Deletes a row of a model
|
||||||
func (gvm *ModelViewCtrl) DeleteRow(row int) error {
|
func (gvm *ModelViewCtrl) DeleteRow(row int) error {
|
||||||
rwModel, isRWModel := gvm.model.(RWModel)
|
rwModel, isRWModel := gvm.model.(RWModel)
|
||||||
|
|
|
||||||
98
viewmodel_test.go
Normal file
98
viewmodel_test.go
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestModelViewCtrl_OpenRight(t *testing.T) {
|
||||||
|
t.Run("should move cols to the right within the model", func(t *testing.T) {
|
||||||
|
rwModel := NewStdModelFromSlice([][]string{
|
||||||
|
{"letters", "numbers", "greek"},
|
||||||
|
{"a", "1", "alpha"},
|
||||||
|
{"b", "2", "bravo"},
|
||||||
|
{"c", "3", "charlie"},
|
||||||
|
})
|
||||||
|
|
||||||
|
mvc := NewGridViewModel(rwModel)
|
||||||
|
err := mvc.OpenRight(1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assertModel(t, rwModel, [][]string{
|
||||||
|
{"letters", "numbers", "", "greek"},
|
||||||
|
{"a", "1", "", "alpha"},
|
||||||
|
{"b", "2", "", "bravo"},
|
||||||
|
{"c", "3", "", "charlie"},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should move cols to the right at the left of the model", func(t *testing.T) {
|
||||||
|
rwModel := NewStdModelFromSlice([][]string{
|
||||||
|
{"letters", "numbers", "greek"},
|
||||||
|
{"a", "1", "alpha"},
|
||||||
|
{"b", "2", "bravo"},
|
||||||
|
{"c", "3", "charlie"},
|
||||||
|
})
|
||||||
|
|
||||||
|
mvc := NewGridViewModel(rwModel)
|
||||||
|
err := mvc.OpenRight(0)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assertModel(t, rwModel, [][]string{
|
||||||
|
{"letters", "", "numbers", "greek"},
|
||||||
|
{"a", "", "1", "alpha"},
|
||||||
|
{"b", "", "2", "bravo"},
|
||||||
|
{"c", "", "3", "charlie"},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should move cols to the right at the right of the model", func(t *testing.T) {
|
||||||
|
rwModel := NewStdModelFromSlice([][]string{
|
||||||
|
{"letters", "numbers", "greek"},
|
||||||
|
{"a", "1", "alpha"},
|
||||||
|
{"b", "2", "bravo"},
|
||||||
|
{"c", "3", "charlie"},
|
||||||
|
})
|
||||||
|
|
||||||
|
mvc := NewGridViewModel(rwModel)
|
||||||
|
err := mvc.OpenRight(2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assertModel(t, rwModel, [][]string{
|
||||||
|
{"letters", "numbers", "greek", ""},
|
||||||
|
{"a", "1", "alpha", ""},
|
||||||
|
{"b", "2", "bravo", ""},
|
||||||
|
{"c", "3", "charlie", ""},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should return error if row out of bounds", func(t *testing.T) {
|
||||||
|
scenario := []int{-1, 3, 12}
|
||||||
|
for _, scenario := range scenario {
|
||||||
|
t.Run(fmt.Sprint(scenario), func(t *testing.T) {
|
||||||
|
rwModel := NewStdModelFromSlice([][]string{
|
||||||
|
{"letters", "numbers", "greek"},
|
||||||
|
{"a", "1", "alpha"},
|
||||||
|
{"b", "2", "bravo"},
|
||||||
|
{"c", "3", "charlie"},
|
||||||
|
})
|
||||||
|
mvc := NewGridViewModel(rwModel)
|
||||||
|
err := mvc.OpenRight(scenario)
|
||||||
|
assert.Error(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertModel(t *testing.T, actual Model, expected [][]string) {
|
||||||
|
dr, dc := actual.Dimensions()
|
||||||
|
assert.Equalf(t, len(expected), dr, "number of rows in model")
|
||||||
|
|
||||||
|
for r, row := range expected {
|
||||||
|
assert.Equalf(t, len(row), dc, "number of cols in row %v", r)
|
||||||
|
for c, cell := range row {
|
||||||
|
assert.Equalf(t, cell, actual.CellValue(r, c), "cell value at row %v, col %v", r, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue