1
0
Fork 0
mirror of https://github.com/emacs-twist/org-babel.git synced 2024-12-14 11:07:30 +00:00

Initial commit

This commit is contained in:
Akira Komamura 2021-12-03 22:44:34 +09:00
commit 16c3622825
12 changed files with 195 additions and 0 deletions

7
flake.lock Normal file
View file

@ -0,0 +1,7 @@
{
"nodes": {
"root": {}
},
"root": "root",
"version": 7
}

5
flake.nix Normal file
View file

@ -0,0 +1,5 @@
{
description = "Nix library for extracting source blocks from Org";
outputs = { ... }: { lib = import ./nix; };
}

18
nix/default.nix Normal file
View file

@ -0,0 +1,18 @@
with builtins;
let
excludeOrgSubtreesOnHeadlines = import ./excludeOrgSubtreesOnHeadlines.nix;
matchOrgTag = import ./matchOrgTag.nix;
matchOrgHeadline = import ./matchOrgHeadline.nix;
matchOrgHeadlines = headlines: s:
builtins.any (t: matchOrgHeadline t s) headlines;
tangleOrgBabel = pkgs.callPackage ./tangleOrgBabel.nix {
processLines = processOrgLines;
};
in
{
inherit matchOrgTag matchOrgHeadline matchOrgHeadlines;
inherit excludeOrgSubtreesOnHeadlines;
inherit tangleOrgBabel;
}

8
nix/dropUntil.nix Normal file
View file

@ -0,0 +1,8 @@
pred: items:
with builtins;
let
xs = import ./dropWhile.nix (x: ! (pred x)) items;
in
if length xs > 0
then tail xs
else [ ]

11
nix/dropWhile.nix Normal file
View file

@ -0,0 +1,11 @@
pred:
with builtins;
let
go = items:
if length items == 0
then [ ]
else if ! (pred (head items))
then items
else go (tail items);
in
go

View file

@ -0,0 +1,37 @@
# Exclude lines of Org subtrees by a heading predicate
pred:
with builtins;
let
dropWhile = import ./dropWhile.nix;
splitListWith = import ./splitWith.nix;
isHeadline = s: substring 0 1 s == "*";
genericHeadlineRegexp = "(\\*+)[[:space:]].+";
getHeadlineLevel = headline:
stringLength (head (match genericHeadlineRegexp headline));
prependOptionalStars = n: rest:
if n == 0
then rest
else prependOptionalStars (n - 1) ("\\*?" + rest);
makeSubtreeEndRegexp = outlineLevel:
prependOptionalStars (outlineLevel - 1) "\\*[[:space:]].+";
dropTillSubtreeEnd = level:
dropWhile (s: !(isHeadline s && match (makeSubtreeEndRegexp level) s != null));
go_ = cut:
cut.before
++
(if cut.sep == null
then [ ]
else go (dropTillSubtreeEnd (getHeadlineLevel cut.sep) cut.after));
go = lines: go_ (splitListWith (s: isHeadline s && pred s) lines);
in
go

4
nix/matchOrgHeadline.nix Normal file
View file

@ -0,0 +1,4 @@
headlineText: s:
builtins.match
"\\*+[[:space:]]+${headlineText}([[:space:]]+:[^[:space:]]+:)?[[:space:]]*"
s != null

4
nix/matchOrgTag.nix Normal file
View file

@ -0,0 +1,4 @@
tag: s:
builtins.match
"\\*+[[:space:]].+:${tag}:.*"
s != null

11
nix/splitWith.nix Normal file
View file

@ -0,0 +1,11 @@
pred:
with builtins;
let
go = before: rest:
if (length rest == 0)
then { inherit before; sep = null; after = [ ]; }
else if pred (head rest)
then { inherit before; sep = head rest; after = tail rest; }
else (go (before ++ [ (head rest) ]) (tail rest));
in
go [ ]

37
nix/tangleOrgBabel.nix Normal file
View file

@ -0,0 +1,37 @@
# Quick-and-dirty re-implementation of org-babel-tangle in Nix.
{ languages
, processLines
}:
string:
with builtins;
let
lines = filter isString (split "\n" string);
dropUntil = import ./dropUntil.nix;
blockStartRegexp =
"[[:space:]]*\#\\+[Bb][Ee][Gg][Ii][Nn]_[Ss][Rr][Cc][[:space:]]+"
+ "(" + (concatStringsSep "|" languages) + ")"
+ "([[:space:]].*)?";
isBlockStart = line: match blockStartRegexp line != null;
splitListWith = import ./splitWith.nix;
blockEndRegexp = "[[:space:]]*\#\\+[Ee][Nn][Dd]_[Ss][Rr][Cc].*";
isBlockEnd = line: match blockEndRegexp line != null;
go = acc: xs:
let
st1 = dropUntil isBlockStart xs;
st2 = splitListWith isBlockEnd st1;
in
if length xs == 0
then acc
else if length st1 == 0
then acc
else (go (acc ++ [ st2.before ]) st2.after);
in
concatStringsSep "\n" (concatLists (go [ ] (processLines lines)))

33
test/test.nix Normal file
View file

@ -0,0 +1,33 @@
# nix-instantiate --eval --strict test/test.nix
with builtins;
let
pkgs = import (fetchTree (fromJSON (readFile ../flake.lock)).nodes.nixpkgs.locked) {
system = builtins.currentSystem;
};
exclude = import ../nix/excludeOrgSubtreesOnHeadlines.nix;
matchOrgTag = import ../nix/matchOrgTag.nix;
matchOrgHeadline = import ../nix/matchOrgHeadline.nix;
dropUntil = import ../nix/dropUntil.nix;
lines = filter isString (split "\n" (readFile ./test.org));
in
pkgs.lib.runTests {
testTagPredicate = {
expr = head (exclude (matchOrgTag "ARCHIVE") lines);
expected = "* Good morning";
};
testHeadlinePredicate = {
expr = head (exclude (matchOrgHeadline "Archived entry") lines);
expected = "* Good morning";
};
testSubtree = {
expr = head (dropUntil (s: s == "Hello!") (exclude (matchOrgTag "irregular") lines));
expected = "* Get to work";
};
testTagPredicate2 = {
expr = pkgs.lib.last (exclude (matchOrgTag "optional") lines);
expected = "It was a good day!";
};
}

20
test/test.org Normal file
View file

@ -0,0 +1,20 @@
* Archived entry :ARCHIVE:
** Child inside an archive entry
* Good morning
Good morning!
* Zao :optional:
/Zao/ means good morning in Mandarin Chinese.
Chinese is optional for non-Chinese people living in countries other than China.
* Hello
Hello!
** Irreguar cases :irregular:
*** If he/she isn't fine
Call an ambulance.
Why did he come to the office in the first place?
* Get to work
Do you love your work?
* Bye
Bye!
It was a good day!
* Zaijian :optional:
/Zaijian/ means goodbye in Mandarin Chinese.