From 89f39627575ea0daa4cef094b40daf2b671d6d14 Mon Sep 17 00:00:00 2001 From: John Kerl Date: Thu, 1 Jul 2021 00:44:33 +0000 Subject: [PATCH] More neatening of on-line help (#588) * Continue neatening on-line help * replace lib.MlrExeName() with "mlr" * synchronize mlr -l/-L/-f/-F/-k/-K --- docs6/mk-func-h2s.sh | 4 +- docs6/reference-dsl-builtin-functions.rst | 2 +- docs6/reference-dsl-builtin-functions.rst.in | 2 +- docs6/reference-dsl-variables.rst | 4 +- docs6/reference-dsl-variables.rst.in | 4 +- docs6/reference-verbs.rst | 6 +- go/build | 4 - go/regression_test.go | 2 +- go/src/auxents/help/entry.go | 87 +- go/src/auxents/hex.go | 2 +- go/src/auxents/lecat.go | 2 +- go/src/auxents/regtest/regtester.go | 4 +- go/src/auxents/repl/ast.go | 3 +- go/src/auxents/repl/verbs.go | 7 +- go/src/auxents/termcvt.go | 10 +- go/src/cli/mlrcli_mlrrc.go | 5 +- go/src/cli/mlrcli_parse.go | 12 +- go/src/cliutil/mlrcli_util.go | 6 +- go/src/cliutil/option_parse.go | 26 +- go/src/cliutil/verb_utils.go | 6 +- go/src/dsl/cst/builtin_function_manager.go | 56 +- go/src/dsl/cst/dump.go | 4 +- go/src/dsl/cst/emit_emitp.go | 4 +- go/src/dsl/cst/emitf.go | 6 +- go/src/dsl/cst/keyword_usage.go | 32 +- go/src/dsl/cst/print.go | 4 +- go/src/dsl/cst/root.go | 5 +- go/src/dsl/cst/tee.go | 6 +- go/src/dsl/cst/validate.go | 6 +- go/src/entrypoint/entrypoint.go | 8 +- go/src/lib/exename.go | 12 - go/src/lib/halfpipe.go | 4 +- go/src/lib/mlrmath.go | 2 +- go/src/lib/paragraph.go | 34 + go/src/output/file-output-handlers.go | 2 +- go/src/runtime/stack.go | 4 +- go/src/stream/stream.go | 3 +- go/src/transformers/aaa_transformer_table.go | 24 +- go/src/transformers/altkv.go | 3 +- go/src/transformers/bar.go | 3 +- go/src/transformers/bootstrap.go | 4 +- go/src/transformers/cat.go | 3 +- go/src/transformers/check.go | 3 +- go/src/transformers/clean-whitespace.go | 3 +- go/src/transformers/count-similar.go | 2 +- go/src/transformers/count.go | 2 +- go/src/transformers/cut.go | 14 +- go/src/transformers/decimate.go | 3 +- go/src/transformers/fill-down.go | 3 +- go/src/transformers/fill-empty.go | 3 +- go/src/transformers/flatten.go | 4 +- go/src/transformers/format-values.go | 3 +- go/src/transformers/fraction.go | 2 +- go/src/transformers/gap.go | 3 +- go/src/transformers/grep.go | 7 +- go/src/transformers/group-by.go | 2 +- go/src/transformers/group-like.go | 2 +- go/src/transformers/having-fields.go | 6 +- go/src/transformers/head.go | 3 +- go/src/transformers/histogram.go | 4 +- go/src/transformers/join.go | 18 +- go/src/transformers/json-parse.go | 2 +- go/src/transformers/json-stringify.go | 2 +- go/src/transformers/label.go | 2 +- go/src/transformers/merge-fields.go | 14 +- go/src/transformers/most-or-least-frequent.go | 5 +- go/src/transformers/nest.go | 4 +- go/src/transformers/nothing.go | 3 +- go/src/transformers/put-or-filter.go | 8 +- go/src/transformers/regularize.go | 2 +- go/src/transformers/remove-empty-columns.go | 3 +- go/src/transformers/rename.go | 4 +- go/src/transformers/reorder.go | 2 +- go/src/transformers/repeat.go | 9 +- go/src/transformers/reshape.go | 4 +- go/src/transformers/sample.go | 4 +- go/src/transformers/sec2gmt.go | 6 +- go/src/transformers/seqgen.go | 3 +- go/src/transformers/shuffle.go | 4 +- go/src/transformers/skip-trivial-records.go | 3 +- go/src/transformers/sort-within-records.go | 3 +- go/src/transformers/sort.go | 6 +- go/src/transformers/stats1.go | 20 +- go/src/transformers/stats2.go | 8 +- go/src/transformers/step.go | 14 +- go/src/transformers/tac.go | 3 +- go/src/transformers/tail.go | 2 +- go/src/transformers/tee.go | 7 +- go/src/transformers/top.go | 2 +- go/src/transformers/unflatten.go | 4 +- go/src/transformers/uniq.go | 4 +- go/src/transformers/unsparsify.go | 2 +- .../transformers/utils/join-bucket-keeper.go | 8 +- go/src/types/mlrval_accessors.go | 2 +- go/todo.txt | 36 +- man6/Makefile | 4 +- man6/manpage.txt | 672 +++++----- man6/mkman.rb | 46 +- man6/mlr6.1 | 1102 ++++++++--------- 99 files changed, 1198 insertions(+), 1345 deletions(-) delete mode 100644 go/src/lib/exename.go create mode 100644 go/src/lib/paragraph.go diff --git a/docs6/mk-func-h2s.sh b/docs6/mk-func-h2s.sh index 705d2f31b..d7965d84f 100755 --- a/docs6/mk-func-h2s.sh +++ b/docs6/mk-func-h2s.sh @@ -3,7 +3,7 @@ # In case the user running this has a .mlrrc export MLRRC=__none__ -mlr -F | grep -v '^[a-zA-Z]' | uniq | while read funcname; do +mlr help list-functions | grep -v '^[a-zA-Z]' | uniq | while read funcname; do displayname=$funcname linkname="$funcname" if [ "$funcname" = '+' ]; then @@ -60,7 +60,7 @@ mlr -F | grep -v '^[a-zA-Z]' | uniq | while read funcname; do echo '' done -mlr -F | grep '^[a-zA-Z]' | sort -u | while read funcname; do +mlr help list-functions | grep '^[a-zA-Z]' | sort -u | while read funcname; do displayname=$funcname linkname="$funcname" if [ "$funcname" = '+' ]; then diff --git a/docs6/reference-dsl-builtin-functions.rst b/docs6/reference-dsl-builtin-functions.rst index 8fea83065..a585fea09 100644 --- a/docs6/reference-dsl-builtin-functions.rst +++ b/docs6/reference-dsl-builtin-functions.rst @@ -15,7 +15,7 @@ List of functions Each function takes a specific number of arguments, as shown below, except for functions marked as variadic such as ``min`` and ``max``. (The latter compute min and max of any number of numerical arguments.) There is no notion of optional or default-on-absent arguments. All argument-passing is positional rather than by name; arguments are passed by value, not by reference. -You can get a list of all functions using **mlr -F**. +You can get a list of all functions using **mlr -f**, with details using **mlr -F**. .. _reference-dsl-colon: diff --git a/docs6/reference-dsl-builtin-functions.rst.in b/docs6/reference-dsl-builtin-functions.rst.in index afad15f45..ab02aa78e 100644 --- a/docs6/reference-dsl-builtin-functions.rst.in +++ b/docs6/reference-dsl-builtin-functions.rst.in @@ -11,6 +11,6 @@ List of functions Each function takes a specific number of arguments, as shown below, except for functions marked as variadic such as ``min`` and ``max``. (The latter compute min and max of any number of numerical arguments.) There is no notion of optional or default-on-absent arguments. All argument-passing is positional rather than by name; arguments are passed by value, not by reference. -You can get a list of all functions using **mlr -F**. +You can get a list of all functions using **mlr -f**, with details using **mlr -F**. GENRST_RUN_CONTENT_GENERATOR(mk-func-h2s.sh) diff --git a/docs6/reference-dsl-variables.rst b/docs6/reference-dsl-variables.rst index ab39c6954..be5c8e36e 100644 --- a/docs6/reference-dsl-variables.rst +++ b/docs6/reference-dsl-variables.rst @@ -611,7 +611,7 @@ The following ``is...`` functions take a value and return a boolean indicating w .. code-block:: none :emphasize-lines: 1-1 - mlr -F | grep ^is + mlr -f | grep ^is is_absent is_array is_bool @@ -635,7 +635,7 @@ The following ``is...`` functions take a value and return a boolean indicating w .. code-block:: none :emphasize-lines: 1-1 - mlr -F | grep ^assert + mlr -f | grep ^assert asserting_absent asserting_array asserting_bool diff --git a/docs6/reference-dsl-variables.rst.in b/docs6/reference-dsl-variables.rst.in index 80eed81ee..5eeb88791 100644 --- a/docs6/reference-dsl-variables.rst.in +++ b/docs6/reference-dsl-variables.rst.in @@ -255,11 +255,11 @@ Type-test and type-assertion expressions The following ``is...`` functions take a value and return a boolean indicating whether the argument is of the indicated type. The ``assert_...`` functions return their argument if it is of the specified type, and cause a fatal error otherwise: GENRST_RUN_COMMAND -mlr -F | grep ^is +mlr -f | grep ^is GENRST_EOF GENRST_RUN_COMMAND -mlr -F | grep ^assert +mlr -f | grep ^assert GENRST_EOF Please see :ref:`cookbook-data-cleaning-examples` for examples of how to use these. diff --git a/docs6/reference-verbs.rst b/docs6/reference-verbs.rst index eaa1f07f5..d8c295f01 100644 --- a/docs6/reference-verbs.rst +++ b/docs6/reference-verbs.rst @@ -1819,8 +1819,8 @@ most-frequent square red 1874 triangle red 1560 circle red 1207 - square blue 589 square yellow 589 + square blue 589 .. code-block:: none :emphasize-lines: 1-1 @@ -1830,8 +1830,8 @@ most-frequent square red 1874 triangle red 1560 circle red 1207 - square yellow 589 square blue 589 + square yellow 589 .. code-block:: none :emphasize-lines: 1-1 @@ -1841,8 +1841,8 @@ most-frequent square red triangle red circle red - square yellow square blue + square yellow See also :ref:`reference-verbs-least-frequent`. diff --git a/go/build b/go/build index 69d9adedb..207d50c2b 100755 --- a/go/build +++ b/go/build @@ -22,10 +22,6 @@ go build mlr.go echo Compile OK echo -# During the C-to-Go port I like to have ../c/mlr and ./mlrgo and have symlinks -# to them from my ~/lbin. Hence the duplicate name here. -cp mlr mlrgo - echo ================================================================ echo UNIT TESTS go test -v miller/src/... diff --git a/go/regression_test.go b/go/regression_test.go index 48870c0c3..c8280e5f9 100644 --- a/go/regression_test.go +++ b/go/regression_test.go @@ -18,7 +18,7 @@ import ( func TestRegression(t *testing.T) { regtester := regtest.NewRegTester( - lib.MlrExeName(), + "mlr", false, // doPopulate 0, // verbosityLevel 0, // firstNFailsToShow diff --git a/go/src/auxents/help/entry.go b/go/src/auxents/help/entry.go index 9e29588b8..e6a3df8ef 100644 --- a/go/src/auxents/help/entry.go +++ b/go/src/auxents/help/entry.go @@ -1,5 +1,5 @@ // ================================================================ -// TODO: comment +// On-line help // ================================================================ package help @@ -8,6 +8,8 @@ import ( "fmt" "os" + "github.com/mattn/go-isatty" + "miller/src/cliutil" "miller/src/dsl/cst" "miller/src/lib" @@ -35,16 +37,15 @@ var shorthandLookupTable = []shorthandInfo{} var handlerLookupTable = []handlerInfo{} func init() { - // For things like 'mlr -F', invoked through the CLI parser which does not + // For things like 'mlr -f', invoked through the CLI parser which does not // go through our HelpMain(). shorthandLookupTable = []shorthandInfo{ - // TODO: remove handler func & replace with just short/long {shorthand: "-l", longhand: "list-verbs"}, - {shorthand: "-L", longhand: "list-verbs-vertically"}, - {shorthand: "-f", longhand: "usage-functions"}, - {shorthand: "-F", longhand: "list-functions"}, - {shorthand: "-k", longhand: "usage-keywords"}, - {shorthand: "-K", longhand: "list-keywords"}, + {shorthand: "-L", longhand: "usage-verbs"}, + {shorthand: "-f", longhand: "list-functions"}, + {shorthand: "-F", longhand: "usage-functions"}, + {shorthand: "-k", longhand: "list-keywords"}, + {shorthand: "-K", longhand: "usage-keywords"}, } // For things like 'mlr help foo', invoked through the auxent framework @@ -63,14 +64,15 @@ func init() { {name: "function", unaryHandlerFunc: helpForFunction}, {name: "keyword", unaryHandlerFunc: helpForKeyword}, {name: "list-functions", zaryHandlerFunc: listFunctions}, - {name: "list-functions-vertically", zaryHandlerFunc: listFunctionsVertically}, + {name: "list-functions-as-paragraph", zaryHandlerFunc: listFunctionsAsParagraph}, {name: "list-keywords", zaryHandlerFunc: listKeywords}, - {name: "list-verbs", zaryHandlerFunc: listVerbsAsParagraph}, - {name: "list-verbs-vertically", zaryHandlerFunc: listVerbsVertically}, + {name: "list-keywords-as-paragraph", zaryHandlerFunc: listKeywordsAsParagraph}, + {name: "list-verbs", zaryHandlerFunc: listVerbs}, + {name: "list-verbs-as-paragraph", zaryHandlerFunc: listVerbsAsParagraph}, {name: "misc", zaryHandlerFunc: helpMiscOptions}, {name: "mlrrc", zaryHandlerFunc: helpMlrrc}, {name: "number-formatting", zaryHandlerFunc: helpNumberFormatting}, - {name: "output-colorizations", zaryHandlerFunc: helpOutputColorization}, + {name: "output-colorization", zaryHandlerFunc: helpOutputColorization}, {name: "separator-options", zaryHandlerFunc: helpSeparatorOptions}, {name: "type-arithmetic-info", zaryHandlerFunc: helpTypeArithmeticInfo}, {name: "usage-functions", zaryHandlerFunc: usageFunctions}, @@ -80,13 +82,6 @@ func init() { } } -// TODO: keywords listed as paragraph -// TODO: search for function/keyword/verb/etc like in the REPL - -// TODO: -// function-list as paragraph (for manpage) -// type-arithmetic-info printTypeArithmeticInfo(os.Stdout, lib.MlrExeName()); - // ================================================================ // For things like 'mlr help foo', invoked through the auxent framework which // goes through our HelpMain(). Here, the args are the full Miller command @@ -125,8 +120,6 @@ func HelpMain(args []string) int { } } - // TODO: free-ranging keyword/function/verb/etc search as in mlr repl. - // "mlr help something" where we do not recognize the something listTopics() @@ -666,58 +659,61 @@ func helpTypeArithmeticInfo() { fmt.Println("TO BE PORTED") } -// ================================================================ -// TODO: port the paragraphifier +// ---------------------------------------------------------------- func listFunctions() { - cst.BuiltinFunctionManagerInstance.ListBuiltinFunctionNames(os.Stdout) + if isatty.IsTerminal(os.Stdout.Fd()) { + cst.BuiltinFunctionManagerInstance.ListBuiltinFunctionNamesAsParagraph(os.Stdout) + } else { + cst.BuiltinFunctionManagerInstance.ListBuiltinFunctionNames(os.Stdout) + } } -// ---------------------------------------------------------------- -func listFunctionsVertically() { - cst.BuiltinFunctionManagerInstance.ListBuiltinFunctionNames(os.Stdout) +func listFunctionsAsParagraph() { + cst.BuiltinFunctionManagerInstance.ListBuiltinFunctionNamesAsParagraph(os.Stdout) } -// ---------------------------------------------------------------- func usageFunctions() { cst.BuiltinFunctionManagerInstance.ListBuiltinFunctionUsages(os.Stdout) } -// ---------------------------------------------------------------- func helpForFunction(arg string) { cst.BuiltinFunctionManagerInstance.TryListBuiltinFunctionUsage(arg, os.Stdout) } -// ================================================================ +// ---------------------------------------------------------------- func listKeywords() { - cst.ListKeywords() + if isatty.IsTerminal(os.Stdout.Fd()) { + cst.ListKeywordsAsParagraph() + } else { + cst.ListKeywordsVertically() + } +} + +func listKeywordsAsParagraph() { + cst.ListKeywordsAsParagraph() } -// ---------------------------------------------------------------- func usageKeywords() { cst.UsageKeywords() } -// ---------------------------------------------------------------- func helpForKeyword(arg string) { cst.UsageForKeyword(arg) } -// ================================================================ +// ---------------------------------------------------------------- +func listVerbs() { + if isatty.IsTerminal(os.Stdout.Fd()) { + transformers.ListVerbNamesAsParagraph() + } else { + transformers.ListVerbNamesVertically() + } +} + func listVerbsAsParagraph() { transformers.ListVerbNamesAsParagraph() } -// ---------------------------------------------------------------- -func listVerbsVertically() { - transformers.ListVerbNamesVertically() -} - -// ---------------------------------------------------------------- -func listVerbNamesAsParagraph() { - transformers.ListVerbNamesAsParagraph() -} - -// ---------------------------------------------------------------- func helpForVerb(arg string) { transformerSetup := transformers.LookUp(arg) if transformerSetup != nil { @@ -729,7 +725,6 @@ func helpForVerb(arg string) { } } -// ---------------------------------------------------------------- func usageVerbs() { transformers.UsageVerbs() } diff --git a/go/src/auxents/hex.go b/go/src/auxents/hex.go index 07a571279..90838bfd0 100644 --- a/go/src/auxents/hex.go +++ b/go/src/auxents/hex.go @@ -64,7 +64,7 @@ func hexMain(args []string) int { istream, err := os.Open(filename) if err != nil { - // TODO: lib.MlrExeName() + // TODO: "mlr" fmt.Fprintln(os.Stderr, "mlr hex:", err) os.Exit(1) } diff --git a/go/src/auxents/lecat.go b/go/src/auxents/lecat.go index 54a009d78..496d0dff0 100644 --- a/go/src/auxents/lecat.go +++ b/go/src/auxents/lecat.go @@ -49,7 +49,7 @@ func lecatMain(args []string) int { istream, err := os.Open(filename) if err != nil { - // TODO: lib.MlrExeName() + // TODO: "mlr" fmt.Fprintln(os.Stderr, "mlr lecat:", err) os.Exit(1) } diff --git a/go/src/auxents/regtest/regtester.go b/go/src/auxents/regtest/regtester.go index 478dddc85..c34c6ef39 100644 --- a/go/src/auxents/regtest/regtester.go +++ b/go/src/auxents/regtest/regtester.go @@ -720,7 +720,7 @@ func (regtester *RegTester) loadEnvFile( return nil, errors.New( fmt.Sprintf( "%s: could not parse line \"%s\" from file \"%s\".\n", - lib.MlrExeName(), line, filename, + "mlr", line, filename, ), ) } @@ -759,7 +759,7 @@ func (regtester *RegTester) loadStringPairFile( return nil, errors.New( fmt.Sprintf( "%s: could not parse line \"%s\" from file \"%s\".\n", - lib.MlrExeName(), line, filename, + "mlr", line, filename, ), ) } diff --git a/go/src/auxents/repl/ast.go b/go/src/auxents/repl/ast.go index eba38fbf2..95dbc75d5 100644 --- a/go/src/auxents/repl/ast.go +++ b/go/src/auxents/repl/ast.go @@ -9,7 +9,6 @@ import ( "os" "miller/src/dsl" - "miller/src/lib" "miller/src/parsing/lexer" "miller/src/parsing/parser" ) @@ -24,7 +23,7 @@ func (repl *Repl) BuildASTFromStringWithMessage( // At present it's overly parser-internal, and confusing. :( // fmt.Fprintln(os.Stderr, err) fmt.Fprintf(os.Stderr, "%s: cannot parse DSL expression.\n", - lib.MlrExeName()) + "mlr") if repl.astPrintMode != ASTPrintNone { fmt.Fprintln(os.Stderr, dslString) } diff --git a/go/src/auxents/repl/verbs.go b/go/src/auxents/repl/verbs.go index d8669ae87..01e7708b4 100644 --- a/go/src/auxents/repl/verbs.go +++ b/go/src/auxents/repl/verbs.go @@ -856,8 +856,7 @@ func handleHelpSingle(repl *Repl, arg string) { } if arg == "function-names" { - // TODO: move to src/auxents/help - cst.BuiltinFunctionManagerInstance.ListBuiltinFunctionNames(os.Stdout) + cst.BuiltinFunctionManagerInstance.ListBuiltinFunctionNamesAsParagraph(os.Stdout) return } @@ -871,6 +870,10 @@ func handleHelpSingle(repl *Repl, arg string) { return } + if cst.TryUsageForKeyword(arg) { + return + } + if cst.BuiltinFunctionManagerInstance.TryListBuiltinFunctionUsage(arg, os.Stdout) { return } diff --git a/go/src/auxents/termcvt.go b/go/src/auxents/termcvt.go index d8c70e819..19af18e63 100644 --- a/go/src/auxents/termcvt.go +++ b/go/src/auxents/termcvt.go @@ -82,14 +82,14 @@ func termcvtMain(args []string) int { istream, err := os.Open(filename) if err != nil { - // TODO: lib.MlrExeName() + // TODO: "mlr" fmt.Fprintln(os.Stderr, "mlr termcvt:", err) os.Exit(1) } ostream, err := os.Open(tempname) if err != nil { - // TODO: lib.MlrExeName() + // TODO: "mlr" fmt.Fprintln(os.Stderr, "mlr termcvt:", err) os.Exit(1) } @@ -102,7 +102,7 @@ func termcvtMain(args []string) int { err = os.Rename(tempname, filename) if err != nil { - // TODO: lib.MlrExeName() + // TODO: "mlr" fmt.Fprintln(os.Stderr, "mlr termcvt:", err) os.Exit(1) } @@ -113,7 +113,7 @@ func termcvtMain(args []string) int { istream, err := os.Open(filename) if err != nil { - // TODO: lib.MlrExeName() + // TODO: "mlr" fmt.Fprintln(os.Stderr, "mlr termcvt:", err) os.Exit(1) } @@ -137,7 +137,7 @@ func termcvtFile(istream *os.File, ostream *os.File, inTerm string, outTerm stri } if err != nil { - // TODO: lib.MlrExeName() + // TODO: "mlr" fmt.Fprintln(os.Stderr, "mlr termcvt:", err) os.Exit(1) } diff --git a/go/src/cli/mlrcli_mlrrc.go b/go/src/cli/mlrcli_mlrrc.go index 08cf864cd..2d4269294 100644 --- a/go/src/cli/mlrcli_mlrrc.go +++ b/go/src/cli/mlrcli_mlrrc.go @@ -9,7 +9,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" ) // ---------------------------------------------------------------- @@ -66,7 +65,7 @@ func tryLoadMlrrc( lineno++ if err != nil { - fmt.Fprintln(os.Stderr, lib.MlrExeName(), err) + fmt.Fprintln(os.Stderr, "mlr", err) os.Exit(1) return false } @@ -77,7 +76,7 @@ func tryLoadMlrrc( if !handleMlrrcLine(options, line) { fmt.Fprintf(os.Stderr, "%s: parse error at file \"%s\" line %d: %s\n", - lib.MlrExeName(), path, lineno, line, + "mlr", path, lineno, line, ) os.Exit(1) } diff --git a/go/src/cli/mlrcli_parse.go b/go/src/cli/mlrcli_parse.go index 085539e82..db46a70a0 100644 --- a/go/src/cli/mlrcli_parse.go +++ b/go/src/cli/mlrcli_parse.go @@ -59,8 +59,8 @@ func ParseCommandLine(args []string) ( // handled } else { // unhandled - fmt.Fprintf(os.Stderr, "%s: option \"%s\" not recognized.\n", lib.MlrExeName(), args[argi]) - fmt.Fprintf(os.Stderr, "Please run \"%s --help\" for usage information.\n", lib.MlrExeName()) + fmt.Fprintf(os.Stderr, "%s: option \"%s\" not recognized.\n", "mlr", args[argi]) + fmt.Fprintf(os.Stderr, "Please run \"%s --help\" for usage information.\n", "mlr") os.Exit(1) } } @@ -114,7 +114,7 @@ func ParseCommandLine(args []string) ( } if options.DoInPlace && (options.FileNames == nil || len(options.FileNames) == 0) { - fmt.Fprintf(os.Stderr, "%s: -I option (in-place operation) requires input files.\n", lib.MlrExeName()) + fmt.Fprintf(os.Stderr, "%s: -I option (in-place operation) requires input files.\n", "mlr") os.Exit(1) } @@ -152,7 +152,7 @@ func parseTransformers( } if (argc - argi) < 1 { - fmt.Fprintf(os.Stderr, "%s: no verb supplied.\n", lib.MlrExeName()) + fmt.Fprintf(os.Stderr, "%s: no verb supplied.\n", "mlr") help.MainUsage(os.Stderr) os.Exit(1) } @@ -167,7 +167,7 @@ func parseTransformers( if transformerSetup == nil { fmt.Fprintf(os.Stderr, "%s: verb \"%s\" not found. Please use \"%s --help\" for a list.\n", - lib.MlrExeName(), verb, lib.MlrExeName()) + "mlr", verb, "mlr") os.Exit(1) } @@ -200,7 +200,7 @@ func parseTransformers( break } else { if argi == argc-1 { - fmt.Fprintf(os.Stderr, "%s: missing next verb after \"then\".\n", lib.MlrExeName()) + fmt.Fprintf(os.Stderr, "%s: missing next verb after \"then\".\n", "mlr") os.Exit(1) } else { argi++ diff --git a/go/src/cliutil/mlrcli_util.go b/go/src/cliutil/mlrcli_util.go index fe1839b0a..4e126eb3c 100644 --- a/go/src/cliutil/mlrcli_util.go +++ b/go/src/cliutil/mlrcli_util.go @@ -3,16 +3,14 @@ package cliutil import ( "fmt" "os" - - "miller/src/lib" ) // For flags with values, e.g. ["-n" "10"], while we're looking at the "-n" // this let us see if the "10" slot exists. func CheckArgCount(args []string, argi int, argc int, n int) { if (argc - argi) < n { - fmt.Fprintf(os.Stderr, "%s: option \"%s\" missing argument(s).\n", lib.MlrExeName(), args[argi]) - fmt.Fprintf(os.Stderr, "Please run \"%s --help\" for detailed usage information.\n", lib.MlrExeName()) + fmt.Fprintf(os.Stderr, "%s: option \"%s\" missing argument(s).\n", "mlr", args[argi]) + fmt.Fprintf(os.Stderr, "Please run \"%s --help\" for detailed usage information.\n", "mlr") os.Exit(1) } } diff --git a/go/src/cliutil/option_parse.go b/go/src/cliutil/option_parse.go index 55d5fd77e..fe0e62857 100644 --- a/go/src/cliutil/option_parse.go +++ b/go/src/cliutil/option_parse.go @@ -97,7 +97,7 @@ func ParseReaderOptions( // CheckArgCount(args, argi, argc, 2); // if (sscanf(args[argi+1], "%lld", &readerOptions.generator_opts.start) != 1) { // fmt.Fprintf(os.Stderr, "%s: could not scan \"%s\".\n", - // lib.MlrExeName(), args[argi+1]); + // "mlr", args[argi+1]); // } // argi += 2; // } else if args[argi] == "--gen-stop" { @@ -105,7 +105,7 @@ func ParseReaderOptions( // CheckArgCount(args, argi, argc, 2); // if (sscanf(args[argi+1], "%lld", &readerOptions.generator_opts.stop) != 1) { // fmt.Fprintf(os.Stderr, "%s: could not scan \"%s\".\n", - // lib.MlrExeName(), args[argi+1]); + // "mlr", args[argi+1]); // } // argi += 2; // } else if args[argi] == "--gen-step" { @@ -113,7 +113,7 @@ func ParseReaderOptions( // CheckArgCount(args, argi, argc, 2); // if (sscanf(args[argi+1], "%lld", &readerOptions.generator_opts.step) != 1) { // fmt.Fprintf(os.Stderr, "%s: could not scan \"%s\".\n", - // lib.MlrExeName(), args[argi+1]); + // "mlr", args[argi+1]); // } // argi += 2; @@ -487,7 +487,7 @@ func ParseWriterOptions( if !ok { fmt.Fprintf(os.Stderr, "%s: --key-color argument must be a decimal integer; got \"%s\".\n", - lib.MlrExeName(), args[argi+1]) + "mlr", args[argi+1]) os.Exit(1) } colorizer.SetKeyColor(code) @@ -500,7 +500,7 @@ func ParseWriterOptions( if !ok { fmt.Fprintf(os.Stderr, "%s: --value-color argument must be a decimal integer; got \"%s\".\n", - lib.MlrExeName(), args[argi+1]) + "mlr", args[argi+1]) os.Exit(1) } colorizer.SetValueColor(code) @@ -513,7 +513,7 @@ func ParseWriterOptions( if !ok { fmt.Fprintf(os.Stderr, "%s: --pass-color argument must be a decimal integer; got \"%s\".\n", - lib.MlrExeName(), args[argi+1]) + "mlr", args[argi+1]) os.Exit(1) } colorizer.SetPassColor(code) @@ -526,7 +526,7 @@ func ParseWriterOptions( if !ok { fmt.Fprintf(os.Stderr, "%s: --fail-color argument must be a decimal integer; got \"%s\".\n", - lib.MlrExeName(), args[argi+1]) + "mlr", args[argi+1]) os.Exit(1) } colorizer.SetFailColor(code) @@ -539,7 +539,7 @@ func ParseWriterOptions( if !ok { fmt.Fprintf(os.Stderr, "%s: --help-color argument must be a decimal integer; got \"%s\".\n", - lib.MlrExeName(), args[argi+1]) + "mlr", args[argi+1]) os.Exit(1) } colorizer.SetHelpColor(code) @@ -600,7 +600,7 @@ func ParseReaderWriterOptions( CheckArgCount(args, argi, argc, 2) if defaultFSes[args[argi+1]] == "" { fmt.Fprintf(os.Stderr, "%s: unrecognized I/O format \"%s\".\n", - lib.MlrExeName(), args[argi+1]) + "mlr", args[argi+1]) os.Exit(1) } readerOptions.InputFileFormat = args[argi+1] @@ -1132,14 +1132,14 @@ func ParseMiscOptions( // if (sscanf(args[argi+1], "%lld", &options.nr_progress_mod) != 1) { // fmt.Fprintf(os.Stderr, // "%s: --nr-progress-mod argument must be a positive integer; got \"%s\".\n", - // lib.MlrExeName(), args[argi+1]); + // "mlr", args[argi+1]); // mainUsageShort() // os.Exit(1); // } // if (options.nr_progress_mod <= 0) { // fmt.Fprintf(os.Stderr, // "%s: --nr-progress-mod argument must be a positive integer; got \"%s\".\n", - // lib.MlrExeName(), args[argi+1]); + // "mlr", args[argi+1]); // mainUsageShort() // os.Exit(1); // } @@ -1154,8 +1154,8 @@ func ParseMiscOptions( } else { fmt.Fprintf(os.Stderr, "%s: --seed argument must be a decimal or hexadecimal integer; got \"%s\".\n", - lib.MlrExeName(), args[argi+1]) - fmt.Fprintf(os.Stderr, "Please run \"%s --help\" for detailed usage information.\n", lib.MlrExeName()) + "mlr", args[argi+1]) + fmt.Fprintf(os.Stderr, "Please run \"%s --help\" for detailed usage information.\n", "mlr") os.Exit(1) } argi += 2 diff --git a/go/src/cliutil/verb_utils.go b/go/src/cliutil/verb_utils.go index cedf083ad..d96790281 100644 --- a/go/src/cliutil/verb_utils.go +++ b/go/src/cliutil/verb_utils.go @@ -18,7 +18,7 @@ import ( func verbCheckArgCount(verb string, opt string, args []string, argi int, argc int, n int) { if (argc - argi) < n { fmt.Fprintf(os.Stderr, "%s %s: option \"%s\" missing argument(s).\n", - lib.MlrExeName(), verb, opt, + "mlr", verb, opt, ) os.Exit(1) } @@ -48,7 +48,7 @@ func VerbGetIntArgOrDie(verb string, opt string, args []string, pargi *int, argc if err != nil { fmt.Fprintf(os.Stderr, "%s %s: could not scan flag \"%s\" argument \"%s\" as int.\n", - lib.MlrExeName(), verb, flag, stringArg, + "mlr", verb, flag, stringArg, ) os.Exit(1) } @@ -64,7 +64,7 @@ func VerbGetFloatArgOrDie(verb string, opt string, args []string, pargi *int, ar if err != nil { fmt.Fprintf(os.Stderr, "%s %s: could not scan flag \"%s\" argument \"%s\" as float.\n", - lib.MlrExeName(), verb, flag, stringArg, + "mlr", verb, flag, stringArg, ) os.Exit(1) } diff --git a/go/src/dsl/cst/builtin_function_manager.go b/go/src/dsl/cst/builtin_function_manager.go index dcc4c9496..2be9980f5 100644 --- a/go/src/dsl/cst/builtin_function_manager.go +++ b/go/src/dsl/cst/builtin_function_manager.go @@ -55,22 +55,49 @@ type BuiltinFunctionInfo struct { func init() { // Go sort API: for ascending sort, return true if element i < element j. sort.Slice(_BUILTIN_FUNCTION_LOOKUP_TABLE, func(i, j int) bool { - //if _BUILTIN_FUNCTION_LOOKUP_TABLE[i].class < _BUILTIN_FUNCTION_LOOKUP_TABLE[j].class { - //return true - //} - //if _BUILTIN_FUNCTION_LOOKUP_TABLE[i].class > _BUILTIN_FUNCTION_LOOKUP_TABLE[j].class { - //return false - //} - if _BUILTIN_FUNCTION_LOOKUP_TABLE[i].name < _BUILTIN_FUNCTION_LOOKUP_TABLE[j].name { + namei := _BUILTIN_FUNCTION_LOOKUP_TABLE[i].name + namej := _BUILTIN_FUNCTION_LOOKUP_TABLE[j].name + + si := startsWithLetter(namei) + sj := startsWithLetter(namej) + + if si && !sj { return true - } - if _BUILTIN_FUNCTION_LOOKUP_TABLE[i].name > _BUILTIN_FUNCTION_LOOKUP_TABLE[j].name { + } else if !si && sj { return false + } else { + + // classi := _BUILTIN_FUNCTION_LOOKUP_TABLE[i].class + // classj := _BUILTIN_FUNCTION_LOOKUP_TABLE[j].class + //if classi < classj { + // return true + //} + //if classi > classj { + // return false + //} + + if namei < namej { + return true + } else { + return false + } } - return false }) } +// TODO: move +func isLetter(c byte) bool { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') +} + +func startsWithLetter(s string) bool { + if len(s) < 1 { + return false + } else { + return isLetter(s[0]) + } +} + var _BUILTIN_FUNCTION_LOOKUP_TABLE = []BuiltinFunctionInfo{ // ---------------------------------------------------------------- @@ -1582,6 +1609,15 @@ func (manager *BuiltinFunctionManager) ListBuiltinFunctionNames(o *os.File) { } } +// ---------------------------------------------------------------- +func (manager *BuiltinFunctionManager) ListBuiltinFunctionNamesAsParagraph(o *os.File) { + functionNames := make([]string, len(*manager.lookupTable)) + for i, builtinFunctionInfo := range *manager.lookupTable { + functionNames[i] = builtinFunctionInfo.name + } + lib.PrintWordsAsParagraph(functionNames, o) +} + // ---------------------------------------------------------------- func (manager *BuiltinFunctionManager) ListBuiltinFunctionUsages(o *os.File) { manager.ListBuiltinFunctionUsagesDecorated( diff --git a/go/src/dsl/cst/dump.go b/go/src/dsl/cst/dump.go index 25320b4b1..f771ecbd5 100644 --- a/go/src/dsl/cst/dump.go +++ b/go/src/dsl/cst/dump.go @@ -141,7 +141,7 @@ func (root *RootNode) buildDumpxStatementNode( return nil, errors.New( fmt.Sprintf( "%s: unhandled redirector node type %s.", - lib.MlrExeName(), string(redirectorNode.Type), + "mlr", string(redirectorNode.Type), ), ) } @@ -219,7 +219,7 @@ func (node *DumpStatementNode) dumpToFileOrPipe( return errors.New( fmt.Sprintf( "%s: output redirection yielded %s, not string.", - lib.MlrExeName(), redirectorTarget.GetTypeName(), + "mlr", redirectorTarget.GetTypeName(), ), ) } diff --git a/go/src/dsl/cst/emit_emitp.go b/go/src/dsl/cst/emit_emitp.go index 2d9f01218..ce7afcbd3 100644 --- a/go/src/dsl/cst/emit_emitp.go +++ b/go/src/dsl/cst/emit_emitp.go @@ -198,7 +198,7 @@ func (root *RootNode) buildEmitXStatementNode( return nil, errors.New( fmt.Sprintf( "%s: unhandled redirector node type %s.", - lib.MlrExeName(), string(redirectorNode.Type), + "mlr", string(redirectorNode.Type), ), ) } @@ -427,7 +427,7 @@ func (node *EmitXStatementNode) emitToFileOrPipe( return errors.New( fmt.Sprintf( "%s: output redirection yielded %s, not string.", - lib.MlrExeName(), redirectorTarget.GetTypeName(), + "mlr", redirectorTarget.GetTypeName(), ), ) } diff --git a/go/src/dsl/cst/emitf.go b/go/src/dsl/cst/emitf.go index fd62a92c5..1b443df47 100644 --- a/go/src/dsl/cst/emitf.go +++ b/go/src/dsl/cst/emitf.go @@ -122,7 +122,7 @@ func (root *RootNode) BuildEmitFStatementNode(astNode *dsl.ASTNode) (IExecutable return nil, errors.New( fmt.Sprintf( "%s: unhandled redirector node type %s.", - lib.MlrExeName(), string(redirectorNode.Type), + "mlr", string(redirectorNode.Type), ), ) } @@ -171,7 +171,7 @@ func getNameFromNamedNode(astNode *dsl.ASTNode, description string) (string, err return "", errors.New( fmt.Sprintf( "%s: can't get name of node type \"%s\" for %s.", - lib.MlrExeName(), string(astNode.Type), description, + "mlr", string(astNode.Type), description, ), ) } @@ -200,7 +200,7 @@ func (node *EmitFStatementNode) emitfToFileOrPipe( return errors.New( fmt.Sprintf( "%s: output redirection yielded %s, not string.", - lib.MlrExeName(), redirectorTarget.GetTypeName(), + "mlr", redirectorTarget.GetTypeName(), ), ) } diff --git a/go/src/dsl/cst/keyword_usage.go b/go/src/dsl/cst/keyword_usage.go index 33ebf6b3b..9e4b97344 100644 --- a/go/src/dsl/cst/keyword_usage.go +++ b/go/src/dsl/cst/keyword_usage.go @@ -2,6 +2,7 @@ package cst import ( "fmt" + "os" "miller/src/lib" ) @@ -82,26 +83,37 @@ func UsageKeywords() { } func UsageForKeyword(name string) { - found := false - for _, entry := range KEYWORD_USAGE_TABLE { - if entry.name == name { - entry.usageFunc() - found = true - break - } - } - if !found { + if !TryUsageForKeyword(name) { fmt.Printf("mlr: unrecognized keyword \"%s\".\n", name) } } +func TryUsageForKeyword(name string) bool { + for _, entry := range KEYWORD_USAGE_TABLE { + if entry.name == name { + entry.usageFunc() + return true + } + } + return false +} + // ---------------------------------------------------------------- -func ListKeywords() { +func ListKeywordsVertically() { for _, entry := range KEYWORD_USAGE_TABLE { fmt.Println(entry.name) } } +// ---------------------------------------------------------------- +func ListKeywordsAsParagraph() { + keywords := make([]string, len(KEYWORD_USAGE_TABLE)) + for i, entry := range KEYWORD_USAGE_TABLE { + keywords[i] = entry.name + } + lib.PrintWordsAsParagraph(keywords, os.Stdout) +} + // ---------------------------------------------------------------- func allKeywordUsage() { fmt.Println( diff --git a/go/src/dsl/cst/print.go b/go/src/dsl/cst/print.go index 311713d73..6f1938b0d 100644 --- a/go/src/dsl/cst/print.go +++ b/go/src/dsl/cst/print.go @@ -284,7 +284,7 @@ func (root *RootNode) buildPrintxStatementNode( return nil, errors.New( fmt.Sprintf( "%s: unhandled redirector node type %s.", - lib.MlrExeName(), string(redirectorNode.Type), + "mlr", string(redirectorNode.Type), ), ) } @@ -365,7 +365,7 @@ func (node *PrintStatementNode) printToFileOrPipe( return errors.New( fmt.Sprintf( "%s: output redirection yielded %s, not string.", - lib.MlrExeName(), redirectorTarget.GetTypeName(), + "mlr", redirectorTarget.GetTypeName(), ), ) } diff --git a/go/src/dsl/cst/root.go b/go/src/dsl/cst/root.go index 0c21ba087..52e5c632d 100644 --- a/go/src/dsl/cst/root.go +++ b/go/src/dsl/cst/root.go @@ -13,7 +13,6 @@ import ( "miller/src/cliutil" "miller/src/dsl" - "miller/src/lib" "miller/src/output" "miller/src/runtime" "miller/src/types" @@ -81,7 +80,7 @@ func (root *RootNode) IngestAST( if warningsAreFatal { fmt.Printf( "%s: Exiting due to warnings treated as fatal.\n", - lib.MlrExeName(), + "mlr", ) os.Exit(1) } @@ -281,7 +280,7 @@ func (root *RootNode) ProcessEndOfStream() { fmt.Fprintf( os.Stderr, "%s: error on end-of-stream close: %v\n", - lib.MlrExeName(), + "mlr", err, ) } diff --git a/go/src/dsl/cst/tee.go b/go/src/dsl/cst/tee.go index 76ff268d3..82e9faf72 100644 --- a/go/src/dsl/cst/tee.go +++ b/go/src/dsl/cst/tee.go @@ -124,7 +124,7 @@ func (root *RootNode) BuildTeeStatementNode(astNode *dsl.ASTNode) (IExecutable, return nil, errors.New( fmt.Sprintf( "%s: unhandled redirector node type %s.", - lib.MlrExeName(), string(redirectorNode.Type), + "mlr", string(redirectorNode.Type), ), ) } @@ -146,7 +146,7 @@ func (node *TeeStatementNode) Execute(state *runtime.State) (*BlockExitPayload, return nil, errors.New( fmt.Sprintf( "%s: tee-evaluaiton yielded %s, not map.", - lib.MlrExeName(), expression.GetTypeName(), + "mlr", expression.GetTypeName(), ), ) } @@ -164,7 +164,7 @@ func (node *TeeStatementNode) teeToFileOrPipe( return errors.New( fmt.Sprintf( "%s: output redirection yielded %s, not string.", - lib.MlrExeName(), redirectorTarget.GetTypeName(), + "mlr", redirectorTarget.GetTypeName(), ), ) } diff --git a/go/src/dsl/cst/validate.go b/go/src/dsl/cst/validate.go index 15750b927..1a310f3f6 100644 --- a/go/src/dsl/cst/validate.go +++ b/go/src/dsl/cst/validate.go @@ -276,7 +276,7 @@ func validateForLoopTwoVariableUniqueNames(astNode *dsl.ASTNode) error { return errors.New( fmt.Sprintf( "%s: redefinition of variable %s in the same scope.", - lib.MlrExeName(), + "mlr", keyVarName, ), ) @@ -312,7 +312,7 @@ func validateForLoopMultivariableUniqueNames(astNode *dsl.ASTNode) error { return errors.New( fmt.Sprintf( "%s: redefinition of variable %s in the same scope.", - lib.MlrExeName(), + "mlr", name, ), ) @@ -325,7 +325,7 @@ func validateForLoopMultivariableUniqueNames(astNode *dsl.ASTNode) error { return errors.New( fmt.Sprintf( "%s: redefinition of variable %s in the same scope.", - lib.MlrExeName(), + "mlr", valVarName, ), ) diff --git a/go/src/entrypoint/entrypoint.go b/go/src/entrypoint/entrypoint.go index b1e0355fe..1e5116eca 100644 --- a/go/src/entrypoint/entrypoint.go +++ b/go/src/entrypoint/entrypoint.go @@ -101,7 +101,7 @@ func processInPlace( for _, fileName := range fileNames { if _, err := os.Stat(fileName); os.IsNotExist(err) { - fmt.Fprintf(os.Stderr, "%s: %v\n", lib.MlrExeName(), err) + fmt.Fprintf(os.Stderr, "%s: %v\n", "mlr", err) os.Exit(1) } @@ -115,7 +115,7 @@ func processInPlace( // as revealed by printing handle.Name(). handle, err := os.CreateTemp(containingDirectory, "mlr-in-place-") if err != nil { - fmt.Fprintf(os.Stderr, "%s: %v\n", lib.MlrExeName(), err) + fmt.Fprintf(os.Stderr, "%s: %v\n", "mlr", err) os.Exit(1) } tempFileName := handle.Name() @@ -134,13 +134,13 @@ func processInPlace( err = handle.Close() if err != nil { - fmt.Fprintf(os.Stderr, "%s: %v\n", lib.MlrExeName(), err) + fmt.Fprintf(os.Stderr, "%s: %v\n", "mlr", err) os.Exit(1) } err = os.Rename(tempFileName, fileName) if err != nil { - fmt.Fprintf(os.Stderr, "%s: %v\n", lib.MlrExeName(), err) + fmt.Fprintf(os.Stderr, "%s: %v\n", "mlr", err) os.Exit(1) } } diff --git a/go/src/lib/exename.go b/go/src/lib/exename.go deleted file mode 100644 index 457a0abb0..000000000 --- a/go/src/lib/exename.go +++ /dev/null @@ -1,12 +0,0 @@ -package lib - -func MlrExeName() string { - // TODO: - // This is ideal, so if someone has a 'mlr.debug' or somesuch, the messages will reflect that: - - // return path.Base(os.Args[0]) - - // ... however it makes automated regression-testing hard, cross-platform. For example, - // 'mlr' vs 'C:\something\something\mlr.exe'. - return "mlr" -} diff --git a/go/src/lib/halfpipe.go b/go/src/lib/halfpipe.go index a7d01a073..bb93c6c01 100644 --- a/go/src/lib/halfpipe.go +++ b/go/src/lib/halfpipe.go @@ -79,7 +79,7 @@ func OpenInboundHalfPipe(commandString string) (*os.File, error) { go func(process *os.Process, readPipe *os.File) { _, err := process.Wait() if err != nil { - fmt.Fprintf(os.Stderr, "%s: %v\n", MlrExeName(), err) + fmt.Fprintf(os.Stderr, "%s: %v\n", "mlr", err) } readPipe.Close() }(process, readPipe) @@ -90,7 +90,7 @@ func OpenInboundHalfPipe(commandString string) (*os.File, error) { func waitAndClose(process *os.Process, readPipe *os.File) { _, err := process.Wait() if err != nil { - fmt.Fprintf(os.Stderr, "%s: %v\n", MlrExeName(), err) + fmt.Fprintf(os.Stderr, "%s: %v\n", "mlr", err) } readPipe.Close() } diff --git a/go/src/lib/mlrmath.go b/go/src/lib/mlrmath.go index 7aea5d435..2ceb9d1ac 100644 --- a/go/src/lib/mlrmath.go +++ b/go/src/lib/mlrmath.go @@ -176,7 +176,7 @@ func GetRealSymmetricEigensystem( if !found { fmt.Fprintf(os.Stderr, "%s: Jacobi eigensolver: max iterations (%d) exceeded. Non-symmetric input?\n", - MlrExeName(), + "mlr", JACOBI_MAXITER, ) os.Exit(1) diff --git a/go/src/lib/paragraph.go b/go/src/lib/paragraph.go new file mode 100644 index 000000000..122526cd6 --- /dev/null +++ b/go/src/lib/paragraph.go @@ -0,0 +1,34 @@ +package lib + +import ( + "fmt" + "os" +) + +// For on-line help contexts like printing all the built-in DSL functions, or +// the list of all verbs. +func PrintWordsAsParagraph(words []string, o *os.File) { + separator := " " + maxlen := 80 + + separatorlen := len(separator) + linelen := 0 + j := 0 + + for _, word := range words { + wordlen := len(word) + linelen += separatorlen + wordlen + if linelen >= maxlen { + fmt.Fprintf(o, "\n") + linelen = separatorlen + wordlen + j = 0 + } + if j > 0 { + fmt.Fprint(o, separator) + } + fmt.Fprint(o, word) + j++ + } + + fmt.Printf("\n") +} diff --git a/go/src/output/file-output-handlers.go b/go/src/output/file-output-handlers.go index 12b7f9da5..cc69ea21a 100644 --- a/go/src/output/file-output-handlers.go +++ b/go/src/output/file-output-handlers.go @@ -282,7 +282,7 @@ func NewPipeWriteOutputHandler( return nil, errors.New( fmt.Sprintf( "%s: could not launch command \"%s\" for pipe-to.", - lib.MlrExeName(), + "mlr", commandString, ), ) diff --git a/go/src/runtime/stack.go b/go/src/runtime/stack.go index 1e2e5288b..1dc85edbd 100644 --- a/go/src/runtime/stack.go +++ b/go/src/runtime/stack.go @@ -453,7 +453,7 @@ func (frame *StackFrame) defineTyped( return errors.New( fmt.Sprintf( "%s: variable %s has already been defined in the same scope.", - lib.MlrExeName(), stackVariable.name, + "mlr", stackVariable.name, ), ) } @@ -477,7 +477,7 @@ func (frame *StackFrame) setIndexed( return errors.New( fmt.Sprintf( "%s: map indices must be int or string; got %s.\n", - lib.MlrExeName(), leadingIndex.GetTypeName(), + "mlr", leadingIndex.GetTypeName(), ), ) } diff --git a/go/src/stream/stream.go b/go/src/stream/stream.go index 96b685ba8..a0ea9b720 100644 --- a/go/src/stream/stream.go +++ b/go/src/stream/stream.go @@ -7,7 +7,6 @@ import ( "miller/src/cliutil" "miller/src/input" - "miller/src/lib" "miller/src/output" "miller/src/transformers" "miller/src/types" @@ -75,7 +74,7 @@ func Stream( for !done { select { case err := <-errorChannel: - fmt.Fprintln(os.Stderr, lib.MlrExeName(), ": ", err) + fmt.Fprintln(os.Stderr, "mlr", ": ", err) os.Exit(1) case _ = <-doneChannel: done = true diff --git a/go/src/transformers/aaa_transformer_table.go b/go/src/transformers/aaa_transformer_table.go index c5e46f389..5b946ebb8 100644 --- a/go/src/transformers/aaa_transformer_table.go +++ b/go/src/transformers/aaa_transformer_table.go @@ -88,29 +88,13 @@ func ListVerbNamesVertically() { // ---------------------------------------------------------------- func ListVerbNamesAsParagraph() { - separator := " " + verbNames := make([]string, len(TRANSFORMER_LOOKUP_TABLE)) - separatorlen := len(separator) - linelen := 0 - j := 0 - - for _, transformerSetup := range TRANSFORMER_LOOKUP_TABLE { - verb := transformerSetup.Verb - verblen := len(verb) - linelen += separatorlen + verblen - if linelen >= 80 { - fmt.Printf("\n") - linelen = separatorlen + verblen - j = 0 - } - if j > 0 { - fmt.Print(separator) - } - fmt.Print(verb) - j++ + for i, transformerSetup := range TRANSFORMER_LOOKUP_TABLE { + verbNames[i] = transformerSetup.Verb } - fmt.Printf("\n") + lib.PrintWordsAsParagraph(verbNames, os.Stdout) } // ---------------------------------------------------------------- diff --git a/go/src/transformers/altkv.go b/go/src/transformers/altkv.go index 0cad389d3..ccaf14628 100644 --- a/go/src/transformers/altkv.go +++ b/go/src/transformers/altkv.go @@ -7,7 +7,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -26,7 +25,7 @@ func transformerAltkvUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameAltkv) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameAltkv) fmt.Fprintf(o, "Given fields with values of the form a,b,c,d,e,f emits a=b,c=d,e=f pairs.\n") fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, "-h|--help Show this message.\n") diff --git a/go/src/transformers/bar.go b/go/src/transformers/bar.go index 65a19725c..5608dab2a 100644 --- a/go/src/transformers/bar.go +++ b/go/src/transformers/bar.go @@ -8,7 +8,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -34,7 +33,7 @@ func transformerBarUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameBar) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameBar) fmt.Fprintf(o, "Replaces a numeric field with a number of asterisks, allowing for cheesy\n") fmt.Fprintf(o, "bar plots. These align best with --opprint or --oxtab output format.\n") fmt.Fprintf(o, "Options:\n") diff --git a/go/src/transformers/bootstrap.go b/go/src/transformers/bootstrap.go index 68ea2da71..f40482160 100644 --- a/go/src/transformers/bootstrap.go +++ b/go/src/transformers/bootstrap.go @@ -26,11 +26,11 @@ func transformerBootstrapUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameBootstrap) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameBootstrap) fmt.Fprintf(o, `Emits an n-sample, with replacement, of the input records. See also %s sample and %s shuffle. -`, lib.MlrExeName(), lib.MlrExeName()) +`, "mlr", "mlr") fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, ` -n Number of samples to output. Defaults to number of input records. diff --git a/go/src/transformers/cat.go b/go/src/transformers/cat.go index c5d783d8d..43b5c7460 100644 --- a/go/src/transformers/cat.go +++ b/go/src/transformers/cat.go @@ -6,7 +6,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -25,7 +24,7 @@ func transformerCatUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameCat) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameCat) fmt.Fprintf(o, "Passes input records directly to output. Most useful for format conversion.\n") fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, "-n Prepend field \"n\" to each record with record-counter starting at 1.\n") diff --git a/go/src/transformers/check.go b/go/src/transformers/check.go index f5faaed34..760ced628 100644 --- a/go/src/transformers/check.go +++ b/go/src/transformers/check.go @@ -6,7 +6,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -25,7 +24,7 @@ func transformerCheckUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameCheck) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameCheck) fmt.Fprintf(o, "Consumes records without printing any output.\n") fmt.Fprintf(o, "Useful for doing a well-formatted check on input data.\n") fmt.Fprintf(o, "Options:\n") diff --git a/go/src/transformers/clean-whitespace.go b/go/src/transformers/clean-whitespace.go index fbc0fa647..a625c6190 100644 --- a/go/src/transformers/clean-whitespace.go +++ b/go/src/transformers/clean-whitespace.go @@ -6,7 +6,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -25,7 +24,7 @@ func transformerCleanWhitespaceUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameCleanWhitespace) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameCleanWhitespace) fmt.Fprintf(o, "For each record, for each field in the record, whitespace-cleans the keys and/or\n") fmt.Fprintf(o, "values. Whitespace-cleaning entails stripping leading and trailing whitespace,\n") fmt.Fprintf(o, "and replacing multiple whitespace with singles. For finer-grained control,\n") diff --git a/go/src/transformers/count-similar.go b/go/src/transformers/count-similar.go index 74582adab..f9ec60fbd 100644 --- a/go/src/transformers/count-similar.go +++ b/go/src/transformers/count-similar.go @@ -26,7 +26,7 @@ func transformerCountSimilarUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameCountSimilar) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameCountSimilar) fmt.Fprintf(o, "Ingests all records, then emits each record augmented by a count of\n") fmt.Fprintf(o, "the number of other records having the same group-by field values.\n") fmt.Fprintf(o, "Options:\n") diff --git a/go/src/transformers/count.go b/go/src/transformers/count.go index ffd791132..085c7ce4c 100644 --- a/go/src/transformers/count.go +++ b/go/src/transformers/count.go @@ -25,7 +25,7 @@ func transformerCountUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameCount) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameCount) fmt.Fprint(o, `Prints number of records, optionally grouped by distinct values for specified field names. `) diff --git a/go/src/transformers/cut.go b/go/src/transformers/cut.go index 3068d9617..cbaf72b62 100644 --- a/go/src/transformers/cut.go +++ b/go/src/transformers/cut.go @@ -26,7 +26,7 @@ func transformerCutUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameCut) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameCut) fmt.Fprintf(o, "Passes through input records with specified fields included/excluded.\n") fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, " -f {a,b,c} Comma-separated field names for cut, e.g. a,b,c.\n") @@ -39,11 +39,11 @@ func transformerCutUsage( fmt.Fprintf(o, " be used. The -o flag is ignored when -r is present.\n") fmt.Fprintf(o, "-h|--help Show this message.\n") fmt.Fprintf(o, "Examples:\n") - fmt.Fprintf(o, " %s %s -f hostname,status\n", lib.MlrExeName(), verbNameCut) - fmt.Fprintf(o, " %s %s -x -f hostname,status\n", lib.MlrExeName(), verbNameCut) - fmt.Fprintf(o, " %s %s -r -f '^status$,sda[0-9]'\n", lib.MlrExeName(), verbNameCut) - fmt.Fprintf(o, " %s %s -r -f '^status$,\"sda[0-9]\"'\n", lib.MlrExeName(), verbNameCut) - fmt.Fprintf(o, " %s %s -r -f '^status$,\"sda[0-9]\"i' (this is case-insensitive)\n", lib.MlrExeName(), verbNameCut) + fmt.Fprintf(o, " %s %s -f hostname,status\n", "mlr", verbNameCut) + fmt.Fprintf(o, " %s %s -x -f hostname,status\n", "mlr", verbNameCut) + fmt.Fprintf(o, " %s %s -r -f '^status$,sda[0-9]'\n", "mlr", verbNameCut) + fmt.Fprintf(o, " %s %s -r -f '^status$,\"sda[0-9]\"'\n", "mlr", verbNameCut) + fmt.Fprintf(o, " %s %s -r -f '^status$,\"sda[0-9]\"i' (this is case-insensitive)\n", "mlr", verbNameCut) if doExit { os.Exit(exitCode) @@ -158,7 +158,7 @@ func NewTransformerCut( fmt.Fprintf( os.Stderr, "%s %s: cannot compile regex [%s]\n", - lib.MlrExeName(), verbNameCut, regexString, + "mlr", verbNameCut, regexString, ) os.Exit(1) } diff --git a/go/src/transformers/decimate.go b/go/src/transformers/decimate.go index d653432fe..c3d01b936 100644 --- a/go/src/transformers/decimate.go +++ b/go/src/transformers/decimate.go @@ -6,7 +6,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -25,7 +24,7 @@ func transformerDecimateUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameDecimate) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameDecimate) fmt.Fprintf(o, "Passes through one of every n records, optionally by category.\n") fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, " -b Decimate by printing first of every n.\n") diff --git a/go/src/transformers/fill-down.go b/go/src/transformers/fill-down.go index a1b6c1b84..f134600a2 100644 --- a/go/src/transformers/fill-down.go +++ b/go/src/transformers/fill-down.go @@ -6,7 +6,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -25,7 +24,7 @@ func transformerFillDownUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameFillDown) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameFillDown) fmt.Fprintln(o, "If a given record has a missing value for a given field, fill that from") fmt.Fprintln(o, "the corresponding value from a previous record, if any.") fmt.Fprintln(o, "By default, a 'missing' field either is absent, or has the empty-string value.") diff --git a/go/src/transformers/fill-empty.go b/go/src/transformers/fill-empty.go index 3f6a41bf5..4893362d0 100644 --- a/go/src/transformers/fill-empty.go +++ b/go/src/transformers/fill-empty.go @@ -6,7 +6,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -26,7 +25,7 @@ func transformerFillEmptyUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameFillEmpty) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameFillEmpty) fmt.Fprintf(o, "Fills empty-string fields with specified fill-value.\n") fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, "-v {string} Fill-value: defaults to \"%s\"\n", defaultFillEmptyString) diff --git a/go/src/transformers/flatten.go b/go/src/transformers/flatten.go index 917c2401b..53313689e 100644 --- a/go/src/transformers/flatten.go +++ b/go/src/transformers/flatten.go @@ -25,14 +25,14 @@ func transformerFlattenUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameFlatten) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameFlatten) fmt.Fprint(o, `Flattens multi-level maps to single-level ones. Example: field with name 'a' and value '{"b": { "c": 4 }}' becomes name 'a.b.c' and value 4. `) fmt.Fprint(o, "Options:\n") fmt.Fprint(o, "-f Comma-separated list of field names to flatten (default all).\n") - fmt.Fprintf(o, "-s Separator, defaulting to %s --oflatsep value.\n", lib.MlrExeName()) + fmt.Fprintf(o, "-s Separator, defaulting to %s --oflatsep value.\n", "mlr") fmt.Fprintf(o, "-h|--help Show this message.\n") if doExit { diff --git a/go/src/transformers/format-values.go b/go/src/transformers/format-values.go index cada8c1fc..a402a1e38 100644 --- a/go/src/transformers/format-values.go +++ b/go/src/transformers/format-values.go @@ -6,7 +6,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -30,7 +29,7 @@ func transformerFormatValuesUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameFormatValues) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameFormatValues) fmt.Fprintf(o, "Applies format strings to all field values, depending on autodetected type.\n") fmt.Fprintf(o, "* If a field value is detected to be integer, applies integer format.\n") fmt.Fprintf(o, "* Else, if a field value is detected to be float, applies float format.\n") diff --git a/go/src/transformers/fraction.go b/go/src/transformers/fraction.go index 60846c66c..86093a076 100644 --- a/go/src/transformers/fraction.go +++ b/go/src/transformers/fraction.go @@ -26,7 +26,7 @@ func transformerFractionUsage( doExit bool, exitCode int, ) { - argv0 := lib.MlrExeName() + argv0 := "mlr" verb := verbNameFraction fmt.Fprintf(o, "Usage: %s %s [options]\n", argv0, verb) fmt.Fprintf(o, "For each record's value in specified fields, computes the ratio of that\n") diff --git a/go/src/transformers/gap.go b/go/src/transformers/gap.go index 0355ee3c2..a3133ec4c 100644 --- a/go/src/transformers/gap.go +++ b/go/src/transformers/gap.go @@ -6,7 +6,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -25,7 +24,7 @@ func transformerGapUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameGap) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameGap) fmt.Fprint(o, "Emits an empty record every n records, or when certain values change.\n") fmt.Fprintf(o, "Options:\n") diff --git a/go/src/transformers/grep.go b/go/src/transformers/grep.go index 25c236a51..c87f9e898 100644 --- a/go/src/transformers/grep.go +++ b/go/src/transformers/grep.go @@ -7,7 +7,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -26,7 +25,7 @@ func transformerGrepUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options] {regular expression}\n", lib.MlrExeName(), verbNameGrep) + fmt.Fprintf(o, "Usage: %s %s [options] {regular expression}\n", "mlr", verbNameGrep) fmt.Fprintf(o, "Passes through records which match the regular expression.\n") fmt.Fprint(o, "Options:\n") @@ -45,7 +44,7 @@ be matched, not against either of these lines, but against the DKVP line and this command is intended to be merely a keystroke-saver. To get all the features of system grep, you can do "%s --odkvp ... | grep ... | %s --idkvp ..." -`, lib.MlrExeName(), lib.MlrExeName(), lib.MlrExeName(), lib.MlrExeName()) +`, "mlr", "mlr", "mlr", "mlr") if doExit { os.Exit(exitCode) @@ -103,7 +102,7 @@ func transformerGrepParseCLI( regexp, err := regexp.Compile(pattern) if err != nil { fmt.Fprintf(os.Stderr, "%s %s: couldn't compile regex \"%s\"\n", - lib.MlrExeName(), verb, pattern) + "mlr", verb, pattern) os.Exit(1) } diff --git a/go/src/transformers/group-by.go b/go/src/transformers/group-by.go index 6d7624ad8..a8221a035 100644 --- a/go/src/transformers/group-by.go +++ b/go/src/transformers/group-by.go @@ -26,7 +26,7 @@ func transformerGroupByUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options] {comma-separated field names}\n", lib.MlrExeName(), verbNameGroupBy) + fmt.Fprintf(o, "Usage: %s %s [options] {comma-separated field names}\n", "mlr", verbNameGroupBy) fmt.Fprint(o, "Outputs records in batches having identical values at specified field names.") fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, "-h|--help Show this message.\n") diff --git a/go/src/transformers/group-like.go b/go/src/transformers/group-like.go index 651c6c2a3..e8bf53965 100644 --- a/go/src/transformers/group-like.go +++ b/go/src/transformers/group-like.go @@ -26,7 +26,7 @@ func transformerGroupLikeUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameGroupLike) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameGroupLike) fmt.Fprint(o, "Outputs records in batches having identical field names.") fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, "-h|--help Show this message.\n") diff --git a/go/src/transformers/having-fields.go b/go/src/transformers/having-fields.go index 299848e12..33df90d0d 100644 --- a/go/src/transformers/having-fields.go +++ b/go/src/transformers/having-fields.go @@ -39,9 +39,9 @@ func transformerHavingFieldsUsage( doExit bool, exitCode int, ) { - exeName := lib.MlrExeName() + exeName := "mlr" verb := verbNameHavingFields - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameHavingFields) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameHavingFields) fmt.Fprintf(o, "Conditionally passes through records depending on each record's field names.\n") fmt.Fprintf(o, "Options:\n") @@ -187,7 +187,7 @@ func NewTransformerHavingFields( fmt.Fprintf( os.Stderr, "%s %s: cannot compile regex \"%s\"\n", - lib.MlrExeName(), + "mlr", verbNameHavingFields, regexString, ) diff --git a/go/src/transformers/head.go b/go/src/transformers/head.go index 8128122f5..a92a3bd6a 100644 --- a/go/src/transformers/head.go +++ b/go/src/transformers/head.go @@ -6,7 +6,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -25,7 +24,7 @@ func transformerHeadUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameHead) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameHead) fmt.Fprintf(o, "Passes through the first n records, optionally by category.\n") fmt.Fprintf(o, "Options:\n") diff --git a/go/src/transformers/histogram.go b/go/src/transformers/histogram.go index 70ca95db7..24d335f48 100644 --- a/go/src/transformers/histogram.go +++ b/go/src/transformers/histogram.go @@ -25,7 +25,7 @@ func transformerHistogramUsage( doExit bool, exitCode int, ) { - argv0 := lib.MlrExeName() + argv0 := "mlr" verb := verbNameHistogram fmt.Fprintf(o, "Just a histogram. Input values < lo or > hi are not counted.\n") fmt.Fprintf(o, "Usage: %s %s [options]\n", argv0, verb) @@ -217,7 +217,7 @@ func (tr *TransformerHistogram) ingestNonAuto( fmt.Fprintf( os.Stderr, "%s %s: cannot parse \"%s\" as float.\n", - lib.MlrExeName(), verbNameHistogram, stringValue.String(), + "mlr", verbNameHistogram, stringValue.String(), ) os.Exit(1) } diff --git a/go/src/transformers/join.go b/go/src/transformers/join.go index aa3616842..484c04706 100644 --- a/go/src/transformers/join.go +++ b/go/src/transformers/join.go @@ -77,7 +77,7 @@ func transformerJoinUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameJoin) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameJoin) fmt.Fprintf(o, "Joins records from specified left file name with records from all file names\n") fmt.Fprintf(o, "at the end of the Miller argument list.\n") fmt.Fprintf(o, "Functionality is essentially the same as the system \"join\" command, but for\n") @@ -103,13 +103,13 @@ func transformerJoinUsage( fmt.Fprintf(o, " -u Enable unsorted input. (This is the default even without -u.)\n") fmt.Fprintf(o, " In this case, the entire left file will be loaded into memory.\n") fmt.Fprintf(o, " --prepipe {command} As in main input options; see %s --help for details.\n", - lib.MlrExeName()) + "mlr") fmt.Fprintf(o, " If you wish to use a prepipe command for the main input as well\n") fmt.Fprintf(o, " as here, it must be specified there as well as here.\n") fmt.Fprintf(o, " --prepipex {command} Likewise.\n") fmt.Fprintf(o, "File-format options default to those for the right file names on the Miller\n") fmt.Fprintf(o, "argument list, but may be overridden for the left file as follows. Please see\n") - fmt.Fprintf(o, "the main \"%s --help\" for more information on syntax for these arguments:\n", lib.MlrExeName()) + fmt.Fprintf(o, "the main \"%s --help\" for more information on syntax for these arguments:\n", "mlr") fmt.Fprintf(o, " -i {one of csv,dkvp,nidx,pprint,xtab}\n") fmt.Fprintf(o, " --irs {record-separator character}\n") fmt.Fprintf(o, " --ifs {field-separator character}\n") @@ -123,7 +123,7 @@ func transformerJoinUsage( fmt.Fprintf(o, "Likewise, if you have 'mlr --csv --implicit-csv-header ...' then the join-in file will be\n") fmt.Fprintf(o, "expected to be headerless as well unless you put '--no-implicit-csv-header' after 'join'.\n") fmt.Fprintf(o, "Please use \"%s --usage-separator-options\" for information on specifying separators.\n", - lib.MlrExeName()) + "mlr") fmt.Fprintf(o, "Please see https://miller.readthedocs.io/en/latest/reference-verbs.html#join for more information\n") fmt.Fprintf(o, "including examples.\n") @@ -220,20 +220,20 @@ func transformerJoinParseCLI( } if opts.leftFileName == "" { - fmt.Fprintf(os.Stderr, "%s %s: need left file name\n", lib.MlrExeName(), verb) + fmt.Fprintf(os.Stderr, "%s %s: need left file name\n", "mlr", verb) transformerSortUsage(os.Stderr, true, 1) return nil } if !opts.emitPairables && !opts.emitLeftUnpairables && !opts.emitRightUnpairables { fmt.Fprintf(os.Stderr, "%s %s: all emit flags are unset; no output is possible.\n", - lib.MlrExeName(), verb) + "mlr", verb) transformerSortUsage(os.Stderr, true, 1) return nil } if opts.outputJoinFieldNames == nil { - fmt.Fprintf(os.Stderr, "%s %s: need output field names\n", lib.MlrExeName(), verb) + fmt.Fprintf(os.Stderr, "%s %s: need output field names\n", "mlr", verb) transformerSortUsage(os.Stderr, true, 1) return nil } @@ -251,7 +251,7 @@ func transformerJoinParseCLI( if llen != rlen || llen != olen { fmt.Fprintf(os.Stderr, "%s %s: must have equal left,right,output field-name lists; got lengths %d,%d,%d.\n", - lib.MlrExeName(), verb, llen, rlen, olen) + "mlr", verb, llen, rlen, olen) os.Exit(1) } @@ -475,7 +475,7 @@ func (tr *TransformerJoin) ingestLeftFile() { select { case err := <-errorChannel: - fmt.Fprintln(os.Stderr, lib.MlrExeName(), ": ", err) + fmt.Fprintln(os.Stderr, "mlr", ": ", err) os.Exit(1) case leftrecAndContext := <-inputChannel: diff --git a/go/src/transformers/json-parse.go b/go/src/transformers/json-parse.go index 8bbdac614..47137d251 100644 --- a/go/src/transformers/json-parse.go +++ b/go/src/transformers/json-parse.go @@ -25,7 +25,7 @@ func transformerJSONParseUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameJSONParse) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameJSONParse) fmt.Fprintln( o, `Tries to convert string field values to parsed JSON, e.g. "[1,2,3]" -> [1,2,3].`, diff --git a/go/src/transformers/json-stringify.go b/go/src/transformers/json-stringify.go index b6693655c..386977a80 100644 --- a/go/src/transformers/json-stringify.go +++ b/go/src/transformers/json-stringify.go @@ -25,7 +25,7 @@ func transformerJSONStringifyUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameJSONStringify) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameJSONStringify) fmt.Fprint(o, `Produces string field values from field-value data, e.g. [1,2,3] -> "[1,2,3]". `) diff --git a/go/src/transformers/label.go b/go/src/transformers/label.go index 0ab50cdbf..370c9153c 100644 --- a/go/src/transformers/label.go +++ b/go/src/transformers/label.go @@ -26,7 +26,7 @@ func transformerLabelUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options] {new1,new2,new3,...}\n", lib.MlrExeName(), verbNameLabel) + fmt.Fprintf(o, "Usage: %s %s [options] {new1,new2,new3,...}\n", "mlr", verbNameLabel) fmt.Fprintf(o, "Given n comma-separated names, renames the first n fields of each record to\n") fmt.Fprintf(o, "have the respective name. (Fields past the nth are left with their original\n") fmt.Fprintf(o, "names.) Particularly useful with --inidx or --implicit-csv-header, to give\n") diff --git a/go/src/transformers/merge-fields.go b/go/src/transformers/merge-fields.go index b3e84a1df..57be9fc58 100644 --- a/go/src/transformers/merge-fields.go +++ b/go/src/transformers/merge-fields.go @@ -37,7 +37,7 @@ func transformerMergeFieldsUsage( doExit bool, exitCode int, ) { - argv0 := lib.MlrExeName() + argv0 := "mlr" verb := verbNameMergeFields fmt.Fprintf(o, "Usage: %s %s [options]\n", argv0, verb) fmt.Fprintf(o, "Computes univariate statistics for each input record, accumulated across\n") @@ -143,13 +143,13 @@ func transformerMergeFieldsParseCLI( // TODO: libify for use across verbs. if len(accumulatorNameList) == 0 { - fmt.Fprintf(os.Stderr, "%s %s: -a option is required.\n", lib.MlrExeName(), verbNameMergeFields) - fmt.Fprintf(os.Stderr, "Please see %s %s --help for more information.\n", lib.MlrExeName(), verbNameMergeFields) + fmt.Fprintf(os.Stderr, "%s %s: -a option is required.\n", "mlr", verbNameMergeFields) + fmt.Fprintf(os.Stderr, "Please see %s %s --help for more information.\n", "mlr", verbNameMergeFields) os.Exit(1) } if len(valueFieldNameList) == 0 { - fmt.Fprintf(os.Stderr, "%s %s: -f option is required.\n", lib.MlrExeName(), verbNameMergeFields) - fmt.Fprintf(os.Stderr, "Please see %s %s --help for more information.\n", lib.MlrExeName(), verbNameMergeFields) + fmt.Fprintf(os.Stderr, "%s %s: -f option is required.\n", "mlr", verbNameMergeFields) + fmt.Fprintf(os.Stderr, "Please see %s %s --help for more information.\n", "mlr", verbNameMergeFields) os.Exit(1) } if outputFieldBasename == "" { @@ -251,7 +251,7 @@ func NewTransformerMergeFields( return nil, errors.New( fmt.Sprintf( "%s %s: accumulator \"%s\" not found.\n", - lib.MlrExeName(), verbNameMergeFields, accumulatorName, + "mlr", verbNameMergeFields, accumulatorName, ), ) } @@ -275,7 +275,7 @@ func NewTransformerMergeFields( fmt.Fprintf( os.Stderr, "%s %s: cannot compile regex [%s]\n", - lib.MlrExeName(), verbNameCut, regexString, + "mlr", verbNameCut, regexString, ) os.Exit(1) } diff --git a/go/src/transformers/most-or-least-frequent.go b/go/src/transformers/most-or-least-frequent.go index 6092e3958..96e7eab89 100644 --- a/go/src/transformers/most-or-least-frequent.go +++ b/go/src/transformers/most-or-least-frequent.go @@ -7,7 +7,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -37,7 +36,7 @@ func transformerMostFrequentUsage( doExit bool, exitCode int, ) { - argv0 := lib.MlrExeName() + argv0 := "mlr" verb := verbNameMostFrequent fmt.Fprintf(o, "Usage: %s %s [options]\n", argv0, verb) fmt.Fprintf(o, "Shows the most frequently occurring distinct values for specified field names.\n") @@ -58,7 +57,7 @@ func transformerLeastFrequentUsage( doExit bool, exitCode int, ) { - argv0 := lib.MlrExeName() + argv0 := "mlr" verb := verbNameLeastFrequent fmt.Fprintf(o, "Usage: %s %s [options]\n", argv0, verb) fmt.Fprintf(o, "Shows the least frequently occurring distinct values for specified field names.\n") diff --git a/go/src/transformers/nest.go b/go/src/transformers/nest.go index 79cc22137..98cafa9f2 100644 --- a/go/src/transformers/nest.go +++ b/go/src/transformers/nest.go @@ -29,7 +29,7 @@ func transformerNestUsage( doExit bool, exitCode int, ) { - argv0 := lib.MlrExeName() + argv0 := "mlr" verb := verbNameNest fmt.Fprintf(o, "Usage: %s %s [options]\n", argv0, verb) @@ -251,7 +251,7 @@ func NewTransformerNest( fmt.Fprintf( os.Stderr, "%s %s: cannot compile regex [%s]\n", - lib.MlrExeName(), verbNameNest, regexString, + "mlr", verbNameNest, regexString, ) os.Exit(1) } diff --git a/go/src/transformers/nothing.go b/go/src/transformers/nothing.go index e2f9043e6..7b59eefae 100644 --- a/go/src/transformers/nothing.go +++ b/go/src/transformers/nothing.go @@ -6,7 +6,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -25,7 +24,7 @@ func transformerNothingUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameNothing) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameNothing) fmt.Fprintf(o, "Drops all input records. Useful for testing, or after tee/print/etc. have\n") fmt.Fprintf(o, "produced other output.\n") fmt.Fprintf(o, "Options:\n") diff --git a/go/src/transformers/put-or-filter.go b/go/src/transformers/put-or-filter.go index 8107023f4..83faadc02 100644 --- a/go/src/transformers/put-or-filter.go +++ b/go/src/transformers/put-or-filter.go @@ -58,7 +58,7 @@ func transformerPutOrFilterUsage( exitCode int, verb string, ) { - fmt.Fprintf(o, "Usage: %s %s [options] {DSL expression}\n", lib.MlrExeName(), verb) + fmt.Fprintf(o, "Usage: %s %s [options] {DSL expression}\n", "mlr", verb) fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, `-f {file name} File containing a DSL expression. If the filename is a directory, @@ -157,7 +157,7 @@ func transformerPutOrFilterParseCLI( theseDSLStrings, err := lib.LoadStringsFromFileOrDir(filename, ".mlr") if err != nil { fmt.Fprintf(os.Stderr, "%s %s: cannot load DSL expression from \"%s\": ", - lib.MlrExeName(), verb, filename) + "mlr", verb, filename) fmt.Println(err) return nil } @@ -181,7 +181,7 @@ func transformerPutOrFilterParseCLI( theseDSLStrings, err := lib.LoadStringsFromFileOrDir(filename, ".mlr") if err != nil { fmt.Fprintf(os.Stderr, "%s %s: cannot load DSL expression from file \"%s\": ", - lib.MlrExeName(), verb, filename) + "mlr", verb, filename) fmt.Println(err) return nil } @@ -404,7 +404,7 @@ func BuildASTFromStringWithMessage(dslString string) (*dsl.AST, error) { // At present it's overly parser-internal, and confusing. :( // fmt.Fprintln(os.Stderr, err) fmt.Fprintf(os.Stderr, "%s: cannot parse DSL expression.\n", - lib.MlrExeName()) + "mlr") fmt.Fprintln(os.Stderr, err) return nil, err } else { diff --git a/go/src/transformers/regularize.go b/go/src/transformers/regularize.go index 5f02161b2..d3bea2932 100644 --- a/go/src/transformers/regularize.go +++ b/go/src/transformers/regularize.go @@ -25,7 +25,7 @@ func transformerRegularizeUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameRegularize) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameRegularize) fmt.Fprint(o, "Outputs records sorted lexically ascending by keys.") fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, "-h|--help Show this message.\n") diff --git a/go/src/transformers/remove-empty-columns.go b/go/src/transformers/remove-empty-columns.go index 4775d98be..6c692def2 100644 --- a/go/src/transformers/remove-empty-columns.go +++ b/go/src/transformers/remove-empty-columns.go @@ -7,7 +7,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -26,7 +25,7 @@ func transformerRemoveEmptyColumnsUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameRemoveEmptyColumns) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameRemoveEmptyColumns) fmt.Fprintf(o, "Omits fields which are empty on every input row. Non-streaming.\n") fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, "-h|--help Show this message.\n") diff --git a/go/src/transformers/rename.go b/go/src/transformers/rename.go index 27ce6a3f5..60101bf8d 100644 --- a/go/src/transformers/rename.go +++ b/go/src/transformers/rename.go @@ -28,10 +28,10 @@ func transformerRenameUsage( doExit bool, exitCode int, ) { - exeName := lib.MlrExeName() + exeName := "mlr" verb := verbNameRename - fmt.Fprintf(o, "Usage: %s %s [options] {old1,new1,old2,new2,...}\n", lib.MlrExeName(), verbNameRename) + fmt.Fprintf(o, "Usage: %s %s [options] {old1,new1,old2,new2,...}\n", "mlr", verbNameRename) fmt.Fprintf(o, "Renames specified fields.\n") fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, "-r Treat old field names as regular expressions. \"ab\", \"a.*b\"\n") diff --git a/go/src/transformers/reorder.go b/go/src/transformers/reorder.go index 589e1ba78..13902e937 100644 --- a/go/src/transformers/reorder.go +++ b/go/src/transformers/reorder.go @@ -25,7 +25,7 @@ func transformerReorderUsage( doExit bool, exitCode int, ) { - argv0 := lib.MlrExeName() + argv0 := "mlr" verb := verbNameReorder fmt.Fprintf(o, "Usage: %s %s [options]\n", argv0, verb) fmt.Fprint(o, diff --git a/go/src/transformers/repeat.go b/go/src/transformers/repeat.go index 8ef3bc5f3..e0d53773b 100644 --- a/go/src/transformers/repeat.go +++ b/go/src/transformers/repeat.go @@ -6,7 +6,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -34,7 +33,7 @@ func transformerRepeatUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameRepeat) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameRepeat) fmt.Fprintf(o, "Copies input records to output records multiple times.\n") fmt.Fprintf(o, "Options must be exactly one of the following:\n") fmt.Fprintf(o, "-n {repeat count} Repeat each input record this many times.\n") @@ -42,19 +41,19 @@ func transformerRepeatUsage( fmt.Fprintf(o, " field name of each input record.\n") fmt.Fprintf(o, "-h|--help Show this message.\n") fmt.Fprintf(o, "Example:\n") - fmt.Fprintf(o, " echo x=0 | %s %s -n 4 then put '$x=urand()'\n", lib.MlrExeName(), verbNameRepeat) + fmt.Fprintf(o, " echo x=0 | %s %s -n 4 then put '$x=urand()'\n", "mlr", verbNameRepeat) fmt.Fprintf(o, "produces:\n") fmt.Fprintf(o, " x=0.488189\n") fmt.Fprintf(o, " x=0.484973\n") fmt.Fprintf(o, " x=0.704983\n") fmt.Fprintf(o, " x=0.147311\n") fmt.Fprintf(o, "Example:\n") - fmt.Fprintf(o, " echo a=1,b=2,c=3 | %s %s -f b\n", lib.MlrExeName(), verbNameRepeat) + fmt.Fprintf(o, " echo a=1,b=2,c=3 | %s %s -f b\n", "mlr", verbNameRepeat) fmt.Fprintf(o, "produces:\n") fmt.Fprintf(o, " a=1,b=2,c=3\n") fmt.Fprintf(o, " a=1,b=2,c=3\n") fmt.Fprintf(o, "Example:\n") - fmt.Fprintf(o, " echo a=1,b=2,c=3 | %s %s -f c\n", lib.MlrExeName(), verbNameRepeat) + fmt.Fprintf(o, " echo a=1,b=2,c=3 | %s %s -f c\n", "mlr", verbNameRepeat) fmt.Fprintf(o, "produces:\n") fmt.Fprintf(o, " a=1,b=2,c=3\n") fmt.Fprintf(o, " a=1,b=2,c=3\n") diff --git a/go/src/transformers/reshape.go b/go/src/transformers/reshape.go index 1f9ad2ef9..7e9d6d80f 100644 --- a/go/src/transformers/reshape.go +++ b/go/src/transformers/reshape.go @@ -53,7 +53,7 @@ func transformerReshapeUsage( doExit bool, exitCode int, ) { - argv0 := lib.MlrExeName() + argv0 := "mlr" verb := verbNameReshape fmt.Fprintf(o, "Usage: %s %s [options]\n", argv0, verb) @@ -250,7 +250,7 @@ func NewTransformerReshape( fmt.Fprintf( os.Stderr, "%s %s: cannot compile regex [%s]\n", - lib.MlrExeName(), verbNameReshape, inputFieldRegexString, + "mlr", verbNameReshape, inputFieldRegexString, ) os.Exit(1) } diff --git a/go/src/transformers/sample.go b/go/src/transformers/sample.go index 58bd66f48..a1a34b515 100644 --- a/go/src/transformers/sample.go +++ b/go/src/transformers/sample.go @@ -25,11 +25,11 @@ func transformerSampleUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameSample) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameSample) fmt.Fprintf(o, `Reservoir sampling (subsampling without replacement), optionally by category. See also %s bootstrap and %s shuffle. -`, lib.MlrExeName(), lib.MlrExeName()) +`, "mlr", "mlr") fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, "-g {a,b,c} Optional: group-by-field names for samples, e.g. a,b,c.\n") fmt.Fprintf(o, "-k {k} Required: number of records to output in total, or by group if using -g.\n") diff --git a/go/src/transformers/sec2gmt.go b/go/src/transformers/sec2gmt.go index 76ace2ff1..ed5efc434 100644 --- a/go/src/transformers/sec2gmt.go +++ b/go/src/transformers/sec2gmt.go @@ -24,13 +24,13 @@ func transformerSec2GMTUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options] {comma-separated list of field names}\n", lib.MlrExeName(), verbNameSec2GMT) + fmt.Fprintf(o, "Usage: %s %s [options] {comma-separated list of field names}\n", "mlr", verbNameSec2GMT) fmt.Fprintf(o, "Replaces a numeric field representing seconds since the epoch with the\n") fmt.Fprintf(o, "corresponding GMT timestamp; leaves non-numbers as-is. This is nothing\n") fmt.Fprintf(o, "more than a keystroke-saver for the sec2gmt function:\n") - fmt.Fprintf(o, " %s %s time1,time2\n", lib.MlrExeName(), verbNameSec2GMT) + fmt.Fprintf(o, " %s %s time1,time2\n", "mlr", verbNameSec2GMT) fmt.Fprintf(o, "is the same as\n") - fmt.Fprintf(o, " %s put '$time1 = sec2gmt($time1); $time2 = sec2gmt($time2)'\n", lib.MlrExeName()) + fmt.Fprintf(o, " %s put '$time1 = sec2gmt($time1); $time2 = sec2gmt($time2)'\n", "mlr") fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, "-1 through -9: format the seconds using 1..9 decimal places, respectively.\n") fmt.Fprintf(o, "--millis Input numbers are treated as milliseconds since the epoch.\n") diff --git a/go/src/transformers/seqgen.go b/go/src/transformers/seqgen.go index 7ffe1f4fe..4eb141f9e 100644 --- a/go/src/transformers/seqgen.go +++ b/go/src/transformers/seqgen.go @@ -7,7 +7,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -26,7 +25,7 @@ func transformerSeqgenUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameSeqgen) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameSeqgen) fmt.Fprintf(o, "Passes input records directly to output. Most useful for format conversion.\n") fmt.Fprintf(o, "Produces a sequence of counters. Discards the input record stream. Produces\n") fmt.Fprintf(o, "output as specified by the options\n") diff --git a/go/src/transformers/shuffle.go b/go/src/transformers/shuffle.go index 9522a826a..5c0b3067e 100644 --- a/go/src/transformers/shuffle.go +++ b/go/src/transformers/shuffle.go @@ -26,10 +26,10 @@ func transformerShuffleUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameShuffle) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameShuffle) fmt.Fprintf(o, "Outputs records randomly permuted. No output records are produced until\n") fmt.Fprintf(o, "all input records are read. See also %s bootstrap and %s sample.\n", - lib.MlrExeName(), lib.MlrExeName(), + "mlr", "mlr", ) fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, "-h|--help Show this message.\n") diff --git a/go/src/transformers/skip-trivial-records.go b/go/src/transformers/skip-trivial-records.go index d1d858bfc..b603434e8 100644 --- a/go/src/transformers/skip-trivial-records.go +++ b/go/src/transformers/skip-trivial-records.go @@ -6,7 +6,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -25,7 +24,7 @@ func transformerSkipTrivialRecordsUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameSkipTrivialRecords) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameSkipTrivialRecords) fmt.Fprintf(o, "Passes through all records except those with zero fields,\n") fmt.Fprintf(o, "or those for which all fields have empty value.\n") fmt.Fprintf(o, "Options:\n") diff --git a/go/src/transformers/sort-within-records.go b/go/src/transformers/sort-within-records.go index 826dacd2c..953f46918 100644 --- a/go/src/transformers/sort-within-records.go +++ b/go/src/transformers/sort-within-records.go @@ -6,7 +6,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -25,7 +24,7 @@ func transformerSortWithinRecordsUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameSortWithinRecords) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameSortWithinRecords) fmt.Fprintln(o, "Outputs records sorted lexically ascending by keys.") fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, "-r Recursively sort subobjects/submaps, e.g. for JSON input.\n") diff --git a/go/src/transformers/sort.go b/go/src/transformers/sort.go index 334395e4c..3deb15362 100644 --- a/go/src/transformers/sort.go +++ b/go/src/transformers/sort.go @@ -68,7 +68,7 @@ func transformerSortUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s {flags}\n", lib.MlrExeName(), verbNameSort) + fmt.Fprintf(o, "Usage: %s %s {flags}\n", "mlr", verbNameSort) fmt.Fprintf(o, "Sorts records primarily by the first specified field, secondarily by the second\n") fmt.Fprintf(o, "field, and so on. (Any records not having all specified sort keys will appear\n") fmt.Fprintf(o, "at the end of the output, in the order they were encountered, regardless of the\n") @@ -84,9 +84,9 @@ func transformerSortUsage( fmt.Fprintf(o, "-h|--help Show this message.\n") fmt.Fprintf(o, "\n") fmt.Fprintf(o, "Example:\n") - fmt.Fprintf(o, " %s %s -f a,b -nr x,y,z\n", lib.MlrExeName(), verbNameSort) + fmt.Fprintf(o, " %s %s -f a,b -nr x,y,z\n", "mlr", verbNameSort) fmt.Fprintf(o, "which is the same as:\n") - fmt.Fprintf(o, " %s %s -f a -f b -nr x -nr y -nr z\n", lib.MlrExeName(), verbNameSort) + fmt.Fprintf(o, " %s %s -f a -f b -nr x -nr y -nr z\n", "mlr", verbNameSort) if doExit { os.Exit(exitCode) diff --git a/go/src/transformers/stats1.go b/go/src/transformers/stats1.go index 2dc8cc608..f02528ab7 100644 --- a/go/src/transformers/stats1.go +++ b/go/src/transformers/stats1.go @@ -27,7 +27,7 @@ func transformerStats1Usage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameStats1) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameStats1) fmt.Fprint(o, `Computes univariate statistics for one or more given fields, accumulated across the input record stream. @@ -52,13 +52,13 @@ Options: `) fmt.Fprintln(o, - "Example: mlr stats1 -a min,p10,p50,p90,max -f value -g size,shape\n", lib.MlrExeName(), verbNameStats1) + "Example: mlr stats1 -a min,p10,p50,p90,max -f value -g size,shape\n", "mlr", verbNameStats1) fmt.Fprintln(o, - "Example: mlr stats1 -a count,mode -f size\n", lib.MlrExeName(), verbNameStats1) + "Example: mlr stats1 -a count,mode -f size\n", "mlr", verbNameStats1) fmt.Fprintln(o, - "Example: mlr stats1 -a count,mode -f size -g shape\n", lib.MlrExeName(), verbNameStats1) + "Example: mlr stats1 -a count,mode -f size -g shape\n", "mlr", verbNameStats1) fmt.Fprintln(o, - "Example: mlr stats1 -a count,mode --fr '^[a-h].*$' -gr '^k.*$'\n", lib.MlrExeName(), verbNameStats1) + "Example: mlr stats1 -a count,mode --fr '^[a-h].*$' -gr '^k.*$'\n", "mlr", verbNameStats1) fmt.Fprintln(o, ` This computes count and mode statistics on all field names beginning with a through h, grouped by all field names starting with k.`) @@ -141,13 +141,13 @@ func transformerStats1ParseCLI( // TODO: libify for use across verbs. if len(accumulatorNameList) == 0 { - fmt.Fprintf(os.Stderr, "%s %s: -a option is required.\n", lib.MlrExeName(), verbNameStats1) - fmt.Fprintf(os.Stderr, "Please see %s %s --help for more information.\n", lib.MlrExeName(), verbNameStats1) + fmt.Fprintf(os.Stderr, "%s %s: -a option is required.\n", "mlr", verbNameStats1) + fmt.Fprintf(os.Stderr, "Please see %s %s --help for more information.\n", "mlr", verbNameStats1) os.Exit(1) } if len(valueFieldNameList) == 0 { - fmt.Fprintf(os.Stderr, "%s %s: -f option is required.\n", lib.MlrExeName(), verbNameStats1) - fmt.Fprintf(os.Stderr, "Please see %s %s --help for more information.\n", lib.MlrExeName(), verbNameStats1) + fmt.Fprintf(os.Stderr, "%s %s: -f option is required.\n", "mlr", verbNameStats1) + fmt.Fprintf(os.Stderr, "Please see %s %s --help for more information.\n", "mlr", verbNameStats1) os.Exit(1) } @@ -244,7 +244,7 @@ func NewTransformerStats1( return nil, errors.New( fmt.Sprintf( "%s stats1: accumulator \"%s\" not found.\n", - lib.MlrExeName(), name, + "mlr", name, ), ) } diff --git a/go/src/transformers/stats2.go b/go/src/transformers/stats2.go index 04197af3f..6a46921f9 100644 --- a/go/src/transformers/stats2.go +++ b/go/src/transformers/stats2.go @@ -32,7 +32,7 @@ func transformerStats2Usage( doExit bool, exitCode int, ) { - argv0 := lib.MlrExeName() + argv0 := "mlr" verb := verbNameStats2 fmt.Fprintf(o, "Usage: %s %s [options]\n", argv0, verb) @@ -76,7 +76,7 @@ func transformerStats2ParseCLI( verb := args[argi] argi++ - argv0 := lib.MlrExeName() + argv0 := "mlr" var accumulatorNameList []string = nil var valueFieldNameList []string = nil @@ -204,7 +204,7 @@ func NewTransformerStats2( return nil, errors.New( fmt.Sprintf( "%s stats2: accumulator \"%s\" not found.\n", - lib.MlrExeName(), name, + "mlr", name, ), ) } @@ -352,7 +352,7 @@ func (tr *TransformerStats2) ingest( ) if accumulator == nil { fmt.Fprintf(os.Stderr, "%s %s: accumulator \"%s\" not found.\n", - lib.MlrExeName(), verbNameStats2, accumulatorName, + "mlr", verbNameStats2, accumulatorName, ) os.Exit(1) } diff --git a/go/src/transformers/step.go b/go/src/transformers/step.go index 239d97342..82a882f21 100644 --- a/go/src/transformers/step.go +++ b/go/src/transformers/step.go @@ -28,7 +28,7 @@ func transformerStepUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameStep) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameStep) fmt.Fprintf(o, "Computes values dependent on the previous record, optionally grouped by category.\n") fmt.Fprintf(o, "Options:\n") @@ -49,7 +49,7 @@ func transformerStepUsage( fmt.Fprintf(o, "-d {x,y,z} Weights for ewma. 1 means current sample gets all weight (no\n") fmt.Fprintf(o, " smoothing), near under under 1 is light smoothing, near over 0 is\n") fmt.Fprintf(o, " heavy smoothing. Multiple weights may be specified, e.g.\n") - fmt.Fprintf(o, " \"%s %s -a ewma -f sys_load -d 0.01,0.1,0.9\". Default if omitted\n", lib.MlrExeName(), verbNameStep) + fmt.Fprintf(o, " \"%s %s -a ewma -f sys_load -d 0.01,0.1,0.9\". Default if omitted\n", "mlr", verbNameStep) fmt.Fprintf(o, " is \"-d %s\".\n", DEFAULT_STRING_ALPHA) fmt.Fprintf(o, "-o {a,b,c} Custom suffixes for EWMA output fields. If omitted, these default to\n") @@ -59,11 +59,11 @@ func transformerStepUsage( fmt.Fprintf(o, "\n") fmt.Fprintf(o, "Examples:\n") - fmt.Fprintf(o, " %s %s -a rsum -f request_size\n", lib.MlrExeName(), verbNameStep) - fmt.Fprintf(o, " %s %s -a delta -f request_size -g hostname\n", lib.MlrExeName(), verbNameStep) - fmt.Fprintf(o, " %s %s -a ewma -d 0.1,0.9 -f x,y\n", lib.MlrExeName(), verbNameStep) - fmt.Fprintf(o, " %s %s -a ewma -d 0.1,0.9 -o smooth,rough -f x,y\n", lib.MlrExeName(), verbNameStep) - fmt.Fprintf(o, " %s %s -a ewma -d 0.1,0.9 -o smooth,rough -f x,y -g group_name\n", lib.MlrExeName(), verbNameStep) + fmt.Fprintf(o, " %s %s -a rsum -f request_size\n", "mlr", verbNameStep) + fmt.Fprintf(o, " %s %s -a delta -f request_size -g hostname\n", "mlr", verbNameStep) + fmt.Fprintf(o, " %s %s -a ewma -d 0.1,0.9 -f x,y\n", "mlr", verbNameStep) + fmt.Fprintf(o, " %s %s -a ewma -d 0.1,0.9 -o smooth,rough -f x,y\n", "mlr", verbNameStep) + fmt.Fprintf(o, " %s %s -a ewma -d 0.1,0.9 -o smooth,rough -f x,y -g group_name\n", "mlr", verbNameStep) fmt.Fprintf(o, "\n") fmt.Fprintf(o, "Please see https://miller.readthedocs.io/en/latest/reference-verbs.html#filter or\n") diff --git a/go/src/transformers/tac.go b/go/src/transformers/tac.go index 90bb9cf01..ea035a13c 100644 --- a/go/src/transformers/tac.go +++ b/go/src/transformers/tac.go @@ -7,7 +7,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/types" ) @@ -26,7 +25,7 @@ func transformerTacUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameTac) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameTac) fmt.Fprintf(o, "Prints records in reverse order from the order in which they were encountered.\n") fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, "-h|--help Show this message.\n") diff --git a/go/src/transformers/tail.go b/go/src/transformers/tail.go index c94a60345..d31f0f7c4 100644 --- a/go/src/transformers/tail.go +++ b/go/src/transformers/tail.go @@ -26,7 +26,7 @@ func transformerTailUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameTail) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameTail) fmt.Fprintln(o, "Passes through the last n records, optionally by category.") fmt.Fprintf(o, "Options:\n") diff --git a/go/src/transformers/tee.go b/go/src/transformers/tee.go index 44d845f94..37faee096 100644 --- a/go/src/transformers/tee.go +++ b/go/src/transformers/tee.go @@ -6,7 +6,6 @@ import ( "strings" "miller/src/cliutil" - "miller/src/lib" "miller/src/output" "miller/src/types" ) @@ -26,7 +25,7 @@ func transformerTeeUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options] {filename}\n", lib.MlrExeName(), verbNameTee) + fmt.Fprintf(o, "Usage: %s %s [options] {filename}\n", "mlr", verbNameTee) fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, `-a Append to existing file, if any, rather than overwriting. @@ -166,7 +165,7 @@ func (tr *TransformerTee) Transform( fmt.Fprintf( os.Stderr, "%s: error writing to tee \"%s\":\n", - lib.MlrExeName(), tr.filenameOrCommandForDisplay, + "mlr", tr.filenameOrCommandForDisplay, ) fmt.Fprintln(os.Stderr, err) os.Exit(1) @@ -179,7 +178,7 @@ func (tr *TransformerTee) Transform( fmt.Fprintf( os.Stderr, "%s: error closing tee \"%s\":\n", - lib.MlrExeName(), tr.filenameOrCommandForDisplay, + "mlr", tr.filenameOrCommandForDisplay, ) fmt.Fprintln(os.Stderr, err) os.Exit(1) diff --git a/go/src/transformers/top.go b/go/src/transformers/top.go index 21b45ebcb..5289b3d7c 100644 --- a/go/src/transformers/top.go +++ b/go/src/transformers/top.go @@ -27,7 +27,7 @@ func transformerTopUsage( doExit bool, exitCode int, ) { - argv0 := lib.MlrExeName() + argv0 := "mlr" verb := verbNameTop fmt.Fprintf(o, "Usage: %s %s [options]\n", argv0, verb) fmt.Fprintf(o, "-f {a,b,c} Value-field names for top counts.\n") diff --git a/go/src/transformers/unflatten.go b/go/src/transformers/unflatten.go index 4a3470eda..234528f2c 100644 --- a/go/src/transformers/unflatten.go +++ b/go/src/transformers/unflatten.go @@ -25,14 +25,14 @@ func transformerUnflattenUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameUnflatten) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameUnflatten) fmt.Fprint(o, `Reverses flatten. Example: field with name 'a.b.c' and value 4 becomes name 'a' and value '{"b": { "c": 4 }}'. `) fmt.Fprintf(o, "Options:\n") fmt.Fprintf(o, "-f {a,b,c} Comma-separated list of field names to unflatten (default all).\n") - fmt.Fprintf(o, "-s {string} Separator, defaulting to %s --oflatsep value.\n", lib.MlrExeName()) + fmt.Fprintf(o, "-s {string} Separator, defaulting to %s --oflatsep value.\n", "mlr") fmt.Fprintf(o, "-h|--help Show this message.\n") if doExit { diff --git a/go/src/transformers/uniq.go b/go/src/transformers/uniq.go index cfcc305b9..782481430 100644 --- a/go/src/transformers/uniq.go +++ b/go/src/transformers/uniq.go @@ -35,7 +35,7 @@ func transformerCountDistinctUsage( doExit bool, exitCode int, ) { - argv0 := lib.MlrExeName() + argv0 := "mlr" verb := verbNameCountDistinct fmt.Fprintf(o, "Usage: %s %s [options]\n", argv0, verb) fmt.Fprintf(o, "Prints number of records having distinct values for specified field names.\n") @@ -135,7 +135,7 @@ func transformerUniqUsage( doExit bool, exitCode int, ) { - argv0 := lib.MlrExeName() + argv0 := "mlr" verb := verbNameUniq fmt.Fprintf(o, "Usage: %s %s [options]\n", argv0, verb) fmt.Fprintf(o, "Prints distinct values for specified field names. With -c, same as\n") diff --git a/go/src/transformers/unsparsify.go b/go/src/transformers/unsparsify.go index 7ccec14f6..08c006c5e 100644 --- a/go/src/transformers/unsparsify.go +++ b/go/src/transformers/unsparsify.go @@ -26,7 +26,7 @@ func transformerUnsparsifyUsage( doExit bool, exitCode int, ) { - fmt.Fprintf(o, "Usage: %s %s [options]\n", lib.MlrExeName(), verbNameUnsparsify) + fmt.Fprintf(o, "Usage: %s %s [options]\n", "mlr", verbNameUnsparsify) fmt.Fprint(o, `Prints records with the union of field names over all input records. For field names absent in a given record but present in others, fills in diff --git a/go/src/transformers/utils/join-bucket-keeper.go b/go/src/transformers/utils/join-bucket-keeper.go index 822640c12..bb4b9f808 100644 --- a/go/src/transformers/utils/join-bucket-keeper.go +++ b/go/src/transformers/utils/join-bucket-keeper.go @@ -170,7 +170,7 @@ func NewJoinBucketKeeper( fmt.Fprintf( os.Stderr, "%s join: Input format %s not found.\n", - lib.MlrExeName(), + "mlr", joinReaderOptions.InputFileFormat, ) os.Exit(1) @@ -314,7 +314,7 @@ func (keeper *JoinBucketKeeper) FindJoinBucket( fmt.Fprintf( os.Stderr, "%s: internal coding error: failed transition from prefill state.\n", - lib.MlrExeName(), + "mlr", ) os.Exit(1) } @@ -464,7 +464,7 @@ func (keeper *JoinBucketKeeper) fillNextJoinBucket() { fmt.Fprintf( os.Stderr, "%s: internal coding error: peek record should have had join keys.\n", - lib.MlrExeName(), + "mlr", ) os.Exit(1) } @@ -572,7 +572,7 @@ func (keeper *JoinBucketKeeper) readRecord() *types.RecordAndContext { select { case err := <-keeper.errorChannel: - fmt.Fprintln(os.Stderr, lib.MlrExeName(), ": ", err) + fmt.Fprintln(os.Stderr, "mlr", ": ", err) os.Exit(1) case leftrecAndContext := <-keeper.inputChannel: if leftrecAndContext.EndOfStream { // end-of-stream marker diff --git a/go/src/types/mlrval_accessors.go b/go/src/types/mlrval_accessors.go index 92b387aeb..fdc744631 100644 --- a/go/src/types/mlrval_accessors.go +++ b/go/src/types/mlrval_accessors.go @@ -144,7 +144,7 @@ func (mv *Mlrval) GetNumericToFloatValueOrDie() (floatValue float64) { fmt.Fprintf( os.Stderr, "%s: couldn't parse \"%s\" as number.", - lib.MlrExeName(), mv.String(), + "mlr", mv.String(), ) os.Exit(1) } diff --git a/go/todo.txt b/go/todo.txt index 5f84edd46..eef7da569 100644 --- a/go/todo.txt +++ b/go/todo.txt @@ -4,12 +4,10 @@ TOP OF LIST: * emit * regex * fmtnum * localtime * * --nr-progress-mod * mlr -k * * cli-audits * doc6 * survey * check issues * -* split up mlr -h * survey email followups * convert all code-blocks to cardify * most/least-frequent: map -> odict -* lib.MlrExeName() -> "mlr" throughout ---------------------------------------------------------------- colorizer: @@ -24,20 +22,21 @@ doclink etc: ---------------------------------------------------------------- HELP +! TABLE -> getTABLE() w/ lazy sorted/sorter * split up help/entry.go -- ? -! improved sort for functions-table -? integrate repl help with main help? - o repl help keyword -* manpage & main help need some basic examples +! type-arithmetic-info + ---------------------------------------------------------------- ---------------------------------------------------------------- DOC6 -* wip - go get github.com/kisielk/godepgraph - godepgraph miller | dot -Tpng -o ~/Desktop/mlrdeps.png -* flamegraph etc double-check +* memory page: + o open with "out of memory" -- what next? + o streaming vs non-streaming + o unsparsify -f + o no out-of-core sort yet ... + o older versions ? quick-examples needs fewer inputs, and outputs for all retained inputs ? or q-e more links to 10min @@ -49,7 +48,6 @@ DOC6 o differences from other languages (cf. juliadocs) * doc notes about --jknquotein & --jvquoteall. make sure they're ignore-accepted in the CLIP. -* audit for mlb -> lib.MlrExeName() (in case mlr.foo) * items: o file-formats: @@ -58,6 +56,10 @@ DOC6 o format ordering: pick one for sphinx, manpage, olh o autodetect: tbd +* separator options -- olh also +* number formatting -- olh also +* double quoting -- olh also + * code to-do items: o stats1 --fr cookbook2.rst.in @@ -84,6 +86,12 @@ DOC6 * case auxfiles: cat them too +---------------------------------------------------------------- +REPLv2 + +* consider making it a verb + o 'put --repl' maybe + ---------------------------------------------------------------- * mlr -k o c,go @@ -108,7 +116,6 @@ w survey ---------------------------------------------------------------- * debug && || on windows more ... -* list-of-verbs shortlist @ top ... * blocker: regexes o finish stats1 -r @@ -171,6 +178,11 @@ w survey - TBD writer -- defer factory until first context? - deeper refactor pulling format out of reader/writer options entirely -- ? +* pkg graph: + go get github.com/kisielk/godepgraph + godepgraph miller | dot -Tpng -o ~/Desktop/mlrdeps.png + flamegraph etc double-check + ---------------------------------------------------------------- * emph go 1.16 @ go.mod & README.md; also gha yaml diff --git a/man6/Makefile b/man6/Makefile index 619cfde31..c8b101b20 100644 --- a/man6/Makefile +++ b/man6/Makefile @@ -12,10 +12,10 @@ top: .always echo mkman end # These targets are only for local dev work. -install: +install: top mkdir -p $(INSTALLDIR) cp mlr6.1 $(INSTALLDIR)/mlr6.1 -installhome: +installhome: top mkdir -p $(INSTALLHOME) cp mlr6.1 $(INSTALLHOME)/mlr6.1 diff --git a/man6/manpage.txt b/man6/manpage.txt index 903c41bed..9bf96a7ad 100644 --- a/man6/manpage.txt +++ b/man6/manpage.txt @@ -95,14 +95,40 @@ DATA FORMATS | fox jumped | Record 2: "1" => "fox", "2" => "jumped" +---------------------+ -OPTIONS - In the following option flags, the version with "i" designates the - input stream, "o" the output stream, and the version without prefix - sets the option for both input and output stream. For example: --irs - sets the input record separator, --ors the output record separator, and - --rs sets both the input and output separator to the given value. +VERB LIST + altkv bar bootstrap cat check clean-whitespace count-distinct count + count-similar cut decimate fill-down fill-empty filter flatten format-values + fraction gap grep group-by group-like having-fields head histogram json-parse + json-stringify join label least-frequent merge-fields most-frequent nest + nothing put regularize remove-empty-columns rename reorder repeat reshape + sample sec2gmtdate sec2gmt seqgen shuffle skip-trivial-records sort + sort-within-records stats1 stats2 step tac tail tee top unflatten uniq + unsparsify - HELP OPTIONS +FUNCTION LIST + abs acos acosh append arrayify asin asinh asserting_absent asserting_array + asserting_bool asserting_boolean asserting_empty asserting_empty_map + asserting_error asserting_float asserting_int asserting_map + asserting_nonempty_map asserting_not_array asserting_not_empty + asserting_not_map asserting_not_null asserting_null asserting_numeric + asserting_present asserting_string atan atan2 atanh bitcount boolean + capitalize cbrt ceil clean_whitespace collapse_whitespace cos cosh depth + dhms2fsec dhms2sec erf erfc exp expm1 flatten float floor fmtnum fsec2dhms + fsec2hms get_keys get_values gmt2sec gsub haskey hexfmt hms2fsec hms2sec + hostname int invqnorm is_absent is_array is_bool is_boolean is_empty + is_empty_map is_error is_float is_int is_map is_nonempty_map is_not_array + is_not_empty is_not_map is_not_null is_null is_numeric is_present is_string + joink joinkv joinv json_parse json_stringify leafcount length log log10 log1p + logifit lstrip madd mapdiff mapexcept mapselect mapsum max md5 mexp min mmul + msub os pow qnorm regextract regextract_or_else round roundm rstrip sec2dhms + sec2gmt sec2gmtdate sec2hms sgn sha1 sha256 sha512 sin sinh splita splitax + splitkv splitkvx splitnv splitnvx sqrt ssub strftime string strip strlen + strptime sub substr substr0 substr1 system systime systimeint tan tanh tolower + toupper truncate typeof unflatten uptime urand urand32 urandint urandrange + version ! != !=~ % & && * ** + - . .* .+ .- ./ / // < << <= == =~ > >= >> >>> + ?: ?? ??? ^ ^^ | || ~ + +HELP OPTIONS Type 'mlr help {topic}' for any of the following: mlr help topics mlr help auxents @@ -117,309 +143,94 @@ OPTIONS mlr help function mlr help keyword mlr help list-functions - mlr help list-functions-vertically + mlr help list-functions-as-paragraph mlr help list-keywords + mlr help list-keywords-as-paragraph mlr help list-verbs - mlr help list-verbs-vertically + mlr help list-verbs-as-paragraph mlr help misc mlr help mlrrc mlr help number-formatting - mlr help output-colorizations + mlr help output-colorization mlr help separator-options + mlr help type-arithmetic-info mlr help usage-functions mlr help usage-keywords mlr help usage-verbs mlr help verb Shorthands: mlr -l = mlr help list-verbs - mlr -L = mlr help list-verbs-vertically - mlr -f = mlr help usage-functions - mlr -F = mlr help list-functions - mlr -k = mlr help usage-keywords - mlr -K = mlr help list-keywords + mlr -L = mlr help usage-verbs + mlr -f = mlr help list-functions + mlr -F = mlr help usage-functions + mlr -k = mlr help list-keywords + mlr -K = mlr help usage-keywords - VERB LIST - altkv bar bootstrap cat check clean-whitespace count-distinct count - count-similar cut decimate fill-down fill-empty filter flatten format-values - fraction gap grep group-by group-like having-fields head histogram json-parse - json-stringify join label least-frequent merge-fields most-frequent nest - nothing put regularize remove-empty-columns rename reorder repeat reshape - sample sec2gmtdate sec2gmt seqgen shuffle skip-trivial-records sort - sort-within-records stats1 stats2 step tac tail tee top unflatten uniq - unsparsify +OPTIONS + In the following option flags, the version with "i" designates the + input stream, "o" the output stream, and the version without prefix + sets the option for both input and output stream. For example: --irs + sets the input record separator, --ors the output record separator, and + --rs sets both the input and output separator to the given value. - FUNCTION LIST - ! - != - !=~ - % - & - && - * - ** - + - - - . - .* - .+ - .- - ./ - / - // - < - << - <= - == - =~ - > - >= - >> - >>> - ?: - ?? - ??? - ^ - ^^ - abs - acos - acosh - append - arrayify - asin - asinh - asserting_absent - asserting_array - asserting_bool - asserting_boolean - asserting_empty - asserting_empty_map - asserting_error - asserting_float - asserting_int - asserting_map - asserting_nonempty_map - asserting_not_array - asserting_not_empty - asserting_not_map - asserting_not_null - asserting_null - asserting_numeric - asserting_present - asserting_string - atan - atan2 - atanh - bitcount - boolean - capitalize - cbrt - ceil - clean_whitespace - collapse_whitespace - cos - cosh - depth - dhms2fsec - dhms2sec - erf - erfc - exp - expm1 - flatten - float - floor - fmtnum - fsec2dhms - fsec2hms - get_keys - get_values - gmt2sec - gsub - haskey - hexfmt - hms2fsec - hms2sec - hostname - int - invqnorm - is_absent - is_array - is_bool - is_boolean - is_empty - is_empty_map - is_error - is_float - is_int - is_map - is_nonempty_map - is_not_array - is_not_empty - is_not_map - is_not_null - is_null - is_numeric - is_present - is_string - joink - joinkv - joinv - json_parse - json_stringify - leafcount - length - log - log10 - log1p - logifit - lstrip - madd - mapdiff - mapexcept - mapselect - mapsum - max - md5 - mexp - min - mmul - msub - os - pow - qnorm - regextract - regextract_or_else - round - roundm - rstrip - sec2dhms - sec2gmt - sec2gmtdate - sec2hms - sgn - sha1 - sha256 - sha512 - sin - sinh - splita - splitax - splitkv - splitkvx - splitnv - splitnvx - sqrt - ssub - strftime - string - strip - strlen - strptime - sub - substr - substr0 - substr1 - system - systime - systimeint - tan - tanh - tolower - toupper - truncate - typeof - unflatten - uptime - urand - urand32 - urandint - urandrange - version - | - || - ~ - Please use "mlr --help-function {function name}" for function-specific help. + DATA-FORMAT OPTIONS + --idkvp --odkvp --dkvp Delimited key-value pairs, e.g "a=1,b=2" + (Miller's default format). - I/O FORMATTING - CSV/CSV-lite: comma-separated values with separate header line - TSV: same but with tabs in places of commas - +---------------------+ - | apple,bat,cog | - | 1,2,3 | Record 1: "apple => "1", "bat" => "2", "cog" => "3" - | 4,5,6 | Record 2: "apple" => "4", "bat" => "5", "cog" => "6" - +---------------------+ + --inidx --onidx --nidx Implicitly-integer-indexed fields (Unix-toolkit style). + -T Synonymous with "--nidx --fs tab". - JSON (sequence or array of objects): - +---------------------+ - | { | - | "apple": 1, | Record 1: "apple" => "1", "bat" => "2", "cog" => "3" - | "bat": 2, | - | "cog": 3 | - | } | - | { | - | "dish": { | Record 2: "dish:egg" => "7", "dish:flint" => "8", "garlic" => "" - | "egg": 7, | - | "flint": 8 | - | }, | - | "garlic": "" | - | } | - +---------------------+ + --icsv --ocsv --csv Comma-separated value (or tab-separated with --fs tab, etc.) - PPRINT: pretty-printed tabular - +---------------------+ - | apple bat cog | - | 1 2 3 | Record 1: "apple => "1", "bat" => "2", "cog" => "3" - | 4 5 6 | Record 2: "apple" => "4", "bat" => "5", "cog" => "6" - +---------------------+ + --itsv --otsv --tsv Keystroke-savers for "--icsv --ifs tab", + "--ocsv --ofs tab", "--csv --fs tab". + --iasv --oasv --asv Similar but using ASCII FS 0x1f and RS 0x1e\n", + --iusv --ousv --usv Similar but using Unicode FS U+241F (UTF-8 0xe2909f)\n", + and RS U+241E (UTF-8 0xe2909e)\n", - Markdown tabular (supported for output only): - +-----------------------+ - | | apple | bat | cog | | - | | --- | --- | --- | | - | | 1 | 2 | 3 | | Record 1: "apple => "1", "bat" => "2", "cog" => "3" - | | 4 | 5 | 6 | | Record 2: "apple" => "4", "bat" => "5", "cog" => "6" - +-----------------------+ + --icsvlite --ocsvlite --csvlite Comma-separated value (or tab-separated with --fs tab, etc.). + The 'lite' CSV does not handle RFC-CSV double-quoting rules; is + slightly faster and handles heterogeneity in the input stream via + empty newline followed by new header line. See also + https://johnkerl.org/miller6/file-formats.html#csv-tsv-asv-usv-etc - XTAB: pretty-printed transposed tabular - +---------------------+ - | apple 1 | Record 1: "apple" => "1", "bat" => "2", "cog" => "3" - | bat 2 | - | cog 3 | - | | - | dish 7 | Record 2: "dish" => "7", "egg" => "8" - | egg 8 | - +---------------------+ + --itsvlite --otsvlite --tsvlite Keystroke-savers for "--icsvlite --ifs tab", + "--ocsvlite --ofs tab", "--csvlite --fs tab". + -t Synonymous with --tsvlite. + --iasvlite --oasvlite --asvlite Similar to --itsvlite et al. but using ASCII FS 0x1f and RS 0x1e\n", + --iusvlite --ousvlite --usvlite Similar to --itsvlite et al. but using Unicode FS U+241F (UTF-8 0xe2909f)\n", + and RS U+241E (UTF-8 0xe2909e)\n", - DKVP: delimited key-value pairs (Miller default format) - +---------------------+ - | apple=1,bat=2,cog=3 | Record 1: "apple" => "1", "bat" => "2", "cog" => "3" - | dish=7,egg=8,flint | Record 2: "dish" => "7", "egg" => "8", "3" => "flint" - +---------------------+ + --ipprint --opprint --pprint Pretty-printed tabular (produces no + output until all input is in). + --right Right-justifies all fields for PPRINT output. + --barred Prints a border around PPRINT output + (only available for output). - NIDX: implicitly numerically indexed (Unix-toolkit style) - +---------------------+ - | the quick brown | Record 1: "1" => "the", "2" => "quick", "3" => "brown" - | fox jumped | Record 2: "1" => "fox", "2" => "jumped" - +---------------------+ + --omd Markdown-tabular (only available for output). - COMMENTS IN DATA - --skip-comments Ignore commented lines (prefixed by "#") - within the input. - --skip-comments-with {string} Ignore commented lines within input, with - specified prefix. - --pass-comments Immediately print commented lines (prefixed by "#") - within the input. - --pass-comments-with {string} Immediately print commented lines within input, with - specified prefix. + --ixtab --oxtab --xtab Pretty-printed vertical-tabular. + --xvright Right-justifies values for XTAB format. - Notes: - * Comments are only honored at the start of a line. - * In the absence of any of the above four options, comments are data like - any other text. - * When pass-comments is used, comment lines are written to standard output - immediately upon being read; they are not part of the record stream. Results - may be counterintuitive. A suggestion is to place comments at the start of - data files. + --ijson --ojson --json JSON tabular: sequence or list of one-level + maps: {...}{...} or [{...},{...}]. + --jvstack Put one key-value pair per line for JSON output. + --no-jvstack Put objects/arrays all on one line for JSON output. + --jsonx --ojsonx Keystroke-savers for --json --jvstack + --jsonx --ojsonx and --ojson --jvstack, respectively. + --jlistwrap Wrap JSON output in outermost [ ]. + --oflatsep {string} Separator for flattening multi-level JSON keys, + e.g. '{"a":{"b":3}}' becomes a:b => 3 for + non-JSON formats. Defaults to ..\n", + + -p is a keystroke-saver for --nidx --fs space --repifs + + Examples: --csv for CSV-formatted input and output; --icsv --opprint for + CSV-formatted input and pretty-printed output. + + Please use --iformat1 --oformat2 rather than --format1 --oformat2. + The latter sets up input and output flags for format1, not all of which + are overridden in all cases by setting output format to format2. FORMAT-CONVERSION KEYSTROKE-SAVERS As keystroke-savers for format-conversion you may use the following: @@ -434,6 +245,9 @@ OPTIONS PPRINT, and markdown, respectively. Note that markdown format is available for output only. + SEPARATORS + THIS IS STILL TBD FOR MILLER 6 + COMPRESSED I/O Decompression done within the Miller process itself: --gzin Uncompress gzip within the Miller process. Done by default if file ends in ".gz". @@ -466,8 +280,24 @@ OPTIONS decisions that might have been made based on the file suffix. Also, --gzin/--bz2in/--zin are ignored if --prepipe is also specified. - SEPARATORS - THIS IS STILL TBD FOR MILLER 6 + COMMENTS IN DATA + --skip-comments Ignore commented lines (prefixed by "#") + within the input. + --skip-comments-with {string} Ignore commented lines within input, with + specified prefix. + --pass-comments Immediately print commented lines (prefixed by "#") + within the input. + --pass-comments-with {string} Immediately print commented lines within input, with + specified prefix. + + Notes: + * Comments are only honored at the start of a line. + * In the absence of any of the above four options, comments are data like + any other text. + * When pass-comments is used, comment lines are written to standard output + immediately upon being read; they are not part of the record stream. Results + may be counterintuitive. A suggestion is to place comments at the start of + data files. CSV-SPECIFIC OPTIONS --implicit-csv-header Use 1,2,3,... as field labels, rather than from line 1 @@ -501,7 +331,6 @@ OPTIONS "put '$c = $a . $b'" then field c won't inherit a or b's was-quoted-on-input flag. - NUMBER FORMATTING THIS IS STILL WIP FOR MILLER 6 --ofmt {format} E.g. %.18f, %.0f, %9.6e. Please use sprintf-style codes for @@ -541,7 +370,7 @@ OPTIONS CSV, CSV headers will be present in each output file statistics are only over each file's own records; and so on. - AUXILIARY COMMANDS +AUXILIARY COMMANDS Available subcommands: aux-list hex @@ -553,6 +382,79 @@ OPTIONS repl For more information, please invoke mlr {subcommand} --help. +REPL + Usage: mlr repl [options] {zero or more data-file names} + -v Prints the expressions's AST (abstract syntax tree), which gives + full transparency on the precedence and associativity rules of + Miller's grammar, to stdout. + + -d Like -v but uses a parenthesized-expression format for the AST. + + -D Like -d but with output all on one line. + + -w Show warnings about uninitialized variables + + -q Don't show startup banner + + -s Don't show prompts + + --load {DSL script file} Load script file before presenting the prompt. + If the name following --load is a directory, load all "*.mlr" files + in that directory. + + --mload {DSL script files} -- Like --load but works with more than one filename, + e.g. '--mload *.mlr --'. + + -h|--help Show this message. + + Or any --icsv, --ojson, etc. reader/writer options as for the main Miller command line. + + Any data-file names are opened just as if you had waited and typed :open {filenames} + at the Miller REPL prompt. + +OUTPUT COLORIZATION + Things having colors: + * Keys in CSV header lines, JSON keys, etc + * Values in CSV data lines, JSON scalar values, etc + in regression-test output + * Some online-help strings + + Rules for coloring: + * By default, colorize output only if writing to stdout and stdout is a TTY. + * Example: color: mlr --csv cat foo.csv + * Example: no color: mlr --csv cat foo.csv > bar.csv + * Example: no color: mlr --csv cat foo.csv | less + * The default colors were chosen since they look OK with white or black terminal background, + and are differentiable with common varieties of human color vision. + + Mechanisms for coloring: + * Miller uses ANSI escape sequences only. This does not work on Windows except on Cygwin. + * Requires TERM environment variable to be set to non-empty string. + * Doesn't try to check to see whether the terminal is capable of 256-color + ANSI vs 16-color ANSI. Note that if colors are in the range 0..15 + then 16-color ANSI escapes are used, so this is in the user's control. + + How you can control colorization: + * Suppression/unsuppression: + * Environment variable export MLR_NO_COLOR=true means don't color even if stdout+TTY. + * Environment variable export MLR_ALWAYS_COLOR=true means do color even if not stdout+TTY. + For example, you might want to use this when piping mlr output to less -r. + * Command-line flags --no-color or -M, --always-color or -C. + + * Color choices can be specified by using environment variables, or command-line flags, + with values 0..255: + * export MLR_KEY_COLOR=208, MLR_VALUE_COLOR-33, etc.: + MLR_KEY_COLOR MLR_VALUE_COLOR MLR_PASS_COLOR MLR_FAIL_COLOR + MLR_REPL_PS1_COLOR MLR_REPL_PS2_COLOR MLR_HELP_COLOR + * Command-line flags --key-color 208, --value-color 33, etc.: + --key-color --value-color --pass-color --fail-color + --repl-ps1-color --repl-ps2-color --help-color + * This is particularly useful if your terminal's background color clashes with current settings. + + If environment-variable settings and command-line flags are both provided,the latter take precedence. + + Please do mlr --list-colors to see the available color codes. + MLRRC You can set up personal defaults via a $HOME/.mlrrc and/or ./.mlrrc. For example, if you usually process CSV, then you can put "--csv" in your .mlrrc file @@ -1581,99 +1483,6 @@ VERBS 'a=,b=3,c=4'. FUNCTIONS FOR FILTER/PUT - ! - (class=boolean #args=1) Logical negation. - - != - (class=boolean #args=2) String/numeric inequality. Mixing number and string results in string compare. - - !=~ - (class=boolean #args=2) String (left-hand side) does not match regex (right-hand side), e.g. '$name !=~ "^a.*b$"'. - - % - (class=arithmetic #args=2) Remainder; never negative-valued (pythonic). - - & - (class=arithmetic #args=2) Bitwise AND. - - && - (class=boolean #args=2) Logical AND. - - * - (class=arithmetic #args=2) Multiplication, with integer*integer overflow to float. - - ** - (class=arithmetic #args=2) Exponentiation. Same as pow, but as an infix operator. - - + - (class=arithmetic #args=1,2) Addition as binary operator; unary plus operator. - - - - (class=arithmetic #args=1,2) Subtraction as binary operator; unary negation operator. - - . - (class=string #args=2) String concatenation. - - .* - (class=arithmetic #args=2) Multiplication, with integer-to-integer overflow. - - .+ - (class=arithmetic #args=2) Addition, with integer-to-integer overflow. - - .- - (class=arithmetic #args=2) Subtraction, with integer-to-integer overflow. - - ./ - (class=arithmetic #args=2) Integer division; not pythonic. - - / - (class=arithmetic #args=2) Division. Integer / integer is floating-point. - - // - (class=arithmetic #args=2) Pythonic integer division, rounding toward negative. - - < - (class=boolean #args=2) String/numeric less-than. Mixing number and string results in string compare. - - << - (class=arithmetic #args=2) Bitwise left-shift. - - <= - (class=boolean #args=2) String/numeric less-than-or-equals. Mixing number and string results in string compare. - - == - (class=boolean #args=2) String/numeric equality. Mixing number and string results in string compare. - - =~ - (class=boolean #args=2) String (left-hand side) matches regex (right-hand side), e.g. '$name =~ "^a.*b$"'. - - > - (class=boolean #args=2) String/numeric greater-than. Mixing number and string results in string compare. - - >= - (class=boolean #args=2) String/numeric greater-than-or-equals. Mixing number and string results in string compare. - - >> - (class=arithmetic #args=2) Bitwise signed right-shift. - - >>> - (class=arithmetic #args=2) Bitwise unsigned right-shift. - - ?: - (class=boolean #args=3) Standard ternary operator. - - ?? - (class=boolean #args=2) Absent-coalesce operator. $a ?? 1 evaluates to 1 if $a isn't defined in the current record. - - ??? - (class=boolean #args=2) Absent-coalesce operator. $a ?? 1 evaluates to 1 if $a isn't defined in the current record, or has empty value. - - ^ - (class=arithmetic #args=2) Bitwise XOR. - - ^^ - (class=boolean #args=2) Logical XOR. - abs (class=math #args=1) Absolute value. @@ -2217,6 +2026,99 @@ FUNCTIONS FOR FILTER/PUT version (class=system #args=0) Returns the Miller version as a string. + ! + (class=boolean #args=1) Logical negation. + + != + (class=boolean #args=2) String/numeric inequality. Mixing number and string results in string compare. + + !=~ + (class=boolean #args=2) String (left-hand side) does not match regex (right-hand side), e.g. '$name !=~ "^a.*b$"'. + + % + (class=arithmetic #args=2) Remainder; never negative-valued (pythonic). + + & + (class=arithmetic #args=2) Bitwise AND. + + && + (class=boolean #args=2) Logical AND. + + * + (class=arithmetic #args=2) Multiplication, with integer*integer overflow to float. + + ** + (class=arithmetic #args=2) Exponentiation. Same as pow, but as an infix operator. + + + + (class=arithmetic #args=1,2) Addition as binary operator; unary plus operator. + + - + (class=arithmetic #args=1,2) Subtraction as binary operator; unary negation operator. + + . + (class=string #args=2) String concatenation. + + .* + (class=arithmetic #args=2) Multiplication, with integer-to-integer overflow. + + .+ + (class=arithmetic #args=2) Addition, with integer-to-integer overflow. + + .- + (class=arithmetic #args=2) Subtraction, with integer-to-integer overflow. + + ./ + (class=arithmetic #args=2) Integer division; not pythonic. + + / + (class=arithmetic #args=2) Division. Integer / integer is floating-point. + + // + (class=arithmetic #args=2) Pythonic integer division, rounding toward negative. + + < + (class=boolean #args=2) String/numeric less-than. Mixing number and string results in string compare. + + << + (class=arithmetic #args=2) Bitwise left-shift. + + <= + (class=boolean #args=2) String/numeric less-than-or-equals. Mixing number and string results in string compare. + + == + (class=boolean #args=2) String/numeric equality. Mixing number and string results in string compare. + + =~ + (class=boolean #args=2) String (left-hand side) matches regex (right-hand side), e.g. '$name =~ "^a.*b$"'. + + > + (class=boolean #args=2) String/numeric greater-than. Mixing number and string results in string compare. + + >= + (class=boolean #args=2) String/numeric greater-than-or-equals. Mixing number and string results in string compare. + + >> + (class=arithmetic #args=2) Bitwise signed right-shift. + + >>> + (class=arithmetic #args=2) Bitwise unsigned right-shift. + + ?: + (class=boolean #args=3) Standard ternary operator. + + ?? + (class=boolean #args=2) Absent-coalesce operator. $a ?? 1 evaluates to 1 if $a isn't defined in the current record. + + ??? + (class=boolean #args=2) Absent-coalesce operator. $a ?? 1 evaluates to 1 if $a isn't defined in the current record, or has empty value. + + ^ + (class=arithmetic #args=2) Bitwise XOR. + + ^^ + (class=boolean #args=2) Logical XOR. + | (class=arithmetic #args=2) Bitwise OR. @@ -2602,4 +2504,4 @@ SEE ALSO - 2021-06-28 MILLER(1) + 2021-07-01 MILLER(1) diff --git a/man6/mkman.rb b/man6/mkman.rb index d7d3ca2b7..f522a8fd9 100755 --- a/man6/mkman.rb +++ b/man6/mkman.rb @@ -43,6 +43,15 @@ a special case.) This manpage documents #{`mlr --version`.chomp}.""" print make_section('DATA FORMATS', []) print make_code_block(`mlr help data-formats`) + print make_section('VERB LIST', []) + print make_code_block(`mlr help list-verbs-as-paragraph`) + + print make_section('FUNCTION LIST', []) + print make_code_block(`mlr help list-functions-as-paragraph`) + + print make_section('HELP OPTIONS', []) + print make_code_block(`mlr help topics`) + print make_section('OPTIONS', [ """In the following option flags, the version with \"i\" designates the input stream, \"o\" the output stream, and the version without prefix sets the option @@ -51,31 +60,20 @@ separator, --ors the output record separator, and --rs sets both the input and output separator to the given value.""" ]) - # TODO: output colorization and repl - print make_subsection('HELP OPTIONS', []) - print make_code_block(`mlr help topics`) - - print make_subsection('VERB LIST', []) - print make_code_block(`mlr help list-verbs`) - - print make_subsection('FUNCTION LIST', []) - # TODO: list as paragraph - print make_code_block(`mlr help list-functions`) - - print make_subsection('I/O FORMATTING', []) - print make_code_block(`mlr help data-formats`) - - print make_subsection('COMMENTS IN DATA', []) - print make_code_block(`mlr help comments-in-data`) + print make_subsection('DATA-FORMAT OPTIONS', []) + print make_code_block(`mlr help data-format-options`) print make_subsection('FORMAT-CONVERSION KEYSTROKE-SAVERS', []) print make_code_block(`mlr help format-conversion`) + print make_subsection('SEPARATORS', []) + print make_code_block(`mlr help separator-options`) + print make_subsection('COMPRESSED I/O', []) print make_code_block(`mlr help compressed-data`) - print make_subsection('SEPARATORS', []) - print make_code_block(`mlr help separator-options`) + print make_subsection('COMMENTS IN DATA', []) + print make_code_block(`mlr help comments-in-data`) print make_subsection('CSV-SPECIFIC OPTIONS', []) print make_code_block(`mlr help csv-options`) @@ -89,13 +87,19 @@ output separator to the given value.""" print make_subsection('OTHER OPTIONS', []) print make_code_block(`mlr help misc`) - print make_subsection('AUXILIARY COMMANDS', []) + print make_section('AUXILIARY COMMANDS', []) print make_code_block(`mlr aux-list`) + print make_section('REPL', []) + print make_code_block(`mlr repl -h`) + + print make_section('OUTPUT COLORIZATION', []) + print make_code_block(`mlr help output-colorization`) + print make_section('MLRRC', []) print make_code_block(`mlr help mlrrc`) - verbs = `mlr help list-verbs-vertically` + verbs = `mlr help list-verbs` print make_section('VERBS', [ "" ]) @@ -105,7 +109,7 @@ output separator to the given value.""" print make_code_block(`mlr #{verb} -h`) end - functions = `mlr help list-functions-vertically` + functions = `mlr help list-functions` print make_section('FUNCTIONS FOR FILTER/PUT', [ "" ]) diff --git a/man6/mlr6.1 b/man6/mlr6.1 index 5755a61ff..80a8d9364 100644 --- a/man6/mlr6.1 +++ b/man6/mlr6.1 @@ -2,12 +2,12 @@ .\" Title: mlr .\" Author: [see the "AUTHOR" section] .\" Generator: ./mkman.rb -.\" Date: 2021-06-28 +.\" Date: 2021-07-01 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" -.TH "MILLER" "1" "2021-06-28" "\ \&" "\ \&" +.TH "MILLER" "1" "2021-07-01" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Portability definitions .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -128,14 +128,52 @@ NIDX: implicitly numerically indexed (Unix-toolkit style) .fi .if n \{\ .RE -.SH "OPTIONS" -.sp -In the following option flags, the version with "i" designates the input -stream, "o" the output stream, and the version without prefix sets the option -for both input and output stream. For example: --irs sets the input record -separator, --ors the output record separator, and --rs sets both the input and -output separator to the given value. -.SS "HELP OPTIONS" +.SH "VERB LIST" +.if n \{\ +.RS 0 +.\} +.nf +altkv bar bootstrap cat check clean-whitespace count-distinct count +count-similar cut decimate fill-down fill-empty filter flatten format-values +fraction gap grep group-by group-like having-fields head histogram json-parse +json-stringify join label least-frequent merge-fields most-frequent nest +nothing put regularize remove-empty-columns rename reorder repeat reshape +sample sec2gmtdate sec2gmt seqgen shuffle skip-trivial-records sort +sort-within-records stats1 stats2 step tac tail tee top unflatten uniq +unsparsify +.fi +.if n \{\ +.RE +.SH "FUNCTION LIST" +.if n \{\ +.RS 0 +.\} +.nf +abs acos acosh append arrayify asin asinh asserting_absent asserting_array +asserting_bool asserting_boolean asserting_empty asserting_empty_map +asserting_error asserting_float asserting_int asserting_map +asserting_nonempty_map asserting_not_array asserting_not_empty +asserting_not_map asserting_not_null asserting_null asserting_numeric +asserting_present asserting_string atan atan2 atanh bitcount boolean +capitalize cbrt ceil clean_whitespace collapse_whitespace cos cosh depth +dhms2fsec dhms2sec erf erfc exp expm1 flatten float floor fmtnum fsec2dhms +fsec2hms get_keys get_values gmt2sec gsub haskey hexfmt hms2fsec hms2sec +hostname int invqnorm is_absent is_array is_bool is_boolean is_empty +is_empty_map is_error is_float is_int is_map is_nonempty_map is_not_array +is_not_empty is_not_map is_not_null is_null is_numeric is_present is_string +joink joinkv joinv json_parse json_stringify leafcount length log log10 log1p +logifit lstrip madd mapdiff mapexcept mapselect mapsum max md5 mexp min mmul +msub os pow qnorm regextract regextract_or_else round roundm rstrip sec2dhms +sec2gmt sec2gmtdate sec2hms sgn sha1 sha256 sha512 sin sinh splita splitax +splitkv splitkvx splitnv splitnvx sqrt ssub strftime string strip strlen +strptime sub substr substr0 substr1 system systime systimeint tan tanh tolower +toupper truncate typeof unflatten uptime urand urand32 urandint urandrange +version ! != !=~ % & && * ** + - . .* .+ .- ./ / // < << <= == =~ > >= >> >>> +?: ?? ??? ^ ^^ | || ~ +.fi +.if n \{\ +.RE +.SH "HELP OPTIONS" .if n \{\ .RS 0 .\} @@ -154,333 +192,100 @@ Type 'mlr help {topic}' for any of the following: mlr help function mlr help keyword mlr help list-functions - mlr help list-functions-vertically + mlr help list-functions-as-paragraph mlr help list-keywords + mlr help list-keywords-as-paragraph mlr help list-verbs - mlr help list-verbs-vertically + mlr help list-verbs-as-paragraph mlr help misc mlr help mlrrc mlr help number-formatting - mlr help output-colorizations + mlr help output-colorization mlr help separator-options + mlr help type-arithmetic-info mlr help usage-functions mlr help usage-keywords mlr help usage-verbs mlr help verb Shorthands: mlr -l = mlr help list-verbs - mlr -L = mlr help list-verbs-vertically - mlr -f = mlr help usage-functions - mlr -F = mlr help list-functions - mlr -k = mlr help usage-keywords - mlr -K = mlr help list-keywords + mlr -L = mlr help usage-verbs + mlr -f = mlr help list-functions + mlr -F = mlr help usage-functions + mlr -k = mlr help list-keywords + mlr -K = mlr help usage-keywords .fi .if n \{\ .RE -.SS "VERB LIST" +.SH "OPTIONS" +.sp +In the following option flags, the version with "i" designates the input +stream, "o" the output stream, and the version without prefix sets the option +for both input and output stream. For example: --irs sets the input record +separator, --ors the output record separator, and --rs sets both the input and +output separator to the given value. +.SS "DATA-FORMAT OPTIONS" .if n \{\ .RS 0 .\} .nf -altkv bar bootstrap cat check clean-whitespace count-distinct count -count-similar cut decimate fill-down fill-empty filter flatten format-values -fraction gap grep group-by group-like having-fields head histogram json-parse -json-stringify join label least-frequent merge-fields most-frequent nest -nothing put regularize remove-empty-columns rename reorder repeat reshape -sample sec2gmtdate sec2gmt seqgen shuffle skip-trivial-records sort -sort-within-records stats1 stats2 step tac tail tee top unflatten uniq -unsparsify -.fi -.if n \{\ -.RE -.SS "FUNCTION LIST" -.if n \{\ -.RS 0 -.\} -.nf -! -!= -!=~ -% -& -&& -* -** -+ -- -\&. -\&.* -\&.+ -\&.- -\&./ -/ -// -< -<< -<= -== -=~ -> ->= ->> ->>> -?: -?? -??? -^ -^^ -abs -acos -acosh -append -arrayify -asin -asinh -asserting_absent -asserting_array -asserting_bool -asserting_boolean -asserting_empty -asserting_empty_map -asserting_error -asserting_float -asserting_int -asserting_map -asserting_nonempty_map -asserting_not_array -asserting_not_empty -asserting_not_map -asserting_not_null -asserting_null -asserting_numeric -asserting_present -asserting_string -atan -atan2 -atanh -bitcount -boolean -capitalize -cbrt -ceil -clean_whitespace -collapse_whitespace -cos -cosh -depth -dhms2fsec -dhms2sec -erf -erfc -exp -expm1 -flatten -float -floor -fmtnum -fsec2dhms -fsec2hms -get_keys -get_values -gmt2sec -gsub -haskey -hexfmt -hms2fsec -hms2sec -hostname -int -invqnorm -is_absent -is_array -is_bool -is_boolean -is_empty -is_empty_map -is_error -is_float -is_int -is_map -is_nonempty_map -is_not_array -is_not_empty -is_not_map -is_not_null -is_null -is_numeric -is_present -is_string -joink -joinkv -joinv -json_parse -json_stringify -leafcount -length -log -log10 -log1p -logifit -lstrip -madd -mapdiff -mapexcept -mapselect -mapsum -max -md5 -mexp -min -mmul -msub -os -pow -qnorm -regextract -regextract_or_else -round -roundm -rstrip -sec2dhms -sec2gmt -sec2gmtdate -sec2hms -sgn -sha1 -sha256 -sha512 -sin -sinh -splita -splitax -splitkv -splitkvx -splitnv -splitnvx -sqrt -ssub -strftime -string -strip -strlen -strptime -sub -substr -substr0 -substr1 -system -systime -systimeint -tan -tanh -tolower -toupper -truncate -typeof -unflatten -uptime -urand -urand32 -urandint -urandrange -version -| -|| -~ -Please use "mlr --help-function {function name}" for function-specific help. -.fi -.if n \{\ -.RE -.SS "I/O FORMATTING" -.if n \{\ -.RS 0 -.\} -.nf -CSV/CSV-lite: comma-separated values with separate header line -TSV: same but with tabs in places of commas -+---------------------+ -| apple,bat,cog | -| 1,2,3 | Record 1: "apple => "1", "bat" => "2", "cog" => "3" -| 4,5,6 | Record 2: "apple" => "4", "bat" => "5", "cog" => "6" -+---------------------+ +--idkvp --odkvp --dkvp Delimited key-value pairs, e.g "a=1,b=2" + (Miller's default format). -JSON (sequence or array of objects): -+---------------------+ -| { | -| "apple": 1, | Record 1: "apple" => "1", "bat" => "2", "cog" => "3" -| "bat": 2, | -| "cog": 3 | -| } | -| { | -| "dish": { | Record 2: "dish:egg" => "7", "dish:flint" => "8", "garlic" => "" -| "egg": 7, | -| "flint": 8 | -| }, | -| "garlic": "" | -| } | -+---------------------+ +--inidx --onidx --nidx Implicitly-integer-indexed fields (Unix-toolkit style). +-T Synonymous with "--nidx --fs tab". -PPRINT: pretty-printed tabular -+---------------------+ -| apple bat cog | -| 1 2 3 | Record 1: "apple => "1", "bat" => "2", "cog" => "3" -| 4 5 6 | Record 2: "apple" => "4", "bat" => "5", "cog" => "6" -+---------------------+ +--icsv --ocsv --csv Comma-separated value (or tab-separated with --fs tab, etc.) -Markdown tabular (supported for output only): -+-----------------------+ -| | apple | bat | cog | | -| | --- | --- | --- | | -| | 1 | 2 | 3 | | Record 1: "apple => "1", "bat" => "2", "cog" => "3" -| | 4 | 5 | 6 | | Record 2: "apple" => "4", "bat" => "5", "cog" => "6" -+-----------------------+ +--itsv --otsv --tsv Keystroke-savers for "--icsv --ifs tab", + "--ocsv --ofs tab", "--csv --fs tab". +--iasv --oasv --asv Similar but using ASCII FS 0x1f and RS 0x1e\en", +--iusv --ousv --usv Similar but using Unicode FS U+241F (UTF-8 0xe2909f)\en", + and RS U+241E (UTF-8 0xe2909e)\en", -XTAB: pretty-printed transposed tabular -+---------------------+ -| apple 1 | Record 1: "apple" => "1", "bat" => "2", "cog" => "3" -| bat 2 | -| cog 3 | -| | -| dish 7 | Record 2: "dish" => "7", "egg" => "8" -| egg 8 | -+---------------------+ +--icsvlite --ocsvlite --csvlite Comma-separated value (or tab-separated with --fs tab, etc.). + The 'lite' CSV does not handle RFC-CSV double-quoting rules; is + slightly faster and handles heterogeneity in the input stream via + empty newline followed by new header line. See also + https://johnkerl.org/miller6/file-formats.html#csv-tsv-asv-usv-etc -DKVP: delimited key-value pairs (Miller default format) -+---------------------+ -| apple=1,bat=2,cog=3 | Record 1: "apple" => "1", "bat" => "2", "cog" => "3" -| dish=7,egg=8,flint | Record 2: "dish" => "7", "egg" => "8", "3" => "flint" -+---------------------+ +--itsvlite --otsvlite --tsvlite Keystroke-savers for "--icsvlite --ifs tab", + "--ocsvlite --ofs tab", "--csvlite --fs tab". +-t Synonymous with --tsvlite. +--iasvlite --oasvlite --asvlite Similar to --itsvlite et al. but using ASCII FS 0x1f and RS 0x1e\en", +--iusvlite --ousvlite --usvlite Similar to --itsvlite et al. but using Unicode FS U+241F (UTF-8 0xe2909f)\en", + and RS U+241E (UTF-8 0xe2909e)\en", -NIDX: implicitly numerically indexed (Unix-toolkit style) -+---------------------+ -| the quick brown | Record 1: "1" => "the", "2" => "quick", "3" => "brown" -| fox jumped | Record 2: "1" => "fox", "2" => "jumped" -+---------------------+ -.fi -.if n \{\ -.RE -.SS "COMMENTS IN DATA" -.if n \{\ -.RS 0 -.\} -.nf ---skip-comments Ignore commented lines (prefixed by "#") - within the input. ---skip-comments-with {string} Ignore commented lines within input, with - specified prefix. ---pass-comments Immediately print commented lines (prefixed by "#") - within the input. ---pass-comments-with {string} Immediately print commented lines within input, with - specified prefix. +--ipprint --opprint --pprint Pretty-printed tabular (produces no + output until all input is in). + --right Right-justifies all fields for PPRINT output. + --barred Prints a border around PPRINT output + (only available for output). -Notes: -* Comments are only honored at the start of a line. -* In the absence of any of the above four options, comments are data like - any other text. -* When pass-comments is used, comment lines are written to standard output - immediately upon being read; they are not part of the record stream. Results - may be counterintuitive. A suggestion is to place comments at the start of - data files. + --omd Markdown-tabular (only available for output). + +--ixtab --oxtab --xtab Pretty-printed vertical-tabular. + --xvright Right-justifies values for XTAB format. + +--ijson --ojson --json JSON tabular: sequence or list of one-level + maps: {...}{...} or [{...},{...}]. + --jvstack Put one key-value pair per line for JSON output. + --no-jvstack Put objects/arrays all on one line for JSON output. + --jsonx --ojsonx Keystroke-savers for --json --jvstack + --jsonx --ojsonx and --ojson --jvstack, respectively. + --jlistwrap Wrap JSON output in outermost [ ]. + --oflatsep {string} Separator for flattening multi-level JSON keys, + e.g. '{"a":{"b":3}}' becomes a:b => 3 for + non-JSON formats. Defaults to ..\en", + +-p is a keystroke-saver for --nidx --fs space --repifs + +Examples: --csv for CSV-formatted input and output; --icsv --opprint for +CSV-formatted input and pretty-printed output. + +Please use --iformat1 --oformat2 rather than --format1 --oformat2. +The latter sets up input and output flags for format1, not all of which +are overridden in all cases by setting output format to format2. .fi .if n \{\ .RE @@ -503,6 +308,15 @@ output only. .fi .if n \{\ .RE +.SS "SEPARATORS" +.if n \{\ +.RS 0 +.\} +.nf +THIS IS STILL TBD FOR MILLER 6 +.fi +.if n \{\ +.RE .SS "COMPRESSED I/O" .if n \{\ .RS 0 @@ -541,12 +355,28 @@ decisions that might have been made based on the file suffix. Also, .fi .if n \{\ .RE -.SS "SEPARATORS" +.SS "COMMENTS IN DATA" .if n \{\ .RS 0 .\} .nf -THIS IS STILL TBD FOR MILLER 6 +--skip-comments Ignore commented lines (prefixed by "#") + within the input. +--skip-comments-with {string} Ignore commented lines within input, with + specified prefix. +--pass-comments Immediately print commented lines (prefixed by "#") + within the input. +--pass-comments-with {string} Immediately print commented lines within input, with + specified prefix. + +Notes: +* Comments are only honored at the start of a line. +* In the absence of any of the above four options, comments are data like + any other text. +* When pass-comments is used, comment lines are written to standard output + immediately upon being read; they are not part of the record stream. Results + may be counterintuitive. A suggestion is to place comments at the start of + data files. .fi .if n \{\ .RE @@ -591,7 +421,6 @@ THIS IS STILL WIP FOR MILLER 6 e.g. if fields a and b were quoted on input and you do "put '$c = $a . $b'" then field c won't inherit a or b's was-quoted-on-input flag. - .fi .if n \{\ .RE @@ -646,7 +475,7 @@ THIS IS STILL WIP FOR MILLER 6 .fi .if n \{\ .RE -.SS "AUXILIARY COMMANDS" +.SH "AUXILIARY COMMANDS" .if n \{\ .RS 0 .\} @@ -664,6 +493,91 @@ For more information, please invoke mlr {subcommand} --help. .fi .if n \{\ .RE +.SH "REPL" +.if n \{\ +.RS 0 +.\} +.nf +Usage: mlr repl [options] {zero or more data-file names} +-v Prints the expressions's AST (abstract syntax tree), which gives + full transparency on the precedence and associativity rules of + Miller's grammar, to stdout. + +-d Like -v but uses a parenthesized-expression format for the AST. + +-D Like -d but with output all on one line. + +-w Show warnings about uninitialized variables + +-q Don't show startup banner + +-s Don't show prompts + +--load {DSL script file} Load script file before presenting the prompt. + If the name following --load is a directory, load all "*.mlr" files + in that directory. + +--mload {DSL script files} -- Like --load but works with more than one filename, + e.g. '--mload *.mlr --'. + +-h|--help Show this message. + +Or any --icsv, --ojson, etc. reader/writer options as for the main Miller command line. + +Any data-file names are opened just as if you had waited and typed :open {filenames} +at the Miller REPL prompt. +.fi +.if n \{\ +.RE +.SH "OUTPUT COLORIZATION" +.if n \{\ +.RS 0 +.\} +.nf +Things having colors: +* Keys in CSV header lines, JSON keys, etc +* Values in CSV data lines, JSON scalar values, etc + in regression-test output +* Some online-help strings + +Rules for coloring: +* By default, colorize output only if writing to stdout and stdout is a TTY. + * Example: color: mlr --csv cat foo.csv + * Example: no color: mlr --csv cat foo.csv > bar.csv + * Example: no color: mlr --csv cat foo.csv | less +* The default colors were chosen since they look OK with white or black terminal background, + and are differentiable with common varieties of human color vision. + +Mechanisms for coloring: +* Miller uses ANSI escape sequences only. This does not work on Windows except on Cygwin. +* Requires TERM environment variable to be set to non-empty string. +* Doesn't try to check to see whether the terminal is capable of 256-color + ANSI vs 16-color ANSI. Note that if colors are in the range 0..15 + then 16-color ANSI escapes are used, so this is in the user's control. + +How you can control colorization: +* Suppression/unsuppression: + * Environment variable export MLR_NO_COLOR=true means don't color even if stdout+TTY. + * Environment variable export MLR_ALWAYS_COLOR=true means do color even if not stdout+TTY. + For example, you might want to use this when piping mlr output to less -r. + * Command-line flags --no-color or -M, --always-color or -C. + +* Color choices can be specified by using environment variables, or command-line flags, + with values 0..255: + * export MLR_KEY_COLOR=208, MLR_VALUE_COLOR-33, etc.: + MLR_KEY_COLOR MLR_VALUE_COLOR MLR_PASS_COLOR MLR_FAIL_COLOR + MLR_REPL_PS1_COLOR MLR_REPL_PS2_COLOR MLR_HELP_COLOR + * Command-line flags --key-color 208, --value-color 33, etc.: + --key-color --value-color --pass-color --fail-color + --repl-ps1-color --repl-ps2-color --help-color + * This is particularly useful if your terminal's background color clashes with current settings. + +If environment-variable settings and command-line flags are both provided,the latter take precedence. + +Please do mlr --list-colors to see the available color codes. +.fi +.if n \{\ +.RE .SH "MLRRC" .if n \{\ .RS 0 @@ -2050,285 +1964,6 @@ being 'b=3,c=4', then the output is the two records 'a=1,b=2,c=' and .SH "FUNCTIONS FOR FILTER/PUT" .sp -.SS "!" -.if n \{\ -.RS 0 -.\} -.nf - (class=boolean #args=1) Logical negation. -.fi -.if n \{\ -.RE -.SS "!=" -.if n \{\ -.RS 0 -.\} -.nf - (class=boolean #args=2) String/numeric inequality. Mixing number and string results in string compare. -.fi -.if n \{\ -.RE -.SS "!=~" -.if n \{\ -.RS 0 -.\} -.nf - (class=boolean #args=2) String (left-hand side) does not match regex (right-hand side), e.g. '$name !=~ "^a.*b$"'. -.fi -.if n \{\ -.RE -.SS "%" -.if n \{\ -.RS 0 -.\} -.nf - (class=arithmetic #args=2) Remainder; never negative-valued (pythonic). -.fi -.if n \{\ -.RE -.SS "&" -.if n \{\ -.RS 0 -.\} -.nf - (class=arithmetic #args=2) Bitwise AND. -.fi -.if n \{\ -.RE -.SS "&&" -.if n \{\ -.RS 0 -.\} -.nf - (class=boolean #args=2) Logical AND. -.fi -.if n \{\ -.RE -.SS "*" -.if n \{\ -.RS 0 -.\} -.nf - (class=arithmetic #args=2) Multiplication, with integer*integer overflow to float. -.fi -.if n \{\ -.RE -.SS "**" -.if n \{\ -.RS 0 -.\} -.nf - (class=arithmetic #args=2) Exponentiation. Same as pow, but as an infix operator. -.fi -.if n \{\ -.RE -.SS "+" -.if n \{\ -.RS 0 -.\} -.nf - (class=arithmetic #args=1,2) Addition as binary operator; unary plus operator. -.fi -.if n \{\ -.RE -.SS "-" -.if n \{\ -.RS 0 -.\} -.nf - (class=arithmetic #args=1,2) Subtraction as binary operator; unary negation operator. -.fi -.if n \{\ -.RE -.SS "." -.if n \{\ -.RS 0 -.\} -.nf - (class=string #args=2) String concatenation. -.fi -.if n \{\ -.RE -.SS ".*" -.if n \{\ -.RS 0 -.\} -.nf - (class=arithmetic #args=2) Multiplication, with integer-to-integer overflow. -.fi -.if n \{\ -.RE -.SS ".+" -.if n \{\ -.RS 0 -.\} -.nf - (class=arithmetic #args=2) Addition, with integer-to-integer overflow. -.fi -.if n \{\ -.RE -.SS ".-" -.if n \{\ -.RS 0 -.\} -.nf - (class=arithmetic #args=2) Subtraction, with integer-to-integer overflow. -.fi -.if n \{\ -.RE -.SS "./" -.if n \{\ -.RS 0 -.\} -.nf - (class=arithmetic #args=2) Integer division; not pythonic. -.fi -.if n \{\ -.RE -.SS "/" -.if n \{\ -.RS 0 -.\} -.nf - (class=arithmetic #args=2) Division. Integer / integer is floating-point. -.fi -.if n \{\ -.RE -.SS "//" -.if n \{\ -.RS 0 -.\} -.nf - (class=arithmetic #args=2) Pythonic integer division, rounding toward negative. -.fi -.if n \{\ -.RE -.SS "<" -.if n \{\ -.RS 0 -.\} -.nf - (class=boolean #args=2) String/numeric less-than. Mixing number and string results in string compare. -.fi -.if n \{\ -.RE -.SS "<<" -.if n \{\ -.RS 0 -.\} -.nf - (class=arithmetic #args=2) Bitwise left-shift. -.fi -.if n \{\ -.RE -.SS "<=" -.if n \{\ -.RS 0 -.\} -.nf - (class=boolean #args=2) String/numeric less-than-or-equals. Mixing number and string results in string compare. -.fi -.if n \{\ -.RE -.SS "==" -.if n \{\ -.RS 0 -.\} -.nf - (class=boolean #args=2) String/numeric equality. Mixing number and string results in string compare. -.fi -.if n \{\ -.RE -.SS "=~" -.if n \{\ -.RS 0 -.\} -.nf - (class=boolean #args=2) String (left-hand side) matches regex (right-hand side), e.g. '$name =~ "^a.*b$"'. -.fi -.if n \{\ -.RE -.SS ">" -.if n \{\ -.RS 0 -.\} -.nf - (class=boolean #args=2) String/numeric greater-than. Mixing number and string results in string compare. -.fi -.if n \{\ -.RE -.SS ">=" -.if n \{\ -.RS 0 -.\} -.nf - (class=boolean #args=2) String/numeric greater-than-or-equals. Mixing number and string results in string compare. -.fi -.if n \{\ -.RE -.SS ">>" -.if n \{\ -.RS 0 -.\} -.nf - (class=arithmetic #args=2) Bitwise signed right-shift. -.fi -.if n \{\ -.RE -.SS ">>>" -.if n \{\ -.RS 0 -.\} -.nf - (class=arithmetic #args=2) Bitwise unsigned right-shift. -.fi -.if n \{\ -.RE -.SS "?:" -.if n \{\ -.RS 0 -.\} -.nf - (class=boolean #args=3) Standard ternary operator. -.fi -.if n \{\ -.RE -.SS "??" -.if n \{\ -.RS 0 -.\} -.nf - (class=boolean #args=2) Absent-coalesce operator. $a ?? 1 evaluates to 1 if $a isn't defined in the current record. -.fi -.if n \{\ -.RE -.SS "???" -.if n \{\ -.RS 0 -.\} -.nf - (class=boolean #args=2) Absent-coalesce operator. $a ?? 1 evaluates to 1 if $a isn't defined in the current record, or has empty value. -.fi -.if n \{\ -.RE -.SS "^" -.if n \{\ -.RS 0 -.\} -.nf - (class=arithmetic #args=2) Bitwise XOR. -.fi -.if n \{\ -.RE -.SS "^^" -.if n \{\ -.RS 0 -.\} -.nf - (class=boolean #args=2) Logical XOR. -.fi -.if n \{\ -.RE .SS "abs" .if n \{\ .RS 0 @@ -3802,6 +3437,285 @@ Int-valued example: '$n=floor(20+urand()*11)'. .fi .if n \{\ .RE +.SS "!" +.if n \{\ +.RS 0 +.\} +.nf + (class=boolean #args=1) Logical negation. +.fi +.if n \{\ +.RE +.SS "!=" +.if n \{\ +.RS 0 +.\} +.nf + (class=boolean #args=2) String/numeric inequality. Mixing number and string results in string compare. +.fi +.if n \{\ +.RE +.SS "!=~" +.if n \{\ +.RS 0 +.\} +.nf + (class=boolean #args=2) String (left-hand side) does not match regex (right-hand side), e.g. '$name !=~ "^a.*b$"'. +.fi +.if n \{\ +.RE +.SS "%" +.if n \{\ +.RS 0 +.\} +.nf + (class=arithmetic #args=2) Remainder; never negative-valued (pythonic). +.fi +.if n \{\ +.RE +.SS "&" +.if n \{\ +.RS 0 +.\} +.nf + (class=arithmetic #args=2) Bitwise AND. +.fi +.if n \{\ +.RE +.SS "&&" +.if n \{\ +.RS 0 +.\} +.nf + (class=boolean #args=2) Logical AND. +.fi +.if n \{\ +.RE +.SS "*" +.if n \{\ +.RS 0 +.\} +.nf + (class=arithmetic #args=2) Multiplication, with integer*integer overflow to float. +.fi +.if n \{\ +.RE +.SS "**" +.if n \{\ +.RS 0 +.\} +.nf + (class=arithmetic #args=2) Exponentiation. Same as pow, but as an infix operator. +.fi +.if n \{\ +.RE +.SS "+" +.if n \{\ +.RS 0 +.\} +.nf + (class=arithmetic #args=1,2) Addition as binary operator; unary plus operator. +.fi +.if n \{\ +.RE +.SS "-" +.if n \{\ +.RS 0 +.\} +.nf + (class=arithmetic #args=1,2) Subtraction as binary operator; unary negation operator. +.fi +.if n \{\ +.RE +.SS "." +.if n \{\ +.RS 0 +.\} +.nf + (class=string #args=2) String concatenation. +.fi +.if n \{\ +.RE +.SS ".*" +.if n \{\ +.RS 0 +.\} +.nf + (class=arithmetic #args=2) Multiplication, with integer-to-integer overflow. +.fi +.if n \{\ +.RE +.SS ".+" +.if n \{\ +.RS 0 +.\} +.nf + (class=arithmetic #args=2) Addition, with integer-to-integer overflow. +.fi +.if n \{\ +.RE +.SS ".-" +.if n \{\ +.RS 0 +.\} +.nf + (class=arithmetic #args=2) Subtraction, with integer-to-integer overflow. +.fi +.if n \{\ +.RE +.SS "./" +.if n \{\ +.RS 0 +.\} +.nf + (class=arithmetic #args=2) Integer division; not pythonic. +.fi +.if n \{\ +.RE +.SS "/" +.if n \{\ +.RS 0 +.\} +.nf + (class=arithmetic #args=2) Division. Integer / integer is floating-point. +.fi +.if n \{\ +.RE +.SS "//" +.if n \{\ +.RS 0 +.\} +.nf + (class=arithmetic #args=2) Pythonic integer division, rounding toward negative. +.fi +.if n \{\ +.RE +.SS "<" +.if n \{\ +.RS 0 +.\} +.nf + (class=boolean #args=2) String/numeric less-than. Mixing number and string results in string compare. +.fi +.if n \{\ +.RE +.SS "<<" +.if n \{\ +.RS 0 +.\} +.nf + (class=arithmetic #args=2) Bitwise left-shift. +.fi +.if n \{\ +.RE +.SS "<=" +.if n \{\ +.RS 0 +.\} +.nf + (class=boolean #args=2) String/numeric less-than-or-equals. Mixing number and string results in string compare. +.fi +.if n \{\ +.RE +.SS "==" +.if n \{\ +.RS 0 +.\} +.nf + (class=boolean #args=2) String/numeric equality. Mixing number and string results in string compare. +.fi +.if n \{\ +.RE +.SS "=~" +.if n \{\ +.RS 0 +.\} +.nf + (class=boolean #args=2) String (left-hand side) matches regex (right-hand side), e.g. '$name =~ "^a.*b$"'. +.fi +.if n \{\ +.RE +.SS ">" +.if n \{\ +.RS 0 +.\} +.nf + (class=boolean #args=2) String/numeric greater-than. Mixing number and string results in string compare. +.fi +.if n \{\ +.RE +.SS ">=" +.if n \{\ +.RS 0 +.\} +.nf + (class=boolean #args=2) String/numeric greater-than-or-equals. Mixing number and string results in string compare. +.fi +.if n \{\ +.RE +.SS ">>" +.if n \{\ +.RS 0 +.\} +.nf + (class=arithmetic #args=2) Bitwise signed right-shift. +.fi +.if n \{\ +.RE +.SS ">>>" +.if n \{\ +.RS 0 +.\} +.nf + (class=arithmetic #args=2) Bitwise unsigned right-shift. +.fi +.if n \{\ +.RE +.SS "?:" +.if n \{\ +.RS 0 +.\} +.nf + (class=boolean #args=3) Standard ternary operator. +.fi +.if n \{\ +.RE +.SS "??" +.if n \{\ +.RS 0 +.\} +.nf + (class=boolean #args=2) Absent-coalesce operator. $a ?? 1 evaluates to 1 if $a isn't defined in the current record. +.fi +.if n \{\ +.RE +.SS "???" +.if n \{\ +.RS 0 +.\} +.nf + (class=boolean #args=2) Absent-coalesce operator. $a ?? 1 evaluates to 1 if $a isn't defined in the current record, or has empty value. +.fi +.if n \{\ +.RE +.SS "^" +.if n \{\ +.RS 0 +.\} +.nf + (class=arithmetic #args=2) Bitwise XOR. +.fi +.if n \{\ +.RE +.SS "^^" +.if n \{\ +.RS 0 +.\} +.nf + (class=boolean #args=2) Logical XOR. +.fi +.if n \{\ +.RE .SS "|" .if n \{\ .RS 0