-
Notifications
You must be signed in to change notification settings - Fork 2
/
tangle.nim
80 lines (70 loc) · 2.13 KB
/
tangle.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# Quick & dirty superfast tangler for org mode files.
import os
import ospaths
import strutils
import nre
import tables
type ParserState = enum
text, namedBlock, code
let blockNameRe = re"#\+NAME:\s*(.+)\s*"
let beginTangleBlock = re"#\+BEGIN_SRC.+:tangle\s+(\S+).*"
let endBlockRe = re"#\+END_SRC\s*"
let macroRe = re"(?<prefix>.*)<<(?<name>.+)>>(?<suffix>.*)"
let paddleRe = re"(\s*)"
let inputName = paramStr 1
let inputText = readFile inputName
var parserState = text
var blockName: string
var tanglePath: string
var counter = 0
var pathToName = initTable[string, string]()
var nameToCode = initTable[string, seq[string]]()
for line in inputText.splitLines:
case parserState
of text:
let m = line.match blockNameRe
if m.isSome:
parserState = namedBlock
blockName = m.get.captures[0]
else:
let m = line.match beginTangleBlock
if m.isSome:
parserState = code
tanglePath = m.get.captures[0]
blockName = "auto-" & counter.intToStr
counter = counter + 1
pathToName[tanglePath] = blockName
of namedBlock:
parserState = code
let m = line.match beginTangleBlock
if m.isSome:
tanglePath = m.get.captures[0]
pathToName[tanglePath] = blockName
of code:
if line.match(endBlockRe).isSome:
parserState = text
else:
if not nameToCode.hasKey(blockName):
nameToCode[blockName] = @[]
nameToCode[blockName].add line
proc paddleLen(s: string): int =
return s.match(paddleRe).get.captures[0].len
proc tangle(prefix: string, blockName: string, output: File) =
let code = nameToCode[blockName]
let paddle = code[0].paddleLen
for rawLine in code:
let line = rawLine.substr paddle
let m = line.match macroRe
if m.isSome:
let m = m.get.captures
tangle prefix & m["prefix"], m["name"], output
output.writeLine m["suffix"]
else:
output.writeLine prefix & line
for tanglePath, blockName in pathToName.pairs:
let path = tanglePath.splitPath[0]
if path != "" and not path.dirExists:
path.createDir
let output = open(tanglePath, fmWrite)
tangle "", blockName, output
close output