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 ----------------------------------------------------------------------
15 function writeto (name
)
17 local f
, err
, cod
= io
.close(_OUTPUT
)
21 local f
, err
, cod
= io
.open(name
, "w")
22 _OUTPUT
= f
or _OUTPUT
29 if type(arg
[1]) == 'userdata' then
30 f
= table.remove(arg
, 1)
32 return f
:write(unpack(arg
))
37 if type(arg
[1]) == 'userdata' then
38 f
= table.remove(arg
, 1)
40 return f
:read(unpack(arg
))
44 if not f
then _ALERT(err
); return end
46 if not a
then _ALERT(b
); return nil
51 function dostring(s
) return do_(loadstring(s
)) end
52 function dofile(s
) return do_(loadfile(s
)) end
54 ----------------------------------------------------------------------
56 ----------------------------------------------------------------------
58 function file_exists(filename
)
59 local f
= io
.open(filename
, "r")
67 function dofile_if_fileexists(filename
)
68 if file_exists(filename
) then dofile(filename
) 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 ----------------------------------------------------------------------
78 ----------------------------------------------------------------------
80 pre_format_html_hooks
= {n
=0}
81 function pre_format_html_hook (url
, html
)
84 table.foreachi(pre_format_html_hooks
,
86 local new
,stop
= fn(url
,html
)
88 if new
then html
=new changed
=1 end
92 return changed
and html
95 goto_url_hooks
= {n
=0}
96 function goto_url_hook (url
, current_url
)
97 table.foreachi(goto_url_hooks
,
99 local new
,stop
= fn(url
, current_url
)
109 follow_url_hooks
= {n
=0}
110 function follow_url_hook (url
)
111 table.foreachi(follow_url_hooks
,
113 local new
,stop
= fn(url
)
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)
140 return string.gsub (s
, pat
, repl
, n
)
142 return string.gsub (s
, pat
, repl
)
147 ----------------------------------------------------------------------
149 ----------------------------------------------------------------------
151 function match (prefix
, url
)
152 return string.sub (url
, 1, string.len (prefix
)) == prefix
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.
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
)
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
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
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
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
)
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",
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",
322 rfc
= "http://www.rfc-editor.org/rfc/rfc%s.txt",
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
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
368 error('smartprefix "'..nick
..'" has unsupported type "'
369 ..type(smartprefixes
[nick
])..'".')
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
)
394 if not mangle_blank_alt
then return nil,nil end
396 html
, n
= gisub (html
, '(<img[^>]-) alt=""', '%1 alt=" "')
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
)
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
)
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)
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)
441 table.insert(pre_format_html_hooks
, mangle_linuxtoday
)
444 function mangle_dictionary_dot_com (url
, html
)
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)
453 -- we've already mangled this page before
457 html
= "<html><head><title>Dictionary.com lookup</title></head>"..
458 "<body><table border=0 cellpadding=5>"..t
.t
.."</table>"..
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")
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
)
484 if not string.find (url
, "%.gz$") or string.len (html
) >= 65536 then
489 writeto (tmp
) write (html
) writeto ()
490 html
= pipe_read ("(gzip -dc "..tmp
.." || cat "..tmp
..") 2>/dev/null")
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.
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.
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 ()",
527 function lua_console_hook (expr
)
528 local x
= console_hook_functions
[expr
]
529 if type (x
) == "function" then
532 return "eval", x
or expr
537 ----------------------------------------------------------------------
539 ----------------------------------------------------------------------
541 -- We need to delete the temporary files that we create.
542 if not tmp_files
then
546 function delete_tmp_files ()
547 if tmp_files
and os
.remove then
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