]> git.decadent.org.uk Git - ion3.git/blob - build/mkman.lua
bd867c610a9f9244fc9380aae0209d9304d2d474
[ion3.git] / build / mkman.lua
1 --
2 -- build/mkman.lua
3 --
4 -- Translates bindings from Ion configuration into a listing for
5 -- manual pages.
6 --
7
8
9 -- Translations {{{
10
11 local translations={}
12
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
21
22 local function TR(x, ...)
23     return string.format(gettext(x), unpack(arg))
24 end
25
26 local function read_translations(pofile)
27     local f, err=io.open(pofile)
28     if not f then 
29         error(err) 
30     end
31     
32     local msgid, msgstr, st, en
33     
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
55
56     if msgid then
57         assert(msgstr)
58         translations[msgid]=msgstr
59     end
60     
61     f:close()
62 end
63
64 -- }}}
65
66
67 -- File parsing {{{
68
69 local function dobindings(fn, bindings)
70     local p={}
71     
72     p.META="Mod1+"
73     p.ALTMETA=""
74     
75     function p.bdoc(text)
76         return {action = "doc", text = text}
77     end
78     
79     function p.submap(kcb_, list)
80         if not list then
81             return function(lst)
82                        return submap(kcb_, lst)
83                    end
84         end
85         return {action = "kpress", kcb = kcb_, submap = list}
86     end
87     
88     local function putcmd(cmd, guard, t)
89         t.cmd=cmd
90         t.guard=guard
91         return t
92     end
93     
94     function p.kpress(keyspec, cmd, guard)
95         return putcmd(cmd, guard, {action = "kpress", kcb = keyspec})
96     end
97     
98     function p.kpress_wait(keyspec, cmd, guard)
99         return putcmd(cmd, guard, {action = "kpress_wait", kcb = keyspec})
100     end
101     
102     local function mact(act_, kcb_, cmd, guard)
103         local st, en, kcb2_, area_=string.find(kcb_, "([^@]*)@(.*)")
104         return putcmd(cmd, guard, {
105             action = act_,
106             kcb = (kcb2_ or kcb_),
107             area = area_,
108         })
109     end
110     
111     function p.mclick(buttonspec, cmd, guard)
112         return mact("mclick", buttonspec, cmd, guard)
113     end
114     
115     function p.mdblclick(buttonspec, cmd, guard)
116         return mact("mdblclick", buttonspec, cmd, guard)
117     end
118     
119     function p.mpress(buttonspec, cmd, guard)
120         return mact("mpress", buttonspec, cmd, guard)
121     end
122
123     function p.mdrag(buttonspec, cmd, guard)
124         return mact("mdrag", buttonspec, cmd, guard)
125     end
126     
127     function p.defbindings(context, bnd)
128         if not bindings[context] then
129             bindings[context]=bnd
130         else
131             for _, v in ipairs(bnd) do
132                 table.insert(bindings[context], v)
133             end
134         end
135     end
136
137     local function dummy() 
138     end
139     
140     p.defmenu=dummy
141     p.defctxmenu=dummy
142     p.menuentry=dummy
143     p.submenu=dummy
144
145     p.ioncore={ set=dummy }
146     
147     local env=setmetatable({}, {
148         __index=p, 
149         __newindex=function(x) 
150                        error("Setting global "..tostring(x))
151                    end,
152     })
153     setfenv(fn, env)
154     fn()
155     return bindings
156 end
157
158 local function parsefile(f, bindings)
159     local fn, err=loadfile(f)
160     if not fn then
161         error(err)
162     end
163     
164     return dobindings(fn, bindings)
165 end
166     
167 -- }}}
168
169
170 -- Binding output {{{
171
172 local function docgroup_bindings(bindings)
173     local out={}
174     local outi=0
175     
176     local function parsetable(t, prefix)
177         for _, v in ipairs(t) do
178             if v.kcb then
179                 v.kcb=string.gsub(v.kcb, "AnyModifier%+", "")
180             end
181             if v.action=="doc" then
182                 outi=outi+1
183                 out[outi]={doc=v.text, bindings={}}
184             elseif v.submap then
185                 parsetable(v.submap, prefix..v.kcb.." ")
186             else
187                 assert(out[outi])
188                 v.kcb=prefix..v.kcb
189                 table.insert(out[outi].bindings, v)
190             end
191         end
192     end
193     
194     parsetable(bindings, "")
195     
196     return out
197 end
198
199
200 local function combine_bindings(v)    
201     local nact={
202         ["mpress"]=TR("press"),
203         ["mclick"]=TR("click"),
204         ["mdrag"]=TR("drag"),
205         ["mdblclick"]=TR("double click"),
206     }
207     local first=true
208     local s=""
209     for _, b in ipairs(v.bindings) do
210         if not first then
211             s=s..', '
212         end
213         first=false
214         if b.action=="kpress" or b.action=="kpress_wait" then
215             s=s..b.kcb
216         else
217             if not b.area then
218                 s=s..TR("%s %s", b.kcb, nact[b.action])
219             else
220                 s=s..TR("%s %s at %s", b.kcb, nact[b.action], b.area)
221             end
222         end
223     end
224     
225     return s
226 end    
227
228 local function write_bindings_man(db)
229     local function write_binding_man(v)
230         return '.TP\n.B '..combine_bindings(v)..'\n'..gettext(v.doc)..'\n'
231     end
232     
233     local s=""
234     
235     for _, v in ipairs(db) do
236         if #(v.bindings)>0 then
237             s=s..write_binding_man(v)
238         end
239     end
240     
241     return s
242 end
243
244 -- }}}
245
246 -- Main {{{
247
248 local infile
249 local outfile
250 local bindings={}
251 local replaces={}
252
253 local function doargs(a)
254     local i=1
255     while i<=#a do
256         if a[i]=='-o' then
257             outfile=a[i+1]
258             i=i+2
259         elseif a[i]=='-i' then
260             infile=a[i+1]
261             i=i+2
262         elseif a[i]=='-D' then
263             replaces[a[i+1]]=a[i+2]
264             i=i+3
265         elseif a[i]=='-po' then
266             read_translations(a[i+1])
267             i=i+2
268         else
269             parsefile(a[i], bindings)
270             i=i+1
271         end
272     end
273 end
274
275 doargs(arg)
276
277 local f, err=io.open(infile)
278 if not f then
279     error(err)
280 end
281
282 local of, oerr=io.open(outfile, 'w+')
283 if not of then
284     error(oerr)
285 end
286
287 for l in f:lines() do
288     l=string.gsub(l, '%s*BINDINGS:([%w%.%-]+)%s*', 
289                   function(s)
290                       if not bindings[s] then
291                           --error('No bindings for '..s)
292                           return "?"
293                       end
294                       local db=docgroup_bindings(bindings[s])
295                       return write_bindings_man(db)
296                   end)
297     
298     for pat, rep in pairs(replaces) do
299         l=string.gsub(l, pat, rep)
300     end
301     
302     of:write(l..'\n')
303 end
304
305 -- }}}
306