elvish_config/lib/moi/util/list.elv
2021-08-24 20:44:01 +02:00

298 lines
5.4 KiB
Plaintext

use builtin
use str
fn -p [@argv]{
local:c = (count $argv)
if (== $c 0) {
put [ (all) ]
} elif (== $c 1) {
put $argv[0]
} else {
fail '0 or 1 argument needed given '$c' arguments: ['(each [e]{ put '"'$e'"' } $argv | str:join ', ')']'
}
}
fn -r [step begin end]{
if (> $step 0) {
builtin:range &step=$step $begin (+ $end 1)
} else {
local:d = (+ $begin $end)
builtin:range &step=(* $step -1) $end (+ $begin 1) | each [e]{ - $d $e }
}
}
fn to-list [@argv]{
try {
-p $@argv
} except e {
put $argv
}
}
fn range [&step=1 b @r]{
if (== $step 0) {
fail 'bad value: step must be positive, but is 0'
}
local:c = (count $r)
if (> $c 1) {
fail 'usage: list:range &step=1 begin? end'
}
local:e = 0
if (== $c 0) {
if (> $step 0) {
b e = $e $b
}
} else {
e = $r[0]
}
-r $step $b $e
}
fn indexes [&from=$false &step=1 @argv]{
if (== $step 0) {
fail 'bad value: step must be positive, but is 0'
}
local:l = (-p $@argv)
local:c = (count $l)
if (not $from) {
range &step=$step (- $c 1)
} else {
if (< $from 0) {
from = (+ $c $from)
}
if (> $step 0) {
if (< $from 0) {
from = 0
}
range &step=$step $from (- $c 1)
} else {
if (>= $from $c) {
from = (- $c 1)
}
range &step=$step $from 0
}
}
}
fn -for [&from=$false &step=1 @argv]{
local:l = (-p $@argv)
indexes &from=$from &step=$step $l | each [i]{ put [ $i $l[$i] ] }
}
fn loop [&from=$false &step=1 &end=$false cb @argv]{
if (not $end) {
-for &from=$from &step=$step $@argv | each [e]{ $cb $@e }
} else {
-for &from=$from &step=$step $@argv | each [e]{
local:i local:v = $@e
if ($end $i $v) {
break
}
$cb $i $v
}
}
}
fn ploop [&from=$false &step=1 cb @argv]{
-for &from=$from &step=$step $@argv | peach [e]{ $cb $@e }
}
fn reverse [@argv]{ loop &step=-1 [_ e]{ put $e } $@argv }
fn reach [cb @argv]{ reverse $@argv | each [e]{ cb $e } }
fn empty [@argv]{ == (count (-p $@argv)) 0 }
fn not-empty [@argv]{ not (empty $@argv) }
fn filter [cb @argv]{
each [v]{
if ($cb $v) {
put $v
}
} (-p $@argv)
}
fn filter-not [cb @argv]{ filter [v]{ not ($cb $v) } $@argv }
fn first [&from=$false &reverse=$false cb @argv]{
local:f = [v]{
if ($cb $v) {
put $v
break
}
}
local:l = (-p $@argv)
if (not $from) {
if $reverse {
reach $f $l
} else {
each $f $l
}
} else {
local:c = (count $l)
if (< $from 0) {
from = (+ $c $from)
}
if $reverse {
local:e = (+ $from 1)
if (> $e $c) {
e = $c
} elif (< $e 0) {
e = 0
}
reach $f $l[..$e]
} else {
local:b = $from
if (> $b $c) {
b = $c
} elif (< $b 0) {
b = 0
}
each $f $l[$b..]
}
}
}
fn filter-index [cb @argv]{
loop [i v]{
if ($cb $v) {
put $i
}
} $@argv
}
fn filter-index-not [cb @argv]{ filter-index [v]{ not ($cb $v) } $@argv }
fn first-index [&from=$false &reverse=$false cb @argv]{
local:idx = -1
local:step = 1
if $reverse {
step = -1
}
loop &from=$from &step=$step [i v]{
if ($cb $v) {
idx = $i
break
}
} $@argv
put $idx
}
fn search [cb @argv]{
loop [i v]{
if ($cb $i $v) {
put $v
}
} $@argv
}
fn search-not [cb @argv]{ search [i v]{ not ($cb $i $v) } $@argv }
fn search-first [&from=$false &reverse=$false cb @argv]{
local:step = 1
if $reverse {
step = -1
}
loop &from=$from &step=$step [i v]{
if ($cb $i $v) {
put $v
break
}
} $@argv
}
fn search-index [cb @argv]{
loop [i v]{
if ($cb $i $v) {
put $i
}
} $@argv
}
fn search-index-not [cb @argv]{ search-index [i v]{ not ($cb $i $v) } $@argv }
fn search-first-index [&from=$false &reverse=$false cb @argv]{
local:idx = -1
local:step = 1
if $reverse {
step = -1
}
loop &from=$from &step=$step [i v]{
if ($cb $i $v) {
idx = $i
break
}
} $@argv
put $idx
}
fn contains [cb @argv]{
local:e = $false
each [v]{
if ($cb $v) {
e = $true
break
}
} (-p $@argv)
put $e
}
fn contains-not [cb @argv]{ contains [v]{ not ($cb $v) } $@argv }
fn exists [cb @argv]{
local:e = $false
loop [i v]{
if ($cb $i $v) {
e = $true
break
}
} $@argv
put $e
}
fn exists-not [cb @argv]{ exists [i v]{ $cb $i $v } $@argv }
fn includes [v @argv]{ contains [e]{ is $v $e } $@argv }
fn includes-not [v @argv]{ contains-not [e]{ is $v $e } $@argv }
fn reduce [v cb @argv]{
each [e]{ v = ($cb $v $e) } (to-list $@argv)
put $v
}
fn remove-duplicate [@argv]{
local:done = [&]
each [v]{
put [&v=$v &e=(has-key $done $v)]
done[$v] = $nil
} (-p $@argv) | each [v]{
assoc $v k (not $v[e])
} | each [v]{
if $v[k] {
put $v[v]
}
}
}
fn premove-duplicate [@argv]{
local:done= [&]
peach [v]{
local:v = $v
done[$v] = $nil
} (-p $@argv)
keys $done
}
fn swap [i j @argv]{
local:l = (-p $@argv)
local:c = (count $l)
i j = (-i $i $c) (-i $j $c)
if (or (== $i $c) (== $j $c)) {
fail 'Index out of range'
}
if (== $i $j) {
all $l
} else {
if (> $i $j) {
i j = $j $i
}
take $i $l
put $l[j]
all $l[(+ $i 1)..$j]
put $l[$i]
drop (+ $j 1) $l
}
}
fn less [cb]{
local:l = [a b]{ < ($cb $a $b) 0 }
put $l
}
fn sort [cb @argv]{ order &less-than=(less $cb) (-p $@argv) }