diff --git a/modules/comma/README.md b/modules/comma/README.md index e29a0df..4b43066 100644 --- a/modules/comma/README.md +++ b/modules/comma/README.md @@ -1,93 +1,165 @@ +# Comma, task and test runner of nu script + Working dir task runner, similar to `pwd-module`, but supports completion and description through custom data formats -- `,` or `*` need to be exported in order to use `,` directly -- Directly execute `,` to create a new template file or edit an existing file -- Custom tasks are written in `$env.comma` and can be nested - - no spaces allowed in name (except testing) -- Generate completions based on the structure of `$env.comma` -- You can use closure to customize completion -- In `$_.act` of default closure, you can receive parameters after the current position -- In `$_.cmp` , you can receive the parameter before the current position -- Supports `computed`, the definition method refers to `$env.comma_scope.computed`, accepts two parameters, runtime parameters and `$env.comma_scope` -- Supports `filter`, similar to `computed`, but only runs when declared, specified through `$_.flt` -- Supports `watch` (and polling), specified through `$_.wth`. - - `glob` defaults to `*`, `op` defaults to `['Write']`, `postpone` defaults to `false` - - In watch mode (not Polling) inject `$_.wth`(op, path, new_path) into parameter `$s` - - when the `interval` field is included, it is polling mode(`clear` defaults to 'false') -- Identity supports alias - - children sub s - - description desc dsc d - - action act a - - completion cmp c - - filter flt f - - computed cpu u - - watch wth w - - tag - - expect exp e x - - mock test_args m - - report rpt r +## Quick Start +`,` or `*` need to be exported in order to use `,` Directly -example: ``` -$env.comma_scope = {|_|{ - created: '2023-12-24{0}01:46:27' - computed: {$_.computed:{|a, s| $'($s.created)($a)' }} - say: {|s| print $'(ansi $_.settings.theme.info)($s)(ansi reset)' } - quick: {$_.filter:{|a, s| do $s.say 'run a `quick` filter' }} - slow: {$_.filter:{|a, s| - do $s.say 'run a `slow` filter' - sleep 1sec - do $s.say 'filter need to be declared' - sleep 1sec - $'($s.computed)<($a)>' - }} -}} +use comma.nu * +``` +When you enter a directory, if a `,.nu` file exists, it will be loaded. (Currently you need to press the Enter key again to take effect) + +Or `source` any file that defines `$env.comma_scope` and `$env.comma` variables + +If there is no `,.nu` file in the current directory, executing `,` without arguments will create a new one from the template. If the file exists, edit it + +### Task Definition +Tasks are written in `$env.comma` and can be nested, and no spaces allowed in name (except testing). + +The nodes of the tree can be ordinary records, and the tasks are defined in the closure of the leaf nodes. + +This tree will be traversed during completion. For tasks, you can customize the completion behavior. + +Customize completion behavior, as well as descriptions, filters, watches, tests, etc. Need to add some special attributes to the record, such as `$_.children`, `$_.action`, `$_.completion` (so `$env.comma` and `$env.comma_scope` accepts a closure to avoid potential naming conflicts). + +``` $env.comma = {|_|{ - created: {|a, s| $s.computed } - inspect: {|a, s| {index: $_, scope: $s, args: $a} | table -e } - test: { - $_.sub: { - batch: { 'created; inspect' | do $_.batch } - watch: { - $_.action: {|a, s| $s | get $_.watch } - $_.completion: {ls *.json | get name} - $_.desc: 'inspect watch context' - $_.watch: { - glob: '*' - op: ['Write', 'Create'] - postpone: true - } - } - open_file: { - $_.action: {|a, s| open $a.0 } - $_.completion: {ls | get name} - $_.desc: 'open a file' - $_.filter: ['slow'] - } - ping: { - $_.action: {|a, s| ping -c 2 localhost } - $_.watch: { - interval: 2sec - clear: true - } - } + dev: { + run: { + $_.action: {|a,s| nu $a.0 } + $_.watch: { glob: '*.nu', clear: true } + $_.completion: { ls *.nu | get name } + $_.desc: "develop a nu script" } - $_.desc: 'run test' - $_.filter: ['quick'] } }} ``` -### todo +These attributes support aliases like: + +| attribute | alias | +|-------------|----------------| +| children | sub, s | +| description | desc, dsc, d | +| action | act, a | +| completion | cmp, c | +| filter | flt, f | +| computed | cpu, u | +| watch | wth, w | +| tag | | +| expect | exp, e, x | +| mock | test_args, m | +| report | rpt, r | + +The closure of the task's `action`, `completion` accepts two parameters, the rest arguments after the breadcrumbs and `$env.comma_scope`. + +`computed` and `filter` are defined in `$env.comma_scope` which is used to share data, alse accept these two parameters. + +`computed` is calculated in the defined order and replaced with the result. +``` +$env.comma_scope = {|_|{ + hello: 'hello' + greet: {$_.computed:{|a, s| $'($s.hello): ($a)' }} +}} +``` + +`filter` is called when it is declared. If a record is returned, it will be merged back to the $env.comma_scope. +``` +$env.comma_scope = {|_|{ + log: {$_.filter:{|a, s| do $_.tips 'run filter' `foo` }} +}} + +$env.comma = {|_|{ + foo: { + $_.sub: { + bar: { + $_.action: { echo 'hello' } + $_.filter: ['log'] + } + } + $_.filter: ['log'] + } +}} +``` + +#### Dry run +If execute the command in `$_.action` with `pp`, and pass `--print` flag with `,`, only prints the arguments received by `pp` without actually executing it. + +`pp` can be run alone with flag `--print`. +``` +pp --print aaa bbbb ccccc dddddd eeeeee [ + ffffff gggggggggg [ + hhhhhhhhh iiiiiiiiii lllllllll + ] mmmmmmmmmmmmm nnnnnnnnnnnn + aaaaaaaaaaaaaaa + xxxxxxxxxxxxxxxx + yyyyyyyyyyyyyyyy + zzzzzzzzzzzzzzz + jjjjjjjjjjjjj +] oooooooo ppppppppp [qqqqqq [rrrrrr ssssss tttttt] uuuuuu] +``` + +### Watch and polling +If `$_.watch` is defined and run with `--watch` flag, it will be run in watch mode. +``` +$env.comma = {|_|{ + foo: { + $_.watch: { + glob: '*' + op: ['Write', 'Create'] + postpone: true + } + } +}} +``` +- `glob` defaults to `*`, `op` defaults to `['Write']`, `postpone` defaults to `false` +- In watch mode (not Polling) inject `$_.watch`(op, path, new_path) into parameter `$s` +- when the `interval` field is included, it is polling mode(`clear` defaults to 'false') + +### Test +If run with the `--test` flag, it will detect that all nodes with `$_.expect` under the current and run their actions. + +If there is also the --watch flag, it will run in watch mode without defining `$_.watch`. + +If `$_.mock` exists, it will be passed as arguments to the `$_.action` and `$_.expect`. + +If `$_.expect` is closure, pass it the result of `$_.action`, rest arguments and `$_.comma_scope`, if return True and the test passes. + +If `$_.expect` is list, will use the closures in it as a set of tests. + +If `$_.expect` is a scalar, it is compared directly with the result of actions. + +If `$_.report` exists and the test fails, execute `$_.report` (has a predefined report `$_.diff`) + +### vscode-tasks +The default template contains `vscode-tasks` and outputs a `.vscode/tasks.json`. + +``` +$env.comma = {|_|{ + vscode-tasks: { + $_.a: { + mkdir .vscode + ', --vscode -j' | do $_.batch ',.nu' | save -f .vscode/tasks.json + } + $_.d: "generate .vscode/tasks.json" + $_.w: { glob: ',.nu' } + } +}} +``` +> requires `augustocdias.tasks-shell-input` to run `$_.completion` closure. + +## todo - [x] run - - [ ] dry - - [ ] dry wrap lines - - [ ] accept list + - [x] dry + - [x] dry wrap lines + - [x] accept list - [x] formatter: outdent - [x] complete - [x] with args - [x] scoped test + - [x] pass scoped - [x] tree map - [x] test - [ ] tag @@ -116,7 +188,6 @@ $env.comma = {|_|{ - [ ] pickString - [x] augustocdias.tasks-shell-input - [x] allow rest args as `promptString` - - https://code.visualstudio.com/docs/editor/variables-reference - [x] clean filter output - [x] add gen vscode-tasks to template - [ ] test and watch diff --git a/modules/comma/comma.nu b/modules/comma/comma.nu index 505b803..3300d8a 100644 --- a/modules/comma/comma.nu +++ b/modules/comma/comma.nu @@ -1,6 +1,12 @@ export def lg [tag?] { let o = $in - print -e $'---($tag)---($o | describe)(char newline)($o | to yaml)' + let t = [ + $'(ansi xterm_grey)--------(ansi xterm_olive)($tag)(ansi xterm_grey)--------' + $'(ansi xterm_grey39)($o | describe)' + $'(ansi xterm_grey66)($o | to yaml)' + (ansi reset) + ] + print -e ($t | str join (char newline)) $o } @@ -190,7 +196,9 @@ module resolve { } for i in ($flts | default []) { if $i in $flt { - $vs = ($vs | merge {$i: (do ($flt | get $i) $args $vs)} ) + let fr = do ($flt | get $i) $args $vs + let fr = if ($fr | describe -d).type == 'record' { $fr } else { {} } + $vs = ($vs | merge $fr) } else { error make -u {msg: $"filter `($i)` not found" } } @@ -770,8 +778,8 @@ export-env { print -e $"(ansi light_gray_italic)($m.0)(ansi reset) (ansi yellow_bold)($m.1?)(ansi reset)" } } - T: { true } - F: { false } + T: {|f| {|r,a,s| do $f $r $a $s; true } } + F: {|f| {|r,a,s| do $f $r $a $s; false } } I: {|x| $x } diff: {|x| use test diff --git a/modules/comma/comma_test.nu b/modules/comma/comma_test.nu index ad4d39a..1405311 100644 --- a/modules/comma/comma_test.nu +++ b/modules/comma/comma_test.nu @@ -65,8 +65,8 @@ $env.comma = {|_|{ 'example a b c e': { $_.act: {, -c example a b c e } $_.x: [ - {|r,a| $r | where value == 'f' | not ($in | is-empty) } - $_.T + {|r,a,s| $r | where value == 'f' | not ($in | is-empty) } + (do $_.T {|r,a,s| $s | lg 'expect'}) {|r,a| 'q1|q2|q3|q4| open a file' == ($r | get 1.description) } ] } @@ -105,8 +105,8 @@ $env.comma = {|_|{ b: { $_.sub: { t1: { - $_.act: $_.T - $_.exp: $_.T + $_.act: { true } + $_.exp: { true } } open_file: { $_.act: {|a, s| open $a.0 } @@ -119,7 +119,7 @@ $env.comma = {|_|{ e: { $_.sub: { f: { - $_.act: $_.T + $_.act: { true } } open_file: { $_.act: {|a, s| open $a.0 } @@ -131,8 +131,8 @@ $env.comma = {|_|{ $_.report: $_.diff } t3: { - $_.act: $_.T - $_.exp: $_.T + $_.act: { true } + $_.exp: { true } } } $_.dsc: 'ok' @@ -141,8 +141,8 @@ $env.comma = {|_|{ } } t2: { - $_.act: $_.T - $_.exp: $_.T + $_.act: { true } + $_.exp: { true } } } $_.dsc: 'this way' @@ -198,15 +198,15 @@ $env.comma = {|_|{ args: [example a b c e] } do $_.test 'run test' { - expect: $_.T + expect: { true } spec: {, -e test example } } do $_.test 'run leaf test' { - expect: $_.T + expect: { true } spec: { , -t example a b t1 } } do $_.test 'suit' { - expect: $_.T + expect: { true } spec: { , -t suit } } } @@ -244,7 +244,7 @@ $env.comma = {|_|{ $_.wth: { glob: '*.nu' } } complete: { - $_.act: $_.T + $_.act: { true } $_.wth: { glob: '*.nu' } } } diff --git a/modules/comma/comma_tmpl.nu b/modules/comma/comma_tmpl.nu index 3963c53..6f97197 100644 --- a/modules/comma/comma_tmpl.nu +++ b/modules/comma/comma_tmpl.nu @@ -1,14 +1,7 @@ $env.comma_scope = {|_|{ created: '{{time}}' computed: {$_.computed:{|a, s| $'($s.created)($a)' }} - quick: {$_.filter:{|a, s| do $_.tips 'run filter' `quick` }} - slow: {$_.filter:{|a, s| - do $_.tips 'run filter' `slow` - sleep 1sec - do $_.tips 'filter need to be declared' - sleep 1sec - $'($s.computed)<($a)>' - }} + log_args: {$_.filter:{|a, s| do $_.tips 'received arguments' $a }} }} $env.comma = {|_|{ @@ -29,36 +22,42 @@ $env.comma = {|_|{ $_.completion: { ls *.nu | get name } $_.desc: "develop a nu script" } - watch: { - $_.a: {|a,s| $', dev run ($a.0)' | do $_.batch ',.nu' } - $_.x: {|r,a| false } - $_.m: [,.nu] - $_.c: { ls *.nu | get name } - } - } - test: { - $_.sub: { - batch: { ', created; , inspect' | do $_.batch ',.nu' } - watch: { - $_.act: {|a, s| $s | get $_.watch } - $_.cmp: {ls *.json | get name} - $_.dsc: 'inspect watch context' - $_.wth: { - glob: '*' - op: ['Write', 'Create'] - postpone: true + build: { + image: { + $_.a: {|a,s| + ^$env.docker-cli pull $a.0 + let tmp = mktemp + $" + FROM ($a.0) + + RUN apt update \\ + && apt-get upgrade -y \\ + && DEBIAN_FRONTEND=noninteractive \\ + apt-get install -y --no-install-recommends \\ + curl ca-certificates \\ + && apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* \\ + && curl -sSL ($a.2) | tar zxf - -C /opt/vendor \\ + && chown -R 33:33 /opt/vendor" + | do $_.outdent + | save -f $tmp + + ^$env.docker-cli build -f $tmp -t $a.1 . + rm -f $tmp + ^$env.docker-cli push $a.1 } - } - ping: { - $_.action: {|a, s| ping -c 2 localhost } - $_.watch: { - interval: 2sec - clear: true + $_.c: {|a,s| + let l = $a | length + if $l < 1 { + ['ubuntu', 'alpine', 'nginx'] + } else if $l < 2 { + ['target'] + } else { + ['vendor'] + } } - $_.filter: ['slow'] + $_.d: 'build docker image' + $_.f: ['log_args'] } } - $_.desc: 'run test' - $_.filter: ['quick'] } }}