diff --git a/helpers/_defer.function.fish b/helpers/_defer.function.fish index 983181555838f4d4c802cb0b8cda694fe599999c..1eab106e7a65a23dc02ffa8bfd452a871fe12b02 100644 --- a/helpers/_defer.function.fish +++ b/helpers/_defer.function.fish @@ -1,26 +1,39 @@ +#!/bin/false + . (status dirname)/_error.function.fish + +# =_defer +# +# Import with `. (status dirname)/_defer.function.fish`. Use with `_defer (<name> | _) <body>. +# e.g. +# > touch foo && _defer rm_foo 'rm -f '(realpath foo) +# +# This creates a new function with a name of something like +# `__cleanup__<script_path>__rm_foo__<uuid>` with `--on-event fish_exit` which +# erases itself on execution (subject to change). + + # workaround for `status filename` not returning the script that sourced [ (count $argv) -eq 1 ] || _error 'Need to supply script name to source command' set current_filename $argv[1] if [ "$current_filename" = "Standard input" ] - set -e current_filename + set -e current_filename else - set current_filename (systemd-escape --path (basename $current_filename)) + set current_filename (systemd-escape --path (basename $current_filename) 2>/dev/null) end function _defer --argument name body - if [ (count $argv) -ne 2 ] || [ -z "$argv[1]" ] || [ -z "$argv[2]" ] - echo Invalid params '(expected 2, name and body, both non-empty)' - return 1 - end - - set name __cleanup__"$current_filename"__(string escape --style=var "$name")__(uuidgen) -# need \; and \<newline> for line break escaping and command delimiting - echo \ - function $name --on-event fish_exit \;\ - $body \;\ - functions --erase $name \;\ - end | source + if [ (count $argv) -ne 2 ] || [ -z "$argv[1]" ] || [ -z "$argv[2]" ] + _error '_defer: Invalid params (expected 2, name and body, both non-empty)' argv + end + + set name __cleanup__"$current_filename"__(string escape --style=var "$name")__(uuidgen) + # need \; and \<newline> for line break escaping and command delimiting + echo \ + function $name --on-event fish_exit \; \ + $body \; \ + functions --erase $name \; \ + end | source end diff --git a/helpers/_error.function.fish b/helpers/_error.function.fish index ecf5efabe9d84d385514f406ab64304f7700b6ba..e54a5e670da03fb3d1599215c973510388e2f05e 100644 --- a/helpers/_error.function.fish +++ b/helpers/_error.function.fish @@ -1,11 +1,34 @@ # use syntax: # . (dirname (status current-filename))/../helpers/_error.function.fish +# TODO change syntax to vars can appear everywhere with prefix (eg _error this is a @foo @bar call) executes to `This is a foo=<foo> bar=<bar> call` +# TODO add script name to source params so we can atleast add a prefix +function _log -a label -a color --description 'Call with `_error <msg> <var1> <var2> … <var_n>` to abort the program' --no-scope-shadowing + for i in $argv[2..] + set out $out {$i}="$$i" + end + + begin + set_color brred + echo -n $argv[1] + set_color red + echo ' ('(string join ', ' $out)')' + set_color normal + end 1>&2 + exit 1 +end + function _error --description 'Call with `_error <msg> <var1> <var2> … <var_n>` to abort the program' --no-scope-shadowing - for i in $argv[2..] - set out $out {$i}="$$i" - end + for i in $argv[2..] + set out $out {$i}="$$i" + end - begin; set_color brred; echo -n $argv[1]; set_color red; echo ' ('(string join ', ' $out)')'; set_color normal; end 1>&2 - exit 1 + begin + set_color brred + echo -n $argv[1] + set_color red + echo ' ('(string join ', ' $out)')' + set_color normal + end 1>&2 + exit 1 end diff --git a/helpers/_import.function.fish b/helpers/_import.function.fish new file mode 100755 index 0000000000000000000000000000000000000000..5a2f52c24ee6e9e1f5cc6f6b4c236beefda0aa4d --- /dev/null +++ b/helpers/_import.function.fish @@ -0,0 +1,49 @@ +#!/bin/false + + +# =_import +# +# Call with `_import <path> [as <prefix>]. Imports exported symbols with a prefix. +# e.g. `colors.fish` exports [`r`, `g`, `b`]. Then `_import colors.fish as cl` +# defines three vars `$cl_r`, `$cl_g`, `$cl_b` while also checking possible +# collisions (and aborting on such). +# +# (TODO or register functions? not sure which is better) + +status dirname +. (status dirname)/_defer.function.fish (status filename) +. (status dirname)/_error.function.fish + +function _import + function b9ef403f-b1cc-4ace-b1bf-218c9eeb334b --inherit-variable args + echo Error: `_import $args` is an illegal usage! + #exit 2 + return 2 + end + set _usage b9ef403f-b1cc-4ace-b1bf-218c9eeb334b + _defer _ 'functions -e b9ef403f-b1cc-4ace-b1bf-218c9eeb334b' + + set SYM_TBL __SYMBOLS__ + + # parse args + set args (string match --regex --groups-only '(.+) as ([[:alnum:]]+)' "$argv") + [ $status -ne 0 ] && $_usage + + set module_path $args[1] + set prefix $args[2] + + [ ! -e "$module_path" ] || [ -z "$prefix" ] && $_usage + + set -e $SYM_TBL + source $module_path || _error 'Could not source module' module_path + set -q $SYM_TBL || _error 'No sym table found in module' module_path SYM_TBL + + for symbol in $$SYM_TBL + set symbol (string split --max 1 -- = $symbol) + [ (count $symbol) -eq 1 ] && set -a symbol $symbol + + printf '%s ' set + [ $prefix = _ ] || printf '%s_' $prefix + printf '%s %s\n' $symbol + end +end diff --git a/helpers/numeric.fish b/helpers/numeric.fish new file mode 100644 index 0000000000000000000000000000000000000000..cb1bedacf9b4c9ef5af16865d263c4cd8b95bf87 --- /dev/null +++ b/helpers/numeric.fish @@ -0,0 +1,17 @@ +#!/usr/bin/env false + + +# matches numbers, pos/neg with/out decimal places +function __t-nil_helper__is_numeric --argument-names x + string match --regex -- '^-?\d+(\.\d+)?$' $x >/dev/null +end + +if functions -q @test + for t in 99 101 005 5.88 -2 -974 -4.5 -0.7 + @test "is_numeric == true: "$t (__t-nil_helper__is_numeric $t) $status -eq 0 + end + + for t in 5. 3s s5 N/A + @test "is_numeric == false: "$t (__t-nil_helper__is_numeric $t) $status -ne 0 + end +end diff --git a/helpers/std.fish b/helpers/std.fish index b7c4760b1e61425f766172c6f6a50253ffbedf43..92f978848c656222c1f54e5ead34dd400ea3b283 100644 --- a/helpers/std.fish +++ b/helpers/std.fish @@ -1,4 +1,9 @@ -. (status dirname)/_error.function.fish +set helpers (dirname (realpath (status filename))) +. $helpers/_error.function.fish (status filename) +. $helpers/_defer.function.fish (status filename) + +set -g __SYMBOLS__ memoize=_memoize_216d7666-6730-426a-9e4b-3ba3f9d31c20 \ + require=_require_983b0cc9-3314-4284-ac16-4372350fd657 begin function _t-nil_helpers_std_find_end_of_flags --description "given \$argv, returns the index of the first non-flag-arg (either not starting with '-' or after encountering '--')"\nERROR\n"end not found: return 0" @@ -20,7 +25,7 @@ begin end end -function _memoize -a function_name +function _memoize_216d7666-6730-426a-9e4b-3ba3f9d31c20 -a function_name set -l MEMOIZE_MAX 102400 set inner_fn_name '__'$function_name'__memoize_inner' @@ -53,3 +58,21 @@ function _memoize -a function_name end ' | source end + +# TODO tests (may require stuff like https://github.com/fish-shell/fish-shell/issues/10019 to test stderr msgs) +function require + switch (count $argv) + case 1: + set -l cmd $argv[1] + [ -x (which $cmd) ] || [ -x $cmd ] || return (_error "[ERROR] Script requirement $cmd not found") + case 2: + if [ $argv[2] != :opt ] + return (_error malformed argv) + end + set -l cmd $argv[2] + [ -x (which $cmd) ] || [ -x $cmd ] || begin; set_color -di yellow; echo "[WARN] Optional requirement $cmd not found"; return 5; end >&2 + end + return (_error malformed argv) +end + +