iconv: Bail out of the loop when an illegal sequence of bytes occurs.
[elinks/elinks-j605.git] / doc / lua-scripting.txt
blob5cda553dc29ee1fc26e1d1d9125794f60d8261b6
1 [[lua-scripting]]
2 Scripting ELinks with Lua
3 -------------------------
5 This file documents the Lua scripting interface of the ELinks web browser.
7 Introduction
8 ~~~~~~~~~~~~
10 What is it
11 ^^^^^^^^^^
13 Lua scripting capabilities permit users to customize the ELinks behaviour to
14 unusual degree - they allow automatic rewriting of HTML code of the received
15 documents, rewriting of the URLs entered by user etc. You can even write your
16 own bookmarks system with Lua. See also contrib/lua/ for some examples of the
17 possibilities of ELinks Lua support.
19 Please do not confuse Lua scripting with JavaScript, EcmaScript, VBScript and
20 similar. Those are embedded in page, allowing per-document scripting related
21 to its presentation and providing some degree of interactivity etc. On the
22 contrary, the current Lua support permits scripts to be embedded to the
23 browser directly, changing the behaviour of the browser, not the document.
25 The original Lua support (in the form of Links-Lua fork of original Links) was
26 written by Peter Wang and Cliff Cunnington.  There are some rough edges
27 remaining, but is suitable for everyday use (I have been using it every day
28 for a year).
30 Where to get it
31 ^^^^^^^^^^^^^^^
33 The Lua scripting support comes with the stock ELinks distribution, no
34 additional patches and tweaks should be needed.
36 The web site of the original Links-Lua is at
37 http://links.sourceforge.net/links-lua/[]. Some older patches against
38 regular Links are available at
39 http://www.sourceforge.net/projects/links/[], but they are not being
40 maintained.
42 Lua can be found at http://www.lua.org/[].
44 What it runs on
45 ^^^^^^^^^^^^^^^
47 The Lua support has only been tested under Linux, although it *should*
48 work under other platforms that ELinks and Lua support (perhaps with some
49 changes to source code?).
51 Also, note that many of the scripts given here assume a Unix system.
52 Your mileage will definitely vary on other platforms.
55 Installing
56 ~~~~~~~~~~
58 Installing Lua
59 ^^^^^^^^^^^^^^
61 Before you can compile ELinks with Lua support, you must compile and install
62 Lua.  The following instructions are for a Linux system.  People on other
63 systems should try to enable `popen` support, but this is not necessary
64 (you will lose a bit of functionality though).
66 1. Download and unpack the Lua `tar.gz` or `zip` somewhere.
67 2. `cd` into the `lua` directory.
68 3. Open `config` in a text editor and uncomment the `POPEN` line.
69 4. Optionally, change the `INSTALL_ROOT line.
70 5. Run `make; make so; make sobin; make install`.  
72 On systems without shared object support, simply run `make; make install`
73 instead.
75 Since ELinks 0.11.0, only version 5.0 of Lua is supported.
76 Future versions of ELinks will probably support Lua 5.1 too;
77 see http://bugzilla.elinks.cz/show_bug.cgi?id=742[bug 742].
80 Installing ELinks
81 ^^^^^^^^^^^^^^^^^
83 Follow the instructions for building ELinks (it is the standard
84 `./configure; make; make install` procedure).  During the configure
85 step make sure that Lua has been detected on your system.
88 Running ELinks with Lua
89 ^^^^^^^^^^^^^^^^^^^^^^^
91 Simply start ELinks as you normally would.  To check you have Lua support
92 compiled in, open up the "Help | About" dialog box.  It should list
93 "Scripting (Lua)" under "Features".
94 If not, make sure you do not have other copies of ELinks
95 running, or start ELinks again with the "-no-connect" option on the
96 command-line.
99 Using ELinks with Lua
100 ~~~~~~~~~~~~~~~~~~~~~
102 Out of the box, ELinks with Lua will do nothing different from regular ELinks.
103 You need to write some scripts.
105 ELinks Lua additions
106 ^^^^^^^^^^^^^^^^^^^^
108 The Lua support is based on the idea of *hooks*.  A hook is a function that
109 gets called at a particular point during the execution of ELinks.  To make
110 ELinks do what you want, you can add and edit such hooks.
112 The Lua support also adds an extra dialog box, which you can open while in
113 ELinks with the comma (`,`) key.  Here you can enter Lua expressions for
114 evaluation, or override it to do something different.
116 And finally, you can bind keystrokes to Lua functions.  These keystrokes
117 won't let you do any more than is possible with the Lua Console, but
118 they're more convenient.
120 Note that this document assumes you have some knowledge of programming in Lua.
121 For that, you should refer to the Lua reference manual
122 (http://www.lua.org/docs.html[]). In fact, the language is relatively
123 trivial, though. You could already do wonders with simply refactoring the
124 example scripts.
126 Config file
127 ^^^^^^^^^^^
129 On startup, ELinks reads in two Lua scripts.  Firstly, a system-wide
130 configuration file called `/etc/elinks/hooks.lua`, then a file in your home
131 directory called `~/.elinks/hooks.lua`.  From these files, you can include
132 other Lua files with `dofile`, if necessary.
134 To see what kind of things you should put in here, look at
135 `contrib/lua/hooks.lua`.
137 Hooks
138 ^^^^^
140 The following hooks are available.
142 goto_url_hook (url, current_url)::
143         This hook is called when the user enters a string into the "Go to URL"
144         dialog box.  It is given the string entered, and the current URL
145         (which may be `nil`).  It should return a string, which is the URL
146         that ELinks should follow, or `nil` to cancel the operation.
148 follow_url_hook (url)::
149         This hook is passed the URL that ELinks is about to follow.  It should
150         return a string (the URL modified or unmodified), or `nil` to stop
151         ELinks following the URL
153 pre_format_html_hook (url, html)::
154         This hook gets called just before the final time an HTML document is
155         formatted, i.e. it only gets called once, after the entire document is
156         downloaded.  It will be passed the URL and HTML text as strings, and
157         should return the modified HTML text, or `nil` if there were no
158         modifications.
160 proxy_for_hook (url)::
161         This hook is called when ELinks is about to load a resource
162         from a URL.  It should return "PROXY:PORT" (e.g. "localhost:8080")
163         to use the specified proxy, "" to contact the origin server
164         directly, or `nil` to use the default proxy of the protocol.
166 lua_console_hook (string)::
167         This hook is passed the string that the user entered into the "Lua
168         Console" dialog box.  It should return two values: the type of action
169         to take (`run`, `eval`, `goto-url` or `nil`), and
170         a second argument, which is the shell command to run or the Lua
171         expression to evaluate. Examples:
172          - `return "run", "someprogram"` will attempt to run the program
173            `someprogram`.
174          - `return "eval", "somefunction(1+2)"` will attempt to call the Lua
175            function `somefunction` with an argument, 3.
176          - `return "goto_url", "http://www.bogus.com"` will ask ELinks to visit
177            the URL "http://www.bogus.com".
178          - `return nil` will do nothing.
180 quit_hook ()::
181         This hook is run just before ELinks quits.  It is useful for cleaning
182         up things, such as temporary files you have created.
185 Functions
186 ^^^^^^^^^
188 As well as providing hooks, ELinks provides some functions in addition to the
189 standard Lua functions.
191 NOTE: The standard Lua function `os.setlocale` affects ELinks' idea of
192 the system locale, which ELinks uses for the "System" charset, for the
193 "System" language, and for formatting dates.  This may however have to
194 be changed in a future version of ELinks, in order to properly support
195 terminal-specific system locales.
197 current_url ()::
198         Returns the URL of the current page being shown (in the ELinks session
199         that invoked the function).
201 current_link ()::
202         Returns the URL of the currently selected link, or `nil` if none is
203         selected.
205 current_title ()::
206         Returns the title of the current page, or `nil` if none.
208 current_document ()::
209         Returns the current document as a string, unformatted.
211 current_document_formatted ([width])::
212         Returns the current document, formatted for the specified screen
213         width.  If the width is not specified, then the document is formatted
214         for the current screen width (i.e. what you see on screen).  Note that
215         this function does *not* guarantee all lines will be shorter than
216         `width`, just as some lines may be wider than the screen when
217         viewing documents online.
219 pipe_read (command)::
220         Executes `command` and reads in all the data from stdout, until there
221         is no more.  This is a hack, because for some reason the standard Lua
222         function `file:read` seems to crash ELinks when used in pipe-reading
223         mode.
225 execute (string)::
226         Executes shell commands `string` without waiting for it to exit.  Beware
227         that you must not read or write to stdin and stdout.  And unlike the
228         standard Lua function `os.execute`, the return value is meaningless.
230 tmpname ()::
231         Returns a unique name for a temporary file, or `nil` if no
232         such name is available.  The returned string includes the
233         directory name.  Unlike the standard Lua function
234         `os.tmpname`, this one generates ELinks-related names
235         (currently with "elinks" at the beginning of the name).
237 WARNING: The `tmpname` function does not create the file and does not
238         guarantee exclusive access to it: the caller must handle the
239         possibility that another process creates the file and begins
240         using it while this function is returning.  Failing to do this
241         may expose you to symlink attacks by other users.  To avoid
242         the risk, use `io.tmpfile` instead; unfortunately, it does not
243         tell you the name of the file.
245 bind_key (keymap, keystroke, function)::
246         Currently, `keymap` must be the string `"main"`.  Keystroke is a
247         keystroke as you would write it in the ELinks config file
248         `~/.elinks/elinks.conf`.  The function `function` should take no
249         arguments, and should return the same values as `lua_console_hook`.
251 edit_bookmark_dialog (cat, name, url, function)::
252         Displays a dialog for editing a bookmark, and returns without
253         waiting for the user to close the dialog.  The return value is
254         `1` if successful, `nil` if arguments are invalid, or nothing
255         at all if out of memory.  The first three arguments
256         must be strings, and the user can then edit them in input
257         fields.  There are also 'OK' and 'Cancel' buttons in the
258         dialog.  If the user presses 'OK', ELinks calls `function`
259         with the three edited strings as arguments, and it should
260         return similar values as in `lua_console_hook`.
262 xdialog (string [, more strings...], function)::
263         Displays a generic dialog for editing multiple strings, and
264         returns without waiting for the user to close the dialog.
265         The return value is `1` if successful, `nil` if arguments are
266         invalid, or nothing at all if out of memory.  All arguments
267         except the last one must be strings, and ELinks places them
268         in input fields in the dialog.  There can be at most 5 such
269         strings.  There are also 'OK' and 'Cancel' buttons in the
270         dialog.  If the user presses 'OK', ELinks calls `function`
271         with the edited strings as arguments, and it should return
272         similar values as in `lua_console_hook`.
274 set_option (option, value)::
275         Sets an ELinks option.  The first argument `option` must be
276         the name of the option as a string.  ELinks then tries to
277         convert the second argument `value` to match the type of the
278         option.  If successful, `set_option` returns `value`, else
279         `nil`.
281 get_option (option)::
282         Returns the value of an ELinks option.  The argument `option`
283         must be the name of the option as a string.  If the option
284         does not exist, `get_option` returns `nil`.
287 Variables
288 ^^^^^^^^^
290 elinks_home::
291         The name of the ELinks home directory, as a string.  Typically
292         this is the .elinks subdirectory of the user's home directory.
295 User protocol
296 ^^^^^^^^^^^^^
298 There is one more little thing which Links-Lua adds, which will not be
299 described in detail here.  It is the fake "user:" protocol, which can be used
300 when writing your own addons.  It allows you to generate web pages containing
301 links to "user://blahblah", which can be intercepted by the `follow_url_hook`
302 (among other things) to perform unusual actions.  For a concrete example, see
303 the bookmark addon.
306 Example recipes
307 ~~~~~~~~~~~~~~~
309 This chapter contains some example scripts that you can use.  All of them come
310 from `contrib/lua/hooks.lua`.  I really recommend you to see it directly
311 instead of copying code out of this document.  Also, not everything in there is
312 covered here.
314 If you would like to contribute scripts, that would be great!  Please send
315 them to me at mailto:tjaden@users.sourceforge.net[].  Cliff and I plan to
316 start a script repository, provided we get some contributions.  As for script
317 ideas, you'll just have to be a little creative :-)
319 Also take a look at the `contrib/lua/` directory in the ELinks distribution.
320 Note that Peter and Cliff don't maintain the Lua support intensively anymore,
321 thus it would be probably nice to Cc me (mailto:pasky@ucw.cz[]) if you want
322 to contribute some patch, so that I would be able to add it to the ELinks
323 distribution.
326 Go to URL on steroids
327 ^^^^^^^^^^^^^^^^^^^^^
329 There are some web sites that I visit often.  Bookmarks are okay, but they are
330 separate from the "Go to URL" dialog box, so I keep forgetting to use them.
331 Also, when I visit a search engine home page, all I really want to do is enter
332 a search term.
334 The following script allows me to type certain strings into the "Go to URL"
335 dialog box, and it will convert them to the URL I actually want to visit.  As
336 a bonus, it allows me perform some searches on sites like Google without
337 loading up the front page first.
339 TIP: The ``URI rewriting'' feature of ELinks handles many of the same
340 tasks as the Lua hook shown here, and you can conveniently configure
341 it via the option manager.  It is not quite as versatile, though.
343 -------------------------------------------------------------------------------
344 function match (prefix, url)
345     return string.sub (url, 1, string.len (prefix)) == prefix
348 function strip (str)
349     return string.gsub (str, "^%s*(.-)%s*$", "%1")
352 function plusify (str)
353     return string.gsub (str, "%s", "+")
356 function goto_url_hook (url, current_url)
357     -- Google search (e.g. ,gg unix browsers).
358     if match (",gg", url) then
359         url = plusify (strip (string.sub (url, 4)))
360         return "http://www.google.com/search?q="..url.."&btnG=Google+Search"
362     -- Freshmeat search.
363     elseif match (",fm", url) then
364         url = plusify (strip (string.sub (url, 4)))
365         return "http://www.freshmeat.net/search/?q="..url
367     -- Dictionary.com search (e.g. ,dict congenial).
368     elseif match (",dict", url) then
369         url = plusify (strip (string.sub (url, 6)))
370         return "http://www.dictionary.com/cgi-bin/dict.pl?db=%2A&term="..url
372     -- RPM search (e.g. ,rpm links).
373     elseif match (",rpm", url) then
374         url = plusify (strip (string.sub (url, 5)))
375         return "http://www.rpmfind.net/linux/rpm2html/search.php?query="
376                 ..url.."&submit=Search+..."
377         
378     -- Netcraft.com search (e.g. ,whatis www.google.com).
379     elseif match (",whatis", url) then
380         url = plusify (strip (string.sub (url, 8)))
381         return "http://uptime.netcraft.com/up/graph/?host="..url
383     -- LinuxToday home page.
384     elseif match (",lt", url) then
385         return "http://linuxtoday.com/"
387     -- Weather forecast for Melbourne, Australia.
388     elseif match (",forecast", url) then
389         return "http://www.bom.gov.au/cgi-bin/wrap_fwo.pl?IDV10450.txt"
391     -- Unmatched
392     else
393         return url
394     end
396 -------------------------------------------------------------------------------
399 Expanding ~ (tilde)
400 ^^^^^^^^^^^^^^^^^^^
402 By adding an extra snippet of code to the previous example, we can make ELinks
403 expand pathnames such as `~/foo/bar`
404 and `~user/zappo`, like in the shell
405 and other Unix programs.
407 -------------------------------------------------------------------------------
408 function goto_url_hook (url, current_url)
409                 .
410                 .
412     -- Expand ~ to home directories.
413     elseif match ("~", url) then
414         if string.sub(url, 2, 2) == "/" then    -- ~/foo
415             return os.getenv ("HOME")..string.sub(url, 2)
416         else                                    -- ~foo/bar
417             return "/home/"..string.sub(url, 2)
418         end
420                 .
421                 .
422 -------------------------------------------------------------------------------
425 Filtering crap
426 ^^^^^^^^^^^^^^
428 Many web pages nowadays have columns to the left and right of the text, which
429 are utterly useless.  If you happen to be viewing the page in a 80x25 screen,
430 the text you want to read ends up crammed into a tiny space in the centre.  We
431 use ELinks Lua support to manipulate the HTML before it reaches the parser.
434 linuxtoday.com
435 ++++++++++++++
437 NOTE: This recipe is out of date for the web site.
439 Linux Today has two problems when viewed in ELinks: the useless columns on the
440 left and the right and all the text appears in cyan.  Here is a quick recipe
441 to fix that:
443 -------------------------------------------------------------------------------
444 -- Plain string.find (no metacharacters)
445 function sstrfind (s, pattern)
446     return string.find (s, pattern, 1, true)
449 function pre_format_html_hook (url, html)
450     -- Strip the left and right columns from Linux Today pages
451     -- and change the font colour to white.
452     if sstrfind (url, "linuxtoday.com") then
453         if sstrfind (url, "news_story") then
454             html = string.gsub (html, '<TABLE CELLSPACING="0".-</TABLE>', '', 1)
455             html = string.gsub (html, '<TR BGCOLOR="#FFF.-</TR></TABLE>', '', 1)
456         else
457             html = string.gsub (html, 'WIDTH="120">\n<TR.+</TABLE></TD>', '>', 1)
458         end
459         html = string.gsub (html, '<A HREF="http://www.internet.com.-</A>', '')
460         html = string.gsub (html, "<IFRAME.-</IFRAME>", "")
461         -- emphasis in text is lost
462         return string.gsub (html, 'text="#002244"', 'text="#001133"', 1)
463     end
465     return nil
467 -------------------------------------------------------------------------------
469 linuxgames.com
470 ++++++++++++++
472 NOTE: This recipe is out of date for the web site.
474 Here is a simpler example, for link:http://www.linuxgames.com/[].
476 -------------------------------------------------------------------------------
477 function pre_format_html_hook (url, html)
478                 .
479                 .
481     elseif string.find (url, "linuxgames.com", 1, true) then
482         return string.gsub (html, "<CENTER>.-</center>", "", 1)
484                 .
485                 .
486 -------------------------------------------------------------------------------
489 Reading gzipped files
490 ^^^^^^^^^^^^^^^^^^^^^
492 NOTE: ELinks already supports gzipped files natively.
494 Sometimes documents come gzipped in order to save space, but then you need to
495 uncompress them to read them with ELinks.  Here is a recipe to handle gzipped
496 files on a Unix system.
498 WARNING: This recipe opens a temporary file insecurely.
500 -------------------------------------------------------------------------------
501 function pre_format_html_hook (url, html)
502                 .
503                 .
505     -- Handle gzip'd files within reasonable size.
506     if string.find (url, "%.gz$") and string.len (html) < 65536 then
507         local name = tmpname ()
508         local file = io.open (name, "wb")
509         file:write (html)
510         file:close ()
511         html = pipe_read ("(gzip -dc "..name.." || cat "..name..") 2>/dev/null")
512         os.remove (name)
513         return html
514     end
516                 .
517                 .
518 -------------------------------------------------------------------------------
521 Printing
522 ^^^^^^^^
524 Printing a web page with ELinks usually involves quite a few steps: Save the
525 current document onto disk.  Run it through ELinks on the command-line (so it
526 fits into 80 columns) to generate a plain text version.  Remove the 80th
527 column from the text version, as it will make printers wrap down to the next
528 line.  Finally, run the processed file through `lpr', then delete it.
530 The following functions allow you to print web pages directly from ELinks,
531 using `lpr' or `enscript'.  Type `lpr()` or `enscript()` in the Lua Console to
532 run them.  (In the `hooks.lua`, I have also made it so you can just type `lpr`
533 or `enscript`.)
535 NOTE: The `io.popen` function is not available on all platforms.
537 -------------------------------------------------------------------------------
538 function pipe_formatted_to (program)
539     local lp, errmsg = io.popen (program, "w")
540     if lp == nil then
541         error (errmsg)
542     else
543         lp:write (current_document_formatted (79))
544         lp:close ()
545     end
548 -- Send the current document to `lpr'.
549 function lpr ()
550     pipe_formatted_to ("lpr")
553 -- Send the current document to `enscript'.
554 function enscript ()
555     pipe_formatted_to ("enscript -fCourier8")
557 -------------------------------------------------------------------------------
560 Deferring to Netscape
561 ^^^^^^^^^^^^^^^^^^^^^
563 If you come across a brain-dead web page that is totally unreadable with
564 ELinks, you'd probably want to open it with a graphical browser.  The
565 following function opens the current document in Netscape.
567 TIP: You can also use the built-in ``URI passing'' feature for this.
569 -------------------------------------------------------------------------------
570 -- When starting Netscape: Set to `nil' if you do not want
571 -- to open a new window for each document.
572 netscape_new_window = 1
574 -- Open current document in Netscape.
575 function netscape ()
576     local new = netscape_new_window and ",new_window" or ""
577     execute ("( netscape -remote 'openURL("..current_url ()..new..")'"
578              .." || netscape '"..current_url ().."' ) 2>/dev/null &")
580 -------------------------------------------------------------------------------
583 Alternative bookmark system
584 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
586 Many people would like to have a bookmark system with categories (note that
587 ELinks already supports that, marketing name Hierarchical bookmarks), and also
588 to be able to view them and search for them in an HTML page.  I have written
589 an alternative bookmark system (for ELinks), which some people may like better
590 than the standard bookmark system.  
593 More ideas
594 ^^^^^^^^^^
596  - The Lua interface needs to be redesigned to provide more flexible, coherent
597    and usable interface to the scripts.
599  - Cliff Cunnington had a neat idea of clipping text that you see in web pages
600    (you enter a regexp that will match the start and end of the text you want
601    to clip), and saving the text to disk, along with the URL and timestamp.
602    This would help if you find that you can't ever remember where you had seen
603    a piece of text, or if you want to keep a piece of information but don't
604    need to save the entire page.
606  - People who use download management programs could write a function to send
607    the current link to their favourite downloading program.
609  - If you wrote a small C program to put text into the X11 selection
610    clipboard, you could pass the current link or URL to that program, to make
611    it easier to paste URLs into other windows.  It might be possible to do the
612    same with GPM, or the KDE/GNOME equivalents.
614  - Send the current page to Babelfish for translation.
616  - Look for stupid JavaScript URLs and convert them to something usable.
618  - More things are possible, I'm sure.  If you have an idea that requires
619    another hook or function, contact me (Peter Wang) and I'll see what I can
620    do.