Gim/internal/command/registry.go
Hayden Hargreaves 98e02553b1 feat: working on the undo stack! Huge progress, not tested
Tests are coming, but there are some infrastructure issues with the
tests
2026-03-30 22:38:33 -07:00

248 lines
4.9 KiB
Go

package command
import (
"fmt"
"strings"
"git.gophernest.net/azpect/TextEditor/internal/action"
tea "github.com/charmbracelet/bubbletea"
)
// Command: Represents a command that can be executed from command mode.
type Command struct {
Name string // Full name: "quit"
ShortForm string // Minimum abbreviation: "q"
Handler func(m action.Model, args []string, force bool) tea.Cmd // Handler function
}
// Registry: Holds all registered commands.
type Registry struct {
commands []Command
}
// NewRegistry: Creates a new command registry with default commands.
func NewRegistry() *Registry {
r := &Registry{}
r.registerDefaults()
return r
}
// Registry.Register: Adds a command to the registry.
func (r *Registry) Register(cmd Command) {
r.commands = append(r.commands, cmd)
}
// Registry.Lookup: Finds a command by name or abbreviation with error handling.
func (r *Registry) Lookup(input string) (*Command, error) {
if input == "" {
return nil, fmt.Errorf("no command given")
}
var matches []*Command
for i := range r.commands {
cmd := &r.commands[i]
// Exact match on short form
if input == cmd.ShortForm {
return cmd, nil
}
// Exact match on full name
if input == cmd.Name {
return cmd, nil
}
// Prefix match: input must be at least as long as short form
// and must be a prefix of the full name
if len(input) >= len(cmd.ShortForm) && strings.HasPrefix(cmd.Name, input) {
matches = append(matches, cmd)
}
}
if len(matches) == 0 {
return nil, fmt.Errorf("unknown command: %s", input)
}
if len(matches) > 1 {
names := make([]string, len(matches))
for i, m := range matches {
names[i] = m.Name
}
return nil, fmt.Errorf("ambiguous command: %s (could be: %s)", input, strings.Join(names, ", "))
}
return matches[0], nil
}
// Parse: Splits a command line into command name and arguments.
func Parse(cmdLine string) (name string, args []string, force bool) {
parts := strings.Fields(cmdLine)
if len(parts) == 0 {
return "", nil, false
}
name = parts[0]
args = parts[1:]
// Check if command ends with ! (force flag)
if strings.HasSuffix(name, "!") {
name = strings.TrimSuffix(name, "!")
force = true
}
return name, args, force
}
// Registry.Execute: Parses and executes a command line.
func (r *Registry) Execute(m action.Model, cmdLine string) (tea.Cmd, error) {
name, args, force := Parse(cmdLine)
cmd, err := r.Lookup(name)
if err != nil {
return nil, err
}
return cmd.Handler(m, args, force), nil
}
// DefaultRegistry is the global command registry
var DefaultRegistry = NewRegistry()
// Registry.registerDefaults: Registers the built-in commands.
func (r *Registry) registerDefaults() {
// Quit commands
r.Register(Command{
Name: "quit",
ShortForm: "q",
Handler: cmdQuit,
})
r.Register(Command{
Name: "qall",
ShortForm: "qa",
Handler: cmdQuitAll,
})
// Write commands
r.Register(Command{
Name: "write",
ShortForm: "w",
Handler: cmdWrite,
})
r.Register(Command{
Name: "wall",
ShortForm: "wa",
Handler: cmdWriteAll,
})
r.Register(Command{
Name: "wq",
ShortForm: "wq",
Handler: cmdWriteQuit,
})
r.Register(Command{
Name: "wqall",
ShortForm: "wqa",
Handler: cmdWriteQuitAll,
})
// Set command
r.Register(Command{
Name: "set",
ShortForm: "se",
Handler: cmdSet,
})
// Register commands
r.Register(Command{
Name: "register",
ShortForm: "reg",
Handler: cmdRegisters,
})
// History commands
r.Register(Command{
Name: "history",
ShortForm: "his",
Handler: cmdHistory,
})
// Buffer commands
r.Register(Command{
Name: "buffers",
ShortForm: "buffers",
Handler: cmdListBuffers,
})
r.Register(Command{
Name: "ls",
ShortForm: "ls",
Handler: cmdListBuffers,
})
r.Register(Command{
Name: "bn",
ShortForm: "bn",
Handler: cmdNextBuffer,
})
r.Register(Command{
Name: "bp",
ShortForm: "bp",
Handler: cmdPrevBuffer,
})
r.Register(Command{
Name: "bf",
ShortForm: "bf",
Handler: cmdFirstBuffer,
})
r.Register(Command{
Name: "bl",
ShortForm: "bl",
Handler: cmdLastBuffer,
})
r.Register(Command{
Name: "b",
ShortForm: "b",
Handler: cmdSelectBuffer,
})
r.Register(Command{
Name: "bdelete",
ShortForm: "bd",
Handler: cmdDeleteBuffer,
})
// File commands
r.Register(Command{
Name: "edit",
ShortForm: "e",
Handler: cmdEdit,
})
// Color scheme commands
r.Register(Command{
Name: "colorscheme",
ShortForm: "colo",
Handler: cmdColorscheme,
})
r.Register(Command{
Name: "colorschemes",
ShortForm: "colorschemes",
Handler: cmdListColorschemes,
})
// Undo stack commands
r.Register(Command{
Name: "undo",
ShortForm: "u",
Handler: cmdUndoList,
})
}