remove comma.nu from repo (#747)

remove a personal project from our public repo.
This commit is contained in:
Darren Schroeder 2024-01-25 06:04:26 -06:00 committed by GitHub
parent d9ba934d77
commit 2e3534d73d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 0 additions and 1453 deletions

View File

@ -1,201 +0,0 @@
# 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
## Quick Start
`,` or `*` need to be exported in order to use `,` Directly
```
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 = {|_|{
dev: {
run: {
$_.action: {|a,s| nu $a.0 }
$_.watch: { glob: '*.nu', clear: true }
$_.completion: { ls *.nu | get name }
$_.desc: "develop a nu script"
}
}
}}
```
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
- [x] dry
- [x] dry wrap lines
- [x] accept list<string>
- [x] formatter: outdent
- [x] complete
- [x] with args
- [x] scoped test
- [x] pass scoped
- [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<string>`
- [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`
- [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

View File

@ -1,941 +0,0 @@
export def show [tag?] {
let o = $in
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
}
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 distro [] {
match $nu.os-info.name {
'linux' => {
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
}
}
_ => {
$nu.os-info.name
}
}
}
export def outdent [] {
let txt = $in | lines | range 1..
let indent = $txt.0 | parse --regex '^(?P<indent>\s*)' | get indent.0 | str length
$txt
| each {|s| $s | str substring $indent.. }
| str join (char newline)
}
}
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
}
}
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 {
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" }
}
}
$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
if not $cl {
do $env.comma_index.settings.theme.watch_separator
}
sleep $w.interval
}
} 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 {
do $env.comma_index.settings.theme.watch_separator
}
}
}
}
}
export def main [tbl --opt: record] {
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 $opt.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] {
let w = term size | get columns
mut lines = []
for a in (unnest (if $strip { $x.0 } else { $x })) {
mut nl = ('' | fill -c $prefix -w $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 = $"('' | fill -c $prefix -w $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 --opt: record] {
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 ($opt.watch? | default false) {
use run watches
watches {
$specs | suit
} [] {} { clear: true }
} else {
$specs | suit
}
}
}
module vscode-tasks {
export def merge [args tbl --opt: record] {
let c = $args | gen $tbl
if $opt.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| $after | path join ',.nu' | path exists}
code: "
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
"
}
]
}
export-env {
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 {
$o | append $val
}
})
}
$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 = '' | fill -c ' ' -w $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)"
}
test_message: {|x|
let indent = '' | fill -c ' ' -w $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)"
}
}
theme: {
info: 'yellow_italic'
batch_hint: 'dark_gray'
watch_separator: {
let w = term size | get columns
print -e $"(ansi dark_gray)('' | fill -c '-' -w $w)(ansi reset)"
}
}
}
distro: (distro)
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
}
show: {$in | show}
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)"
}
}
log: {|lv s|
let c = ['navy' 'teal' 'xpurplea' 'xgreen' 'olive' 'maroon']
let t = date now | format date '%Y-%m-%dT%H:%M:%S'
print -e $"(ansi ($c | get $lv))($t) (ansi light_gray)($s)(ansi reset)"
}
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
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)
}
}
)
}
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 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 --as-str] {
if $print or (do -i { $env.comma_index | get $env.comma_index.dry_run } | default false) {
use run
let r = run dry $x --strip
if $as_str {
$r
} else {
print -e $"(ansi light_gray)($r)(ansi reset)(char newline)"
}
} else {
use tree spread
^$x.0 ...(spread ($x | range 1..))
}
}
def completion [...context] {
use resolve
use run
$context
| parse argv
| run complete (resolve comma)
}
export def --wrapped , [
# 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'
] {
use resolve
if ($args | is-empty) {
if $vscode {
use vscode-tasks
vscode-tasks merge $args (resolve comma) --opt {json: $json}
} else if ([$env.PWD, ',.nu'] | path join | path exists) {
^$env.EDITOR ,.nu
} else {
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 {
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 --opt {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 --opt {watch: $watch}
}
}
}

View File

@ -1,248 +0,0 @@
$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 }
}
pp: {
$_.a: {
pp --print --as-str 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,s| $r | where value == 'f' | not ($in | is-empty) }
(do $_.T {|r,a,s| $s | show 'expect'})
{|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: { true }
$_.exp: { true }
}
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: { true }
}
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: { true }
$_.exp: { true }
}
}
$_.dsc: 'ok'
$_.flt: ['q3']
}
}
}
t2: {
$_.act: { true }
$_.exp: { true }
}
}
$_.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: { true }
spec: {, -e test example }
}
do $_.test 'run leaf test' {
expect: { true }
spec: { , -t example a b t1 }
}
do $_.test 'suit' {
expect: { true }
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: { true }
$_.wth: { glob: '*.nu' }
}
}
}
}}

View File

@ -1,63 +0,0 @@
$env.comma_scope = {|_|{
created: '{{time}}'
computed: {$_.computed:{|a, s| $'($s.created)($a)' }}
log_args: {$_.filter:{|a, s| do $_.tips 'received arguments' $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"
}
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
}
$_.c: {|a,s|
let l = $a | length
if $l < 1 {
['ubuntu', 'alpine', 'nginx']
} else if $l < 2 {
['target']
} else {
['vendor']
}
}
$_.d: 'build docker image'
$_.f: ['log_args']
}
}
}
}}