-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdjot.lua
171 lines (151 loc) · 3.69 KB
/
djot.lua
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
local block = require("djot.block")
local ast = require("djot.ast")
local html = require("djot.html")
local match = require("djot.match")
local json = require("djot.json")
local apply_filter = require("djot.filter").apply_filter
local unpack_match = match.unpack_match
local format_match = match.format_match
local StringHandle = {}
function StringHandle:new()
local buffer = {}
setmetatable(buffer, StringHandle)
StringHandle.__index = StringHandle
return buffer
end
function StringHandle:write(s)
self[#self + 1] = s
end
function StringHandle:flush()
return table.concat(self)
end
local Tokenizer = block.Tokenizer
-- Doc
local Doc = {}
function Doc:new(tokenizer, sourcepos)
local the_ast, sourcepos_map =
ast.to_ast(tokenizer, sourcepos)
local state = {
ast = the_ast,
sourcepos_map = sourcepos_map,
matches = tokenizer.matches
}
setmetatable(state, self)
self.__index = self
return state
end
function Doc:render_ast(handle, use_json)
if not handle then
handle = StringHandle:new()
end
if use_json then
handle:write(json.encode(self.ast))
else
ast.render(self.ast, handle)
end
if use_json then
handle:write("\n")
end
return handle:flush()
end
function Doc:render_html(handle)
if not handle then
handle = StringHandle:new()
end
local renderer = html.Renderer:new()
renderer:render(self.ast, handle)
return handle:flush()
end
function Doc:apply_filter(filter)
apply_filter(self.ast, filter)
return self
end
function Doc:render_matches(handle, use_json, warn)
if not handle then
handle = StringHandle:new()
end
if use_json then
handle:write("[")
end
for idx,match in ipairs(self.matches) do
if use_json then
local startpos, endpos, annotation = unpack_match(match)
if idx > 1 then
handle:write(",")
end
handle:write(json.encode({ annotation, {startpos, endpos} }))
handle:write("\n")
else
handle:write(format_match(match))
end
end
if use_json then
handle:write("]\n")
end
return handle:flush()
end
-- function Doc:format_source_pos(bytepos)
-- local pos = self.sourcepos_map[bytepos]
-- if pos then
-- return string.format("line %d, column %d", pos[1], pos[2])
-- else
-- return string.format("byte position %d", bytepos)
-- end
-- end
-- function Doc:render_warnings(handle, as_json)
-- if #self.warnings == 0 then
-- return
-- end
-- if as_json then
-- handle:write(json.encode(warnings))
-- else
-- for _,warning in ipairs(self.warnings) do
-- handle:write(string.format("%s at %s\n",
-- warning.message, self:format_source_pos(warning.pos)))
-- end
-- end
-- if as_json then
-- handle:write("\n")
-- end
-- return handle:flush()
-- end
local function parse(input, sourcepos, warn)
local tokenizer = Tokenizer:new(input, warn)
return Doc:new(tokenizer, sourcepos)
end
local function tokenize(input)
return Tokenizer:new(input):tokenize()
end
local function render_matches(input, handle, use_json, warn)
if not handle then
handle = StringHandle:new()
end
local tokenizer = Tokenizer:new(input, warn)
local idx = 0
if use_json then
handle:write("[")
end
for match in tokenizer:tokenize() do
idx = idx + 1
if use_json then
local startpos, endpos, annotation = unpack_match(match)
if idx > 1 then
handle:write(",")
end
handle:write(json.encode({ annotation, {startpos, endpos} }))
handle:write("\n")
else
handle:write(format_match(match))
end
end
if use_json then
handle:write("]\n")
end
return handle:flush()
end
return {
parse = parse,
tokenize = tokenize,
render_matches = render_matches,
version = "0.2.0"
}