Added temporary command x-replace

This runs a search and replace over the entire model.  This is just
temporary at the moment in order to get something working.

Also added hitting backspace on an empty entrybox to cancel it.
This commit is contained in:
Leon Mika 2020-09-29 23:08:57 +00:00
parent 04aeff6b52
commit 6e6e586f1d
5 changed files with 71 additions and 20 deletions

View file

@ -5,6 +5,8 @@ import (
"fmt"
"regexp"
"github.com/lmika/shellwords"
"github.com/lmika/ted/ui"
)
@ -60,20 +62,19 @@ func (cm *CommandMapping) KeyMapping(key rune) *Command {
// Evaluate a command
func (cm *CommandMapping) Eval(ctx *CommandContext, expr string) error {
// TODO: Use propper expression language here
cmd := cm.Commands[expr]
toks := shellwords.Split(expr)
if len(toks) == 0 {
return nil
}
cmd := cm.Commands[toks[0]]
if cmd != nil {
return cmd.Do(ctx)
return cmd.Do(ctx.WithArgs(toks[1:]))
}
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)
// }
//}
// Registers the standard view navigation commands. These commands require the frame
func (cm *CommandMapping) RegisterViewCommands() {
cm.Define("move-down", "Moves the cursor down one row", "", gridNavOperation(func(grid *ui.Grid) { grid.MoveBy(0, 1) }))
@ -153,6 +154,34 @@ func (cm *CommandMapping) RegisterViewCommands() {
}
}
})
cm.Define("x-replace", "Performs a search and replace", "", func(ctx *CommandContext) error {
if len(ctx.Args()) != 2 {
return errors.New("Usage: x-replace MATCH REPLACEMENT")
}
match := ctx.Args()[0]
repl := ctx.Args()[1]
re, err := regexp.Compile(match)
if err != nil {
return fmt.Errorf("invalid regexp: %v", err)
}
matchCount := 0
height, width := ctx.ModelVC().Model().Dimensions()
for r := 0; r < height; r++ {
for c := 0; c < width; c++ {
cell := ctx.ModelVC().Model().CellValue(r, c)
if re.FindStringIndex(cell) != nil {
ctx.ModelVC().SetCellValue(r, c, re.ReplaceAllString(cell, repl))
matchCount++
}
}
}
ctx.Frame().ShowMessage(fmt.Sprintf("Replaced %d matches", matchCount))
return nil
})
cm.Define("open-right", "Inserts a column to the right of the curser", "", func(ctx *CommandContext) error {
grid := ctx.Frame().Grid()

1
go.mod
View file

@ -3,6 +3,7 @@ module github.com/lmika/ted
go 1.15
require (
github.com/lmika/shellwords v0.0.0-20140714114018-ce258dd729fe
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/nsf/termbox-go v0.0.0-20200418040025-38ba6e5628f1
)

2
go.sum
View file

@ -1,3 +1,5 @@
github.com/lmika/shellwords v0.0.0-20140714114018-ce258dd729fe h1:1UXS/6OFkbi6JrihPykmYO1VtsABB02QQ+YmYYzTY18=
github.com/lmika/shellwords v0.0.0-20140714114018-ce258dd729fe/go.mod h1:qpdOkLougV5Yry4Px9f1w1pNMavcr6Z67VW5Ro+vW5I=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/nsf/termbox-go v0.0.0-20200418040025-38ba6e5628f1 h1:lh3PyZvY+B9nFliSGTn5uFuqQQJGuNrD0MLCokv09ag=

View file

@ -1,8 +1,9 @@
package main
import (
"github.com/lmika/ted/ui"
"regexp"
"github.com/lmika/ted/ui"
)
// The session is responsible for managing the UI and the model and handling
@ -61,7 +62,7 @@ func (session *Session) KeyPressed(key rune, mod int) {
cmd := session.Commands.KeyMapping(key)
if cmd != nil {
err := cmd.Do(&CommandContext{session})
err := cmd.Do(&CommandContext{session, nil})
if err != nil {
session.Frame.ShowMessage(err.Error())
}
@ -71,6 +72,18 @@ func (session *Session) KeyPressed(key rune, mod int) {
// The command context used by the session
type CommandContext struct {
session *Session
args []string
}
func (scc *CommandContext) WithArgs(args []string) *CommandContext {
return &CommandContext{
session: scc.session,
args: args,
}
}
func (scc *CommandContext) Args() []string {
return scc.args
}
func (scc *CommandContext) ModelVC() *ModelViewCtrl {

View file

@ -124,6 +124,8 @@ func (te *TextEntry) KeyPressed(key rune, mod int) {
if mod&ModKeyAlt != 0 {
te.backspaceWhile(unicode.IsSpace)
te.backspaceWhile(func(r rune) bool { return !unicode.IsSpace(r) })
} else if te.cursorOffset == 0 {
te.cancelAndExit()
} else {
te.backspace()
}
@ -136,14 +138,18 @@ func (te *TextEntry) KeyPressed(key rune, mod int) {
te.OnEntry(te.value)
}
} else if key == KeyCtrlC {
if te.OnCancel != nil {
te.OnCancel()
}
te.cancelAndExit()
}
//panic(fmt.Sprintf("Entered key: '%x', mod: '%x'", key, mod))
}
func (te *TextEntry) cancelAndExit() {
if te.OnCancel != nil {
te.OnCancel()
}
}
// Backspace
func (te *TextEntry) backspace() {
te.removeCharAtPos(te.cursorOffset - 1)