cmd: fix -h handling

Fixes `cue -h` and `cue cmd -h` parsing.

Closes #723

Change-Id: I1aeafab49fe8630400829ba2b48372d61ad83232

Closes #827
https://github.com/cuelang/cue/pull/827

GitOrigin-RevId: 30996db2cd6fe7e044ac6ad5a194bca555976515
Change-Id: I4370ec8860c47ca79496e24a55ffc3416f8fefcb
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9081
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Paul Jolly <paul@myitcv.org.uk>
diff --git a/cmd/cue/cmd/root.go b/cmd/cue/cmd/root.go
index fd65bed..de4c8f6 100644
--- a/cmd/cue/cmd/root.go
+++ b/cmd/cue/cmd/root.go
@@ -239,8 +239,8 @@
 		// "fix":   {"fix", nil},
 	}
 
-	// handle help and --help on root 'cue' command
-	if args[0] == "help" || args[0] == "--help" {
+	// handle help, --help and -h on root 'cue' command
+	if args[0] == "help" || args[0] == "--help" || args[0] == "-h" {
 		// Allow errors.
 		_ = addSubcommands(cmd, sub, args[1:], true)
 		return cmd, nil
@@ -301,10 +301,10 @@
 			oldargs := []string{args[0]}
 			args = args[1:]
 
-			// Check for 'cue cmd --help'
+			// Check for 'cue cmd --help|-h'
 			// it is behaving differently for this one command, cobra does not seem to pick it up
 			// See issue #340
-			if len(args) == 1 && args[0] == "--help" {
+			if len(args) == 1 && (args[0] == "--help" || args[0] == "-h") {
 				return cmd.Usage()
 			}
 
diff --git a/cmd/cue/cmd/root_test.go b/cmd/cue/cmd/root_test.go
index 31ef2ec..5232f4c 100644
--- a/cmd/cue/cmd/root_test.go
+++ b/cmd/cue/cmd/root_test.go
@@ -27,6 +27,11 @@
 		t.Error("help command failed unexpectedly")
 	}
 
+	cmd, err = New([]string{"-h"})
+	if err != nil || cmd == nil {
+		t.Error("help command failed unexpectedly")
+	}
+
 	cmd, err = New([]string{"help", "cmd"})
 	if err != nil || cmd == nil {
 		t.Error("help command failed unexpectedly")
@@ -37,6 +42,11 @@
 		t.Error("help command failed unexpectedly")
 	}
 
+	cmd, err = New([]string{"cmd", "-h"})
+	if err != nil || cmd == nil {
+		t.Error("help command failed unexpectedly")
+	}
+
 	cmd, err = New([]string{"help", "eval"})
 	if err != nil || cmd == nil {
 		t.Error("help command failed unexpectedly")
diff --git a/cmd/cue/cmd/testdata/script/help.txt b/cmd/cue/cmd/testdata/script/help.txt
new file mode 100644
index 0000000..268867d
--- /dev/null
+++ b/cmd/cue/cmd/testdata/script/help.txt
@@ -0,0 +1,67 @@
+# Verify that the various forms of requesting help work
+
+cue help
+cmp stdout stdout.golden
+
+cue --help
+cmp stdout stdout.golden
+
+cue -h
+cmp stdout stdout.golden
+
+-- stdout.golden --
+cue evaluates CUE files, an extension of JSON, and sends them
+to user-defined commands for processing.
+
+Commands are defined in CUE as follows:
+
+	import "tool/exec"
+	command: deploy: {
+		exec.Run
+		cmd:   "kubectl"
+		args:  [ "-f", "deploy" ]
+		in:    json.Encode(userValue) // encode the emitted configuration.
+	}
+
+cue can also combine the results of http or grpc request with the input
+configuration for further processing. For more information on defining commands
+run 'cue help cmd' or go to cuelang.org/pkg/cmd.
+
+For more information on writing CUE configuration files see cuelang.org.
+
+Usage:
+  cue [command]
+
+Available Commands:
+  cmd         run a user-defined shell command
+  completion  Generate completion script
+  def         print consolidated definitions
+  eval        evaluate and print a configuration
+  export      output data in a standard format
+  fix         rewrite packages to latest standards
+  fmt         formats CUE configuration files
+  get         add dependencies to the current module
+  help        Help about any command
+  import      convert other formats to CUE files
+  mod         module maintenance
+  trim        remove superfluous fields
+  version     print CUE version
+  vet         validate data
+
+Flags:
+  -E, --all-errors   print all available errors
+  -h, --help         help for cue
+  -i, --ignore       proceed in the presence of errors
+  -s, --simplify     simplify output
+      --strict       report errors for lossy mappings
+      --trace        trace computation
+  -v, --verbose      print information about progress
+
+Additional help topics:
+  cue commands   user-defined commands
+  cue filetypes  supported file types and qualifiers
+  cue flags      common flags for composing packages
+  cue injection  inject files or values into specific fields for a build
+  cue inputs     package list, patterns, and files
+
+Use "cue [command] --help" for more information about a command.
diff --git a/cmd/cue/cmd/testdata/script/help_cmd_flags.txt b/cmd/cue/cmd/testdata/script/help_cmd_flags.txt
new file mode 100644
index 0000000..8cad548
--- /dev/null
+++ b/cmd/cue/cmd/testdata/script/help_cmd_flags.txt
@@ -0,0 +1,148 @@
+cue cmd -h
+cmp stdout expect-stdout
+
+cue cmd --help
+cmp stdout expect-stdout
+
+-- cue.mod --
+-- task_tool.cue --
+package home
+
+import "tool/cli"
+
+// say hello to someone
+command: hello: {
+    task: say: {
+        cli.Print
+        text: "Hello world!"
+    }
+}
+
+// echo something back
+command: echo: {
+    task: echo: {
+        cli.Print
+        text: "ECHO Echo echo..."
+    }
+}
+
+-- expect-stdout --
+cmd executes the named command for each of the named instances.
+
+Commands define actions on instances. For example, they may
+specify how to upload a configuration to Kubernetes. Commands are
+defined directly in tool files, which are regular CUE files
+within the same package with a filename ending in _tool.cue.
+These are typically defined at the module root so that they apply
+to all instances.
+
+Each command consists of one or more tasks. A task may, for
+example, load or write a file, consult a user on the command
+line, fetch a web page, and so on. Each task has inputs and
+outputs. Outputs are typically filled out by the task
+implementation as the task completes.
+
+Inputs of tasks my refer to outputs of other tasks. The cue tool
+does a static analysis of the configuration and only starts tasks
+that are fully specified. Upon completion of each task, cue
+rewrites the instance, filling in the completed task, and
+reevaluates which other tasks can now start, and so on until all
+tasks have completed.
+
+Available tasks can be found in the package documentation at
+
+	https://pkg.go.dev/cuelang.org/go/pkg/tool?tab=subdirectories
+
+Examples:
+
+In this simple example, we define a command called "hello",
+which declares a single task called "print" which uses
+"tool/exec.Run" to execute a shell command that echos output to
+the terminal:
+
+	$ cat <<EOF > hello_tool.cue
+	package foo
+
+	import "tool/exec"
+
+	city: "Amsterdam"
+	who: *"World" | string @tag(who)
+
+	// Say hello!
+	command: hello: {
+		print: exec.Run & {
+			cmd: "echo Hello \(who)! Welcome to \(city)."
+		}
+	}
+	EOF
+
+We run the "hello" command like this:
+
+	$ cue cmd hello
+	Hello World! Welcome to Amsterdam.
+
+	$ cue cmd --inject who=Jan hello
+	Hello Jan! Welcome to Amsterdam.
+
+
+In this example we declare the "prompted" command which has four
+tasks. The first task prompts the user for a string input. The
+second task depends on the first, and echos the response back to
+the user with a friendly message. The third task pipes the output
+from the second to a file. The fourth task pipes the output from
+the second to standard output (i.e. it echos it again).
+
+	package foo
+
+	import (
+		"tool/cli"
+		"tool/exec"
+		"tool/file"
+	)
+
+	city: "Amsterdam"
+
+	// Say hello!
+	command: prompter: {
+		// save transcript to this file
+		var: file: *"out.txt" | string @tag(file)
+
+		ask: cli.Ask & {
+			prompt:   "What is your name?"
+			response: string
+		}
+
+		// starts after ask
+		echo: exec.Run & {
+			cmd:    ["echo", "Hello", ask.response + "!"]
+			stdout: string // capture stdout
+		}
+
+		// starts after echo
+		append: file.Append & {
+			filename: var.file
+			contents: echo.stdout
+		}
+
+		// also starts after echo
+		print: cli.Print & {
+			text: echo.stdout
+		}
+	}
+
+Run "cue help commands" for more details on tasks and commands.
+
+Usage:
+  cue cmd <name> [inputs] [flags]
+
+Flags:
+  -h, --help                 help for cmd
+  -t, --inject stringArray   set the value of a tagged field
+
+Global Flags:
+  -E, --all-errors   print all available errors
+  -i, --ignore       proceed in the presence of errors
+  -s, --simplify     simplify output
+      --strict       report errors for lossy mappings
+      --trace        trace computation
+  -v, --verbose      print information about progress