Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ Special Terms | Meaning
------------- | -------
`*` | matches any sequence of non-path-separators
`/**/` | matches zero or more directories
`[^abc]` | excludes files matching a/b/c at the appropriate location
`[!abc]` | identical to `[^abc]`
`[^a-z]` | excludes files matching any character between a to z at the appropriate location
`[!a-z]` | identical to `[^a-z]`

Any character with a special meaning can be escaped with a backslash (`\`).

Expand Down
39 changes: 23 additions & 16 deletions default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -105,18 +105,24 @@ let
#
# Examples:
# match "a*/b" "abc/b" # Returns true
# match "a*/∫" "abc/∫" # Returns true
# match "a*/b" "a/c/b" # Returns false
# match "a*/∫" "a/c/∫" # Returns false
# match "**/c" "a/b/c" # Returns true
# match "**/c" "a/b" # Returns false
# match "a\\*b" "ab" # Returns false
# match "a\\*b" "a*b" # Returns true
# match "å\\*b" "åb" # Returns false
# match "å\\*b" "å*b" # Returns true
match = pattern: name:
let
patLen = stringLength pattern;

nameLen = stringLength name;

charAt = str: i: substring i 1 str;
charAt = str: i: internal.decodeUtf8 str i;

nextCharLen = str: i: stringLength (charAt str i);

isSeparator = char: char == "/";

Expand All @@ -136,6 +142,8 @@ let
isEscape = patChar == "\\";
isClass = patChar == "[";
nextPatChar = if (patIdx + 1) < patLen then charAt pattern (patIdx + 1) else "";
nameCharLen = nextCharLen name nameIdx;
patCharLen = nextCharLen pattern patIdx;
in
if isStar then
handleStar args
Expand All @@ -147,16 +155,16 @@ let
false
else if nextPatChar == nameChar then
doMatch (args // {
nameIdx = nameIdx + 1;
patIdx = patIdx + 2;
nameIdx = nameIdx + nameCharLen;
patIdx = patIdx + patCharLen + (nextCharLen pattern (patIdx + 1));
startOfSegment = isSeparator nameChar;
})
else
handleBacktrack args
else if patChar == nameChar then
doMatch (args // {
nameIdx = nameIdx + 1;
patIdx = patIdx + 1;
nameIdx = nameIdx + nameCharLen;
patIdx = patIdx + patCharLen;
startOfSegment = isSeparator patChar;
})
else
Expand All @@ -173,11 +181,12 @@ let
handleCharClass = args:
let
classInfo = internal.parseCharClass pattern args.patIdx;
matches = internal.matchesCharClass classInfo.content
(charAt name args.nameIdx);
nameChar = charAt name args.nameIdx;
nameCharLen = nextCharLen name args.nameIdx;
matches = internal.matchesCharClass classInfo.content nameChar;
in if (if classInfo.isNegated then !matches else matches) then
doMatch (args // {
nameIdx = args.nameIdx + 1;
nameIdx = args.nameIdx + nameCharLen;
patIdx = classInfo.endIdx + 1;
startOfSegment = false;
})
Expand All @@ -187,25 +196,23 @@ let
handleStar = args:
let
# Check ahead for a second '*'.
nextPatIdx = args.patIdx + 1;
nextPatIdx = args.patIdx + nextCharLen pattern args.patIdx;

isDoublestar = nextPatIdx < patLen && charAt pattern nextPatIdx == "*";

starBacktrack = {
inherit (args) nameIdx;
# Doublestar must begin with separator, otherwise we're going to
# treat it like a single star like bash.
patIdx = nextPatIdx + (if isDoublestar then 1 else 0);
patIdx = nextPatIdx + (if isDoublestar then nextCharLen pattern nextPatIdx else 0);
};

# Doublestar must also end with separator, treating as single star.
doublestarAfterChar = charAt pattern (nextPatIdx + 1);
doublestarAfterChar = charAt pattern (nextPatIdx + (if isDoublestar then nextCharLen pattern nextPatIdx else 0));

doublestarBacktrack = {
inherit (args) nameIdx;
# Add two to be after the separator.
# e.g. '**/?' where nextPatIdx is index of '?'.
patIdx = nextPatIdx + 2;
patIdx = nextPatIdx + (2 * nextCharLen pattern nextPatIdx);
};

in
Expand All @@ -231,13 +238,13 @@ let
let
starBacktrack = {
inherit (args.starBacktrack) patIdx;
nameIdx = args.starBacktrack.nameIdx + 1;
nameIdx = args.starBacktrack.nameIdx + nextCharLen name args.starBacktrack.nameIdx;
};

starNameChar = charAt name args.starBacktrack.nameIdx;

nextSeparatorIdx =
internal.findNextSeparator name args.doublestarBacktrack.nameIdx;
internal.findUnescapedChar name args.doublestarBacktrack.nameIdx [ "/" ];

doublestarBacktrack = {
inherit (args.doublestarBacktrack) patIdx;
Expand Down
6 changes: 3 additions & 3 deletions dev/flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 17 additions & 1 deletion flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 9 additions & 7 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
description = "Simplify Nix source management using familiar glob patterns";

inputs.nixpkgs-lib.url = "github:nix-community/nixpkgs.lib";
inputs.utf8.url = "github:figsoda/utf8";

outputs = { self, nixpkgs-lib }:
let
outputs = { self, nixpkgs-lib, utf8 }:
let
inherit (builtins)
fromJSON
readFile
Expand All @@ -27,17 +28,17 @@

pkgsFor = system: import nixpkgs { inherit system; };

globset = import self { inherit (nixpkgs-lib) lib; };
globset = import self { lib = nixpkgs-lib.lib // { utf8 = utf8.lib; }; };
in {
lib = globset;

tests = forAllSystems (system: import ./internal/tests.nix {
lib = nixpkgs-lib.lib // { inherit globset; };
lib = nixpkgs-lib.lib // { inherit globset; utf8 = utf8.lib; };
});

packages = forAllSystems (system: {
default = (import ./integration-tests.nix { pkgs = pkgsFor system; });
integration-tests = (import ./integration-tests.nix { pkgs = pkgsFor system; });
default = (import ./integration-tests.nix { pkgs = pkgsFor system; utf8 = utf8.lib; });
integration-tests = (import ./integration-tests.nix { pkgs = pkgsFor system; utf8 = utf8.lib; });
});

checks = forAllSystems (system: {
Expand All @@ -48,11 +49,12 @@
--eval-store "$HOME" \
--extra-experimental-features flakes \
--override-input nixpkgs-lib ${nixpkgs-lib} \
--override-input utf8 ${utf8} \
--flake ${self}#tests
touch $out
'';

integration-tests = (import ./integration-tests.nix { pkgs = pkgsFor system; });
integration-tests = (import ./integration-tests.nix { pkgs = pkgsFor system; utf8 = utf8.lib; });
});
};
}
Loading