implementing dependency management in the cli

This commit is contained in:
viljarb
2026-03-25 14:27:38 +01:00
parent 7a68735dbb
commit 13d54d9e81
3 changed files with 208 additions and 0 deletions

View File

@@ -28,6 +28,12 @@ func (r *REPL) execute(input string) (string, error) {
if after, ok := strings.CutPrefix(input, "pm"); ok {
if strings.Contains(strings.Split(after, " ")[1], "start") {
//trimmedAfter := strings.TrimSpace(after)
//parts := shellSplit(trimmedAfter)
// Prevent accidental attempts to run "pm start ..." inside the REPL.
// (The REPL uses `status/title/help` and shell execution instead.)
//if len(parts) > 1 && strings.Contains(parts[1], "start") {
return "Nice try👻", nil
}

View File

@@ -31,6 +31,7 @@ var baseSuggestions = []prompt.Suggest{
{Text: "delete", Description: "Delete an issue by ID"},
{Text: "comment", Description: "Add a comment on an issue by ID"},
{Text: "comments", Description: "List comments on an issue by ID"},
{Text: "dep", Description: "Manage dependencies for an issue"},
{Text: "new", Description: "Alias for create command"},
{Text: "ls", Description: "Alias for list command"},
@@ -123,6 +124,15 @@ var sprintSubcommands = []prompt.Suggest{
{Text: "del", Description: "Alias for delete subcommand"},
}
var depSubcommands = []prompt.Suggest{
{Text: "view", Description: "View dependencies of an issue"},
{Text: "list", Description: "Alias for view"},
{Text: "show", Description: "Alias for view"},
{Text: "add", Description: "Add a dependency"},
{Text: "remove", Description: "Remove a dependency"},
{Text: "rm", Description: "Alias for remove"},
}
// statusValues is a list of prompt suggestions for status types
var statusValues = []prompt.Suggest{
{Text: "open", Description: "Open status"},
@@ -195,6 +205,73 @@ func commandSuggestions(words []string) []prompt.Suggest {
func flagSuggestions(cmd string, words []string, text string) []prompt.Suggest {
lastWord, prevWord := parseWords(words, text)
// Custom completion logic for `pm dep ...`
if cmd == "dep" {
switch len(words) {
case 1:
// `pm dep ` => next token could be a subcommand; default view is handled
// once the user types an issue id
if strings.HasSuffix(text, " ") {
return depSubcommands
}
return nil
case 2:
// either:
// - pm dep <issueID> (default view)
// - pm dep <subcommand>
if strings.HasSuffix(text, " ") {
sub := words[1]
switch sub {
case "view", "list", "show", "add", "remove", "rm":
// After a valid subcommand we expect the issue id next.
return issueIDSuggestions("", true)
default:
// Treat it as an issue id already; no more suggestions.
return nil
}
}
// Typing the 2nd token: suggest subcommands and issue IDs that match.
suggests := make([]prompt.Suggest, 0, len(depSubcommands))
suggests = append(suggests, filterByPrefix(depSubcommands, lastWord)...)
//suggests = append(suggests, issueIDSuggestions(lastWord, true)...)
return suggests
case 3:
// If subcommand is `add/remove`, third token is the issue id.
// If subcommand is show/list, third token is the issue id.
sub := words[1]
switch sub {
case "add", "remove", "rm":
if strings.HasSuffix(text, " ") {
// `pm dep add <issueID> ` => next token is dependsOnID.
return issueIDSuggestions("", true)
}
return issueIDSuggestions(lastWord, true)
default:
// show/list/show => completing the issue id.
if strings.HasSuffix(text, " ") {
return nil
}
return issueIDSuggestions(lastWord, true)
}
case 4:
// add/remove/rm have a 4th token: dependsOnID.
sub := words[1]
if sub == "add" || sub == "remove" || sub == "rm" {
if strings.HasSuffix(text, " ") {
return nil
}
return issueIDSuggestions(lastWord, true)
}
return nil
}
return nil
}
if values := getFlagValues(prevWord); values != nil {
return filterByPrefix(values, lastWord)
}