[dev] [acmebrowse] Mouse driven interface for edbrowse

From: Paul Onyschuk <ptmelville_AT_gmail.com>
Date: Thu, 24 Jul 2014 23:15:35 +0200

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

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:

. 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 - mouse driven interface for edbrowse
	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.
	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
	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.
	acme(1), acmeevent(1), edbrowse(1), tmux(1), rc(1), acme(4)
	Not implemented yet:
	- support for multiple sessions (not the ones in edbrowse)
	- sanitizing regexps sent to edbrowse
	"Paste" and "Edit" aren't working properly (sometimes?).
# 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
	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
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
	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
	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
Paul Onyschuk
Received on Thu Jul 24 2014 - 23:15:35 CEST

This archive was generated by hypermail 2.3.0 : Thu Jul 24 2014 - 23:24:07 CEST