Skip to content

Instantly share code, notes, and snippets.

@brenns10
Last active July 11, 2022 00:20
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save brenns10/69d39f6c46170093f73d to your computer and use it in GitHub Desktop.
Save brenns10/69d39f6c46170093f73d to your computer and use it in GitHub Desktop.
Emacs Web Searching

Introduction

Sometimes I want to make a quick web search, and I’d prefer not to leave Emacs. Sure, I could switch over to a different workspace and open a browser, but I’d much rather do it in Emacs if possible. eww will let you search instead of enter a URL, but you only get one search engine (which is, by default, Duck Duck Go). I’m used to the wonderful interface of Chrome, which allows you to use a keyword to specify your search engine, right within the “Omnibox”. Anything else feels crude. So, I decided I would implement my own search solution!

Interface

The code below creates two commands:

  • search-web allows you to search by specifying an engine like this: “ddg:search term here”, or by omitting the engine and just entering a term, so that you use your default search engine.
  • search-engine allows you to search by prompting you for a search engine and a search term seperately. This is actually a helper function to search-web, but maybe you’d prefer to be prompted! Who am I to judge?

Both functions will give you an error message if you provide a bad search engine.

Installation

You can “install” this into your Emacs by simply adding the code blocks below to your .emacs. Or, if you happen to use an Org-Babel init system like I do, you can just drop this file in there and add it to your list of modules.

Implementation

So, first we need a list of search engines. I define search engines to be a list containing the following items:

  • A list of keyword names for the search engine
  • A format string containing one %s where the url-encoded search term goes.

I created search-engines as a list of these search engines. You can customize them as much as you’d like. Also, search-engine-default is the keyword name of a default search engine, for when you don’t specify it in search-web.

(setq search-engines
      '(
        (("google" "g") "https://google.com/search?q=%s")
        (("duckduckgo" "d" "ddg") "https://duckduckgo.com/?q=%s")
        (("rfc" "r") "https://www.rfc-editor.org/rfc/rfc%s.txt")
        (("rfc-kw" "rk") "https://www.rfc-editor.org/search/rfc_search_detail.php?title=%s")
        ))
(setq search-engine-default "google")

Below is a nifty little recursive helper function to get a search engine’s url format string from a keyword.

(defun search-get-engine (engine-name engine-list)
  (cond
   ((null engine-list) nil)
   ((member engine-name (caar engine-list)) (cadar engine-list))
   (t (search-get-engine engine-name (cdr engine-list)))))

Now, all that’s left is the two interactive commands. The first will prompt for an engine, followed by a search term. If the search term is unknown, we’ll print an error message in the minibuffer, and fail.

(defun search-engine (engine-name term)
  "Search for a term using an engine."
  (interactive "MEngine: \nMTerm: ")
  (let* ((url (search-get-engine engine-name search-engines)))
    (if (equal url nil)
        (message "Error: search engine \"%s\" unknown." engine-name)
      (eww (format url (url-hexify-string term))))))

The second command is more of a “dwim” (i.e. do what I mean) command. It uses your default search engine when you don’t use a colon. When you do, it assumes that the first part is to specify your search engine (like this: “rfc:793”). If you’d like to use a colon in an actual search term, you’ll have to explicitly specify your search engine (even if you’d like to use the default).

(defun search-web (term)
  "Search the web using google or a specified engine."
  (interactive "MQuery: ")
  (let ((idx (position ?: term)))
    (if (equal idx nil)
        (search-engine search-engine-default term)
      (search-engine (subseq term 0 idx)
                     (subseq term (+ 1 idx))))))

To use this, you can always use M-x search-web. However, you may want to do it quicker. In that case, I think C-c w is a good choice for a shortcut:

(global-set-key (kbd "C-c w") 'search-web)
@tashrifsanil
Copy link

tashrifsanil commented Sep 7, 2016

Hi,
Awesome job by the way. I just made a minor change to the org file that fixes issues when searching with duckduckgo. Before the fix it would complain about using a non javascript version. I forked your gist for that sole purpose. The fix is on my gist. I would normally do a pull request but with gist you can't, that's why I'm telling you upfront

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment