align repl with cli

This commit is contained in:
Robin Olsen
2026-03-11 14:05:57 +01:00
parent b5cbacd532
commit 2c8ba4e393
4 changed files with 87 additions and 14 deletions

View File

@@ -21,14 +21,70 @@ func execute(input string) (string, error) {
return ReplTitle, nil
}
if input == "status" {
return executePMCommand("survey status")
}
if after, ok := strings.CutPrefix(input, "pm"); ok {
return executePMCommand(after)
}
return executeShellCommand(input)
}
// shellSplit splits input respecting quoted strings and escapes
// similar to how a shell would parse arguments
func shellSplit(input string) []string {
var args []string
var current strings.Builder
var inQuote rune
var escaped bool
for _, ch := range input {
if escaped {
current.WriteRune(ch)
escaped = false
continue
}
if ch == '\\' {
escaped = true
continue
}
if inQuote != 0 {
if ch == inQuote {
inQuote = 0
continue
}
current.WriteRune(ch)
continue
}
if ch == '"' || ch == '\'' {
inQuote = ch
continue
}
if ch == ' ' || ch == '\t' {
if current.Len() > 0 {
args = append(args, current.String())
current.Reset()
}
continue
}
current.WriteRune(ch)
}
if current.Len() > 0 {
args = append(args, current.String())
}
return args
}
func executeShellCommand(input string) (string, error) {
parts := strings.Fields(input)
parts := shellSplit(input)
if len(parts) == 0 {
return "", nil
}
@@ -39,7 +95,7 @@ func executeShellCommand(input string) (string, error) {
}
func executePMCommand(input string) (string, error) {
parts := strings.Fields(input)
parts := shellSplit(input)
if len(parts) == 0 {
return "", nil
}

View File

@@ -22,8 +22,8 @@ type ValidationFeedback = models.ValidationFeedback
const (
ReplHelp = `Type 'pm help' for available PM commands.
Type 'pm status' to check task progress.
You can also run shell commands directly. Type 'exit' or 'quit' to leave.`
You can also run shell commands directly. Type 'exit' or 'quit' to leave.
Type 'status' to check task progress.`
ReplTitle = "Welcome to Project Management CLI! " + ReplHelp
)
@@ -144,8 +144,19 @@ func (r *REPL) Run(ctx context.Context, config app.Config) error {
// Add the input to the history for future navigation.
history = append(history, input)
output, _ := execute(input) // Ignore errors for now, gives better ux
fmt.Println(style.TextStyle.Render(output)) // Print the output of the command in a styled format.
output, err := execute(input)
if err != nil {
// Show command output (even on error) in normal text style
if output != "" {
fmt.Println(style.TextStyle.Render(output))
}
// Show error message in red if no output was captured
if output == "" {
fmt.Println(style.ErrorStyle.Render(err.Error()))
}
} else if output != "" {
fmt.Println(style.TextStyle.Render(output))
}
}
return nil

View File

@@ -12,6 +12,7 @@ import (
// rootSuggestions is a list of prompt suggestions for root-level commands.
var rootSuggestions = []prompt.Suggest{
{Text: "pm", Description: "Project Management System"},
{Text: "status", Description: "Show task status"},
{Text: "exit", Description: "Exit pm CLI"},
{Text: "help", Description: "Show help information"},
{Text: "title", Description: "Print the welcome title"},
@@ -38,7 +39,8 @@ var createFlags = []prompt.Suggest{
{Text: "--desc", Description: "Issue description"},
{Text: "--status", Description: "Issue status (open, closed, in_progress)"},
{Text: "--type", Description: "Issue type (bug, feature, task)"},
{Text: "--priority", Description: "Issue priority (0-5)"},
{Text: "--priority", Description: "Issue priority (0-4)"},
{Text: "--assignee", Description: "Issue assignee"},
}
// updateFlags is a list of prompt suggestions for the update command flags.
@@ -47,7 +49,8 @@ var updateFlags = []prompt.Suggest{
{Text: "--desc", Description: "New issue description"},
{Text: "--status", Description: "New issue status (open, closed, in_progress)"},
{Text: "--type", Description: "New issue type (bug, feature, task)"},
{Text: "--priority", Description: "New issue priority (0-5)"},
{Text: "--priority", Description: "New issue priority (0-4)"},
{Text: "--assignee", Description: "New issue assignee"},
}
// listFlags is a list of prompt suggestions for the list command flags.
@@ -56,8 +59,9 @@ var listFlags = []prompt.Suggest{
{Text: "--desc", Description: "Filter by description"},
{Text: "--status", Description: "Filter by status (open, closed, in_progress)"},
{Text: "--type", Description: "Filter by type (bug, feature, task)"},
{Text: "--priority", Description: "Filter by priority (0-5)"},
{Text: "--priority", Description: "Filter by priority (0-4)"},
{Text: "--limit", Description: "Limit number of results"},
{Text: "--assignee", Description: "Filter by assignee"},
}
var deleteFlags = []prompt.Suggest{
@@ -81,18 +85,19 @@ var statusValues = []prompt.Suggest{
// typeValues is a list of prompt suggestions for issue types
var typeValues = []prompt.Suggest{
{Text: "task", Description: "Task issue type"},
{Text: "bug", Description: "Bug issue type"},
{Text: "feature", Description: "Feature issue type"},
{Text: "task", Description: "Task issue type"},
{Text: "chore", Description: "Chore issue type"},
}
// priorityValues is a list of prompt suggestions for issue priority levels
var priorityValues = []prompt.Suggest{
{Text: "0", Description: "Lowest priority"},
{Text: "0", Description: "Irrelevant"},
{Text: "1", Description: "Low priority"},
{Text: "2", Description: "Medium-low priority"},
{Text: "3", Description: "Medium priority"},
{Text: "4", Description: "High priority"},
{Text: "2", Description: "Normal priority"},
{Text: "3", Description: "High priority"},
{Text: "4", Description: "Critical priority"},
}
// isIDCommand maps command names to a boolean indicating whether they expect an issue ID as an argument.