Only build the 'travis' github branch on Travis
[notion/jeffpc.git] / build / mkman.lua
blobafdf08bcac554926742381fc862f9a6f71a146b0
1 --
2 -- build/mkman.lua
3 --
4 -- Translates bindings from Ion configuration into a listing for
5 -- manual pages.
6 --
9 -- Translations {{{
11 local translations={}
13 local function gettext(x)
14 local t=translations[x]
15 if not t or t=="" then
16 return x
17 else
18 return t
19 end
20 end
22 local function TR(x, ...)
23 return string.format(gettext(x), ...)
24 end
26 local function read_translations(pofile)
27 local f, err=io.open(pofile)
28 if not f then
29 error(err)
30 end
32 local msgid, msgstr, st, en
34 for l in f:lines() do
35 if string.find(l, "^msgid") then
36 if msgid then
37 assert(msgstr)
38 translations[msgid]=msgstr
39 msgstr=nil
40 end
41 st, en, msgid=string.find(l, '^msgid%s*"(.*)"%s*$')
42 elseif string.find(l, "^msgstr") then
43 assert(msgid and not msgstr)
44 st, en, msgstr=string.find(l, '^msgstr%s*"(.*)"%s*$')
45 elseif not (string.find(l, "^%s*#") or string.find(l, "^%s*$")) then
46 local st, en, str=string.find(l, '^%s*"(.*)"%s*$')
47 assert(msgid or msgstr)
48 if not msgstr then
49 msgid=msgid..str
50 else
51 msgstr=msgstr..str
52 end
53 end
54 end
56 if msgid then
57 assert(msgstr)
58 translations[msgid]=msgstr
59 end
61 f:close()
62 end
64 -- }}}
67 -- File parsing {{{
69 local function dobindings(f, bindings)
70 local p={}
71 local dummy = function() end
73 p.META="Mod1+"
74 p.ALTMETA=""
76 p.dopath=dummy
77 p.defmenu=dummy
78 p.defctxmenu=dummy
79 p.menuentry=dummy
80 p.submenu=dummy
81 p.submap_enter=dummy
82 p.submap_leave=dummy
83 p.submap_wait=dummy
85 p.ioncore={
86 set=dummy,
89 function p.bdoc(text)
90 return {action = "doc", text = text}
91 end
93 function p.submap(kcb_, list)
94 if not list then
95 return function(lst)
96 return p.submap(kcb_, lst)
97 end
98 end
99 return {action = "kpress", kcb = kcb_, submap = list}
102 local function putcmd(cmd, guard, t)
103 t.cmd=cmd
104 t.guard=guard
105 return t
108 function p.kpress(keyspec, cmd, guard)
109 return putcmd(cmd, guard, {action = "kpress", kcb = keyspec})
112 function p.kpress_wait(keyspec, cmd, guard)
113 return putcmd(cmd, guard, {action = "kpress_wait", kcb = keyspec})
116 local function mact(act_, kcb_, cmd, guard)
117 local st, en, kcb2_, area_=string.find(kcb_, "([^@]*)@(.*)")
118 return putcmd(cmd, guard, {
119 action = act_,
120 kcb = (kcb2_ or kcb_),
121 area = area_,
125 function p.mclick(buttonspec, cmd, guard)
126 return mact("mclick", buttonspec, cmd, guard)
129 function p.mdblclick(buttonspec, cmd, guard)
130 return mact("mdblclick", buttonspec, cmd, guard)
133 function p.mpress(buttonspec, cmd, guard)
134 return mact("mpress", buttonspec, cmd, guard)
137 function p.mdrag(buttonspec, cmd, guard)
138 return mact("mdrag", buttonspec, cmd, guard)
141 function ins(t, v)
142 if not t.seen then
143 t.seen={}
146 if (not v.kcb) or v.submap then
147 -- Submap rebinds are not presently handled
148 table.insert(t, v)
149 else
150 local id=v.action..":"..v.kcb..":"..(v.area or "")
151 local i=t.seen[id]
152 if i then
153 t[i].invalid=true
155 if v.cmd then
156 table.insert(t, v)
157 t.seen[id]=#t
158 else
159 -- Unbind only
160 t.seen[id]=nil
165 function p.defbindings(context, bnd)
166 if not bindings[context] then
167 bindings[context]={}
168 else
169 -- Reset documentation
170 table.insert(bindings[context], { action = "doc", text = nil })
173 for _, v in ipairs(bnd) do
174 ins(bindings[context], v)
178 local env=setmetatable({}, {
179 __index=p,
180 __newindex=function(x)
181 error("Setting global "..tostring(x))
182 end,
185 local fn, err
187 if _ENV then
188 fn, err=loadfile(f, nil, env)
189 else
190 fn, err=loadfile(f)
193 if not fn then
194 error(err)
197 if not _ENV then
198 setfenv(fn, env)
201 fn()
202 return bindings
205 -- }}}
208 -- Binding output {{{
210 local function docgroup_bindings(bindings)
211 local out={}
212 local outi=0
214 local function parsetable(t, prefix)
215 --for _, v in ipairs(t) do
216 -- ipairs doesn't like nil values, that e.g. submap_wait dummy might generate
217 for i=1,#t do
218 local v=t[i]
219 if v and not v.invalid then
220 if v.kcb then
221 v.kcb=string.gsub(v.kcb, "AnyModifier%+", "")
223 if v.action=="doc" then
224 if outi==0 or #out[outi].bindings>0 then
225 outi=outi+1
227 out[outi]={doc=v.text, bindings={}}
228 elseif v.submap then
229 parsetable(v.submap, prefix..v.kcb.." ")
230 else
231 assert(out[outi])
232 v.kcb=prefix..v.kcb
233 table.insert(out[outi].bindings, v)
239 if outi~=0 and #out[outi].bindings==0 then
240 out[outi]=nil
243 parsetable(bindings, "")
245 return out
249 local function combine_bindings(v)
250 local nact={
251 ["mpress"]=TR("press"),
252 ["mclick"]=TR("click"),
253 ["mdrag"]=TR("drag"),
254 ["mdblclick"]=TR("double click"),
256 local first=true
257 local s=""
258 for _, b in ipairs(v.bindings) do
259 if not first then
260 s=s..', '
262 first=false
263 if b.action=="kpress" or b.action=="kpress_wait" then
264 s=s..b.kcb
265 else
266 if not b.area then
267 s=s..TR("%s %s", b.kcb, nact[b.action])
268 else
269 s=s..TR("%s %s at %s", b.kcb, nact[b.action], b.area)
274 return s
275 end
277 local function write_bindings_man(db)
278 local function write_binding_man(v)
279 return '.TP\n.B '..combine_bindings(v)..'\n'..gettext(v.doc or "?")..'\n'
282 local s=""
284 for _, v in ipairs(db) do
285 if #(v.bindings)>0 then
286 s=s..write_binding_man(v)
290 return s
293 -- }}}
295 -- Main {{{
297 local infile
298 local outfile
299 local bindings={}
300 local replaces={}
302 local function doargs(a)
303 local i=1
304 while i<=#a do
305 if a[i]=='-o' then
306 outfile=a[i+1]
307 i=i+2
308 elseif a[i]=='-i' then
309 infile=a[i+1]
310 i=i+2
311 elseif a[i]=='-D' then
312 replaces[a[i+1]]=a[i+2]
313 i=i+3
314 elseif a[i]=='-po' then
315 read_translations(a[i+1])
316 i=i+2
317 else
318 dobindings(a[i], bindings)
319 i=i+1
324 doargs({...})
326 local f, err=io.open(infile)
327 if not f then
328 error(err)
331 local of, oerr=io.open(outfile, 'w+')
332 if not of then
333 error(oerr)
336 for l in f:lines() do
337 l=string.gsub(l, '%s*BINDINGS:([%w%.%-]+)%s*',
338 function(s)
339 if not bindings[s] then
340 --error('No bindings for '..s)
341 return "?"
343 local db=docgroup_bindings(bindings[s])
344 return write_bindings_man(db)
345 end)
347 for pat, rep in pairs(replaces) do
348 l=string.gsub(l, pat, rep)
351 of:write(l..'\n')
354 -- }}}