Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
#+title: =engine-mode= #+options: toc:nil num:nil [[https://melpa.org/#/engine-mode][https://melpa.org/packages/engine-mode-badge.svg]] [[https://stable.melpa.org/#/engine-mode][https://stable.melpa.org/packages/engine-mode-badge.svg]] [[https://www.gnu.org/licenses/gpl-3.0][https://img.shields.io/badge/License-GPL%20v3-blue.svg]] [[https://github.com/hrs/engine-mode/actions/workflows/test.yml][https://github.com/hrs/engine-mode/actions/workflows/test.yml/badge.svg?branch=main]] ~engine-mode~ is a global minor mode for Emacs. It enables you to easily define search engines, bind them to keybindings, and query them from the comfort of your editor. #+ATTR_HTML: :alt Demo searching for a term, with the results opening in a browser window. #+ATTR_HTML: :width 100% [[file:./doc/demo.gif]] For example, suppose we want to be able to easily search GitHub: #+begin_src emacs-lisp (defengine github "https://github.com/search?ref=simplesearch&q=%s") #+end_src This defines an interactive function ~engine/search-github~. When executed it will take the selected region (or prompt for input, if no region is selected) and search GitHub for it, displaying the results in your default browser. The ~defengine~ macro can also take an optional key combination, prefixed with ~engine/keymap-prefix~ (which defaults to =C-x /=). That keybinding will be wrapped in a call to ~kbd~. #+begin_src emacs-lisp (defengine duckduckgo "https://duckduckgo.com/?q=%s" :keybinding "d") #+end_src =C-x / d= is now bound to the new function ~engine/search-duckduckgo~! Nifty. If you'd like to see a video on the whys and wherefores of this mode, check out [[https://www.youtube.com/watch?v=MBhJBMYfWUo][the talk @hrs gave at EmacsNYC]]. ** Installation ~engine-mode~ is available on MELPA. Using ~use-package~: #+begin_src emacs-lisp (use-package engine-mode :ensure t :config (engine-mode t)) #+end_src You can also install it like any other elisp file by adding it to your load path and globally enabling it: #+begin_src emacs-lisp (require 'engine-mode) (engine-mode t) #+end_src ** Changing your default browser ~engine-mode~ uses the ~engine/browser-function~ variable to determine which browser it should use to open the URL it constructs. To change the default browser, redefine ~engine/browser-function~. For example, to always use Emacs' built-in ~eww~ browser: #+begin_src emacs-lisp (setq engine/browser-function 'eww-browse-url) #+end_src ~engine/browser-function~ defaults to ~browse-url-browser-function~, which Emacs uses globally to open links. The implementation of the ~browse-url-browser-function~ variable contains a comprehensive list of possible browser functions. You can get to that by hitting =C-h v browse-url-browser-function <RETURN>= and following the link to =browse-url.el=. ** Changing your browser on a per-engine basis To only change the browser for a single engine, use the ~:browser~ keyword argument when you define the engine. For example, to use ~eww~ only for your GitHub search results, try: #+begin_src emacs-lisp (defengine github "https://github.com/search?ref=simplesearch&q=%s" :browser 'eww-browse-url) #+end_src As mentioned about, see the implementation of the ~browse-url-browser-function~ for a definitive list of browsers. ** Changing the keymap prefix The default keymap prefix for ~engine-mode~ is =C-x /=. If you'd like to bind the keymap to an additional prefix (say, =C-c s=), you totally can: #+begin_src emacs-lisp (engine/set-keymap-prefix (kbd "C-c s")) #+end_src If you use ~use-package~, you can achieve the same thing with: #+begin_src emacs-lisp :bind-keymap ("C-c s" . engine-mode-prefixed-map) #+end_src ** Custom docstrings ~defengine~ assigns each engine a reasonable default docstring, but you can override that on a case-by-case basis with the ~:docstring~ keyword argument: #+begin_src emacs-lisp (defengine ctan "https://www.ctan.org/search/?x=1&PORTAL=on&phrase=%s" :docstring "Search the Comprehensive TeX Archive Network (ctan.org)") #+end_src ** Modifying the search term before sending it An engine might want to transform a search term in some way before it interpolates the term into the URL. Maybe the term should have a different encoding, or be capitalized differently, or, uh, be passed through [[https://en.wikipedia.org/wiki/ROT13][ROT13]]. Whatever the reason, you can apply a custom transformation to a search term by passing a function to ~defengine~ through the ~:term-transformation-hook~ keyword argument. For example, to UPCASE all of your DuckDuckGo searches: #+begin_src emacs-lisp (defengine duckduckgo "https://duckduckgo.com/?q=%s" :term-transformation-hook upcase) #+end_src Or, to ensure that all your queries are encoded as latin-1: #+begin_src emacs-lisp (defengine diec2 "dlc.iec.cat/results.asp?txtEntrada=%s" :term-transformation-hook (lambda (term) (encode-coding-string term latin-1)) :keybinding "c") #+end_src You could also use a ~:term-transformation-hook~ to make an engine behave differently when given a [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Prefix-Command-Arguments.html][prefix argument]] (i.e. typing =C-u= before invoking the engine). Some search engines support querying for exact phrases by enclosing the search string with double quotes. Transformations could be useful in this case to perform a literal search instead if the universal argument is present: #+begin_src emacs-lisp (defengine duckduckgo "https://duckduckgo.com/?q=%s" :term-transformation-hook (lambda (term) (if current-prefix-arg (concat "\"" term "\"") term)) :keybinding "d") #+end_src Typing =C-x / d= will perform a regular search, but typing =C-u C-x / d= will wrap your query in quotes before searching for it. That's especially useful when searching for the contents of the region. ** Importing keyword searches from other browsers Since many browsers save keyword searches using the same format as engine-mode (that is, by using ~%s~ in a url to indicate a search term), it's not too hard to import them into Emacs. [[https://github.com/sshaw][@sshaw]] has written a script to [[https://gist.github.com/sshaw/9b635eabde582ebec442][import from Chrome on OS X]]. Thanks for that! ** Comparison with =webjump= Emacs has a perfectly lovely built-in =webjump= package which allows the user to define a set of URLs, interpolate search terms into them, and visit them in the browser. Why might you use =engine-mode= instead of =webjump=? - You want to bind specific searches to keybindings. Because =engine-mode= defines a function for each engine, keybindings in =engine-mode= can be associated directly with specific searches. - You'd like to associate browser functions with engines on a case-by-case basis. For example, if you want to perform some searches in Firefox, and other searches in =eww=, that's trivial in =engine-mode=. - You like some of =engine-mode='s minor UI conveniences. If you've got a region selected, for example, =engine-mode= will use that as the search query, while =webjump= will ignore it and offer an empty prompt. If you're not interested in these features, =webjump= is a great choice! Honestly, the author of =engine-mode= probably wouldn't have bothered writing it if they'd known =webjump= existed at the time. 😅 ** Engine examples #+begin_src emacs-lisp (defengine amazon "https://www.amazon.com/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords=%s") (defengine duckduckgo "https://duckduckgo.com/?q=%s" :keybinding "d") (defengine github "https://github.com/search?ref=simplesearch&q=%s") (defengine google "https://www.google.com/search?ie=utf-8&oe=utf-8&q=%s" :keybinding "g") (defengine google-images "https://www.google.com/images?hl=en&source=hp&biw=1440&bih=795&gbv=2&aq=f&aqi=&aql=&oq=&q=%s") (defengine google-maps "https://maps.google.com/maps?q=%s" :docstring "Mappin' it up.") (defengine project-gutenberg "https://www.gutenberg.org/ebooks/search/?query=%s") (defengine qwant "https://www.qwant.com/?q=%s") (defengine stack-overflow "https://stackoverflow.com/search?q=%s") (defengine twitter "https://twitter.com/search?q=%s") (defengine wikipedia "https://www.wikipedia.org/search-redirect.php?language=en&go=Go&search=%s" :keybinding "w" :docstring "Searchin' the wikis.") (defengine wiktionary "https://www.wikipedia.org/search-redirect.php?family=wiktionary&language=en&go=Go&search=%s") (defengine wolfram-alpha "https://www.wolframalpha.com/input/?i=%s") (defengine youtube "https://www.youtube.com/results?aq=f&oq=&search_query=%s") #+end_src