diff --git a/modules/comma/README.md b/modules/comma/README.md index 695a9c7..e29a0df 100644 --- a/modules/comma/README.md +++ b/modules/comma/README.md @@ -2,76 +2,129 @@ Working dir task runner, similar to `pwd-module`, but supports completion and de - `,` 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 `$env.commax.act` of default closure, you can receive parameters after the current position -- In `$env.commax.cmp` , you can receive the parameter before the current position +- 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 `$env.comm.flt` -- Supports `watch`, specified through `$env.comm.wth`. Support polling like 'poll:2sec' +- 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 + example: ``` -$env.comma_scope = { - created: '2023-12-21{4}10:35:31' - computed: {$env.comm.cpu:{|a, s| $'($s.created)($a)' }} - say: {|s| print $'(ansi yellow_italic)($s)(ansi reset)' } - quick: {$env.comm.flt:{|a, s| do $s.say 'run a `quick` filter' }} - slow: {$env.comm.flt:{|a, s| +$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)>' }} -} +}} -$env.comma = { +$env.comma = {|_|{ created: {|a, s| $s.computed } - open: { - $env.comm.sub: { - any: { - $env.comm.act: {|a, s| open $a.0} - $env.comm.cmp: {ls | get name} - $env.comm.dsc: 'open a file' - } - json: { - $env.comm.act: {|a, s| open $a.0} - $env.comm.cmp: {ls *.json | get name} - $env.comm.dsc: 'open a json file' - $env.comm.wth: '*.json' - } - scope: { - $env.comm.act: {|a, s| print $'args: ($a)'; $s } - $env.comm.flt: ['slow'] - $env.comm.dsc: 'open scope' - $env.comm.wth: 'poll:2sec' - } - } - $env.comm.dsc: 'open something' - $env.comm.flt: ['quick'] - } - # Nest as you like - a: { - b: { - c: { - $env.commax.act: {|x| print $x } - $env.commax.dsc: 'description' - $env.commax.cmp: {|| ls | get name } - } - d: { pwd } - } - x: { - $env.commax.sub: { - y: { - $env.commax.act: {|x| print y} - $env.commax.cmp: {|| [y1 y2 y3]} - $env.commax.dsc: 'description' + 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 } } - $env.commax.dsc: 'xxx' } + $_.desc: 'run test' + $_.filter: ['quick'] } -} - +}} ``` + +### todo +- [x] run + - [ ] dry + - [ ] dry wrap lines + - [ ] accept list + - [x] formatter: outdent +- [x] complete + - [x] with args +- [x] scoped test + - [x] tree map + - [x] test + - [ ] tag + - [ ] watch mode + - [x] override sub node watch + - [x] args + - [x] allow running on leaf node + - [x] test action + - [x] scope + - [ ] filter + - [x] support many expect (list) for one spec + - [ ] curl integration + - [ ] report + - [x] `$x.report` in `test_message` should be `list` + - [x] diff + - [ ] run with `nu -c` (dynamic source nu file) +- [ ] template + - [x] vscode-tasks + - [ ] should panic when identity not exists +- [ ] integration + - [x] gen vscode task json file + - [x] tree map + - [x] batch mode + - [x] run complete in batch mode + - [x] Input variables + - [ ] 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 +- [x] modulize + - [x] refactor with `resolve node` + - [x] run + - [x] complete + - [x] fix redundant filter in description +- [x] theme + - [x] poll sep bar + - [x] tips diff --git a/modules/comma/comma.nu b/modules/comma/comma.nu index daa3428..505b803 100644 --- a/modules/comma/comma.nu +++ b/modules/comma/comma.nu @@ -1,27 +1,665 @@ -def unindent [] { - let txt = $in | lines | range 1.. - let indent = $txt.0 | parse --regex '^(?P\s*)' | get indent.0 | str length - $txt - | each {|s| $s | str substring $indent.. } - | str join (char newline) +export def lg [tag?] { + let o = $in + print -e $'---($tag)---($o | describe)(char newline)($o | to yaml)' + $o } -def 'path parents' [] { - $in - | path expand - | path split - | reduce -f [ '' ] {|x, acc| [( $acc.0 | path join $x ), ...$acc] } - | range ..-2 +module utils { + export def gendict [size extend] { + let keys = $in + mut k = [] + let n = $keys | length + let rk = random chars -l ($n * $size) + for i in 1..$n { + let b = ($i - 1) * $size + let e = $i * $size + $k ++= ($rk | str substring $b..$e) + } + let ids = $keys + | zip $k + | reduce -f {} {|x, acc| + let id = if ($x.0 | describe -d).type == 'list' { $x.0 } else { [$x.0] } + $id | reduce -f $acc {|i,a| $a | insert $i $"($id.0)_($x.1)" } + } + $extend + | transpose k v + | reduce -f $ids {|x, acc| + $acc | insert $x.k { $x.v } + } + } + + + export def 'str repeat' [n] { + let o = $in + if $n < 1 { return '' } + mut r = '' + for i in 0..($n - 1) { + $r += $o + } + $r + } + + export def 'os type' [] { + let info = cat /etc/os-release + | lines + | reduce -f {} {|x, acc| + let a = $x | split row '=' + $acc | upsert $a.0 ($a.1| str replace -a '"' '') + } + if 'ID_LIKE' in $info { + if not ($info.ID_LIKE | parse -r '(rhel|fedora|redhat)' | is-empty) { + 'redhat' + } else { + $info.ID_LIKE + } + } else { + $info.ID + } + } + + export def outdent [] { + let txt = $in | lines | range 1.. + let indent = $txt.0 | parse --regex '^(?P\s*)' | get indent.0 | str length + $txt + | each {|s| $s | str substring $indent.. } + | str join (char newline) + } } -def find [] { - $in - | path parents - | filter {|x| $x | path join ',.nu' | path exists } - | get 0? +module tree { + export def node [] { + let o = $in + let _ = $env.comma_index + let t = ($o | describe -d).type + if $t == 'closure' { + { end: true, $_.act: $o } + } else if ($_.act in $o) { + { end: true, ...$o } + } else if ($_.sub in $o) { + { end: false, ...$o } + } else { + { end: false, $_.sub: $o} + } + } + + def gather [cur _] { + mut data = $in + mut wth = ($data.watch? | default []) + mut flt = ($data.filter? | default []) + if $_.flt in $cur { $flt ++= ($cur | get $_.flt) } + if $_.wth in $cur { $wth ++= ($cur | get $_.wth) } + { + filter: $flt + watch: $wth + } + } + + export def select [data --strict] { + let ph = $in + let _ = $env.comma_index + mut cur = $data | node + mut ops = {} | gather $cur $_ + mut rest = [] + for i in $ph { + if $cur.end { + $rest ++= $i + } else { + $ops = ($ops | gather $cur $_) + let sub = $cur | get $_.sub + if $i in $sub { + $cur = ($sub | get $i | node) + } else { + if $strict { + $cur = ({ do $_.tips "not found" $i } | node) + } else { + $cur + } + break + } + } + } + { + node: $cur + rest: $rest + ...$ops + } + } + + export def map [cb bc?] { + let t = $in | node + let _ = $env.comma_index + travel [] [] $t $cb $bc $_ + } + + def travel [path g data cb bc _] { + if $data.end { + do $cb $path $g $data $_ + } else { + $data | get $_.sub + | transpose k v + | reduce -f [] {|x, a| + let v = $x.v | node + let g = if ($bc | describe -d).type == 'closure' { + $g | append (do $bc $v $_) + } else { $g } + let r = travel ($path | append $x.k) $g $v $cb $bc $_ + if ($r | is-empty) { + $a + } else { + $a | append $r + } + } + } + } + + + export def spread [list lv=0] { + $list + | each {|x| + if ($x | describe -d).type == 'list' { + spread $x ($lv + 1) + } else { + $x + } + } | flatten + } + } -def comma_file [] { +module resolve { + export def scope [args, vars, flts] { + mut vs = {} + mut cpu = [] + mut flt = {} + let _ = $env.comma_index + for i in ($vars | transpose k v) { + if ($i.v | describe -d).type == 'record' { + if $_.cpu in $i.v { + $cpu ++= {k: $i.k, v: ($i.v | get $_.cpu)} + } else if $_.flt in $i.v { + $flt = ($flt | merge {$i.k: ($i.v | get $_.flt)} ) + } else { + $vs = ($vs | merge {$i.k: $i.v}) + } + } else { + $vs = ($vs | merge {$i.k: $i.v}) + } + } + for i in $cpu { + $vs = ($vs | merge {$i.k: (do $i.v $args $vs)} ) + } + for i in ($flts | default []) { + if $i in $flt { + $vs = ($vs | merge {$i: (do ($flt | get $i) $args $vs)} ) + } else { + error make -u {msg: $"filter `($i)` not found" } + } + } + $vs + } + + + export def comma [key = 'comma'] { + let _ = $env.comma_index + if ($env | get $key | describe -d).type == 'closure' { + do ($env | get $key) $_ + } else { + $env | get $key + } + } +} + +module run { + export def watches [act argv scope w] { + if $w == null { return } + let _ = $env.comma_index + let cl = $w.clear? | default false + if 'interval' in $w { + loop { + if $cl { + clear + } + do $act $argv $scope + sleep $w.interval + print -e $env.comma_index.settings.theme.watch_separator + } + } else { + if $cl { + clear + } + if not ($w.postpone? | default false) { + do $act $argv ($scope | upsert $_.wth { op: null path: null new_path: null }) + } + let ops = if ($w.op? | is-empty) {['Write']} else { $w.op } + watch . --glob=($w.glob? | default '*') {|op, path, new_path| + if $cl { + clear + } + if $op in $ops { + do $act $argv ($scope | upsert $_.wth { + op: $op + path: $path + new_path: $path + }) + if not $cl { + print -e $env.comma_index.settings.theme.watch_separator + } + } + } + } + } + + export def main [tbl --watch: bool] { + let n = $in + use tree + use resolve + let n = $n | tree select --strict $tbl + let _ = $env.comma_index + if not $n.node.end { + do $_.tips "require argument" ($n.node | get $_.sub | columns) + return + } + let flt = if $_.flt in $n.node { [...$n.filter ...($n.node | get $_.flt)] } else { $n.filter } + let wth = if $watch { + if $_.wth in $n.node { + [...$n.watch ($n.node | get $_.watch)] + } else { + $n.watch + } + | reduce -f {} {|i,a| $a | merge $i} + } else { + null + } + let act = $n.node | get $_.act + let scope = resolve scope $n.rest (resolve comma 'comma_scope') $flt + + if ($wth | is-empty) { + do $act $n.rest $scope + } else { + watches $act $n.rest $scope $wth + } + } + + export def complete [tbl] { + let n = $in + let n = if ($n | last) == '' { $n | range ..-2 } else { $n } + use tree + use resolve + let n = $n | tree select $tbl + let _ = $env.comma_index + let flt = if $_.flt in $n.node { [...$n.filter ...($n.node | get $_.flt)] } else { $n.filter } + let wth = if $_.wth in $n.node { $n.node | get $_.wth } else { null } + if $n.node.end { + let cmp = $n.node | get $_.cmp + let scope = resolve scope null (resolve comma 'comma_scope') $flt + do $cmp $n.rest $scope + } else { + $n.node | get $_.sub | transpose k v | each {|x| $x | update v ($x.v | tree node) | enrich desc $flt } + } + } + + def 'enrich desc' [flt] { + let o = $in + let _ = $env.comma_index + let flt = if $_.flt in $o.v { + [...$flt, ...($o.v | get $_.flt)] + } else { + $flt + } + let f = if ($flt | is-empty) { '' } else { $"($flt | str join '|')|" } + let w = if $_.wth in $o.v { + let w = $o.v | get $_.wth + if 'interval' in $w { + $"[poll:($w.interval)]" + } else { + let ops = if ($w.op? | is-empty) {['Write']} else {$w.op} + | str join ',' + $"[($ops)|($w.glob? | default '*')]" + } + } else { '' } + + let suf = $"($w)($f)" + let suf = if ($suf | is-empty) { $suf } else { $"($suf) " } + if ($o.v | describe -d).type == 'record' { + let dsc = if $_.dsc in $o.v { $o.v | get $_.dsc } else { '' } + if ($dsc | is-empty) and ($suf | is-empty) { + $o.k + } else { + { value: $o.k, description: $"($suf)($dsc)"} + } + } else { + # TODO: ? + { value: $o.k, description: $"__($suf)" } + } + } + + def unnest [list lv=0] { + mut cur = [] + mut rt = [] + for i in $list { + if ($i | describe -d).type == 'list' { + $rt = [...$rt, {it: $cur, lv: $lv}, ...(unnest $i ($lv + 1))] + $cur = [] + } else { + $cur = [...$cur, $i] + } + } + if not ($cur | is-empty) { + $rt = [...$rt, {it: $cur, lv: $lv}] + } + return $rt + } + + export def --wrapped dry [...x --prefix=' ' --strip] { + use utils 'str repeat' + let w = term size | get columns + mut lines = [] + for a in (unnest (if $strip { $x.0 } else { $x })) { + mut nl = ($prefix | str repeat $a.lv) + for t in $a.it { + let line = if ($nl | str replace -a ' ' '' | is-empty) { $"($nl)($t)" } else { $"($nl) ($t)" } + if ($line | str length) > $w { + $lines ++= $nl + $nl = $"($prefix | str repeat $a.lv)($t)" + } else { + $nl = $line + } + } + $lines ++= $nl + } + $lines | str join $" \\(char newline)" + } + +} + +module test { + def 'run exp' [expect result o] { + let r = do $expect $result $o.args? $o.scope? + if ($r | describe -d).type == 'bool' { $r } else { + error make -u {msg: $"(view source $o.expect) must be bool" } + } + } + + export def diffo [x] { + let tbl = $x + | transpose k v + | if ($in | length) != 2 { + error make -u { msg: "must be two fields" } + } else { + $in + } + | each {|i| + let n = mktemp -t + echo ($i.v? | default '' | into string) out> $n + $i | insert n $n + } + let a = $tbl.0 + let b = $tbl.1 + let d = ^diff -u --color $a.n $b.n + | lines + | each {|x| + if ($x | str starts-with $"--- ($a.n)") { + $"--- ($a.k)" + } else if ($x | str starts-with $"+++ ($b.n)") { + $"+++ ($b.k)" + } else { + $x + } + } + rm -f $a.n + rm -f $b.n + $d + } + + export def main [fmt, indent, dsc, o] { + let result = do $o.spec? $o.args? $o.scope? | default false + let exp_type = ($o.expect? | describe -d).type + mut stat_list = [] + let status = if $exp_type == 'nothing' { + true == $result + } else if $exp_type == 'closure' { + run exp $o.expect $result $o + } else if $exp_type == 'list' { + $stat_list = ($o.expect | each {|r| run exp $r $result $o }) + $stat_list | all {|x| $x == true } + } else if $exp_type == 'record' { + } else { + $o.expect? == $result + } + let report = if $status { null } else { + let e = if $exp_type == 'closure' { + $"<(view source $o.expect)>" + } else if $exp_type == 'list' { + $o.expect | zip $stat_list + | reduce -f [] {|i,a| $a | append (if $i.1 {'SUCC'} else {$"<(view source $i.0)>"}) } + } else { + $o.expect? + } + let r = { + args: $o.args? + result: $result + expect: $e + } + if ($o.report? | is-empty) { + $r | to yaml | lines + } else { + do $o.report $r + } + } + do $fmt { + indent: $indent + status: $status + message: $dsc + args: $o.args? + report: $report + } + } + + def suit [] { + let specs = $in + use resolve + mut lv = [] + for i in $specs { + let l = $lv | length + let t = $i.path | range ..-2 + for j in ($t | enumerate) { + let desc = $i.g | get $j.index + let g = $env.comma_index.settings.test_group + if $j.index < $l { + let a = $lv | get $j.index + if $j.item == $a { + } else { + do $g { indent: $j.index title: $j.item desc: $desc} + } + } else { + do $g { indent: $j.index title: $j.item desc: $desc} + } + } + main $i.fmt ($i.indent - 1) $i.desc { + expect: $i.expect + spec: $i.spec + args: $i.mock + report: $i.report + scope: (resolve scope null (resolve comma 'comma_scope') []) + } + $lv = $t + } + } + + + export def run [tbl --watch: bool] { + let argv = $in + let _ = $env.comma_index + use tree + let bc = {|node, _| + if $_.dsc in $node { + $node | get $_.dsc + } else { + '' + } + } + let cb = {|pth, g, node, _| + let indent = ($pth | length) + if $_.exp in $node { + let exp = $node | get $_.exp + let spec = $node | get $_.act + let mock = if $_.mock in $node { $node | get $_.mock } + let report = if $_.rpt in $node { $node | get $_.rpt } + let desc = $pth | last + { + path: $pth + g: $g + fmt: $env.comma_index.settings.test_message + indent: $indent + desc: $desc + expect: $exp + spec: $spec + mock: $mock + report: $report + } + } + } + let specs = $argv + | flatten + | tree select --strict $tbl + | do { + let i = $in + if $_.sub in $i.node { + $i.node | get $_.sub + } else { + let n = $argv | last + {$n: ($i.node | reject 'end') } + } + } + | tree map $cb $bc + if ($watch | default false) { + use run watches + watches { + $specs | suit + } [] {} { clear: true } + } else { + $specs | suit + } + } +} + +module vscode-tasks { + export def merge [args tbl --json: bool] { + let c = $args | gen $tbl + if $json { + $c | to json + } else { + $c + } + } + + export def gen [tbl] { + let argv = $in + let _ = $env.comma_index + use tree + let bc = {|node, _| + if $_.dsc in $node { + $node | get $_.dsc + } else { + '' + } + } + let cb = {|pth, g, node, _| + let indent = ($pth | length) + if $_.exp in $node { + [] + } else { + let label = $g + | filter {|x| not ($x | is-empty) } + | str join ' | ' + let command = $pth + | str join ' ' + let args = view source ($node | get $_.act) + | str replace -ar $'[ \n]' '' + | parse --regex '\{\|(.+?)\|.+\}' + let args = if ($args| is-empty) { '' } else { $args.0.capture0 } + let argid = if ($args | is-empty) { '' } else { + $"_($args | str replace -ar $'[ ,\n]' '_')" + } + let cmp = if $_.cmp in $node { random chars -l 8 } + { + label: $label + command: $command + cmp: $cmp + args: $args + argid: $argid + } + } + } + let vs = $argv + | flatten + | tree select --strict $tbl + | $in.node + | reject 'end' + | tree map $cb $bc + let nuc = "nu -c 'use comma.nu *; source ,.nu;" + let tasks = $vs + | each {|x| + let input = if ($x.cmp | is-empty) { '' } else { $" ${input:($x.cmp)}"} + let input = if ($x.args | is-empty) { $input } else { + $"($input) ${input:($x.argid)}" + } + let label = if ($x.label | is-empty) { '' } else { $" [($x.label)]" } + { + type: 'shell' + label: $"($x.command)" + command: $"($nuc) , ($x.command)($input)'" + problemMatcher: [] + } + } + let inputs = $vs + | filter {|x| not ($x.cmp | is-empty) } + | each {|x| { + id: $x.cmp + type: 'command' + command: 'shellCommand.execute' + args: { command: $"($nuc) , -c --vscode ($x.command)'" } + } } + let args = $vs + | reduce -f {} {|x,a| + if ($x.args | is-empty) { $a } else { + if $x.argid in $a { $a } else { + $a | insert $x.argid { + "type": "promptString", + "id": $x.argid, + "description": $x.args + } + } + } + } + | transpose k v + | get v + + { + version: "2.0.0" + tasks: $tasks + inputs: [...$inputs ...$args] + } + } +} + +def 'find parent' [] { + let o = $in + let depth = ($env.PWD | path expand | path split | length) - 1 + mut cur = [',.nu'] + mut e = '' + for i in 0..$depth { + $e = ($cur | path join) + if ($e | path exists) { break } + $cur = ['..', ...$cur] + $e = '' + } + $e +} + + + +def 'comma file' [] { [ { condition: {|_, after| not ($after | path join ',.nu' | path exists)} @@ -30,8 +668,13 @@ def comma_file [] { { condition: {|_, after| $after | path join ',.nu' | path exists} code: " - print $'(ansi default_underline)(ansi default_bold),(ansi reset).nu (ansi green_italic)detected(ansi reset)...' - print $'(ansi yellow_italic)activating(ansi reset) (ansi default_underline)(ansi default_bold),(ansi reset) module with `(ansi default_dimmed)(ansi default_italic)source ,.nu(ansi reset)`' + print -e $'(ansi default_underline)(ansi default_bold),(ansi reset).nu (ansi green_italic)detected(ansi reset)...' + print -e $'(ansi $env.comma_index.settings.theme.info)activating(ansi reset) (ansi default_underline)(ansi default_bold),(ansi reset) module with `(ansi default_dimmed)(ansi default_italic)source ,.nu(ansi reset)`' + + # TODO: allow parent dir + $env.comma_index.wd = $after + $env.comma_index.session_id = (random chars) + source ,.nu " } @@ -39,383 +682,246 @@ def comma_file [] { } export-env { - $env.config = ( $env.config | upsert hooks.env_change.PWD { |config| - let o = ($config | get -i hooks.env_change.PWD) - let val = (comma_file) - if $o == null { - $val - } else { - $o | append $val - } - }) - $env.comm = ([sub dsc act cmp flt cpu wth] | gendict 5) -} - -def gendict [size: int = 5] { - let keys = $in - mut k = [] - let n = $keys | length - let rk = random chars -l ($n * $size) - for i in 1..$n { - let b = ($i - 1) * $size - let e = $i * $size - $k ++= ($rk | str substring $b..$e) - } - $keys - | zip $k - | reduce -f {} {|x, acc| - $acc | upsert $x.0 $"($x.0)_($x.1)" - } -} - -def log [tag? -c] { - let o = $in - if ($c) { - echo $'---(char newline)' | save -f ~/.cache/comma.log - } else { - echo $'---($tag)---($o | describe)(char newline)($o | to yaml)' | save -a ~/.cache/comma.log - } - $o -} - -def 'as act' [] { - let o = $in - let ix = $env.comm - let t = ($o | describe -d).type - if $t == 'closure' { - { $ix.act: $o } - } else if ($ix.sub in $o) { - null - } else if ($ix.act in $o) { - $o - } else { - null - } -} - -def resolve-scope [args, vars, flts] { - mut vs = {} - mut cpu = [] - mut flt = {} - for i in ($vars | transpose k v) { - if ($i.v | describe -d).type == 'record' { - if $env.comm.cpu in $i.v { - $cpu ++= {k: $i.k, v: ($i.v | get $env.comm.cpu)} - } else if $env.comm.flt in $i.v { - $flt = ($flt | merge {$i.k: ($i.v | get $env.comm.flt)} ) + use utils * + # batch mode + if not ($env.config? | is-empty) { + $env.config = ( $env.config | upsert hooks.env_change.PWD { |config| + let o = ($config | get -i hooks.env_change.PWD) + let val = (comma file) + if $o == null { + $val } else { - $vs = ($vs | merge {$i.k: $i.v}) + $o | append $val } - } else { - $vs = ($vs | merge {$i.k: $i.v}) - } + }) } - for i in $cpu { - $vs = ($vs | merge {$i.k: (do $i.v $args $vs)} ) - } - for i in ($flts | default []) { - if $i in $flt { - $vs = ($vs | merge {$i: (do ($flt | get $i) $args $vs)} ) - } else { - error make {msg: $"filter `($i)` not found" } - } - } - $vs -} - -def get-comma [] { - if ($env.comma | describe -d).type == 'closure' { - do $env.comma $env.comm - } else { - $env.comma - } -} - -def get-scope [] { - if ($env.comma_scope | describe -d).type == 'closure' { - do $env.comma_scope $env.comm - } else { - $env.comma_scope - } -} - -def run [tbl] { - let loc = $in - let ix = $env.comm - mut act = $tbl - mut argv = [] - mut flt = [] - for i in $loc { - let a = $act | as act - if ($a | is-empty) { - if ($ix.sub in $act) and ($i in ($act | get $ix.sub)) { - if $ix.flt in $act { - $flt ++= ($act | get $ix.flt) + $env.comma_index = ( + [ + [children sub s] + [description desc dsc d] + [action act a] + [completion cmp c] + [filter flt f] + [computed cpu u] + [watch wth w] + tag + # test + [expect exp e x] + [mock test_args m] + [report rpt r] + # internal + dry_run + ] + | gendict 5 { + settings: { + test_group: {|x| + let indent = ' ' | str repeat $x.indent + let s = $"(ansi bg_dark_gray)GROUP(ansi reset)" + let t = $"(ansi yellow_bold)($x.title)(ansi reset)" + let d = $"(ansi light_gray)($x.desc)(ansi reset)" + print $"($indent)($s) ($t) ($d)" } - let n = $act | get $ix.sub | get $i - $act = $n - } else if $i in $act { - let n = $act | get $i - $act = $n - } else { - $act = {|| print $"not found `($i)`"} - break - } - } else { - $argv ++= $i - } - } - let a = $act | as act - if ($a | is-empty) { - let c = if $ix.sub in $act { $act | get $ix.sub | columns } else { $act | columns } - print $'require argument: ($c)' - } else { - if $ix.flt in $a { - $flt ++= ($a | get $ix.flt) - } - let scope = (resolve-scope $argv (get-scope) $flt) - let cls = $a | get $ix.act - let argv = $argv - if $ix.wth in $a { - mut poll = [] - let g = $a | get $ix.wth - let g = if ($g | is-empty) { - '*' - } else if ($g | str starts-with 'poll') { - let p = $g | split row ':' - $poll ++= ($p.1? | default '1sec' | into duration) - } else { - $g - } - - if ($poll | is-empty) { - watch . --glob=$g {|| do $cls $argv $scope } - } else { - loop { - do $cls $argv $scope - sleep $poll.0 - print $"(ansi dark_gray)----------(ansi reset)" - } - } - } else { - do $cls $argv $scope - } - } -} - -def enrich-desc [flt] { - let o = $in - let _ = $env.comm - let flt = if $_.flt in $o.v { [...$flt, ...($o.v | get $_.flt)] } else { $flt } - let f = if ($flt | is-empty) { '' } else { $"($flt | str join '|')|" } - let w = if $_.wth in $o.v { - let w = $o.v | get $_.wth - if ($w | is-empty) { - $"[watch]" - } else if ($w | str starts-with 'poll') { - $"[($w)]" - } else { - $"[watch:($w)]" - } - } else { '' } - - let suf = $"($w)($f)" - let suf = if ($suf | is-empty) { $suf } else { $"($suf) " } - if ($o.v | describe -d).type == 'record' { - let dsc = if $_.dsc in $o.v { $o.v | get $_.dsc } else { '' } - if ($dsc | is-empty) { - $o.k - } else { - { value: $o.k, description: $"($suf)($dsc)"} - } - } else { - { value: $o.k, description: $"__($suf)" } - } -} - -def complete [tbl] { - let argv = $in - let ix = $env.comm - mut tbl = (get-comma) - mut flt = [] - for i in $argv { - let c = if ($i | is-empty) { - $tbl - } else { - let tp = ($tbl | describe -d).type - if ($tp == 'record') and ($i in $tbl) { - let j = $tbl | get $i - if $ix.sub in $j { - if $ix.flt in $j { - $flt ++= ($j | get $ix.flt) + test_message: {|x| + let indent = ' ' | str repeat $x.indent + let status = if $x.status { + $"(ansi bg_green)SUCC(ansi reset)" + } else { + $"(ansi bg_red)FAIL(ansi reset)" + } + print $"($indent)($status) (ansi yellow_bold)($x.message) (ansi light_gray)($x.args)(ansi reset)" + if not ($x.report | is-empty) { + let report = if $indent == 0 { + $x.report + } else { + $x.report | each {|i| $"($indent)($i)"} + } + | str join (char newline) + print $"(ansi light_gray)($report)(ansi reset)" } - $j | get $ix.sub - } else { - $j } - } else { - $tbl - } - } - let a = $c | as act - if not ($a | is-empty) { - let r = do ($a | get $ix.cmp) $argv (resolve-scope null (get-scope) null) - $tbl = $r - } else { - $tbl = $c - } - } - let flt = $flt - match ($tbl | describe -d).type { - record => { - $tbl - | transpose k v - | each {|x| - if ($x.v | describe -d).type == 'closure' { - $x.k - } else { - $x | enrich-desc $flt + theme: { + info: 'yellow_italic' + batch_hint: 'dark_gray' + watch_separator: $"(ansi dark_gray)------------------------------(ansi reset)" } } + os: (os type) + arch: (uname -m) + lg: {$in | lg} + batch: {|mod| + let o = $in + | lines + | split row ';' + | flatten + let cmd = ['use comma.nu *' $'source ($mod)' ...$o ] + | str join (char newline) + print -e $"(ansi $env.comma_index.settings.theme.batch_hint)($cmd)(ansi reset)" + nu -c $cmd + } + test: {|dsc, spec| + use test + let fmt = $env.comma_index.settings.test_message + test $fmt 0 $dsc $spec + } + tips: {|...m| + if ($m | length) > 2 { + print -e $"(ansi light_gray_italic)Accepts no more than (ansi yellow_bold)2(ansi reset)(ansi light_gray_italic) parameters(ansi reset)" + } else { + print -e $"(ansi light_gray_italic)($m.0)(ansi reset) (ansi yellow_bold)($m.1?)(ansi reset)" + } + } + T: { true } + F: { false } + I: {|x| $x } + diff: {|x| + use test + test diffo {expect: $x.expect, result: $x.result} + } + outdent: { $in | outdent } + config: {|cb| + # FIXME: no affected $env + $env.comma_index.settings = (do $cb $env.comma_index.settings) + } } - list => { $tbl } - _ => { $tbl } - } + ) } -def summary [] { - let o = $in - $o + +def summary [$tbl] { + let argv = $in + use tree + $argv + | flatten + | tree select --strict $tbl + | $in.node + | get $env.comma_index.sub + | tree map { |pth, g, node| { + path: $pth + node: $node + } } } def 'parse argv' [] { let context = $in $context.0 | str substring 0..$context.1 + | split row ';' + | last + | str trim -l | split row -r '\s+' | range 1.. | where not ($it | str starts-with '-') } -def compos [...context] { +def expose [t, a, tbl] { + match $t { + test => { + use test + $a | test run $tbl + } + summary => { + $a | summary $tbl + } + vscode => { + use vscode-tasks + $a | vscode-tasks gen $tbl + } + dry => { + use run + run dry $a + } + _ => { + let _ = $env.comma_index + do $_.tips "expose has different arguments" [ + test + summary + vscode + ] + } + } +} + +# perform or print +export def --wrapped pp [...x --print] { + if $print or (do -i { $env.comma_index | get $env.comma_index.dry_run } | default false) { + use run + run dry $x --strip + } else { + use tree spread + ^$x.0 (spread ($x | range 1..)) + } +} + +def completion [...context] { + use resolve + use run $context | parse argv - | complete (get-comma) + | run complete (resolve comma) } export def --wrapped , [ - --summary - --completion - ...args:string@compos + # flag with parameters is not supported + --json (-j) + --completion (-c) + --vscode + --test (-t) + --tag (-g) + --watch (-w) + --print (-p) + --expose (-e) # for test + ...args:string@'completion' ] { - if $summary { - let r = get-comma | summary | to json - return $r - } - if $completion { - return - } + use resolve if ($args | is-empty) { - if ([$env.PWD, ',.nu'] | path join | path exists) { + if $vscode { + use vscode-tasks + vscode-tasks merge $args (resolve comma) --json $json + } else if ([$env.PWD, ',.nu'] | path join | path exists) { ^$env.EDITOR ,.nu } else { - let a = [closure record no] | input list 'create ,.nu?' - if $a == 'record' { - $" - $env.comma_scope = { - created: '(date now | format date '%Y-%m-%d{%w}%H:%M:%S')' - computed: {$env.comm.cpu:{|a, s| $'\($s.created\)\($a\)' }} - say: {|s| print $'\(ansi yellow_italic\)\($s\)\(ansi reset\)' } - quick: {$env.comm.flt:{|a, s| do $s.say 'run a `quick` filter' }} - slow: {$env.comm.flt:{|a, s| - do $s.say 'run a `slow` filter' - sleep 1sec - do $s.say 'filter need to be declared' - sleep 1sec - $'\($s.computed\)<\($a\)>' - }} - } - - $env.comma = { - created: {|a, s| $s.computed } - open: { - $env.comm.sub: { - any: { - $env.comm.act: {|a, s| open $a.0} - $env.comm.cmp: {ls | get name} - $env.comm.dsc: 'open a file' - } - json: { - $env.comm.act: {|a, s| open $a.0} - $env.comm.cmp: {ls *.json | get name} - $env.comm.dsc: 'open a json file' - $env.comm.wth: '*.json' - } - scope: { - $env.comm.act: {|a, s| print $'args: \($a\)'; $s } - $env.comm.flt: ['slow'] - $env.comm.dsc: 'open scope' - $env.comm.wth: 'poll:2sec' - } - } - $env.comm.dsc: 'open something' - $env.comm.flt: ['quick'] - } - } - " - | unindent - | save $",.nu" - #source ',.nu' - } - if $a == 'closure' { - $" - $env.comma_scope = {|_|{ - created: '(date now | format date '%Y-%m-%d{%w}%H:%M:%S')' - computed: {$_.cpu:{|a, s| $'\($s.created\)\($a\)' }} - say: {|s| print $'\(ansi yellow_italic\)\($s\)\(ansi reset\)' } - quick: {$_.flt:{|a, s| do $s.say 'run a `quick` filter' }} - slow: {$_.flt:{|a, s| - do $s.say 'run a `slow` filter' - sleep 1sec - do $s.say 'filter need to be declared' - sleep 1sec - $'\($s.computed\)<\($a\)>' - }} - }} - - $env.comma = {|_|{ - created: {|a, s| $s.computed } - open: { - $_.sub: { - any: { - $_.act: {|a, s| open $a.0} - $_.cmp: {ls | get name} - $_.dsc: 'open a file' - } - json: { - $_.act: {|a, s| open $a.0} - $_.cmp: {ls *.json | get name} - $_.dsc: 'open a json file' - $_.wth: '*.json' - } - scope: { - $_.act: {|a, s| print $'args: \($a\)'; $s } - $_.flt: ['slow'] - $_.dsc: 'open scope' - $_.wth: 'poll:2sec' - } - } - $_.dsc: 'open something' - $_.flt: ['quick'] - } - }} - " - | unindent - | save $",.nu" + let a = [yes no] | input list 'create ,.nu ?' + let time = date now | format date '%Y-%m-%d{%w}%H:%M:%S' + let txt = [($nu.config-path | path dirname) scripts comma_tmpl.nu] + | path join + | open $in + | str replace '{{time}}' $time + if $a == 'yes' { + $txt | save $",.nu" #source ',.nu' + } else { + $txt } } } else { - $args | run (get-comma) + let tbl = resolve comma + if $completion { + use run + let c = $args | flatten | run complete $tbl + if $vscode { + $c + | each {|x| + if ($x | describe -d).type == 'string' { $x } else { + $"($x.value)||($x.description)|" + } + } + | str join (char newline) + } else if $json { + $c | to json + } else { + $c + } + } else if $test { + use test + $args | flatten | test run $tbl --watch $watch + } else if $expose { + expose $args.0 ($args | range 1..) $tbl + } else { + if $print { + $env.comma_index = ($env.comma_index | upsert $env.comma_index.dry_run true) + } + use run + $args | flatten | run $tbl --watch $watch + } } } diff --git a/modules/comma/comma_test.nu b/modules/comma/comma_test.nu new file mode 100644 index 0000000..ad4d39a --- /dev/null +++ b/modules/comma/comma_test.nu @@ -0,0 +1,252 @@ +$env.comma_scope = {|_|{ + created: '2023-12-23{6}12:51:14' + computed: {$_.computed:{|a, s| $'($s.created)($a)' }} + say: {|s| print -e $'(ansi $_.settings.theme.info)($s)(ansi reset)' } + q1: {$_.flt:{|a, s| do $s.say 'run `q1` filter' }} + q2: {$_.flt:{|a, s| do $s.say 'run `q2` filter' }} + q3: {$_.flt:{|a, s| do $s.say 'run `q3` filter' }} + q4: {$_.flt:{|a, s| do $s.say 'run `q4` filter' }} + slow: {$_.flt:{|a, s| + do $s.say 'run a `slow` filter' + sleep 1sec + do $s.say 'filter need to be declared' + sleep 1sec + $'($s.computed)<($a)>' + }} +}} + +$env.comma = {|_|{ + created: {|a, s| $s.computed } + inspect: {|a, s| {index: $_, scope: $s, args: $a} } + suit: { + scope: { + '`say` in scope': { + $_.act: {|a, s| $s} + $_.exp: {|r, a| 'say' in $r } + } + } + dry_run: { + a: { pp pwd } + no: { + $_.a: {, suit dry_run a } + $_.x: {|r| ($r | lines | get 0) == $env.PWD } + } + yes: { + $_.a: {, -p suit dry_run a } + $_.x: {|r| $r == 'pwd'} + } + ee: { + $_.a: { + 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] + } + $_.x: ( ' + aaa bbbb ccccc dddddd eeeeee \ + ffffff gggggggggg \ + hhhhhhhhh iiiiiiiiii lllllllll \ + mmmmmmmmmmmmm nnnnnnnnnnnn aaaaaaaaaaaaaaa xxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyy \ + zzzzzzzzzzzzzzz jjjjjjjjjjjjj \ + oooooooo ppppppppp \ + qqqqqq \ + rrrrrr ssssss tttttt \ + uuuuuu' | do $_.outdent) + $_.report: $_.diff + } + } + completion: { + '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| 'q1|q2|q3|q4| open a file' == ($r | get 1.description) } + ] + } + 'with args': { + $_.act: { , -c example a b c e open_file } + $_.x: {|r,a| ',.nu' in $r } + } + args: { + $_.a: {|a,s| $a } + $_.c: {|a,s| $a } + } + '': { + $_.act: { , test -c } + $_.x: {|r,a| $r | where value == 'ping' | not ($in | is-empty) } + } + 'run with args': { + $_.act: {|a| , suit completion args $a } + $_.m: [a b c d e f g] + $_.x: {|r,a| $r == $a } + } + 'with multiple args': { + $_.act: {|a| , -c suit completion args $a } + $_.m: [a b c d e f g] + $_.x: {|r,a| $r == $a } + } + } + vscode: { + 'gen': { + $_.a: { , --vscode } + $_.x: {|r,a| $r.version == '2.0.0' } + } + } + } + example: { + a: { + b: { + $_.sub: { + t1: { + $_.act: $_.T + $_.exp: $_.T + } + open_file: { + $_.act: {|a, s| open $a.0 } + $_.cmp: {ls | get name} + $_.dsc: 'open a file' + } + c: { + $_.sub: { + d: {|| print 'ok'} + e: { + $_.sub: { + f: { + $_.act: $_.T + } + open_file: { + $_.act: {|a, s| open $a.0 } + $_.cmp: {ls | get name} + $_.dsc: 'open a file' + $_.filter: ['q4'] + $_.exp: {|r, a| $r == (open ',.nu') } + $_.mock: [',.nu'] + $_.report: $_.diff + } + t3: { + $_.act: $_.T + $_.exp: $_.T + } + } + $_.dsc: 'ok' + $_.flt: ['q3'] + } + } + } + t2: { + $_.act: $_.T + $_.exp: $_.T + } + } + $_.dsc: 'this way' + $_.filter: ['q1' 'q2'] + } + g: {} + } + set: {|a, s| do $_.config {|d| $d | upsert $a.0 $a.1 } } + get: {|a,s| $_.settings; {a: 123} } + add: {|a,s| ($a.0 | into int) + ($a.1 | into int) } + } + test: { + comma: { + $_.act: { + ', test all' | do $_.batch 'comma_test.nu' + } + $_.wth: { + glob: '*.nu' + clear: true + } + $_.dsc: 'copy this to uplevel' + } + all: { + do $_.test 'add' { + expect: {|x| $x == 3 } + spec: {|a|, example add 1 2 } + } + do $_.test 'struct' { + spec: {|a| , test struct } + } + do $_.test 'args' { + expect: {|x, a| true } + spec: {|x| [$x] } + args: 'this is args' + context: {|x, a| $x} + } + do $_.test 'set env' { + spec: { , test set-env } + expect: {|x| $x.a? == 123 } + } + do $_.test 'open file' { + expect: {|x| $x == (open ,.nu) } + spec: { , example a b c e open_file ,.nu } + } + do $_.test 'completion' { + expect: {|x| ',.nu' in $x } + spec: { , -c example a b c e open_file } + args: [example a b c e open_file] + } + do $_.test 'completion' { + expect: {|x| $x | where value == 'f' | not ($in | is-empty) } + spec: {|x| , -c $x } + args: [example a b c e] + } + do $_.test 'run test' { + expect: $_.T + spec: {, -e test example } + } + do $_.test 'run leaf test' { + expect: $_.T + spec: { , -t example a b t1 } + } + do $_.test 'suit' { + expect: $_.T + spec: { , -t suit } + } + } + struct: { + $_.act: { + , example a b c e f + } + } + set-env: { + $_.act: { + , example set a 123 + , example get + } + } + other: {|a, s| + $s + } + poll: { + $_.act: { print $env.PWD } + $_.wth: { + interval: 1sec + } + } + ping: { + $_.action: {|a, s| ping -c 2 localhost } + $_.watch: { + interval: 2sec + clear: true + } + $_.filter: ['slow'] + } + vscode: { + gen: { + $_.act: {|a,s| print $a.0 } + $_.wth: { glob: '*.nu' } + } + complete: { + $_.act: $_.T + $_.wth: { glob: '*.nu' } + } + } + } +}} diff --git a/modules/comma/comma_tmpl.nu b/modules/comma/comma_tmpl.nu new file mode 100644 index 0000000..3963c53 --- /dev/null +++ b/modules/comma/comma_tmpl.nu @@ -0,0 +1,64 @@ +$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)>' + }} +}} + +$env.comma = {|_|{ + created: {|a, s| $s.computed } + inspect: {|a, s| {index: $_, scope: $s, args: $a} | table -e } + vscode-tasks: { + $_.a: { + mkdir .vscode + ', --vscode -j' | do $_.batch ',.nu' | save -f .vscode/tasks.json + } + $_.d: "generate .vscode/tasks.json" + $_.w: { glob: ',.nu' } + } + dev: { + run: { + $_.action: {|a,s| nu $a.0 } + $_.watch: { glob: '*.nu', clear: true } + $_.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 + } + } + ping: { + $_.action: {|a, s| ping -c 2 localhost } + $_.watch: { + interval: 2sec + clear: true + } + $_.filter: ['slow'] + } + } + $_.desc: 'run test' + $_.filter: ['quick'] + } +}} diff --git a/modules/cwdhist/cwdhist.nu b/modules/cwdhist/cwdhist.nu index 2d0db12..5a49c00 100644 --- a/modules/cwdhist/cwdhist.nu +++ b/modules/cwdhist/cwdhist.nu @@ -77,6 +77,11 @@ export def empty-sqlite [] { | decode base64 --binary | gzip -d } +export def 'cwd history delete' [cwd] { + open $env.cwd_history_file + | query db $"delete from cwd_history where cwd = '($cwd)';" +} + export-env { $env.cwd_history_full = false $env.cwd_history_file = '~/.cache/nu_cwd_history.sqlite' diff --git a/modules/docker/docker.nu b/modules/docker/docker.nu index e32fc80..9c31ab9 100644 --- a/modules/docker/docker.nu +++ b/modules/docker/docker.nu @@ -36,37 +36,30 @@ export def container-process-list [ -n: string@"nu-complete docker ns" container?: string@"nu-complete docker containers" ] { + let cli = $env.docker-cli if ($container | is-empty) { - let cli = $env.docker-cli - if $cli == 'docker' { - ^$cli ps -a --format '{"id":"{{.ID}}", "image": "{{.Image}}", "name":"{{.Names}}", "cmd":{{.Command}}, "port":"{{.Ports}}", "status":"{{.Status}}", "created":"{{.CreatedAt}}"}' + let fmt = '{"id":"{{.ID}}", "image": "{{.Image}}", "name":"{{.Names}}", "cmd":{{.Command}}, "port":"{{.Ports}}", "status":"{{.Status}}", "created":"{{.CreatedAt}}"}' + let fmt = if $cli == 'podman' { $fmt | str replace '{{.Command}}' '"{{.Command}}"' | str replace '{{.CreatedAt}}' '{{.Created}}' } else { $fmt } + ^$cli ps -a --format $fmt | lines | each {|x| let r = $x | from json - let t = $r.created | str substring ..25 | into datetime -f '%Y-%m-%d %H:%M:%S %z' + let t = $r.created | into datetime $r | upsert created $t } - } else if $cli == 'podman' { - ^$cli ps -a --format '{"id":"{{.ID}}", "image": "{{.Image}}", "name":"{{.Names}}", "cmd":"{{.Command}}", "port":"{{.Ports}}", "status":"{{.Status}}", "created":"{{.Created}}"}' - | lines - | each {|x| - let r = $x | from json - let t = $r.created | str substring ..32 | into datetime - $r | upsert created $t - } - } else { - ^$cli ($n | with-flag -n) ps -a - | from ssv - | rename id image cmd created status port name - } } else { - let r = ^$env.docker-cli ($n | with-flag -n) inspect $container + let r = ^$cli ($n | with-flag -n) inspect $container | from json | get 0 - #let e = $r.Config.Env | reduce -f {} {|i, a| - # let x = $i | split row '=' - # $a | upsert $x.0 $x.1? - #} + let image = $r.Image + let img = ^$cli ($n | with-flag -n) inspect $image + | from json + | get 0 + let imgEnv = $img.Config.Env? + | reduce -f {} {|i, a| + let x = $i | split row '=' + $a | upsert $x.0 $x.1? + } let m = $r.Mounts | reduce -f {} {|i, a| if $i.Type == 'bind' { @@ -78,13 +71,13 @@ export def container-process-list [ { name: $r.Name? hostname: $r.Config.Hostname? - image: $r.Image + image: $image created: $r.Created id: $r.Id ports: $p - # FIXME: env + env: $imgEnv mounts: $m - path: $r.Path + entrypoint: $r.Path? args: $r.Args } } @@ -97,29 +90,30 @@ export def image-list [ ] { if ($img | is-empty) { ^$env.docker-cli ($n | with-flag -n) images - | from ssv -a - | each {|x| - let size = $x.SIZE | into filesize - let path = $x.REPOSITORY | split row '/' - let image = $path | last - let repo = $path | range ..(($path|length) - 2) | str join '/' - { - repo: $repo - image: $image - tag: $x.TAG - id: $x.'IMAGE ID' - created: $x.CREATED - size: $size + | from ssv -a + | each {|x| + let size = $x.SIZE | into filesize + let path = $x.REPOSITORY | split row '/' + let image = $path | last + let repo = $path | range ..(($path|length) - 2) | str join '/' + { + repo: $repo + image: $image + tag: $x.TAG + id: $x.'IMAGE ID' + created: $x.CREATED + size: $size + } } - } } else { let r = ^$env.docker-cli ($n | with-flag -n) inspect $img - | from json - | get 0 - let e = $r.Config.Env | reduce -f {} {|i, a| - let x = $i | split row '=' - $a | upsert $x.0 $x.1? - } + | from json + | get 0 + let e = $r.Config.Env? + | reduce -f {} {|i, a| + let x = $i | split row '=' + $a | upsert $x.0 $x.1? + } { id: $r.Id created: $r.Created @@ -129,7 +123,7 @@ export def image-list [ size: $r.Size labels: $r.Labels? env: $e - entrypoint: $r.Config.Entrypoint + entrypoint: $r.Config.Entrypoint? cmd: $r.Config.Cmd? } } diff --git a/modules/kubernetes/kubernetes.nu b/modules/kubernetes/kubernetes.nu index a42e3b1..4bdecba 100644 --- a/modules/kubernetes/kubernetes.nu +++ b/modules/kubernetes/kubernetes.nu @@ -526,7 +526,7 @@ export def kgno [] { def "nu-complete kube deploys and pods" [context: string, offset: int] { let ctx = $context | argx parse let ns = $ctx.namespace? | with-flag -n - if ($ctx._pos.pod? | default '' | str ends-with '-') { + if ($ctx.a? | default false) or ($ctx._pos.pod? | default '' | str ends-with '-') { kubectl get $ns pods | from ssv -a | get NAME } else { kubectl get $ns deployments | from ssv -a | get NAME | each {|x| $"($x)-"} @@ -588,6 +588,7 @@ export def --wrapped ka [ --namespace (-n): string@"nu-complete kube ns" --container(-c): string@"nu-complete kube ctns" --selector(-l): string + --all-pods(-a) ...args ] { let n = $namespace | with-flag -n @@ -634,6 +635,7 @@ export def kl [ --container(-c): string@"nu-complete kube ctns" --follow(-f) --previous(-p) + --all-pods(-a) ] { let n = $namespace | with-flag -n let c = $container | with-flag -c