ftblog

:: widerstand zwecklos ::
email jabber gpgkey
hackergotchi

January 21, 2010

interface the web using zsh

Filed under: computer -- 17:48

This has been lingering on my laptop for some time now. For about a year,
actually. If you know surfraw, you know the idea.

If you don't, then imagine you'd like to search something via google real
quick from the command line like this:
lookup google that-thing-i-want-to-know-about

If you think, that's worth having, read on.

"This" is called `zsh-lookup', or `lookup' for short (or `lu' for really
short). It's implemented in zsh and does not share any code with surfraw.
It's licenced under the same terms as zsh is - which is BSD-ish.

Why reinvent the wheel if surfraw exists? Well, since lookup is written
in zsh and not in POSIX shell, it can take advantage of all those features zsh
has to offer. That means, really flexible configuration via `zstyle',
completion based on compsys - context sensitive correctly working for all
shipped backends - and, in my opinion, cleaner code because zsh knows about
arrays and associative arrays (read: hashes). Lookup also has support for
creating aliases for its backends (similar to git aliases); and completion for
those aliases just works. Out of the box.

Surfraw does support more web services than lookup does. A lot more. Something
like 100 vs. 20. I don't care for most of the services that lookup doesn't
implement - which is the reason they aren't implemented in the first place.

Feel free to implement new backends for lookup. The `LOOKUP_be_leo' file should
walk you through most of the questions that may arise during the process. Read
it beforehand. Really. If you'd like to look at a very simple backend, take a
look at the one for `cpan'. More complex backends would be `gmane' and `rfc'.

Now, after a year of using the thing, I'm pretty confident that it works well
enough. I am thinking about submitting it to zsh upstream for inclusion - if
the maintainers think that it's worth it.

For now, you can get the latest code from github:
git clone git://github.com/ft/zsh-lookup.git

To get it working you may use the `import_into_fpath.sh' script. After that you
need to load and initialise the system:
autoload -Uz lookupinit; lookupinit

The backends all document themselves, so if you'd like to know how the `gmane'
backend works, do:
lu -h gmane

Here's the documentation that would be available via "man zshcontrib" if lookup
ever gets included in zsh:
WORLD WIDE WEB SERVICES FOR ZSH
    Loading this subsystem enables the user to access useful webservices
    (such as google, gmane, wikipedia and many more) via the command line.

    In order to load and initialize the system, you need a issue the fol
    lowing command:

           autoload -Uz lookupinit && lookupinit

    After that, a function called lookup is available. Its basic syntax is
    as follows:

           lookup [GLOBAL-OPTION(s)...] <backend> OPTION(s)...

    <backend> is a string describing the service that will be accessed.
    Backends are self-documenting. To access a backends documentation, use
    lookups -h global-option as described below.

    -h [backend]
           Print a help message.

           If [backend] is defined, it will display the self-documentation
           of the named backend.

    -i (Re)initialize the lookup subsystem.

           This is usually not required (unless you add new backends at
           runtime).

    -a <alias-definition>
           Add a backend alias.

           <alias-definition> has this format: alias-identifier="back
           end-name -options".

    -d <alias-identifier>
           Remove the backend alias named <alias-identifier>.

    -Q Let a handler function create the QUERY string.

           See Query Handlers below.

    -q <argument>
           same as -Q, but lets you give an argument for the handler func
           tion, too.

    -l List available backends.

    -L List defined backend aliases.

    -P Print which browser command would be used instead of actually
           executing it.

    -R Send url to remote (GUI) browser (like firefox).


Quickstart
    This section is for people who do not want to setup the lookup system
    on their own:

           zstyle ':lookup:*' txt-browser w3m
           zstyle ':lookup:*' txt-formats "%s"
           zstyle ':lookup:*' gui-browser firefox
           zstyle ':lookup:*' gui-formats -remote "openurl(%s)"
           zstyle ':lookup:*' use-pager true
           zstyle ':lookup:*' pager-auto true
           zstyle ':lookup:*' pager less -M

    If you want to use other browsers, youll figure it out from here.

    Now to find out what backends there are, do:

           lookup -l

    To get documentation for a backend do (the gmane backend here):

           lookup -h gmane

    Feel free to use lu instead of lookup to avoid a lot of typing. So, if
    you want to search the web via google.com for zsh, do:

           lu google zsh


Configuration
    The lookup feature is primarily configured via zstyle. For additional
    convenience the user can define and remove aliases for backends via the
    -a and -d options of the lookup function (see examples below).

    The context used for zstyle is:
           :lookup:<execution-ident>:<backend>:<local-part>

    <executing-ident>
           Is an identifier for the code region in which a style is looked up.
           Valid strings are: -main-, -backend-, -queryhandler-, -hook- and
           -browser-. These are provided for maximum control of the con
           text. Usually using * for this field will be good enough.

    <backend>
           Is the backend in question. Find out about valid strings via:
           lookup -l.

    <local-part>
           Usually, this is set to -default-. Backends may set this to
           another value, though (the rfc backend does, for example). See
           the backends documentation for details.

    This is a description of all styles that are looked up by the main sys
    tem itself. Backends do look up other styles as well; they are
    described in the backends self-documentation.

    debug When set, lookup will print some debugging information to stdout
           and it only prints out what command if would run instead o actu
           ally running it (the latter has the same effect as the -P
           option). [Type: boolean; Default: false]

    txt-browser
           This sets up the text based browser, which lookup will call to
           access a web service. [Type: string; Default: $BROWSER, if that
           is unset: w3m]

    txt-formats
           A list of arguments that is passed to the text based browser.
           Within these arguments the string %s is replaced by the URL that
           the browser should open. [Type: string; Default: %s]

    gui-browser
           This is the "remote" GUI browser, which is called when the -R
           option of lookup is used. The default is the same as for the
           text based browser.

           Thus, for making use of the -R option you will have to set up
           this style and possibly the txt-formats style (See below, and
           Examples). [Type: string; Default: see txt-browser]

    gui-formats
           A list of arguments that is passed to the "remote" GUI browser.
           Within these arguments the string %s is replaced by the URL that
           the browser should open. [Type: string; Default: see txt-for
           mats]

    use-pager
           When displaying a backends self-documentation, you may want to
           read that text in a pager because the text may be too long for
           your terminal.

           Setting this style will always put the help text into a pager
           (unless pager-auto is set, too). [Type: boolean; Default: false]

    pager-auto
           If set, a pager is only used to display help-texts if the text
           would not fit on the screen (see prompt-height below). This has
           no effect if use-pager is not set to true. [Type: boolean;
           Default: false]

    pager The pager to use for displaying help texts. [Type: string;
           Default: $PAGER, if that is unset: more]

    prompt-height
           This is the height of the prompt assumed when calculating
           whether to use a pager when pager-auto is set. [Type: integer;
           Default: 1]

    query-handlers
           A list of handlers, that may be used to alter (and possibly gen
           erate) a query for a web service. See Query Handlers and Exam
           ples below. [Type: list; Default: empty]

    hooks A list of functions to run at a certain time. There is one hook
           type directly before a backend is run; and one that is run
           directly after a backend ran and a browser is to be spawned. (If
           a backend runs other hooks, it will document those itself). See
           Hooks below. [Type: list; Default: empty]


Query Handlers
    Query Handlers can be used to automate the generation and changing of
    queries. Usually, after all option parsing is done, the remaining argu
    ments to a backend are copied into the QUERY variable, concatenating
    them by single spaces.

    This QUERY variable is a global parameter to the lookup system, so that
    you may change it in query handlers and the caller will used the
    changed variable.

    Such a handler itself is just a shell function named LOOKUP_qh_name,
    where name is the name of the handler which you use in the query-han
    dlers style.

    The <execution-identifier> part of the zstyle context used in such han
    dlers is -queryhandler- (this is only important if you want to make
    your handlers configurable by zstyle).

    The Examples section below has an example of how to automate queries
    using such a handler.


Hooks
    The basic lookup system (backends may run their own hooks, which they
    will document themselves if they do) runs two hooks: One before a back
    end is run, the other after a backend was run, before the browser is
    spawned.

    The hook list for the former is looked up in the :lookup:-main-:<back
    end>:-default- context, for the latter in the :lookup:-browser-:<back
    end>:-default- context.

    In contrast to query handlers the name of a hook in the zstyle list is
    the same as the functions that is called. The following arguments are
    provided to these functions: In the -main- context: the same arguments
    that are passed to the backend. In the -browser- context: the same URL
    that is handed over to the browser.

    There is a special variable unencQUERY that is available in hooks in
    the -browser- context. It contains the unencoded query string. With
    that the -browser- hooks can be used to set xterm or GNU screen titles.

    The <execution-identifier> part of the zstyle context used in hooks is
    -hook- (this is only important if you want to make your hooks config
    urable by zstyle).


Examples
    Basic calls:
           lookup google zsh
           lookup deb_bts -p zsh

    Calls using the shorter lu:
           lu google zsh
           lu usenet zsh

    Example backend aliases:
           lu -a s=google
           lu -a d=leo
           lu -a z=zsh_mla
           lu -a wd="wikipedia -l de"

    And use those aliases:
           lu s zsh compsys
           lu d sugar
           lu z -w 12345
           lu wd zsh

    Setup firefox as your "remote" GUI browser:
           zstyle ':lookup:*' gui-browser firefox
           zstyle ':lookup:*' gui-formats -remote "openurl(%s)"

    Do the same for opera:
           zstyle ':lookup:*' gui-browser opera
           zstyle ':lookup:*' gui-formats -newtab -remote "openURL(%s)"

    And finally an example for Query Handlers:

    Lets assume, you have a command that queries your music player as to
    which Song is currently playing, in one of the following formats:

           np: Artist - Album - Track
           np: Artist - Track

    Lets further assume such a program is called audio-stat. If the player
    is stopped is displays: -stopped-

    Now wouldnt it be convenient if we could use such information in order
    to make queries with the letssingit backend (which queries www.letssin
    git.com)? It would and the following does:

           zstyle ':lookup:*:letssingit:*' query-handlers letssingit
           function LOOKUP_qh_letssingit() {
               local mode=${lookup_communicate[mode]}
               local np
               case ${mode} in
               (artist|album|song)
                   np="$(audio-stat)"
                   np=${np/np: /}
                   if [[ ${np} == -stopped- ]] ; then
                       printf \n Currently not playing anything!\n\n
                       return 3
                   fi
                   ;;
               esac
               case ${mode} in
               (artist)
                   QUERY=${np%% - *}
                   ;;
               (album)
                   np=${np% - *}
                   if [[ ${np} == *\ -\ * ]] ; then
                       QUERY=${np#* - }
                   else
                       printf \n Could not get album (%s)!\n\n "$(audio-stat)"
                       return 3
                   fi
                   ;;
               (song)
                   QUERY=${np##* - }
                   ;;
               esac
               return 0
           }

    Now, to search for the lyrics of the currently running song, you can do
    this:
           lu -Q letssingit -m song

    You can use -m artist or -m album in order to search for lyrics of the
    currently playing artist or album, too.

Powered by zblog
valid css | valid xhtml | utf-8 encoded | best viewed with anybrowser