pl.po: update
[elinks.git] / contrib / lua / hooks.lua.in
blobc0283d40d78b4daacad64c2f90b9dfd32437659d
1 -- Example hooks.lua file, put in ~/.elinks/ as hooks.lua.
3 -- TODO: Bookmarks stuff should be completely moved to bm.lua. --pasky
5 -- Take care about @SOMETHING@, we're processed with autoconf!
7 ----------------------------------------------------------------------
8 -- Compatibility routines for Lua 4 code.
9 -- Taken from Lua's compat.lua.
10 ----------------------------------------------------------------------
12 _INPUT = io.stdin
13 _OUTPUT = io.stdout
15 function writeto (name)
16 if name == nil then
17 local f, err, cod = io.close(_OUTPUT)
18 _OUTPUT = io.stdout
19 return f, err, cod
20 else
21 local f, err, cod = io.open(name, "w")
22 _OUTPUT = f or _OUTPUT
23 return f, err, cod
24 end
25 end
27 function write (...)
28 local f = _OUTPUT
29 if type(arg[1]) == 'userdata' then
30 f = table.remove(arg, 1)
31 end
32 return f:write(unpack(arg))
33 end
35 function read (...)
36 local f = _INPUT
37 if type(arg[1]) == 'userdata' then
38 f = table.remove(arg, 1)
39 end
40 return f:read(unpack(arg))
41 end
43 function do_ (f, err)
44 if not f then _ALERT(err); return end
45 local a,b = pcall(f)
46 if not a then _ALERT(b); return nil
47 else return b or true
48 end
49 end
51 function dostring(s) return do_(loadstring(s)) end
52 function dofile(s) return do_(loadfile(s)) end
54 ----------------------------------------------------------------------
55 -- Load configuration
56 ----------------------------------------------------------------------
58 function file_exists(filename)
59 local f = io.open(filename, "r")
60 if f then
61 io.close(f)
62 return 1
63 end
64 return nil
65 end
67 function dofile_if_fileexists(filename)
68 if file_exists(filename) then dofile(filename) end
69 end
71 dofile_if_fileexists ("@sysconfdir@/config.lua")
72 home_dir = (os.getenv ("HOME") or "/home/"..os.getenv("USER")) or "."
73 hooks_file = elinks_home.."/hooks.lua" -- for reload()
74 dofile_if_fileexists (elinks_home.."/config.lua")
76 ----------------------------------------------------------------------
77 -- hooks
78 ----------------------------------------------------------------------
80 pre_format_html_hooks = {n=0}
81 function pre_format_html_hook (url, html)
82 local changed = nil
84 table.foreachi(pre_format_html_hooks,
85 function (i, fn)
86 local new,stop = fn(url,html)
88 if new then html=new changed=1 end
89 return stop
90 end)
92 return changed and html
93 end
95 goto_url_hooks = {n=0}
96 function goto_url_hook (url, current_url)
97 table.foreachi(goto_url_hooks,
98 function (i, fn)
99 local new,stop = fn(url, current_url)
101 url = new
103 return stop
104 end)
106 return url
109 follow_url_hooks = {n=0}
110 function follow_url_hook (url)
111 table.foreachi(follow_url_hooks,
112 function (i, fn)
113 local new,stop = fn(url)
115 url = new
117 return stop
118 end)
120 return url
123 quit_hooks = {n=0}
124 function quit_hook (url, html)
125 table.foreachi(quit_hooks, function (i, fn) return fn() end)
128 ----------------------------------------------------------------------
129 -- case-insensitive string.gsub
130 ----------------------------------------------------------------------
132 -- Please note that this is not completely correct yet.
133 -- It will not handle pattern classes like %a properly.
134 -- FIXME: Handle pattern classes.
136 function gisub (s, pat, repl, n)
137 pat = string.gsub (pat, '(%a)',
138 function (v) return '['..string.upper(v)..string.lower(v)..']' end)
139 if n then
140 return string.gsub (s, pat, repl, n)
141 else
142 return string.gsub (s, pat, repl)
147 ----------------------------------------------------------------------
148 -- goto_url_hook
149 ----------------------------------------------------------------------
151 function match (prefix, url)
152 return string.sub (url, 1, string.len (prefix)) == prefix
155 function hx (c)
156 return string.char((c >= 10 and (c - 10) + string.byte ('A')) or c + string.byte ('0'))
159 function char2hex (c)
160 return '%'..hx (string.byte (c) / 16)..hx (math.mod(string.byte (c), 16))
163 function escape (str)
164 return string.gsub (str, "(%W)", char2hex)
167 -- You can write smt like "gg" to goto URL dialog and it'll go to google.com.
169 -- Note that this is obsoleted by the URI rewrite plugin.
171 dumbprefixes = {
172 arc = "http://web.archive.org/web/*/%c",
173 b = "http://babelfish.altavista.com/babelfish/tr",
174 bz = "http://bugzilla.elinks.cz",
175 bug = "http://bugzilla.elinks.cz",
176 d = "http://www.dict.org",
177 g = "http://www.google.com/",
178 gg = "http://www.google.com/",
179 go = "http://www.google.com/",
180 fm = "http://www.freshmeat.net/",
181 sf = "http://www.sourceforge.net/",
182 dbug = "http://bugs.debian.org/",
183 dpkg = "http://packages.debian.org/",
184 -- Hm, is this Debian-centric? -- Miciah
185 lua = "file:///usr/share/doc/lua40-doc/manual/idx.html",
186 pycur = "http://www.python.org/doc/current/",
187 pydev = "http://www.python.org/dev/doc/devel/",
188 pyhelp = "http://starship.python.net/crew/theller/pyhelp.cgi",
189 pyvault = "http://www.vex.net/parnassus/",
190 e2 = "http://www.everything2.org/",
191 sd = "http://www.slashdot.org/",
192 vhtml = "http://validator.w3.org/check?uri=%c",
193 vcss = "http://jigsaw.w3.org/css-validator/validator?uri=%c",
196 function debian_package (url, t)
197 url = string.gsub(url, '(%w+):(%w+)', function (key, val) t[key] = val end)
199 return 'http://packages.debian.org/cgi-bin/search_contents.pl?word='
200 ..escape(string.gsub(url, '%s*([^%s]+)%s*', '%1'))
201 ..'&searchmode='..(t.searchmode or 'searchfilesanddirs')
202 ..'&case='..(t.case or 'insensitive')
203 ..'&version='..(t.version or pipe_read('test -r /etc/debian_version && cut -d/ -f1 /etc/debian_version | tr -d \\\\n || echo stable') or 'stable')
204 ..'&arch='..(t.arch or pipe_read('test -x /usr/bin/dpkg-architecture && dpkg-architecture -qDEB_HOST_ARCH | tr -d \\\\n || echo i386'))
207 function debian_contents (url)
208 return debian_package (url, { searchmode = "filelist" })
211 function debian_file (url)
212 return debian_package (url, { searchmode = "searchfilesanddirs" })
215 function cvsweb (base, project, url)
216 local t = {n=0}
217 local file, old, new
218 local replacements
220 -- allow <file>:<revision>[-><revision>]
221 url,replacements = string.gsub(url, "^(.*):(.*)->(.*)$", "%1 %2 %3")
222 if replacements == 0 then url = string.gsub(url, "^(.*):(.*)$", "%1 %2") end
224 -- split into words
225 string.gsub(url, "([^%s]+)", function (w) table.insert(t, w) end)
226 file, old, new = t[1], t[2], t[3]
228 if t[4] then error('this smartprefix takes only one to three arguments') return nil end
229 if not file then error('no file given') return nil end
231 if new then return base..project.."/"..file..".diff?r1="..old.."&r2="..new.."&f=u"
232 elseif old then return base.."~checkout~/"..project.."/"..file..(old ~= "latest" and "?rev="..old or "")
233 else return base..project.."/"..file
237 function gmane (url)
238 local group, words
240 _,_,group,words = string.find(url, "([^%s]+)%s%s*(.*)$")
242 if not words then return nil end
244 return "http://search.gmane.org/search.php?query="..words.."&group="..group
247 -- You can write "gg:foo" or "gg foo" to goto URL dialog and it'll ask google
248 -- for it automagically.
250 -- Note that this is _mostly_ obsoleted by the URI rewrite plugin. (It can't do the
251 -- metas, though.)
253 function bugzilla (base_url, arguments)
254 if not arguments or arguments == '' then return base_url end
256 if string.find(arguments, '^[%d]+$') then
257 return base_url..'show_bug.cgi?id='..arguments
260 return base_url..'buglist.cgi?short_desc_type=allwordssubstr'
261 ..'&short_desc='..escape(arguments)
264 smartprefixes = {
265 arc = "http://web.archive.org/web/*/%s",
266 bug = function (url) return bugzilla('http://bugzilla.elinks.cz/', url) end,
267 cambridge = "http://dictionary.cambridge.org/results.asp?searchword=%s",
268 cliki = "http://www.cliki.net/admin/search?words=%s",
269 -- If you want to add a smartprefix for another project's CVSweb,
270 -- just create a lambda like this. Aren't high-level languages fun?
271 cvs = function (x) return cvsweb ("http://cvsweb.elinks.cz/cvsweb.cgi/", "elinks", x) end,
272 d = "http://www.dict.org/bin/Dict?Query=%s&Form=Dict1&Strategy=*&Database=*&submit=Submit+query",
273 debcontents = debian_contents,
274 debfile = debian_file,
275 dmoz = "http://search.dmoz.org/cgi-bin/search?search=%s",
276 foldoc = "http://wombat.doc.ic.ac.uk/foldoc/foldoc.cgi?%s",
277 g = "http://www.google.com/search?q=%s&btnG=Google+Search",
278 gd = "http://www.google.com/search?q=%s&cat=gwd/Top",
279 gg = "http://www.google.com/search?q=%s&btnG=Google+Search",
280 -- Whose idea was it to use 'gg' for websearches? -- Miciah
281 --gg = "http://groups.google.com/groups?q=%s",
282 gi = "http://images.google.com/images?q=%s",
283 gmane = gmane,
284 gn = "http://news.google.com/news?q=%s",
285 go = "http://www.google.com/search?q=%s&btnG=Google+Search",
286 gwho = "http://www.googlism.com/?ism=%s&name=1",
287 gwhat = "http://www.googlism.com/?ism=%s&name=2",
288 gwhere = "http://www.googlism.com/?ism=%s&name=3",
289 gwhen = "http://www.googlism.com/?ism=%s&name=4",
290 fm = "http://www.freshmeat.net/search/?q=%s",
291 savannah = "http://savannah.nongnu.org/search/?words=%s&type_of_search=soft&exact=1",
292 sf = "http://sourceforge.net/search/?q=%s",
293 sfp = "http://sourceforge.net/projects/%s",
294 sd = "http://www.slashdot.org/search.pl?query=%s",
295 sdc = "http://www.slashdot.org/search.pl?query=%s&op=comments",
296 sdu = "http://www.slashdot.org/search.pl?query=%s&op=users",
297 sdp = "http://www.slashdot.org/search.pl?query=%s&op=polls",
298 sdj = "http://www.slashdot.org/search.pl?query=%s&op=journals",
299 dbug = "http://bugs.debian.org/%s",
300 dpkg = "http://packages.debian.org/%s",
301 emacs = "http://www.emacswiki.org/cgi-bin/wiki.pl?search=%s",
302 lyrics = "http://music.lycos.com/lyrics/results.asp?QT=L&QW=%s",
303 lxr = "http://lxr.linux.no/ident?i=%s",
304 leo = "http://dict.leo.org/?search=%s",
305 onelook = "http://onelook.com/?w=%s&ls=a",
306 py = "http://starship.python.net/crew/theller/pyhelp.cgi?keyword=%s&version=current",
307 pydev = "http://starship.python.net/crew/theller/pyhelp.cgi?keyword=%s&version=devel",
308 pyvault = "http://py.vaults.ca/apyllo.py?find=%s",
309 e2 = "http://www.everything2.org/?node=%s",
310 encz = "http://www.slovnik.cz/bin/ecd?ecd_il=1&ecd_vcb=%s&ecd_trn=translate&ecd_trn_dir=0&ecd_lines=15&ecd_hptxt=0",
311 czen = "http://www.slovnik.cz/bin/ecd?ecd_il=1&ecd_vcb=%s&ecd_trn=translate&ecd_trn_dir=1&ecd_lines=15&ecd_hptxt=0",
312 dict = "http://dictionary.reference.com/search?q=%s",
313 thes = "http://thesaurus.reference.com/search?q=%s",
314 a = "http://acronymfinder.com/af-query.asp?String=exact&Acronym=%s",
315 imdb = "http://imdb.com/Find?%s",
316 mw = "http://www.m-w.com/cgi-bin/dictionary?book=Dictionary&va=%s",
317 mwt = "http://www.m-w.com/cgi-bin/thesaurus?book=Thesaurus&va=%s",
318 whatis = "http://uptime.netcraft.com/up/graph/?host=%s",
319 wiki = "http://www.wikipedia.org/w/wiki.phtml?search=%s",
320 wn = "http://www.cogsci.princeton.edu/cgi-bin/webwn1.7.1?stage=1&word=%s",
321 -- rfc by number
322 rfc = "http://www.rfc-editor.org/rfc/rfc%s.txt",
323 -- rfc search
324 rfcs = "http://www.rfc-editor.org/cgi-bin/rfcsearch.pl?searchwords=%s&format=http&abstract=abson&keywords=keyon&num=25",
325 cr = "http://www.rfc-editor.org/cgi-bin/rfcsearch.pl?searchwords=%s&format=http&abstract=abson&keywords=keyon&num=25",
326 -- Internet Draft search
327 rfcid = "http://www.rfc-editor.org/cgi-bin/idsearch.pl?searchwords=%s&format=http&abstract=abson&keywords=keyon&num=25",
328 urbandict = "http://www.urbandictionary.com/define.php?term=%s",
329 id = "http://www.rfc-editor.org/cgi-bin/idsearch.pl?searchwords=%s&format=http&abstract=abson&keywords=keyon&num=25",
330 draft = "http://www.rfc-editor.org/cgi-bin/idsearch.pl?searchwords=%s&format=http&abstract=abson&keywords=keyon&num=25",
333 -- Expand ~ to home directories.
334 function expand_tilde (url, current_url)
335 if not match ("~", url) then return url,nil end
337 if string.sub(url, 2, 2) == "/" or string.len(url) == 1 then -- ~/foo
338 return home_dir..string.sub(url, 2),true
339 else -- ~foo/bar
340 return "/home/"..string.sub(url, 2),true
343 table.insert(goto_url_hooks, expand_tilde)
346 -- Don't take localhost as directory name
347 function expand_localhost (url)
348 if not match("localhost", url) then return url,nil end
350 return "http://"..url,nil
352 table.insert(goto_url_hooks, expand_localhost)
355 function complete_uri_prefix (url, current_url)
356 if dumbprefixes[url] then
357 return string.gsub(dumbprefixes[url], "%%c", current_url or ""),true
360 if string.find(url,'%s') or string.find(url, ':') then
361 local _,_,nick,val = string.find(url, "^([^%s:]+)[:%s]%s*(.-)%s*$")
362 if nick and smartprefixes[nick] then
363 if type(smartprefixes[nick]) == 'function' then
364 return smartprefixes[nick](val),true
365 elseif type(smartprefixes[nick]) == 'string' then
366 return string.format(smartprefixes[nick], escape(val)),true
367 else
368 error('smartprefix "'..nick..'" has unsupported type "'
369 ..type(smartprefixes[nick])..'".')
370 return url,nil
375 -- Unmatched.
376 return url,nil
378 table.insert(goto_url_hooks, complete_uri_prefix)
381 ----------------------------------------------------------------------
382 -- pre_format_html_hook
383 ----------------------------------------------------------------------
385 -- Plain string.find (no metacharacters).
386 function sstrfind (s, pattern)
387 return string.find (s, pattern, 1, 1)
390 -- Mangle ALT="" in IMG tags.
391 function mangle_blank_alt (url, html)
392 local n
394 if not mangle_blank_alt then return nil,nil end
396 html, n = gisub (html, '(<img[^>]-) alt=""', '%1 alt="&nbsp;"')
398 return ((n > 0) and html), nil
400 table.insert(pre_format_html_hooks, mangle_blank_alt)
403 -- Fix unclosed INPUT tags.
404 function mangle_unclosed_input_tags (url, html)
405 local n
407 html, n = gisub (html, '(<input[^>]-[^=]")<', '%1><')
409 return ((n > 0) and html), nil
411 table.insert(pre_format_html_hooks, mangle_unclosed_input_tags)
414 -- Fix unclosed A tags.
415 function mangle_unclosed_a_tags (url, html)
416 local n
418 html, n = gisub (html, '(<a[^>]-[^=]")<', '%1><')
420 return ((n > 0) and html), nil
422 table.insert(pre_format_html_hooks, mangle_unclosed_a_tags)
425 function mangle_linuxtoday (url, html)
426 if not sstrfind (url, "linuxtoday.com") then return nil,nil end
428 if sstrfind (url, "news_story") then
429 html = string.gsub (html, '<TABLE CELLSPACING="0".-</TABLE>', '', 1)
430 html = string.gsub (html, '<TR BGCOLOR="#FFF.-</TR></TABLE>', '', 1)
431 else
432 html = string.gsub (html, 'WIDTH="120">\n<TR.+</TABLE></TD>', '>', 1)
434 html = string.gsub (html, '<A HREF="http://www.internet.com.-</A>', '')
435 html = string.gsub (html, "<IFRAME.-</IFRAME>", "")
436 -- emphasis in text is lost
437 html = string.gsub (html, 'text="#002244"', 'text="#001133"', 1)
439 return html,true
441 table.insert(pre_format_html_hooks, mangle_linuxtoday)
444 function mangle_dictionary_dot_com (url, html)
445 local t = { t = "" }
446 local n
448 if not sstrfind (url, "dictionary.com/cgi-bin/dict.pl") then return nil,nil end
450 _,n = string.gsub (html, "resultItemStart %-%-%>(.-)%<%!%-%- resultItemEnd",
451 function (x) t.t = t.t.."<tr><td>"..x.."</td></tr>" end)
452 if n == 0 then
453 -- we've already mangled this page before
454 return nil,true
457 html = "<html><head><title>Dictionary.com lookup</title></head>"..
458 "<body><table border=0 cellpadding=5>"..t.t.."</table>"..
459 "</body></html>"
461 return html,true
463 table.insert(pre_format_html_hooks, mangle_dictionary_dot_com)
466 function mangle_allmusic_dot_com (url, html)
467 if not sstrfind (url, "allmusic.com") then return nil,nil end
469 html = string.gsub(html, "javascript:z%('(.-)'%)", "/cg/amg.dll?p=amg&sql=%1")
471 return html,true
473 table.insert(pre_format_html_hooks, mangle_allmusic_dot_com)
476 -- Handle gzip'd files within reasonable size.
477 -- Note that this is not needed anymore since we have a support for this
478 -- in core ELinks. I still keep it here for a reference (as an example),
479 -- though. If you will add something similiar using pipe_read(), feel free
480 -- to remove this. --pasky
481 function decompress_html (url, html)
482 local tmp
484 if not string.find (url, "%.gz$") or string.len (html) >= 65536 then
485 return nil,nil
488 tmp = tmpname ()
489 writeto (tmp) write (html) writeto ()
490 html = pipe_read ("(gzip -dc "..tmp.." || cat "..tmp..") 2>/dev/null")
491 os.remove (tmp)
493 return html,nil
495 --table.insert(pre_format_html_hooks, decompress_html)
497 ----------------------------------------------------------------------
498 -- Miscellaneous functions, accessed with the Lua Console.
499 ----------------------------------------------------------------------
501 -- Reload this file (hooks.lua) from within Links.
502 function reload ()
503 dofile (hooks_file)
506 -- Helper function.
507 function catto (output)
508 local doc = current_document_formatted (79)
509 if doc then writeto (output) write (doc) writeto () end
512 -- Email the current document, using Mutt (http://www.mutt.org).
513 -- This only works when called from lua_console_hook, below.
514 function mutt ()
515 local tmp = tmpname ()
516 writeto (tmp) write (current_document ()) writeto ()
517 table.insert (tmp_files, tmp)
518 return "run", "mutt -a "..tmp
521 -- Table of expressions which are recognised by our lua_console_hook.
522 console_hook_functions = {
523 reload = "reload ()",
524 mutt = mutt,
527 function lua_console_hook (expr)
528 local x = console_hook_functions[expr]
529 if type (x) == "function" then
530 return x ()
531 else
532 return "eval", x or expr
537 ----------------------------------------------------------------------
538 -- quit_hook
539 ----------------------------------------------------------------------
541 -- We need to delete the temporary files that we create.
542 if not tmp_files then
543 tmp_files = {}
546 function delete_tmp_files ()
547 if tmp_files and os.remove then
548 tmp_files.n = nil
549 for i,v in tmp_files do os.remove (v) end
552 table.insert(quit_hooks, delete_tmp_files)
555 ----------------------------------------------------------------------
556 -- Examples of keybinding
557 ----------------------------------------------------------------------
559 -- Bind Ctrl-H to a "Home" page.
561 -- bind_key ("main", "Ctrl-H",
562 -- function () return "goto_url", "http://www.google.com/" end)
564 -- Bind Alt-p to print.
566 -- bind_key ("main", "Alt-p", lpr)
568 -- Bind Alt-m to toggle ALT="" mangling.
570 bind_key ("main", "Alt-m",
571 function () mangle_blank_alt = not mangle_blank_alt end)
574 -- vim: shiftwidth=4 softtabstop=4