2012 0005 0019
While many an emacs include dabbrev-expand for within-buffer completion, I’ve always wanted (purely for reasons of amusement) to take it further: completion via Google’s search suggestions. I was going to do this as a weekend project, but an ugly version was surprisingly simple.
Conveniently, curl is all we need to fetch the completions for a query string as JSON:
> echo -en $(curl -H "Accept: application/json" \
"http://suggestqueries.google.com/complete/search?client=firefox&q=query")
["query",["query","query xiv","query letter","query_posts","query shark","query access","query tracker","query string","query letter sample","queryperformancecounter"]]
using a (very platform dependent) echo trick to convert the escaped unicode sequences to their proper characters.
With this, a quick hack in elisp is all that’s necessary to parse the results into emacs and insert it into the current buffer:
(defun google-request (query)
(shell-command-to-string
(format
"echo -en $(curl -H \"Accept: application/json\" \"http://suggestqueries.google.com/complete/search?client=firefox&q=%s\" 2>/dev/null)"
query)))
(defun google-preprocess (query)
(let ((l (split-string
(apply 'string
(removel
'(?\" ?\[ ?\])
(string-to-list query)))
",")))
(if (> (length (car (cdr l))) 0)
(remove (car l) (cdr l))
nil)))
(defun google-complete ()
(interactive)
(end-of-thing 'word)
(let ((s (thing-at-point 'word)))
(when s
(let ((q (google-preprocess (google-request s))))
(when q
(insert (substring
(car q)
(length s))))))))
(defun removel (el l)
(cond (el (removel (cdr el) (remove (car el) l)))
(t l)))
Since it went more swiftly than anticipated, I generalized the code to parsing any delimited shell output and wrapped it in a minor mode with some key bindings and customize variables. Right now, I’m uncreatively calling it shell-parse.el.
After activating shell-parse-mode, it has support for scrolling through the list of completions forwards (shell-parse-complete) and backwards (shell-parse-complete-backwards) with the C-Tab and C-Shift-Tab keys, respectively. Using M-x customize-mode <Enter>
shell-parse-mode, you can swap out the curl command with any shell snippet that will kick back completions, and change the delimiter as well.
You can grab shell-parse.el on github. Simply load-file the shell-parse.el script in .emacs and it should be ready to go.
It has a few todos scattered through it yet, and is not very idiomatic emacs or portable, but that’s what github’s issue tracker is for, after all.