All checks were successful
Run Test Suite / test (push) Successful in 39s
There are some odd things being done in the testing files, that should get reviewed.
233 lines
4.6 KiB
Go
233 lines
4.6 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,
|
|
})
|
|
|
|
// 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,
|
|
})
|
|
}
|