254 lines
4.9 KiB
Go
254 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,
|
|
})
|
|
|
|
r.Register(Command{
|
|
Name: "search",
|
|
ShortForm: "s",
|
|
Handler: cmdSearch,
|
|
})
|
|
}
|