101 lines
1.6 KiB
Nix
101 lines
1.6 KiB
Nix
|
{ depot, lib, ... }:
|
||
|
|
||
|
let
|
||
|
|
||
|
inherit (depot.users.sterni.nix)
|
||
|
char
|
||
|
int
|
||
|
string
|
||
|
flow
|
||
|
;
|
||
|
|
||
|
reserved = c: builtins.elem c [
|
||
|
"!"
|
||
|
"#"
|
||
|
"$"
|
||
|
"&"
|
||
|
"'"
|
||
|
"("
|
||
|
")"
|
||
|
"*"
|
||
|
"+"
|
||
|
","
|
||
|
"/"
|
||
|
":"
|
||
|
";"
|
||
|
"="
|
||
|
"?"
|
||
|
"@"
|
||
|
"["
|
||
|
"]"
|
||
|
];
|
||
|
|
||
|
unreserved = c: char.asciiAlphaNum c
|
||
|
|| builtins.elem c [ "-" "_" "." "~" ];
|
||
|
|
||
|
percentEncode = c:
|
||
|
if unreserved c
|
||
|
then c
|
||
|
else "%" + (string.fit
|
||
|
{
|
||
|
width = 2;
|
||
|
char = "0";
|
||
|
side = "left";
|
||
|
}
|
||
|
(int.toHex (char.ord c)));
|
||
|
|
||
|
encode = { leaveReserved ? false }: s:
|
||
|
let
|
||
|
chars = lib.stringToCharacters s;
|
||
|
tr = c:
|
||
|
if leaveReserved && reserved c
|
||
|
then c
|
||
|
else percentEncode c;
|
||
|
in
|
||
|
lib.concatStrings (builtins.map tr chars);
|
||
|
|
||
|
decode = s:
|
||
|
let
|
||
|
tokens = builtins.split "%" s;
|
||
|
decodeStep =
|
||
|
{ result ? ""
|
||
|
, inPercent ? false
|
||
|
}: s:
|
||
|
flow.cond [
|
||
|
[
|
||
|
(builtins.isList s)
|
||
|
{
|
||
|
inherit result;
|
||
|
inPercent = true;
|
||
|
}
|
||
|
]
|
||
|
[
|
||
|
inPercent
|
||
|
{
|
||
|
inPercent = false;
|
||
|
# first two characters came after an %
|
||
|
# the rest is the string until the next %
|
||
|
result = result
|
||
|
+ char.chr (int.fromHex (string.take 2 s))
|
||
|
+ (string.drop 2 s);
|
||
|
}
|
||
|
]
|
||
|
[
|
||
|
(!inPercent)
|
||
|
{
|
||
|
result = result + s;
|
||
|
}
|
||
|
]
|
||
|
];
|
||
|
|
||
|
in
|
||
|
(builtins.foldl' decodeStep { } tokens).result;
|
||
|
|
||
|
in
|
||
|
{
|
||
|
inherit
|
||
|
encode
|
||
|
decode
|
||
|
;
|
||
|
}
|