From 9267fc92a7bb0b163fd1289bb0c3373f90c6c3d9 Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Tue, 24 Sep 2024 12:45:22 +1000 Subject: [PATCH] A few minor feature Added automatic resizing of the columns when loading a model Added colouring of the currently search for cell --- commandmap.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++- go.mod | 18 +++++++++++++---- go.sum | 3 +-- main.go | 1 + session.go | 38 ++++++++++++++++++++++++++++++++++-- viewmodel.go | 12 +++++++++--- 6 files changed, 114 insertions(+), 12 deletions(-) diff --git a/commandmap.go b/commandmap.go index 18355c7..6da306f 100644 --- a/commandmap.go +++ b/commandmap.go @@ -126,12 +126,17 @@ func (cm *CommandMapping) RegisterViewCommands() { }) cm.Define("search", "Search for a cell", "", func(ctx *CommandContext) error { ctx.Frame().Prompt(PromptOptions{Prompt: "/"}, func(res string) error { + if res == "" { + ctx.Session().SetLastSearch(nil) + return nil + } + re, err := regexp.Compile(res) if err != nil { return fmt.Errorf("invalid regexp: %v", err) } - ctx.session.LastSearch = re + ctx.Session().SetLastSearch(re) return ctx.Session().Commands.Eval(ctx, "search-next") }) return nil @@ -252,6 +257,28 @@ func (cm *CommandMapping) RegisterViewCommands() { cm.Define("mark-row-red", "Set row marker to red", "", func(ctx *CommandContext) error { _, cellY := ctx.Frame().Grid().CellPosition() + namedArgs, _ := extractNamedArgs(ctx.args) + if rowMatch, hasRowMatch := namedArgs["row-match"]; hasRowMatch { + rows, cols := ctx.ModelVC().Model().Dimensions() + + for r := 0; r < rows; r++ { + rowMatches := false + for c := 0; c < cols; c++ { + cellVal := ctx.ModelVC().Model().CellValue(r, c) + if cellVal == rowMatch { + rowMatches = true + break + } + } + if rowMatches { + attrs := ctx.ModelVC().RowAttrs(r) + attrs.Marker = MarkerRed + ctx.ModelVC().SetRowAttrs(r, attrs) + } + } + return nil + } + attrs := ctx.ModelVC().RowAttrs(cellY) attrs.Marker = MarkerRed ctx.ModelVC().SetRowAttrs(cellY, attrs) @@ -495,3 +522,28 @@ func gridNavOperation(op func(grid *ui.Grid)) func(ctx *CommandContext) error { return nil } } + +// extractNamedArgs will extract out any arguments of the form '-name value' and stick it in a map. +// Any non-named arguments will be extracted out as positional. If an argument only has a name, it +// will be added to the map with the empty string as the value. +func extractNamedArgs(args []string) (namedArgs map[string]string, positionalArgs []string) { + for len(args) > 0 { + if args[0][0] == '-' { + if namedArgs == nil { + namedArgs = make(map[string]string) + } + + if len(args) >= 2 && args[1][0] != '-' { + namedArgs[args[0][1:]] = args[1] + args = args[2:] + } else { + namedArgs[args[0][1:]] = "" + args = args[1:] + } + } else { + positionalArgs = append(positionalArgs, args[0]) + args = args[1:] + } + } + return namedArgs, positionalArgs +} diff --git a/go.mod b/go.mod index 6bb538b..d31faa9 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,21 @@ module github.com/lmika/ted -go 1.15 +go 1.22 require ( github.com/gdamore/tcell v1.4.0 github.com/lmika/shellwords v0.0.0-20140714114018-ce258dd729fe - github.com/mattn/go-runewidth v0.0.10 // indirect - github.com/rivo/uniseg v0.2.0 // indirect - github.com/stretchr/testify v1.7.5 // indirect + github.com/stretchr/testify v1.7.5 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gdamore/encoding v1.0.0 // indirect + github.com/lucasb-eyer/go-colorful v1.0.3 // indirect + github.com/mattn/go-runewidth v0.0.10 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756 // indirect + golang.org/x/text v0.3.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index b1e8d4a..a863b4b 100644 --- a/go.sum +++ b/go.sum @@ -14,12 +14,10 @@ github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRR 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/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= 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= @@ -28,6 +26,7 @@ golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756 h1:9nuHUbU8dRnRRfj9KjWUVrJeo 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/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 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= diff --git a/main.go b/main.go index 7459418..36cead3 100644 --- a/main.go +++ b/main.go @@ -30,6 +30,7 @@ func main() { frame := NewFrame(uiManager) session := NewSession(uiManager, frame, codecBuilder(flag.Arg(0))) session.LoadFromSource() + session.ResizeToBestFit() uiManager.SetRootComponent(frame.RootComponent()) frame.enterMode(GridMode) diff --git a/session.go b/session.go index 7418549..4776971 100644 --- a/session.go +++ b/session.go @@ -6,6 +6,12 @@ import ( "github.com/lmika/ted/ui" ) +const ( + bestFixRightMargin = 2 + bestFixMinColumnSize = 8 + bestFixMaxColumnSize = 32 +) + // The session is responsible for managing the UI and the model and handling // the interaction between the two and the user. type Session struct { @@ -15,7 +21,7 @@ type Session struct { Commands *CommandMapping UIManager *ui.Ui modelController *ModelViewCtrl - pasteBoard RWModel + pasteBoard RWModel LastSearch *regexp.Regexp } @@ -29,7 +35,7 @@ func NewSession(uiManager *ui.Ui, frame *Frame, source ModelSource) *Session { Commands: NewCommandMapping(), UIManager: uiManager, modelController: NewGridViewModel(model), - pasteBoard: NewSingleCellStdModel(), + pasteBoard: NewSingleCellStdModel(), } frame.SetModel(&SessionGridModel{session.modelController}) @@ -55,6 +61,23 @@ func (session *Session) LoadFromSource() { session.modelController.SetModel(newModel) } +func (sesion *Session) ResizeToBestFit() { + mr, mc := sesion.model.Dimensions() + colMaxSize := make([]int, mc) + for c := 0; c < mc; c++ { + colMaxSize[c] = bestFixMinColumnSize + for r := 0; r < mr; r++ { + colMaxSize[c] = max(colMaxSize[c], len(sesion.model.CellValue(r, c))+bestFixRightMargin) + } + } + + for c, ml := range colMaxSize { + sesion.modelController.SetColAttrs(c, SliceAttr{ + Size: min(ml, bestFixMaxColumnSize), + }) + } +} + // Input from the frame func (session *Session) KeyPressed(key rune, mod int) { // Add the mod key modifier @@ -71,6 +94,11 @@ func (session *Session) KeyPressed(key rune, mod int) { } } +func (s *Session) SetLastSearch(re *regexp.Regexp) { + s.LastSearch = re + s.modelController.lastSearchRegexp = re +} + // The command context used by the session type CommandContext struct { session *Session @@ -132,6 +160,12 @@ func (sgm *SessionGridModel) CellValue(x int, y int) string { } func (sgm *SessionGridModel) CellAttributes(x int, y int) (fg, bg ui.Attribute) { + if sgm.GridViewModel.lastSearchRegexp != nil { + if sgm.GridViewModel.lastSearchRegexp.MatchString(sgm.GridViewModel.Model().CellValue(y, x)) { + return ui.ColorMagenta, 0 + } + } + rowAttrs := sgm.GridViewModel.RowAttrs(y) colAttrs := sgm.GridViewModel.ColAttrs(y) diff --git a/viewmodel.go b/viewmodel.go index 720552f..ba06ff5 100644 --- a/viewmodel.go +++ b/viewmodel.go @@ -2,12 +2,14 @@ package main import ( "errors" + "regexp" ) type ModelViewCtrl struct { - model Model - rowAttrs []SliceAttr - colAttrs []SliceAttr + model Model + rowAttrs []SliceAttr + colAttrs []SliceAttr + lastSearchRegexp *regexp.Regexp } func NewGridViewModel(model Model) *ModelViewCtrl { @@ -16,6 +18,10 @@ func NewGridViewModel(model Model) *ModelViewCtrl { return gvm } +func (gvm *ModelViewCtrl) SetLastSearchRegexp(r *regexp.Regexp) { + gvm.lastSearchRegexp = r +} + func (gvm *ModelViewCtrl) Model() Model { return gvm.model }