From 7b8a6f22c4c23433314c9819386e57a1ddcebc0d Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sat, 25 Oct 2025 13:38:25 +0100 Subject: [PATCH 01/32] #872 alias shell configuration `--copy` --- app/app.go | 4 +- builtins/core/structs/alias.go | 170 ++++++++++++++++++++++++ builtins/core/structs/alias_test.go | 57 ++++++-- builtins/core/structs/function.go | 79 ----------- builtins/core/structs/function_doc.yaml | 105 --------------- docs/commands/alias.md | 25 ++-- version.svg | 2 +- 7 files changed, 231 insertions(+), 211 deletions(-) create mode 100644 builtins/core/structs/alias.go diff --git a/app/app.go b/app/app.go index 959f00ef8..4c7226018 100644 --- a/app/app.go +++ b/app/app.go @@ -16,8 +16,8 @@ const Name = "murex" // Format of version string should be "$(Major).$(Minor).$(Revision) ($Branch)" const ( Major = 7 - Minor = 1 - Revision = 4143 + Minor = 2 + Revision = 2 ) var ( diff --git a/builtins/core/structs/alias.go b/builtins/core/structs/alias.go new file mode 100644 index 000000000..8a7570ddd --- /dev/null +++ b/builtins/core/structs/alias.go @@ -0,0 +1,170 @@ +package structs + +import ( + "errors" + "fmt" + "regexp" + + "github.com/lmorg/murex/lang" + "github.com/lmorg/murex/lang/parameters" + "github.com/lmorg/murex/lang/types" + "github.com/lmorg/murex/shell/autocomplete" + "github.com/lmorg/murex/shell/hintsummary" + "github.com/lmorg/murex/utils/json" +) + +func init() { + lang.DefineFunction("alias", cmdAlias, types.Null) + lang.DefineFunction("!alias", cmdUnalias, types.Null) +} + +const ( + usageAlias = ` +usage: alias [ --copy ] alias_name = command parameter1 parameter2 ... +please note: command and parameters should not be quoted as one parameter to alias` +) + +const ( + fAliasCopy = "--copy" +) + +var argsAlias = ¶meters.Arguments{ + Flags: map[string]string{ + fAliasCopy: types.Boolean, + "-c": fAliasCopy, + }, + AllowAdditional: true, + IgnoreInvalidFlags: false, +} + +func aliasErr(err error, name string) error { + if err == nil { + return nil + } + + if name == "" { + return fmt.Errorf("%v%s", err, usageAlias) + } + + return fmt.Errorf("%v\nalias name: %s%s", err, name, usageAlias) +} + +func cmdAlias(p *lang.Process) error { + if p.Parameters.Len() == 0 { + p.Stdout.SetDataType(types.Json) + b, err := json.Marshal(lang.GlobalAliases.Dump(), p.Stdout.IsTTY()) + if err != nil { + return err + } + _, err = p.Stdout.Writeln(b) + return err + + } + + p.Stdout.SetDataType(types.Null) + + flags, aliasParams, err := p.Parameters.ParseFlags(argsAlias) + if err != nil { + return aliasErr(err, "") + } + + name, params, err := aliasParseParams(aliasParams) + if err != nil { + return aliasErr(err, name) + } + + if flags[fAliasCopy] == types.TrueString { + cmdAliasCopy(p, name, params) + } + + lang.GlobalAliases.Add(name, params, p.FileRef) + return nil +} + +var ( + rxAlias = regexp.MustCompile(`^([-_.a-zA-Z0-9]+)=(.*?)$`) + + errAliasMissingCommand = errors.New("missing command to alias") + errInvalidSyntax = errors.New("invalid syntax") + errAliasUnknown = errors.New("unknown error parsing alias") +) + +func aliasParseParams(aliasParams []string) (string, []string, error) { + if !rxAlias.MatchString(aliasParams[0]) && len(aliasParams) >= 2 && len(aliasParams[1]) >= 1 && aliasParams[1][0] != '=' { + return "", nil, errInvalidSyntax + } + + var ( + split = rxAlias.FindStringSubmatch(aliasParams[0]) + name string + params []string + ) + + if len(split) == 0 { + name = aliasParams[0] + params = aliasParams[1:] + switch { + case len(params) == 0: + return name, nil, errAliasMissingCommand + case len(params[0]) == 1 && params[0] == "=": + params = params[1:] + case len(params[0]) > 0 && params[0][0] == '=': + params[0] = params[0][1:] + default: + return name, nil, errAliasUnknown + } + + } else { + name = split[1] + params = append([]string{split[2]}, aliasParams[1:]...) + } + + if len(params) == 0 { + return name, nil, errAliasMissingCommand + } + + if params[0] == "" && len(params) > 0 { + params = params[1:] + } + + if len(params) == 0 || params[0] == "" { + return name, nil, errAliasMissingCommand + } + + return name, params, nil +} + +func cmdAliasCopy(p *lang.Process, name string, params []string) { + // summary + summary := hintsummary.Summary.Get(params[0]) + if summary != "" { + hintsummary.Summary.Set(name, summary) + } + + // method + dts := lang.MethodStdin.Types(params[0]) + for i := range dts { + lang.MethodStdin.Define(name, dts[i]) + } + + // autocomplete + if len(params) == 1 { + flags, ok := autocomplete.ExesFlags[params[0]] + if ok { + autocomplete.ExesFlags[name] = flags + autocomplete.ExesFlagsFileRef[name] = p.FileRef + } + } +} + +func cmdUnalias(p *lang.Process) error { + p.Stdout.SetDataType(types.Null) + + for _, name := range p.Parameters.StringArray() { + err := lang.GlobalAliases.Delete(name) + if err != nil { + return err + } + } + return nil +} diff --git a/builtins/core/structs/alias_test.go b/builtins/core/structs/alias_test.go index 87b8f4c6b..2661b779e 100644 --- a/builtins/core/structs/alias_test.go +++ b/builtins/core/structs/alias_test.go @@ -11,38 +11,39 @@ import ( func TestAliasParamParsing(t *testing.T) { alias := fmt.Sprintf("GoTest-alias-%d-", rand.Int()) + const errMissingCommand = "missing command to alias" tests := []test.MurexTest{ // errors { - Block: fmt.Sprintf(`alias %s%d`, alias, -1), - Stderr: "no command supplied", + Block: fmt.Sprintf(`alias %s%d`, alias, -1), + Stderr: errMissingCommand, ExitNum: 1, }, { - Block: fmt.Sprintf(`alias %s%d `, alias, -2), - Stderr: "no command supplied", + Block: fmt.Sprintf(`alias %s%d `, alias, -2), + Stderr: errMissingCommand, ExitNum: 1, }, { - Block: fmt.Sprintf(`alias %s%d=`, alias, -3), - Stderr: "no command supplied", + Block: fmt.Sprintf(`alias %s%d=`, alias, -3), + Stderr: errMissingCommand, ExitNum: 1, }, { - Block: fmt.Sprintf(`alias %s%d= `, alias, -4), - Stderr: "no command supplied", + Block: fmt.Sprintf(`alias %s%d= `, alias, -4), + Stderr: errMissingCommand, ExitNum: 1, }, { - Block: fmt.Sprintf(`alias %s%d =`, alias, -1), - Stderr: "no command supplied", + Block: fmt.Sprintf(`alias %s%d =`, alias, -5), + Stderr: errMissingCommand, ExitNum: 1, }, { - Block: fmt.Sprintf(`alias %s%d foobar`, alias, -1), - Stderr: "invalid syntax", + Block: fmt.Sprintf(`alias %s%d foobar`, alias, -6), + Stderr: "invalid syntax", ExitNum: 1, }, @@ -112,8 +113,40 @@ func TestAliasParamParsing(t *testing.T) { Block: fmt.Sprintf(`alias %s%d = foo bar; alias -> [%s%d]`, alias, 12, alias, 12), Stdout: "[\"foo\",\"bar\"]", }, + } + + test.RunMurexTestsRx(tests, t) +} +func TestAliasCopy(t *testing.T) { + token := fmt.Sprintf("GoTest-alias-copy-%d-", rand.Int()) + tests := []test.MurexTest{ + { + Block: fmt.Sprintf(` + summary %[1]s-foo-%[2]d foobar-%[2]d + alias %[1]s-bar-%[2]d = %[1]s-foo-%[2]d + runtime --summaries -> [%[1]s-bar-%[2]d] + `, token, 0), + Stderr: "not found", + ExitNum: 1, + }, + { + Block: fmt.Sprintf(` + summary %[1]s-foo-%[2]d foobar-%[2]d + alias --copy %[1]s-bar-%[2]d = %[1]s-foo-%[2]d + runtime --summaries -> [%[1]s-bar-%[2]d] + `, token, 1), + Stdout: "^foobar-1$", + }, + { + Block: fmt.Sprintf(` + autocomplete set %[1]s-foo-%[2]d %%[{Flags: [ "foobar-%[2]d" ]}] + alias --copy %[1]s-bar-%[2]d = %[1]s-foo-%[2]d + runtime --autocomplete -> [[ /%[1]s-foo-%[2]d/FlagValues/0/Flags/0 ]] + `, token, 2), + Stdout: "^foobar-2$", + }, } test.RunMurexTestsRx(tests, t) diff --git a/builtins/core/structs/function.go b/builtins/core/structs/function.go index 0aa6e03d8..4c6341d99 100644 --- a/builtins/core/structs/function.go +++ b/builtins/core/structs/function.go @@ -3,7 +3,6 @@ package structs import ( "errors" "fmt" - "regexp" "strings" "github.com/lmorg/murex/config/defaults" @@ -14,8 +13,6 @@ import ( ) func init() { - lang.DefineFunction("alias", cmdAlias, types.Null) - lang.DefineFunction("!alias", cmdUnalias, types.Null) lang.DefineFunction("function", cmdFunc, types.Null) lang.DefineFunction("!function", cmdUnfunc, types.Null) lang.DefineFunction("private", cmdPrivate, types.Null) @@ -33,82 +30,6 @@ func init() { `) } -var rxAlias = regexp.MustCompile(`^([-_.a-zA-Z0-9]+)=(.*?)$`) - -func cmdAlias(p *lang.Process) error { - if p.Parameters.Len() == 0 { - p.Stdout.SetDataType(types.Json) - b, err := json.Marshal(lang.GlobalAliases.Dump(), p.Stdout.IsTTY()) - if err != nil { - return err - } - _, err = p.Stdout.Writeln(b) - return err - - } - - p.Stdout.SetDataType(types.Null) - - s, _ := p.Parameters.String(0) - eq, _ := p.Parameters.String(1) - - if !rxAlias.MatchString(s) && len(eq) > 0 && eq[0] != '=' { - return errors.New("invalid syntax. Expecting `alias new_name=original_name parameter1 parameter2 ...`") - } - - var ( - split = rxAlias.FindStringSubmatch(s) - name string - params []string - ) - - if len(split) == 0 { - name = s - params = p.Parameters.StringArray()[1:] - switch { - case len(params) == 0: - return fmt.Errorf("no command supplied") - case len(params[0]) == 1 && params[0] == "=": - params = params[1:] - case len(params[0]) > 0 && params[0][0] == '=': - params[0] = params[0][1:] - default: - return fmt.Errorf("unknown error. Please check syntax follows `alias new_name=original_name parameter1 parameter2 ...`") - } - - } else { - name = split[1] - params = append([]string{split[2]}, p.Parameters.StringArray()[1:]...) - } - - if len(params) == 0 { - return fmt.Errorf("no command supplied") - } - - if params[0] == "" && len(params) > 0 { - params = params[1:] - } - - if len(params) == 0 || params[0] == "" { - return fmt.Errorf("no command supplied") - } - - lang.GlobalAliases.Add(name, params, p.FileRef) - return nil -} - -func cmdUnalias(p *lang.Process) error { - p.Stdout.SetDataType(types.Null) - - for _, name := range p.Parameters.StringArray() { - err := lang.GlobalAliases.Delete(name) - if err != nil { - return err - } - } - return nil -} - func cmdFunc(p *lang.Process) error { var dtParamsT []lang.MurexFuncParam diff --git a/builtins/core/structs/function_doc.yaml b/builtins/core/structs/function_doc.yaml index a99c7a034..5f12b5da3 100644 --- a/builtins/core/structs/function_doc.yaml +++ b/builtins/core/structs/function_doc.yaml @@ -1,108 +1,3 @@ -- DocumentID: alias - Title: >+ - Alias "shortcut": `alias` - CategoryID: commands - SubCategoryIDs: - - commands.shell - - commands.posix - Summary: >- - Create an alias for a command - Description: |- - `alias` allows you to create a shortcut or abbreviation for a longer command. - - IMPORTANT: aliases in Murex are not macros and are therefore different than - other shells. if the shortcut requires any dynamics such as `piping`, - `command sequencing`, `variable evaluations` or `scripting`... - Prefer the **`function`** builtin. - Usage: |- - ``` - alias alias=command parameter parameter - - !alias command - ``` - Examples: |- - Because aliases are parsed into an array of parameters, you cannot put the - entire alias within quotes. For example: - - ``` - # bad :( - » alias hw="out Hello, World!" - » hw - exec "out\\ Hello,\\ World!": executable file not found in $PATH - - # good :) - » alias hw=out "Hello, World!" - » hw - Hello, World! - ``` - - Notice how only the command `out "Hello, World!"` is quoted in `alias` the - same way you would have done if you'd run that command "naked" in the command - line? This is how `alias` expects it's parameters and where `alias` on Murex - differs from `alias` in POSIX shells. - - To materialize those differences, pay attention to the examples below: - - ``` - # bad : the following statements generate errors, - # prefer function builtin to implent them - - » alias myalias=out "Hello, World!" | wc - » alias myalias=out $myvariable | wc - » alias myalias=out ${vmstat} | wc - » alias myalias=out "hello" && out "world" - » alias myalias=out "hello" ; out "world" - » alias myalias="out hello; out world" - ``` - - In some ways this makes `alias` a little less flexible than it might - otherwise be. However the design of this is to keep `alias` focused on it's - core objective. To implement the above aliasing, you can use `function` - instead. - Flags: - Detail: |- - ### Allowed characters - - Alias names can only include alpha-numeric characters, hyphen and underscore. - The following regex is used to validate the `alias`'s parameters: - `^([-_a-zA-Z0-9]+)=(.*?)$` - - ### Undefining an alias - - Like all other definable states in Murex, you can delete an alias with the - bang prefix: - - ``` - » alias hw=out "Hello, World!" - » hw - Hello, World! - - » !alias hw - » hw - exec "hw": executable file not found in $PATH - ``` - - ### Order of preference - - {{ include "gen/includes/order-of-precedence.inc.md" }} - Synonyms: - - alias - - "!alias" - Related: - - function - - private - - source - - g - - let - - set - - global - - export - - exec - - fexec - - method - - - - DocumentID: function Title: >+ Public Function: `function` diff --git a/docs/commands/alias.md b/docs/commands/alias.md index 3a11667f5..99e3be69a 100644 --- a/docs/commands/alias.md +++ b/docs/commands/alias.md @@ -14,7 +14,7 @@ IMPORTANT: aliases in Murex are not macros and are therefore different than ## Usage ``` -alias alias=command parameter parameter +alias [ --copy | -c ] alias=command parameter parameter ... !alias command ``` @@ -60,6 +60,13 @@ otherwise be. However the design of this is to keep `alias` focused on it's core objective. To implement the above aliasing, you can use `function` instead. +## Flags + +* `--copy` + copies `method`, `summary` and `autocomplete` of destination command. `autocomplete` is only copied if alias does not include parameters. +* `-c` + alias for `--copy` + ## Detail ### Allowed characters @@ -123,29 +130,23 @@ You can override this order of precedence via the `fexec` and `exec` builtins. ## See Also -* [Define Environmental Variable: `export`](../commands/export.md): - Define an environmental variable and set it's value -* [Define Global: `global`](../commands/global.md): - Define a global variable and set it's value * [Define Method Relationships (`method`)](../commands/method.md): Define a methods supported data-types -* [Define Variable: `set`](../commands/set.md): - Define a variable (typically local) and set it's value * [Execute External Command: `exec`](../commands/exec.md): Runs an executable * [Execute Function or Builtin: `fexec`](../commands/fexec.md): Execute a command or function, bypassing the usual order of precedence. -* [Globbing: `g`](../commands/g.md): - Glob pattern matching for file system objects (eg `*.txt`) * [Include / Evaluate Murex Code: `source`](../commands/source.md): Import Murex code from another file or code block -* [Integer Operations: `let`](../deprecated/let.md): - Evaluate a mathematical function and assign to variable (removed 7.0) * [Private Function: `private`](../commands/private.md): Define a private function block * [Public Function: `function`](../commands/function.md): Define a function block +* [Set Command Summary Hint: `summary`](../commands/summary.md): + Defines a summary help text for a command +* [Tab Autocompletion: `autocomplete`](../commands/autocomplete.md): + Set definitions for tab-completion in the command line
-This document was generated from [builtins/core/structs/function_doc.yaml](https://github.com/lmorg/murex/blob/master/builtins/core/structs/function_doc.yaml). \ No newline at end of file +This document was generated from [builtins/core/structs/alias_doc.yaml](https://github.com/lmorg/murex/blob/master/builtins/core/structs/alias_doc.yaml). \ No newline at end of file diff --git a/version.svg b/version.svg index 0098a0202..629b68acf 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.1.4143Version7.1.4143 +Version: 7.2.0002Version7.2.0002 From 11aac87763f936d90d52f420a4bb4a6dc18cdcea Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sat, 25 Oct 2025 16:28:15 +0100 Subject: [PATCH 02/32] `args` support for `StrictFlagPlacement` and `--` --- app/app.go | 2 +- builtins/core/management/shell_doc.yaml | 47 ++++++++++++++++++++++-- builtins/core/structs/alias.go | 5 +-- docs/commands/README.md | 5 ++- docs/commands/args.md | 48 +++++++++++++++++++++++++ gen/vuepress/commands_generated.json | 10 +++--- lang/parameters/flags.go | 35 ++++++++++++------ lang/parameters/flags_test.go | 45 +++++++++++++++++++++++ version.svg | 2 +- 9 files changed, 175 insertions(+), 24 deletions(-) diff --git a/app/app.go b/app/app.go index 4c7226018..0d868f3d5 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 2 + Revision = 4 ) var ( diff --git a/builtins/core/management/shell_doc.yaml b/builtins/core/management/shell_doc.yaml index 8990c9e8c..4c7a51c28 100644 --- a/builtins/core/management/shell_doc.yaml +++ b/builtins/core/management/shell_doc.yaml @@ -62,6 +62,8 @@ Title: >+ Parse Murex Source: `murex-parser` CategoryID: commands + SubCategoryIDs: + - commands.lang Summary: >- Runs the Murex parser against a block of code Description: |- @@ -113,10 +115,51 @@ {{ include "examples/flags.mx" }} ``` Flags: - Detail: + Detail: |- + ### Flags vs Parameters + + #### Flags + + Flags are any values pass via `-` or `--` prefixed labels. For example + `--datatype str` would assign the value `str` to the flag name `--datatype`. + + Flags can be `str`, `int` `num` `bool`. These values will be type checked and + `args` will return an error if a user passes (for example) alpha character to + a numeric flag. + + Boolean flags do not require `true` nor `false` values to be included; the + absence of a boolean flag automatically sets it to _false_, while the presence + automatically sets it to _true_. + + #### Parameters + + Parameters are any values that are not assigned to a flag. For example + `cat file1.txt file2.txt file3.txt`. + + #### Allowing Flag-like Parameters + + Sometimes you'll want parameters that look like flags. For example + `calculator -3 + 2` where `-3` might normally be considered a flag. + + There are two ways you can force `args` to read values as a parameter: + + 1. **User controlled**: the user can use the `--` flag to denote that everything + which follows is a parameter. eg `calculator -- -3 + 2`. + + 2. **Developer controlled**: A better option is to enable `StrictFlagPlacement` + and have the first parameter be non-flag option. Eg + `calculator print -3 + 2`. With `StrictFlagPlacement`, anything including + and proceeding a parameter will always be parsed as a parameter regardless + of whether it looks like a flag or not. + + (here, `calculator` is a hypothetical command) Synonyms: Related: - reserved-vars + - str + - int + - num + - bool @@ -173,4 +216,4 @@ Related: - murex-docs - summary - - man-summary \ No newline at end of file + - man-summary diff --git a/builtins/core/structs/alias.go b/builtins/core/structs/alias.go index 8a7570ddd..76cd00e6f 100644 --- a/builtins/core/structs/alias.go +++ b/builtins/core/structs/alias.go @@ -33,8 +33,9 @@ var argsAlias = ¶meters.Arguments{ fAliasCopy: types.Boolean, "-c": fAliasCopy, }, - AllowAdditional: true, - IgnoreInvalidFlags: false, + AllowAdditional: true, + IgnoreInvalidFlags: false, + StrictFlagPlacement: true, } func aliasErr(err error, name string) error { diff --git a/docs/commands/README.md b/docs/commands/README.md index 783855d22..b36d69969 100644 --- a/docs/commands/README.md +++ b/docs/commands/README.md @@ -395,6 +395,8 @@ Various commands that enable control flow, error handling and other important ch Reads the stdin and exit number from previous process and not's it's condition * [Null: `null`](../commands/devnull.md): null function. Similar to /dev/null +* [Parse Murex Source: `murex-parser`](../commands/murex-parser.md): + Runs the Murex parser against a block of code * [Private Function: `private`](../commands/private.md): Define a private function block * [Public Function: `function`](../commands/function.md): @@ -436,10 +438,7 @@ Tools for providing help and hints, useful when working inside the interactive s * [Set Command Summary Hint: `summary`](../commands/summary.md): Defines a summary help text for a command -### Uncategorised -* [Parse Murex Source: `murex-parser`](../commands/murex-parser.md): - Runs the Murex parser against a block of code ## Optional Builtins diff --git a/docs/commands/args.md b/docs/commands/args.md index 6c8f58be5..5cd3ed676 100644 --- a/docs/commands/args.md +++ b/docs/commands/args.md @@ -78,10 +78,58 @@ $args[Additional] -> foreach flag { } ``` +## Detail + +### Flags vs Parameters + +#### Flags + +Flags are any values pass via `-` or `--` prefixed labels. For example +`--datatype str` would assign the value `str` to the flag name `--datatype`. + +Flags can be `str`, `int` `num` `bool`. These values will be type checked and +`args` will return an error if a user passes (for example) alpha character to +a numeric flag. + +Boolean flags do not require `true` nor `false` values to be included; the +absence of a boolean flag automatically sets it to _false_, while the presence +automatically sets it to _true_. + +#### Parameters + +Parameters are any values that are not assigned to a flag. For example +`cat file1.txt file2.txt file3.txt`. + +#### Allowing Flag-like Parameters + +Sometimes you'll want parameters that look like flags. For example +`calculator -3 + 2` where `-3` might normally be considered a flag. + +There are two ways you can force `args` to read values as a parameter: + +1. **User controlled**: the user can use the `--` flag to denote that everything + which follows is a parameter. eg `calculator -- -3 + 2`. + +2. **Developer controlled**: A better option is to enable `StrictFlagPlacement` + and have the first parameter be non-flag option. Eg + `calculator print -3 + 2`. With `StrictFlagPlacement`, anything including + and proceeding a parameter will always be parsed as a parameter regardless + of whether it looks like a flag or not. + +(here, `calculator` is a hypothetical command) + ## See Also * [Reserved Variables](../user-guide/reserved-vars.md): Special variables reserved by Murex +* [`bool`](../types/bool.md): + Boolean (primitive) +* [`int`](../types/int.md): + Whole number (primitive) +* [`num` (number)](../types/num.md): + Floating point number (primitive) +* [`str` (string)](../types/str.md): + string (primitive)
diff --git a/gen/vuepress/commands_generated.json b/gen/vuepress/commands_generated.json index f3c68d9e1..00dea0e6b 100644 --- a/gen/vuepress/commands_generated.json +++ b/gen/vuepress/commands_generated.json @@ -818,6 +818,11 @@ "link": "commands/devnull.md", "text": "Null: null" }, + { + "icon": "file-lines", + "link": "commands/murex-parser.md", + "text": "Parse Murex Source: murex-parser" + }, { "icon": "file-lines", "link": "commands/private.md", @@ -911,10 +916,5 @@ "collapsible": true, "icon": "folder", "text": "Help and Hint Tools" - }, - { - "icon": "file-lines", - "link": "commands/murex-parser.md", - "text": "Parse Murex Source: murex-parser" } ] \ No newline at end of file diff --git a/lang/parameters/flags.go b/lang/parameters/flags.go index d1c67fe88..f2f222029 100644 --- a/lang/parameters/flags.go +++ b/lang/parameters/flags.go @@ -9,9 +9,10 @@ import ( // Arguments is a struct which holds the allowed flags supported when parsing the flags (with ParseFlags) type Arguments struct { - AllowAdditional bool - IgnoreInvalidFlags bool - Flags map[string]string + AllowAdditional bool + IgnoreInvalidFlags bool + StrictFlagPlacement bool + Flags map[string]string } const invalidParameters = "invalid parameters" @@ -27,21 +28,32 @@ const invalidParameters = "invalid parameters" // "--bool": "bool", // "-b": "--bool" // } -func ParseFlags(params []string, args *Arguments) (flags map[string]string, additional []string, err error) { - var previous string - flags = make(map[string]string) - additional = make([]string, 0) +// +// Returns: +// 1. map of flags, +// 2. additional parameters, +// 3. error +func ParseFlags(params []string, args *Arguments) (map[string]string, []string, error) { + var ( + previous string + flags = make(map[string]string) + additional = make([]string, 0) + ignoreFlags bool + ) for i := range params { scanFlags: switch { + case ignoreFlags: + additional = append(additional, params[i]) + case strings.HasPrefix(params[i], "-"): switch { + case args.AllowAdditional && params[i] == "--": + ignoreFlags = true case strings.HasPrefix(args.Flags[params[i]], "-"): params[i] = args.Flags[params[i]] goto scanFlags - //case previous != "": - // return nil, nil, fmt.Errorf("%s: flag found without value: `%s`", invalidParameters, previous) case args.Flags[params[i]] == types.Boolean: flags[params[i]] = types.TrueString case args.Flags[params[i]] != "": @@ -64,6 +76,9 @@ func ParseFlags(params []string, args *Arguments) (flags map[string]string, addi return nil, nil, fmt.Errorf("%s: parameter found without a flag: `%s`", invalidParameters, params[i]) } additional = append(additional, params[i]) + if args.StrictFlagPlacement { + ignoreFlags = true + } } } @@ -71,7 +86,7 @@ func ParseFlags(params []string, args *Arguments) (flags map[string]string, addi return nil, nil, fmt.Errorf("%s: flag found without value: `%s`", invalidParameters, previous) } - return + return flags, additional, nil } // ParseFlags - this instance of ParseFlags is a wrapper function for ParseFlags (above) so you can use inside your diff --git a/lang/parameters/flags_test.go b/lang/parameters/flags_test.go index fd0822420..5d2bc8a5b 100644 --- a/lang/parameters/flags_test.go +++ b/lang/parameters/flags_test.go @@ -37,6 +37,51 @@ func TestFlags(t *testing.T) { ExpAdditional: nil, Error: false, }, + { + Parameters: []string{"foobar", "--string", "--test", "--number", "-5"}, + Arguments: parameters.Arguments{ + StrictFlagPlacement: false, + AllowAdditional: true, + Flags: map[string]string{ + "--string": types.String, + "--number": types.Number, + }, + }, + ExpFlags: map[string]string{ + "--string": "--test", + "--number": "-5", + }, + ExpAdditional: []string{"foobar"}, + Error: false, + }, + { + Parameters: []string{"foobar", "--string", "--test", "--number", "-5"}, + Arguments: parameters.Arguments{ + StrictFlagPlacement: true, + AllowAdditional: true, + Flags: map[string]string{ + "--string": types.String, + "--number": types.Number, + }, + }, + ExpFlags: map[string]string{}, + ExpAdditional: []string{"foobar", "--string", "--test", "--number", "-5"}, + Error: false, + }, + { + Parameters: []string{"--", "foobar", "--string", "--test", "--number", "-5"}, + Arguments: parameters.Arguments{ + StrictFlagPlacement: false, + AllowAdditional: true, + Flags: map[string]string{ + "--string": types.String, + "--number": types.Number, + }, + }, + ExpFlags: map[string]string{}, + ExpAdditional: []string{"foobar", "--string", "--test", "--number", "-5"}, + Error: false, + }, } count.Tests(t, len(tests)) diff --git a/version.svg b/version.svg index 629b68acf..9f19cce7a 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0002Version7.2.0002 +Version: 7.2.0004Version7.2.0004 From c9d40de52b8cadf85f623bb27e71081102427150 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sun, 26 Oct 2025 00:30:54 +0100 Subject: [PATCH 03/32] core: allow filterable function table --- app/app.go | 2 +- lang/funcid.go | 21 ++++++ lang/funcid_options.go | 33 ++++++++++ lang/parameters/flags.go | 116 +++++++++++++++++++++++++++++++--- lang/parameters/flags_test.go | 25 ++++---- version.svg | 2 +- 6 files changed, 177 insertions(+), 22 deletions(-) create mode 100644 lang/funcid_options.go diff --git a/app/app.go b/app/app.go index 0d868f3d5..dbdf3c858 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 4 + Revision = 5 ) var ( diff --git a/lang/funcid.go b/lang/funcid.go index 8b4cad81e..6dbfba8da 100644 --- a/lang/funcid.go +++ b/lang/funcid.go @@ -95,6 +95,27 @@ func (f *funcID) ListAll() fidList { return procs } +// List processes registered in the FID (Function ID) table - return as a ordered list +func (f *funcID) List(options ...OptFidList) fidList { + f.mutex.Lock() + procs := make(fidList, len(f.list)) + var i int + for _, p := range f.list { + fid: + for i := range options { + if !options[i](p) { + continue fid + } + } + procs[i] = p + i++ + } + f.mutex.Unlock() + + sort.Sort(procs) + return procs +} + // Dump returns a list of FIDs in a format for `runtime` builtin func (f *funcID) Dump() any { fidList := f.ListAll() diff --git a/lang/funcid_options.go b/lang/funcid_options.go new file mode 100644 index 000000000..aa8a290f4 --- /dev/null +++ b/lang/funcid_options.go @@ -0,0 +1,33 @@ +package lang + +type OptFidList func(*Process) bool + +func FidWithBackground(background bool) OptFidList { + return func(p *Process) bool { + return p.Background.Get() == background + } +} + +func FidWithStopped(stopped bool) OptFidList { + return func(p *Process) bool { + select { + case <-p.HasStopped: + return true && stopped + default: + return false && stopped + } + } +} + +func FidWithIsChildOf(fid uint32, isChild bool) OptFidList { + return func(p *Process) bool { + pp := p.Parent + for pp.Id != ShellProcess.Id { + if p.Id == fid { + return true && isChild + } + pp = pp.Parent + } + return false && isChild + } +} diff --git a/lang/parameters/flags.go b/lang/parameters/flags.go index f2f222029..d38c45b52 100644 --- a/lang/parameters/flags.go +++ b/lang/parameters/flags.go @@ -7,6 +7,101 @@ import ( "github.com/lmorg/murex/lang/types" ) +type FlagValueT interface { + String() string + Integer() int + Number() float64 + Boolean() bool + Any() any +} + +type flagValue struct { + v any + dt string +} + +func (fv *flagValue) String() string { + if fv.dt == types.String { + return fv.v.(string) + } + panic(fmt.Sprintf("cannot String() on %s", fv.dt)) +} + +func (fv *flagValue) Integer() int { + if fv.dt == types.Integer { + return fv.v.(int) + } + panic(fmt.Sprintf("cannot Integer() on %s", fv.dt)) +} + +func (fv *flagValue) Number() float64 { + if fv.dt == types.Number || fv.dt == types.Float { + return fv.v.(float64) + } + panic(fmt.Sprintf("cannot Number() on %s", fv.dt)) +} + +func (fv *flagValue) Boolean() bool { + if fv.dt == types.Boolean { + return fv.v.(bool) + } + panic(fmt.Sprintf("cannot Boolean() on %s", fv.dt)) +} + +func (fv *flagValue) Any() any { + return fv.v +} + +type nullValue struct{} + +func (nv *nullValue) String() string { return "" } +func (nv *nullValue) Integer() int { return 0 } +func (nv *nullValue) Number() float64 { return 0 } +func (nv *nullValue) Boolean() bool { return false } +func (nv *nullValue) Any() any { return nil } + +type FlagsT struct { + flags map[string]FlagValueT +} + +func (f *FlagsT) set(flag string, v any, dt string) error { + v, err := types.ConvertGoType(v, dt) + if err != nil { + return fmt.Errorf("flag %s is not a %s\n%v", flag, dt, err) + } + f.flags[flag] = &flagValue{v: v, dt: dt} + return nil +} + +func (f *FlagsT) GetValue(flag string) FlagValueT { + v, ok := f.flags[flag] + if ok { + return v + } + return &nullValue{} +} + +func (f *FlagsT) GetNullable(flag string) (FlagValueT, bool) { + v, ok := f.flags[flag] + return v, ok +} + +func (f *FlagsT) GetMap() map[string]any { + m := make(map[string]any) + for k, v := range f.flags { + m[k] = v.Any() + } + return m +} + +func (f *FlagsT) Len() int { + return len(f.flags) +} + +func newFlagsT() *FlagsT { + return &FlagsT{flags: make(map[string]FlagValueT)} +} + // Arguments is a struct which holds the allowed flags supported when parsing the flags (with ParseFlags) type Arguments struct { AllowAdditional bool @@ -33,15 +128,16 @@ const invalidParameters = "invalid parameters" // 1. map of flags, // 2. additional parameters, // 3. error -func ParseFlags(params []string, args *Arguments) (map[string]string, []string, error) { +func ParseFlags(params []string, args *Arguments) (*FlagsT, []string, error) { var ( previous string - flags = make(map[string]string) + flags = newFlagsT() additional = make([]string, 0) ignoreFlags bool + i int ) - for i := range params { + for i = range params { scanFlags: switch { case ignoreFlags: @@ -55,20 +151,24 @@ func ParseFlags(params []string, args *Arguments) (map[string]string, []string, params[i] = args.Flags[params[i]] goto scanFlags case args.Flags[params[i]] == types.Boolean: - flags[params[i]] = types.TrueString + flags.set(params[i], true, types.Boolean) case args.Flags[params[i]] != "": previous = params[i] case previous != "": - flags[previous] = params[i] + if err := flags.set(previous, params[i], args.Flags[previous]); err != nil { + return nil, nil, err + } previous = "" case args.IgnoreInvalidFlags && args.AllowAdditional: additional = append(additional, params[i]) default: - return nil, nil, fmt.Errorf("%s: flag not recognised: `%s`", invalidParameters, params[i]) + return nil, nil, fmt.Errorf("%s: flag not recognized: `%s`", invalidParameters, params[i]) } case previous != "": - flags[previous] = params[i] + if err := flags.set(previous, params[i], args.Flags[previous]); err != nil { + return nil, nil, err + } previous = "" default: @@ -91,7 +191,7 @@ func ParseFlags(params []string, args *Arguments) (map[string]string, []string, // ParseFlags - this instance of ParseFlags is a wrapper function for ParseFlags (above) so you can use inside your // lang.Process.Parameters object -func (p *Parameters) ParseFlags(args *Arguments) (flags map[string]string, additional []string, err error) { +func (p *Parameters) ParseFlags(args *Arguments) (flags *FlagsT, additional []string, err error) { p.mutex.RLock() defer p.mutex.RUnlock() diff --git a/lang/parameters/flags_test.go b/lang/parameters/flags_test.go index 5d2bc8a5b..ca7aea64c 100644 --- a/lang/parameters/flags_test.go +++ b/lang/parameters/flags_test.go @@ -13,7 +13,7 @@ type flagTest struct { Parameters []string Arguments parameters.Arguments - ExpFlags map[string]string + ExpFlags map[string]any ExpAdditional []string Error bool @@ -30,9 +30,9 @@ func TestFlags(t *testing.T) { "--number": types.Number, }, }, - ExpFlags: map[string]string{ + ExpFlags: map[string]any{ "--string": "--test", - "--number": "-5", + "--number": -5, }, ExpAdditional: nil, Error: false, @@ -47,9 +47,9 @@ func TestFlags(t *testing.T) { "--number": types.Number, }, }, - ExpFlags: map[string]string{ + ExpFlags: map[string]any{ "--string": "--test", - "--number": "-5", + "--number": -5, }, ExpAdditional: []string{"foobar"}, Error: false, @@ -64,7 +64,7 @@ func TestFlags(t *testing.T) { "--number": types.Number, }, }, - ExpFlags: map[string]string{}, + ExpFlags: map[string]any{}, ExpAdditional: []string{"foobar", "--string", "--test", "--number", "-5"}, Error: false, }, @@ -78,7 +78,7 @@ func TestFlags(t *testing.T) { "--number": types.Number, }, }, - ExpFlags: map[string]string{}, + ExpFlags: map[string]any{}, ExpAdditional: []string{"foobar", "--string", "--test", "--number", "-5"}, Error: false, }, @@ -88,17 +88,18 @@ func TestFlags(t *testing.T) { for i, test := range tests { if test.ExpFlags == nil { - test.ExpFlags = make(map[string]string) + test.ExpFlags = make(map[string]any) } if test.ExpAdditional == nil { test.ExpAdditional = make([]string, 0) } - flags, additional, err := parameters.ParseFlags(test.Parameters, &test.Arguments) + flagsT, additional, err := parameters.ParseFlags(test.Parameters, &test.Arguments) + flags := flagsT.GetMap() - if flags == nil { - flags = make(map[string]string) - } + //if flags == nil { + // flags = make(map[string]*parameters.FlagValueT) + //} if additional == nil { additional = make([]string, 0) } diff --git a/version.svg b/version.svg index 9f19cce7a..9fb2c9650 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0004Version7.2.0004 +Version: 7.2.0005Version7.2.0005 From 9485f10ce7cbfdc0806582553d88c314956db256 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sun, 26 Oct 2025 00:31:32 +0100 Subject: [PATCH 04/32] alias: update doc --- builtins/core/structs/alias_doc.yaml | 103 +++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 builtins/core/structs/alias_doc.yaml diff --git a/builtins/core/structs/alias_doc.yaml b/builtins/core/structs/alias_doc.yaml new file mode 100644 index 000000000..58fa10e57 --- /dev/null +++ b/builtins/core/structs/alias_doc.yaml @@ -0,0 +1,103 @@ +- DocumentID: alias + Title: >+ + Alias "shortcut": `alias` + CategoryID: commands + SubCategoryIDs: + - commands.shell + - commands.posix + Summary: >- + Create an alias for a command + Description: |- + `alias` allows you to create a shortcut or abbreviation for a longer command. + + IMPORTANT: aliases in Murex are not macros and are therefore different than + other shells. if the shortcut requires any dynamics such as `piping`, + `command sequencing`, `variable evaluations` or `scripting`... + Prefer the **`function`** builtin. + Usage: |- + ``` + alias [ --copy | -c ] alias=command parameter parameter ... + + !alias command + ``` + Examples: |- + Because aliases are parsed into an array of parameters, you cannot put the + entire alias within quotes. For example: + + ``` + # bad :( + » alias hw="out Hello, World!" + » hw + exec "out\\ Hello,\\ World!": executable file not found in $PATH + + # good :) + » alias hw=out "Hello, World!" + » hw + Hello, World! + ``` + + Notice how only the command `out "Hello, World!"` is quoted in `alias` the + same way you would have done if you'd run that command "naked" in the command + line? This is how `alias` expects it's parameters and where `alias` on Murex + differs from `alias` in POSIX shells. + + To materialize those differences, pay attention to the examples below: + + ``` + # bad : the following statements generate errors, + # prefer function builtin to implent them + + » alias myalias=out "Hello, World!" | wc + » alias myalias=out $myvariable | wc + » alias myalias=out ${vmstat} | wc + » alias myalias=out "hello" && out "world" + » alias myalias=out "hello" ; out "world" + » alias myalias="out hello; out world" + ``` + + In some ways this makes `alias` a little less flexible than it might + otherwise be. However the design of this is to keep `alias` focused on it's + core objective. To implement the above aliasing, you can use `function` + instead. + Flags: + --copy: >- + copies `method`, `summary` and `autocomplete` of destination command. + `autocomplete` is only copied if alias does not include parameters. + -c: alias for `--copy` + Detail: |- + ### Allowed characters + + Alias names can only include alpha-numeric characters, hyphen and underscore. + The following regex is used to validate the `alias`'s parameters: + `^([-_a-zA-Z0-9]+)=(.*?)$` + + ### Undefining an alias + + Like all other definable states in Murex, you can delete an alias with the + bang prefix: + + ``` + » alias hw=out "Hello, World!" + » hw + Hello, World! + + » !alias hw + » hw + exec "hw": executable file not found in $PATH + ``` + + ### Order of preference + + {{ include "gen/includes/order-of-precedence.inc.md" }} + Synonyms: + - alias + - "!alias" + Related: + - function + - private + - source + - exec + - fexec + - method + - autocomplete + - summary From d5448de18ca8181037d2186cab5aa74e3f41acb2 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sun, 26 Oct 2025 00:32:16 +0100 Subject: [PATCH 05/32] fid-list: rewrite to support filtering --- builtins/core/processes/fid-list_new.go | 255 ++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 builtins/core/processes/fid-list_new.go diff --git a/builtins/core/processes/fid-list_new.go b/builtins/core/processes/fid-list_new.go new file mode 100644 index 000000000..63c45f124 --- /dev/null +++ b/builtins/core/processes/fid-list_new.go @@ -0,0 +1,255 @@ +package processes + +import ( + "fmt" + + "github.com/lmorg/murex/lang" + "github.com/lmorg/murex/lang/parameters" + "github.com/lmorg/murex/lang/state" + "github.com/lmorg/murex/lang/types" + "github.com/lmorg/murex/utils/json" +) + +func init() { + lang.DefineFunction("fid-list-new", cmdFidListNew, types.JsonLines) + + /*defaults.AppendProfile(` + autocomplete set fid-list { [{ + "DynamicDesc": ({ fid-list --help }) + }] } + + alias jobs=fid-list --jobs + method define jobs { + "in": "null", + "out": "*" + } + config eval shell safe-commands { -> append jobs }`)*/ +} + +const ( + fCsv = "--csv" + fJsonL = "--jsonl" + fTty = "--tty" + fJobs = "--jobs" + fStopped = "--stopped" + fBackground = "--background" + fExcChildrenOf = "--exc-children-of" + fIncChildrenOf = "--inc-children-of" + fHelp = "--help" +) + +var argsFidList = ¶meters.Arguments{ + AllowAdditional: false, + IgnoreInvalidFlags: false, + StrictFlagPlacement: false, + Flags: map[string]string{ + fCsv: types.Boolean, + fJsonL: types.Boolean, + fTty: types.Boolean, + + fJobs: types.Boolean, + fStopped: types.Boolean, + fBackground: types.Boolean, + + fIncChildrenOf: types.Integer, + fExcChildrenOf: types.Integer, + + fHelp: types.Boolean, + }, +} + +func cmdFidListNew(p *lang.Process) error { + flags, _, err := p.Parameters.ParseFlags(argsFidList) + if err != nil { + return err + } + + switch { + case flags.GetValue(fCsv).Boolean(): + return cmdFidListCSV(p) + + case flags.GetValue(fJsonL).Boolean(): + return cmdFidListPipe(p) + + case flags.GetValue(fTty).Boolean(): + return cmdFidListTTY(p) + + case flags.GetValue(fJobs).Boolean(): + return cmdJobs(p) + + case flags.GetValue(fStopped).Boolean(): + return cmdJobsStopped(p) + + case flags.GetValue(fBackground).Boolean(): + return cmdJobsBackground(p) + + case flags.GetValue(fHelp).Boolean(): + return cmdFidListHelp(p) + + default: + if p.Stdout.IsTTY() { + return cmdFidListTTY(p) + } + return cmdFidListPipe(p) + } +} + +func cmdFidListHelp(p *lang.Process) error { + flags := map[string]string{ + "--csv": "Outputs as CSV table", + "--jsonl": "Outputs as a jsonlines (a greppable array of JSON objects). This is the default mode when `fid-list` is piped", + "--tty": "Outputs as a human readable table. This is the default mode when outputting to a TTY", + "--stopped": "JSON map of all stopped processes running under murex", + "--background": "JSON map of all background processes running under murex", + "--jobs": "List stopped or background processes (similar to POSIX jobs)", + "--help": "Displays a list of parameters", + } + p.Stdout.SetDataType(types.Json) + b, err := json.Marshal(flags, p.Stdout.IsTTY()) + if err != nil { + return err + } + + _, err = p.Stdout.Write(b) + return err +} + +func cmdFidListNewTTY(p *lang.Process, procs []*lang.Process) error { + p.Stdout.SetDataType(types.Generic) + p.Stdout.Writeln([]byte(fmt.Sprintf("%7s %7s %7s %-12s %-8s %-3s %-10s %-10s %-10s %s", + "FID", "Parent", "Scope", "State", "Run Mode", "BG", "Out Pipe", "Err Pipe", "Command", "Parameters"))) + + for _, process := range procs { + s := fmt.Sprintf("%7d %7d %7d %-12s %-8s %-3s %-10s %-10s %-10s %s", + process.Id, + process.Parent.Id, + process.Scope.Id, + process.State.String(), + process.RunMode.String(), + process.Background.String(), + process.NamedPipeOut, + process.NamedPipeErr, + process.Name.String(), + getParams(process), + ) + _, err := p.Stdout.Writeln([]byte(s)) + if err != nil { + return err + } + } + return nil +} + +func cmdFidListNewCSV(p *lang.Process, procs []*lang.Process) error { + p.Stdout.SetDataType("csv") + p.Stdout.Writeln([]byte(fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s", + "FID", "Parent", "Scope", "State", "Run Mode", "BG", "Out Pipe", "Err Pipe", "Command", "Parameters"))) + + for _, process := range procs { + s := fmt.Sprintf("%d,%d,%d,%s,%s,%s,%s,%s,%s,%s", + process.Id, + process.Parent.Id, + process.Scope.Id, + process.State.String(), + process.RunMode.String(), + process.Background.String(), + process.NamedPipeOut, + process.NamedPipeErr, + process.Name.String(), + getParams(process), + ) + _, err := p.Stdout.Writeln([]byte(s)) + if err != nil { + return err + } + } + return nil +} + +func cmdFidListNewPipe(p *lang.Process, procs []*lang.Process) error { + p.Stdout.SetDataType(types.JsonLines) + + b, err := lang.MarshalData(p, types.Json, []any{ + "FID", + "Parent", + "Scope", + "State", + "RunMode", + "BG", + "OutPipe", + "ErrPipe", + "Command", + "Parameters", + }) + if err != nil { + return err + } + _, err = p.Stdout.Writeln(b) + if err != nil { + return err + } + + for _, process := range procs { + b, err = lang.MarshalData(p, types.Json, []any{ + process.Id, + process.Parent.Id, + process.Scope.Id, + process.State.String(), + process.RunMode.String(), + process.Background.Get(), + process.NamedPipeOut, + process.NamedPipeErr, + process.Name.String(), + getParams(process), + }) + if err != nil { + return err + } + _, err = p.Stdout.Writeln(b) + if err != nil { + return err + } + } + + return nil +} + +func cmdJobsNewStopped(p *lang.Process, procs []*lang.Process) error { + m := make(map[uint32]string) + + for _, process := range procs { + if process.State.Get() != state.Stopped { + continue + } + m[process.Id] = process.Name.String() + " " + getParams(process) + } + + b, err := lang.MarshalData(p, types.Json, m) + if err != nil { + return err + } + + p.Stdout.SetDataType(types.Json) + _, err = p.Stdout.Write(b) + return err +} + +func cmdJobsNewBackground(p *lang.Process, procs []*lang.Process) error { + m := make(map[uint32]string) + + for _, process := range procs { + if !process.Background.Get() { + continue + } + m[process.Id] = process.Name.String() + " " + getParams(process) + } + + b, err := lang.MarshalData(p, types.Json, m) + if err != nil { + return err + } + + p.Stdout.SetDataType(types.Json) + _, err = p.Stdout.Write(b) + return err +} From a952644725150e8d71aae1393402ba33bc1b69bc Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sun, 26 Oct 2025 00:32:45 +0100 Subject: [PATCH 06/32] core: args flags package rewrite --- app/app.go | 2 +- builtins/core/dag/fanout.go | 6 +- builtins/core/datatools/count.go | 115 +++++++++++----------- builtins/core/datatools/structkeys.go | 15 ++- builtins/core/io/read.go | 12 +-- builtins/core/management/shell.go | 8 +- builtins/core/pipe/pipe.go | 8 +- builtins/core/pretty/pretty.go | 6 +- builtins/core/processes/fid-list.go | 25 +---- builtins/core/runtime/runtime.go | 4 +- builtins/core/structs/alias.go | 2 +- builtins/core/structs/foreach.go | 24 +---- builtins/core/structs/foreach_parallel.go | 7 +- builtins/core/tabulate/tabulate.go | 8 +- builtins/core/time/datetime.go | 6 +- builtins/core/typemgmt/round.go | 4 +- version.svg | 2 +- 17 files changed, 105 insertions(+), 149 deletions(-) diff --git a/app/app.go b/app/app.go index dbdf3c858..92fc2ecde 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 5 + Revision = 6 ) var ( diff --git a/builtins/core/dag/fanout.go b/builtins/core/dag/fanout.go index 190cff355..5ca6fdf28 100644 --- a/builtins/core/dag/fanout.go +++ b/builtins/core/dag/fanout.go @@ -52,7 +52,7 @@ func cmdFanout(p *lang.Process) error { return err } - dt := flags[fDataType] + dt := flags.GetValue(fDataType).String() if dt == "" { if p.IsMethod { dt = p.Stdin.GetDataType() @@ -65,7 +65,7 @@ func cmdFanout(p *lang.Process) error { } p.Stdout.SetDataType(dt) - parse := flags[fParse] == types.TrueString + parse := flags.GetValue(fParse).Boolean() switch { case len(sBlocks) == 0: @@ -141,7 +141,7 @@ func cmdFanout(p *lang.Process) error { wg.Wait() - if flags[fConcatenate] == types.TrueString { + if flags.GetValue(fConcatenate).Boolean() { for i := range rBlocks { if errs[i] != nil { return fmt.Errorf("error returned from vertex %d:\n%v", i+1, err) diff --git a/builtins/core/datatools/count.go b/builtins/core/datatools/count.go index 6ae1b7462..af898ce5d 100644 --- a/builtins/core/datatools/count.go +++ b/builtins/core/datatools/count.go @@ -74,83 +74,78 @@ func cmdCount(p *lang.Process) error { return err } - if len(flags) == 0 { - flags[argTotal] = types.TrueString - } - - for f := range flags { - switch f { - case argDuplications: - v, err := countDuplications(p) - if err != nil { - p.Stdout.SetDataType(types.Null) - return err - } - - b, err := json.Marshal(v, p.Stdout.IsTTY()) - if err != nil { - p.Stdout.SetDataType(types.Null) - return err - } + switch { + case flags.GetValue(argDuplications).Boolean(): + v, err := countDuplications(p) + if err != nil { + p.Stdout.SetDataType(types.Null) + return err + } - p.Stdout.SetDataType(types.Json) - _, err = p.Stdout.Write(b) + b, err := json.Marshal(v, p.Stdout.IsTTY()) + if err != nil { + p.Stdout.SetDataType(types.Null) return err + } - case argUnique: - v, err := countUnique(p) - if err != nil { - p.Stdout.SetDataType(types.Null) - return err - } + p.Stdout.SetDataType(types.Json) + _, err = p.Stdout.Write(b) + return err - p.Stdout.SetDataType(types.Integer) - _, err = p.Stdout.Write([]byte(strconv.Itoa(v))) + case flags.GetValue(argUnique).Boolean(): + v, err := countUnique(p) + if err != nil { + p.Stdout.SetDataType(types.Null) return err + } - case argTotal: - v, err := countTotal(p) - if err != nil { - p.Stdout.SetDataType(types.Null) - return err - } + p.Stdout.SetDataType(types.Integer) + _, err = p.Stdout.Write([]byte(strconv.Itoa(v))) + return err - p.Stdout.SetDataType(types.Integer) - _, err = p.Stdout.Write([]byte(strconv.Itoa(v))) + case flags.GetValue(argSum).Boolean(), flags.GetValue(argSumStrict).Boolean(): + f, err := countSum(p, flags.GetValue(argSumStrict).Boolean()) + if err != nil { + p.Stdout.SetDataType(types.Null) return err + } - case argSum, argSumStrict: - f, err := countSum(p, flags[argSumStrict] == types.TrueString) - if err != nil { - p.Stdout.SetDataType(types.Null) - return err - } + p.Stdout.SetDataType(types.Number) + _, err = p.Stdout.Write([]byte(types.FloatToString(f))) + return err - p.Stdout.SetDataType(types.Number) - _, err = p.Stdout.Write([]byte(types.FloatToString(f))) + case flags.GetValue(argBytes).Boolean(): + p.Stdout.SetDataType(types.Integer) + b, err := p.Stdin.ReadAll() + if err != nil { return err + } + _, err = p.Stdout.Write([]byte(fmt.Sprintf("%d", len(b)))) + return err - case argBytes: - p.Stdout.SetDataType(types.Integer) - b, err := p.Stdin.ReadAll() - if err != nil { - return err - } - _, err = p.Stdout.Write([]byte(fmt.Sprintf("%d", len(b)))) + case flags.GetValue(argRunes).Boolean(): + p.Stdout.SetDataType(types.Integer) + b, err := p.Stdin.ReadAll() + if err != nil { return err + } + _, err = p.Stdout.Write([]byte(fmt.Sprintf("%d", utf8.RuneCount(b)))) + return err - case argRunes: - p.Stdout.SetDataType(types.Integer) - b, err := p.Stdin.ReadAll() - if err != nil { - return err - } - _, err = p.Stdout.Write([]byte(fmt.Sprintf("%d", utf8.RuneCount(b)))) + case flags.GetValue(argTotal).Boolean(): + fallthrough + + default: + v, err := countTotal(p) + if err != nil { + p.Stdout.SetDataType(types.Null) return err } - } - return nil + p.Stdout.SetDataType(types.Integer) + _, err = p.Stdout.Write([]byte(strconv.Itoa(v))) + return err + } } func countDuplications(p *lang.Process) (map[string]int, error) { diff --git a/builtins/core/datatools/structkeys.go b/builtins/core/datatools/structkeys.go index 9cafbf6bf..84f8b4db9 100644 --- a/builtins/core/datatools/structkeys.go +++ b/builtins/core/datatools/structkeys.go @@ -32,19 +32,18 @@ func cmdStructKeys(p *lang.Process) error { return err } - separator := flags["--separator"] + separator := flags.GetValue("--separator").String() if separator == "" { separator = "/" } - depth := flags["--depth"] - if depth == "" && len(additional) == 1 { - depth = additional[0] + depth := flags.GetValue("--depth").Integer() + if depth == 0 && len(additional) == 1 { + depth, _ = strconv.Atoi(additional[0]) } - nDeep, _ := strconv.Atoi(depth) - if nDeep < 1 { - nDeep = -1 + if depth == 0 { + depth = -1 } dt := p.Stdin.GetDataType() @@ -60,7 +59,7 @@ func cmdStructKeys(p *lang.Process) error { return err } - err = objectkeys.Recursive(p.Context, "", v, dt, separator, aw.WriteString, nDeep) + err = objectkeys.Recursive(p.Context, "", v, dt, separator, aw.WriteString, depth) if err != nil { return err } diff --git a/builtins/core/io/read.go b/builtins/core/io/read.go index 55f6556d9..7589c7b6a 100644 --- a/builtins/core/io/read.go +++ b/builtins/core/io/read.go @@ -58,12 +58,12 @@ func read(p *lang.Process, dt string, paramAdjust int) error { } if len(additional) == 0 { - prompt = flags[flagReadPrompt] - varName = flags[flagReadVariable] - defaultVal = flags[flagReadDefault] - datatype := flags[flagReadDataType] - mask = flags[flagReadMask] - complete = flags[flagReadComplete] + prompt = flags.GetValue(flagReadPrompt).String() + varName = flags.GetValue(flagReadVariable).String() + defaultVal = flags.GetValue(flagReadDefault).String() + datatype := flags.GetValue(flagReadDataType).String() + mask = flags.GetValue(flagReadMask).String() + complete = flags.GetValue(flagReadComplete).String() if datatype != "" { dt = datatype diff --git a/builtins/core/management/shell.go b/builtins/core/management/shell.go index 00f762639..f06d9a047 100644 --- a/builtins/core/management/shell.go +++ b/builtins/core/management/shell.go @@ -39,7 +39,7 @@ func cmdArgs(p *lang.Process) (err error) { type flags struct { Self string - Flags map[string]string + Flags map[string]any Additional []string Error string } @@ -57,11 +57,13 @@ func cmdArgs(p *lang.Process) (err error) { jObj.Self = p.Scope.Name.String() } - jObj.Flags, jObj.Additional, err = parameters.ParseFlags(params, &args) + var flagsT *parameters.FlagsT + flagsT, jObj.Additional, err = parameters.ParseFlags(params, &args) if err != nil { jObj.Error = err.Error() p.ExitNum = 1 } + jObj.Flags = flagsT.GetMap() b, err = json.Marshal(jObj, false) if err != nil { @@ -192,7 +194,7 @@ func cmdManParser(p *lang.Process) error { } var b []byte - if cmdFlags[manArgDescriptions] == types.TrueString { + if cmdFlags.GetValue(manArgDescriptions).Boolean() { b, err = json.Marshal(descriptions, p.Stdout.IsTTY()) } else { b, err = json.Marshal(flags, p.Stdout.IsTTY()) diff --git a/builtins/core/pipe/pipe.go b/builtins/core/pipe/pipe.go index a2e5e1f2d..5e0ab6605 100644 --- a/builtins/core/pipe/pipe.go +++ b/builtins/core/pipe/pipe.go @@ -42,12 +42,12 @@ func cmdPipe(p *lang.Process) error { return errors.New("no name specified for named pipe. Usage: `pipe name [ --pipe-type creation-data ]") } - if len(flags) > 1 { - return errors.New("too many types of pipe specified. Please use only one flag per") + if flags.Len() > 1 { + return errors.New("too many types of pipe specified. Please use only one flag per command invocation") } - for flag := range flags { - return lang.GlobalPipes.CreatePipe(additional[0], flag[2:], flags[flag]) + for flag := range flags.GetMap() { + return lang.GlobalPipes.CreatePipe(additional[0], flag[2:], flags.GetValue(flag).String()) } for _, name := range additional { diff --git a/builtins/core/pretty/pretty.go b/builtins/core/pretty/pretty.go index 6b09e0a71..c3f02d231 100644 --- a/builtins/core/pretty/pretty.go +++ b/builtins/core/pretty/pretty.go @@ -48,11 +48,11 @@ func cmdPretty(p *lang.Process) error { } switch { - case flags[fDataType] != "": - return prettyType(p, flags[fDataType], flags[fStrict] == types.TrueString) + case flags.GetValue(fDataType).String() != "": + return prettyType(p, flags.GetValue(fDataType).String(), flags.GetValue(fStrict).Boolean()) default: - return prettyType(p, p.Stdin.GetDataType(), flags[fStrict] == types.TrueString) + return prettyType(p, p.Stdin.GetDataType(), flags.GetValue(fStrict).Boolean()) } } diff --git a/builtins/core/processes/fid-list.go b/builtins/core/processes/fid-list.go index 3c7e68ea6..3c6bd2519 100644 --- a/builtins/core/processes/fid-list.go +++ b/builtins/core/processes/fid-list.go @@ -8,11 +8,10 @@ import ( "github.com/lmorg/murex/lang" "github.com/lmorg/murex/lang/state" "github.com/lmorg/murex/lang/types" - "github.com/lmorg/murex/utils/json" ) func init() { - lang.DefineFunction("fid-list", cmdFidList, types.JsonLines) + lang.DefineFunction("fid-list", cmdFidListOld, types.JsonLines) defaults.AppendProfile(` autocomplete set fid-list { [{ @@ -35,7 +34,7 @@ func getParams(p *lang.Process) string { return s } -func cmdFidList(p *lang.Process) error { +func cmdFidListOld(p *lang.Process) error { flag, _ := p.Parameters.String(0) switch flag { case "": @@ -70,26 +69,6 @@ func cmdFidList(p *lang.Process) error { } } -func cmdFidListHelp(p *lang.Process) error { - flags := map[string]string{ - "--csv": "Outputs as CSV table", - "--jsonl": "Outputs as a jsonlines (a greppable array of JSON objects). This is the default mode when `fid-list` is piped", - "--tty": "Outputs as a human readable table. This is the default mode when outputting to a TTY", - "--stopped": "JSON map of all stopped processes running under murex", - "--background": "JSON map of all background processes running under murex", - "--jobs": "List stopped or background processes (similar to POSIX jobs)", - "--help": "Displays a list of parameters", - } - p.Stdout.SetDataType(types.Json) - b, err := json.Marshal(flags, p.Stdout.IsTTY()) - if err != nil { - return err - } - - _, err = p.Stdout.Write(b) - return err -} - func cmdFidListTTY(p *lang.Process) error { p.Stdout.SetDataType(types.Generic) p.Stdout.Writeln([]byte(fmt.Sprintf("%7s %7s %7s %-12s %-8s %-3s %-10s %-10s %-10s %s", diff --git a/builtins/core/runtime/runtime.go b/builtins/core/runtime/runtime.go index 1dbf7efa2..01eea2c44 100644 --- a/builtins/core/runtime/runtime.go +++ b/builtins/core/runtime/runtime.go @@ -158,12 +158,12 @@ func cmdRuntime(p *lang.Process) error { return err } - if len(f) == 0 { + if f.Len() == 0 { return errors.New("please include one or more parameters") } ret := make(map[string]any) - for flag := range f { + for flag := range f.GetMap() { switch flag { case fVars: ret[flag[2:]] = p.Scope.Variables.Dump() diff --git a/builtins/core/structs/alias.go b/builtins/core/structs/alias.go index 76cd00e6f..293a86664 100644 --- a/builtins/core/structs/alias.go +++ b/builtins/core/structs/alias.go @@ -74,7 +74,7 @@ func cmdAlias(p *lang.Process) error { return aliasErr(err, name) } - if flags[fAliasCopy] == types.TrueString { + if flags.GetValue(fAliasCopy).Boolean() { cmdAliasCopy(p, name, params) } diff --git a/builtins/core/structs/foreach.go b/builtins/core/structs/foreach.go index 282588fc2..b1b38defa 100644 --- a/builtins/core/structs/foreach.go +++ b/builtins/core/structs/foreach.go @@ -43,14 +43,14 @@ func cmdForEach(p *lang.Process) error { } switch { - case flags[foreachJmap] == types.TrueString: + case flags.GetValue(foreachJmap).Boolean(): return cmdForEachJmap(p) - case flags[foreachParallel] != "": - return cmdForEachParallel(p, flags, additional) + case flags.GetValue(foreachParallel).Integer() != 0: + return cmdForEachParallel(p, flags.GetValue(foreachParallel).Integer(), additional) default: - return cmdForEachDefault(p, flags, additional) + return cmdForEachDefault(p, flags.GetValue(foreachStep).Integer(), additional) } } @@ -63,15 +63,6 @@ func convertToByte(v any) ([]byte, error) { return []byte(s.(string)), nil } -func getFlagValueInt(flags map[string]string, flagName string) (int, error) { - v, err := types.ConvertGoType(flags[flagName], types.Integer) - if err != nil { - return 0, fmt.Errorf(`expecting integer for %s, instead got "%s": %s`, flagName, flags[flagName], err.Error()) - } - - return v.(int), nil -} - func forEachInitializer(p *lang.Process, additional []string) (block []rune, varName string, err error) { dataType := p.Stdin.GetDataType() if dataType == types.Json { @@ -99,17 +90,12 @@ func forEachInitializer(p *lang.Process, additional []string) (block []rune, var return } -func cmdForEachDefault(p *lang.Process, flags map[string]string, additional []string) error { +func cmdForEachDefault(p *lang.Process, steps int, additional []string) error { block, varName, err := forEachInitializer(p, additional) if err != nil { return err } - steps, err := getFlagValueInt(flags, foreachStep) - if err != nil { - return err - } - var ( step int iteration int diff --git a/builtins/core/structs/foreach_parallel.go b/builtins/core/structs/foreach_parallel.go index a77c58584..029fe263c 100644 --- a/builtins/core/structs/foreach_parallel.go +++ b/builtins/core/structs/foreach_parallel.go @@ -9,17 +9,12 @@ import ( const MAX_INT = int(^uint(0) >> 1) -func cmdForEachParallel(p *lang.Process, flags map[string]string, additional []string) error { +func cmdForEachParallel(p *lang.Process, parallel int, additional []string) error { block, varName, err := forEachInitializer(p, additional) if err != nil { return err } - parallel, err := getFlagValueInt(flags, foreachParallel) - if err != nil { - return err - } - if parallel < 1 { parallel = MAX_INT } diff --git a/builtins/core/tabulate/tabulate.go b/builtins/core/tabulate/tabulate.go index c5558adf6..5d908ec52 100644 --- a/builtins/core/tabulate/tabulate.go +++ b/builtins/core/tabulate/tabulate.go @@ -102,10 +102,10 @@ func cmdTabulate(p *lang.Process) error { //iValStart int // where the value starts when column wraps and keyVal used ) - for flag, value := range f { + for flag, value := range f.GetMap() { switch flag { case fSeparator: - separator = value + separator = value.(string) case fSplitComma: splitComma = true case fSplitSpace: @@ -115,7 +115,7 @@ func cmdTabulate(p *lang.Process) error { case fKeyVal: keyVal = true case fJoiner: - joiner = value + joiner = value.(string) case fMap: keyVal = true case fColumnWraps: @@ -149,7 +149,7 @@ func cmdTabulate(p *lang.Process) error { p.Name.String(), types.String, types.Generic, dt) } - if f[fMap] == "" { + if !f.GetValue(fMap).Boolean() { p.Stdout.SetDataType("csv") w = csv.NewWriter(p.Stdout) } else { diff --git a/builtins/core/time/datetime.go b/builtins/core/time/datetime.go index 09ee8d122..0d68aa872 100644 --- a/builtins/core/time/datetime.go +++ b/builtins/core/time/datetime.go @@ -59,9 +59,9 @@ func cmdDateTime(p *lang.Process) error { } var ( - fIn = flags[_FLAG_IN] - fOut = flags[_FLAG_OUT] - fValue = flags[_FLAG_VAL] + fIn = flags.GetValue(_FLAG_IN).String() + fOut = flags.GetValue(_FLAG_OUT).String() + fValue = flags.GetValue(_FLAG_VAL).String() ) switch len(additional) { diff --git a/builtins/core/typemgmt/round.go b/builtins/core/typemgmt/round.go index 6583d7f29..ec46b3461 100644 --- a/builtins/core/typemgmt/round.go +++ b/builtins/core/typemgmt/round.go @@ -53,8 +53,8 @@ func cmdRound(p *lang.Process) error { } precision := v.(float64) - roundDown := flags[flagRoundDown] == types.TrueString - roundUp := flags[flagRoundUp] == types.TrueString + roundDown := flags.GetValue(flagRoundDown).Boolean() + roundUp := flags.GetValue(flagRoundUp).Boolean() if roundUp && roundDown { return fmt.Errorf("you cannot use both %s/-d and %s/-u flags together", flagRoundDown, flagRoundUp) diff --git a/version.svg b/version.svg index 9fb2c9650..88dabf3a7 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0005Version7.2.0005 +Version: 7.2.0006Version7.2.0006 From ca049fa0c25217821712bf4e82c74419db3b625d Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sun, 26 Oct 2025 12:36:16 +0000 Subject: [PATCH 07/32] core: refactoring forks --- app/app.go | 2 +- builtins/core/processes/fid-list.go | 26 ++++++++++-- builtins/core/processes/fid-list_new.go | 54 ++++++++++++++++--------- lang/fork.go | 5 ++- lang/funcid.go | 27 +++++++------ lang/funcid_options.go | 42 +++++++++++++------ version.svg | 2 +- 7 files changed, 107 insertions(+), 51 deletions(-) diff --git a/app/app.go b/app/app.go index 92fc2ecde..f41771bfc 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 6 + Revision = 34 ) var ( diff --git a/builtins/core/processes/fid-list.go b/builtins/core/processes/fid-list.go index 3c6bd2519..00c45169b 100644 --- a/builtins/core/processes/fid-list.go +++ b/builtins/core/processes/fid-list.go @@ -4,13 +4,13 @@ import ( "fmt" "strings" - "github.com/lmorg/murex/config/defaults" "github.com/lmorg/murex/lang" "github.com/lmorg/murex/lang/state" "github.com/lmorg/murex/lang/types" + "github.com/lmorg/murex/utils/json" ) -func init() { +/*func init() { lang.DefineFunction("fid-list", cmdFidListOld, types.JsonLines) defaults.AppendProfile(` @@ -24,7 +24,7 @@ func init() { "out": "*" } config eval shell safe-commands { -> append jobs }`) -} +}*/ func getParams(p *lang.Process) string { s := string(p.Parameters.Raw()) @@ -69,6 +69,26 @@ func cmdFidListOld(p *lang.Process) error { } } +func cmdFidListHelp(p *lang.Process) error { + flags := map[string]string{ + "--csv": "Outputs as CSV table", + "--jsonl": "Outputs as a jsonlines (a greppable array of JSON objects). This is the default mode when `fid-list` is piped", + "--tty": "Outputs as a human readable table. This is the default mode when outputting to a TTY", + "--stopped": "JSON map of all stopped processes running under murex", + "--background": "JSON map of all background processes running under murex", + "--jobs": "List stopped or background processes (similar to POSIX jobs)", + "--help": "Displays a list of parameters", + } + p.Stdout.SetDataType(types.Json) + b, err := json.Marshal(flags, p.Stdout.IsTTY()) + if err != nil { + return err + } + + _, err = p.Stdout.Write(b) + return err +} + func cmdFidListTTY(p *lang.Process) error { p.Stdout.SetDataType(types.Generic) p.Stdout.Writeln([]byte(fmt.Sprintf("%7s %7s %7s %-12s %-8s %-3s %-10s %-10s %-10s %s", diff --git a/builtins/core/processes/fid-list_new.go b/builtins/core/processes/fid-list_new.go index 63c45f124..bd4d829c1 100644 --- a/builtins/core/processes/fid-list_new.go +++ b/builtins/core/processes/fid-list_new.go @@ -3,6 +3,7 @@ package processes import ( "fmt" + "github.com/lmorg/murex/config/defaults" "github.com/lmorg/murex/lang" "github.com/lmorg/murex/lang/parameters" "github.com/lmorg/murex/lang/state" @@ -11,9 +12,9 @@ import ( ) func init() { - lang.DefineFunction("fid-list-new", cmdFidListNew, types.JsonLines) + lang.DefineFunction("fid-list", cmdFidListNew, types.JsonLines) - /*defaults.AppendProfile(` + defaults.AppendProfile(` autocomplete set fid-list { [{ "DynamicDesc": ({ fid-list --help }) }] } @@ -23,7 +24,7 @@ func init() { "in": "null", "out": "*" } - config eval shell safe-commands { -> append jobs }`)*/ + config eval shell safe-commands { -> append jobs }`) } const ( @@ -64,45 +65,60 @@ func cmdFidListNew(p *lang.Process) error { return err } + options := []lang.OptFidList{lang.FidWithIsFork(false)} + //options := []lang.OptFidList{} + + if v, ok := flags.GetNullable(fIncChildrenOf); ok { + options = append(options, lang.FidWithIsChildOf(uint32(v.Integer()), true)) + } + + if v, ok := flags.GetNullable(fExcChildrenOf); ok { + options = append(options, lang.FidWithIsChildOf(uint32(v.Integer()), false)) + } + + procs := lang.GlobalFIDs.List(options...) + switch { case flags.GetValue(fCsv).Boolean(): - return cmdFidListCSV(p) + return cmdFidListNewCSV(p, procs) case flags.GetValue(fJsonL).Boolean(): - return cmdFidListPipe(p) + return cmdFidListNewPipe(p, procs) case flags.GetValue(fTty).Boolean(): - return cmdFidListTTY(p) + return cmdFidListNewTTY(p, procs) case flags.GetValue(fJobs).Boolean(): return cmdJobs(p) case flags.GetValue(fStopped).Boolean(): - return cmdJobsStopped(p) + return cmdJobsNewStopped(p, procs) case flags.GetValue(fBackground).Boolean(): - return cmdJobsBackground(p) + return cmdJobsNewBackground(p, procs) case flags.GetValue(fHelp).Boolean(): - return cmdFidListHelp(p) + return cmdFidListNewHelp(p) default: if p.Stdout.IsTTY() { - return cmdFidListTTY(p) + return cmdFidListNewTTY(p, procs) } - return cmdFidListPipe(p) + return cmdFidListNewPipe(p, procs) } } -func cmdFidListHelp(p *lang.Process) error { +func cmdFidListNewHelp(p *lang.Process) error { flags := map[string]string{ - "--csv": "Outputs as CSV table", - "--jsonl": "Outputs as a jsonlines (a greppable array of JSON objects). This is the default mode when `fid-list` is piped", - "--tty": "Outputs as a human readable table. This is the default mode when outputting to a TTY", - "--stopped": "JSON map of all stopped processes running under murex", - "--background": "JSON map of all background processes running under murex", - "--jobs": "List stopped or background processes (similar to POSIX jobs)", - "--help": "Displays a list of parameters", + fCsv: "Outputs as CSV table", + fJsonL: "Outputs as a jsonlines (a greppable array of JSON objects). This is the default mode when `fid-list` is piped", + fTty: "Outputs as a human readable table. This is the default mode when outputting to a TTY", + fStopped: "JSON map of all stopped processes running under murex", + fBackground: "JSON map of all background processes running under murex", + fJobs: "List stopped or background processes (similar to POSIX jobs)", + fIncChildrenOf: " Include only children of FID", + fExcChildrenOf: " Exclude all children of FID", + fHelp: "Displays a list of parameters", } p.Stdout.SetDataType(types.Json) b, err := json.Marshal(flags, p.Stdout.IsTTY()) diff --git a/lang/fork.go b/lang/fork.go index 5c4606e50..a0326d56e 100644 --- a/lang/fork.go +++ b/lang/fork.go @@ -115,6 +115,7 @@ func (p *Process) Fork(flags int) *Fork { fork.OperatorLogicAnd = p.OperatorLogicAnd fork.OperatorLogicOr = p.OperatorLogicOr fork.IsNot = p.IsNot + fork.IsFork = true fork.Previous = p.Previous fork.Next = p.Next @@ -169,7 +170,7 @@ func (p *Process) Fork(flags int) *Fork { fork.Name.Append(ForkSuffix) GlobalFIDs.Register(fork.Process) fork.fidRegistered = true - fork.IsFork = true + //fork.IsFork = true default: //panic("must include either F_PARENT_VARTABLE or F_NEW_VARTABLE") @@ -179,7 +180,7 @@ func (p *Process) Fork(flags int) *Fork { fork.Name.Append(ForkSuffix) GlobalFIDs.Register(fork.Process) fork.fidRegistered = true - fork.IsFork = true + //fork.IsFork = true } if flags&F_NEW_CONFIG != 0 { diff --git a/lang/funcid.go b/lang/funcid.go index 6dbfba8da..939760829 100644 --- a/lang/funcid.go +++ b/lang/funcid.go @@ -97,22 +97,23 @@ func (f *funcID) ListAll() fidList { // List processes registered in the FID (Function ID) table - return as a ordered list func (f *funcID) List(options ...OptFidList) fidList { - f.mutex.Lock() - procs := make(fidList, len(f.list)) - var i int - for _, p := range f.list { - fid: - for i := range options { - if !options[i](p) { - continue fid - } + fids := f.ListAll() + + var procs fidList + + for _, p := range fids { + //fmt.Printf("start: %d %s\n", p.Id, p.Name.String()) + inc := true + for opt := range options { + //fmt.Printf("opt %d: %d %s\n", opt, p.Id, p.Name.String()) + inc = inc && options[opt](p) } - procs[i] = p - i++ + if inc { + procs = append(procs, p) + } + //fmt.Printf("end: %d %s\n", p.Id, p.Name.String()) } - f.mutex.Unlock() - sort.Sort(procs) return procs } diff --git a/lang/funcid_options.go b/lang/funcid_options.go index aa8a290f4..f07ba696c 100644 --- a/lang/funcid_options.go +++ b/lang/funcid_options.go @@ -1,33 +1,51 @@ package lang +import ( + "fmt" +) + type OptFidList func(*Process) bool -func FidWithBackground(background bool) OptFidList { +func FidWithIsBackground(include bool) OptFidList { return func(p *Process) bool { - return p.Background.Get() == background + return p.Background.Get() == include } } -func FidWithStopped(stopped bool) OptFidList { +func FidWithIsStopped(include bool) OptFidList { return func(p *Process) bool { select { case <-p.HasStopped: - return true && stopped + return include default: - return false && stopped + return !include } } } -func FidWithIsChildOf(fid uint32, isChild bool) OptFidList { +func FidWithIsChildOf(fid uint32, include bool) OptFidList { return func(p *Process) bool { - pp := p.Parent - for pp.Id != ShellProcess.Id { - if p.Id == fid { - return true && isChild + + proc := p.Parent + + for { + fmt.Printf("FidWithIsChildOf %d\n", proc.Id) + if proc.Id == fid { + return include + } + + proc = proc.Parent + + if proc.Id == ShellProcess.Id { + return !include } - pp = pp.Parent } - return false && isChild + } +} + +func FidWithIsFork(include bool) OptFidList { + return func(p *Process) bool { + fmt.Printf("%d %s: (%v == %v) == %v\n", p.Id, p.Name.String(), p.IsFork, include, p.IsFork == include) + return p.IsFork == include } } diff --git a/version.svg b/version.svg index 88dabf3a7..d7b096ec3 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0006Version7.2.0006 +Version: 7.2.0034Version7.2.0034 From 0563c8b158adb0b0d50327f865ab5f068c798f75 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sun, 26 Oct 2025 23:38:35 +0000 Subject: [PATCH 08/32] refactor: fid-list, forks, fids --- app/app.go | 2 +- builtins/core/processes/fid-list_new.go | 61 +++++++++++++++---------- lang/fork.go | 17 +++---- lang/funcid_options.go | 6 --- lang/runmode/runmode_string.go | 5 +- lang/state/functionstate.go | 1 + lang/state/functionstate_string.go | 26 ++++++----- lang/variables_reserved.go | 1 + utils/parser/pipetoken_string.go | 5 +- version.svg | 2 +- 10 files changed, 70 insertions(+), 56 deletions(-) diff --git a/app/app.go b/app/app.go index f41771bfc..f8593a073 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 34 + Revision = 48 ) var ( diff --git a/builtins/core/processes/fid-list_new.go b/builtins/core/processes/fid-list_new.go index bd4d829c1..9443a60f5 100644 --- a/builtins/core/processes/fid-list_new.go +++ b/builtins/core/processes/fid-list_new.go @@ -28,15 +28,17 @@ func init() { } const ( - fCsv = "--csv" - fJsonL = "--jsonl" - fTty = "--tty" - fJobs = "--jobs" - fStopped = "--stopped" - fBackground = "--background" - fExcChildrenOf = "--exc-children-of" - fIncChildrenOf = "--inc-children-of" - fHelp = "--help" + fCsv = "--csv" + fJsonL = "--jsonl" + fTty = "--tty" + fJobs = "--jobs" + fStopped = "--stopped" + fBackground = "--background" + fIncChildrenOf = "--children-of" + fExcChildrenOf = "--no-children-of" + fIncFnContainer = "--function-groups" + fExcFnContainer = "--no-function-groups" + fHelp = "--help" ) var argsFidList = ¶meters.Arguments{ @@ -52,8 +54,10 @@ var argsFidList = ¶meters.Arguments{ fStopped: types.Boolean, fBackground: types.Boolean, - fIncChildrenOf: types.Integer, - fExcChildrenOf: types.Integer, + fIncChildrenOf: types.Integer, + fExcChildrenOf: types.Integer, + fIncFnContainer: types.Boolean, + fExcFnContainer: types.Boolean, fHelp: types.Boolean, }, @@ -65,8 +69,7 @@ func cmdFidListNew(p *lang.Process) error { return err } - options := []lang.OptFidList{lang.FidWithIsFork(false)} - //options := []lang.OptFidList{} + options := []lang.OptFidList{} if v, ok := flags.GetNullable(fIncChildrenOf); ok { options = append(options, lang.FidWithIsChildOf(uint32(v.Integer()), true)) @@ -76,6 +79,14 @@ func cmdFidListNew(p *lang.Process) error { options = append(options, lang.FidWithIsChildOf(uint32(v.Integer()), false)) } + if _, ok := flags.GetNullable(fIncFnContainer); ok { + options = append(options, lang.FidWithIsFork(false)) + } + + if _, ok := flags.GetNullable(fExcFnContainer); ok { + options = append(options, lang.FidWithIsFork(false)) + } + procs := lang.GlobalFIDs.List(options...) switch { @@ -110,15 +121,17 @@ func cmdFidListNew(p *lang.Process) error { func cmdFidListNewHelp(p *lang.Process) error { flags := map[string]string{ - fCsv: "Outputs as CSV table", - fJsonL: "Outputs as a jsonlines (a greppable array of JSON objects). This is the default mode when `fid-list` is piped", - fTty: "Outputs as a human readable table. This is the default mode when outputting to a TTY", - fStopped: "JSON map of all stopped processes running under murex", - fBackground: "JSON map of all background processes running under murex", - fJobs: "List stopped or background processes (similar to POSIX jobs)", - fIncChildrenOf: " Include only children of FID", - fExcChildrenOf: " Exclude all children of FID", - fHelp: "Displays a list of parameters", + fCsv: "Outputs as CSV table", + fJsonL: "Outputs as a jsonlines (a greppable array of JSON objects). This is the default mode when `fid-list` is piped", + fTty: "Outputs as a human readable table. This is the default mode when outputting to a TTY", + fStopped: "JSON map of all stopped processes running under murex", + fBackground: "JSON map of all background processes running under murex", + fJobs: "List stopped or background processes (similar to POSIX jobs)", + fIncChildrenOf: " Include only children of FID", + fExcChildrenOf: " Exclude all children of FID", + fIncFnContainer: "Include only function containers", + fExcFnContainer: "Exclude all function containers", + fHelp: "Displays a list of parameters", } p.Stdout.SetDataType(types.Json) b, err := json.Marshal(flags, p.Stdout.IsTTY()) @@ -132,11 +145,11 @@ func cmdFidListNewHelp(p *lang.Process) error { func cmdFidListNewTTY(p *lang.Process, procs []*lang.Process) error { p.Stdout.SetDataType(types.Generic) - p.Stdout.Writeln([]byte(fmt.Sprintf("%7s %7s %7s %-12s %-8s %-3s %-10s %-10s %-10s %s", + p.Stdout.Writeln([]byte(fmt.Sprintf("%7s %7s %7s %-13s %-8s %-3s %-10s %-10s %-10s %s", "FID", "Parent", "Scope", "State", "Run Mode", "BG", "Out Pipe", "Err Pipe", "Command", "Parameters"))) for _, process := range procs { - s := fmt.Sprintf("%7d %7d %7d %-12s %-8s %-3s %-10s %-10s %-10s %s", + s := fmt.Sprintf("%7d %7d %7d %-13s %-8s %-3s %-10s %-10s %-10s %s", process.Id, process.Parent.Id, process.Scope.Id, diff --git a/lang/fork.go b/lang/fork.go index a0326d56e..5823d02f8 100644 --- a/lang/fork.go +++ b/lang/fork.go @@ -95,7 +95,7 @@ type Fork struct { preview bool } -const ForkSuffix = " (fork)" +//const ForkSuffix = " (fork)" // Fork will create a new handle for executing a code block func (p *Process) Fork(flags int) *Fork { @@ -107,7 +107,7 @@ func (p *Process) Fork(flags int) *Fork { trace(fork.Process) fork.raw = p.raw - fork.State.Set(state.MemAllocated) + fork.State.Set(state.FunctionGroup) fork.Background.Set(flags&F_BACKGROUND != 0 || p.Background.Get()) fork.HasJobId.Set(flags&F_ASSIGN_JOBID != 0 || p.HasJobId.Get()) @@ -116,6 +116,7 @@ func (p *Process) Fork(flags int) *Fork { fork.OperatorLogicOr = p.OperatorLogicOr fork.IsNot = p.IsNot fork.IsFork = true + fork.Parent = p //p.Parent fork.Previous = p.Previous fork.Next = p.Next @@ -132,7 +133,7 @@ func (p *Process) Fork(flags int) *Fork { if flags&F_FUNCTION != 0 { fork.Scope = fork.Process - fork.Parent = fork.Process + //fork.Parent = fork.Process fork.Context, fork.Done = context.WithCancel(context.Background()) fork.Kill = fork.Done @@ -160,24 +161,24 @@ func (p *Process) Fork(flags int) *Fork { switch { case flags&F_PARENT_VARTABLE != 0: - fork.Parent = p.Parent + //fork.Parent = p.Parent fork.Variables = p.Variables fork.Id = p.Id case flags&F_NEW_VARTABLE != 0: - fork.Parent = p.Parent + //fork.Parent = p.Parent fork.Variables = p.Variables - fork.Name.Append(ForkSuffix) + //.Name.Append(ForkSuffix) GlobalFIDs.Register(fork.Process) fork.fidRegistered = true //fork.IsFork = true default: //panic("must include either F_PARENT_VARTABLE or F_NEW_VARTABLE") - fork.Parent = p.Parent + //fork.Parent = p.Parent fork.Variables = NewVariables(fork.Process) fork.Variables = p.Variables - fork.Name.Append(ForkSuffix) + //fork.Name.Append(ForkSuffix) GlobalFIDs.Register(fork.Process) fork.fidRegistered = true //fork.IsFork = true diff --git a/lang/funcid_options.go b/lang/funcid_options.go index f07ba696c..2b364af83 100644 --- a/lang/funcid_options.go +++ b/lang/funcid_options.go @@ -1,9 +1,5 @@ package lang -import ( - "fmt" -) - type OptFidList func(*Process) bool func FidWithIsBackground(include bool) OptFidList { @@ -29,7 +25,6 @@ func FidWithIsChildOf(fid uint32, include bool) OptFidList { proc := p.Parent for { - fmt.Printf("FidWithIsChildOf %d\n", proc.Id) if proc.Id == fid { return include } @@ -45,7 +40,6 @@ func FidWithIsChildOf(fid uint32, include bool) OptFidList { func FidWithIsFork(include bool) OptFidList { return func(p *Process) bool { - fmt.Printf("%d %s: (%v == %v) == %v\n", p.Id, p.Name.String(), p.IsFork, include, p.IsFork == include) return p.IsFork == include } } diff --git a/lang/runmode/runmode_string.go b/lang/runmode/runmode_string.go index 1cd74324e..6f3f00593 100644 --- a/lang/runmode/runmode_string.go +++ b/lang/runmode/runmode_string.go @@ -32,8 +32,9 @@ const _RunMode_name = "DefaultNormalBlockUnsafeFunctionUnsafeModuleUnsafeBlockTr var _RunMode_index = [...]uint8{0, 7, 13, 24, 38, 50, 58, 70, 81, 96, 107, 122, 136, 154, 163, 176, 188, 204} func (i RunMode) String() string { - if i < 0 || i >= RunMode(len(_RunMode_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_RunMode_index)-1 { return "RunMode(" + strconv.FormatInt(int64(i), 10) + ")" } - return _RunMode_name[_RunMode_index[i]:_RunMode_index[i+1]] + return _RunMode_name[_RunMode_index[idx]:_RunMode_index[idx+1]] } diff --git a/lang/state/functionstate.go b/lang/state/functionstate.go index fc7959e5b..cfde5f8e4 100644 --- a/lang/state/functionstate.go +++ b/lang/state/functionstate.go @@ -8,6 +8,7 @@ type FunctionState int32 // The different states available to FunctionState: const ( Undefined FunctionState = iota + FunctionGroup MemAllocated Assigned Starting diff --git a/lang/state/functionstate_string.go b/lang/state/functionstate_string.go index cee86c9ed..ea109aab8 100644 --- a/lang/state/functionstate_string.go +++ b/lang/state/functionstate_string.go @@ -9,23 +9,25 @@ func _() { // Re-run the stringer command to generate them again. var x [1]struct{} _ = x[Undefined-0] - _ = x[MemAllocated-1] - _ = x[Assigned-2] - _ = x[Starting-3] - _ = x[Executing-4] - _ = x[Executed-5] - _ = x[Terminating-6] - _ = x[AwaitingGC-7] - _ = x[Stopped-8] + _ = x[FunctionGroup-1] + _ = x[MemAllocated-2] + _ = x[Assigned-3] + _ = x[Starting-4] + _ = x[Executing-5] + _ = x[Executed-6] + _ = x[Terminating-7] + _ = x[AwaitingGC-8] + _ = x[Stopped-9] } -const _FunctionState_name = "UndefinedMemAllocatedAssignedStartingExecutingExecutedTerminatingAwaitingGCStopped" +const _FunctionState_name = "UndefinedFunctionGroupMemAllocatedAssignedStartingExecutingExecutedTerminatingAwaitingGCStopped" -var _FunctionState_index = [...]uint8{0, 9, 21, 29, 37, 46, 54, 65, 75, 82} +var _FunctionState_index = [...]uint8{0, 9, 22, 34, 42, 50, 59, 67, 78, 88, 95} func (i FunctionState) String() string { - if i < 0 || i >= FunctionState(len(_FunctionState_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_FunctionState_index)-1 { return "FunctionState(" + strconv.FormatInt(int64(i), 10) + ")" } - return _FunctionState_name[_FunctionState_index[i]:_FunctionState_index[i+1]] + return _FunctionState_name[_FunctionState_index[idx]:_FunctionState_index[idx+1]] } diff --git a/lang/variables_reserved.go b/lang/variables_reserved.go index 80c791249..f2ad9f44c 100644 --- a/lang/variables_reserved.go +++ b/lang/variables_reserved.go @@ -20,6 +20,7 @@ var envDataTypes = map[string][]string{ func getVarSelf(p *Process) any { bg := p.Scope.Background.Get() return map[string]any{ + //"FID": int(p.Parent.Id), "Parent": int(p.Scope.Parent.Id), "Scope": int(p.Scope.Id), "TTY": p.Scope.Stdout.IsTTY(), diff --git a/utils/parser/pipetoken_string.go b/utils/parser/pipetoken_string.go index 558cae7d4..d62d81efb 100644 --- a/utils/parser/pipetoken_string.go +++ b/utils/parser/pipetoken_string.go @@ -21,8 +21,9 @@ const _PipeToken_name = "PipeTokenNonePipeTokenPosixPipeTokenArrowPipeTokenGener var _PipeToken_index = [...]uint8{0, 13, 27, 41, 57, 74, 89} func (i PipeToken) String() string { - if i < 0 || i >= PipeToken(len(_PipeToken_index)-1) { + idx := int(i) - 0 + if i < 0 || idx >= len(_PipeToken_index)-1 { return "PipeToken(" + strconv.FormatInt(int64(i), 10) + ")" } - return _PipeToken_name[_PipeToken_index[i]:_PipeToken_index[i+1]] + return _PipeToken_name[_PipeToken_index[idx]:_PipeToken_index[idx+1]] } diff --git a/version.svg b/version.svg index d7b096ec3..dedbc0d86 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0034Version7.2.0034 +Version: 7.2.0048Version7.2.0048 From 638bfcc5ed28de821b42edbc970f2cd2136595a0 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sun, 26 Oct 2025 23:44:29 +0000 Subject: [PATCH 09/32] foreach: fix regression bug in --parallel after args rewrite --- app/app.go | 2 +- builtins/core/structs/foreach.go | 6 ++++-- version.svg | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/app.go b/app/app.go index f8593a073..80f0fd7fe 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 48 + Revision = 49 ) var ( diff --git a/builtins/core/structs/foreach.go b/builtins/core/structs/foreach.go index b1b38defa..3ad5e29b2 100644 --- a/builtins/core/structs/foreach.go +++ b/builtins/core/structs/foreach.go @@ -42,12 +42,14 @@ func cmdForEach(p *lang.Process) error { return err } + foreachParallelVal, foreachParallelOk := flags.GetNullable(foreachParallel) + switch { case flags.GetValue(foreachJmap).Boolean(): return cmdForEachJmap(p) - case flags.GetValue(foreachParallel).Integer() != 0: - return cmdForEachParallel(p, flags.GetValue(foreachParallel).Integer(), additional) + case foreachParallelOk: + return cmdForEachParallel(p, foreachParallelVal.Integer(), additional) default: return cmdForEachDefault(p, flags.GetValue(foreachStep).Integer(), additional) diff --git a/version.svg b/version.svg index dedbc0d86..f9bdcd640 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0048Version7.2.0048 +Version: 7.2.0049Version7.2.0049 From 3423460d21954a4e8ed7d869f431df39fb2aced3 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Mon, 27 Oct 2025 23:17:56 +0000 Subject: [PATCH 10/32] #953 autocomplete: fix panic when JSON struct is zero-length --- app/app.go | 2 +- builtins/core/autocomplete/autocomplete.go | 9 ++++++--- .../core/autocomplete/autocomplete_test.go | 18 ++++++++++++++++++ version.svg | 2 +- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/app/app.go b/app/app.go index 80f0fd7fe..163f6d9a2 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 49 + Revision = 50 ) var ( diff --git a/builtins/core/autocomplete/autocomplete.go b/builtins/core/autocomplete/autocomplete.go index 2565ff981..b88c3ca9c 100644 --- a/builtins/core/autocomplete/autocomplete.go +++ b/builtins/core/autocomplete/autocomplete.go @@ -28,9 +28,6 @@ func cmdAutocomplete(p *lang.Process) error { case "set": return set(p) - //case "cache-dynamic": - // return cacheDynamic(p) - default: p.Stdout.SetDataType(types.Null) return errors.New("Not a valid mode. Please use `get` or `set`") @@ -57,6 +54,8 @@ func get(p *lang.Process) error { return err } +var ErrEmptyAutocomplete = errors.New("empty autocomplete") + func set(p *lang.Process) error { p.Stdout.SetDataType(types.Null) @@ -93,6 +92,10 @@ func set(p *lang.Process) error { return err } + if len(flags) == 0 { + return ErrEmptyAutocomplete + } + // So we don't have nil values in JSON if flags[0].CacheTTL == 0 { flags[0].CacheTTL = 5 diff --git a/builtins/core/autocomplete/autocomplete_test.go b/builtins/core/autocomplete/autocomplete_test.go index 32bccc40c..8a1abe276 100644 --- a/builtins/core/autocomplete/autocomplete_test.go +++ b/builtins/core/autocomplete/autocomplete_test.go @@ -4,7 +4,9 @@ import ( "testing" _ "github.com/lmorg/murex/builtins" + cmdautocomplete "github.com/lmorg/murex/builtins/core/autocomplete" "github.com/lmorg/murex/lang" + "github.com/lmorg/murex/test" "github.com/lmorg/murex/test/count" ) @@ -88,3 +90,19 @@ func TestAutocomplete(t *testing.T) { t.Logf(" Actual: %s", string(stdout)) } } + +// Bugfix: panic in autocomplete: +// https://github.com/lmorg/murex/issues/953 +func TestAutocompleteIssue953(t *testing.T) { + count.Tests(t, 1) + + tests := []test.MurexTest{ + { + Block: `autocomplete set foobar %[]`, + Stderr: cmdautocomplete.ErrEmptyAutocomplete.Error(), + ExitNum: 1, + }, + } + + test.RunMurexTestsRx(tests, t) +} diff --git a/version.svg b/version.svg index f9bdcd640..20c1b640e 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0049Version7.2.0049 +Version: 7.2.0050Version7.2.0050 From f002473869d4a84c01e9c62c40a2d2648af2b3c6 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Mon, 27 Oct 2025 23:27:36 +0000 Subject: [PATCH 11/32] #864 core: temp directory value is immutable --- app/app.go | 2 +- builtins/core/io/lockfile.go | 2 +- builtins/core/io/tmp.go | 2 +- docs/commands/tmp.md | 2 +- shell/shell.go | 2 +- utils/consts/consts_test.go | 6 +++--- utils/consts/consts_unix.go | 4 ++-- utils/consts/consts_windows.go | 6 +++--- utils/consts/temp.go | 20 ++++++++++++-------- utils/tmpfile.go | 2 +- version.svg | 2 +- 11 files changed, 27 insertions(+), 23 deletions(-) diff --git a/app/app.go b/app/app.go index 163f6d9a2..355873701 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 50 + Revision = 51 ) var ( diff --git a/builtins/core/io/lockfile.go b/builtins/core/io/lockfile.go index 934b2636e..c7fc7bb16 100644 --- a/builtins/core/io/lockfile.go +++ b/builtins/core/io/lockfile.go @@ -77,5 +77,5 @@ func fileExists(path string) bool { } func lockFilePath(key string) string { - return consts.TempDir + key + ".lockfile" + return consts.TmpDir() + key + ".lockfile" } diff --git a/builtins/core/io/tmp.go b/builtins/core/io/tmp.go index 54080d4de..c835aac32 100644 --- a/builtins/core/io/tmp.go +++ b/builtins/core/io/tmp.go @@ -33,7 +33,7 @@ func cmdTempFile(p *lang.Process) error { return err } - name := consts.TempDir + hex.EncodeToString(h.Sum(nil)) + "-" + strconv.Itoa(os.Getpid()) + ext + name := consts.TmpDir() + hex.EncodeToString(h.Sum(nil)) + "-" + strconv.Itoa(os.Getpid()) + ext file, err := os.Create(name) if err != nil { diff --git a/docs/commands/tmp.md b/docs/commands/tmp.md index d73cd4854..1c1ab2d4b 100644 --- a/docs/commands/tmp.md +++ b/docs/commands/tmp.md @@ -70,7 +70,7 @@ func cmdTempFile(p *lang.Process) error { return err } - name := consts.TempDir + hex.EncodeToString(h.Sum(nil)) + "-" + strconv.Itoa(os.Getpid()) + ext + name := consts.TmpDir() + hex.EncodeToString(h.Sum(nil)) + "-" + strconv.Itoa(os.Getpid()) + ext file, err := os.Create(name) if err != nil { diff --git a/shell/shell.go b/shell/shell.go index 2c00d8d6f..e7a63fe6f 100644 --- a/shell/shell.go +++ b/shell/shell.go @@ -94,7 +94,7 @@ func Start() { } lang.Interactive = true - Prompt.TempDirectory = consts.TempDir + Prompt.TempDirectory = consts.TmpDir() definePromptHistory() Prompt.AutocompleteHistory = autocompleteHistoryLine diff --git a/utils/consts/consts_test.go b/utils/consts/consts_test.go index f65cb47e5..add5bb386 100644 --- a/utils/consts/consts_test.go +++ b/utils/consts/consts_test.go @@ -10,11 +10,11 @@ import ( func TestTempDir(t *testing.T) { count.Tests(t, 1) - if TempDir == "" { + if TmpDir() == "" { t.Error("No temp directory specified") } - if TempDir == tempDir { - t.Log("ioutil.TempDir() failed so using fallback path:", tempDir) + if TmpDir() == _TMP_DIR { + t.Log("ioutil.TempDir() failed so using fallback path:", _TMP_DIR) } } diff --git a/utils/consts/consts_unix.go b/utils/consts/consts_unix.go index 55c9fdc56..e608b82e7 100644 --- a/utils/consts/consts_unix.go +++ b/utils/consts/consts_unix.go @@ -7,6 +7,6 @@ const ( // PathSlash is an OS specific directory separator PathSlash = "/" - // tempDir is the location of temp directory if it cannot be automatically determind - tempDir = "/tmp/murex/" + // _TMP_DIR is the location of temp directory if it cannot be automatically determined + _TMP_DIR = "/tmp/murex/" ) diff --git a/utils/consts/consts_windows.go b/utils/consts/consts_windows.go index f0a218697..716130a51 100644 --- a/utils/consts/consts_windows.go +++ b/utils/consts/consts_windows.go @@ -5,9 +5,9 @@ package consts const ( // PathSlash is an OS specific directory separator. - // Normally in Windows this would be a \ but lets standardise everything in murex to be / + // Normally in Windows this would be a \ but lets standardize everything in murex to be / PathSlash = "/" - // tempDir is the location of temp directory if it cannot be automatically determind - tempDir = `c:/temp/murex/` + // _TMP_DIR is the location of temp directory if it cannot be automatically determined + _TMP_DIR = `c:/temp/murex/` ) diff --git a/utils/consts/temp.go b/utils/consts/temp.go index 000dab6c4..781fa8686 100644 --- a/utils/consts/temp.go +++ b/utils/consts/temp.go @@ -6,22 +6,22 @@ import ( "github.com/lmorg/murex/app" ) -// TempDir is the location of temp directory -var TempDir string +// temporaryDirectory is the location of tmp directory +var temporaryDirectory string func init() { var err error - TempDir, err = os.MkdirTemp("", app.Name) - if err != nil || TempDir == "" { - TempDir = tempDir + temporaryDirectory, err = os.MkdirTemp("", app.Name) + if err != nil || temporaryDirectory == "" { + temporaryDirectory = _TMP_DIR } - if TempDir[len(TempDir)-1:] != PathSlash { - TempDir += PathSlash + if temporaryDirectory[len(temporaryDirectory)-1:] != PathSlash { + temporaryDirectory += PathSlash } - createDirIfNotExist(TempDir) + createDirIfNotExist(temporaryDirectory) } func createDirIfNotExist(dir string) { @@ -36,3 +36,7 @@ func createDirIfNotExist(dir string) { } } } + +func TmpDir() string { + return temporaryDirectory +} diff --git a/utils/tmpfile.go b/utils/tmpfile.go index 089a2845b..47fa63eaf 100644 --- a/utils/tmpfile.go +++ b/utils/tmpfile.go @@ -34,7 +34,7 @@ func NewTempFile(reader io.Reader, ext string) (*TempFile, error) { return nil, err } - name := consts.TempDir + hex.EncodeToString(h.Sum(nil)) + "-" + strconv.Itoa(os.Getpid()) + ext + name := consts.TmpDir() + hex.EncodeToString(h.Sum(nil)) + "-" + strconv.Itoa(os.Getpid()) + ext file, err := os.Create(name) if err != nil { diff --git a/version.svg b/version.svg index 20c1b640e..f24ad3eca 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0050Version7.2.0050 +Version: 7.2.0051Version7.2.0051 From 70a01f9e1a915b855f8de0bb7cd91dbd66f44f39 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Mon, 27 Oct 2025 23:33:06 +0000 Subject: [PATCH 12/32] #857 escape builtins should use IsMethod instead of param count --- app/app.go | 2 +- builtins/core/escape/escape.go | 6 +++--- version.svg | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/app.go b/app/app.go index 355873701..fe366673b 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 51 + Revision = 52 ) var ( diff --git a/builtins/core/escape/escape.go b/builtins/core/escape/escape.go index bef16dc06..da40a4250 100644 --- a/builtins/core/escape/escape.go +++ b/builtins/core/escape/escape.go @@ -25,7 +25,7 @@ func cmdEscape(p *lang.Process) error { p.Stdout.SetDataType(types.String) var str string - if p.Parameters.Len() == 0 { + if p.IsMethod { b, err := p.Stdin.ReadAll() if err != nil { return err @@ -56,7 +56,7 @@ func cmdHtml(p *lang.Process) error { p.Stdout.SetDataType(types.String) var str string - if p.Parameters.Len() == 0 { + if p.IsMethod { b, err := p.Stdin.ReadAll() if err != nil { return err @@ -83,7 +83,7 @@ func cmdUrl(p *lang.Process) (err error) { p.Stdout.SetDataType(types.String) var str string - if p.Parameters.Len() == 0 { + if p.IsMethod { b, err := p.Stdin.ReadAll() if err != nil { return err diff --git a/version.svg b/version.svg index f24ad3eca..90377f8ef 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0051Version7.2.0051 +Version: 7.2.0052Version7.2.0052 From fe6a092470c37b51b202c936228e930dc0c33914 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Mon, 27 Oct 2025 23:49:13 +0000 Subject: [PATCH 13/32] #857 escape builtins unit tests updated --- app/app.go | 2 +- builtins/core/escape/escape_test.go | 166 ++++++++++++++-------------- version.svg | 2 +- 3 files changed, 88 insertions(+), 82 deletions(-) diff --git a/app/app.go b/app/app.go index fe366673b..5e681b65d 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 52 + Revision = 53 ) var ( diff --git a/builtins/core/escape/escape_test.go b/builtins/core/escape/escape_test.go index 14cf4aa09..5f5b514bf 100644 --- a/builtins/core/escape/escape_test.go +++ b/builtins/core/escape/escape_test.go @@ -1,43 +1,42 @@ -package escape +package escape_test import ( "testing" - _ "github.com/lmorg/murex/builtins/core/expressions" - _ "github.com/lmorg/murex/builtins/types/string" - "github.com/lmorg/murex/lang/types" + _ "github.com/lmorg/murex/builtins" "github.com/lmorg/murex/test" ) func TestEscape(t *testing.T) { - // as stdin - - test.RunMethodTest( - t, cmdEscape, "escape", - `hello world`, types.String, nil, - `"hello world"`, nil) - - test.RunMethodTest( - t, cmdEscape, "escape", - `"hello world"`, types.String, nil, - `"\"hello world\""`, nil) - - // as a parameter - - test.RunMethodTest( - t, cmdEscape, "escape", - ``, types.String, []string{`hello`, `world`}, - `"hello world"`, nil) - - test.RunMethodTest( - t, cmdEscape, "escape", - ``, types.String, []string{"hello world"}, - `"hello world"`, nil) - - test.RunMethodTest( - t, cmdEscape, "escape", - ``, types.String, []string{`"hello world"`}, - `"\"hello world\""`, nil) + tests := []test.MurexTest{ + // method + + { + Block: `tout str hello world -> escape`, + Stdout: `"hello world"`, + }, + { + Block: `tout str '"hello world"' -> escape`, + Stdout: `"\"hello world\""`, + }, + + // parameter + + { + Block: `escape hello world`, + Stdout: `"hello world"`, + }, + { + Block: `escape "hello world"`, + Stdout: `"hello world"`, + }, + { + Block: `escape '"hello world"'`, + Stdout: `"\"hello world\""`, + }, + } + + test.RunMurexTests(tests, t) } func TestEscapeBang(t *testing.T) { @@ -67,35 +66,36 @@ func TestEscapeBang(t *testing.T) { test.RunMurexTests(tests, t) } -func TestHtml(t *testing.T) { - // as stdin - - test.RunMethodTest( - t, cmdHtml, "eschtml", - `foo & bar`, types.String, nil, - `foo & bar`, nil) - - test.RunMethodTest( - t, cmdHtml, "eschtml", - `"foo & bar"`, types.String, nil, - `"foo & bar"`, nil) +func TestHTML(t *testing.T) { + tests := []test.MurexTest{ + // method - // as a parameter + { + Block: `tout str foo & bar -> eschtml`, + Stdout: `foo & bar`, + }, + { + Block: `tout str '"foo & bar"' -> eschtml`, + Stdout: `"foo & bar"`, + }, - test.RunMethodTest( - t, cmdHtml, "escape", - ``, types.String, []string{`foo`, `&`, `bar`}, - `foo & bar`, nil) + // parameter - test.RunMethodTest( - t, cmdHtml, "escape", - ``, types.String, []string{"foo & bar"}, - `foo & bar`, nil) + { + Block: `eschtml foo & bar`, + Stdout: `foo & bar`, + }, + { + Block: `eschtml "foo & bar"`, + Stdout: `foo & bar`, + }, + { + Block: `eschtml '"foo & bar"'`, + Stdout: `"foo & bar"`, + }, + } - test.RunMethodTest( - t, cmdHtml, "escape", - ``, types.String, []string{`"foo & bar"`}, - `"foo & bar"`, nil) + test.RunMurexTests(tests, t) } func TestHtmlBang(t *testing.T) { @@ -110,25 +110,27 @@ func TestHtmlBang(t *testing.T) { } func TestUrl(t *testing.T) { - // as stdin - - test.RunMethodTest( - t, cmdUrl, "escurl", - `foo bar`, types.String, nil, - `foo%20bar`, nil) + tests := []test.MurexTest{ + // method - // as a parameter + { + Block: `tout str foo bar -> escurl`, + Stdout: `foo%20bar`, + }, - test.RunMethodTest( - t, cmdUrl, "escurl", - ``, types.String, []string{`foo`, `bar`}, - `foo%20bar`, nil) + // parameter - test.RunMethodTest( - t, cmdUrl, "escurl", - ``, types.String, []string{"foo bar"}, - `foo%20bar`, nil) + { + Block: `escurl foo bar`, + Stdout: `foo%20bar`, + }, + { + Block: `escurl "foo bar"`, + Stdout: `foo%20bar`, + }, + } + test.RunMurexTests(tests, t) } func TestUrlBang(t *testing.T) { @@ -143,16 +145,20 @@ func TestUrlBang(t *testing.T) { } func TestCli(t *testing.T) { - // as stdin + tests := []test.MurexTest{ + // method - test.RunMethodTest( - t, cmdEscapeCli, "esccli", - `foo bar`, types.String, nil, - "foo\\ bar\n", nil) -} + { + Block: `tout str foo bar -> esccli`, + Stdout: "foo\\ bar\n", + }, + { + Block: `tout str '"foo bar"' -> esccli`, + Stdout: "\\\"foo\\ bar\\\"\n", + }, + + // parameter -func TestCli2(t *testing.T) { - tests := []test.MurexTest{ { Block: `esccli foo bar`, Stdout: "foo bar\n", diff --git a/version.svg b/version.svg index 90377f8ef..689764428 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0052Version7.2.0052 +Version: 7.2.0053Version7.2.0053 From 3328b291133ffeb2f5fea196f0032a65f8a10488 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sun, 2 Nov 2025 17:25:39 +0000 Subject: [PATCH 14/32] cache.db: dont cache anything with a TTL < 1hr --- app/app.go | 2 +- utils/cache/internal.go | 5 +++++ version.svg | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/app.go b/app/app.go index 5e681b65d..55758b9b0 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 53 + Revision = 58 ) var ( diff --git a/utils/cache/internal.go b/utils/cache/internal.go index b2c6ab144..6b8d77f9c 100644 --- a/utils/cache/internal.go +++ b/utils/cache/internal.go @@ -90,6 +90,11 @@ func (ic *internalCacheT) Write(key string, value *[]byte, ttl time.Time) { return } + if ttl.Before(time.Now().Add(59 * time.Minute)) { + // lets not bother writing anything to cache.db if the TTL < 1 hr + return + } + ic.mutex.Lock() ic.cache[key] = &cacheItemT{value, ttl} ic.mutex.Unlock() diff --git a/version.svg b/version.svg index 689764428..98d92f7b5 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0053Version7.2.0053 +Version: 7.2.0058Version7.2.0058 From dfff8ace26c9eca702009b7f01988713f58081d5 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sun, 2 Nov 2025 21:57:39 +0000 Subject: [PATCH 15/32] wasm: support for builds via tinygo --- Makefile | 17 +++++++- app/app.go | 2 +- builtins/core/httpclient/client.go | 52 ++++------------------- builtins/core/httpclient/client_std.go | 44 +++++++++++++++++++ builtins/core/httpclient/client_tinygo.go | 14 ++++++ builtins/core/runtime/runtime.go | 4 +- builtins/core/runtime/runtime_std.go | 14 ++++++ builtins/core/runtime/runtime_tinygo.go | 16 +++++++ lang/process_fallback.go | 4 +- lang/process_unix.go | 4 +- shell/session/session_fallback.go | 9 +++- shell/session/session_unix.go | 4 +- version.svg | 2 +- 13 files changed, 130 insertions(+), 56 deletions(-) create mode 100644 builtins/core/httpclient/client_std.go create mode 100644 builtins/core/httpclient/client_tinygo.go create mode 100644 builtins/core/runtime/runtime_std.go create mode 100644 builtins/core/runtime/runtime_tinygo.go diff --git a/Makefile b/Makefile index 5b2520c56..26784db12 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,9 @@ BUILD_TAGS?=$(shell cat builtins/optional/standard-opts.txt || echo "") # Default target .PHONY: all +all: generate all: build +all: build-wasm # Build the binary .PHONY: build @@ -39,11 +41,24 @@ run: build-dev # Build with dev flags .PHONY: build-dev -build-dev: generate build-dev: GO_FLAGS += -gcflags="-N -l" -race build-dev: BUILD_TAGS := "$(BUILD_TAGS),pprof,trace,no_crash_handler" build-dev: build +# Build with TinyGo instead of default Go binary +.PHONY: build-tinygo +build-tinygo: LDFLAGS=-ldflags "-X github.com/lmorg/murex/app.branch=${BRANCH} -X github.com/lmorg/murex/app.buildDate=${BUILD_DATE}" +build-tinygo: BUILD_TAGS := "$(BUILD_TAGS),tinygo,no_cachedb,no_cmd_select,no_pty" +build-tinygo: + @echo "Building ${BINARY_NAME} using TinyGo..." + tinygo build -x -tags ${BUILD_TAGS} + +# Build WASM +.PHONY: build-wasm +build-wasm: export GOOS=js +build-wasm: export GOARCH=wasm +build-wasm: build-tinygo + # Test .PHONY: test test: build diff --git a/app/app.go b/app/app.go index 55758b9b0..329a4ffb7 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 58 + Revision = 61 ) var ( diff --git a/builtins/core/httpclient/client.go b/builtins/core/httpclient/client.go index 313cd6313..e0af59920 100644 --- a/builtins/core/httpclient/client.go +++ b/builtins/core/httpclient/client.go @@ -2,7 +2,6 @@ package httpclient import ( "context" - "crypto/tls" "net" "net/http" neturl "net/url" @@ -24,58 +23,27 @@ const ( var rxHttpProto = regexp.MustCompile(`(?i)^http(s)?://`) // Request generates a HTTP request -func Request(ctx context.Context, method, url string, body stdio.Io, conf *config.Config, setTimeout bool) (response *http.Response, err error) { - toStr, err := conf.Get("http", "timeout", types.String) +func Request(ctx context.Context, method, url string, body stdio.Io, conf *config.Config, setTimeout bool) (*http.Response, error) { + client, err := createClient(conf, setTimeout) if err != nil { - return - } - toDur, err := time.ParseDuration(toStr.(string) + "s") - if err != nil { - return - } - - insecure, err := conf.Get("http", "insecure", types.Boolean) - if err != nil { - return - } - - var client *http.Client - if setTimeout { - tr := http.Transport{ - Dial: dialTimeout(toDur, toDur), - TLSClientConfig: &tls.Config{InsecureSkipVerify: insecure.(bool)}, - } - - client = &http.Client{ - Timeout: toDur, - Transport: &tr, - } - - } else { - tr := http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: insecure.(bool)}, - } - - client = &http.Client{ - Transport: &tr, - } + return nil, err } userAgent, err := conf.Get("http", "user-agent", types.String) if err != nil { - return + return nil, err } request, err := http.NewRequest(method, url, body) if err != nil { - return + return nil, err } request = request.WithContext(ctx) urlParsed, err := neturl.Parse(url) if err != nil { - return + return nil, err } if body != nil { @@ -92,16 +60,14 @@ func Request(ctx context.Context, method, url string, body stdio.Io, conf *confi redirects, err := conf.Get("http", "redirect", types.Boolean) if err != nil { - return + return nil, err } if redirects.(bool) { - response, err = client.Do(request) - } else { - response, err = client.Transport.RoundTrip(request) + return client.Do(request) } - return + return client.Transport.RoundTrip(request) } // dialTimeout function unashamedly copy and pasted from: diff --git a/builtins/core/httpclient/client_std.go b/builtins/core/httpclient/client_std.go new file mode 100644 index 000000000..3d399f99a --- /dev/null +++ b/builtins/core/httpclient/client_std.go @@ -0,0 +1,44 @@ +//go:build !tinygo +// +build !tinygo + +package httpclient + +import ( + "crypto/tls" + "net/http" + "time" + + "github.com/lmorg/murex/config" + "github.com/lmorg/murex/lang/types" +) + +func createClient(conf *config.Config, setTimeout bool) (*http.Client, error) { + toStr, err := conf.Get("http", "timeout", types.String) + if err != nil { + return nil, err + } + toDur, err := time.ParseDuration(toStr.(string) + "s") + if err != nil { + return nil, err + } + + insecure, err := conf.Get("http", "insecure", types.Boolean) + if err != nil { + return nil, err + } + + if setTimeout { + tr := http.Transport{ + Dial: dialTimeout(toDur, toDur), + TLSClientConfig: &tls.Config{InsecureSkipVerify: insecure.(bool)}, + } + + return &http.Client{Timeout: toDur, Transport: &tr}, nil + } + + tr := http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: insecure.(bool)}, + } + + return &http.Client{Transport: &tr}, nil +} diff --git a/builtins/core/httpclient/client_tinygo.go b/builtins/core/httpclient/client_tinygo.go new file mode 100644 index 000000000..d201c36aa --- /dev/null +++ b/builtins/core/httpclient/client_tinygo.go @@ -0,0 +1,14 @@ +//go:build tinygo +// +build tinygo + +package httpclient + +import ( + "net/http" + + "github.com/lmorg/murex/config" +) + +func createClient(conf *config.Config, setTimeout bool) (*http.Client, error) { + return &http.Client{}, nil +} diff --git a/builtins/core/runtime/runtime.go b/builtins/core/runtime/runtime.go index 01eea2c44..59b3c187c 100644 --- a/builtins/core/runtime/runtime.go +++ b/builtins/core/runtime/runtime.go @@ -352,8 +352,8 @@ func dumpAbout() any { "Alloc": humannumbers.Bytes(mem.Alloc), "SessionLifeTime": humannumbers.Bytes(mem.TotalAlloc), "Sys": humannumbers.Bytes(mem.Sys), - "NumGC": mem.NumGC, - "NumForcedGC": mem.NumForcedGC, + "NumGC": memNumGC(&mem), + "NumForcedGC": memNumForcedGC(&mem), } return m diff --git a/builtins/core/runtime/runtime_std.go b/builtins/core/runtime/runtime_std.go new file mode 100644 index 000000000..bd7fe75ad --- /dev/null +++ b/builtins/core/runtime/runtime_std.go @@ -0,0 +1,14 @@ +//go:build !tinygo +// +build !tinygo + +package cmdruntime + +import "runtime" + +func memNumGC(mem *runtime.MemStats) any { + return mem.NumGC +} + +func memNumForcedGC(mem *runtime.MemStats) any { + return mem.NumForcedGC +} diff --git a/builtins/core/runtime/runtime_tinygo.go b/builtins/core/runtime/runtime_tinygo.go new file mode 100644 index 000000000..7300fee5d --- /dev/null +++ b/builtins/core/runtime/runtime_tinygo.go @@ -0,0 +1,16 @@ +//go:build tinygo +// +build tinygo + +package cmdruntime + +import "runtime" + +const unsupportedTinyGo = "unsupported in TinyGo" + +func memNumGC(mem *runtime.MemStats) any { + return unsupportedTinyGo +} + +func memNumForcedGC(mem *runtime.MemStats) any { + return unsupportedTinyGo +} diff --git a/lang/process_fallback.go b/lang/process_fallback.go index 8f6037b6b..941f403b6 100644 --- a/lang/process_fallback.go +++ b/lang/process_fallback.go @@ -1,5 +1,5 @@ -//go:build windows || plan9 || js -// +build windows plan9 js +//go:build windows || plan9 || js || no_pty +// +build windows plan9 js no_pty package lang diff --git a/lang/process_unix.go b/lang/process_unix.go index 1208f27d1..193b47aec 100644 --- a/lang/process_unix.go +++ b/lang/process_unix.go @@ -1,5 +1,5 @@ -//go:build !windows && !plan9 && !js -// +build !windows,!plan9,!js +//go:build !windows && !plan9 && !js && !no_pty +// +build !windows,!plan9,!js,!no_pty package lang diff --git a/shell/session/session_fallback.go b/shell/session/session_fallback.go index 0c5bdc0a2..d66dc8066 100644 --- a/shell/session/session_fallback.go +++ b/shell/session/session_fallback.go @@ -1,9 +1,10 @@ -//go:build js || windows || plan9 -// +build js windows plan9 +//go:build js || windows || plan9 || tinygo +// +build js windows plan9 tinygo package session import ( + "os" "runtime" "github.com/lmorg/murex/debug" @@ -18,3 +19,7 @@ func UnixIsSession() bool { return false } func UnixCreateSession() { debug.Logf("!!! UnixCreateSession is not supported on %s", runtime.GOOS) } + +func UnixTTY() *os.File { + return os.Stdin +} diff --git a/shell/session/session_unix.go b/shell/session/session_unix.go index 93431ab55..b6268d6c5 100644 --- a/shell/session/session_unix.go +++ b/shell/session/session_unix.go @@ -1,5 +1,5 @@ -//go:build !js && !windows && !plan9 -// +build !js,!windows,!plan9 +//go:build !js && !windows && !plan9 && !tinygo +// +build !js,!windows,!plan9,!tinygo package session diff --git a/version.svg b/version.svg index 98d92f7b5..2caa09961 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0058Version7.2.0058 +Version: 7.2.0061Version7.2.0061 From 1d08fca7bf0846d38069d302ec5ec655cc7912d8 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sun, 2 Nov 2025 23:03:19 +0000 Subject: [PATCH 16/32] integrations: yarn refactor (WIP) --- app/app.go | 2 +- integrations/yarn_any.mx | 122 ++++++++++++++++++++++++--------------- version.svg | 2 +- 3 files changed, 76 insertions(+), 50 deletions(-) diff --git a/app/app.go b/app/app.go index 329a4ffb7..e3eebf142 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 61 + Revision = 62 ) var ( diff --git a/integrations/yarn_any.mx b/integrations/yarn_any.mx index 11d760463..657e5eedd 100644 --- a/integrations/yarn_any.mx +++ b/integrations/yarn_any.mx @@ -2,60 +2,86 @@ return } -autocomplete: set yarn ({[ +private yarn.autocomplete.1 { + cast json + autocomplete = %{} + + trypipe { + g ${yarn bin}/* \ + -> regexp s,^.*/,, \ + -> foreach --jmap bin { $bin } { out "yarn bin" } \ + -> set autocomplete + } + + trypipe { + $autocomplete <~ ${ yarn help -> tabulate: --key-value --split-comma --key-inc-hint --map } + } +} + +test unit private yarn.autocomplete.1 %{ + StdoutType: json + StdoutIsMap: true + StdoutGreaterThan: 10 +} + + + +private yarn.autocomplete.commands { + yarn help \ + -> [Commands..Run]re \ + -> [:1] \ + -> cast str \ + -> foreach --jmap cmd { $cmd } { yarn help $cmd -> [Usage..Options]rebt } +} + +test unit private yarn.autocomplete.commands %{ + StdoutType: json + StdoutIsMap: true + StdoutGreaterThan: 10 +} + +bg { + MODULE.yarn_autocomplete_commands = yarn.autocomplete.commands() +} + +autocomplete set yarn %[ { - "CacheTTL": 30, - "Dynamic": ({ - g: ${yarn bin}/* -> regexp: s,^.*/,, - }), - "FlagsDesc": ${ - trypipe { - yarn help -> tabulate: --key-value --split-comma --key-inc-hint --map - } - }, - "Optional": true, - "AllowMultiple": true, - "AllowNoFlagValue": true, - "FlagValues": {"*": [ - { "IncDirs": true }, - { "Goto": "/0" } - ]} - }, + CacheTTL: 120 + DynamicDesc: '{yarn.autocomplete.1}' + Optional: true + AllowMultiple: true + AllowNoFlagValue: true + FlagValues: { + "*": [ + { IncDirs: true } + { Goto: "/0" } + ] + } + } { - "DynamicDesc": ({ + DynamicDesc: '{ cast json - if { g: package.json } then { + if { g package.json } then { open package.json -> [ scripts ] } - }), - "Optional": true - }, - { - "Flags": ${ - trypipe { - yarn help -> [Commands..Run]re -> [:1] -> cast str -> format json - } - }, - "FlagValues": { - ${ - trypipe { - yarn help -> [Commands..Run]re -> [:1] -> foreach MOD_cmd { - out ("$MOD_cmd": - [{ - "DynamicDesc": ({ + }' + Optional: true + } + /#{ + DynamicDesc: '{ $MODULE.yarn_autocomplete_commands }' + FlagValues: { + "*": [{ + DynamicDesc: '{ yarn help $MOD_cmd -> tabulate: --key-value --split-comma --key-inc-hint --map - }), - "AllowMultiple": true, - "AllowNoFlagValue": true, - "FlagValues": {"*": [ - { "IncDirs": true }, - { "Goto": "/2/add/0" } + }) + AllowMultiple: true + AllowNoFlagValue: true + FlagValues: {"*": [ + { IncDirs: true } + { Goto: "/2/add/0" } ]} }],) - } - } - } - "": [{ }] + }] } - } -]}) \ No newline at end of file + }#/ +] \ No newline at end of file diff --git a/version.svg b/version.svg index 2caa09961..b881232f2 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0061Version7.2.0061 +Version: 7.2.0062Version7.2.0062 From 50b3943ab0b7f85e9b6659a5584ad863c940e24b Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sun, 9 Nov 2025 22:19:03 +0000 Subject: [PATCH 17/32] chore: rename main_GOOS.go -> signals_GOOS.go --- app/app.go | 2 +- main_js.go | 4 ++-- main_plan9.go => signals_plan9.go | 0 main_unix.go => signals_unix.go | 0 main_windows.go => signals_windows.go | 0 version.svg | 2 +- 6 files changed, 4 insertions(+), 4 deletions(-) rename main_plan9.go => signals_plan9.go (100%) rename main_unix.go => signals_unix.go (100%) rename main_windows.go => signals_windows.go (100%) diff --git a/app/app.go b/app/app.go index e3eebf142..8fad8669c 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 62 + Revision = 63 ) var ( diff --git a/main_js.go b/main_js.go index c07d2deaf..2557fb602 100644 --- a/main_js.go +++ b/main_js.go @@ -13,7 +13,6 @@ import ( "github.com/lmorg/murex/config/profile" "github.com/lmorg/murex/lang" "github.com/lmorg/murex/shell" - signalhandler "github.com/lmorg/murex/shell/signal_handler" "github.com/lmorg/murex/utils/ansi" "github.com/lmorg/readline/v4" ) @@ -124,7 +123,8 @@ func wasmKeyPress() js.Func { }) } +/* func registerSignalHandlers(interactiveMode bool) { signalhandler.Handlers = &signalhandler.SignalFunctionsT{} signalhandler.EventLoop(interactiveMode) -} +}*/ diff --git a/main_plan9.go b/signals_plan9.go similarity index 100% rename from main_plan9.go rename to signals_plan9.go diff --git a/main_unix.go b/signals_unix.go similarity index 100% rename from main_unix.go rename to signals_unix.go diff --git a/main_windows.go b/signals_windows.go similarity index 100% rename from main_windows.go rename to signals_windows.go diff --git a/version.svg b/version.svg index b881232f2..7daa6c887 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0062Version7.2.0062 +Version: 7.2.0063Version7.2.0063 From cab431e79130566b379e2a2e0a16f398f707c07b Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sun, 9 Nov 2025 23:31:14 +0000 Subject: [PATCH 18/32] integrations: python: uv + venv.mx --- app/app.go | 2 +- integrations/python_any.mx | 57 ++++++++++++++++++++++++++++++++++++++ version.svg | 2 +- 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 integrations/python_any.mx diff --git a/app/app.go b/app/app.go index 8fad8669c..ae3d4cb18 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 63 + Revision = 64 ) var ( diff --git a/integrations/python_any.mx b/integrations/python_any.mx new file mode 100644 index 000000000..bf6a95c43 --- /dev/null +++ b/integrations/python_any.mx @@ -0,0 +1,57 @@ +if { os posix } then { + function venv.mx { + # Enter a Python virtual environment from a Murex shell + + venv = $1 ?? ".venv/bin/activate" + + out "Entering venv: $(venv)..." + + out " + config set shell prompt '{ + out %((venv) \$PWD[-1] {BLUE}»{RESET} ) + }' + config set shell prompt-multiline '{ + len = \${pwd_short -> [-1] -> count --bytes} - 1 + printf %((venv) %\${\$len}s » ) \$linenum + }' + out 'Type `exit` or ctrl+d to return' + " -> tmp -> set murex_init + + bash -c %( + source $venv + $MUREX_EXE -quiet -ignore-whatsnew -i -execute source $murex_init + ) + } +} + +if { which uv } then { + summary uv ${ uv --help -> [..1] } + + autocomplete set uv %[ + { + DynamicDesc: '{ uv --help -> tabulate --column-wraps --split-comma --map --key-inc-hint }' + DynamicPreview: '{ uv --help }' + #AllowMultiple: true + AllowAny: true + } + { + DynamicDesc: '{ uv $1 --help -> tabulate --column-wraps --split-comma --map --key-inc-hint }' + DynamicPreview: '{ uv help $1 }' + AllowMultiple: true + AllowAny: true + } + ] +} + +if { which uvx } then { + summary uvx ${ uvx --help -> [..1] } + + autocomplete set uvx %[ + { + DynamicDesc: '{ uvx --help -> tabulate --column-wraps --split-comma --map --key-inc-hint }' + DynamicPreview: '{ uv --help }' + AllowMultiple: true + AllowAny: true + } + ] +} diff --git a/version.svg b/version.svg index 7daa6c887..c8ab7bee4 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0063Version7.2.0063 +Version: 7.2.0064Version7.2.0064 From 012aa4081ba5dd7230e55d04bc7694195f077c64 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Mon, 10 Nov 2025 21:28:45 +0000 Subject: [PATCH 19/32] integrations: uv --- app/app.go | 2 +- integrations/python_any.mx | 57 ----------------------------- integrations/python_posix.mx | 23 ++++++++++++ integrations/python_uv_any.mx | 69 +++++++++++++++++++++++++++++++++++ lang/test_messages.go | 4 +- version.svg | 2 +- 6 files changed, 96 insertions(+), 61 deletions(-) delete mode 100644 integrations/python_any.mx create mode 100644 integrations/python_posix.mx create mode 100644 integrations/python_uv_any.mx diff --git a/app/app.go b/app/app.go index ae3d4cb18..aa3314a07 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 64 + Revision = 65 ) var ( diff --git a/integrations/python_any.mx b/integrations/python_any.mx deleted file mode 100644 index bf6a95c43..000000000 --- a/integrations/python_any.mx +++ /dev/null @@ -1,57 +0,0 @@ -if { os posix } then { - function venv.mx { - # Enter a Python virtual environment from a Murex shell - - venv = $1 ?? ".venv/bin/activate" - - out "Entering venv: $(venv)..." - - out " - config set shell prompt '{ - out %((venv) \$PWD[-1] {BLUE}»{RESET} ) - }' - config set shell prompt-multiline '{ - len = \${pwd_short -> [-1] -> count --bytes} - 1 - printf %((venv) %\${\$len}s » ) \$linenum - }' - out 'Type `exit` or ctrl+d to return' - " -> tmp -> set murex_init - - bash -c %( - source $venv - $MUREX_EXE -quiet -ignore-whatsnew -i -execute source $murex_init - ) - } -} - -if { which uv } then { - summary uv ${ uv --help -> [..1] } - - autocomplete set uv %[ - { - DynamicDesc: '{ uv --help -> tabulate --column-wraps --split-comma --map --key-inc-hint }' - DynamicPreview: '{ uv --help }' - #AllowMultiple: true - AllowAny: true - } - { - DynamicDesc: '{ uv $1 --help -> tabulate --column-wraps --split-comma --map --key-inc-hint }' - DynamicPreview: '{ uv help $1 }' - AllowMultiple: true - AllowAny: true - } - ] -} - -if { which uvx } then { - summary uvx ${ uvx --help -> [..1] } - - autocomplete set uvx %[ - { - DynamicDesc: '{ uvx --help -> tabulate --column-wraps --split-comma --map --key-inc-hint }' - DynamicPreview: '{ uv --help }' - AllowMultiple: true - AllowAny: true - } - ] -} diff --git a/integrations/python_posix.mx b/integrations/python_posix.mx new file mode 100644 index 000000000..3c1b9caaa --- /dev/null +++ b/integrations/python_posix.mx @@ -0,0 +1,23 @@ +function venv.mx { + # Enter a Python virtual environment from a Murex shell + + venv = $1 ?? ".venv/bin/activate" + + out "Entering venv: $(venv)..." + + out " + config set shell prompt '{ + out %((venv) \$PWD[-1] {BLUE}»{RESET} ) + }' + config set shell prompt-multiline '{ + len = \${pwd_short -> [-1] -> count --bytes} - 1 + printf %((venv) %\${\$len}s » ) \$linenum + }' + out 'Type `exit` or ctrl+d to return' + " -> tmp -> set murex_init + + bash -c %( + source $venv + $MUREX_EXE -quiet -ignore-whatsnew -i -execute source $murex_init + ) +} diff --git a/integrations/python_uv_any.mx b/integrations/python_uv_any.mx new file mode 100644 index 000000000..63ec0be4f --- /dev/null +++ b/integrations/python_uv_any.mx @@ -0,0 +1,69 @@ +if { which uv } then { + private uv.summary { + # Automatically populate the command summary for `uv` + uv --help -> [..1] + } + + summary uv fexec(private /builtin/integrations_python_uv_any/uv.summary) + + private uv.autocomplete { + # Autocompletions for `uv` + + config set proc strict-arrays false + + parameters = ${ + trypipe { @PARAMS -> [...-]re } + } ?: %[] + + uv @parameters --help \ + -> tabulate --column-wraps --split-comma --map --key-inc-hint + } + + private uv.preview { + # Man page for `uv` preview + + config set proc strict-arrays false + + parameters = ${ + try { @PARAMS -> [...-]re } + } ?: %[] + + uv help @parameters + } + + autocomplete set uv %[ + { + DynamicDesc: '{ uv.autocomplete }' + DynamicPreview: '{ uv.preview }' + AllowMultiple: true + AllowAny: true + } + ] + + test unit private uv.summary %{ + StdoutType: * + StdoutRegex: Python + } + + test unit private uv.autocomplete %{ + StdoutType: json + StdoutIsMap: true + } + + test unit private uv.preview %{ + StdoutType: * + } +} + +if { which uvx } then { + summary uvx ${ uvx --help -> [..1] } + + autocomplete set uvx %[ + { + DynamicDesc: '{ uvx --help -> tabulate --column-wraps --split-comma --map --key-inc-hint }' + DynamicPreview: '{ uv --help }' + AllowMultiple: true + AllowAny: true + } + ] +} diff --git a/lang/test_messages.go b/lang/test_messages.go index f09d74490..dba950fa6 100644 --- a/lang/test_messages.go +++ b/lang/test_messages.go @@ -71,7 +71,7 @@ func tMsgDataTypeMatch(stdType string) string { } func tMsgStringMismatch(property string, std []byte) string { - return fmt.Sprintf("%s string mismatch. Got: '%s'", property, std) + return fmt.Sprintf("%s string mismatch. Got: %s", property, std) } func tMsgStringMatch(property string) string { return fmt.Sprintf("%s matches expected string", property) @@ -81,7 +81,7 @@ func tMsgRegexCompileErr(property string, err error) string { return fmt.Sprintf("%s could not compile: %s", property, err) } func tMsgRegexMismatch(property string, std []byte) string { - return fmt.Sprintf("%s expression did not match. Got: '%s'", property, std) + return fmt.Sprintf("%s expression did not match. Got: %s", property, std) } func tMsgRegexMatch(property string) string { return fmt.Sprintf("%s matches expected regex expression", property) diff --git a/version.svg b/version.svg index c8ab7bee4..0f1a32e88 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0064Version7.2.0064 +Version: 7.2.0065Version7.2.0065 From dca418dc87fb8b7f77ee01604d6a483baf07bee4 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Mon, 10 Nov 2025 21:29:41 +0000 Subject: [PATCH 20/32] #956 integrations: yarn bug fix --- app/app.go | 2 +- integrations/yarn_any.mx | 15 ++++++++------- version.svg | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/app/app.go b/app/app.go index aa3314a07..5e33f38f9 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 65 + Revision = 66 ) var ( diff --git a/integrations/yarn_any.mx b/integrations/yarn_any.mx index 657e5eedd..eae506f14 100644 --- a/integrations/yarn_any.mx +++ b/integrations/yarn_any.mx @@ -7,15 +7,18 @@ private yarn.autocomplete.1 { autocomplete = %{} trypipe { - g ${yarn bin}/* \ - -> regexp s,^.*/,, \ - -> foreach --jmap bin { $bin } { out "yarn bin" } \ - -> set autocomplete + autocomplete <~ ${ + g ${yarn bin}/* \ + -> regexp s,^.*/,, \ + -> foreach --jmap bin { $bin } { out "yarn bin" } + } } trypipe { - $autocomplete <~ ${ yarn help -> tabulate: --key-value --split-comma --key-inc-hint --map } + autocomplete <~ ${ yarn help -> tabulate: --key-value --split-comma --key-inc-hint --map } } + + $autocomplete } test unit private yarn.autocomplete.1 %{ @@ -24,8 +27,6 @@ test unit private yarn.autocomplete.1 %{ StdoutGreaterThan: 10 } - - private yarn.autocomplete.commands { yarn help \ -> [Commands..Run]re \ diff --git a/version.svg b/version.svg index 0f1a32e88..97d4e2170 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0065Version7.2.0065 +Version: 7.2.0066Version7.2.0066 From 33125026beda1958efe1d39140ea2ab6ecc04a8b Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Mon, 10 Nov 2025 22:55:44 +0000 Subject: [PATCH 21/32] integrations: yarn: don't unit test because there are too many edge case implementations of yarn --- app/app.go | 2 +- integrations/yarn_any.mx | 8 ++++---- version.svg | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/app.go b/app/app.go index 5e33f38f9..011f23cec 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 66 + Revision = 67 ) var ( diff --git a/integrations/yarn_any.mx b/integrations/yarn_any.mx index eae506f14..071707365 100644 --- a/integrations/yarn_any.mx +++ b/integrations/yarn_any.mx @@ -21,11 +21,11 @@ private yarn.autocomplete.1 { $autocomplete } -test unit private yarn.autocomplete.1 %{ +/#test unit private yarn.autocomplete.1 %{ StdoutType: json StdoutIsMap: true StdoutGreaterThan: 10 -} +}#/ private yarn.autocomplete.commands { yarn help \ @@ -35,11 +35,11 @@ private yarn.autocomplete.commands { -> foreach --jmap cmd { $cmd } { yarn help $cmd -> [Usage..Options]rebt } } -test unit private yarn.autocomplete.commands %{ +/#test unit private yarn.autocomplete.commands %{ StdoutType: json StdoutIsMap: true StdoutGreaterThan: 10 -} +}#/ bg { MODULE.yarn_autocomplete_commands = yarn.autocomplete.commands() diff --git a/version.svg b/version.svg index 97d4e2170..9e162dd8a 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0066Version7.2.0066 +Version: 7.2.0067Version7.2.0067 From 80f50a66e7e7e80734c2a9df36813c0d81f6adf2 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Tue, 25 Nov 2025 23:31:37 +0000 Subject: [PATCH 22/32] integrations: python venv improvements (#960) --- app/app.go | 2 +- integrations/python_posix.mx | 40 +++++++++++++++++++++++++----------- version.svg | 2 +- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/app/app.go b/app/app.go index 011f23cec..3ddca5853 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 67 + Revision = 68 ) var ( diff --git a/integrations/python_posix.mx b/integrations/python_posix.mx index 3c1b9caaa..9b0ce7a6e 100644 --- a/integrations/python_posix.mx +++ b/integrations/python_posix.mx @@ -1,23 +1,39 @@ function venv.mx { # Enter a Python virtual environment from a Murex shell + + venv = $1 ?? ".venv" + activate = "$(venv)/bin/activate" - venv = $1 ?? ".venv/bin/activate" + if { g $activate } else { + err "Cannot start Python virtual environment because" + err "file does not exist: $activate" + return + } - out "Entering venv: $(venv)..." + out "Entering Python virtual environment: $(venv)..." + + export MUREX_OLD_PROMPT = ${ config get shell prompt -> base64 } + export MUREX_OLD_PROMPT_ML = ${ config get shell prompt-multiline -> base64 } out " - config set shell prompt '{ - out %((venv) \$PWD[-1] {BLUE}»{RESET} ) - }' - config set shell prompt-multiline '{ - len = \${pwd_short -> [-1] -> count --bytes} - 1 - printf %((venv) %\${\$len}s » ) \$linenum - }' + function _old_prompt \${ \$ENV.MUREX_OLD_PROMPT -> base64 -d } + function _old_prompt_ml \${ \$ENV.MUREX_OLD_PROMPT_ML -> base64 -d } + + config set shell prompt { + out %(($venv) \${_old_prompt}) + } + + config set shell prompt-multiline { + out %(($venv) \${_old_prompt_ml}) + } + + alias pydoc = python -m pydoc + out 'Type `exit` or ctrl+d to return' " -> tmp -> set murex_init - bash -c %( - source $venv - $MUREX_EXE -quiet -ignore-whatsnew -i -execute source $murex_init + bash -e -c %( + source $venv/bin/activate + $MUREX_EXE -load-modules -quiet -ignore-whatsnew -i -execute source $murex_init ) } diff --git a/version.svg b/version.svg index 9e162dd8a..5e016d156 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0067Version7.2.0067 +Version: Version From e7e40120ee0adab9242c7f13691e1dced8502776 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Tue, 25 Nov 2025 23:32:26 +0000 Subject: [PATCH 23/32] integrations: terraform-docs summary --- app/app.go | 2 +- integrations/terraform-docs_any.mx | 4 +++- version.svg | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/app.go b/app/app.go index 3ddca5853..5e2cccdfd 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 68 + Revision = 69 ) var ( diff --git a/integrations/terraform-docs_any.mx b/integrations/terraform-docs_any.mx index f4c1294d8..3d8fab7cf 100644 --- a/integrations/terraform-docs_any.mx +++ b/integrations/terraform-docs_any.mx @@ -1,3 +1,5 @@ +summary terraform-docs "A utility to generate documentation from Terraform modules in various output formats" + autocomplete set terraform-docs %[ { DynamicDesc: '{ @@ -9,4 +11,4 @@ autocomplete set terraform-docs %[ AllowAny: true ListView: true } -] \ No newline at end of file +] diff --git a/version.svg b/version.svg index 5e016d156..f720b49be 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: Version +Version: 7.2.0069Version7.2.0069 From f951aaac74e3861c59498f0778c8bce880b9ce8d Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Thu, 27 Nov 2025 10:41:39 +0000 Subject: [PATCH 24/32] makefile: add tags to `make test` --- Makefile | 4 ++-- app/app.go | 2 +- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- version.svg | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 26784db12..3c0c955a3 100644 --- a/Makefile +++ b/Makefile @@ -61,9 +61,9 @@ build-wasm: build-tinygo # Test .PHONY: test -test: build +test: @mkdir -p ./test/tmp - go test ./... -count 1 -race -covermode=atomic + go test ./... -count 1 -race -covermode=atomic -tags "$(BUILD_TAGS),no_crash_handler" ${BUILD_DIR}/${BINARY_NAME} -c 'g behavioural/*.mx -> foreach f { source $$f }; test run *' # Benchmark diff --git a/app/app.go b/app/app.go index 5e2cccdfd..57806f4c6 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 69 + Revision = 70 ) var ( diff --git a/go.mod b/go.mod index ede916768..720abcc55 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/mattn/go-sqlite3 v1.14.32 github.com/pelletier/go-toml v1.9.5 github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee - golang.org/x/sys v0.37.0 + golang.org/x/sys v0.38.0 golang.org/x/text v0.30.0 gopkg.in/yaml.v3 v3.0.1 modernc.org/sqlite v1.39.1 @@ -35,9 +35,9 @@ require ( github.com/stretchr/testify v1.11.1 // indirect golang.org/x/exp v0.0.0-20251017212417-90e834f514db // indirect golang.org/x/image v0.32.0 // indirect - golang.org/x/mod v0.29.0 // indirect - golang.org/x/sync v0.17.0 // indirect - golang.org/x/tools v0.38.0 // indirect + golang.org/x/mod v0.30.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/tools v0.39.0 // indirect modernc.org/libc v1.66.10 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect diff --git a/go.sum b/go.sum index 547887507..91c381f69 100644 --- a/go.sum +++ b/go.sum @@ -57,18 +57,18 @@ golang.org/x/exp v0.0.0-20251017212417-90e834f514db/go.mod h1:j/pmGrbnkbPtQfxEe5 golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.32.0 h1:6lZQWq75h7L5IWNk0r+SCpUJ6tUVd3v4ZHnbRKLkUDQ= golang.org/x/image v0.32.0/go.mod h1:/R37rrQmKXtO6tYXAjtDLwQgFLHmhW+V6ayXlxzP2Pc= -golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= -golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= -golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= -golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= -golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= -golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/version.svg b/version.svg index f720b49be..394fccab4 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0069Version7.2.0069 +Version: 7.2.0070Version7.2.0070 From 6251e56af1e45af7887e43e3cf07ea914f7f1074 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Thu, 27 Nov 2025 10:42:20 +0000 Subject: [PATCH 25/32] chore: update deps --- app/app.go | 2 +- go.mod | 15 ++++++++------- go.sum | 42 ++++++++++++++++++++++++------------------ version.svg | 2 +- 4 files changed, 34 insertions(+), 27 deletions(-) diff --git a/app/app.go b/app/app.go index 57806f4c6..e6fd8fe67 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 70 + Revision = 72 ) var ( diff --git a/go.mod b/go.mod index 720abcc55..835a83597 100644 --- a/go.mod +++ b/go.mod @@ -12,19 +12,20 @@ require ( github.com/fsnotify/fsnotify v1.9.0 github.com/hashicorp/hcl v1.0.0 github.com/lmorg/apachelogs v0.0.0-20161115121556-e5f3eae677ad - github.com/lmorg/readline/v4 v4.2.1 + github.com/lmorg/readline/v4 v4.2.2 github.com/mattn/go-runewidth v0.0.19 github.com/mattn/go-sqlite3 v1.14.32 github.com/pelletier/go-toml v1.9.5 github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee golang.org/x/sys v0.38.0 - golang.org/x/text v0.30.0 + golang.org/x/text v0.31.0 gopkg.in/yaml.v3 v3.0.1 - modernc.org/sqlite v1.39.1 + modernc.org/sqlite v1.40.1 ) require ( - github.com/clipperhouse/uax29/v2 v2.2.0 // indirect + github.com/clipperhouse/stringish v0.1.1 // indirect + github.com/clipperhouse/uax29/v2 v2.3.0 // indirect github.com/disintegration/imaging v1.6.2 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/google/uuid v1.6.0 // indirect @@ -33,12 +34,12 @@ require ( github.com/ncruces/go-strftime v1.0.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/stretchr/testify v1.11.1 // indirect - golang.org/x/exp v0.0.0-20251017212417-90e834f514db // indirect - golang.org/x/image v0.32.0 // indirect + golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 // indirect + golang.org/x/image v0.33.0 // indirect golang.org/x/mod v0.30.0 // indirect golang.org/x/sync v0.18.0 // indirect golang.org/x/tools v0.39.0 // indirect - modernc.org/libc v1.66.10 // indirect + modernc.org/libc v1.67.1 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect ) diff --git a/go.sum b/go.sum index 91c381f69..f9568e1eb 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,10 @@ github.com/boombuler/barcode v1.1.0 h1:ChaYjBR63fr4LFyGn8E8nt7dBSt3MiU3zMOZqFvVk github.com/boombuler/barcode v1.1.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= -github.com/clipperhouse/uax29/v2 v2.2.0 h1:ChwIKnQN3kcZteTXMgb1wztSgaU+ZemkgWdohwgs8tY= -github.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= +github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= +github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= +github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= +github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -26,12 +28,14 @@ github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17k github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/lmorg/apachelogs v0.0.0-20161115121556-e5f3eae677ad h1:TQcz4T52CwRmLT4KexBSPAL2XxAWKlsbpPyQ1hg9T50= github.com/lmorg/apachelogs v0.0.0-20161115121556-e5f3eae677ad/go.mod h1:ZCbRp0gZDkH+2t/flBuXpT4+FyrVodEONI0l5jUwYH0= -github.com/lmorg/readline/v4 v4.2.1 h1:tUr0/j6CPEmjMd7QMWm3D1WTVwPlH8f/QtSLgbyvgYU= -github.com/lmorg/readline/v4 v4.2.1/go.mod h1:Zdp/tnRZl0eTssyikMGSp61wOZwxJLw/CtK2sE2f9e8= +github.com/lmorg/readline/v4 v4.2.2 h1:aR1buzcMO525Omo7fS3H4ecUuONPv3nIENKHcTgrESg= +github.com/lmorg/readline/v4 v4.2.2/go.mod h1:Zdp/tnRZl0eTssyikMGSp61wOZwxJLw/CtK2sE2f9e8= github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= @@ -52,11 +56,11 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -golang.org/x/exp v0.0.0-20251017212417-90e834f514db h1:by6IehL4BH5k3e3SJmcoNbOobMey2SLpAF79iPOEBvw= -golang.org/x/exp v0.0.0-20251017212417-90e834f514db/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= +golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 h1:DHNhtq3sNNzrvduZZIiFyXWOL9IWaDPHqTnLJp+rCBY= +golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.32.0 h1:6lZQWq75h7L5IWNk0r+SCpUJ6tUVd3v4ZHnbRKLkUDQ= -golang.org/x/image v0.32.0/go.mod h1:/R37rrQmKXtO6tYXAjtDLwQgFLHmhW+V6ayXlxzP2Pc= +golang.org/x/image v0.33.0 h1:LXRZRnv1+zGd5XBUVRFmYEphyyKJjQjCRiOuAP3sZfQ= +golang.org/x/image v0.33.0/go.mod h1:DD3OsTYT9chzuzTQt+zMcOlBHgfoKQb1gry8p76Y1sc= golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= @@ -65,26 +69,28 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= -golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -modernc.org/cc/v4 v4.26.5 h1:xM3bX7Mve6G8K8b+T11ReenJOT+BmVqQj0FY5T4+5Y4= -modernc.org/cc/v4 v4.26.5/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= -modernc.org/ccgo/v4 v4.28.1 h1:wPKYn5EC/mYTqBO373jKjvX2n+3+aK7+sICCv4Fjy1A= -modernc.org/ccgo/v4 v4.28.1/go.mod h1:uD+4RnfrVgE6ec9NGguUNdhqzNIeeomeXf6CL0GTE5Q= +modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis= +modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.30.1 h1:4r4U1J6Fhj98NKfSjnPUN7Ze2c6MnAdL0hWw6+LrJpc= +modernc.org/ccgo/v4 v4.30.1/go.mod h1:bIOeI1JL54Utlxn+LwrFyjCx2n2RDiYEaJVSrgdrRfM= modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA= modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/gc/v3 v3.1.1 h1:k8T3gkXWY9sEiytKhcgyiZ2L0DTyCQ/nvX+LoCljoRE= +modernc.org/gc/v3 v3.1.1/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= -modernc.org/libc v1.66.10 h1:yZkb3YeLx4oynyR+iUsXsybsX4Ubx7MQlSYEw4yj59A= -modernc.org/libc v1.66.10/go.mod h1:8vGSEwvoUoltr4dlywvHqjtAqHBaw0j1jI7iFBTAr2I= +modernc.org/libc v1.67.1 h1:bFaqOaa5/zbWYJo8aW0tXPX21hXsngG2M7mckCnFSVk= +modernc.org/libc v1.67.1/go.mod h1:QvvnnJ5P7aitu0ReNpVIEyesuhmDLQ8kaEoyMjIFZJA= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= @@ -93,8 +99,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.39.1 h1:H+/wGFzuSCIEVCvXYVHX5RQglwhMOvtHSv+VtidL2r4= -modernc.org/sqlite v1.39.1/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE= +modernc.org/sqlite v1.40.1 h1:VfuXcxcUWWKRBuP8+BR9L7VnmusMgBNNnBYGEe9w/iY= +modernc.org/sqlite v1.40.1/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/version.svg b/version.svg index 394fccab4..6af681d9c 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0070Version7.2.0070 +Version: 7.2.0072Version7.2.0072 From 6456b12cdb451ad10293b5331d7eafb868d2e79c Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Wed, 3 Dec 2025 21:18:03 +0000 Subject: [PATCH 26/32] expressions bugfix: caught error wasn't being returned correctly --- app/app.go | 2 +- docs/commands/expr.md | 2 +- lang/expressions/exp14.go | 102 +++++---------------------------- lang/expressions/expression.go | 2 +- version.svg | 2 +- 5 files changed, 17 insertions(+), 93 deletions(-) diff --git a/app/app.go b/app/app.go index e6fd8fe67..99b3aaf8a 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 72 + Revision = 73 ) var ( diff --git a/docs/commands/expr.md b/docs/commands/expr.md index fe615ac8e..0068e6e6c 100644 --- a/docs/commands/expr.md +++ b/docs/commands/expr.md @@ -219,7 +219,7 @@ func executeExpression(tree *ParserT, order symbols.Exp) (err error) { case symbols.AssignAndDivide: err = expAssignAndOperate(tree, _assDiv) case symbols.AssignAndMultiply: - err = expAssignAndOperate(tree, _assMulti) + err = expAssignAndOperate(tree, _assMul) case symbols.AssignOrMerge: err = expAssignMerge(tree) diff --git a/lang/expressions/exp14.go b/lang/expressions/exp14.go index 79228e9e8..086097a87 100644 --- a/lang/expressions/exp14.go +++ b/lang/expressions/exp14.go @@ -106,7 +106,7 @@ func expAssign(tree *ParserT, overwriteType bool) error { } } - // this is ugly but Go's JSON marshaller is better behaved than Murexes on with empty values + // this is ugly but Go's JSON marshaller is more correct than Murexes with empty values if dt == types.Json { b, err := right.Marshal() if err != nil { @@ -136,7 +136,7 @@ func expAssign(tree *ParserT, overwriteType bool) error { v, err = types.ConvertGoType(right.Value, dt) if err != nil { - raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) + return raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) } } } @@ -154,95 +154,12 @@ func expAssign(tree *ParserT, overwriteType bool) error { }) } -/*func expAssignAdd(tree *ParserT) error { - leftNode, rightNode, err := tree.getLeftAndRightSymbols() - if err != nil { - return err - } - - if err = convertAssigneeToBareword(tree, leftNode); err != nil { - return err - } - - right, err := rightNode.dt.GetValue() - if err != nil { - return err - } - - if leftNode.key != symbols.Bareword { - return raiseError(tree.expression, leftNode, 0, fmt.Sprintf( - "left side of %s should be a bareword, instead got %s", - tree.currentSymbol().key, leftNode.key)) - } - - v, dt, err := tree.getVar(leftNode.value, varAsValue) - if err != nil { - if !tree.StrictTypes() && strings.Contains(err.Error(), lang.ErrDoesNotExist) { - // var doesn't exist and we have strict types disabled so lets create var - v, dt, err = float64(0), types.Number, nil - } else { - return raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) - } - } - - var result any - - switch dt { - case types.Number, types.Float: - if right.Primitive != primitives.Number { - return raiseError(tree.expression, tree.currentSymbol(), 0, fmt.Sprintf( - "cannot %s %s to %s", tree.currentSymbol().key, right.Primitive, dt)) - } - result = v.(float64) + right.Value.(float64) - - case types.Integer: - if right.Primitive != primitives.Number { - return raiseError(tree.expression, tree.currentSymbol(), 0, fmt.Sprintf( - "cannot %s %s to %s", tree.currentSymbol().key, right.Primitive, dt)) - } - result = float64(v.(int)) + right.Value.(float64) - - case types.Boolean: - return raiseError(tree.expression, tree.currentSymbol(), 0, fmt.Sprintf( - "cannot %s %s", tree.currentSymbol().key, dt)) - - case types.Null: - switch right.Primitive { - case primitives.String: - result = right.Value.(string) - case primitives.Number: - result = right.Value.(float64) - default: - return raiseError(tree.expression, tree.currentSymbol(), 0, fmt.Sprintf( - "cannot %s %s to %s", tree.currentSymbol().key, right.Primitive, dt)) - } - - default: - if right.Primitive != primitives.String { - return raiseError(tree.expression, tree.currentSymbol(), 0, fmt.Sprintf( - "cannot %s %s to %s", tree.currentSymbol().key, right.Primitive, dt)) - } - result = v.(string) + right.Value.(string) - } - - err = tree.setVar(leftNode.value, result, right.DataType) - if err != nil { - return raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) - } - - return tree.foldAst(&astNodeT{ - key: symbols.Calculated, - pos: tree.ast[tree.astPos].pos, - dt: primitives.NewPrimitive(primitives.Null, nil), - }) -}*/ - type assFnT func(float64, float64) float64 -func _assAdd(lv float64, rv float64) float64 { return lv + rv } -func _assSub(lv float64, rv float64) float64 { return lv - rv } -func _assMulti(lv float64, rv float64) float64 { return lv * rv } -func _assDiv(lv float64, rv float64) float64 { return lv / rv } +func _assAdd(lv float64, rv float64) float64 { return lv + rv } +func _assSub(lv float64, rv float64) float64 { return lv - rv } +func _assMul(lv float64, rv float64) float64 { return lv * rv } +func _assDiv(lv float64, rv float64) float64 { return lv / rv } func expAssignAndOperate(tree *ParserT, operation assFnT) error { leftNode, rightNode, err := tree.getLeftAndRightSymbols() @@ -362,6 +279,13 @@ func expAssignMerge(tree *ParserT) error { err.Error())) } + /*if dt == "" || dt == types.Null { + dt = right.DataType + } + b, err := lang.MarshalData(tree.p, dt, merged) + if err != nil { + return raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) + }*/ err = tree.setVar(leftNode.value, merged, dt) if err != nil { return raiseError(tree.expression, tree.currentSymbol(), 0, err.Error()) diff --git a/lang/expressions/expression.go b/lang/expressions/expression.go index 0eaeaf84c..0cd463810 100644 --- a/lang/expressions/expression.go +++ b/lang/expressions/expression.go @@ -101,7 +101,7 @@ func executeExpression(tree *ParserT, order symbols.Exp) (err error) { case symbols.AssignAndDivide: err = expAssignAndOperate(tree, _assDiv) case symbols.AssignAndMultiply: - err = expAssignAndOperate(tree, _assMulti) + err = expAssignAndOperate(tree, _assMul) case symbols.AssignOrMerge: err = expAssignMerge(tree) diff --git a/version.svg b/version.svg index 6af681d9c..1cd052a20 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0072Version7.2.0072 +Version: 7.2.0073Version7.2.0073 From f3704ffc29538b296707b211bab02c9b72a9d960 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Thu, 22 Jan 2026 22:39:18 +0000 Subject: [PATCH 27/32] update copyright date --- app/app.go | 4 ++-- version.svg | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/app.go b/app/app.go index 99b3aaf8a..7f7518f45 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 73 + Revision = 74 ) var ( @@ -29,7 +29,7 @@ func Branch() string { return branch } func BuildDate() string { return strings.ReplaceAll(buildDate, "_", " ") } // Copyright is the copyright owner string -const Copyright = "2018-2025 Laurence Morgan" +const Copyright = "2018-2026 Laurence Morgan" // License is the projects software license const License = "GPL v2" diff --git a/version.svg b/version.svg index 1cd052a20..5e016d156 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0073Version7.2.0073 +Version: Version From 2fee565c2c95898288988b07a7eb7762ac705c00 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Thu, 22 Jan 2026 22:40:23 +0000 Subject: [PATCH 28/32] update dependencies --- app/app.go | 2 +- go.mod | 19 ++++++++----------- go.sum | 44 ++++++++++++++++++++++---------------------- version.svg | 2 +- 4 files changed, 32 insertions(+), 35 deletions(-) diff --git a/app/app.go b/app/app.go index 7f7518f45..09e96c1e8 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 74 + Revision = 75 ) var ( diff --git a/go.mod b/go.mod index 835a83597..f8cddb865 100644 --- a/go.mod +++ b/go.mod @@ -14,18 +14,18 @@ require ( github.com/lmorg/apachelogs v0.0.0-20161115121556-e5f3eae677ad github.com/lmorg/readline/v4 v4.2.2 github.com/mattn/go-runewidth v0.0.19 - github.com/mattn/go-sqlite3 v1.14.32 + github.com/mattn/go-sqlite3 v1.14.33 github.com/pelletier/go-toml v1.9.5 github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee - golang.org/x/sys v0.38.0 - golang.org/x/text v0.31.0 + golang.org/x/sys v0.40.0 + golang.org/x/text v0.33.0 gopkg.in/yaml.v3 v3.0.1 - modernc.org/sqlite v1.40.1 + modernc.org/sqlite v1.44.3 ) require ( github.com/clipperhouse/stringish v0.1.1 // indirect - github.com/clipperhouse/uax29/v2 v2.3.0 // indirect + github.com/clipperhouse/uax29/v2 v2.3.1 // indirect github.com/disintegration/imaging v1.6.2 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/google/uuid v1.6.0 // indirect @@ -34,12 +34,9 @@ require ( github.com/ncruces/go-strftime v1.0.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/stretchr/testify v1.11.1 // indirect - golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 // indirect - golang.org/x/image v0.33.0 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/tools v0.39.0 // indirect - modernc.org/libc v1.67.1 // indirect + golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect + golang.org/x/image v0.35.0 // indirect + modernc.org/libc v1.67.6 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect ) diff --git a/go.sum b/go.sum index f9568e1eb..574e673a4 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,8 @@ github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyM github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= -github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= -github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= +github.com/clipperhouse/uax29/v2 v2.3.1 h1:RjM8gnVbFbgI67SBekIC7ihFpyXwRPYWXn9BZActHbw= +github.com/clipperhouse/uax29/v2 v2.3.1/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -42,8 +42,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= -github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs= -github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/go-sqlite3 v1.14.33 h1:A5blZ5ulQo2AtayQ9/limgHEkFreKj1Dv226a1K73s0= +github.com/mattn/go-sqlite3 v1.14.33/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= @@ -56,23 +56,23 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 h1:DHNhtq3sNNzrvduZZIiFyXWOL9IWaDPHqTnLJp+rCBY= -golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0= +golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU= +golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.33.0 h1:LXRZRnv1+zGd5XBUVRFmYEphyyKJjQjCRiOuAP3sZfQ= -golang.org/x/image v0.33.0/go.mod h1:DD3OsTYT9chzuzTQt+zMcOlBHgfoKQb1gry8p76Y1sc= -golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/image v0.35.0 h1:LKjiHdgMtO8z7Fh18nGY6KDcoEtVfsgLDPeLyguqb7I= +golang.org/x/image v0.35.0/go.mod h1:MwPLTVgvxSASsxdLzKrl8BRFuyqMyGhLwmC+TO1Sybk= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= -golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -89,8 +89,8 @@ modernc.org/gc/v3 v3.1.1 h1:k8T3gkXWY9sEiytKhcgyiZ2L0DTyCQ/nvX+LoCljoRE= modernc.org/gc/v3 v3.1.1/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= -modernc.org/libc v1.67.1 h1:bFaqOaa5/zbWYJo8aW0tXPX21hXsngG2M7mckCnFSVk= -modernc.org/libc v1.67.1/go.mod h1:QvvnnJ5P7aitu0ReNpVIEyesuhmDLQ8kaEoyMjIFZJA= +modernc.org/libc v1.67.6 h1:eVOQvpModVLKOdT+LvBPjdQqfrZq+pC39BygcT+E7OI= +modernc.org/libc v1.67.6/go.mod h1:JAhxUVlolfYDErnwiqaLvUqc8nfb2r6S6slAgZOnaiE= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= @@ -99,8 +99,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.40.1 h1:VfuXcxcUWWKRBuP8+BR9L7VnmusMgBNNnBYGEe9w/iY= -modernc.org/sqlite v1.40.1/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE= +modernc.org/sqlite v1.44.3 h1:+39JvV/HWMcYslAwRxHb8067w+2zowvFOUrOWIy9PjY= +modernc.org/sqlite v1.44.3/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/version.svg b/version.svg index 5e016d156..ecc0dce87 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: Version +Version: 7.2.0075Version7.2.0075 From 492d987191a82bfe1bdf110aa0d434bc4ec4f8f9 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Thu, 22 Jan 2026 22:44:01 +0000 Subject: [PATCH 29/32] docgen: update copyright date --- app/app.go | 2 +- utils/docgen/main.go | 2 +- version.svg | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/app.go b/app/app.go index 09e96c1e8..69c748c80 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 75 + Revision = 76 ) var ( diff --git a/utils/docgen/main.go b/utils/docgen/main.go index d167d31de..f24164b58 100644 --- a/utils/docgen/main.go +++ b/utils/docgen/main.go @@ -14,7 +14,7 @@ const ( Version = "5.0.1" // Copyright is the copyright owner string - Copyright = "(c) 2018-2025 Laurence Morgan" + Copyright = "(c) 2018-2026 Laurence Morgan" // License is the projects software license License = "License GPL v2" diff --git a/version.svg b/version.svg index ecc0dce87..97b859804 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0075Version7.2.0075 +Version: 7.2.0076Version7.2.0076 From c9d41fd9aaa39d12c58db77a1d0be9d509a57d5e Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sun, 1 Feb 2026 17:49:51 +0000 Subject: [PATCH 30/32] update changelog --- app/app.go | 2 +- docs/changelog/README.md | 5 +++ docs/changelog/v7.2.md | 68 +++++++++++++++++++++++++++++++++++++ gen/changelog/v7.2.inc.md | 37 ++++++++++++++++++++ gen/changelog/v7.2_doc.yaml | 19 +++++++++++ version.svg | 2 +- 6 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 docs/changelog/v7.2.md create mode 100644 gen/changelog/v7.2.inc.md create mode 100644 gen/changelog/v7.2_doc.yaml diff --git a/app/app.go b/app/app.go index 69c748c80..620115829 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 76 + Revision = 77 ) var ( diff --git a/docs/changelog/README.md b/docs/changelog/README.md index ba3a2bed8..0bf348671 100644 --- a/docs/changelog/README.md +++ b/docs/changelog/README.md @@ -4,6 +4,11 @@ Track new features, any breaking changes, and the release history here. ## Articles +### 01.02.2026 - [v7.2](../changelog/v7.2.md) + +This release brings several improvements in scripting environments for Javascript/Typescript and Python support. Core features include the new `--copy` flag for aliases to inherit shell configuration, and bugfixes to address autocomplete panics, expression error handling, and 3rd party integration issues. + + ### 23.10.2025 - [v7.1](../changelog/v7.1.md) This release focuses mainly on bugfixes and quality-of-life with the exception of three **experimental** new major additions: diff --git a/docs/changelog/v7.2.md b/docs/changelog/v7.2.md new file mode 100644 index 000000000..4d7a9ba33 --- /dev/null +++ b/docs/changelog/v7.2.md @@ -0,0 +1,68 @@ +# v7.2 + +This release brings several improvements in scripting environments for Javascript/Typescript and Python support. Core features include the new `--copy` flag for aliases to inherit shell configuration, and bugfixes to address autocomplete panics, expression error handling, and 3rd party integration issues. + +## Breaking Changes + +None + +## v7.2.xxxx + +### Features + +* `alias`: new `--copy` flag to inherit shell configuration from aliased commands ([issue](https://github.com/lmorg/murex/issues/872)) +* `args`: `StrictFlagPlacement` and `--` separator +* `fid-list`: rewrite to support filtering +* core: allow filterable function table +* cache.db: don't cache anything with a TTL < 1hr +* integrations: `yarn` refactor +* integrations: Python `uv` support +* integrations: Python virtual environment improvements ([issue](https://github.com/lmorg/murex/issues/960)) +* integrations: `terraform-docs` summary +* makefile: add tags to make test +* wasm: support for builds via tinygo (EXPERIMENTAL) +* chore: update dependencies + +### Bug Fixes + +* autocomplete: fix panic when JSON struct is zero-length ([issue](https://github.com/lmorg/murex/issues/953)) +* `foreach`: fix regression bug in `--parallel` after args rewrite +* escape builtins: use `IsMethod()` instead of `Parameters.Len()` ([issue](https://github.com/lmorg/murex/issues/857)) +* integrations: `yarn` bug fix - resolve initialization hang with corepack ([issue](https://github.com/lmorg/murex/issues/956)) +* expressions: caught error wasn't being returned correctly +* core: temp directory value is now immutable ([issue](https://github.com/lmorg/murex/issues/864)) + +## Special Thanks + +Thank yous for this release goes to [priscira](https://github.com/priscira), [lokalius](https://github.com/lokalius) for your testing and feedback. + +Also thank you to everyone in the [discussions group](https://github.com/lmorg/murex/discussions) and all who raise bug reports. + +You rock! + +
+ +Published: 01.02.2026 at 12:00 + +## See Also + +* [Alias "shortcut": `alias`](../commands/alias.md): + Create an alias for a command +* [Define Function Arguments: `args`](../commands/args.md): + Command line flag parser for Murex shell scripting +* [Display Running Functions: `fid-list`](../commands/fid-list.md): + Lists all running functions within the current Murex session +* [How To Contribute](../Murex/CONTRIBUTING.md): + Murex is community project. We gratefully accept contributions +* [Integrations](../user-guide/integrations.md): + Default integrations shipped with Murex +* [Quote String: `escape`](../commands/escape.md): + Escape or unescape input +* [Tab Autocompletion: `autocomplete`](../commands/autocomplete.md): + Set definitions for tab-completion in the command line +* [expressions](../changelog/expressions.md): + + +
+ +This document was generated from [gen/changelog/v7.2_doc.yaml](https://github.com/lmorg/murex/blob/master/gen/changelog/v7.2_doc.yaml). \ No newline at end of file diff --git a/gen/changelog/v7.2.inc.md b/gen/changelog/v7.2.inc.md new file mode 100644 index 000000000..bdf51d418 --- /dev/null +++ b/gen/changelog/v7.2.inc.md @@ -0,0 +1,37 @@ +## Breaking Changes + +None + +## v7.2.xxxx + +### Features + +* `alias`: new `--copy` flag to inherit shell configuration from aliased commands ([issue](https://github.com/lmorg/murex/issues/872)) +* `args`: `StrictFlagPlacement` and `--` separator +* `fid-list`: rewrite to support filtering +* core: allow filterable function table +* cache.db: don't cache anything with a TTL < 1hr +* integrations: `yarn` refactor +* integrations: Python `uv` support +* integrations: Python virtual environment improvements ([issue](https://github.com/lmorg/murex/issues/960)) +* integrations: `terraform-docs` summary +* makefile: add tags to make test +* wasm: support for builds via tinygo (EXPERIMENTAL) +* chore: update dependencies + +### Bug Fixes + +* autocomplete: fix panic when JSON struct is zero-length ([issue](https://github.com/lmorg/murex/issues/953)) +* `foreach`: fix regression bug in `--parallel` after args rewrite +* escape builtins: use `IsMethod()` instead of `Parameters.Len()` ([issue](https://github.com/lmorg/murex/issues/857)) +* integrations: `yarn` bug fix - resolve initialization hang with corepack ([issue](https://github.com/lmorg/murex/issues/956)) +* expressions: caught error wasn't being returned correctly +* core: temp directory value is now immutable ([issue](https://github.com/lmorg/murex/issues/864)) + +## Special Thanks + +Thank yous for this release goes to [priscira](https://github.com/priscira), [lokalius](https://github.com/lokalius) for your testing and feedback. + +Also thank you to everyone in the [discussions group](https://github.com/lmorg/murex/discussions) and all who raise bug reports. + +You rock! diff --git a/gen/changelog/v7.2_doc.yaml b/gen/changelog/v7.2_doc.yaml new file mode 100644 index 000000000..2ca2e80e2 --- /dev/null +++ b/gen/changelog/v7.2_doc.yaml @@ -0,0 +1,19 @@ +- DocumentID: v7.2 + Title: >- + v7.2 + CategoryID: changelog + DateTime: 2026-02-01 12:00 + Summary: >- + This release brings several improvements in scripting environments for Javascript/Typescript and Python support. Core features include the new `--copy` flag for aliases to inherit shell configuration, and bugfixes to address autocomplete panics, expression error handling, and 3rd party integration issues. + Description: |- + {{ include "gen/changelog/v7.2.inc.md" }} + Related: + - CONTRIBUTING + - integrations + - alias + - args + - autocomplete + - fid-list + - escape + - expressions + diff --git a/version.svg b/version.svg index 97b859804..badd191db 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0076Version7.2.0076 +Version: 7.2.0077Version7.2.0077 From 2bde6c261f2585c7bd764149f0f27fcab291fd92 Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sun, 1 Feb 2026 17:50:56 +0000 Subject: [PATCH 31/32] dev tools: add AI prompt to generate changelogs --- .github/prompts/createChangeLog.prompt.md | 109 ++++++++++++++++++++++ app/app.go | 2 +- builtins/docs/summaries.go | 2 + go.mod | 3 + version.svg | 2 +- 5 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 .github/prompts/createChangeLog.prompt.md diff --git a/.github/prompts/createChangeLog.prompt.md b/.github/prompts/createChangeLog.prompt.md new file mode 100644 index 000000000..0d8639904 --- /dev/null +++ b/.github/prompts/createChangeLog.prompt.md @@ -0,0 +1,109 @@ +--- +name: createChangeLog +description: Works through the release PR to compile a change long +argument-hint: versionNumber +--- +# Instructions +- Follow EVERY step +- Do NOT start the following step until the previous step has finished +- Do NOT skip any steps +- This project is `Murex`, found on Github at https://github.com/lmorg/murex +- changelogs are found in `gen/changelog/` +- changelogs consist of 2 (two) files with the naming convention: + 1. `${VERSION}_doc.yaml` + 2. `${VERSION}.inc.md` +- `${VERSION}` is a version number and should follow the format: `v${MAJOR}.{MINOR}` where: + 1. `${MAJOR}` is a numeric value + 2. `${MINOR}` is a numeric value + + +# Step 1: Find Github Pull Request (PR) +- Check for open PRs in Github for only the Murex repository. We are only interested in a PR that is named like `v7.1`. Ignore all other PRs. +- There should only be one PR. If there is more than one PRs, or you are unsure which PR to check, then stop all steps and ask which PR to read. +- Do not read multiple PRs +- Do not read other repositories other than `murex` + +# Step 2: Read all git commits, then summarize changes +From the selected PR: +- Read every git commit and create a list of changes. +- Use git commit messages as a clue for the change. +- If a commit message has a value like `#123` (`#` followed by a number) then this is a Github Issue. You should also read that Github issue to understand the change. +- Multiple git commits might be part of the same change. +- A git commit might contain multiple changes. + +You should output a bullet point list of each change, with a short summary in the following format: +``` +- ${COMPONENT}: ${SUMMARY} ([issue](${ISSUE})) +``` + 1. `${COMPONENT}` is a one word title for the system that is being changed + 2. `${SUMMARY}` is the summary you generate + 3. `${ISSUE}` is a URL to the Github issue -- if an change has a related Github Issue + +Some issues might be links to Github discussions. + +Also include a reference to any contributors either creating related Github issues, github discussions, commits or pull requests. These users should be related to this version and who are not `@lmorg`. + +# Step 3: Grouping changes + +The changes should be grouped into the following groups: +1. **Breaking changes**: these are changes that might impact the users upgrading from previous versions of this project +2. **Features**: these are new features added to the project in this version +3. **Bug Fixes**: these are changes that do not introduce new features but that fix bugs or issues with existing features + +# Step 5: Update changelog +This step refers only to `${VERSION}.inc.md`: +- This file should be in `gen/changelog/`. +- If a file does not exist, then you can create one. +- If a file does exist then review the contents of it and add any changes you've identified if they don't already exist in this document +- This is a markdown document. +- It's contents should match the following: +``` +## Breaking Changes + +- ${COMPONENT}: ${SUMMARY} ([issue](${ISSUE})) + +## v${VERSION}.xxxx + +### Features + +- ${COMPONENT}: ${SUMMARY} ([issue](${ISSUE})) + +### Bug Fixes + +- ${COMPONENT}: ${SUMMARY} ([issue](${ISSUE})) + +## Special Thanks + +Thank yous for this release goes to ${LIST_OF_USERS_WHO_CONTRIBUTED} for your code, testing and feedback. + +Also thank you to everyone in the [discussions group](https://github.com/lmorg/murex/discussions) and all who raise bug reports. + +You rock! +``` + +# Step 6: Update summary + +This step refers only to `${VERSION}_doc.yaml`: +- This file should be in `gen/changelog/`. +- If a file does not exist, then you can create one. +- If a file does exist then review the contents of it and add any changes if you think it alters the nature of the version summary. +- This is a YAML document. +- It's contents should match the following: + +``` +- DocumentID: ${VERSION} + Title: >- + ${VERSION} + CategoryID: changelog + DateTime: ${VERSION} + Summary: >- + ${VERSION_SUMMARY} + Description: |- + {{ include "gen/changelog/${VERSION}.inc.md" }} + Related: + - CONTRIBUTING +``` +- ${VERSION} should be replaced with the version number. +- ${DATE} should be replaced with the current date and time, formatted like the following example: 2025-10-23 22:35 +- ${VERSION_SUMMARY} will be a summary of all the changes in this version. + diff --git a/app/app.go b/app/app.go index 620115829..46bc23b67 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 77 + Revision = 78 ) var ( diff --git a/builtins/docs/summaries.go b/builtins/docs/summaries.go index b53a043ba..f635edded 100644 --- a/builtins/docs/summaries.go +++ b/builtins/docs/summaries.go @@ -423,6 +423,7 @@ func init() { "changelog/v6.4": "This change brings a number of ergonomic improvements to job control, `datetime` and working with structures.", "changelog/v7.0": "Introducing experimental support for XML, new integrations, and several other quality-of-life improvements. Four deprecated builtins have been removed too, which is this release sees an increment of its major version number", "changelog/v7.1": "This release focuses mainly on bugfixes and quality-of-life with the exception of three **experimental** new major additions:\n* `foreach` now supports running processes in parallel\n* `fanout` is a new builtin that allows sending stdout to the stdin of many processes\n* `md` is a new datatype added. Currently only supports rendering markdown tables but more features will follow in future releases", + "changelog/v7.2": "This release brings several improvements in scripting environments for Javascript/Typescript and Python support. Core features include the new `--copy` flag for aliases to inherit shell configuration, and bugfixes to address autocomplete panics, expression error handling, and 3rd party integration issues.", "deprecated/equ": "Evaluate a mathematical function (removed 7.0)", "deprecated/die": "Terminate murex with an exit number of 1 (removed 7.0)", "deprecated/let": "Evaluate a mathematical function and assign to variable (removed 7.0)", @@ -1089,5 +1090,6 @@ func init() { "changelog/v6.4": "changelog/v6.4", "changelog/v7.0": "changelog/v7.0", "changelog/v7.1": "changelog/v7.1", + "changelog/v7.2": "changelog/v7.2", } } diff --git a/go.mod b/go.mod index f8cddb865..2ae9f64f9 100644 --- a/go.mod +++ b/go.mod @@ -36,6 +36,9 @@ require ( github.com/stretchr/testify v1.11.1 // indirect golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect golang.org/x/image v0.35.0 // indirect + golang.org/x/mod v0.32.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/tools v0.41.0 // indirect modernc.org/libc v1.67.6 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect diff --git a/version.svg b/version.svg index badd191db..29dfa6833 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0077Version7.2.0077 +Version: 7.2.0078Version7.2.0078 From 47148fdcc7864d5254dec2a8ec0a5c99f2f5712e Mon Sep 17 00:00:00 2001 From: Laurence Morgan Date: Sun, 1 Feb 2026 22:25:47 +0000 Subject: [PATCH 32/32] update changelog --- .github/prompts/createChangeLog.prompt.md | 2 +- app/app.go | 2 +- docs/changelog/README.md | 2 +- docs/changelog/v7.2.md | 4 ++-- gen/changelog/v7.2.inc.md | 2 +- gen/changelog/v7.2_doc.yaml | 2 +- version.svg | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/prompts/createChangeLog.prompt.md b/.github/prompts/createChangeLog.prompt.md index 0d8639904..cf0cb5809 100644 --- a/.github/prompts/createChangeLog.prompt.md +++ b/.github/prompts/createChangeLog.prompt.md @@ -74,7 +74,7 @@ This step refers only to `${VERSION}.inc.md`: ## Special Thanks -Thank yous for this release goes to ${LIST_OF_USERS_WHO_CONTRIBUTED} for your code, testing and feedback. +Thank yous for this release go to ${LIST_OF_USERS_WHO_CONTRIBUTED} for your code, testing and feedback. Also thank you to everyone in the [discussions group](https://github.com/lmorg/murex/discussions) and all who raise bug reports. diff --git a/app/app.go b/app/app.go index 46bc23b67..5f61d211c 100644 --- a/app/app.go +++ b/app/app.go @@ -17,7 +17,7 @@ const Name = "murex" const ( Major = 7 Minor = 2 - Revision = 78 + Revision = 79 ) var ( diff --git a/docs/changelog/README.md b/docs/changelog/README.md index 0bf348671..98acd2ba0 100644 --- a/docs/changelog/README.md +++ b/docs/changelog/README.md @@ -6,7 +6,7 @@ Track new features, any breaking changes, and the release history here. ### 01.02.2026 - [v7.2](../changelog/v7.2.md) -This release brings several improvements in scripting environments for Javascript/Typescript and Python support. Core features include the new `--copy` flag for aliases to inherit shell configuration, and bugfixes to address autocomplete panics, expression error handling, and 3rd party integration issues. +This release brings several improvements for scripting environments in Javascript/Typescript and Python support. Core features include the new `--copy` flag for aliases to inherit shell configuration, and bugfixes to address autocomplete panics, expression error handling, and 3rd party integration issues. ### 23.10.2025 - [v7.1](../changelog/v7.1.md) diff --git a/docs/changelog/v7.2.md b/docs/changelog/v7.2.md index 4d7a9ba33..6d3088345 100644 --- a/docs/changelog/v7.2.md +++ b/docs/changelog/v7.2.md @@ -1,6 +1,6 @@ # v7.2 -This release brings several improvements in scripting environments for Javascript/Typescript and Python support. Core features include the new `--copy` flag for aliases to inherit shell configuration, and bugfixes to address autocomplete panics, expression error handling, and 3rd party integration issues. +This release brings several improvements for scripting environments in Javascript/Typescript and Python support. Core features include the new `--copy` flag for aliases to inherit shell configuration, and bugfixes to address autocomplete panics, expression error handling, and 3rd party integration issues. ## Breaking Changes @@ -34,7 +34,7 @@ None ## Special Thanks -Thank yous for this release goes to [priscira](https://github.com/priscira), [lokalius](https://github.com/lokalius) for your testing and feedback. +Thank yous for this release go to [@priscira](https://github.com/priscira), [@lokalius](https://github.com/lokalius) and [@fyrak1s](https://github.com/fyrak1s), for your testing and feedback. Also thank you to everyone in the [discussions group](https://github.com/lmorg/murex/discussions) and all who raise bug reports. diff --git a/gen/changelog/v7.2.inc.md b/gen/changelog/v7.2.inc.md index bdf51d418..a3c4269ea 100644 --- a/gen/changelog/v7.2.inc.md +++ b/gen/changelog/v7.2.inc.md @@ -30,7 +30,7 @@ None ## Special Thanks -Thank yous for this release goes to [priscira](https://github.com/priscira), [lokalius](https://github.com/lokalius) for your testing and feedback. +Thank yous for this release go to [@priscira](https://github.com/priscira), [@lokalius](https://github.com/lokalius) and [@fyrak1s](https://github.com/fyrak1s), for your testing and feedback. Also thank you to everyone in the [discussions group](https://github.com/lmorg/murex/discussions) and all who raise bug reports. diff --git a/gen/changelog/v7.2_doc.yaml b/gen/changelog/v7.2_doc.yaml index 2ca2e80e2..6f1f3b157 100644 --- a/gen/changelog/v7.2_doc.yaml +++ b/gen/changelog/v7.2_doc.yaml @@ -4,7 +4,7 @@ CategoryID: changelog DateTime: 2026-02-01 12:00 Summary: >- - This release brings several improvements in scripting environments for Javascript/Typescript and Python support. Core features include the new `--copy` flag for aliases to inherit shell configuration, and bugfixes to address autocomplete panics, expression error handling, and 3rd party integration issues. + This release brings several improvements for scripting environments in Javascript/Typescript and Python support. Core features include the new `--copy` flag for aliases to inherit shell configuration, and bugfixes to address autocomplete panics, expression error handling, and 3rd party integration issues. Description: |- {{ include "gen/changelog/v7.2.inc.md" }} Related: diff --git a/version.svg b/version.svg index 29dfa6833..bc05e5f36 100644 --- a/version.svg +++ b/version.svg @@ -1 +1 @@ -Version: 7.2.0078Version7.2.0078 +Version: 7.2.0079Version7.2.0079