Lisp Event Manager for Uzbl. By Michael Raskin. Works with ECL now; seems to be working with SBCL; should work with CCL. Reads from stdin and writes mostly to stdout - socat is supposed to care about sockets. It is supposed to be run one-instance-per-Uzbl-instance. But a few progv-s would allow to localize all the *uzbl-[something]* variables.
You can browse Monotone repository at: http://mtn-host.prjek.net/viewmtn/uzbl-lisp-em/branch/head/info/com.ignorelist.401a0bf1.raskin.uzbl-lisp-em (my config is also there)
Another branch, http://mtn-host.prjek.net/viewmtn/uzbl-lisp-em/branch/head/info/com.ignorelist.401a0bf1.raskin.uzbl-js , contains JavaScript snippets I use in my config.
It depends on ASDF packages :cl-ppcre, :iterate and :trivial-utf-8. The main fuction is “event-loop”, it is called without arguments.
It can be built with ECL by loading the following:
(asdf:defsystem :uzbl-em.bin
:serial t
:depends-on
(
:cl-ppcre
:trivial-utf-8
:iterate
)
:components (
(:file #.(pathname-name (truename "em.lisp")))
)
)
(asdf:make-build :uzbl-em.bin :type :program
:epilogue-code `(progn (funcall (find-symbol "EVENT-LOOP" :common-lisp-user)) (ext:quit 0)))
(quit)
Recent fixes: * Added ${var-name} Uzbl variable expansion for shell commands. * Fixed UTF-8 processing: exporting variables with Unicode characters in them and running commands with Unicode characters embedded crashed Uzbl * Fixed uri variable processing - set it on LOAD_COMMIT, too * Fixed combos - “press Shift press A release Shift release a” no longer leave EM in the state “A is still pressed”
It is not split into separate files, but everything is split into fairly small functions (no single multi-screen switch), so splitting would be simple.
Look at my configuration for usage examples. If you consider actually trying to use this, you can ask me for more detailed explanations (on IRC or using my e-mail in the mailing list)
Basic bindings are done using
event bind [mode] [key-combo] [parameter-treatment-mode] [handler-type] [binding-content]
Modes are just names; the default mode is command. You can register some modes to ignore bindings.
Lisp-EM supports proper key combos: [{Ctrl}w]q means “Control and w together; then release both and press q”. Non-special-symbols-only combos are ignored (because they occur at random while typing quickly).
Parameter passing modes:
* on-first: run the binding once the main command is entered; clear input buffer afterwards * once-preserving: run the binding once the main command is entered; do not clear input buffer afterwards. Currently useless, but can later become useful if chains gain proper triggering post-effect support. * on-enter: read parameter until special key called :enter is pressed; then run binding and clear input buffer. * each-key: read parameter, calling the binding on each keypress.
Handler types:
* uzbl - run a uzbl command * uzbl-raw - the same, but without escaping * shell - export uzbl variables to environment and run a command. It is supposed to be a command with arguments; separating symbol should be specified in “quotes” - you can use any symbol, actually
shell |!#| sh!#-c!#xterm
should run xterm.
(in-package :common-lisp-user)
; Compatibility hack
(eval-when
(:compile-toplevel :load-toplevel :execute)
(loop for pack in '(:ext :sb-posix :ccl :sb-ext)
when (find-package pack) do
(loop for sym in '("GETENV" "SETENV" "RUN-PROGRAM") do
(let
((s (find-symbol sym pack)))
(when s (shadowing-import s)))))
)
(defmacro debug-print (&rest args)
`(format *error-output* ,@args)
;`(progn)
)
(defmacro just-print-errors (&rest body)
`(block nil
(handler-case
(progn ,@body)
(error (x)
(debug-print "Error occured: ~s~%" x)
))))
(defvar *whitespace* '(#\Tab #\Return #\NewLine #\Linefeed #\Space))
(defun to-uzbl-name (sym) (cl-ppcre:regex-replace-all "-" (symbol-name sym) "_"))
(defun to-inner-name (str)
(intern (string-upcase (cl-ppcre:regex-replace-all
"_" (string-trim *whitespace* str) "-"))
:keyword))
(defun uzbl-command (str)
(debug-print ">> ~s~%" str)
(format t "~a~%" str))
(defun uzbl-fmt-command (&rest args)
(uzbl-command (apply 'format nil args)))
(defvar *double-escaped-chars* '("\\"))
(defvar *escaped-chars* '("@" "\""))
(defvar *advanced-escapes* '(("\\n" "\\\\n")))
(defun escape-for-uzbl (str)
(let ((str str))
(loop for c in *double-escaped-chars* do
(setf str
(cl-ppcre:regex-replace-all
(concatenate 'string "\\" c)
str (concatenate 'string "\\\\\\" c)))
)
(loop for c in *escaped-chars* do
(setf str
(cl-ppcre:regex-replace-all
c str (concatenate 'string "\\\\" c)))
)
(loop for c in *advanced-escapes* do
(setf str
(cl-ppcre:regex-replace-all
(first c) str (second c)
)))
str))
(defvar *uzbl-extra-event-handlers* (make-hash-table :test 'equal))
(defmacro execute-binding (type binding-set cmd param)
`(call-handler ,type ,binding-set nil ,cmd ,param))
(defvar *uzbl-binding-executors* (make-hash-table))
(defmacro defhandler (type group args &rest body)
`(setf
(gethash ,type ,group)
(lambda ,args ,@body)
))
(defmacro defnullhandler (type group)
`(defhandler ,type ,group (&rest args) (declare (ignore args))))
(defun no-such-handler (type group)
(lambda (&rest args)
(debug-print "Undefined handler: ~s for ~s called with args ~s~%"
type group args)
))
(defmacro call-handler (type group applyp &rest args)
`(progn
(loop for x in (gethash (list ',group ,type) *uzbl-extra-event-handlers*)
do (,(if applyp 'apply 'funcall) x ,@args))
(,(if applyp 'apply 'funcall)
(gethash ,type ,group (no-such-handler ,type ',group))
,@args
)
))
(defvar *uzbl-event-bindings* (make-hash-table))
(defun read-until (thestream delimiter)
(let* (
(chars (do* ((thechar t (read-char thestream nil nil nil))
(chars nil (cons thechar chars))
)
((or (equal thechar delimiter) (null thechar)) (reverse (cdr chars)))))
(str (map 'string 'identity chars)))
str))
(defun split-by (str delimiter &optional (n 1))
(with-input-from-string
(s str)
(concatenate
'list
(loop for n from 1 to n collect (read-until s delimiter))
(list (read-line s nil "")))))
(defun parse-event (line)
(cond
((stringp line)
(let* (
(split-line (split-by line #\Space))
(type (to-inner-name (first split-line)))
(data (second split-line))
)
(list type data))
)
((listp line) line)
))
(defmacro handle-event (line binding-level)
`(let
((line ,line))
(when
line
(let*
((event (parse-event line))
)
(debug-print "<< ~s << ~s~%" ',binding-level line)
(call-handler (car event) ,binding-level t (cdr event))
t
)
)))
(defun event-loop ()
(loop while (handle-event (just-print-errors (read-line t nil nil))
*uzbl-event-bindings*)))
(defvar *uzbl-id* nil)
(defvar *uzbl-common-event-bindings* (make-hash-table))
(defhandler :event *uzbl-event-bindings* (data)
(let*
(
(split-data (split-by data #\Space))
(id (cl-ppcre:regex-replace-all "[][]" (first split-data) ""))
(*uzbl-id* id)
)
(declare
(special *uzbl-id*))
(handle-event (second split-data) *uzbl-common-event-bindings*)
))
(defhandler :lisp *uzbl-common-event-bindings* (data)
(let*
(
(code
`(let
(
(id ,*uzbl-id*)
)
,(read-from-string data)
))
)
(eval code)
))
(defhandler :plugin *uzbl-common-event-bindings* (data)
(just-print-errors
(load
(format
nil "~a/.local/share/uzbl/lisp-em-plugins/~a.lisp"
(getenv "HOME") data))))
(defhandler :quit *uzbl-common-event-bindings* (data)
(declare (ignore data))
(quit))
(defhandler :instance-exit *uzbl-common-event-bindings* (data)
(declare (ignore data))
)
(defhandler :instance-start *uzbl-common-event-bindings* (data)
(declare (ignorable data)))
(defvar *uzbl-builtins* nil)
(defhandler :builtins *uzbl-common-event-bindings* (data)
(setf *uzbl-builtins* (cl-ppcre:split #\Space data)))
(defvar *uzbl-vars* (make-hash-table :test 'equal))
(defvar *uzbl-var-types* (make-hash-table :test 'equal))
(defhandler :variable-set *uzbl-common-event-bindings* (data)
(let*
(
(split-data-1 (split-by data #\Space))
(split-data-2 (split-by (second split-data-1) #\Space))
(name (first split-data-1))
(type (first split-data-2))
(raw-value (second split-data-2))
(value (cond
((equalp type "str") raw-value)
((equalp type "int") (parse-integer raw-value))
(t (progn (debug-print "Unknown type: ~s~%" type) raw-value))
))
)
(setf (gethash name *uzbl-vars*) value)
(setf (gethash name *uzbl-var-types*) type)
))
(defun export-vars ()
(maphash
(lambda (k v)
(setenv (format nil "uzbl_~a" k)
(map
'string 'code-char
(trivial-utf-8:string-to-utf-8-bytes
(format nil "~a" v)))))
*uzbl-vars*)
(setenv "uzbl_id" *uzbl-id*)
)
(defvar *uzbl-key-syms*
'(
("space" "__" " ")
("Shift_L" "" "")
("Shift_R" "" "")
("Control_L" "Ctrl" "^")
("Control_R" "Ctrl" "^")
("ISO_Level3_Shift" "" "")
("ISO_Next_Group" "" "")
("[" "Open_Bracket" "[")
("{" "Open_Brace" "{")
))
(defvar *uzbl-keystr* "")
(defvar *uzbl-keystr-head* nil)
(defvar *uzbl-keystr-tail* nil)
(defvar *uzbl-active-key-command* nil)
(defvar *uzbl-pressed-keys* nil)
(defvar *uzbl-combo-keys* nil)
(defvar *uzbl-last-keypress* "")
(defvar *uzbl-special-key* nil)
(defvar *uzbl-key-bindings* (make-hash-table :test 'equal))
(defvar *uzbl-flash-key-bindings* (make-hash-table :test 'equal))
(defvar *uzbl-immortal-key-bindings* (make-hash-table :test 'equal))
(defvar *uzbl-mode* :command)
(defvar *uzbl-nocommand-modes* (make-hash-table :test 'equal))
(defun convert-key (s)
(or
(let
((ks (second (assoc s *uzbl-key-syms* :test 'equal))))
(when ks (convert-key ks))
)
(when (<= (length s) 1) s)
(format nil "{~a}" s)
))
(defhandler :key-press *uzbl-common-event-bindings* (data)
(let
((key (convert-key data)))
(when (> (length key) 0)
(let*
((kb (gethash key *uzbl-immortal-key-bindings*)))
(debug-print "Checking for an immortal binding ~s got ~s.~%" key kb)
(if kb
(execute-binding
(first kb) *uzbl-binding-executors* (second kb) "")
(progn
(pushnew key
*uzbl-pressed-keys* :test 'equal)
(pushnew key
*uzbl-combo-keys* :test 'equal)
))))))
(defun decode-keystr (s)
(let ((s s))
(loop for x in *uzbl-key-syms*
when (> (length (second x)) 1)
do
(setf s (cl-ppcre:regex-replace-all
(format nil "{~a}" (second x))
s (third x)
)))
s))
(defun resplit-keypresses ()
(debug-print "Resplitting ~s~%" *uzbl-keystr*)
(cond
((< (length *uzbl-keystr*) (length *uzbl-keystr-head*))
(setf *uzbl-keystr-head* nil)
(setf *uzbl-active-key-command* nil)
)
((null *uzbl-keystr-head*)
(let*
((keys-entry (list *uzbl-keystr* *uzbl-mode*))
(kb (gethash keys-entry *uzbl-key-bindings*))
)
(debug-print "Retrieved ~s binding as ~s.~%"
keys-entry kb)
(when kb
(setf *uzbl-keystr-head* *uzbl-keystr*)
(setf *uzbl-keystr-tail* "")
(setf *uzbl-active-key-command* kb)
)
))
((/= (length *uzbl-keystr*)
(+ (length *uzbl-keystr-head*) (length *uzbl-keystr-tail*)))
(setf *uzbl-keystr-tail*
(decode-keystr (subseq *uzbl-keystr* (length *uzbl-keystr-head*))))
)
)
(debug-print "Resplit ~s into ~s and ~s with command entry ~s.~%"
*uzbl-keystr*
*uzbl-keystr-head* *uzbl-keystr-tail*
*uzbl-active-key-command*)
)
(defhandler :lisp *uzbl-binding-executors* (cmd param)
(let*
(
(core-code (read-from-string cmd))
(code
`(let*
(
(id ,*uzbl-id*)
(param ,param)
)
,core-code))
)
(eval code)))
(defhandler :uzbl-raw *uzbl-binding-executors* (cmd param)
(uzbl-command (cl-ppcre:regex-replace-all "%s" cmd param)))
(defhandler :uzbl *uzbl-binding-executors* (cmd param)
(uzbl-command (escape-for-uzbl (cl-ppcre:regex-replace-all "%s" cmd param))))
(defvar *uzbl-key-triggers* (make-hash-table))
(defhandler :chain *uzbl-binding-executors* (cmd param)
(let*
(
(meta-separator (elt cmd 0))
(first-cut (split-by cmd meta-separator 2))
(separator-regex (second first-cut))
(commands (cl-ppcre:split
separator-regex
(string-left-trim *whitespace* (third first-cut))))
(commands-cut
(mapcar
(lambda (x)
(let*
((y (split-by x #\Space 2)))
(list
(to-inner-name (first y))
(to-inner-name (second y))
(third y)
)))
commands))
)
(debug-print "Running chain with meta-separator ~s, separator ~s.~%"
meta-separator separator-regex)
(debug-print "Commands: ~s." commands-cut)
(loop for x in commands-cut
when (call-handler (first x) *uzbl-key-triggers*
nil *uzbl-last-keypress* *uzbl-keystr*)
do (execute-binding (second x) *uzbl-binding-executors*
(third x) param)
)
))
(defhandler :event *uzbl-binding-executors* (cmd param)
(handle-event (cl-ppcre:regex-replace-all "%s" cmd param)
*uzbl-common-event-bindings*))
(defhandler :each-key *uzbl-key-triggers* (key keystr) (declare (ignore key keystr)) (lambda ()))
(defhandler :each-new-key *uzbl-key-triggers* (key keystr) (declare (ignore keystr))
(when (> (length key) 0) (lambda ())))
(defhandler :on-enter *uzbl-key-triggers* (key keystr)
(declare (ignore keystr))
(when (equal *uzbl-special-key* :enter)
(lambda () (call-handler :clear-keystr *uzbl-common-event-bindings* nil nil))))
(defhandler :on-first *uzbl-key-triggers* (key keystr)
(declare (ignore key keystr))
(lambda () (call-handler :clear-keystr *uzbl-common-event-bindings* nil nil)))
(defhandler :once-preserving *uzbl-key-triggers* (key keystr)
(when (equal *uzbl-keystr-head* keystr) (lambda ())))
(defun handle-keypress (str)
(if
(let*
((real-str (cl-ppcre:regex-replace-all "{__}" str " ")))
(and
(> (length real-str) 1)
(not (cl-ppcre:scan "{" real-str))
)
)
(loop for n from 1 to (- (length str) 2) do
(handle-keypress (subseq str n (+ n 1))))
(progn
(setf *uzbl-last-keypress* str)
(or
(let
((kb (gethash (list str *uzbl-mode*) *uzbl-flash-key-bindings*)))
(debug-print "Got flash-binding ~s for ~s.~%" kb (list str *uzbl-mode*))
(when kb
(execute-binding (first kb) *uzbl-binding-executors* (second kb) "")
t)
)
(when
(not (gethash *uzbl-mode* *uzbl-nocommand-modes*))
(setf *uzbl-keystr* (concatenate 'string *uzbl-keystr* str))
(resplit-keypresses)
(uzbl-fmt-command "set keycmd = ~a~%" (escape-for-uzbl *uzbl-keystr*))
(let*
(
(keypress-finalizer
(when *uzbl-active-key-command*
(call-handler (first *uzbl-active-key-command*)
*uzbl-key-triggers*
nil str *uzbl-keystr*)))
)
(when keypress-finalizer
(execute-binding (second *uzbl-active-key-command*)
*uzbl-binding-executors*
(third *uzbl-active-key-command*)
*uzbl-keystr-tail*)
(funcall keypress-finalizer)
)
)
)
)
)
)
)
(defhandler :key-release *uzbl-common-event-bindings* (data)
(setf
*uzbl-pressed-keys*
(remove (convert-key data) *uzbl-pressed-keys* :test 'equalp)
)
(and (not *uzbl-pressed-keys*)
*uzbl-combo-keys*
(progn
(handle-keypress
(format
nil
(if (> (length *uzbl-combo-keys*) 1)
"[~{~a~}]"
"~{~a~}"
)
(reverse *uzbl-combo-keys*)
))
(setf *uzbl-combo-keys* nil))
))
(defhandler :back-keystr *uzbl-common-event-bindings* (data)
(declare (ignore data))
(setf *uzbl-keystr* (subseq *uzbl-keystr* 0 (max 0 (- (length *uzbl-keystr*) 1))))
(handle-keypress "")
)
(defhandler :clear-keystr *uzbl-common-event-bindings* (data)
(declare (ignore data))
(setf
*uzbl-keystr* ""
*uzbl-keystr-head* nil
*uzbl-keystr-tail* nil
*uzbl-pressed-keys* nil
*uzbl-combo-keys* nil
*uzbl-active-key-command* nil
*uzbl-last-keypress* ""
*uzbl-special-key* nil
)
(uzbl-command "set keycmd = ")
)
(defhandler :mode *uzbl-common-event-bindings* (data)
(setf *uzbl-mode* (to-inner-name data))
(call-handler :clear-keystr *uzbl-common-event-bindings* nil ""))
(defhandler :bind *uzbl-common-event-bindings* (data)
(let*
(
(split-data (split-by data #\Space 4))
(keys (second split-data))
(mode (to-inner-name (first split-data)))
(trigger (to-inner-name (third split-data)))
(type (to-inner-name (fourth split-data)))
(content (fifth split-data))
(keys-entry (list keys mode))
(binding-entry (list trigger type content))
)
(debug-print "Binding ~s to ~s~%" keys-entry binding-entry)
(setf
(gethash keys-entry *uzbl-key-bindings*)
binding-entry)
))
(defhandler :flash-bind *uzbl-common-event-bindings* (data)
(let*
(
(split-data (split-by data #\Space 3))
(keys (second split-data))
(mode (to-inner-name (first split-data)))
(trigger (to-inner-name (third split-data)))
(content (fourth split-data))
(keys-entry (list keys mode))
(binding-entry (list trigger content))
)
(debug-print "Flash-binding ~s to ~s~%" keys-entry binding-entry)
(setf
(gethash keys-entry *uzbl-flash-key-bindings*)
binding-entry)
))
(defhandler :immortal-bind *uzbl-common-event-bindings* (data)
(let*
(
(split-data (split-by data #\Space 2))
(key (first split-data))
(type (to-inner-name (second split-data)))
(content (third split-data))
(binding-entry (list type content))
)
(debug-print "Immortal-binding ~s to ~s~%" key binding-entry)
(setf
(gethash key *uzbl-immortal-key-bindings*)
binding-entry)
))
(defhandler :subscribe-event *uzbl-common-event-bindings* (data)
(let*
(
(split-data (split-by data #\Space 2))
(event-name (to-inner-name (first split-data)))
(binding-type (to-inner-name (second split-data)))
(content (third split-data))
)
(push
(lambda (data)
(debug-print "Using subscription to ~s to execute ~s binding ~s.~%"
event-name binding-type content)
(execute-binding binding-type
*uzbl-binding-executors* content data))
(gethash (list '*uzbl-common-event-bindings* event-name)
*uzbl-extra-event-handlers*)
)
)
)
(defhandler :flush-subscription *uzbl-common-event-bindings* (data)
(setf (gethash (list '*uzbl-common-event-bindings* (to-inner-name data))
*uzbl-extra-event-handlers*)
nil))
(defhandler :register-nocommand-mode *uzbl-common-event-bindings* (data)
(setf (gethash (to-inner-name data) *uzbl-nocommand-modes*) t)
)
(defhandler :unregister-nocommand-mode *uzbl-common-event-bindings* (data)
(remhash (to-inner-name data) *uzbl-nocommand-modes*)
)
(defhandler :|| *uzbl-event-bindings* (data) (declare (ignore data)))
(defhandler :command-error *uzbl-common-event-bindings* (data) (declare (ignore data)))
(defhandler :special-key *uzbl-common-event-bindings* (data)
(setf *uzbl-special-key* (to-inner-name data))
(handle-keypress ""))
(defhandler :run-command *uzbl-common-event-bindings* (data)
(let*
(
(meta-separator (elt data 0))
(cut-1 (split-by data meta-separator 2))
(separator-regex (second cut-1))
(command-parts
(cl-ppcre:split separator-regex
(string-left-trim *whitespace* (third cut-1))))
)
(run-program
(first command-parts)
(rest command-parts)
:wait nil :search t
:allow-other-keys t
)
))
(defun escape-for-shell (str)
(concatenate
'string
"'" (cl-ppcre:regex-replace-all "'" str "'\\''") "'"))
(defhandler :shell-novars *uzbl-binding-executors* (cmd param)
(let*
(
(data (cl-ppcre:regex-replace-all "%s" cmd param))
(meta-separator (elt data 0))
(cut-1 (split-by data meta-separator 2))
(separator-regex (second cut-1))
(command-parts
(mapcar
(lambda (x) (map 'string 'code-char (trivial-utf-8:string-to-utf-8-bytes x)))
(cl-ppcre:split
separator-regex
(string-left-trim *whitespace* (third cut-1)))))
)
(run-program
(first command-parts)
(rest command-parts)
:wait nil :search t
:allow-other-keys t
)
))
(defun escape-for-regex (str)
(cl-ppcre:regex-replace-all
"\\\\"
(cl-ppcre:regex-replace-all "(.)" str "[\\1]")
"\\\\\\\\"
)
)
(defun replace-unescaped (str from to escape double-escape)
(let*
(
(split-by-de (cl-ppcre:split (escape-for-regex double-escape) str))
(split-by-se
(mapcar
(lambda (s)
(cl-ppcre:split
(escape-for-regex (concatenate 'string escape from))
s))
split-by-de))
(with-replaced
(mapcar
(lambda (x)
(mapcar (lambda (y) (cl-ppcre:regex-replace-all
(escape-for-regex from) y to))
x
))
split-by-se
))
(res
(apply
'concatenate 'string
(iterate:iter
(iterate:for x :in with-replaced)
(unless
(iterate:first-time-p)
(iterate:collect escape))
(iterate:collect
(apply
'concatenate 'string
(iterate:iter
(iterate:for y :in x)
(unless
(iterate:first-time-p)
(iterate:collect from))
(iterate:collect y)
)))
)))
)
res
))
(defun substitute-vars (str ht &key
(escape "\\") double-escape (from-format "${~a}"))
(let* ((res str))
(maphash
(lambda (k v)
(setf res
(replace-unescaped
res
(format nil from-format k)
v escape
(or double-escape
(concatenate
'string escape escape)))))
ht)
res))
(defhandler :shell *uzbl-binding-executors* (cmd param)
(let*
(
(data (cl-ppcre:regex-replace-all "%s" cmd param))
(meta-separator (elt data 0))
(cut-1 (split-by data meta-separator 2))
(separator-regex (second cut-1))
(cmdline (third cut-1))
(command-parts
(mapcar
(lambda (x)
(map 'string 'code-char
(trivial-utf-8:string-to-utf-8-bytes
(substitute-vars x *uzbl-vars*))))
(cl-ppcre:split
separator-regex
(string-left-trim *whitespace* cmdline))))
)
(export-vars)
(debug-print "Running a program ~s with args ~s~%"
(first command-parts)
(rest command-parts))
(run-program
(first command-parts)
(rest command-parts)
:wait nil :search t
:allow-other-keys t
)
))
(defhandler :as-binding *uzbl-common-event-bindings* (data)
(let*
(
(cut-1 (split-by data #\Space))
)
(execute-binding
(to-inner-name (first cut-1))
*uzbl-binding-executors*
(second cut-1)
""
)
))
(defhandler :load-commit *uzbl-common-event-bindings* (data)
(setf (gethash "uri" *uzbl-vars*) data))
(defhandler :focus-lost *uzbl-common-event-bindings* (data)
(declare (ignore data))
(setf *uzbl-pressed-keys* nil)
(call-handler :key-release *uzbl-common-event-bindings* nil ""))
(defhandler :title-changed *uzbl-common-event-bindings* (data)
(setf (gethash "title" *uzbl-vars*) data))
(defnullhandler :focus-gained *uzbl-common-event-bindings*)
(defnullhandler :form-active *uzbl-common-event-bindings*)
(defnullhandler :geometry-changed *uzbl-common-event-bindings*)
(defnullhandler :link-hover *uzbl-common-event-bindings*)
(defnullhandler :link-unhover *uzbl-common-event-bindings*)
(defnullhandler :load-start *uzbl-common-event-bindings*)
(defnullhandler :request-starting *uzbl-common-event-bindings*)
(defnullhandler :load-finish *uzbl-common-event-bindings*)
(defnullhandler :load-progress *uzbl-common-event-bindings*)
(defnullhandler :load-error *uzbl-common-event-bindings*)
(defnullhandler :ptr-move *uzbl-common-event-bindings*)
(defnullhandler :root-active *uzbl-common-event-bindings*)
(defnullhandler :unknown-scheme *uzbl-common-event-bindings*)
(defnullhandler :null *uzbl-binding-executors*)