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) 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 } // Register adds a command to the registry func (r *Registry) Register(cmd Command) { r.commands = append(r.commands, cmd) } // Lookup finds a command by name or abbreviation // Returns the command and any error (unknown or ambiguous) 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) { parts := strings.Fields(cmdLine) if len(parts) == 0 { return "", nil } return parts[0], parts[1:] } // Execute parses and executes a command line func (r *Registry) Execute(m action.Model, cmdLine string) (tea.Cmd, error) { name, args := Parse(cmdLine) cmd, err := r.Lookup(name) if err != nil { return nil, err } return cmd.Handler(m, args), nil } // DefaultRegistry is the global command registry var DefaultRegistry = NewRegistry() // 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, }) // Set command r.Register(Command{ Name: "set", ShortForm: "se", Handler: cmdSet, }) // Register commands r.Register(Command{ Name: "register", ShortForm: "reg", Handler: cmdRegisters, }) }