Updated interaction between custom CLI syntax and Cobra flags
This commit is contained in:
+62
-27
@@ -12,9 +12,10 @@ import (
|
||||
|
||||
// ParsedArgs represents preprocessed command arguments
|
||||
type ParsedArgs struct {
|
||||
Command string
|
||||
Filters []string
|
||||
Modifiers []string
|
||||
Command string
|
||||
Filters []string
|
||||
Modifiers []string
|
||||
CmdArgIndex int // position of command in os.Args[1:], -1 if not found
|
||||
}
|
||||
|
||||
// Context key for parsed args
|
||||
@@ -84,28 +85,29 @@ func Execute() error {
|
||||
if len(os.Args) > 1 {
|
||||
firstArg := os.Args[1]
|
||||
if firstArg == "-h" || firstArg == "--help" || firstArg == "help" {
|
||||
// Let Cobra handle help - skip preprocessing
|
||||
return rootCmd.Execute()
|
||||
}
|
||||
}
|
||||
|
||||
// Preprocess arguments BEFORE Cobra routing
|
||||
// Preprocess arguments (read-only scan — os.Args is never mutated)
|
||||
if len(os.Args) > 1 {
|
||||
parsed := preprocessArgs(os.Args[1:])
|
||||
|
||||
// Store in context for commands to use
|
||||
ctx := context.WithValue(context.Background(), parsedArgsKey, parsed)
|
||||
rootCmd.SetContext(ctx)
|
||||
|
||||
// Rewrite os.Args for Cobra based on parsed command
|
||||
// This allows Cobra to route to the correct command
|
||||
if parsed.Command != "list" || len(parsed.Filters) > 0 || len(parsed.Modifiers) > 0 {
|
||||
// Reconstruct args: [command, ...filters, ...modifiers]
|
||||
newArgs := []string{os.Args[0], parsed.Command}
|
||||
newArgs = append(newArgs, parsed.Filters...)
|
||||
newArgs = append(newArgs, parsed.Modifiers...)
|
||||
os.Args = newArgs
|
||||
// Build clean args for Cobra via SetArgs (os.Args stays untouched).
|
||||
if parsed.CmdArgIndex >= 0 {
|
||||
i := parsed.CmdArgIndex + 1 // offset for binary name in os.Args
|
||||
cmdAndAfter := os.Args[i:] // command + subcommands + their flags
|
||||
preCmdFlags := collectFlags(os.Args[1:i]) // persistent flags before command
|
||||
|
||||
cobraArgs := make([]string, 0, len(cmdAndAfter)+len(preCmdFlags))
|
||||
cobraArgs = append(cobraArgs, cmdAndAfter...)
|
||||
cobraArgs = append(cobraArgs, preCmdFlags...)
|
||||
rootCmd.SetArgs(cobraArgs)
|
||||
}
|
||||
// CmdArgIndex == -1: no command found, don't call SetArgs.
|
||||
// Cobra processes os.Args naturally → root command → default report.
|
||||
}
|
||||
|
||||
return rootCmd.Execute()
|
||||
@@ -127,9 +129,10 @@ func getParsedArgs(cmd *cobra.Command) *ParsedArgs {
|
||||
func preprocessArgs(args []string) *ParsedArgs {
|
||||
if len(args) == 0 {
|
||||
return &ParsedArgs{
|
||||
Command: "list", // Default command
|
||||
Filters: []string{},
|
||||
Modifiers: []string{},
|
||||
Command: "list", // Default command
|
||||
Filters: []string{},
|
||||
Modifiers: []string{},
|
||||
CmdArgIndex: -1,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,9 +170,10 @@ func preprocessArgs(args []string) *ParsedArgs {
|
||||
// If no command found, treat as filters for default list command
|
||||
if cmdIdx == -1 {
|
||||
return &ParsedArgs{
|
||||
Command: "list",
|
||||
Filters: stripFlags(args),
|
||||
Modifiers: []string{},
|
||||
Command: "list",
|
||||
Filters: stripFlags(args),
|
||||
Modifiers: []string{},
|
||||
CmdArgIndex: -1,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,16 +187,18 @@ func preprocessArgs(args []string) *ParsedArgs {
|
||||
// Determine how to interpret right args
|
||||
if commandsWithModifiers[cmdName] {
|
||||
return &ParsedArgs{
|
||||
Command: cmdName,
|
||||
Filters: leftArgs,
|
||||
Modifiers: rightArgs,
|
||||
Command: cmdName,
|
||||
Filters: leftArgs,
|
||||
Modifiers: rightArgs,
|
||||
CmdArgIndex: cmdIdx,
|
||||
}
|
||||
} else {
|
||||
allFilters := append(leftArgs, rightArgs...)
|
||||
return &ParsedArgs{
|
||||
Command: cmdName,
|
||||
Filters: allFilters,
|
||||
Modifiers: []string{},
|
||||
Command: cmdName,
|
||||
Filters: allFilters,
|
||||
Modifiers: []string{},
|
||||
CmdArgIndex: cmdIdx,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,6 +214,35 @@ func stripFlags(args []string) []string {
|
||||
return result
|
||||
}
|
||||
|
||||
// collectFlags extracts flag arguments (with their values) from a slice.
|
||||
// Uses Cobra's persistent flag registry to determine if a flag takes a value.
|
||||
func collectFlags(args []string) []string {
|
||||
var flags []string
|
||||
for i := 0; i < len(args); i++ {
|
||||
if !strings.HasPrefix(args[i], "-") {
|
||||
continue
|
||||
}
|
||||
flags = append(flags, args[i])
|
||||
// If flag uses = syntax, value is already included
|
||||
if strings.Contains(args[i], "=") {
|
||||
continue
|
||||
}
|
||||
// Check if this flag takes a value argument
|
||||
if i+1 < len(args) {
|
||||
name := strings.TrimLeft(args[i], "-")
|
||||
f := rootCmd.PersistentFlags().Lookup(name)
|
||||
if f == nil && len(name) == 1 {
|
||||
f = rootCmd.PersistentFlags().ShorthandLookup(name)
|
||||
}
|
||||
if f != nil && f.Value.Type() != "bool" {
|
||||
i++
|
||||
flags = append(flags, args[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Add persistent flags for directory overrides
|
||||
rootCmd.PersistentFlags().StringVar(&configDirFlag, "config-dir", "",
|
||||
|
||||
@@ -2,3 +2,39 @@
|
||||
`Buy milk due:8d wait:5d` still showing up
|
||||
|
||||
# Missing uncomplete feat
|
||||
Undo / uncomplete fails in web-ui. task still has checked box and strikethrough.
|
||||
|
||||
# Cycling priority - Web
|
||||
Trying to edit a task priority results in following console error:
|
||||
GQLaRcBw.js:1 PUT https://opal.jnss.me/api/tasks/8814798c-97af-4134-9786-47e027d164c8 400 (Bad Request)
|
||||
window.fetch @ GQLaRcBw.js:1
|
||||
n @ nlPNz7OE.js:1
|
||||
update @ nlPNz7OE.js:1
|
||||
updateTask @ 2.qiXA3Mmu.js:1
|
||||
X @ 2.qiXA3Mmu.js:3
|
||||
Q @ 2.qiXA3Mmu.js:1
|
||||
(anonymous) @ idxpmzXF.js:1
|
||||
Qe @ jWcw5lls.js:1
|
||||
n @ idxpmzXF.js:1
|
||||
nlPNz7OE.js:1 API Error [/tasks/8814798c-97af-4134-9786-47e027d164c8]: Error: HTTP 400:
|
||||
at n (nlPNz7OE.js:1:1556)
|
||||
at async Object.updateTask (2.qiXA3Mmu.js:1:4502)
|
||||
at async X (2.qiXA3Mmu.js:3:3519)
|
||||
at async HTMLDivElement.Q (2.qiXA3Mmu.js:1:58579)
|
||||
n @ nlPNz7OE.js:1
|
||||
await in n
|
||||
update @ nlPNz7OE.js:1
|
||||
updateTask @ 2.qiXA3Mmu.js:1
|
||||
X @ 2.qiXA3Mmu.js:3
|
||||
Q @ 2.qiXA3Mmu.js:1
|
||||
(anonymous) @ idxpmzXF.js:1
|
||||
Qe @ jWcw5lls.js:1
|
||||
n @ idxpmzXF.js:1
|
||||
2.qiXA3Mmu.js:3 Failed to update task: Error: HTTP 400:
|
||||
at n (nlPNz7OE.js:1:1556)
|
||||
at async Object.updateTask (2.qiXA3Mmu.js:1:4502)
|
||||
at async X (2.qiXA3Mmu.js:3:3519)
|
||||
at async HTMLDivElement.Q (2.qiXA3Mmu.js:1:58579)
|
||||
|
||||
# Ambiguity complete and details tap.
|
||||
Pressing the task description completes the task. only the checkbox click should complete task, otherwise open details view. to complete swipe left
|
||||
|
||||
Reference in New Issue
Block a user