diff options
author | sterni <sternenseemann@systemli.org> | 2021-09-11T19·56+0200 |
---|---|---|
committer | sterni <sternenseemann@systemli.org> | 2021-09-12T09·25+0000 |
commit | e507b842918f80340257304bd9541cb3b3abc9da (patch) | |
tree | 62537407066e338491b489be3c54a40f21d77f27 /users/sterni | |
parent | 2f750e4a14be68f275f6fe23995eb9a994e0f5de (diff) |
feat(users/sterni/nix/string): very simple printf implementation r/2851
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>
Diffstat (limited to 'users/sterni')
-rw-r--r-- | users/sterni/nix/string/default.nix | 38 | ||||
-rw-r--r-- | users/sterni/nix/string/tests/default.nix | 7 |
2 files changed, 45 insertions, 0 deletions
diff --git a/users/sterni/nix/string/default.nix b/users/sterni/nix/string/default.nix index 3fe7c04618c3..19d2cec243c0 100644 --- a/users/sterni/nix/string/default.nix +++ b/users/sterni/nix/string/default.nix @@ -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 ; } diff --git a/users/sterni/nix/string/tests/default.nix b/users/sterni/nix/string/tests/default.nix index 2caecbfa7b3f..c8aec9464077 100644 --- a/users/sterni/nix/string/tests/default.nix +++ b/users/sterni/nix/string/tests/default.nix @@ -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 ] |