The tests are starting to get messy, lots of duplication. Going to resolve that. Lots of this is due to AI generation of tests.
241 lines
4.7 KiB
Go
241 lines
4.7 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,
|
|
})
|
|
}
|