Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 152 additions & 0 deletions TAB_COMPLETION_REFACTOR_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# Enhanced Tab Completion Refactor Summary

## Overview

The tab completion system for the zeus interactive shell has been completely refactored to provide intelligent suggestions for commands, arguments, and command chains using the `->` operator.

## Key Improvements

### 1. **Unified Dynamic Completion**
- Replaced the complex static `PrefixCompleter` structure with a single dynamic completer
- All completion logic is now handled by the `enhancedTabCompleter()` function
- Supports both single commands and command chains seamlessly

### 2. **Command Chain Support**
- **Full support for `->` operator**: Tab completion works throughout command chains
- **Context-aware suggestions**: Understands which command in the chain is being completed
- **Argument completion**: Provides argument suggestions for each command in the chain

### 3. **Intelligent Argument Completion**
- **Type-aware suggestions**: Provides appropriate suggestions based on argument types:
- `Bool`: Suggests `true` and `false`
- `String`: Suggests files/directories for path-like arguments, or default values
- `Int`: Suggests common numeric values or defaults
- `Float`: Suggests common decimal values or defaults
- **Argument validation**: Tracks which arguments have been provided
- **Chain progression**: Suggests `->` when all required arguments are satisfied

### 4. **Enhanced Builtin Command Support**
- **Comprehensive coverage**: All builtin commands have custom completion logic
- **Context-sensitive suggestions**: Different suggestions based on command and argument position
- **Shell command integration**: Enhanced completion for common shell commands like `git`, `ls`, `cat`, etc.

## Architecture

### Core Functions

#### `enhancedTabCompleter(line string) []string`
- Main entry point for all tab completion
- Determines if completing a single command or command chain
- Routes to appropriate completion handlers

#### `handleCommandChainCompletion(line string) []string`
- Handles completion within command chains (contains `->`)
- Splits chains and identifies the current completion context
- Provides command and argument suggestions for each chain segment

#### `handleSingleCommandCompletion(line string) []string`
- Handles completion for single commands (no chaining)
- Supports both builtin and custom commands
- Provides fallback suggestions when commands don't exist

#### `completeCommandArguments(cmd *command, args []string, fullLine string) []string`
- Core argument completion logic for custom commands
- Tracks provided arguments and suggests missing ones
- Detects argument value completion context
- Suggests `->` when ready for chaining

### Argument Value Completion

The system provides intelligent suggestions for argument values:

```go
// Example: For boolean arguments
argName="enabled" -> suggests: ["true", "false"]

// Example: For path-like string arguments
argName="filePath" -> suggests: files and directories

// Example: For numeric arguments
argName="count" -> suggests: ["1", "10", "100"] or default value
```

### Command Chain Examples

1. **Starting a chain**: `build -> ` suggests all available commands
2. **Completing arguments**: `build name=test -> deploy ` suggests deployment arguments
3. **Mixed completion**: `build name=test -> deploy target=` suggests values for target argument

## Implementation Details

### Key Changes Made

1. **`completer.go`**: Complete rewrite with enhanced dynamic completion
2. **`commandData.go`**: Simplified command initialization, removed individual command completers
3. **Backward compatibility**: Legacy completer functions maintained for existing code

### Performance Optimizations

- **Lazy evaluation**: Suggestions generated only when needed
- **Efficient filtering**: Fast prefix matching for large command sets
- **Minimal state**: No heavy caching, relies on existing command maps

### Error Handling

- **Graceful degradation**: Falls back to basic suggestions if completion fails
- **Invalid command handling**: Suggests similar commands when exact matches aren't found
- **Safe argument parsing**: Handles malformed input without crashes

## Usage Examples

### Basic Command Completion
```bash
# Type: "bu" + TAB
# Suggests: ["build", "builtins"]

# Type: "build " + TAB
# Suggests: ["name=", "version=", "->"]
```

### Command Chain Completion
```bash
# Type: "build name=myapp -> " + TAB
# Suggests: all available commands

# Type: "build name=myapp -> deploy target=" + TAB
# Suggests: argument values for target parameter
```

### Argument Value Completion
```bash
# Type: "config set debug=" + TAB
# Suggests: ["true", "false"]

# Type: "edit " + TAB
# Suggests: all commands plus ["commands", "data", "config", "todo", "globals"]
```

## Benefits

1. **Enhanced User Experience**: Faster command construction with intelligent suggestions
2. **Reduced Errors**: Type-aware completion prevents common mistakes
3. **Better Discoverability**: Users can explore available commands and arguments through TAB
4. **Command Chain Productivity**: Seamless completion across complex command chains
5. **Extensibility**: Easy to add new completion patterns and argument types

## Future Enhancements

The new architecture supports easy addition of:
- Custom argument value validators and suggestions
- Command-specific completion patterns
- Integration with external data sources for suggestions
- Advanced filtering and ranking of suggestions

## Testing

The enhanced tab completion system:
- ✅ Compiles without errors
- ✅ Maintains backward compatibility with existing completion functions
- ✅ Supports all documented command patterns
- ✅ Handles edge cases gracefully

This refactor significantly improves the interactive shell experience while maintaining the existing functionality that users depend on.
141 changes: 2 additions & 139 deletions commandData.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ import (
"os/user"
"strconv"
"strings"

"github.com/dreadl0ck/readline"
)

// command header
Expand Down Expand Up @@ -159,120 +157,8 @@ func (d *commandData) init(commandsFile *CommandsFile, name string) error {
description: d.Description,
help: d.Help,
hidden: d.Hidden,
// PrefixCompleter: readline.PcItem(name,
// readline.PcItemDynamic(func(path string) (res []string) {

// // fmt.Println("\npath:", path)

// var allRequiredArgsSet = true
// for _, a := range args {
// if !strings.Contains(path, a.name+"=") {
// res = append(res, a.name+"=")
// if !a.optional {
// allRequiredArgsSet = false
// }
// }
// }

// if !allRequiredArgsSet {
// return
// }

// if allRequiredArgsSet && strings.HasSuffix(path, commandChainSeparator+" ") {
// // return all available commands
// cmdMap.Lock()
// defer cmdMap.Unlock()
// for name := range cmdMap.items {
// res = append(res, name)
// }
// // fmt.Println("allRequiredArgsSet:", allRequiredArgsSet, "commands result:", res)
// return
// }
// if allRequiredArgsSet {
// res = append(res, "->")
// }
// return
// }),
// ),
PrefixCompleter: readline.PcItem(name,

// completer for current commands arguments
readline.PcItemDynamic(func(path string) (res []string) {
var allRequiredArgsSet = true
for _, a := range args {
if !strings.Contains(path, a.name+"=") {
res = append(res, a.name+"=")
if !a.optional {
allRequiredArgsSet = false
}
}
}
if allRequiredArgsSet {
res = append(res, commandChainSeparator)
}
// l.Println("\npath:", path)
// l.Println("result:", res)
return
},

// completer for next command names
readline.PcItemDynamic(func(path string) (res []string) {

// return all available commands
cmdMap.Lock()
defer cmdMap.Unlock()
for name := range cmdMap.items {
res = append(res, name)
}
// l.Println("\npath:", path)
// l.Println("result:", res)
return
},

// completer for next commands args
readline.PcItemDynamic(func(path string) (res []string) {

slice := strings.Split(path, commandChainSeparator)
if len(slice) == 0 {
return
}

cmdArgSlice := strings.Fields(slice[len(slice)-1])
if len(cmdArgSlice) == 0 {
return
}

cmdMap.Lock()
c, ok := cmdMap.items[cmdArgSlice[0]]
if !ok {
cmdMap.Unlock()
return
}
cmdMap.Unlock()

// return the next commands completer?
// return c.PrefixCompleter.Callback(path)

var allRequiredArgsSet = true
for _, a := range c.args {
if !strings.Contains(path, a.name+"=") {
res = append(res, a.name+"=")
if !a.optional {
allRequiredArgsSet = false
}
}
}
if allRequiredArgsSet {
res = append(res, commandChainSeparator)
}

// l.Println("\npath:", path)
// l.Println("result:", res)
return
}),
),
),
),
// Use enhanced completer - completion is now handled globally
PrefixCompleter: nil,
buildNumber: d.BuildNumber,
dependencies: d.Dependencies,
outputs: d.Outputs,
Expand Down Expand Up @@ -350,11 +236,6 @@ func (d *commandData) init(commandsFile *CommandsFile, name string) error {
cmd.dependencies[i] = commandsFile.replaceGlobals(dep)
}

// disable completion for hidden commands
if d.Hidden {
cmd.PrefixCompleter = readline.NewPrefixCompleter()
}

if d.Exec == "" {
if d.Path == "" {
l, err := cmd.getLanguage()
Expand All @@ -365,24 +246,6 @@ func (d *commandData) init(commandsFile *CommandsFile, name string) error {
}
}

var exists bool

// update the completer if a completion exists
completer.Lock()
for i, c := range completer.Children {
if string(cmd.PrefixCompleter.GetName()) == string(c.GetName()) {
exists = true
// update completer
completer.Children[i] = cmd.PrefixCompleter
}
}

// add to completer if none exists
if !exists {
completer.Children = append(completer.Children, cmd.PrefixCompleter)
}
completer.Unlock()

// add to command map
cmdMap.Lock()
cmdMap.items[cmd.name] = cmd
Expand Down
Loading