PageRenderTime 56ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/elpa/helm-20160217.958/helm-net.el

https://github.com/my8bird/emacs
Emacs Lisp | 526 lines | 411 code | 65 blank | 50 comment | 17 complexity | fa66acf8f573407866ca2abe95d67f17 MD5 | raw file
  1. ;;; helm-net.el --- helm browse url and search web. -*- lexical-binding: t -*-
  2. ;; Copyright (C) 2012 ~ 2015 Thierry Volpiatto <thierry.volpiatto@gmail.com>
  3. ;; This program is free software; you can redistribute it and/or modify
  4. ;; it under the terms of the GNU General Public License as published by
  5. ;; the Free Software Foundation, either version 3 of the License, or
  6. ;; (at your option) any later version.
  7. ;; This program is distributed in the hope that it will be useful,
  8. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. ;; GNU General Public License for more details.
  11. ;; You should have received a copy of the GNU General Public License
  12. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ;;; Code:
  14. (require 'cl-lib)
  15. (require 'helm)
  16. (require 'helm-help)
  17. (require 'url)
  18. (require 'xml)
  19. (require 'browse-url)
  20. (defgroup helm-net nil
  21. "Net related applications and libraries for Helm."
  22. :group 'helm)
  23. (defcustom helm-google-suggest-default-browser-function nil
  24. "The browse url function you prefer to use with google suggest.
  25. When nil, use the first browser function available
  26. See `helm-browse-url-default-browser-alist'."
  27. :group 'helm-net
  28. :type 'symbol)
  29. (defcustom helm-home-url "http://www.google.fr"
  30. "Default url to use as home url."
  31. :group 'helm-net
  32. :type 'string)
  33. (defcustom helm-surfraw-default-browser-function nil
  34. "The browse url function you prefer to use with surfraw.
  35. When nil, fallback to `browse-url-browser-function'."
  36. :group 'helm-net
  37. :type 'symbol)
  38. (defcustom helm-google-suggest-url
  39. "http://google.com/complete/search?output=toolbar&q="
  40. "URL used for looking up Google suggestions."
  41. :type 'string
  42. :group 'helm-net)
  43. (defcustom helm-google-suggest-search-url
  44. "http://www.google.com/search?ie=utf-8&oe=utf-8&q=%s"
  45. "URL used for Google searching."
  46. :type 'string
  47. :group 'helm-net)
  48. (defcustom helm-net-prefer-curl nil
  49. "When non--nil use CURL external program to fetch data.
  50. Otherwise `url-retrieve-synchronously' is used."
  51. :type 'boolean
  52. :group 'helm-net)
  53. (defvaralias 'helm-google-suggest-use-curl-p 'helm-net-prefer-curl)
  54. (make-obsolete-variable 'helm-google-suggest-use-curl-p 'helm-net-prefer-curl "1.7.7")
  55. (defcustom helm-surfraw-duckduckgo-url
  56. "https://duckduckgo.com/lite/?q=%s&kp=1"
  57. "The duckduckgo url.
  58. This is a format string, don't forget the `%s'.
  59. If you have personal settings saved on duckduckgo you should have
  60. a personal url, see your settings on duckduckgo."
  61. :type 'string
  62. :group 'helm-net)
  63. (defcustom helm-wikipedia-suggest-url
  64. "https://en.wikipedia.org/w/api.php?action=opensearch&search="
  65. "Url used for looking up Wikipedia suggestions."
  66. :type 'string
  67. :group 'helm-net)
  68. (defcustom helm-search-suggest-action-wikipedia-url
  69. "https://en.wikipedia.org/wiki/Special:Search?search=%s"
  70. "The Wikipedia search url.
  71. This is a format string, don't forget the `%s'."
  72. :type 'string
  73. :group 'helm-net)
  74. (defcustom helm-wikipedia-summary-url
  75. "http://en.wikipedia.org/w/api.php?action=parse&format=json&prop=text&section=0&page="
  76. "URL for getting the summary of a Wikipedia topic."
  77. :type 'string
  78. :group 'helm-net)
  79. (defcustom helm-wikipedia-follow-delay 2
  80. "Delay before wikipedia summary popup."
  81. :type 'number
  82. :group 'helm-net)
  83. (defcustom helm-search-suggest-action-youtube-url
  84. "http://www.youtube.com/results?aq=f&search_query=%s"
  85. "The Youtube search url.
  86. This is a format string, don't forget the `%s'."
  87. :type 'string
  88. :group 'helm-net)
  89. (defcustom helm-search-suggest-action-imdb-url
  90. "http://www.imdb.com/find?s=all&q=%s"
  91. "The IMDb search url.
  92. This is a format string, don't forget the `%s'."
  93. :type 'string
  94. :group 'helm-net)
  95. (defcustom helm-search-suggest-action-google-maps-url
  96. "http://maps.google.com/maps?f=q&source=s_q&q=%s"
  97. "The Google Maps search url.
  98. This is a format string, don't forget the `%s'."
  99. :type 'string
  100. :group 'helm-net)
  101. (defcustom helm-search-suggest-action-google-news-url
  102. "http://www.google.com/search?safe=off&prmd=nvlifd&source=lnms&tbs=nws:1&q=%s"
  103. "The Google News search url.
  104. This is a format string, don't forget the `%s'."
  105. :type 'string
  106. :group 'helm-net)
  107. (defcustom helm-google-suggest-actions
  108. '(("Google Search" . helm-google-suggest-action)
  109. ("Wikipedia" . (lambda (candidate)
  110. (helm-search-suggest-perform-additional-action
  111. helm-search-suggest-action-wikipedia-url
  112. candidate)))
  113. ("Youtube" . (lambda (candidate)
  114. (helm-search-suggest-perform-additional-action
  115. helm-search-suggest-action-youtube-url
  116. candidate)))
  117. ("IMDb" . (lambda (candidate)
  118. (helm-search-suggest-perform-additional-action
  119. helm-search-suggest-action-imdb-url
  120. candidate)))
  121. ("Google Maps" . (lambda (candidate)
  122. (helm-search-suggest-perform-additional-action
  123. helm-search-suggest-action-google-maps-url
  124. candidate)))
  125. ("Google News" . (lambda (candidate)
  126. (helm-search-suggest-perform-additional-action
  127. helm-search-suggest-action-google-news-url
  128. candidate))))
  129. "List of actions for google suggest sources."
  130. :group 'helm-net
  131. :type '(alist :key-type string :value-type function))
  132. (defcustom helm-browse-url-firefox-new-window "-new-tab"
  133. "Allow choosing to browse url in new window or new tab.
  134. Can be \"-new-tab\" (default) or \"-new-window\"."
  135. :group 'helm-net
  136. :type '(radio
  137. (const :tag "New tab" "-new-tab")
  138. (const :tag "New window" "-new-window")))
  139. ;;; Additional actions for search suggestions
  140. ;;
  141. ;;
  142. ;; Internal
  143. (defun helm-search-suggest-perform-additional-action (url query)
  144. "Perform the search via URL using QUERY as input."
  145. (browse-url (format url (url-hexify-string query))))
  146. (defun helm-net--url-retrieve-sync (request parser)
  147. (if helm-net-prefer-curl
  148. (with-temp-buffer
  149. (call-process "curl" nil t nil request)
  150. (funcall parser))
  151. (with-current-buffer (url-retrieve-synchronously request)
  152. (funcall parser))))
  153. ;;; Google Suggestions
  154. ;;
  155. ;;
  156. (defun helm-google-suggest-parser ()
  157. (cl-loop
  158. with result-alist = (xml-get-children
  159. (car (xml-parse-region
  160. (point-min) (point-max)))
  161. 'CompleteSuggestion)
  162. for i in result-alist collect
  163. (cdr (cl-caadr (assoc 'suggestion i)))))
  164. (defun helm-google-suggest-fetch (input)
  165. "Fetch suggestions for INPUT from XML buffer."
  166. (let ((request (concat helm-google-suggest-url
  167. (url-hexify-string input))))
  168. (helm-net--url-retrieve-sync
  169. request #'helm-google-suggest-parser)))
  170. (defun helm-google-suggest-set-candidates (&optional request-prefix)
  171. "Set candidates with result and number of google results found."
  172. (let ((suggestions (helm-google-suggest-fetch
  173. (or (and request-prefix
  174. (concat request-prefix
  175. " " helm-pattern))
  176. helm-pattern))))
  177. (if (member helm-pattern suggestions)
  178. suggestions
  179. ;; if there is no suggestion exactly matching the input then
  180. ;; prepend a Search on Google item to the list
  181. (append
  182. suggestions
  183. (list (cons (format "Search for '%s' on Google" helm-input)
  184. helm-input))))))
  185. (defun helm-ggs-set-number-result (num)
  186. (if num
  187. (progn
  188. (and (numberp num) (setq num (number-to-string num)))
  189. (cl-loop for i in (reverse (split-string num "" t))
  190. for count from 1
  191. append (list i) into C
  192. when (= count 3)
  193. append (list ",") into C
  194. and do (setq count 0)
  195. finally return
  196. (replace-regexp-in-string
  197. "^," "" (mapconcat 'identity (reverse C) ""))))
  198. "?"))
  199. (defun helm-google-suggest-action (candidate)
  200. "Default action to jump to a google suggested candidate."
  201. (let ((arg (format helm-google-suggest-search-url
  202. (url-hexify-string candidate))))
  203. (helm-aif helm-google-suggest-default-browser-function
  204. (funcall it arg)
  205. (helm-browse-url arg))))
  206. (defvar helm-google-suggest-default-function
  207. 'helm-google-suggest-set-candidates
  208. "Default function to use in helm google suggest.")
  209. (defvar helm-source-google-suggest
  210. (helm-build-sync-source "Google Suggest"
  211. :candidates (lambda ()
  212. (funcall helm-google-suggest-default-function))
  213. :action 'helm-google-suggest-actions
  214. :volatile t
  215. :keymap helm-map
  216. :requires-pattern 3))
  217. (defun helm-google-suggest-emacs-lisp ()
  218. "Try to emacs lisp complete with google suggestions."
  219. (helm-google-suggest-set-candidates "emacs lisp"))
  220. ;;; Wikipedia suggestions
  221. ;;
  222. ;;
  223. (declare-function json-read-from-string "json" (string))
  224. (defun helm-wikipedia-suggest-fetch ()
  225. "Fetch Wikipedia suggestions and return them as a list."
  226. (require 'json)
  227. (let ((request (concat helm-wikipedia-suggest-url
  228. (url-hexify-string helm-pattern))))
  229. (helm-net--url-retrieve-sync
  230. request #'helm-wikipedia--parse-buffer)))
  231. (defun helm-wikipedia--parse-buffer ()
  232. (goto-char (point-min))
  233. (when (re-search-forward "^\\[.+\\[\\(.*\\)\\]\\]" nil t)
  234. (cl-loop for i across (aref (json-read-from-string (match-string 0)) 1)
  235. collect i into result
  236. finally return (or result
  237. (append
  238. result
  239. (list (cons (format "Search for '%s' on wikipedia"
  240. helm-pattern)
  241. helm-pattern)))))))
  242. (defvar helm-wikipedia--summary-cache (make-hash-table :test 'equal))
  243. (defun helm-wikipedia-persistent-action (candidate)
  244. (unless (string= (format "Search for '%s' on wikipedia"
  245. helm-pattern)
  246. (helm-get-selection nil t))
  247. (message "Fetching summary from Wikipedia...")
  248. (let ((buf (get-buffer-create "*helm wikipedia summary*"))
  249. result mess)
  250. (while (progn
  251. (setq result (or (gethash candidate helm-wikipedia--summary-cache)
  252. (puthash candidate
  253. (prog1
  254. (helm-wikipedia-fetch-summary candidate)
  255. (setq mess "Done"))
  256. helm-wikipedia--summary-cache)))
  257. (when (and result
  258. (listp result))
  259. (setq candidate (cdr result))
  260. (message "Redirected to %s" candidate)
  261. t)))
  262. (if (not result)
  263. (message "Error when getting summary.")
  264. (with-current-buffer buf
  265. (erase-buffer)
  266. (setq cursor-type nil)
  267. (insert result)
  268. (fill-region (point-min) (point-max))
  269. (goto-char (point-min)))
  270. (display-buffer buf)
  271. (message mess)))))
  272. (defun helm-wikipedia-fetch-summary (input)
  273. (let* ((request (concat helm-wikipedia-summary-url
  274. (url-hexify-string input))))
  275. (helm-net--url-retrieve-sync
  276. request #'helm-wikipedia--parse-summary)))
  277. (defun helm-wikipedia--parse-summary ()
  278. (goto-char (point-min))
  279. (when (search-forward "{" nil t)
  280. (let ((result (cdr (assoc '*
  281. (assoc 'text
  282. (assoc 'parse
  283. (json-read-from-string
  284. (buffer-substring-no-properties
  285. (1- (point)) (point-max)))))))))
  286. (when result
  287. (if (string-match "<span class=\"redirectText\"><a href=[^>]+>\\([^<]+\\)" result)
  288. (cons 'redirect (match-string 1 result))
  289. ;; find the beginning of the summary text in the result
  290. ;; check if there is a table before the summary and skip that
  291. (when (or (string-match "</table>\\(\n<div.*?</div>\\)?\n<p>" result)
  292. ;; otherwise just find the first paragraph
  293. (string-match "<p>" result))
  294. ;; remove cruft and do a simple formatting
  295. (replace-regexp-in-string
  296. "Cite error: .*" ""
  297. (replace-regexp-in-string
  298. "&#160;" ""
  299. (replace-regexp-in-string
  300. "\\[[^\]]+\\]" ""
  301. (replace-regexp-in-string
  302. "<[^>]*>" ""
  303. (replace-regexp-in-string
  304. "</p>\n<p>" "\n\n"
  305. (substring result (match-end 0)))))))))))))
  306. (defvar helm-source-wikipedia-suggest
  307. (helm-build-sync-source "Wikipedia Suggest"
  308. :candidates #'helm-wikipedia-suggest-fetch
  309. :action '(("Wikipedia" . (lambda (candidate)
  310. (helm-search-suggest-perform-additional-action
  311. helm-search-suggest-action-wikipedia-url
  312. candidate))))
  313. :persistent-action #'helm-wikipedia-persistent-action
  314. :volatile t
  315. :keymap helm-map
  316. :follow 1
  317. :follow-delay helm-wikipedia-follow-delay
  318. :requires-pattern 3))
  319. ;;; Web browser functions.
  320. ;;
  321. ;;
  322. ;; If default setting of `w3m-command' is not
  323. ;; what you want and you modify it, you will have to reeval
  324. ;; also `helm-browse-url-default-browser-alist'.
  325. (defvar helm-browse-url-chromium-program "chromium-browser")
  326. (defvar helm-browse-url-uzbl-program "uzbl-browser")
  327. (defvar helm-browse-url-conkeror-program "conkeror")
  328. (defvar helm-browse-url-default-browser-alist
  329. `((,(or (and (boundp 'w3m-command) w3m-command)
  330. "/usr/bin/w3m") . w3m-browse-url)
  331. (,browse-url-firefox-program . browse-url-firefox)
  332. (,helm-browse-url-chromium-program . helm-browse-url-chromium)
  333. (,helm-browse-url-conkeror-program . helm-browse-url-conkeror)
  334. (,helm-browse-url-uzbl-program . helm-browse-url-uzbl)
  335. (,browse-url-kde-program . browse-url-kde)
  336. (,browse-url-gnome-moz-program . browse-url-gnome-moz)
  337. (,browse-url-mozilla-program . browse-url-mozilla)
  338. (,browse-url-galeon-program . browse-url-galeon)
  339. (,browse-url-netscape-program . browse-url-netscape)
  340. (,browse-url-mosaic-program . browse-url-mosaic)
  341. (,browse-url-xterm-program . browse-url-text-xterm)
  342. ("emacs" . eww-browse-url))
  343. "*Alist of \(executable . function\) to try to find a suitable url browser.")
  344. (cl-defun helm-generic-browser (url cmd-name &rest args)
  345. "Browse URL with NAME browser."
  346. (let ((proc (concat cmd-name " " url)))
  347. (message "Starting %s..." cmd-name)
  348. (apply 'start-process proc nil cmd-name
  349. (append args (list url)))
  350. (set-process-sentinel
  351. (get-process proc)
  352. (lambda (process event)
  353. (when (string= event "finished\n")
  354. (message "%s process %s" process event))))))
  355. (defun helm-browse-url-firefox (url &optional _ignore)
  356. "Same as `browse-url-firefox' but detach from emacs.
  357. So when you quit emacs you can keep your firefox open
  358. and not be prompted to kill firefox process.
  359. NOTE: Probably not supported on some systems (e.g Windows)."
  360. (interactive (list (read-string "URL: " (browse-url-url-at-point))
  361. nil))
  362. (let ((process-environment (browse-url-process-environment)))
  363. (call-process-shell-command
  364. (format "(%s %s %s &)"
  365. browse-url-firefox-program
  366. helm-browse-url-firefox-new-window
  367. url))))
  368. (defun helm-browse-url-chromium (url &optional _ignore)
  369. "Browse URL with google chrome browser."
  370. (interactive "sURL: ")
  371. (helm-generic-browser
  372. url helm-browse-url-chromium-program))
  373. (defun helm-browse-url-uzbl (url &optional _ignore)
  374. "Browse URL with uzbl browser."
  375. (interactive "sURL: ")
  376. (helm-generic-browser url helm-browse-url-uzbl-program "-u"))
  377. (defun helm-browse-url-conkeror (url &optional _ignore)
  378. "Browse URL with conkeror browser."
  379. (interactive "sURL: ")
  380. (helm-generic-browser url helm-browse-url-conkeror-program))
  381. (defun helm-browse-url-default-browser (url &rest args)
  382. "Find the first available browser and ask it to load URL."
  383. (let ((default-browser-fn
  384. (cl-loop for (exe . fn) in helm-browse-url-default-browser-alist
  385. thereis (and exe (executable-find exe) (fboundp fn) fn))))
  386. (if default-browser-fn
  387. (apply default-browser-fn url args)
  388. (error "No usable browser found"))))
  389. (defun helm-browse-url (url &rest args)
  390. "Default command to browse URL."
  391. (if browse-url-browser-function
  392. (browse-url url args)
  393. (helm-browse-url-default-browser url args)))
  394. ;;; Surfraw
  395. ;;
  396. ;; Need external program surfraw.
  397. ;; <http://surfraw.alioth.debian.org/>
  398. ;; Internal
  399. (defvar helm-surfraw-engines-history nil)
  400. (defvar helm-surfraw-input-history nil)
  401. (defvar helm-surfraw--elvi-cache nil)
  402. (defun helm-build-elvi-list ()
  403. "Return list of all engines and descriptions handled by surfraw."
  404. (or helm-surfraw--elvi-cache
  405. (setq helm-surfraw--elvi-cache
  406. (cdr (with-temp-buffer
  407. (call-process "surfraw" nil t nil "-elvi")
  408. (split-string (buffer-string) "\n"))))))
  409. ;;;###autoload
  410. (defun helm-surfraw (pattern engine)
  411. "Preconfigured `helm' to search PATTERN with search ENGINE."
  412. (interactive (list (read-string "SearchFor: "
  413. nil 'helm-surfraw-input-history
  414. (thing-at-point 'symbol))
  415. (helm-comp-read
  416. "Engine: "
  417. (helm-build-elvi-list)
  418. :must-match t
  419. :name "Surfraw Search Engines"
  420. :del-input nil
  421. :history helm-surfraw-engines-history)))
  422. (let* ((engine-nodesc (car (split-string engine)))
  423. (url (if (string= engine-nodesc "duckduckgo")
  424. ;; "sr duckduckgo -p foo" is broken, workaround.
  425. (format helm-surfraw-duckduckgo-url
  426. (url-hexify-string pattern))
  427. (with-temp-buffer
  428. (apply 'call-process "surfraw" nil t nil
  429. (append (list engine-nodesc "-p") (split-string pattern)))
  430. (replace-regexp-in-string
  431. "\n" "" (buffer-string)))))
  432. (browse-url-browser-function (or helm-surfraw-default-browser-function
  433. browse-url-browser-function)))
  434. (if (string= engine-nodesc "W")
  435. (helm-browse-url helm-home-url)
  436. (helm-browse-url url)
  437. (setq helm-surfraw-engines-history
  438. (cons engine (delete engine helm-surfraw-engines-history))))))
  439. ;;;###autoload
  440. (defun helm-google-suggest ()
  441. "Preconfigured `helm' for google search with google suggest."
  442. (interactive)
  443. (helm-other-buffer 'helm-source-google-suggest "*helm google*"))
  444. ;;;###autoload
  445. (defun helm-wikipedia-suggest ()
  446. "Preconfigured `helm' for Wikipedia lookup with Wikipedia suggest."
  447. (interactive)
  448. (helm :sources 'helm-source-wikipedia-suggest
  449. :buffer "*helm wikipedia*"))
  450. (provide 'helm-net)
  451. ;; Local Variables:
  452. ;; byte-compile-warnings: (not cl-functions obsolete)
  453. ;; coding: utf-8
  454. ;; indent-tabs-mode: nil
  455. ;; End:
  456. ;;; helm-net.el ends here