(require 'browse-url)
(unless (fboundp browse-url-browser-function)
(error "URL browse function `browse-url-browser-function' is not defined: %s" browse-url-browser-function))
(defgroup web-query nil
"Search web sites."
:prefix "web-query-"
:group 'hypermedia)
(defcustom web-query-list
'(("all" . (:google "http://"))
("define" . (:custom "http://www.google.com/search?hl=en&q=define%3A"))
("word" . (:custom "http://www.answers.com/main/ntquery?s="))
("wikipedia" . (:custom "http://en.wikipedia.org/wiki/Special:Search?search="))
("emacs-lisp" . (:google "http://www.gnu.org/emacs/"))
("emacswiki" . (:google "http://www.emacswiki.org/"))
("lisp" . (:custom "http://lispdoc.com/?search=Basic+search&q="))
("html" . (:google "http://www.htmlquick.com/reference/"))
("css" . (:google "http://www.w3schools.com/css/"))
("javascript" . (:google "http://www.w3schools.com"))
("java" . (:google "http://java.sun.com/javase/6/docs/api/"))
("android" . (:custom "http://developer.android.com/search.html#q=" "t=0"))
("clojure" . (:google "http://clojure.org/api/"))
("ruby" . (:google "http://ruby-doc.org/"))
("perl" . (:google "http://perldoc.perl.org/search.html?q="))
("python" . (:google "http://docs.python.org/ref/"))
("freshmeat" . (:custom "http://freshmeat.net/search/?section=projects&q="))
("nullman" . (:google "http://nullman.net/")))
"Association list of names to query type and URL to use with `web-query'.
The following format is used:
((NAME . (TYPE URL [SUFFIX]))
(...))
NAME is a descriptive name.
TYPE is one of:
:google
:custom
URL is dependent on TYPE as follows:
If :google then URL is used for 'site:'.
If :custom then URL is used as prefix to query string.
SUFFIX is an optional string to be added to the end of the
query."
:type 'list
:group 'web-query)
(defcustom web-query-lucky
t
"If non-nil, perform Google lucky query instead of normal query."
:type 'boolean
:group 'web-query)
(defvar web-query-name-history
(mapcar 'car web-query-list)
"History of `web-query' name arguments.
\nInitialized with `web-query-list'.")
(defvar web-query-query-history
nil
"History of `web-query' query arguments.
\nOne association list per query name.")
(defun web-query-custom (url query &optional suffix)
"Browse result of a custom QUERY with optional SUFFIX appended to URL.
\nUsed internally by `web-query'."
(funcall browse-url-browser-function
(concat url (url-hexify-string query)
(if suffix
suffix
""))))
(defun web-query-google-url (url)
"Return string created from splitting URL into \"site:\" and \"inurl:\" Google parts."
(string-match "\\(http://.*?\\)\\(/.*\\)" url)
(concat
"site:" (or (match-string 1 url) "")
" inurl:" (or (match-string 2 url) "")))
(defun web-query-google (url query lucky)
"Browse result of a Google QUERY limited to URL site.
\nUsed internally by `web-query'.
If LUCKY is non-nil, Google's \"I'm Feeling Lucky\" query is used."
(funcall browse-url-browser-function
(concat "http://www.google.com/search?q="
(url-hexify-string (concat query " " (web-query-google-url url)))
(if lucky
"&btnI=Search"
"&btnG=Search"))))
(defun web-query (&optional name query)
"Lookup NAME in `web-query-list', then submit associated URL and QUERY to `web-query-google'."
(interactive)
(let* ((name (or name
(read-from-minibuffer "Name: "
(car web-query-name-history)
nil nil
'web-query-name-history)))
(hist (progn
(unless (assoc name web-query-query-history)
(push (list name nil) web-query-query-history))
(cadr (assoc name web-query-query-history))))
(query (or query
(read-from-minibuffer "Query: "
nil nil nil
'hist))))
(when (member query hist)
(setq hist (remove query hist)))
(push query hist)
(setcdr (assoc name web-query-query-history) (list hist))
(multiple-value-bind (type url suffix) (cdr (assoc name web-query-list))
(case type
(:custom (web-query-custom url query suffix))
(:google (web-query-google url query web-query-lucky))))))
(when (require-if-available 'mm-url)
(when (load "mm-url" t)
(defun web-query-google-define (query)
"Submit QUERY to Google Define and print the result in the minibuffer."
(interactive "sQuery: ")
(let* ((url (concat
"http://www.google.com/search?hl=en&q=define%3A"
(replace-regexp-in-string " " "%20" query)))
(definition
(save-excursion
(with-temp-buffer
(mm-url-insert url)
(goto-char (point-min))
(if (search-forward "No definitions were found" nil t)
"No definitions were found"
(buffer-substring (search-forward "<li>") (- (search-forward "<") 1)))))))
(message "%s: %s" query definition)))
(defun web-query-google-define-at-point ()
"Call `web-query-google-define' with word at point or active region."
(interactive)
(let ((query (replace-regexp-in-string
" " "%20"
(if (and transient-mark-mode mark-active)
(buffer-substring-no-properties (region-beginning) (region-end))
(substring-no-properties (thing-at-point 'word))))))
(web-query-google-define query)))))
(defun web-query-word (word)
"Submit WORD to a dictionary site (as specified in `web-query-list')."
(interactive "sWord: ")
(web-query "word" word))
(defun web-query-word-at-point ()
"Call `web-query-word' with word at point or active region.
\nIf no word is found, user is prompted for one."
(interactive)
(let ((word (replace-regexp-in-string
" " "%20"
(if (and transient-mark-mode mark-active)
(buffer-substring-no-properties (region-beginning) (region-end))
(substring-no-properties (or (thing-at-point 'word) ""))))))
(if (> (length word) 0)
(web-query-word word)
(web-query-word (read-from-minibuffer "Word: ")))))
(defun web-query-symbol-by-mode (query)
"Call `web-query' with QUERY using current `major-mode' to determine what type of query to perform.
Supported modes:
`emacs-lisp-mode'
`html-mode'
`html-helper-mode'
`css-mode'
`javascript-mode'
`java-mode'
`jde-mode'
`clojure-mode'
`ruby-mode'
`perl-mode'
`python-mode'
Defaults to dictionary word lookup."
(interactive "sQuery: ")
(web-query
(cond
((equal major-mode 'emacs-lisp-mode)
"emacs-lisp")
((or (equal major-mode 'html-mode)
(equal major-mode 'html-helper-mode))
"html")
((equal major-mode 'css-mode)
"css")
((equal major-mode 'javascript-mode)
"javascript")
((or (equal major-mode 'java-mode)
(equal major-mode 'jde-mode))
"java")
((equal major-mode 'clojure-mode)
"clojure")
((equal major-mode 'ruby-mode)
"ruby")
((equal major-mode 'perl-mode)
"perl")
((equal major-mode 'python-mode)
"python")
(t
"word"))
query))
(defun web-query-symbol-by-mode-at-point ()
"Call `web-query-symbol-by-mode' with symbol at point or active region.
\nIf no symbol is found, user is prompted for one."
(interactive)
(let ((query (replace-regexp-in-string
" " "%20"
(if (and transient-mark-mode mark-active)
(buffer-substring-no-properties (region-beginning) (region-end))
(substring-no-properties (or (thing-at-point 'symbol) ""))))))
(web-query-symbol-by-mode
(if (> (length query) 0)
query
(read-from-minibuffer "Query: ")))))
(provide 'web-query)