Skip to content

Commit

Permalink
Let mlr help take pre-flags, such as --always-color
Browse files Browse the repository at this point in the history
  • Loading branch information
johnkerl committed May 15, 2023
1 parent d16310e commit 145a25e
Show file tree
Hide file tree
Showing 28 changed files with 209 additions and 109 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ bench-input:build
# See ./regression_test.go for information on how to get more details
# for debugging. TL;DR is for CI jobs, we have 'go test -v'; for
# interactive use, instead of 'go test -v' simply use 'mlr regtest
# -vvv' or 'mlr regtest -s 20'. See also internal/pkg/auxents/regtest.
# -vvv' or 'mlr regtest -s 20'. See also internal/pkg/terminals/regtest.
regression-test: build
go test -v regression_test.go

Expand Down
2 changes: 1 addition & 1 deletion README-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ So, in broad overview, the key packages are:
* This package defines the grammar for Miller's domain-specific language (DSL) for the Miller `put` and `filter` verbs. And, GOCC is a joy to use. :)
* It is used on the terms of its open-source license.
* [golang.org/x/term](https://pkg.go.dev/golang.org/x/term):
* Just a one-line Miller callsite for is-a-terminal checking for the [Miller REPL](./internal/pkg/auxents/repl/README.md).
* Just a one-line Miller callsite for is-a-terminal checking for the [Miller REPL](./internal/pkg/terminals/repl/README.md).
* It is used on the terms of its open-source license.
* See also [./go.mod](go.mod). Setup:
* `go get github.com/goccmack/gocc`
Expand Down
7 changes: 7 additions & 0 deletions docs/src/glossary.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,13 @@ can split it into several files, one for each distinct `id`. See the [section
on tee statements](reference-dsl-output-statements.md#tee-statements) for an
example.

## terminals

These include `mlr help`, `mlr regtest`, `mlr repl`, and `mlr version`. They
aren't verbs but they can be preceded by various command-line flags. They're in
contrast to [auxents](#auxents) which are effectively standalone programs
packaged with Miller.

## terminator

Used in two senses:
Expand Down
15 changes: 0 additions & 15 deletions internal/pkg/auxents/auxents.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,6 @@ package auxents
import (
"fmt"
"os"
"runtime"

"github.com/johnkerl/miller/internal/pkg/auxents/help"
"github.com/johnkerl/miller/internal/pkg/auxents/regtest"
"github.com/johnkerl/miller/internal/pkg/auxents/repl"
"github.com/johnkerl/miller/internal/pkg/version"
)

// tAuxMain is a function-pointer type for the entrypoint handler for a given auxent,
Expand All @@ -37,10 +31,6 @@ func init() {
{"lecat", lecatMain},
{"termcvt", termcvtMain},
{"unhex", unhexMain},
{"help", help.HelpMain},
{"regtest", regtest.RegTestMain},
{"repl", repl.ReplMain},
{"version", showVersion},
}
}

Expand Down Expand Up @@ -77,8 +67,3 @@ func ShowAuxEntries(o *os.File) {

fmt.Fprintf(o, "For more information, please invoke mlr {subcommand} --help.\n")
}

func showVersion(args []string) int {
fmt.Printf("mlr version %s for %s/%s/%s\n", version.STRING, runtime.GOOS, runtime.GOARCH, runtime.Version())
return 0
}
4 changes: 1 addition & 3 deletions internal/pkg/auxents/doc.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// Package auxents implements little helper-tools embedded within Miller, such
// as mlr hex and mlr termcvt. It also implements mlr help (on-line help), mlr
// regtest (for regressio-testing), and mlr repl (Miller's read-evaluate-print
// loop).
// as `mlr hex` and `mlr termcvt`.
package auxents
4 changes: 2 additions & 2 deletions internal/pkg/cli/flag_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,8 @@ func (ft *FlagTable) GetDowndashSectionNames() []string {
// since in Go you needn't specify all struct initializers, so for example a
// Flag struct-initializer which doesn't say `help: "..."` will have empty help
// string. This nil-checking doesn't need to be done on every Miller
// invocation, but rather, only at build time. The `mlr help` auxent has an
// entry point wherein a regression-test case can do `mlr help nil-check` and
// invocation, but rather, only at build time. The `mlr help` terminal has an
// entrypoint wherein a regression-test case can do `mlr help nil-check` and
// make this function exits cleanly.
func (ft *FlagTable) NilCheck() {
lib.InternalCodingErrorWithMessageIf(ft.sections == nil, "Nil table sections")
Expand Down
43 changes: 31 additions & 12 deletions internal/pkg/climain/mlrcli_parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,11 @@ import (
"fmt"
"os"

"github.com/johnkerl/miller/internal/pkg/auxents/help"
"github.com/johnkerl/miller/internal/pkg/cli"
"github.com/johnkerl/miller/internal/pkg/lib"
"github.com/johnkerl/miller/internal/pkg/mlrval"
"github.com/johnkerl/miller/internal/pkg/terminals"
"github.com/johnkerl/miller/internal/pkg/terminals/help"
"github.com/johnkerl/miller/internal/pkg/transformers"
"github.com/johnkerl/miller/internal/pkg/version"
)
Expand All @@ -99,21 +100,23 @@ func ParseCommandLine(
}

// Pass one as described at the top of this file.
flagSequences, verbSequences, dataFileNames := parseCommandLinePassOne(args)
flagSequences, terminalSequence, verbSequences, dataFileNames := parseCommandLinePassOne(args)

// Pass two as described at the top of this file.
return parseCommandLinePassTwo(flagSequences, verbSequences, dataFileNames)
return parseCommandLinePassTwo(flagSequences, terminalSequence, verbSequences, dataFileNames)
}

// parseCommandLinePassOne is as described at the top of this file.
func parseCommandLinePassOne(
args []string,
) (
flagSequences [][]string,
terminalSequence []string,
verbSequences [][]string,
dataFileNames []string,
) {
flagSequences = make([][]string, 0)
terminalSequence = nil
verbSequences = make([][]string, 0)
dataFileNames = make([]string, 0)

Expand Down Expand Up @@ -143,7 +146,7 @@ func parseCommandLinePassOne(
os.Exit(0)
} else if help.ParseTerminalUsage(args[argi]) {
// Exiting flag: handle it immediately.
// Most help is in the 'mlr help' auxent but there are a few
// Most help is in the 'mlr help' terminal but there are a few
// shorthands like 'mlr -h' and 'mlr -F'.
os.Exit(0)

Expand All @@ -165,6 +168,12 @@ func parseCommandLinePassOne(
os.Exit(1)
}

} else if onFirst && terminals.Dispatchable(args[argi]) {
// mlr help, mlr regtest, etc -- _everything_ on the command line after this
// will be handled by that terminal
terminalSequence = args[argi:]
break

} else if onFirst || args[argi] == "then" || args[argi] == "+" {
// The first verb in the then-chain can *optionally* be preceded by
// 'then'. The others one *must* be.
Expand Down Expand Up @@ -212,22 +221,26 @@ func parseCommandLinePassOne(
}
}

for ; argi < argc; argi++ {
dataFileNames = append(dataFileNames, args[argi])
}
if terminalSequence == nil {

if len(verbSequences) == 0 {
fmt.Fprintf(os.Stderr, "%s: no verb supplied.\n", "mlr")
help.MainUsage(os.Stderr)
os.Exit(1)
for ; argi < argc; argi++ {
dataFileNames = append(dataFileNames, args[argi])
}

if len(verbSequences) == 0 {
fmt.Fprintf(os.Stderr, "%s: no verb supplied.\n", "mlr")
help.MainUsage(os.Stderr)
os.Exit(1)
}
}

return flagSequences, verbSequences, dataFileNames
return flagSequences, terminalSequence, verbSequences, dataFileNames
}

// parseCommandLinePassTwo is as described at the top of this file.
func parseCommandLinePassTwo(
flagSequences [][]string,
terminalSequence []string,
verbSequences [][]string,
dataFileNames []string,
) (
Expand Down Expand Up @@ -300,6 +313,12 @@ func parseCommandLinePassTwo(
}
}

if terminalSequence != nil {
terminals.Dispatch(terminalSequence)
// They are expected to exit the process
panic("mlr: internal coding error: terminal did not exit the process")
}

// Now process the verb-sequences from pass one, with options-struct set up
// and finalized.
for i, verbSequence := range verbSequences {
Expand Down
6 changes: 3 additions & 3 deletions internal/pkg/lib/getoptify.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (
// is a keystroke-saver for the user.
//
// This is OK to do here globally since Miller is quite consistent (in main,
// verbs, and auxents) that multi-character options start with two dashes, e.g.
// "--csv". (The sole exception is the sort verb's -nf/-nr which are handled
// specially there.)
// verbs, auxents, and terminals) that multi-character options start with two
// dashes, e.g. "--csv". (The sole exception is the sort verb's -nf/-nr which
// are handled specially there.)
//
// Additionally, we split "--foo=bar" into "--foo" and "bar".
func Getoptify(inargs []string) []string {
Expand Down
3 changes: 3 additions & 0 deletions internal/pkg/terminals/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Package terminals implements `mlr help` (on-line help), `mlr regtest` (for regressio-testing),
// `mlr repl` (Miller's read-evaluate-print loop), and `mlr version`.
package terminals
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ var handlerLookupTable = tHandlerLookupTable{}
var shorthandLookupTable = tShorthandTable{}

func init() {
// For things like 'mlr help foo', invoked through the auxent framework
// For things like 'mlr help foo', invoked through the terminals framework
// which goes through our HelpMain().
handlerLookupTable = tHandlerLookupTable{
sections: []tHandlerInfoSection{
Expand Down Expand Up @@ -108,6 +108,7 @@ func init() {
name: "Other",
handlerInfos: []tHandlerInfo{
{name: "auxents", zaryHandlerFunc: helpAuxents},
{name: "terminals", zaryHandlerFunc: helpTerminals},
{name: "mlrrc", zaryHandlerFunc: helpMlrrc},
{name: "output-colorization", zaryHandlerFunc: helpOutputColorization},
{name: "type-arithmetic-info", zaryHandlerFunc: helpTypeArithmeticInfo},
Expand Down Expand Up @@ -183,11 +184,12 @@ func init() {
}

// ================================================================
// For things like 'mlr help foo', invoked through the auxent framework which
// goes through our HelpMain(). Here, the args are the full Miller command
// line: "mlr help foo bar".
// For things like 'mlr help foo', invoked through the terminals framework which
// goes through our HelpMain(). Here, the args are the terminal part of the full
// Miller command line: if the latter was "mlr --some-flag help foo bar" then
// the former is "help foo bar".
func HelpMain(args []string) int {
args = args[2:]
args = args[1:]

// "mlr help" and nothing else
if len(args) == 0 {
Expand Down Expand Up @@ -320,14 +322,15 @@ func listSeparatorRegexAliases() {
cli.ListSeparatorRegexAliasesForOnlineHelp()
}

// ----------------------------------------------------------------
func helpAuxents() {
fmt.Print(`Miller has a few otherwise-standalone executables packaged within it.
They do not participate in any other parts of Miller.
Please "mlr aux-list" for more information.
`)
// imports github.com/johnkerl/miller/internal/pkg/auxents: import cycle not allowed
// auxents.ShowAuxEntries(o)
}

func helpTerminals() {
fmt.Println("Terminals include on-line help, regression-test entry point, and the REPL.")
}

// ----------------------------------------------------------------
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package regtest
import (
"fmt"
"os"
"path"
"strconv"
"strings"
)
Expand All @@ -16,8 +15,7 @@ const defaultPath = "./test/cases"

// ================================================================
func regTestUsage(verbName string, o *os.File, exitCode int) {
exeName := path.Base(os.Args[0])
fmt.Fprintf(o, "Usage: %s %s [options] [one or more directories/files]\n", exeName, verbName)
fmt.Fprintf(o, "Usage: mlr %s [options] [one or more directories/files]\n", verbName)
fmt.Fprintf(o, "If no directories/files are specified, the directory %s is used by default.\n", defaultPath)
fmt.Fprintf(o, "Recursively walks the directory/ies looking for foo.cmd files having Miller command-lines,\n")
fmt.Fprintf(o, "with foo.expout and foo.experr files having expected stdout and stderr, respectively.\n")
Expand All @@ -41,10 +39,10 @@ func regTestUsage(verbName string, o *os.File, exitCode int) {
// Here the args are the full Miller command line: "mlr regtest --foo bar".
func RegTestMain(args []string) int {

exeName := args[0]
verbName := args[1]
exeName := "mlr"
verbName := args[0]
argc := len(args)
argi := 2
argi := 1
verbosityLevel := 0
doPopulate := false
plainMode := false
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,13 @@ at the Miller REPL prompt.
os.Exit(exitCode)
}

// Here the args are the full Miller command line: "mlr repl foo bar".
// Here the args are the full Miller command line: if the latter was "mlr
// --some-flag repl foo bar" then the former is "repl foo bar".
func ReplMain(args []string) int {
exeName := path.Base(args[0])
replName := args[1]
exeName := os.Args[0]
replName := args[0]
argc := len(args)
argi := 2
argi := 1

showStartupBanner := true
showPrompts := true
Expand Down Expand Up @@ -184,14 +185,14 @@ func ReplMain(args []string) int {

err = repl.handleSession(os.Stdin)
if err != nil {
fmt.Fprintf(os.Stderr, "%s %s: %v", repl.exeName, repl.replName, err)
fmt.Fprintf(os.Stderr, "mlr s: %v", repl.replName, err)
os.Exit(1)
}

repl.bufferedRecordOutputStream.Flush()
err = repl.closeBufferedOutputStream()
if err != nil {
fmt.Fprintf(os.Stderr, "%s %s: %v", repl.exeName, repl.replName, err)
fmt.Fprintf(os.Stderr, "mlr s: %v", repl.replName, err)
os.Exit(1)
}
return 0
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 145a25e

Please sign in to comment.