initial commit
This commit is contained in:
parent
9ffc0e170f
commit
69b66ff555
63
README.md
63
README.md
|
@ -1,2 +1,65 @@
|
||||||
# elv-lib
|
# elv-lib
|
||||||
|
|
||||||
|
elv-lib includes some useful module functions and completions
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## mods
|
||||||
|
|
||||||
|
This folder groups modules for different usages:
|
||||||
|
|
||||||
|
### file
|
||||||
|
|
||||||
|
file provides functions to complete a filename/directory motive with different methods:
|
||||||
|
|
||||||
|
* exact motive
|
||||||
|
* contains motive (with or without deep search)
|
||||||
|
|
||||||
|
- search by prefix (with or without deep search)
|
||||||
|
- search by suffix (with or without deep search)
|
||||||
|
- filter results by given extension
|
||||||
|
|
||||||
|
### format
|
||||||
|
|
||||||
|
format provides functions to beautify a given input. Examples:
|
||||||
|
|
||||||
|
- format:size returns a size (in bytes) in a human-readable format
|
||||||
|
- format:list displays data in columns
|
||||||
|
|
||||||
|
### ip
|
||||||
|
|
||||||
|
ip provides useful functions to manipulate IPv4 or IPv6 addresses.
|
||||||
|
|
||||||
|
### list
|
||||||
|
|
||||||
|
list provides functions to manipulate data of type list. Examples:
|
||||||
|
|
||||||
|
* list:foreach acts as builtin each with the callback function on the form {|i v| } where i is the index in the list an v the value
|
||||||
|
* list:reach acts as builtin each in reverse order
|
||||||
|
* list:filter filters in a list with the given callback criterium
|
||||||
|
* list:contains check if a list contains a specific entry or an entry which passes a callback
|
||||||
|
* etc.
|
||||||
|
|
||||||
|
### map
|
||||||
|
|
||||||
|
map provides functions to manipulate data of type map.
|
||||||
|
|
||||||
|
### num
|
||||||
|
|
||||||
|
num provides useful functions for number operations which are not part of builtin functions or math: module functions.
|
||||||
|
|
||||||
|
### option
|
||||||
|
|
||||||
|
### pdf
|
||||||
|
|
||||||
|
pdf provides functions to manipulate PDF files (qpdf is required to make this module work).
|
||||||
|
|
||||||
|
## completion
|
||||||
|
|
||||||
|
The folder completion contains the completion for some programs:
|
||||||
|
|
||||||
|
- [arc](https://github.com/mholt/archiver)
|
||||||
|
- [kcp](https://github.com/bvaudour/kcp)
|
||||||
|
- mpv
|
||||||
|
- pacman
|
||||||
|
- ssh
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
var dir = $E:HOME/.config/elvish/aliases
|
||||||
|
|
||||||
|
for file [(set _ = ?(put $dir/*.elv))] {
|
||||||
|
var content = (cat $file | slurp)
|
||||||
|
eval $content
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
use ./mods/common
|
||||||
|
edit:add-var cond~ $common:cond~
|
||||||
|
edit:add-var cexec~ $common:cexec~
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
use ./mods/num
|
||||||
|
edit:add-var '++~' $'num:++~'
|
||||||
|
edit:add-var '--~' $'num:--~'
|
||||||
|
edit:add-var neg~ $num:neg~
|
||||||
|
edit:add-var is-neg~ $num:is-neg~
|
||||||
|
edit:add-var is-zero~ $num:is-zero~
|
||||||
|
edit:add-var is-one~ $num:is-one~
|
||||||
|
edit:add-var min~ $num:min~
|
||||||
|
edit:add-var max~ $num:max~
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
use ./completion/arc
|
||||||
|
use ./completion/archiver
|
||||||
|
use ./completion/desarchiver
|
||||||
|
use ./completion/kcp
|
||||||
|
use ./completion/mpv
|
||||||
|
use ./completion/pacman
|
||||||
|
use ./completion/ssh
|
||||||
|
use ./completion/sudo
|
||||||
|
use ./completion/use
|
|
@ -0,0 +1,53 @@
|
||||||
|
use ./file
|
||||||
|
|
||||||
|
var commands = [
|
||||||
|
help
|
||||||
|
archive
|
||||||
|
unarchive
|
||||||
|
extract
|
||||||
|
ls
|
||||||
|
]
|
||||||
|
|
||||||
|
var description = [
|
||||||
|
&help='Display the help'
|
||||||
|
&archive='Create un new archive'
|
||||||
|
&unarchive='Extract all'
|
||||||
|
&extract='Extract a single file'
|
||||||
|
&ls='List the content'
|
||||||
|
]
|
||||||
|
|
||||||
|
var extensions = [ tar bz2 zip gz lz4 sz xz zst rar ]
|
||||||
|
|
||||||
|
fn -comp-commands {
|
||||||
|
each {|c|
|
||||||
|
edit:complex-candidate $c &display=(printf '%s (%s)' $c $description[$c])
|
||||||
|
} $commands
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -comp-inline-files {|archive|
|
||||||
|
try {
|
||||||
|
arc ls $archive | eawk {|_ @argv| put $argv[-1] }
|
||||||
|
} except e {
|
||||||
|
nop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete {|@argv|
|
||||||
|
var c cmd = (count $argv) $argv[1]
|
||||||
|
if (== $c 2) {
|
||||||
|
-comp-commands
|
||||||
|
} elif (== $c 3) {
|
||||||
|
if (not (has-value [help archive] $cmd)) {
|
||||||
|
file:complete $argv[-1] $@extensions
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (eq $cmd archive) {
|
||||||
|
edit:complete-filename $@argv
|
||||||
|
} elif (eq $cmd extract) {
|
||||||
|
var archive = $argv[2]
|
||||||
|
-comp-inline-files $archive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set edit:completion:arg-completer[arc] = $complete~
|
|
@ -0,0 +1,29 @@
|
||||||
|
var options = [
|
||||||
|
z
|
||||||
|
l
|
||||||
|
x
|
||||||
|
b
|
||||||
|
g
|
||||||
|
h
|
||||||
|
]
|
||||||
|
|
||||||
|
var description = [
|
||||||
|
&z='zst compression (default)'
|
||||||
|
&l='lz4 compression'
|
||||||
|
&x='xz compression'
|
||||||
|
&b='bz2 compression'
|
||||||
|
&g='gzip compression'
|
||||||
|
&h='display help'
|
||||||
|
]
|
||||||
|
|
||||||
|
fn -options {
|
||||||
|
each {|o|
|
||||||
|
put [&short=$o &desc=$description[$o]]
|
||||||
|
} $options
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete {|@argv|
|
||||||
|
edit:complete-getopt $argv [(-options)] [ $edit:complete-filename~ ...]
|
||||||
|
}
|
||||||
|
|
||||||
|
set edit:completion:arg-completer[archiver] = $complete~
|
|
@ -0,0 +1,10 @@
|
||||||
|
use ./file
|
||||||
|
|
||||||
|
var extensions = [ tar bz2 zip gz lz4 sz xz zst rar ]
|
||||||
|
|
||||||
|
fn complete {|@argv|
|
||||||
|
var m = $argv[-1]
|
||||||
|
file:complete $m $@extensions
|
||||||
|
}
|
||||||
|
|
||||||
|
set edit:completion:arg-completer[desarchiver] = $complete~
|
|
@ -0,0 +1,7 @@
|
||||||
|
use ../mods/common
|
||||||
|
use ../mods/file
|
||||||
|
|
||||||
|
fn complete {|motive @extensions|
|
||||||
|
var type = (common:cond (eq $motive '') prefix deep-prefix)
|
||||||
|
file:match-extensions &type=$type $motive $@extensions
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
fn -remotes-packages { kcp -lN }
|
||||||
|
|
||||||
|
var options = [
|
||||||
|
-h
|
||||||
|
-v
|
||||||
|
-i
|
||||||
|
-di
|
||||||
|
-u
|
||||||
|
-l
|
||||||
|
-lN
|
||||||
|
-lS
|
||||||
|
-lI
|
||||||
|
-lO
|
||||||
|
-lx
|
||||||
|
-lxS
|
||||||
|
-lxI
|
||||||
|
-lxO
|
||||||
|
-lf
|
||||||
|
-s
|
||||||
|
-g
|
||||||
|
-V
|
||||||
|
]
|
||||||
|
|
||||||
|
var np = [
|
||||||
|
-i
|
||||||
|
-di
|
||||||
|
-s
|
||||||
|
-g
|
||||||
|
-V
|
||||||
|
]
|
||||||
|
|
||||||
|
fn complete {|@argv|
|
||||||
|
var c = (count $argv)
|
||||||
|
if (== $c 2) {
|
||||||
|
all $options
|
||||||
|
} elif (and (== $c 3) (has-value $np $argv[-2])) {
|
||||||
|
-remotes-packages
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set edit:completion:arg-completer[kcp] = $complete~
|
|
@ -0,0 +1,53 @@
|
||||||
|
use ./file
|
||||||
|
|
||||||
|
var extensions = [
|
||||||
|
aac
|
||||||
|
ape
|
||||||
|
avi
|
||||||
|
divx
|
||||||
|
flac
|
||||||
|
flv
|
||||||
|
m3u
|
||||||
|
m4a
|
||||||
|
m4v
|
||||||
|
mp3
|
||||||
|
mp4
|
||||||
|
mpeg
|
||||||
|
mpg
|
||||||
|
mkv
|
||||||
|
mng
|
||||||
|
mov
|
||||||
|
qt
|
||||||
|
oga
|
||||||
|
ogg
|
||||||
|
ogm
|
||||||
|
ogv
|
||||||
|
opus
|
||||||
|
ra
|
||||||
|
rv
|
||||||
|
ts
|
||||||
|
vob
|
||||||
|
wav
|
||||||
|
webm
|
||||||
|
wmv
|
||||||
|
wma
|
||||||
|
wmx
|
||||||
|
]
|
||||||
|
|
||||||
|
fn complete {|@argv|
|
||||||
|
var c = (count $argv)
|
||||||
|
if (== $c 2) {
|
||||||
|
put --speed
|
||||||
|
-files $argv[-1]
|
||||||
|
} elif (== $c 3) {
|
||||||
|
if (eq $argv[-2] --speed) {
|
||||||
|
put 0.8 0.9 1.0 1.1 1.2
|
||||||
|
} else {
|
||||||
|
file:complete $argv[-1] $@extensions
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
-files $argv[-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set edit:completion:arg-completer[mpv] = $complete~
|
|
@ -0,0 +1,99 @@
|
||||||
|
use str
|
||||||
|
use ../mods/file
|
||||||
|
use ../mods/list
|
||||||
|
|
||||||
|
fn -local-packages { pacman -Q | eawk {|_ p @_| put $p } }
|
||||||
|
|
||||||
|
fn -repo-packages {
|
||||||
|
var packages = [(pacman -Ss | list:pforeach &step=2 {|_ v|
|
||||||
|
put $v
|
||||||
|
} | eawk {|_ p @_|
|
||||||
|
put $p
|
||||||
|
})]
|
||||||
|
var spackages = [&]
|
||||||
|
peach {|p|
|
||||||
|
str:split '/' $p
|
||||||
|
} $packages | peach {|e|
|
||||||
|
set spackages[$e] = $nil
|
||||||
|
}
|
||||||
|
keys $spackages
|
||||||
|
all $packages
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = [
|
||||||
|
-h
|
||||||
|
-V
|
||||||
|
-Q
|
||||||
|
-Qs
|
||||||
|
-Ql
|
||||||
|
-Qi
|
||||||
|
-Qm
|
||||||
|
-Qdt
|
||||||
|
-Qo
|
||||||
|
-R
|
||||||
|
-Rsn
|
||||||
|
-S
|
||||||
|
-Ss
|
||||||
|
-Si
|
||||||
|
-Sii
|
||||||
|
-Syu
|
||||||
|
-Syyu
|
||||||
|
-U
|
||||||
|
-D
|
||||||
|
]
|
||||||
|
|
||||||
|
var asdeps = [
|
||||||
|
-S
|
||||||
|
-U
|
||||||
|
-D
|
||||||
|
]
|
||||||
|
|
||||||
|
var lpack = [
|
||||||
|
-Q
|
||||||
|
-Qs
|
||||||
|
-Ql
|
||||||
|
-Qi
|
||||||
|
-D
|
||||||
|
-R
|
||||||
|
-Rsn
|
||||||
|
]
|
||||||
|
|
||||||
|
var rpack = [
|
||||||
|
-S
|
||||||
|
-Ss
|
||||||
|
-Si
|
||||||
|
-Sii
|
||||||
|
]
|
||||||
|
|
||||||
|
var dpack = [
|
||||||
|
-U
|
||||||
|
]
|
||||||
|
|
||||||
|
var fpack = [
|
||||||
|
-Qo
|
||||||
|
]
|
||||||
|
|
||||||
|
var extensions = [ tar.zst tar.xz tar.gz tar.bz2 ]
|
||||||
|
|
||||||
|
fn complete {|@argv|
|
||||||
|
var c = (count $argv)
|
||||||
|
if (< $c 3) {
|
||||||
|
all $options
|
||||||
|
} else {
|
||||||
|
var cmd = $argv[1]
|
||||||
|
if (and (== $c 3) (has-value $asdeps $cmd)) {
|
||||||
|
put --asdeps --asexplicit
|
||||||
|
}
|
||||||
|
if (has-value $lpack $cmd) {
|
||||||
|
-local-packages
|
||||||
|
} elif (has-value $rpack $cmd) {
|
||||||
|
-repo-packages
|
||||||
|
} elif (has-value $dpack $cmd) {
|
||||||
|
file:complete $argv[-1] $@extensions
|
||||||
|
} elif (has-value $fpack $cmd) {
|
||||||
|
edit:complete-filename $argv[-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set edit:completion:arg-completer[pacman] = $complete~
|
|
@ -0,0 +1,95 @@
|
||||||
|
use path
|
||||||
|
use re
|
||||||
|
use str
|
||||||
|
use ../mods/common
|
||||||
|
use ../mods/list
|
||||||
|
use ../mods/map
|
||||||
|
use ../mods/option
|
||||||
|
|
||||||
|
var options-ssh = [ 1 2 4 6 A D f g I i L l m o v a b C c e F k N n p q R s T t X x ]
|
||||||
|
var options-scp = [ 3 4 6 B C p q r v c F i l o P S ]
|
||||||
|
|
||||||
|
fn -kh {
|
||||||
|
cat ~/.ssh/known_hosts | peach {|l|
|
||||||
|
put [(str:split ' ' $l)]
|
||||||
|
} | peach {|e|
|
||||||
|
var domains @_ = $@e
|
||||||
|
str:split ',' $domains
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -port {|cmd @argv|
|
||||||
|
var o = (common:cond (eq $cmd 'ssh') '-p' '-P')
|
||||||
|
var margs = (option:map $argv)
|
||||||
|
var p = (map:value-of $margs $o &default=[])
|
||||||
|
cond:cexec (list:is-empty $p) 22 { put $p[-1] }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -complete-names {
|
||||||
|
var fp = $E:HOME/.config/elvish/private/sshnames
|
||||||
|
if (path:is-regular $fp) {
|
||||||
|
cat $fp | from-lines | each {|n| put (printf '%s@' $n) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -complete-domains {|name hosts|
|
||||||
|
each {|h|
|
||||||
|
put (printf '%s@%s' $name $h)
|
||||||
|
} $hosts
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -complete-remote-dir {|port address dir|
|
||||||
|
var cmd = (printf ^
|
||||||
|
"for f in '%s'*; do if [[ -d $f ]]; then echo $f/; else echo $f; fi; done" ^
|
||||||
|
$dir)
|
||||||
|
try {
|
||||||
|
ssh -p $port $address $cmd | each {|f|
|
||||||
|
put (printf '%s:%s' $address $f)
|
||||||
|
}
|
||||||
|
} except e { }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -complete-args {|hosts cmd @argv|
|
||||||
|
var arg = $argv[-1]
|
||||||
|
var i = (str:index $arg @)
|
||||||
|
if (< $i 0) {
|
||||||
|
-complete-names
|
||||||
|
all $hosts
|
||||||
|
if (eq $cmd scp) {
|
||||||
|
edit:complete-filename $cmd $@argv
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var n h = $arg[..$i] $arg[(+ $i 1)..]
|
||||||
|
if (eq $cmd scp) {
|
||||||
|
set i = (str:index $h :)
|
||||||
|
if (>= $i 0) {
|
||||||
|
var d = $h[(+ $i 1)..]
|
||||||
|
set h = $h[..$i]
|
||||||
|
if (list:contains $h $hosts) {
|
||||||
|
var p = (-port $cmd @argv)
|
||||||
|
-complete-remote-dir $p $n@$h $d
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
-complete-domains $n $hosts
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete {|@argv|
|
||||||
|
var @hosts = (-kh)
|
||||||
|
var cmd = $argv[0]
|
||||||
|
var is-ssh = (eq $cmd ssh)
|
||||||
|
var po = (common:cond $is-ssh -p -P)
|
||||||
|
if (<= (count $argv) 2) {
|
||||||
|
all (common:cond $is-ssh $options-ssh $options-scp)
|
||||||
|
-complete-args $hosts $@argv
|
||||||
|
} elif (eq $argv[-2] $po) {
|
||||||
|
put 22
|
||||||
|
} else {
|
||||||
|
-complete-args $hosts $@argv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set edit:completion:arg-completer[scp] = $complete~
|
||||||
|
set edit:completion:arg-completer[ssh] = $complete~
|
|
@ -0,0 +1,10 @@
|
||||||
|
fn complete {|@argv|
|
||||||
|
if (and (> (count $argv) 2) (has-key $edit:completion:arg-completer $argv[1])) {
|
||||||
|
$edit:completion:arg-completer[$argv[1]] (all $argv[1:])
|
||||||
|
} else {
|
||||||
|
edit:complete-sudo $@argv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set edit:completion:arg-completer[sudo] = $edit:complete-sudo~
|
||||||
|
#edit:completion:arg-completer[sudo] = $-complete~
|
|
@ -0,0 +1,31 @@
|
||||||
|
use path
|
||||||
|
use str
|
||||||
|
use ./file
|
||||||
|
|
||||||
|
var libdir = $E:HOME/.config/elvish/lib
|
||||||
|
var builtin_modules = [
|
||||||
|
builtin
|
||||||
|
epm
|
||||||
|
file
|
||||||
|
math
|
||||||
|
path
|
||||||
|
re
|
||||||
|
readline-binding
|
||||||
|
store
|
||||||
|
str
|
||||||
|
unix
|
||||||
|
]
|
||||||
|
|
||||||
|
set edit:completion:arg-completer[use] = {|@argv|
|
||||||
|
use str
|
||||||
|
use path
|
||||||
|
all $builtin_modules
|
||||||
|
put $libdir/**.elv | each {|f|
|
||||||
|
if (path:is-regular $f) {
|
||||||
|
str:trim-prefix $f $libdir/
|
||||||
|
}
|
||||||
|
} | each {|f| str:trim-suffix $f .elv }
|
||||||
|
if (> (count $argv) 1) {
|
||||||
|
file:complete $argv[-1] elv | each {|f| str:trim-suffix $f .elv }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
fn to-list {|@argv|
|
||||||
|
var c = (count $argv)
|
||||||
|
if (== $c 0) {
|
||||||
|
put [ (all) ]
|
||||||
|
} elif (== $c 1) {
|
||||||
|
put $argv[0]
|
||||||
|
} else {
|
||||||
|
fail (printf '0 or 1 argument needed given %d arguments: %v' $c $argv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cond {|cond v1 v2|
|
||||||
|
if $cond {
|
||||||
|
put $v1
|
||||||
|
} else {
|
||||||
|
put $v2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cexec {|cond v1 v2|
|
||||||
|
var r = (cond $cond $v1 $v2)
|
||||||
|
if (eq (kind-of $r) fn) {
|
||||||
|
$r
|
||||||
|
} else {
|
||||||
|
put $r
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
use str
|
||||||
|
use ./list
|
||||||
|
use ./map
|
||||||
|
|
||||||
|
var search-type = [
|
||||||
|
&exact= {|m| ls $m 2>/dev/null }
|
||||||
|
&match= {|m| put *$m* }
|
||||||
|
&prefix= {|m| put $m* }
|
||||||
|
&suffix= {|m| put *$m }
|
||||||
|
&deep-match= {|m| put **$m** }
|
||||||
|
&deep-prefix= {|m| put $m** }
|
||||||
|
&deep-suffix= {|m| put **$m }
|
||||||
|
]
|
||||||
|
|
||||||
|
fn comp {|f1 f2|
|
||||||
|
var fl1 fl2 = (str:to-lower $f1) (str:to-lower $f2)
|
||||||
|
var c = (str:compare $fl1 $fl2)
|
||||||
|
if (!= $c 0) {
|
||||||
|
put $c
|
||||||
|
} else {
|
||||||
|
str:compare $f1 $f2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -r {|sort result|
|
||||||
|
if $sort {
|
||||||
|
keys $result | list:sort $comp~
|
||||||
|
} else {
|
||||||
|
keys $result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -s {|&sort=$false &type=exact @motive|
|
||||||
|
var f result = $search-type[$type] [&]
|
||||||
|
if (list:is-empty $motive) {
|
||||||
|
set result = (put * | map:to-set)
|
||||||
|
} else {
|
||||||
|
peach {|m|
|
||||||
|
try {
|
||||||
|
$f $m | peach {|e|
|
||||||
|
set result[$e] = $nil
|
||||||
|
}
|
||||||
|
} except e { }
|
||||||
|
} $motive
|
||||||
|
}
|
||||||
|
-r $sort $result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match {|&sort=$false &type=prefix @motive|
|
||||||
|
-s &sort=$sort &type=$type $@motive
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match-extensions {|&sort=$false &type=deep-prefix motive @extensions|
|
||||||
|
var result = [&]
|
||||||
|
-s &type=$type $motive | peach {|f|
|
||||||
|
if (list:contains {|e| str:has-suffix $f .$e } $extensions) {
|
||||||
|
set result[$f] = $nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
-r $sort $result
|
||||||
|
}
|
|
@ -0,0 +1,198 @@
|
||||||
|
use math
|
||||||
|
use re
|
||||||
|
use str
|
||||||
|
use ./common
|
||||||
|
|
||||||
|
fn chars {|v|
|
||||||
|
str:split '' $v
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len {|v|
|
||||||
|
chars $v | count
|
||||||
|
}
|
||||||
|
|
||||||
|
fn string {|v|
|
||||||
|
var k = (kind-of $v)
|
||||||
|
if (eq $k string) {
|
||||||
|
put $v
|
||||||
|
} elif (eq $k number) {
|
||||||
|
to-string $v
|
||||||
|
} elif (eq $k bool) {
|
||||||
|
common:cond $v 'X' ''
|
||||||
|
} elif (eq $k list) {
|
||||||
|
each $string~ $v | str:join ''
|
||||||
|
} elif (eq $v $nil) {
|
||||||
|
put ''
|
||||||
|
} else {
|
||||||
|
to-string $v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn int {|v|
|
||||||
|
var k = (kind-of $v)
|
||||||
|
if (eq $k 'string') {
|
||||||
|
try {
|
||||||
|
var n = (math:trunc $v)
|
||||||
|
var s @_ = (str:split '.' (to-string $n))
|
||||||
|
put $s
|
||||||
|
} except e {
|
||||||
|
fail (printf '%s n’est pas un nombre' $v)
|
||||||
|
}
|
||||||
|
} elif (eq $k 'number') {
|
||||||
|
int (to-string $v)
|
||||||
|
} elif (eq $k 'bool') {
|
||||||
|
common:cond $v 1 0
|
||||||
|
} else {
|
||||||
|
put 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn repeat {|n s|
|
||||||
|
use builtin
|
||||||
|
builtin:repeat $n $s | str:join ''
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blank {|n|
|
||||||
|
repeat $n ' '
|
||||||
|
}
|
||||||
|
|
||||||
|
fn left {|str size|
|
||||||
|
var l = (len $str)
|
||||||
|
if (< $l $size) {
|
||||||
|
string [ $str (blank (- $size $l)) ]
|
||||||
|
} elif (== $l $size) {
|
||||||
|
put $str
|
||||||
|
} else {
|
||||||
|
string [ (chars $str) ][..$size]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn right {|str size|
|
||||||
|
var l = (len $str)
|
||||||
|
if (< $l $size) {
|
||||||
|
string [ (blank (- $size $l)) $str ]
|
||||||
|
} elif (== $l $size) {
|
||||||
|
put $str
|
||||||
|
} else {
|
||||||
|
string [ (chars $str) ][(- $l $size)..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn center {|str size|
|
||||||
|
var l = (len $str)
|
||||||
|
if (< $l $size) {
|
||||||
|
var d = (- $size $l)
|
||||||
|
var b = (math:trunc (/ $d 2))
|
||||||
|
var e = (- $d $b)
|
||||||
|
string [ (blank $b) $str (blank $e) ]
|
||||||
|
} elif (== $l $size) {
|
||||||
|
put $str
|
||||||
|
} else {
|
||||||
|
var d = (- $l $size)
|
||||||
|
var b = (math:trunc (/ $d 2))
|
||||||
|
var e = (+ $b $size)
|
||||||
|
string [ (chars $str) ][$b..$e]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var -align = [
|
||||||
|
¢er=$center~
|
||||||
|
&right=$right~
|
||||||
|
&left=$left~
|
||||||
|
]
|
||||||
|
|
||||||
|
fn column {|&align=left name @label|
|
||||||
|
var c = [
|
||||||
|
&name=$name
|
||||||
|
&align=$-align[$align]
|
||||||
|
&size=0
|
||||||
|
&label=''
|
||||||
|
]
|
||||||
|
if (> (count $label) 0) {
|
||||||
|
set c[label] = $label[0]
|
||||||
|
set c[size] = (count $label[0])
|
||||||
|
}
|
||||||
|
put $c
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update-props {|props data|
|
||||||
|
each {|d|
|
||||||
|
set @props = (each {|c|
|
||||||
|
var n = $c[name]
|
||||||
|
if (has-key $d $n) {
|
||||||
|
var v = (string $d[$n])
|
||||||
|
var l = (count $v)
|
||||||
|
if (< $c[size] $l) {
|
||||||
|
set c[size] = $l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
put $c
|
||||||
|
} $props)
|
||||||
|
} $data
|
||||||
|
put $props
|
||||||
|
}
|
||||||
|
|
||||||
|
fn line-header {|&sep=' ' props|
|
||||||
|
var @data = (each {|c|
|
||||||
|
$c[align] $c[label] $c[size]
|
||||||
|
} $props)
|
||||||
|
str:join $sep $data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn line {|&sep=' ' props line|
|
||||||
|
var @data = (each {|c|
|
||||||
|
var n v = $c[name] ''
|
||||||
|
if (has-key $line $n) {
|
||||||
|
set v = (string $line[$n])
|
||||||
|
}
|
||||||
|
$c[align] $v $c[size]
|
||||||
|
} $props)
|
||||||
|
str:join $sep $data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list {|&with-header=$true &csep=' ' &hsep='-' &recompute=$true props data|
|
||||||
|
if $recompute {
|
||||||
|
set props = (update-props $props $data)
|
||||||
|
}
|
||||||
|
if $with-header {
|
||||||
|
echo (line-header &sep=$csep $props)
|
||||||
|
if (bool $hsep) {
|
||||||
|
var s = (* (- (count $props) 1) (count $csep))
|
||||||
|
each {|c|
|
||||||
|
set s = (+ $s $c[size])
|
||||||
|
} $props
|
||||||
|
echo (repeat (math:trunc (/ $s (count $hsep))) $hsep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
each {|d|
|
||||||
|
echo (line &sep=$csep $props $d)
|
||||||
|
} $data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size {|size|
|
||||||
|
var u = 0
|
||||||
|
var m = [
|
||||||
|
&10=Kio
|
||||||
|
&20=Mio
|
||||||
|
&30=Gio
|
||||||
|
&40=Tio
|
||||||
|
&50=Pio
|
||||||
|
&60=Eio
|
||||||
|
&70=Zio
|
||||||
|
&80=Yio
|
||||||
|
]
|
||||||
|
while (< $u 80) {
|
||||||
|
var p = (math:pow 2 (+ $u 10))
|
||||||
|
if (< $size $p) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
set u = (to-string (+ $u 10))
|
||||||
|
}
|
||||||
|
if (== $u 0) {
|
||||||
|
put $size
|
||||||
|
} else {
|
||||||
|
var p = (math:pow 2 $u)
|
||||||
|
var e = (/ $size $p)
|
||||||
|
printf '%.1f%s' $e $m[$u]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
use re
|
||||||
|
use str
|
||||||
|
use ./common
|
||||||
|
use ./list
|
||||||
|
use ./num
|
||||||
|
|
||||||
|
fn is-ipv4 {|arg|
|
||||||
|
common:cexec ^
|
||||||
|
(re:match '^([0-9]{1,3}\.){3}[0-9]{1,3}$' $arg) ^
|
||||||
|
{ not (str:split '.' $arg | list:contains {|p| > $p 255 }) } ^
|
||||||
|
$false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is-ipv6 {|arg|
|
||||||
|
var p = '[0-9a-fA-F]{1,4}'
|
||||||
|
var g1 g2 = (printf '(%s:)' $p) (printf '(:%s)' $p)
|
||||||
|
var cases = [
|
||||||
|
(printf '%s{7,7}%s' $g1 $p)
|
||||||
|
(printf '%s{1,7}:' $g1)
|
||||||
|
(printf '%s{1,6}:%s' $g1 $p)
|
||||||
|
(printf '%s{1,5}%s{1,2}' $g1 $g2)
|
||||||
|
(printf '%s{1,4}%s{1,3}' $g1 $g2)
|
||||||
|
(printf '%s{1,3}%s{1,4}' $g1 $g2)
|
||||||
|
(printf '%s{1,2}%s{1,5}' $g1 $g2)
|
||||||
|
(printf '%s:%s{1,6}' $p $g2)
|
||||||
|
(printf ':%s{1,7}' $g2)
|
||||||
|
'::'
|
||||||
|
]
|
||||||
|
var r = (printf '^(%s)$' (str:join '|' $cases))
|
||||||
|
re:match $r $arg
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is-ip {|arg|
|
||||||
|
or (is-ipv4 $arg) (is-ipv6 $arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -l6 {|p|
|
||||||
|
set p = (str:to-lower $p)
|
||||||
|
var c = (- 4 (count $p))
|
||||||
|
put (repeat $c '0') $p | str:join ''
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -m6 {|p|
|
||||||
|
while (and (> (count $p) 1) (eq $p[0] 0)) {
|
||||||
|
set p = $p[1..]
|
||||||
|
}
|
||||||
|
put $p
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -max0 {|parts|
|
||||||
|
var idx s = -1 1
|
||||||
|
var ci cs f = -1 0 $false
|
||||||
|
list:foreach {|i p|
|
||||||
|
if (eq $p 0) {
|
||||||
|
if $f {
|
||||||
|
set cs = (num:++ $cs)
|
||||||
|
} else {
|
||||||
|
set ci cs f = $i 1 $true
|
||||||
|
}
|
||||||
|
} elif $f {
|
||||||
|
set f = $false
|
||||||
|
if (> $cs $s) {
|
||||||
|
set idx s = $ci $cs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} $parts
|
||||||
|
if (and $f (> $cs $s)) {
|
||||||
|
set idx s = $ci $cs
|
||||||
|
}
|
||||||
|
put $idx $s
|
||||||
|
}
|
||||||
|
|
||||||
|
fn long6 {|ip|
|
||||||
|
if (not (is-ipv6 $ip)) {
|
||||||
|
fail 'Not an IPv6'
|
||||||
|
}
|
||||||
|
if (eq $ip '::') {
|
||||||
|
repeat 8 '0000' | str:join ':'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var c = (- 7 (str:count $ip ':'))
|
||||||
|
if (> $c 0) {
|
||||||
|
var i = (str:index $ip '::')
|
||||||
|
var z = (repeat $c ':' | str:join '')
|
||||||
|
set ip = (str:join '' [$ip[..$i] $z $ip[$i..]])
|
||||||
|
}
|
||||||
|
str:split ':' $ip | each $-l6~ | str:join ':'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn middle6 {|ip|
|
||||||
|
str:split ':' (long6 $ip) | each $-m6~ | str:join ':'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn short6 {|ip|
|
||||||
|
var parts = [(str:split ':' (middle6 $ip))]
|
||||||
|
var i s = (-max0 $parts)
|
||||||
|
if (>= $i 0) {
|
||||||
|
var left right = $parts[..$i] $parts[(+ $i $s)..]
|
||||||
|
if (== (count $left) 0) {
|
||||||
|
set left = ['']
|
||||||
|
}
|
||||||
|
if (== (count $right) 0) {
|
||||||
|
set right = ['']
|
||||||
|
}
|
||||||
|
set @parts = $@left '' $@right
|
||||||
|
}
|
||||||
|
str:join ':' $parts
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -cmp {|e1 e2|
|
||||||
|
var c = 0
|
||||||
|
list:foreach {|i p1|
|
||||||
|
var p2 = $e2[$i]
|
||||||
|
set c = (compare $p1 $p2)
|
||||||
|
if (!= $c 0) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} $e1
|
||||||
|
put $c
|
||||||
|
}
|
||||||
|
|
||||||
|
fn comp4 {|ip1 ip2|
|
||||||
|
if (or (not (is-ipv4 $ip1)) (not (is-ipv4 $ip2))) {
|
||||||
|
fail (printf 'Not an IPv4: %s → %s' $ip1 $ip2)
|
||||||
|
}
|
||||||
|
-cmp [(str:split . $ip1)] [(str:split . $ip2)]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn comp6 {|ip1 ip2|
|
||||||
|
if (or (not (is-ipv6 $ip1)) (not (is-ipv6 $ip2))) {
|
||||||
|
fail (printf 'Not an IPv6: %s → %s' $ip1 $ip2)
|
||||||
|
}
|
||||||
|
-cmp [(str:split : (middle6 $ip1))] [(str:split : (middle6 $ip2))]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn comp {|ip1 ip2|
|
||||||
|
if (is-ipv4 $ip1) {
|
||||||
|
if (is-ipv4 $ip2) {
|
||||||
|
comp4 $ip1 $ip2
|
||||||
|
} else {
|
||||||
|
put -1
|
||||||
|
}
|
||||||
|
} elif (is-ipv6 $ip1) {
|
||||||
|
if (is-ipv4 $ip2) {
|
||||||
|
put 1
|
||||||
|
} elif (is-ipv6 $ip2) {
|
||||||
|
comp6 $ip1 $ip2
|
||||||
|
} else {
|
||||||
|
put -1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fail (printf 'Not an IP: %s → %s' $ip1 $ip2)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,178 @@
|
||||||
|
use ./common
|
||||||
|
use ./num
|
||||||
|
|
||||||
|
var -l~ = $common:to-list~
|
||||||
|
var -c~ = $common:cexec~
|
||||||
|
var '++~' = $'num:++~'
|
||||||
|
var is-neg~ = $num:is-neg~
|
||||||
|
|
||||||
|
|
||||||
|
fn indexes {|&from=0 &step=1 @argv|
|
||||||
|
var c = (count (-l $@argv))
|
||||||
|
var from = (-c (is-neg $from) (+ $from $c) $from)
|
||||||
|
var to = (-c (is-neg $step) -1 $c)
|
||||||
|
if (and (>= $from 0) (< $from $c)) {
|
||||||
|
range &step=$step $from $to
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn loop {|&from=0 &step=1 @argv|
|
||||||
|
var l = (-l $@argv)
|
||||||
|
indexes &from=$from &step=$step $l | each {|i|
|
||||||
|
put [ $i $l[$i] ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foreach {|&from=0 &step=1 &end=$false cb @argv|
|
||||||
|
if (not $end) {
|
||||||
|
loop &from=$from &step=$step $@argv | each {|e| $cb $@e}
|
||||||
|
} else {
|
||||||
|
loop &from=$from &step=$step $@argv | each {|e|
|
||||||
|
if ($end $@e) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
$cb $@e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pforeach {|&from=0 &step=1 cb @argv|
|
||||||
|
loop &from=$from &step=$step $@argv | peach {|e| $cb $@e}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reach {|cb @argv|
|
||||||
|
foreach &from=-1 &step=-1 {|_ e| $cb $e} $@argv
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reverse {|@argv|
|
||||||
|
reach $put~ $@argv
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is-empty {|@argv|
|
||||||
|
num:is-zero (count (-l $@argv))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is-not-empty {|@argv|
|
||||||
|
not (is-empty $@argv)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filter {|cb @argv|
|
||||||
|
each {|e|
|
||||||
|
-c ($cb $e) $e $nop~
|
||||||
|
} (-l $@argv)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filter-not {|cb @argv|
|
||||||
|
filter {|v| not ($cb $v)} $@argv
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contains {|cb @argv|
|
||||||
|
var cb2~ = (common:cond (eq (kind-of $cb) fn) $cb {|e| eq $cb $e})
|
||||||
|
each {|e|
|
||||||
|
if (cb2 $e) {
|
||||||
|
put $true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} (-l $@argv)
|
||||||
|
put $false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contains-not {|cb @argv|
|
||||||
|
not (contains $cb $@argv)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search {|cb @argv|
|
||||||
|
foreach {|i e|
|
||||||
|
-c ($cb $i $e) [$i $e] $nop~
|
||||||
|
} $@argv
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search-not {|cb @argv|
|
||||||
|
search {|i e| not ($cb $i $e) } $@argv
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exists {|cb @argv|
|
||||||
|
var r = $false
|
||||||
|
foreach {|i e|
|
||||||
|
if ($cb $i $e) {
|
||||||
|
set r = $true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} $@argv
|
||||||
|
put $r
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exists-not {|cb @argv|
|
||||||
|
not (exists $cb $@argv)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search-first {|&from=$nil &reverse=$false cb @argv|
|
||||||
|
var step = (-c $reverse -1 1)
|
||||||
|
if (not $from) {
|
||||||
|
set from = (-c $reverse -1 0)
|
||||||
|
}
|
||||||
|
foreach &from=$from &step=$step {|i e|
|
||||||
|
if ($cb $i $e) {
|
||||||
|
put [$i $e]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} $@argv
|
||||||
|
}
|
||||||
|
|
||||||
|
fn first {|&from=$nil &reverse=$false cb @argv|
|
||||||
|
search-first &from=$from &reverse=$reverse {|_ e| $cb $e} $@argv | each {|e|
|
||||||
|
put $e[1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reduce {|acc cb @argv|
|
||||||
|
each {|e|
|
||||||
|
set acc = ($cb $acc $e)
|
||||||
|
} (-l $@argv)
|
||||||
|
put $acc
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove-duplicate {|@argv|
|
||||||
|
var done = [&]
|
||||||
|
each {|e|
|
||||||
|
if (not (has-key $done $e)) {
|
||||||
|
set done[$e] = $nil
|
||||||
|
put $e
|
||||||
|
}
|
||||||
|
} (-l $@argv)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn swap {|i j @argv|
|
||||||
|
var l = (-l $@argv)
|
||||||
|
var c = (count $l)
|
||||||
|
if (< $i 0) {
|
||||||
|
set i = (+ $i $c)
|
||||||
|
}
|
||||||
|
if (< $j 0) {
|
||||||
|
set j = (+ $j $c)
|
||||||
|
}
|
||||||
|
if (or (is-neg $i) (is-neg $j) (>= $i $c) (>= $j $c)) {
|
||||||
|
fail 'index out of range'
|
||||||
|
}
|
||||||
|
if (== $i $j) {
|
||||||
|
all $l
|
||||||
|
} else {
|
||||||
|
if (> $i $j) {
|
||||||
|
set i j = $j $i
|
||||||
|
}
|
||||||
|
take $i $l
|
||||||
|
put $l[$j]
|
||||||
|
all $l[(++ $i)..$j]
|
||||||
|
put $l[$i]
|
||||||
|
drop (++ $j) $l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn less {|cb|
|
||||||
|
put {|a b| < ($cb $a $b) 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sort {|cb @argv|
|
||||||
|
order &less-than=(less $cb) (-l $@argv)
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
use ./common
|
||||||
|
use ./list
|
||||||
|
use ./num
|
||||||
|
|
||||||
|
fn is-empty {|m|
|
||||||
|
num:is-zero (count $m)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn values {|m|
|
||||||
|
keys $m | each {|k| put $m[$k]}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pvalues {|m|
|
||||||
|
keys $m | peach {|k| put $m[$k]}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value-of {|m k &default=$nil|
|
||||||
|
common:cexec (has-key $m $k) { put $m[$k] } { put $default }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unzip {|m|
|
||||||
|
var keys values = [] []
|
||||||
|
keys $m | each {|k|
|
||||||
|
set @keys = $@keys $k
|
||||||
|
set @values = $@values $m[$k]
|
||||||
|
}
|
||||||
|
put $keys $values
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zip {|keys values|
|
||||||
|
var ck cv = (count $keys) (count $values)
|
||||||
|
var c = (num:min [$ck $cv])
|
||||||
|
var m = [&]
|
||||||
|
range $c | peach {|i|
|
||||||
|
put [&k=$keys[$i] &v=$values[$i]]
|
||||||
|
} | each {|e|
|
||||||
|
set m[$e[k]] = $e[v]
|
||||||
|
}
|
||||||
|
put $m
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to-map {|@argv|
|
||||||
|
var l = (list:-l $@argv)
|
||||||
|
zip [(list:indexes $l)] $l
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to-set {|@argv|
|
||||||
|
var m = [&]
|
||||||
|
each {|k|
|
||||||
|
set m[$k] = $nil
|
||||||
|
} (list:-l $@argv)
|
||||||
|
put $m
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mult-dissoc {|m @argv|
|
||||||
|
each {|k|
|
||||||
|
set m = (dissoc $m $k)
|
||||||
|
} $argv
|
||||||
|
put $m
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mult-assoc {|&replace=$true m @argv|
|
||||||
|
each {|e|
|
||||||
|
var k v = $@e
|
||||||
|
if (or $replace (not (has-key $m $k))) {
|
||||||
|
set m = (assoc $m $k $v)
|
||||||
|
}
|
||||||
|
} $argv
|
||||||
|
put $m
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add {|m k @values|
|
||||||
|
var values = (list:-l $values)
|
||||||
|
set m[$k] = (common:cexec (has-key $m $k) { put [(all $m[$k]) $@values ] } $values)
|
||||||
|
put $m
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foreach {|cb @m|
|
||||||
|
set m = (common:cexec (list:is-empty $m) $one~ { put $m[0] })
|
||||||
|
keys $m | each {|k| put [$k $m[$k]]} | each {|e| $cb $@e}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
fn ++ {|n|
|
||||||
|
+ $n 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -- {|n|
|
||||||
|
- $n 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn neg {|n|
|
||||||
|
* $n -1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is-zero {|n|
|
||||||
|
== $n 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is-neg {|n|
|
||||||
|
< $n 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is-one {|n|
|
||||||
|
== $n 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -minmax {|cb @numbers|
|
||||||
|
use ./common
|
||||||
|
var l = (common:to-list $@numbers)
|
||||||
|
if (is-zero (count $l)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var m = $l[0]
|
||||||
|
all $l[1..] | each {|n|
|
||||||
|
if ($cb $n $m) {
|
||||||
|
set m = $n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
put $m
|
||||||
|
}
|
||||||
|
|
||||||
|
fn min {|@numbers|
|
||||||
|
-minmax $'<~' $@numbers
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max {|@numbers|
|
||||||
|
-minmax $'>~' $@numbers
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
use re
|
||||||
|
use str
|
||||||
|
use ./common
|
||||||
|
use ./list
|
||||||
|
use ./map
|
||||||
|
use ./num
|
||||||
|
|
||||||
|
fn is-aggregate {|option|
|
||||||
|
re:match '^\-\w{2,}$' $option
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is-short {|option|
|
||||||
|
re:match '^\-\w$' $option
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is-long {|option|
|
||||||
|
re:match '^\-\-\w+(=.*)?$' $option
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is-option {|option|
|
||||||
|
or (is-short $option) (is-long $option) (is-aggregate $option)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn split {|option|
|
||||||
|
if (is-aggregate $option) {
|
||||||
|
each {|e| put -$e} $option[1..]
|
||||||
|
} elif (is-long $option) {
|
||||||
|
var i = (str:index $option '=')
|
||||||
|
if (num:is-neg $i) {
|
||||||
|
put $option
|
||||||
|
} else {
|
||||||
|
put $option[..$i] $option[(num:++ $i)..]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
put $option
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -j {|options|
|
||||||
|
var o = (each {|o| put $o[1..] } $options | str:join '')
|
||||||
|
if (not-eq $o '') {
|
||||||
|
put -$o
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn join {|@options|
|
||||||
|
set options = (common:to-list $@options)
|
||||||
|
var cb = {|_ o| or (is-short $o) (is-aggregate $o) }
|
||||||
|
var i0 = 0
|
||||||
|
list:search-not $cb $options | each {|e|
|
||||||
|
var i1 v = $@e
|
||||||
|
-j $options[$i0..$i1]
|
||||||
|
put $v
|
||||||
|
set i0 = (num:++ $i1)
|
||||||
|
}
|
||||||
|
-j $options[$i0..]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expand {|@argv|
|
||||||
|
each $split~ (common:to-list $@argv)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map {|@argv|
|
||||||
|
set @argv = (expand $@argv)
|
||||||
|
var result i c = [&] 0 (count $argv)
|
||||||
|
var last = (num:-- $c)
|
||||||
|
while (< $i $c) {
|
||||||
|
var e = $argv[$i]
|
||||||
|
if (is-option $e) {
|
||||||
|
var k v = $e []
|
||||||
|
if (< $i $last) {
|
||||||
|
var j = (num:++ $i)
|
||||||
|
set e = $argv[$j]
|
||||||
|
if (not (is-option $e)) {
|
||||||
|
set i @v = $j $@v $e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set result = (map:add $result $k $v)
|
||||||
|
} else {
|
||||||
|
set result = (map:add $result '' [$e])
|
||||||
|
}
|
||||||
|
set i = (num:++ $i)
|
||||||
|
}
|
||||||
|
put $result
|
||||||
|
}
|
|
@ -0,0 +1,420 @@
|
||||||
|
use path
|
||||||
|
use re
|
||||||
|
use str
|
||||||
|
use ./common
|
||||||
|
use ./map
|
||||||
|
|
||||||
|
fn is-pdf {|file|
|
||||||
|
eq (path:ext $file) '.pdf'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exist {|file|
|
||||||
|
or (path:is-dir &follow-symlink=$true $file) (path:is-regular &follow-symlink=$true $file)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn not-exist {|file|
|
||||||
|
not (exist $file)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is-pdf-exist {|file|
|
||||||
|
and (is-pdf $file) (exist $file)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is-number {|v|
|
||||||
|
re:match '^\d+$' (to-string $v)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is-page-selection {|v|
|
||||||
|
re:match '^(r?\d+|z)(-(r?\d+|z))?(,(r?\d+|z)(-(r?\d+|z))?)*(:(even|odd))?$' (to-string $v)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is-rotate-selection {|v|
|
||||||
|
re:match '^(\+|-)?\d+(:(r?\d+|z)(-(r?\d+|z))?(,(r?\d+|z)(-(r?\d+|z))?)*(:(even|odd))?)?$' (to-string $v)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is-selection {|v|
|
||||||
|
or (is-page-selection $v) (is-rotate-selection $v)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is-object {|v|
|
||||||
|
re:match '^ \d+\ 0\ R$' $v
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version {|in|
|
||||||
|
var version = (head -n 1 $in)
|
||||||
|
set version @_ = (str:split "\r" $version)
|
||||||
|
str:trim-prefix $version '%PDF-'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn json {|in|
|
||||||
|
qpdf $in --json | from-json
|
||||||
|
}
|
||||||
|
|
||||||
|
fn form {|in|
|
||||||
|
var json = (json $in)
|
||||||
|
put $json[acroform]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encryption {|in|
|
||||||
|
var json = (json $in)
|
||||||
|
put $json[encrypt]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn objects {|in|
|
||||||
|
var json = (json $in)
|
||||||
|
put $json[objects]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -format {|dict o|
|
||||||
|
var t = (kind-of $o)
|
||||||
|
if (eq $t string) {
|
||||||
|
if (has-key $dict $o) {
|
||||||
|
set o = $dict[$o]
|
||||||
|
}
|
||||||
|
} elif (eq $t list) {
|
||||||
|
set @o = (all $o | each {|e|
|
||||||
|
common:cexec (has-key $dict $e) { put $dict[$e] } $e
|
||||||
|
})
|
||||||
|
} elif (eq $t map) {
|
||||||
|
map:foreach {|k v|
|
||||||
|
set o[$k] = (-format $dict $v)
|
||||||
|
} $o
|
||||||
|
}
|
||||||
|
put $o
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn -deep {|&dict=$nil objects @keys|
|
||||||
|
if (== (count $keys) 0) {
|
||||||
|
common:cexec (not-eq $dict $nil) { -format $dict $objects } $objects
|
||||||
|
put $true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (not-eq $dict $nil) {
|
||||||
|
set objects = (-format $dict $objects)
|
||||||
|
}
|
||||||
|
var id @next = $@keys
|
||||||
|
var t = (kind-of $objects)
|
||||||
|
if (eq $t map) {
|
||||||
|
if (has-key $objects $id) {
|
||||||
|
-deep &dict=$dict $objects[$id] $@next
|
||||||
|
}
|
||||||
|
} elif (eq $t list) {
|
||||||
|
if (and (is-number $id) (< $id (count $objects))) {
|
||||||
|
-deep &dict=$dict $objects[$id] $@next
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
put $nil $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -object {|&extend=$false objects id|
|
||||||
|
var dict = (common:cond $extend $objects $nil)
|
||||||
|
var o _ = (-deep &dict=$dict $objects $id)
|
||||||
|
put $o
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deep {|&extend=$false in @keys|
|
||||||
|
var objects = (objects $in)
|
||||||
|
var dict = (common:cond $extend $objects $nil)
|
||||||
|
-deep &dict=$dict $dict $@keys
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contains {|in @keys|
|
||||||
|
var _ ok = (deep $in $@keys)
|
||||||
|
put $ok
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value {|&extend=$false in @keys|
|
||||||
|
var v _ = (deep &extend=$extend $in $@keys)
|
||||||
|
put $v
|
||||||
|
}
|
||||||
|
|
||||||
|
fn object {|&extend=$false in key|
|
||||||
|
-object &extend=$extend (objects $in) $key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -filter {|&extend=$false objects cond|
|
||||||
|
var out = [&]
|
||||||
|
map:foreach {|k o|
|
||||||
|
if ($cond $o) {
|
||||||
|
set out[$k] = $o
|
||||||
|
}
|
||||||
|
} $objects
|
||||||
|
put $out
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filter {|&extend=$false in cond|
|
||||||
|
-filter &extend=$extend (objects $in) $cond
|
||||||
|
}
|
||||||
|
|
||||||
|
fn font-filter {|o|
|
||||||
|
and ^
|
||||||
|
(eq (kind-of $o) map) ^
|
||||||
|
(has-key $o /Type) ^
|
||||||
|
(eq $o[/Type] /Font)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fonts {|in|
|
||||||
|
var dict = (objects $in)
|
||||||
|
var fonts = (-filter $dict $font-filter~)
|
||||||
|
put $fonts | map:foreach {|id f|
|
||||||
|
map:foreach {|k v|
|
||||||
|
if (has-key $dict $v) {
|
||||||
|
set f[$k] = $dict[$v]
|
||||||
|
}
|
||||||
|
} $f
|
||||||
|
var fd = $f[/FontDescriptor]
|
||||||
|
map:foreach {|k v|
|
||||||
|
if (and (not-eq $k /FontFile2) (has-key $dict $v)) {
|
||||||
|
set fd[$k] = $dict[$v]
|
||||||
|
}
|
||||||
|
} $fd
|
||||||
|
set f[/FontDescriptor] = $fd
|
||||||
|
set f[id] = $id
|
||||||
|
put $f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn image-filter {|o|
|
||||||
|
and ^
|
||||||
|
(eq (kind-of $o) map) ^
|
||||||
|
(has-key $o /Subtype) ^
|
||||||
|
(eq $o[/Subtype] /Image)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn images {|in|
|
||||||
|
var json = (json $in)
|
||||||
|
var dict = $json[objects]
|
||||||
|
all $json[pages] | each {|p|
|
||||||
|
var n = $p[pageposfrom1]
|
||||||
|
all $p[images] | each {|i|
|
||||||
|
var id = $i[object]
|
||||||
|
var img = (-object $dict $id)
|
||||||
|
map:foreach {|k v|
|
||||||
|
if (has-key $dict $v) {
|
||||||
|
set img[$k] = $dict[$v]
|
||||||
|
}
|
||||||
|
} $img
|
||||||
|
if (has-key $img /ColorSpace) {
|
||||||
|
var @cs = (all $img[/ColorSpace] | each {|v|
|
||||||
|
if (has-key $dict $v) {
|
||||||
|
put $dict[$v]
|
||||||
|
} else {
|
||||||
|
put $v
|
||||||
|
}
|
||||||
|
})
|
||||||
|
set img[/ColorSpace] = $cs
|
||||||
|
}
|
||||||
|
if (has-key $img /DecodeParms) {
|
||||||
|
var dp = $img[/DecodeParms]
|
||||||
|
map:foreach {|k v|
|
||||||
|
if (has-key $dict $v) {
|
||||||
|
set dp[$k] = $dict[$v]
|
||||||
|
}
|
||||||
|
} $dp
|
||||||
|
set img[/DecodeParms] = $dp
|
||||||
|
}
|
||||||
|
set img[id] = $id
|
||||||
|
set img[page] = $n
|
||||||
|
set img[name] = $i[name]
|
||||||
|
put $img
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trailer {|&extend=$false in|
|
||||||
|
object &extend=$extend $in 'trailer'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pages {|in|
|
||||||
|
var json = (json $in)
|
||||||
|
put $json[pages]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page {|in nb|
|
||||||
|
put (pages $in)[(- $nb 1)]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nb-pages {|in|
|
||||||
|
qpdf --show-npages $in
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attachments {|in|
|
||||||
|
var data = []
|
||||||
|
var json = (json $in)
|
||||||
|
var attachments = $json[attachments]
|
||||||
|
if (> (count $attachments) 0) {
|
||||||
|
set @data = (qpdf --list-attachments $in | eawk {|_ f @_|
|
||||||
|
put $f
|
||||||
|
})
|
||||||
|
}
|
||||||
|
put $data
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse-selection {|@selection|
|
||||||
|
var out = []
|
||||||
|
var in = $nil
|
||||||
|
each {|e|
|
||||||
|
if (is-pdf $e) {
|
||||||
|
if (not-exist $e) {
|
||||||
|
fail (printf '%s: le fichier n’existe pas' $e)
|
||||||
|
}
|
||||||
|
if (not-eq $in $nil) {
|
||||||
|
set @out = $@out $in
|
||||||
|
}
|
||||||
|
set in = [
|
||||||
|
&file=$e
|
||||||
|
&rotate=$nil
|
||||||
|
&selections=[]
|
||||||
|
]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (eq $in $nil) {
|
||||||
|
fail (printf '%s: pas de fichier avant la sélection' $e)
|
||||||
|
}
|
||||||
|
var r rc = $in[rotate] $nil
|
||||||
|
if (is-page-selection $e) {
|
||||||
|
set rc = $false
|
||||||
|
} elif (is-rotate-selection $e) {
|
||||||
|
set rc = $true
|
||||||
|
} else {
|
||||||
|
fail (printf '%s: paramètre invalide' $e)
|
||||||
|
}
|
||||||
|
if (not-eq $r $rc) {
|
||||||
|
if (not-eq $r $nil) {
|
||||||
|
set @out = $@out $in
|
||||||
|
set in[selections] = []
|
||||||
|
}
|
||||||
|
set in[rotate] = $rc
|
||||||
|
}
|
||||||
|
set in[selections] = [ (all $in[selections]) $e ]
|
||||||
|
} $selection
|
||||||
|
if (not-eq $in $nil) {
|
||||||
|
set @out = $@out $in
|
||||||
|
}
|
||||||
|
put $out
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -t {
|
||||||
|
mktemp -q /tmp/qpdf_XXXXXXXXXX.pdf
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rotate {|&empty=$false &out=$nil &keep=$false in @rotate|
|
||||||
|
var @args = $in (common:cond (eq $out $nil) --replace-input $out)
|
||||||
|
if $empty {
|
||||||
|
set @args = $@args --empty
|
||||||
|
}
|
||||||
|
if $keep {
|
||||||
|
set @rotate = (each {|r| put --rotate=$r } $rotate)
|
||||||
|
qpdf $@args $@rotate
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var tmp = []
|
||||||
|
try {
|
||||||
|
var @tmp = (each {|r|
|
||||||
|
var t r @s = (-t) (str:split ':' $r)
|
||||||
|
set s = (str:join ':' $s)
|
||||||
|
if (eq $s '') {
|
||||||
|
qpdf $in $t --rotate=$r
|
||||||
|
} else {
|
||||||
|
qpdf $in $t --pages $in $s --
|
||||||
|
qpdf $t --replace-input --rotate=$r
|
||||||
|
}
|
||||||
|
put $t
|
||||||
|
} $rotate)
|
||||||
|
qpdf $@args --pages $@tmp --
|
||||||
|
} finally {
|
||||||
|
rm -f $@tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -catarg {|selection|
|
||||||
|
var f r s = $selection[file] $selection[rotate] $selection[selections]
|
||||||
|
var out tmp = [] []
|
||||||
|
if $r {
|
||||||
|
var t = (-t)
|
||||||
|
set @tmp = $t
|
||||||
|
set @out = $@out $t
|
||||||
|
rotate &out=$t $f $@s
|
||||||
|
} else {
|
||||||
|
set @out = $@out $f
|
||||||
|
if (> (count $s) 0) {
|
||||||
|
set @out = $@out (str:join ',' $s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
put $out $tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cat {|&empty=$false &collate=$nil &out=$nil @selection|
|
||||||
|
var inputs = (parse-selection $@selection)
|
||||||
|
var pages tmp = [] []
|
||||||
|
each {|in|
|
||||||
|
var a t = (-catarg $in)
|
||||||
|
set @pages = $@pages $@a
|
||||||
|
set @tmp = $@tmp $@t
|
||||||
|
} $inputs
|
||||||
|
try {
|
||||||
|
var in = $pages[0]
|
||||||
|
var @args = $in (common:cond (eq $out $nil) --replace-input $out)
|
||||||
|
if $empty {
|
||||||
|
set @args = $@args --empty
|
||||||
|
}
|
||||||
|
if $collate {
|
||||||
|
var c = --collate(common:cexec (is-number $collate) { put =$collate } '')
|
||||||
|
set @args = $@args $c
|
||||||
|
}
|
||||||
|
qpdf $@args --pages $@pages --
|
||||||
|
} finally {
|
||||||
|
each {|t|
|
||||||
|
rm -f $t
|
||||||
|
} $tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decrypt {|&out=$nil in @passwd|
|
||||||
|
var @args = $in (common:cond (eq $out $nil) --replace-input $out) --decrypt
|
||||||
|
if (> (count $passwd) 0) {
|
||||||
|
set @args = $@args $passwd[0]
|
||||||
|
}
|
||||||
|
qpdf $@args
|
||||||
|
}
|
||||||
|
|
||||||
|
fn -l0 {|n size|
|
||||||
|
set n = (to-string $n)
|
||||||
|
var l = (- $size (count $n))
|
||||||
|
str:join '' [ (repeat $l 0) $n ]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn split {|&empty=$false &size=1 in out|
|
||||||
|
if (not-exist $out) {
|
||||||
|
mkdir $out
|
||||||
|
}
|
||||||
|
var @args = (common:cexec $empty --empty $nop~)
|
||||||
|
qpdf $@args --split-pages=$size $in $out'/%d.pdf'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uncat {|&empty=$false in out @selection|
|
||||||
|
if (not-exist $out) {
|
||||||
|
mkdir $out
|
||||||
|
}
|
||||||
|
var i = 1
|
||||||
|
var n = (count $selection)
|
||||||
|
set n = (count (to-string $n))
|
||||||
|
each {|s|
|
||||||
|
cat &empty=$empty &out=$out'/'(-l0 $i $n)'.pdf' $in $s
|
||||||
|
set i = (+ $i 1)
|
||||||
|
} $selection
|
||||||
|
}
|
||||||
|
|
||||||
|
fn raw-stream {|in out id|
|
||||||
|
qpdf $in --show-object=$id --raw-stream-data > $out
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filtered-stream {|in out id|
|
||||||
|
qpdf $in --show-object=$id --filtered-stream-data --normalize-content=n --stream-data=uncompress --decode-level=all > $out
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attachment {|in out id|
|
||||||
|
qpdf $in --show-attachment=$id > $out
|
||||||
|
}
|
Loading…
Reference in New Issue