Added search and replaced split out edit and replace cell commands
This commit is contained in:
parent
b658536ad1
commit
598d9bd962
101
commandmap.go
101
commandmap.go
|
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/lmika/ted/ui"
|
||||
)
|
||||
|
|
@ -67,11 +68,11 @@ func (cm *CommandMapping) Eval(ctx *CommandContext, expr string) error {
|
|||
return fmt.Errorf("no such command: %v", expr)
|
||||
}
|
||||
|
||||
func (cm *CommandMapping) DoEval(ctx *CommandContext, expr string) {
|
||||
if err := cm.Eval(ctx, expr); err != nil {
|
||||
ctx.ShowError(err)
|
||||
}
|
||||
}
|
||||
//func (cm *CommandMapping) DoEval(ctx *CommandContext, expr string) {
|
||||
// if err := cm.Eval(ctx, expr); err != nil {
|
||||
// ctx.ShowError(err)
|
||||
// }
|
||||
//}
|
||||
|
||||
// Registers the standard view navigation commands. These commands require the frame
|
||||
func (cm *CommandMapping) RegisterViewCommands() {
|
||||
|
|
@ -105,6 +106,64 @@ func (cm *CommandMapping) RegisterViewCommands() {
|
|||
grid.MoveTo(dimX-1, cellY)
|
||||
}))
|
||||
|
||||
cm.Define("delete-row", "Removes the currently selected row", "", func(ctx *CommandContext) error {
|
||||
grid := ctx.Frame().Grid()
|
||||
_, cellY := grid.CellPosition()
|
||||
|
||||
if rwModel, isRwModel := ctx.Session().Model.(RWModel); isRwModel {
|
||||
DeleteRow(rwModel, cellY)
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("model is read-only")
|
||||
})
|
||||
cm.Define("delete-col", "Removes the currently selected column", "", func(ctx *CommandContext) error {
|
||||
grid := ctx.Frame().Grid()
|
||||
cellX, _ := grid.CellPosition()
|
||||
|
||||
if rwModel, isRwModel := ctx.Session().Model.(RWModel); isRwModel {
|
||||
DeleteCol(rwModel, cellX)
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("model is read-only")
|
||||
})
|
||||
cm.Define("search", "Search for a cell", "", func(ctx *CommandContext) error {
|
||||
ctx.Frame().Prompt(PromptOptions{ Prompt: "/" }, func(res string) error {
|
||||
re, err := regexp.Compile(res)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid regexp: %v", err)
|
||||
}
|
||||
|
||||
ctx.session.LastSearch = re
|
||||
return ctx.Session().Commands.Eval(ctx, "search-next")
|
||||
})
|
||||
return nil
|
||||
})
|
||||
cm.Define("search-next", "Goto the next cell", "", func(ctx *CommandContext) error {
|
||||
if ctx.session.LastSearch == nil {
|
||||
ctx.Session().Commands.Eval(ctx, "search")
|
||||
}
|
||||
|
||||
height, width := ctx.session.Model.Dimensions()
|
||||
startX, startY := ctx.Frame().Grid().CellPosition()
|
||||
cellX, cellY := startX, startY
|
||||
|
||||
for {
|
||||
cellX++
|
||||
if cellX >= width {
|
||||
cellX = 0
|
||||
cellY = (cellY + 1) % height
|
||||
}
|
||||
if ctx.session.LastSearch.MatchString(ctx.session.Model.CellValue(cellY, cellX)) {
|
||||
ctx.Frame().Grid().MoveTo(cellX, cellY)
|
||||
return nil
|
||||
} else if (cellX == startX) && (cellY == startY) {
|
||||
return errors.New("No match found")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
cm.Define("open-right", "Inserts a column to the right of the curser", "", func(ctx *CommandContext) error {
|
||||
grid := ctx.Frame().Grid()
|
||||
cellX, _ := grid.CellPosition()
|
||||
|
|
@ -149,18 +208,34 @@ func (cm *CommandMapping) RegisterViewCommands() {
|
|||
})
|
||||
|
||||
cm.Define("enter-command", "Enter command", "", func(ctx *CommandContext) error {
|
||||
ctx.Frame().Prompt(":", func(res string) {
|
||||
cm.DoEval(ctx, res)
|
||||
ctx.Frame().Prompt(PromptOptions{ Prompt: ":" }, func(res string) error {
|
||||
return cm.Eval(ctx, res)
|
||||
})
|
||||
return nil
|
||||
})
|
||||
|
||||
cm.Define("set-cell", "Change the value of the selected cell", "", func(ctx *CommandContext) error {
|
||||
cm.Define("replace-cell", "Replace the value of the selected cell", "", func(ctx *CommandContext) error {
|
||||
grid := ctx.Frame().Grid()
|
||||
cellX, cellY := grid.CellPosition()
|
||||
if rwModel, isRwModel := ctx.Session().Model.(RWModel); isRwModel {
|
||||
ctx.Frame().Prompt("> ", func(res string) {
|
||||
ctx.Frame().Prompt(PromptOptions{ Prompt: "> " }, func(res string) error {
|
||||
rwModel.SetCellValue(cellY, cellX, res)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
cm.Define("edit-cell", "Modify the value of the selected cell", "", func(ctx *CommandContext) error {
|
||||
grid := ctx.Frame().Grid()
|
||||
cellX, cellY := grid.CellPosition()
|
||||
|
||||
if rwModel, isRwModel := ctx.Session().Model.(RWModel); isRwModel {
|
||||
ctx.Frame().Prompt(PromptOptions{
|
||||
Prompt: "> ",
|
||||
InitialValue: grid.Model().CellValue(cellY, cellX),
|
||||
}, func(res string) error {
|
||||
rwModel.SetCellValue(cellY, cellX, res)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
return nil
|
||||
|
|
@ -219,10 +294,16 @@ func (cm *CommandMapping) RegisterViewKeyBindings() {
|
|||
cm.MapKey(ui.KeyArrowLeft, cm.Command("move-left"))
|
||||
cm.MapKey(ui.KeyArrowRight, cm.Command("move-right"))
|
||||
|
||||
cm.MapKey('e', cm.Command("set-cell"))
|
||||
cm.MapKey('e', cm.Command("edit-cell"))
|
||||
cm.MapKey('r', cm.Command("replace-cell"))
|
||||
|
||||
cm.MapKey('a', cm.Command("append"))
|
||||
|
||||
cm.MapKey('D', cm.Command("delete-row"))
|
||||
|
||||
cm.MapKey('/', cm.Command("search"))
|
||||
cm.MapKey('n', cm.Command("search-next"))
|
||||
|
||||
cm.MapKey(':', cm.Command("enter-command"))
|
||||
}
|
||||
|
||||
|
|
|
|||
21
frame.go
21
frame.go
|
|
@ -99,15 +99,28 @@ func (frame *Frame) Message(s string) {
|
|||
frame.messageView.Text = s
|
||||
}
|
||||
|
||||
func (frame *Frame) Error(err error) {
|
||||
if err != nil {
|
||||
frame.messageView.Text = err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
type PromptOptions struct {
|
||||
Prompt string
|
||||
InitialValue string
|
||||
}
|
||||
|
||||
// Prompt the user for input. This switches the mode to entry mode.
|
||||
func (frame *Frame) Prompt(prompt string, callback func(res string)) {
|
||||
frame.textEntry.Prompt = prompt
|
||||
frame.textEntry.SetValue("")
|
||||
func (frame *Frame) Prompt(options PromptOptions, callback func(res string) error) {
|
||||
frame.textEntry.Prompt = options.Prompt
|
||||
frame.textEntry.SetValue(options.InitialValue)
|
||||
|
||||
frame.textEntry.OnCancel = frame.exitEntryMode
|
||||
frame.textEntry.OnEntry = func(res string) {
|
||||
frame.exitEntryMode()
|
||||
callback(res)
|
||||
if err := callback(res); err != nil {
|
||||
frame.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
frame.setMode(EntryMode)
|
||||
|
|
|
|||
23
model.go
23
model.go
|
|
@ -26,3 +26,26 @@ type RWModel interface {
|
|||
// Returns true if the model has been modified in some way
|
||||
IsDirty() bool
|
||||
}
|
||||
|
||||
// Deletes a row of a model
|
||||
func DeleteRow(model RWModel, row int) {
|
||||
h, w := model.Dimensions()
|
||||
for r := row; r < h-1; r++ {
|
||||
for c := 0; c < w; c++ {
|
||||
model.SetCellValue(r, c, model.CellValue(r+1, c))
|
||||
}
|
||||
}
|
||||
|
||||
model.Resize(h-1, w)
|
||||
}
|
||||
|
||||
// Deletes a column of a model
|
||||
func DeleteCol(model RWModel, col int) {
|
||||
h, w := model.Dimensions()
|
||||
for c := col; c < w-1; c++ {
|
||||
for r := 0; r < h; r++ {
|
||||
model.SetCellValue(r, c, model.CellValue(r, c+1))
|
||||
}
|
||||
}
|
||||
model.Resize(h, w-1)
|
||||
}
|
||||
|
|
|
|||
13
session.go
13
session.go
|
|
@ -1,6 +1,9 @@
|
|||
package main
|
||||
|
||||
import "github.com/lmika/ted/ui"
|
||||
import (
|
||||
"github.com/lmika/ted/ui"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// The session is responsible for managing the UI and the model and handling
|
||||
// the interaction between the two and the user.
|
||||
|
|
@ -10,6 +13,8 @@ type Session struct {
|
|||
Frame *Frame
|
||||
Commands *CommandMapping
|
||||
UIManager *ui.Ui
|
||||
|
||||
LastSearch *regexp.Regexp
|
||||
}
|
||||
|
||||
func NewSession(uiManager *ui.Ui, frame *Frame, source ModelSource) *Session {
|
||||
|
|
@ -73,10 +78,8 @@ func (scc *CommandContext) Frame() *Frame {
|
|||
}
|
||||
|
||||
// Error displays an error if err is not nil
|
||||
func (scc *CommandContext) ShowError(err error) {
|
||||
if err != nil {
|
||||
scc.Frame().Message(err.Error())
|
||||
}
|
||||
func (scc *CommandContext) Error(err error) {
|
||||
scc.Frame().Error(err)
|
||||
}
|
||||
|
||||
// Session grid model
|
||||
|
|
|
|||
Loading…
Reference in a new issue