diff --git a/nix/parseParamsString.nix b/nix/parseParamsString.nix new file mode 100644 index 0000000..1807d55 --- /dev/null +++ b/nix/parseParamsString.nix @@ -0,0 +1,35 @@ +with builtins; +let + listToAttrs = xs: + if length xs == 0 + then { } + else if length xs == 1 + then throw "parseParamsString: Found an odd number of items: ${head xs}" + else { ${head xs} = elemAt xs 1; } // listToAttrs (tail (tail xs)); + + stripPat = "[[:space:]]+(.*)"; + + stripLeft = string: + if match stripPat string != null + then head (match stripPat string) + else string; + + pat1 = "\"([^\"]+)\"(.*)"; + + pat2 = "([^\"][^[:space:]]*)(.*)"; + + go = m: [ (elemAt m 0) ] ++ parse (elemAt m 1); + + parse' = string: + if string == "" + then [ ] + else if match pat1 string != null + then go (match pat1 string) + else if match pat2 string != null + then go (match pat2 string) + else throw "Match nothing: ${string}"; + + parse = string: parse' (stripLeft string); +in +string: +listToAttrs (parse string) diff --git a/nix/tangleOrgBabel.nix b/nix/tangleOrgBabel.nix index 27243e7..340e7a5 100644 --- a/nix/tangleOrgBabel.nix +++ b/nix/tangleOrgBabel.nix @@ -12,9 +12,27 @@ let blockStartRegexp = "[[:space:]]*\#\\+[Bb][Ee][Gg][Ii][Nn]_[Ss][Rr][Cc][[:space:]]+" + "(" + (concatStringsSep "|" languages) + ")" - + "([[:space:]].*)?"; + + "(([[:space:]].*)?)"; - isBlockStart = line: match blockStartRegexp line != null; + parseParamsString = import ./parseParamsString.nix; + + parseParamsString' = s: + if s == null + then { } + else parseParamsString s; + + checkBlockParams = attrs: + foldl' (acc: value: acc && value) true + (attrValues + (mapAttrs (name: value: + if name == ":tangle" + then value == "yes" + else true + ) attrs)); + + isBlockStart = line: + (match blockStartRegexp line != null) + && checkBlockParams (parseParamsString' (elemAt (match blockStartRegexp line) 2)); splitListWith = import ./splitWith.nix; diff --git a/test/test.nix b/test/test.nix index 24467da..24bdd07 100644 --- a/test/test.nix +++ b/test/test.nix @@ -7,6 +7,7 @@ let matchOrgTag = import ../nix/matchOrgTag.nix; matchOrgHeadline = import ../nix/matchOrgHeadline.nix; dropUntil = import ../nix/dropUntil.nix; + tangleOrgBabel = import ../nix/tangleOrgBabel.nix; lines = filter (s: isString s && s != "") (split "\n" (readFile ./test.org)); in pkgs.lib.runTests { @@ -39,4 +40,19 @@ pkgs.lib.runTests { expr = pkgs.lib.last (select (matchOrgTag "optional") lines); expected = "/Zaijian/ means goodbye in Mandarin Chinese."; }; + + testTangleOrgBabel = { + expr = pkgs.lib.pipe (tangleOrgBabel { } (readFile ./testTangle.org)) [ + (split "\n") + (filter isString) + ]; + + expected = [ + "Default" + "Alternative language name" + "Upper case" + ":tangle yes" + "Extra spaces around params" + ]; + }; } diff --git a/test/testTangle.org b/test/testTangle.org new file mode 100644 index 0000000..f4059f9 --- /dev/null +++ b/test/testTangle.org @@ -0,0 +1,31 @@ +#+begin_src +No language +#+end_src + +#+begin_src emacs-lisp +Default +#+end_src + +#+begin_src elisp +Alternative language name +#+end_src elisp + +#+BEGIN_SRC emacs-lisp +Upper case +#+END_SRC + +#+BEGIN_SRC shell +Different language +#+END_SRC + +#+begin_src emacs-lisp :tangle yes +:tangle yes +#+end_src + +#+begin_src emacs-lisp :tangle yes +Extra spaces around params +#+end_src + +#+begin_src emacs-lisp :tangle no +:tangle no +#+end_src