PageRenderTime 54ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/elpa/helm-20140609.136/helm-net.el

https://github.com/atsushi-i-fsp/dot_emacs
Emacs Lisp | 600 lines | 468 code | 69 blank | 63 comment | 35 complexity | 9ba32d8226b17a1921a27a9d2b7828bc MD5 | raw file
  1. ;;; helm-net.el --- helm browse url and search web. -*- lexical-binding: t -*-
  2. ;; Copyright (C) 2012 ~ 2014 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 'url)
  17. (require 'xml)
  18. (require 'browse-url)
  19. (defgroup helm-net nil
  20. "Net related applications and libraries for Helm."
  21. :group 'helm)
  22. (defcustom helm-google-suggest-default-browser-function nil
  23. "The browse url function you prefer to use with google suggest.
  24. When nil, use the first browser function available
  25. See `helm-browse-url-default-browser-alist'."
  26. :group 'helm-net
  27. :type 'symbol)
  28. (defcustom helm-home-url "http://www.google.fr"
  29. "Default url to use as home url."
  30. :group 'helm-net
  31. :type 'string)
  32. (defcustom helm-surfraw-default-browser-function nil
  33. "The browse url function you prefer to use with surfraw.
  34. When nil, fallback to `browse-url-browser-function'."
  35. :group 'helm-net
  36. :type 'symbol)
  37. (defcustom helm-google-suggest-url
  38. "http://google.com/complete/search?output=toolbar&q="
  39. "URL used for looking up Google suggestions."
  40. :type 'string
  41. :group 'helm-net)
  42. (defcustom helm-google-suggest-search-url
  43. "http://www.google.com/search?ie=utf-8&oe=utf-8&q="
  44. "URL used for Google searching."
  45. :type 'string
  46. :group 'helm-net)
  47. (defcustom helm-google-suggest-use-curl-p nil
  48. "When non--nil use CURL to get info from `helm-google-suggest-url'.
  49. Otherwise `url-retrieve-synchronously' is used."
  50. :type 'boolean
  51. :group 'helm-net)
  52. (defcustom helm-yahoo-suggest-url
  53. "http://search.yahooapis.com/WebSearchService/V1/relatedSuggestion?appid=Generic&query="
  54. "Url used for looking up Yahoo suggestions."
  55. :type 'string
  56. :group 'helm-net)
  57. (defcustom helm-yahoo-suggest-search-url
  58. "http://search.yahoo.com/search?&ei=UTF-8&fr&h=c&p="
  59. "Url used for Yahoo searching."
  60. :type 'string
  61. :group 'helm-net)
  62. (defcustom helm-surfraw-duckduckgo-url
  63. "https://duckduckgo.com/lite/?q=%s&kp=1"
  64. "The duckduckgo url.
  65. This is a format string, don't forget the `%s'.
  66. If you have personal settings saved on duckduckgo you should have
  67. a personal url, see your settings on duckduckgo."
  68. :type 'string
  69. :group 'helm-net)
  70. (defcustom helm-wikipedia-suggest-url
  71. "http://en.wikipedia.org/w/api.php?action=opensearch&search="
  72. "Url used for looking up Wikipedia suggestions."
  73. :type 'string
  74. :group 'helm-net)
  75. (defcustom helm-search-suggest-action-wikipedia-url
  76. "https://en.wikipedia.org/wiki/Special:Search?search=%s"
  77. "The Wikipedia search url.
  78. This is a format string, don't forget the `%s'."
  79. :type 'string
  80. :group 'helm-net)
  81. (defcustom helm-wikipedia-summary-url
  82. "http://en.wikipedia.org/w/api.php?action=parse&format=json&prop=text&section=0&page="
  83. "URL for getting the summary of a Wikipedia topic."
  84. :type 'string
  85. :group 'helm-net)
  86. (defcustom helm-wikipedia-follow-delay 2
  87. "Delay before wikipedia summary popup."
  88. :type 'number
  89. :group 'helm-net)
  90. (defcustom helm-search-suggest-action-youtube-url
  91. "http://www.youtube.com/results?aq=f&search_query=%s"
  92. "The Youtube search url.
  93. This is a format string, don't forget the `%s'."
  94. :type 'string
  95. :group 'helm-net)
  96. (defcustom helm-search-suggest-action-imdb-url
  97. "http://www.imdb.com/find?s=all&q=%s"
  98. "The IMDb search url.
  99. This is a format string, don't forget the `%s'."
  100. :type 'string
  101. :group 'helm-net)
  102. (defcustom helm-search-suggest-action-google-maps-url
  103. "http://maps.google.com/maps?f=q&source=s_q&q=%s"
  104. "The Google Maps search url.
  105. This is a format string, don't forget the `%s'."
  106. :type 'string
  107. :group 'helm-net)
  108. (defcustom helm-search-suggest-action-google-news-url
  109. "http://www.google.com/search?safe=off&prmd=nvlifd&source=lnms&tbs=nws:1&q=%s"
  110. "The Google News search url.
  111. This is a format string, don't forget the `%s'."
  112. :type 'string
  113. :group 'helm-net)
  114. ;;; Additional actions for search suggestions
  115. ;;
  116. ;;
  117. ;; Internal
  118. (defun helm-search-suggest-perform-additional-action (url query)
  119. "Perform the search via URL using QUERY as input."
  120. (browse-url (format url (url-hexify-string query))))
  121. (defvar helm-search-suggest-additional-actions
  122. '(("Wikipedia" . (lambda (candidate)
  123. (helm-search-suggest-perform-additional-action
  124. helm-search-suggest-action-wikipedia-url
  125. candidate)))
  126. ("Youtube" . (lambda (candidate)
  127. (helm-search-suggest-perform-additional-action
  128. helm-search-suggest-action-youtube-url
  129. candidate)))
  130. ("IMDb" . (lambda (candidate)
  131. (helm-search-suggest-perform-additional-action
  132. helm-search-suggest-action-imdb-url
  133. candidate)))
  134. ("Google Maps" . (lambda (candidate)
  135. (helm-search-suggest-perform-additional-action
  136. helm-search-suggest-action-google-maps-url
  137. candidate)))
  138. ("Google News" . (lambda (candidate)
  139. (helm-search-suggest-perform-additional-action
  140. helm-search-suggest-action-google-news-url
  141. candidate))))
  142. "List of additional actions for suggest sources.")
  143. ;;; Google Suggestions
  144. ;;
  145. ;;
  146. ;; Internal
  147. (defvar helm-ggs-max-length-real-flag 0)
  148. (defvar helm-ggs-max-length-num-flag 0)
  149. (defun helm-google-suggest-fetch (input)
  150. "Fetch suggestions for INPUT from XML buffer.
  151. Return an alist with elements like (data . number_results)."
  152. (setq helm-ggs-max-length-real-flag 0
  153. helm-ggs-max-length-num-flag 0)
  154. (let ((request (concat helm-google-suggest-url
  155. (url-hexify-string input)))
  156. (fetch #'(lambda ()
  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
  163. for data = (cdr (cl-caadr (assoc 'suggestion i)))
  164. for nqueries = (cdr (cl-caadr (assoc 'num_queries i)))
  165. for lqueries = (length (helm-ggs-set-number-result
  166. nqueries))
  167. for ldata = (length data)
  168. do
  169. (progn
  170. (when (> ldata helm-ggs-max-length-real-flag)
  171. (setq helm-ggs-max-length-real-flag ldata))
  172. (when (> lqueries helm-ggs-max-length-num-flag)
  173. (setq helm-ggs-max-length-num-flag lqueries)))
  174. collect (cons data nqueries) into cont
  175. finally return cont))))
  176. (if helm-google-suggest-use-curl-p
  177. (with-temp-buffer
  178. (call-process "curl" nil t nil request)
  179. (funcall fetch))
  180. (with-current-buffer
  181. (url-retrieve-synchronously request)
  182. (funcall fetch)))))
  183. (defun helm-google-suggest-set-candidates (&optional request-prefix)
  184. "Set candidates with result and number of google results found."
  185. (let ((suggestions
  186. (cl-loop with suggested-results = (helm-google-suggest-fetch
  187. (or (and request-prefix
  188. (concat request-prefix
  189. " " helm-pattern))
  190. helm-pattern))
  191. for (real . numresult) in suggested-results
  192. ;; Prepare number of results with ","
  193. for fnumresult = (helm-ggs-set-number-result numresult)
  194. ;; Calculate number of spaces to add before fnumresult
  195. ;; if it is smaller than longest result
  196. ;; `helm-ggs-max-length-num-flag'.
  197. ;; e.g 1,234,567
  198. ;; 345,678
  199. ;; To be sure it is aligned properly.
  200. for nspaces = (if (< (length fnumresult)
  201. helm-ggs-max-length-num-flag)
  202. (- helm-ggs-max-length-num-flag
  203. (length fnumresult))
  204. 0)
  205. ;; Add now the spaces before fnumresult.
  206. for align-fnumresult = (concat (make-string nspaces ? )
  207. fnumresult)
  208. for interval = (- helm-ggs-max-length-real-flag
  209. (length real))
  210. for spaces = (make-string (+ 2 interval) ? )
  211. for display = (format "%s%s(%s results)"
  212. real spaces align-fnumresult)
  213. collect (cons display real))))
  214. (if (cl-loop for (_disp . dat) in suggestions
  215. thereis (equal dat helm-pattern))
  216. suggestions
  217. ;; if there is no suggestion exactly matching the input then
  218. ;; prepend a Search on Google item to the list
  219. (append
  220. suggestions
  221. (list (cons (concat "Search for " "'" helm-input "'" " on Google")
  222. helm-input))))))
  223. (defun helm-ggs-set-number-result (num)
  224. (if num
  225. (progn
  226. (and (numberp num) (setq num (number-to-string num)))
  227. (cl-loop for i in (reverse (split-string num "" t))
  228. for count from 1
  229. append (list i) into C
  230. when (= count 3)
  231. append (list ",") into C
  232. and do (setq count 0)
  233. finally return
  234. (replace-regexp-in-string
  235. "^," "" (mapconcat 'identity (reverse C) ""))))
  236. "?"))
  237. (defun helm-google-suggest-action (candidate)
  238. "Default action to jump to a google suggested candidate."
  239. (let ((arg (concat helm-google-suggest-search-url
  240. (url-hexify-string candidate))))
  241. (helm-aif helm-google-suggest-default-browser-function
  242. (funcall it arg)
  243. (helm-browse-url arg))))
  244. (defvar helm-google-suggest-default-function
  245. 'helm-google-suggest-set-candidates
  246. "Default function to use in helm google suggest.")
  247. (defvar helm-source-google-suggest
  248. `((name . "Google Suggest")
  249. (candidates . (lambda ()
  250. (funcall helm-google-suggest-default-function)))
  251. (action . ,(cons '("Google Search" . helm-google-suggest-action)
  252. helm-search-suggest-additional-actions))
  253. (volatile)
  254. (keymap . ,helm-map)
  255. (requires-pattern . 3)))
  256. (defun helm-google-suggest-emacs-lisp ()
  257. "Try to emacs lisp complete with google suggestions."
  258. (helm-google-suggest-set-candidates "emacs lisp"))
  259. ;;; Yahoo suggestions
  260. ;;
  261. ;;
  262. (defun helm-yahoo-suggest-fetch (input)
  263. "Fetch Yahoo suggestions for INPUT from XML buffer.
  264. Return an alist with elements like (data . number_results)."
  265. (let ((request (concat helm-yahoo-suggest-url
  266. (url-hexify-string input))))
  267. (with-current-buffer
  268. (url-retrieve-synchronously request)
  269. (cl-loop with result-alist =
  270. (xml-get-children
  271. (car (xml-parse-region
  272. (point-min) (point-max)))
  273. 'Result)
  274. for i in result-alist
  275. collect (cl-caddr i)))))
  276. (defun helm-yahoo-suggest-set-candidates ()
  277. "Set candidates with Yahoo results found."
  278. (let ((suggestions (helm-yahoo-suggest-fetch helm-input)))
  279. (or suggestions
  280. (append
  281. suggestions
  282. (list (cons (concat "Search for " "'" helm-input "'" " on Yahoo")
  283. helm-input))))))
  284. (defun helm-yahoo-suggest-action (candidate)
  285. "Default action to jump to a Yahoo suggested candidate."
  286. (helm-browse-url (concat helm-yahoo-suggest-search-url
  287. (url-hexify-string candidate))))
  288. (defvar helm-source-yahoo-suggest
  289. `((name . "Yahoo Suggest")
  290. (candidates . helm-yahoo-suggest-set-candidates)
  291. (action . (("Yahoo Search" . helm-yahoo-suggest-action)))
  292. (volatile)
  293. (keymap . ,helm-map)
  294. (requires-pattern . 3)))
  295. ;;; Wikipedia suggestions
  296. ;;
  297. ;;
  298. (declare-function json-read-from-string "json" (string))
  299. (defun helm-wikipedia-suggest-fetch ()
  300. "Fetch Wikipedia suggestions and return them as a list."
  301. (require 'json)
  302. (let ((request (concat helm-wikipedia-suggest-url
  303. (url-hexify-string helm-pattern))))
  304. (if helm-google-suggest-use-curl-p
  305. (with-temp-buffer
  306. (call-process "curl" nil t nil request)
  307. (helm-wikipedia--parse-buffer))
  308. (with-current-buffer
  309. (url-retrieve-synchronously request)
  310. (helm-wikipedia--parse-buffer)))))
  311. (defun helm-wikipedia--parse-buffer ()
  312. (goto-char (point-min))
  313. (when (re-search-forward "^\\[.+\\[\\(.*\\)\\]\\]" nil t)
  314. (cl-loop for i across (aref (json-read-from-string (match-string 0)) 1)
  315. collect i into result
  316. finally return (or result
  317. (append
  318. result
  319. (list (cons (format "Search for '%s' on wikipedia"
  320. helm-pattern)
  321. helm-pattern)))))))
  322. (defvar helm-wikipedia--summary-cache (make-hash-table :test 'equal))
  323. (defun helm-wikipedia-persistent-action (candidate)
  324. (unless (string= (format "Search for '%s' on wikipedia"
  325. helm-pattern)
  326. (helm-get-selection nil t))
  327. (message "Fetching summary from Wikipedia...")
  328. (let ((buf (get-buffer-create "*helm wikipedia summary*"))
  329. result mess)
  330. (while (progn
  331. (setq result (or (gethash candidate helm-wikipedia--summary-cache)
  332. (puthash candidate
  333. (prog1
  334. (helm-wikipedia-fetch-summary candidate)
  335. (setq mess "Done"))
  336. helm-wikipedia--summary-cache)))
  337. (when (and result
  338. (listp result))
  339. (setq candidate (cdr result))
  340. (message "Redirected to %s" candidate)
  341. t)))
  342. (if (not result)
  343. (message "Error when getting summary.")
  344. (with-current-buffer buf
  345. (erase-buffer)
  346. (setq cursor-type nil)
  347. (insert result)
  348. (fill-region (point-min) (point-max))
  349. (goto-char (point-min)))
  350. (display-buffer buf)
  351. (message mess)))))
  352. (defun helm-wikipedia-fetch-summary (input)
  353. (let* ((request (concat helm-wikipedia-summary-url (url-hexify-string input))))
  354. (if helm-google-suggest-use-curl-p
  355. (with-temp-buffer
  356. (call-process "curl" nil t nil request)
  357. (helm-wikipedia--parse-summary))
  358. (with-current-buffer
  359. (url-retrieve-synchronously request)
  360. (helm-wikipedia--parse-summary)))))
  361. (defun helm-wikipedia--parse-summary ()
  362. (goto-char (point-min))
  363. (when (search-forward "{" nil t)
  364. (let ((result (cdr (assoc '*
  365. (assoc 'text
  366. (assoc 'parse
  367. (json-read-from-string
  368. (buffer-substring-no-properties
  369. (1- (point)) (point-max)))))))))
  370. (when result
  371. (if (string-match "<span class=\"redirectText\"><a href=[^>]+>\\([^<]+\\)" result)
  372. (cons 'redirect (match-string 1 result))
  373. ;; find the beginning of the summary text in the result
  374. ;; check if there is a table before the summary and skip that
  375. (when (or (string-match "</table>\\(\n<div.*?</div>\\)?\n<p>" result)
  376. ;; otherwise just find the first paragraph
  377. (string-match "<p>" result))
  378. ;; remove cruft and do a simple formatting
  379. (replace-regexp-in-string
  380. "Cite error: .*" ""
  381. (replace-regexp-in-string
  382. "&#160;" ""
  383. (replace-regexp-in-string
  384. "\\[[^\]]+\\]" ""
  385. (replace-regexp-in-string
  386. "<[^>]*>" ""
  387. (replace-regexp-in-string
  388. "</p>\n<p>" "\n\n"
  389. (substring result (match-end 0)))))))))))))
  390. (defvar helm-source-wikipedia-suggest
  391. `((name . "Wikipedia Suggest")
  392. (candidates . helm-wikipedia-suggest-fetch)
  393. (action . (("Wikipedia" . (lambda (candidate)
  394. (helm-search-suggest-perform-additional-action
  395. helm-search-suggest-action-wikipedia-url
  396. candidate)))))
  397. (persistent-action . helm-wikipedia-persistent-action)
  398. (volatile)
  399. (keymap . ,helm-map)
  400. (follow . 1)
  401. (follow-delay . ,helm-wikipedia-follow-delay)
  402. (requires-pattern . 3)))
  403. ;;; Web browser functions.
  404. ;;
  405. ;;
  406. ;; If default setting of `w3m-command' is not
  407. ;; what you want and you modify it, you will have to reeval
  408. ;; also `helm-browse-url-default-browser-alist'.
  409. (defvar helm-browse-url-chromium-program "chromium-browser")
  410. (defvar helm-browse-url-uzbl-program "uzbl-browser")
  411. (defvar helm-browse-url-default-browser-alist
  412. `((,(or (and (boundp 'w3m-command) w3m-command)
  413. "/usr/bin/w3m") . w3m-browse-url)
  414. (,browse-url-firefox-program . browse-url-firefox)
  415. (,helm-browse-url-chromium-program . helm-browse-url-chromium)
  416. (,helm-browse-url-uzbl-program . helm-browse-url-uzbl)
  417. (,browse-url-kde-program . browse-url-kde)
  418. (,browse-url-gnome-moz-program . browse-url-gnome-moz)
  419. (,browse-url-mozilla-program . browse-url-mozilla)
  420. (,browse-url-galeon-program . browse-url-galeon)
  421. (,browse-url-netscape-program . browse-url-netscape)
  422. (,browse-url-mosaic-program . browse-url-mosaic)
  423. (,browse-url-xterm-program . browse-url-text-xterm)
  424. ("emacs" . eww-browse-url))
  425. "*Alist of \(executable . function\) to try to find a suitable url browser.")
  426. (cl-defun helm-generic-browser (url name &rest args)
  427. "Browse URL with NAME browser."
  428. (let ((proc (concat name " " url)))
  429. (message "Starting %s..." name)
  430. (apply 'start-process proc nil name
  431. (append args (list url)))
  432. (set-process-sentinel
  433. (get-process proc)
  434. #'(lambda (process event)
  435. (when (string= event "finished\n")
  436. (message "%s process %s" process event))))))
  437. (defun helm-browse-url-chromium (url)
  438. "Browse URL with google chrome browser."
  439. (interactive "sURL: ")
  440. (helm-generic-browser
  441. url helm-browse-url-chromium-program))
  442. (defun helm-browse-url-uzbl (url &optional _ignore)
  443. "Browse URL with uzbl browser."
  444. (interactive "sURL: ")
  445. (helm-generic-browser url helm-browse-url-uzbl-program "-u"))
  446. (defun helm-browse-url-default-browser (url &rest args)
  447. "Find the first available browser and ask it to load URL."
  448. (let ((default-browser-fn
  449. (cl-loop for (exe . fn) in helm-browse-url-default-browser-alist
  450. thereis (and exe (executable-find exe) (fboundp fn) fn))))
  451. (if default-browser-fn
  452. (apply default-browser-fn url args)
  453. (error "No usable browser found"))))
  454. (defun helm-browse-url (url &rest args)
  455. "Default command to browse URL."
  456. (if browse-url-browser-function
  457. (browse-url url args)
  458. (helm-browse-url-default-browser url args)))
  459. ;;; Surfraw
  460. ;;
  461. ;; Need external program surfraw.
  462. ;; <http://surfraw.alioth.debian.org/>
  463. ;; Internal
  464. (defvar helm-surfraw-engines-history nil)
  465. (defvar helm-surfraw-input-history nil)
  466. (defvar helm-surfraw--elvi-cache nil)
  467. (defun helm-build-elvi-list ()
  468. "Return list of all engines and descriptions handled by surfraw."
  469. (or helm-surfraw--elvi-cache
  470. (setq helm-surfraw--elvi-cache
  471. (cdr (with-temp-buffer
  472. (call-process "surfraw" nil t nil "-elvi")
  473. (split-string (buffer-string) "\n"))))))
  474. ;;;###autoload
  475. (defun helm-surfraw (pattern engine)
  476. "Preconfigured `helm' to search PATTERN with search ENGINE."
  477. (interactive (list (read-string "SearchFor: "
  478. nil 'helm-surfraw-input-history
  479. (thing-at-point 'symbol))
  480. (helm-comp-read
  481. "Engine: "
  482. (helm-build-elvi-list)
  483. :must-match t
  484. :name "Surfraw Search Engines"
  485. :del-input nil
  486. :history helm-surfraw-engines-history)))
  487. (let* ((engine-nodesc (car (split-string engine)))
  488. (url (if (string= engine-nodesc "duckduckgo")
  489. ;; "sr duckduckgo -p foo" is broken, workaround.
  490. (format helm-surfraw-duckduckgo-url
  491. (url-hexify-string pattern))
  492. (with-temp-buffer
  493. (apply 'call-process "surfraw" nil t nil
  494. (append (list engine-nodesc "-p") (split-string pattern)))
  495. (replace-regexp-in-string
  496. "\n" "" (buffer-string)))))
  497. (browse-url-browser-function (or helm-surfraw-default-browser-function
  498. browse-url-browser-function)))
  499. (if (string= engine-nodesc "W")
  500. (helm-browse-url helm-home-url)
  501. (helm-browse-url url)
  502. (setq helm-surfraw-engines-history
  503. (cons engine (delete engine helm-surfraw-engines-history))))))
  504. ;;;###autoload
  505. (defun helm-google-suggest ()
  506. "Preconfigured `helm' for google search with google suggest."
  507. (interactive)
  508. (helm-other-buffer 'helm-source-google-suggest "*helm google*"))
  509. ;;;###autoload
  510. (defun helm-yahoo-suggest ()
  511. "Preconfigured `helm' for Yahoo searching with Yahoo suggest."
  512. (interactive)
  513. (helm-other-buffer 'helm-source-yahoo-suggest "*helm yahoo*"))
  514. ;;;###autoload
  515. (defun helm-wikipedia-suggest ()
  516. "Preconfigured `helm' for Wikipedia lookup with Wikipedia suggest."
  517. (interactive)
  518. (helm :sources 'helm-source-wikipedia-suggest
  519. :buffer "*helm wikipedia*"))
  520. (provide 'helm-net)
  521. ;; Local Variables:
  522. ;; byte-compile-warnings: (not cl-functions obsolete)
  523. ;; coding: utf-8
  524. ;; indent-tabs-mode: nil
  525. ;; End:
  526. ;;; helm-net.el ends here