PageRenderTime 48ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/navigation/engine-mode.el

https://github.com/budevg/emacs-conf
Emacs Lisp | 178 lines | 98 code | 41 blank | 39 comment | 10 complexity | 93b9fefc2e52db891f99a67137db7a61 MD5 | raw file
  1. ;;; engine-mode.el --- Define and query search engines from within Emacs.
  2. ;; Author: Harry R. Schwartz <hello@harryrschwartz.com>
  3. ;; Version: 2.1.1
  4. ;; URL: https://github.com/hrs/engine-mode
  5. ;; Package-Requires: ((cl-lib "0.5"))
  6. ;; This file is NOT part of GNU Emacs.
  7. ;;; Commentary:
  8. ;; `engine-mode' is a global minor mode for Emacs. It enables you to
  9. ;; easily define search engines, bind them to keybindings, and query
  10. ;; them from the comfort of your editor.
  11. ;; For example, suppose we want to be able to easily search GitHub:
  12. ;; (defengine github
  13. ;; "https://github.com/search?ref=simplesearch&q=%s")
  14. ;; This defines an interactive function `engine/search-github'. When
  15. ;; executed it will take the selected region (or prompt for input, if
  16. ;; no region is selected) and search GitHub for it, displaying the
  17. ;; results in your default browser.
  18. ;; The `defengine' macro can also take an optional key combination,
  19. ;; prefixed with "C-x /":
  20. ;; (defengine duckduckgo
  21. ;; "https://duckduckgo.com/?q=%s"
  22. ;; :keybinding "d")
  23. ;; `C-x / d' is now bound to the new function
  24. ;; engine/search-duckduckgo'! Nifty.
  25. ;;; License:
  26. ;; This program is free software: you can redistribute it and/or modify
  27. ;; it under the terms of the GNU General Public License as published by
  28. ;; the Free Software Foundation, either version 3 of the License, or
  29. ;; (at your option) any later version.
  30. ;; This program is distributed in the hope that it will be useful,
  31. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  32. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  33. ;; GNU General Public License for more details.
  34. ;; You should have received a copy of the GNU General Public License
  35. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  36. ;;; Code:
  37. (eval-when-compile (require 'cl-macs))
  38. (eval-when-compile (require 'format-spec))
  39. (defcustom engine/keybinding-prefix "C-x /"
  40. "The default engine-mode keybindings prefix."
  41. :group 'engine-mode
  42. :type 'string)
  43. (define-prefix-command 'engine-mode-prefixed-map)
  44. (defvar engine-mode-prefixed-map)
  45. (defvar engine-mode-map
  46. (let ((map (make-sparse-keymap)))
  47. (define-key map (kbd engine/keybinding-prefix) engine-mode-prefixed-map)
  48. map)
  49. "Keymap for `engine-mode'.")
  50. ;;;###autoload
  51. (define-minor-mode engine-mode
  52. "Minor mode for defining and querying search engines through Emacs.
  53. \\{engine-mode-map}"
  54. :global t
  55. :keymap engine-mode-map)
  56. (defun engine/set-keymap-prefix (prefix-key)
  57. "Bind the engine-mode keymap to a new prefix.
  58. For example, to use \"C-c s\" instead of the default \"C-x /\":
  59. \(engine/set-keymap-prefix (kbd \"C-c s\"))"
  60. (define-key engine-mode-map (kbd engine/keybinding-prefix) nil)
  61. (define-key engine-mode-map prefix-key engine-mode-prefixed-map))
  62. (defcustom engine/browser-function nil
  63. "The default browser function used when opening a URL in an engine.
  64. Defaults to `nil' which means to go with `browse-url-browser-function'."
  65. :group 'engine-mode
  66. :type 'symbol)
  67. (defun engine/search-prompt (engine-name default-word)
  68. (if (string= default-word "")
  69. (format "Search %s: " (capitalize engine-name))
  70. (format "Search %s (%s): " (capitalize engine-name) default-word)))
  71. (defun engine/prompted-search-term (engine-name)
  72. (let ((current-word (or (thing-at-point 'symbol 'no-properties) "")))
  73. (read-string (engine/search-prompt engine-name current-word)
  74. nil nil current-word)))
  75. (defun engine/get-query (engine-name)
  76. "Return the selected region (if any) or prompt the user for a query."
  77. (if (use-region-p)
  78. (buffer-substring (region-beginning) (region-end))
  79. (engine/prompted-search-term engine-name)))
  80. (defun engine/execute-search (search-engine-url browser-function search-term)
  81. "Display the results of the query."
  82. (interactive)
  83. (let ((browse-url-browser-function (or browser-function
  84. browse-url-browser-function)))
  85. (browse-url
  86. (format-spec search-engine-url
  87. (format-spec-make ?s (url-hexify-string search-term))))))
  88. (defun engine/function-name (engine-name)
  89. (intern (concat "engine/search-" (downcase (symbol-name engine-name)))))
  90. (defun engine/docstring (engine-name)
  91. (concat "Search "
  92. (capitalize (symbol-name engine-name))
  93. " for the selected text. Prompt for input if none is selected."))
  94. (defun engine/bind-key (engine-name keybinding)
  95. (when keybinding
  96. `(define-key engine-mode-prefixed-map (kbd ,keybinding)
  97. (quote ,(engine/function-name engine-name)))))
  98. ;;;###autoload
  99. (cl-defmacro defengine (engine-name search-engine-url &key keybinding docstring (browser 'engine/browser-function) (term-transformation-hook 'identity))
  100. "Define a custom search engine.
  101. `engine-name' is a symbol naming the engine.
  102. `search-engine-url' is the url to be queried, with a \"%s\"
  103. standing in for the search term.
  104. The optional keyword argument `docstring' assigns a docstring to
  105. the generated function. A reasonably sensible docstring will be
  106. generated if a custom one isn't provided.
  107. The optional keyword argument `browser` assigns the browser
  108. function to be used when opening the URL.
  109. The optional keyword argument `term-transformation-hook' is a
  110. function that will be applied to the search term before it's
  111. substituted into `search-engine-url'. For example, if we wanted
  112. to always upcase our search terms, we might use:
  113. \(defengine duckduckgo
  114. \"https://duckduckgo.com/?q=%s\"
  115. :term-transformation-hook 'upcase)
  116. In this case, searching for \"foobar\" will hit the url
  117. \"https://duckduckgo.com/?q=FOOBAR\".
  118. The optional keyword argument `keybinding' is a string describing
  119. the key to bind the new function.
  120. Keybindings are in the `engine-mode-map', so they're prefixed.
  121. For example, to search Wikipedia, use:
  122. (defengine wikipedia
  123. \"http://www.wikipedia.org/search-redirect.php?language=en&go=Go&search=%s\"
  124. :keybinding \"w\"
  125. :docstring \"Search Wikipedia!\")
  126. Hitting \"C-x / w\" will be bound to the newly-defined
  127. `engine/search-wikipedia' function."
  128. (cl-assert (symbolp engine-name))
  129. `(prog1
  130. (defun ,(engine/function-name engine-name) (search-term)
  131. ,(or docstring (engine/docstring engine-name))
  132. (interactive
  133. (list (engine/get-query ,(symbol-name engine-name))))
  134. (engine/execute-search ,search-engine-url ,browser (,term-transformation-hook search-term)))
  135. ,(engine/bind-key engine-name keybinding)))
  136. (provide 'engine-mode)
  137. ;;; engine-mode.el ends here