feat(users/sterni/nix/string): very simple printf implementation

This is mostly to yet another silly idea which turns out to be
possible. This may be actually useful should I implement more
sophisticated format specifiers like "%xd" or "%f".

Change-Id: Ia56cd6f5793a09fe5e19c91a8e8f9098f3244d57
Reviewed-on: https://cl.tvl.fyi/c/depot/+/3537
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
This commit is contained in:
sterni 2021-09-11 21:56:05 +02:00
parent 2f750e4a14
commit e507b84291
2 changed files with 45 additions and 0 deletions

View file

@ -59,6 +59,43 @@ let
# pattern matching for strings only
match = val: matcher: matcher."${val}";
/* Bare-bones printf implementation. Supported format specifiers:
* `%%` escapes `%`
* `%s` is substituted by a string
As expected, the first argument is a format string and the values
for its format specifiers need to provided as the next arguments
in order.
Type: string -> (printfVal : either string (a -> printfVal))
*/
printf = formatString:
let
specifierWithArg = token: builtins.elem token [
"%s"
];
isSpecifier = lib.hasPrefix "%";
tokens = lib.flatten (builtins.split "(%.)" formatString);
argsNeeded = builtins.length (builtins.filter specifierWithArg tokens);
format = args: (builtins.foldl' ({ out ? "", argIndex ? 0 }: token: {
argIndex = argIndex + (if specifierWithArg token then 1 else 0);
out =
/**/ if token == "%s" then out + builtins.elemAt args argIndex
else if token == "%%" then out + "%"
else if isSpecifier token then throw "Unsupported format specifier ${token}"
else out + token;
}) {} tokens).out;
accumulateArgs = argCount: args:
if argCount > 0
then arg: accumulateArgs (argCount - 1) (args ++ [ arg ])
else format args;
in
accumulateArgs argsNeeded [];
in {
inherit
take
@ -72,5 +109,6 @@ in {
pad
fit
match
printf
;
}

View file

@ -56,10 +56,17 @@ let
}))
];
f = "f";
testPrintf = it "prints f" [
(assertEq "basic %s usage" "print ${f}" (string.printf "print %s" f))
(assertEq "% escaping" "100%" (string.printf "100%%"))
];
in
runTestsuite "nix.string" [
testTakeDrop
testIndexing
testFinding
testMatch
testPrintf
]