I've been playing around with idea of using edbrowse (CLI web browser with ed-like interface) together with acme. Launching it using win(1) in acme is fine, but far from usable. I decided to improve on that. This script is result of that - it needs to be launched in acme. Tmux is used for bridging two worlds. Since readme is included in script (just keep scrolling, you will find it), there is not much else left to say.
This is early version, but usable enough so it can be shared I guess. Here is screenshot [1], not sure how useful is that, since acme looks utilitarian as always. [1] http://i.imgur.com/w4Zh6qs.png Here is script enclosed inside "--" marks: -- #!/bin/rc . 9.rc . $PLAN9/lib/acme.rc # Preserve tabs and newlines, when tokenizing readme tmpifs = $ifs ifs = ' ' # README in form of here document readme = `{cat <<EOF} ACMEBROWSE(1) NAME acmebrowse - mouse driven interface for edbrowse DESCRIPTION This document can be accessed in acme by executing a window title in the tag: clicking a mouse button 2 on "acmebrowse". Some familiarity with acme(1) and edbrowse(1) is assumed. First of all win(1) isn't used. Instead events emitted by acme are parsed using acmeevent(1). This allows to assign a new context to the mouse actions. The result is an interface that can be used almost without a keyboard. The basic usage is very simple. The text executed with a button two is send to edbrowse as a literal command with an additional lookup for custom commands in this script. In a similar fashion button three is used for sending the selected text as a regular expression. Example. After launching acmebrowse, an address can by typed in the tag. Clicking "b http://the-brannons.com/edbrowse/" with a button two will send text as a literal command, edbrowse will open this page (not much to see, beside a status information). "Print" after a button two click will be translated to "," command, which will print a whole site. The text in a window can be clicked with a button three to send a search query e.g. "{user's guide}" will be translated to "/{user's guide}/". The first line with a phrase will be printed. "Go" clicked with a button two will be send as "g1" and "," commands - edbrowse will follow a first link in the line and then print a whole page. This is pretty much it. Commands with an exclamation mark need some explanation. The way acme works, a button two click on "Quit!" will select only "Quit". This quirk/feature is used to prevent an accidental execution of a command. Whole phrase "Quit!" must be drag-selected with a button two. In some cases it is used to provide an alternative version of command e.g. "Go!" will follow a link without printing. "Quit!" is used to clear things up, when exiting including closing of tmux session running in background. IMPLEMENTATION NOTES The script is written in rc(1), since acme is needed anyway, this was hardly a choice. Acme and edbrowse are bridged together using tmux. Detached session of tmux is spawned, edbrowse is started inside. Then flow of the script goes as follow: - capture the input from acme using acmeevent - parse and then send commands to edbrowse using tmux send-keys - block till edbrowse is done using tmux wait-for - select the whole text in acme window, so it will be overwritten - pipe the buffer from edbrowse to acme using tmux capture-pane - jump to the top/beginning of a text in acme - erase the buffer in tmux using clear-history FILES ~/.eb/bookmarks EXAMPLES Managing the bookmarks. "URLs" command will print the HTML version of links on a specified line. "Bookmarks!" will append the content of a buffer to a bookmark file. Those commands combined will add a new entry in bookmarks. SEE ALSO acme(1), acmeevent(1), edbrowse(1), tmux(1), rc(1), acme(4) CAVEATS Not implemented yet: - support for multiple sessions (not the ones in edbrowse) - sanitizing regexps sent to edbrowse BUGS "Paste" and "Edit" aren't working properly (sometimes?). EOF # End of README # Set $ifs back to default value ifs = $tmpifs # Target_window for tmux twindow = browse target = (-t ed: ^ $twindow) fn tsend { tmux send-keys $target $* } # man acmeevent(1) fn event { # $1 - c1 origin of event # $2 - c2 type of action # $3 - q0 beginning of selection # $4 - q1 end of selection # $5 - eq0 beginning of expanded selection # $6 - eq1 end of expanded selection # $7 - flag # $8 - nr number of runes in $9 # $9 - text # $10 - chorded argument # $11 - origin of chorded argument switch ($1$2) { case E* # write to body or tag case F* # generated by ourselves; ignore case K* # type away we do not care case Mi # mouse: text inserted in tag case MI # mouse: text inserted in body case Md # mouse: text deleted from tag case MD # mouse: text deleted from body # We don't care about those events winwriteevent $* case Mx MX # button 2 in tag or body if (~$9 Cut Look Paste Snarf) winwriteevent $* if not if (~$9 acmebrowse) echo -n $readme if not { parsecmd $9 pipetowin } case Ml ML # button 3 in tag or body # Send selection as regexp to edbrowse tmux send-keys -l $target /$9/ ';' \ send-keys $target Enter pipetowin } } fn parsecmd { switch ($1) { case Back # Go back one level tsend '^' Enter case Bookmarks # Open bookmark file and print tsend 'b ~/.eb/bookmarks' Enter , Enter case Bookmarks! # Add bookmark, used together with URLs command. tsend 'w+ ~/.eb/bookmarks' Enter case DDG* # Searching in duckduckgo.com ddg = `{echo $1} ddg = $ddg(2-) ddg = 'b http://ddg.gg/lite?q=' ^ $"ddg tmux send-keys -l $target $ddg ';' \ send-keys $target Enter , Enter case Go # Follow 1st link in the line and print tsend g1 Enter , Enter case Go2 # Follow 2nd link and... tsend g2 Enter , Enter case Go! # Follow without print - for binary files etc tsend g1 Enter case Go2! tsend g2 Enter case Info # Show title and address of current page tsend ft Enter f Enter case Interrupt # Send Ctrl-C to edbrowse tsend C-c case Javascript # Toggle off/on javascript tsend js Enter case Print # Print whole file tsend , Enter case Quit! # With exclamation mark, must be drag-selected. tsend qt Enter windel sure exit case Refresh # Refresh page - can be useful for JS tsend rf Enter case URLs # Show addresses behind links in selected line. tsend A Enter , Enter case Write! # Save (binary) file to disk. tsend w/ Enter case * # Send selection as plain command to edbrowse tmux send-keys -l $target $1 ';' \ send-keys $target Enter } } fn pipetowin { # Block till edbrowse opens web page. tmux send-keys $target '!tmux wait-for -S ' ^ $twindow Enter ';' \ wait-for $twindow # Select content of window in acme, so writing to data will erase it. echo -n , | winwrite addr winctl 'dot=addr' # Pipe output from tmux pane to acme window tmux capture-pane -p -S -10000 $target | winwrite data # Jump to the top/beginning of text in acme echo -n 0 | winwrite addr winctl 'dot=addr' winctl show # Erase visible part (pane) and scrollback in tmux tmux send-keys -R $target ';' clear-history $target } fn tmuxinit { # Unset $TMUX (in case it's running) and create detached session. TMUX=() tmux new-session -d -s ed -n dummy # Set history-limit to 10k lines - for long web pages. tmux set-option -q -t ed history-limit 10000 # Postpone starting of edbrowse, otherwise history-limit won't work. tmux new-window -a -t ed:dummy -n $twindow edbrowse # Close dummy window tmux send-keys -t ed:dummy exit Enter } fn acmeinit { # Create new window in acme, change name newwindow winname acmebrowse # Add commands to tag in acme echo '| i? i* i= | DDG | b http://' | winwrite tag echo -n 'Back Refresh | Print Go! Go2! | Info URLs Bookmarks!' \ ' Write! | Javascript Interrupt | Quit!' | winwrite tag } # Initialize tmux, acme and start loop tmuxinit acmeinit pipetowin wineventloop -- Paul Onyschuk