Personal emacs config
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7004 lines
265 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. ;;; counsel.el --- Various completion functions using Ivy -*- lexical-binding: t -*-
  2. ;; Copyright (C) 2015-2021 Free Software Foundation, Inc.
  3. ;; Author: Oleh Krehel <ohwoeowho@gmail.com>
  4. ;; URL: https://github.com/abo-abo/swiper
  5. ;; Package-Version: 0.13.4
  6. ;; Package-Commit: 8cf3f1821cbd1c266296bbd5e59582ae6b8b90a6
  7. ;; Version: 0.13.4
  8. ;; Package-Requires: ((emacs "24.5") (ivy "0.13.4") (swiper "0.13.4"))
  9. ;; Keywords: convenience, matching, tools
  10. ;; This file is part of GNU Emacs.
  11. ;; This file is free software; you can redistribute it and/or modify
  12. ;; it under the terms of the GNU General Public License as published by
  13. ;; the Free Software Foundation; either version 3, or (at your option)
  14. ;; any later version.
  15. ;; This program is distributed in the hope that it will be useful,
  16. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. ;; GNU General Public License for more details.
  19. ;; For a full copy of the GNU General Public License
  20. ;; see <https://www.gnu.org/licenses/>.
  21. ;;; Commentary:
  22. ;; Just call one of the interactive functions in this file to complete
  23. ;; the corresponding thing using `ivy'.
  24. ;;
  25. ;; Currently available:
  26. ;; - Symbol completion for Elisp, Common Lisp, Python, Clojure, C, C++.
  27. ;; - Describe functions for Elisp: function, variable, library, command,
  28. ;; bindings, theme.
  29. ;; - Navigation functions: imenu, ace-line, semantic, outline.
  30. ;; - Git utilities: git-files, git-grep, git-log, git-stash, git-checkout.
  31. ;; - Grep utilities: grep, ag, pt, recoll, ack, rg.
  32. ;; - System utilities: process list, rhythmbox, linux-app.
  33. ;; - Many more.
  34. ;;; Code:
  35. (require 'ivy)
  36. (require 'swiper)
  37. (require 'compile)
  38. (require 'dired)
  39. (eval-when-compile
  40. (require 'subr-x))
  41. (defgroup counsel nil
  42. "Completion functions using Ivy."
  43. :group 'matching
  44. :prefix "counsel-")
  45. ;;* Utility
  46. (defun counsel--elisp-to-pcre (regex &optional look-around)
  47. "Convert REGEX from Elisp format to PCRE format, on best-effort basis.
  48. REGEX may be of any format returned by an Ivy regex function,
  49. namely a string or a list. The return value is always a string.
  50. Note that incorrect results may be returned for sufficiently
  51. complex regexes."
  52. (if (consp regex)
  53. (if (and look-around
  54. (or (cdr regex)
  55. (not (cdar regex))))
  56. (concat
  57. "^"
  58. (mapconcat
  59. (lambda (pair)
  60. (let ((subexp (counsel--elisp-to-pcre (car pair))))
  61. (format "(?%c.*%s)"
  62. (if (cdr pair) ?= ?!)
  63. subexp)))
  64. regex
  65. ""))
  66. (mapconcat
  67. (lambda (pair)
  68. (let ((subexp (counsel--elisp-to-pcre (car pair))))
  69. (if (string-match-p "|" subexp)
  70. (format "(?:%s)" subexp)
  71. subexp)))
  72. (cl-remove-if-not #'cdr regex)
  73. ".*"))
  74. (replace-regexp-in-string
  75. "\\\\[(){}|`']\\|[()]"
  76. (lambda (s)
  77. (or (cdr (assoc s '(("\\(" . "(")
  78. ("\\)" . ")")
  79. ("(" . "\\(")
  80. (")" . "\\)")
  81. ("\\{" . "{")
  82. ("\\}" . "}")
  83. ("\\|" . "|")
  84. ("\\`" . "^")
  85. ("\\'" . "$"))))
  86. (error
  87. "Unexpected error in `counsel--elisp-to-pcre' (got match %S)" s)))
  88. regex t t)))
  89. (defun counsel-directory-name (dir)
  90. "Return the name of directory DIR with a slash."
  91. (file-name-as-directory
  92. (file-name-nondirectory
  93. (directory-file-name dir))))
  94. (defun counsel-string-compose (prefix str)
  95. "Make PREFIX the display prefix of STR through text properties."
  96. (let ((str (copy-sequence str)))
  97. (put-text-property
  98. 0 1 'display
  99. (concat prefix (substring str 0 1))
  100. str)
  101. str))
  102. (defalias 'counsel--executable-find
  103. ;; Gained optional argument in 27.1.
  104. (if (>= emacs-major-version 27)
  105. #'executable-find
  106. (lambda (command &optional _remote)
  107. (executable-find command)))
  108. "Compatibility shim for `executable-find'.")
  109. (defun counsel-require-program (cmd)
  110. "Check system for program used in CMD, printing error if not found.
  111. CMD is either a string or a list of strings.
  112. To skip the `executable-find' check, start the string with a space."
  113. (unless (and (stringp cmd) (string-prefix-p " " cmd))
  114. (let ((program (if (listp cmd)
  115. (car cmd)
  116. (car (split-string cmd)))))
  117. (or (and (stringp program)
  118. (not (string= program ""))
  119. (counsel--executable-find program t))
  120. (user-error "Required program \"%s\" not found in your path" program)))))
  121. (declare-function eshell-split-path "esh-util")
  122. (defun counsel-prompt-function-dir ()
  123. "Return prompt appended with the parent directory."
  124. (require 'esh-util)
  125. (let* ((dir (ivy-state-directory ivy-last))
  126. (parts (nthcdr 3 (eshell-split-path dir)))
  127. (dir (format " [%s]: " (if parts (apply #'concat "..." parts) dir))))
  128. (ivy-add-prompt-count
  129. (replace-regexp-in-string ; Insert dir before any trailing colon.
  130. "\\(?:: ?\\)?\\'" dir (ivy-state-prompt ivy-last) t t))))
  131. (defalias 'counsel--flatten
  132. ;; Added in Emacs 27.1
  133. (if (fboundp 'flatten-tree)
  134. #'flatten-tree
  135. (lambda (tree)
  136. (let (elems)
  137. (while (consp tree)
  138. (let ((elem (pop tree)))
  139. (while (consp elem)
  140. (push (cdr elem) tree)
  141. (setq elem (car elem)))
  142. (if elem (push elem elems))))
  143. (if tree (push tree elems))
  144. (nreverse elems))))
  145. "Compatibility shim for `flatten-tree'.")
  146. (defun counsel--format (formatter &rest args)
  147. "Like `format' but FORMATTER can be a list.
  148. When FORMATTER is a list, only `%s' is replaced with ARGS.
  149. Return a list or string depending on input."
  150. (cond
  151. ((listp formatter)
  152. (counsel--flatten (mapcar
  153. (lambda (it) (if (equal it "%s") (pop args) it))
  154. formatter)))
  155. (t (apply #'format formatter args))))
  156. ;;* Async Utility
  157. (defvar counsel--async-time nil
  158. "Store the time when a new process was started.
  159. Or the time of the last minibuffer update.")
  160. (defvar counsel--async-start nil
  161. "Store the time when a new process was started.")
  162. (defvar counsel--async-timer nil
  163. "Timer used to dispose `counsel--async-command.")
  164. (defvar counsel--async-duration nil
  165. "Store the time a process takes to gather all its candidates.
  166. The time is measured in seconds.")
  167. (defvar counsel--async-exit-code-plist ()
  168. "Associate commands with their exit code descriptions.
  169. This plist maps commands to a plist mapping their exit codes to
  170. descriptions.")
  171. (defvar counsel--async-last-error-string nil
  172. "When the process returned non-0, store the output here.")
  173. (defun counsel-set-async-exit-code (cmd number str)
  174. "For CMD, associate NUMBER exit code with STR."
  175. (let ((plist (plist-get counsel--async-exit-code-plist cmd)))
  176. (setq counsel--async-exit-code-plist
  177. (plist-put counsel--async-exit-code-plist
  178. cmd
  179. (plist-put plist number str)))))
  180. (defvar counsel-async-split-string-re-alist '((t . "[\r\n]"))
  181. "Store the regexp for splitting shell command output.")
  182. (defvar counsel-async-ignore-re-alist nil
  183. "An alist of regexp matching candidates to ignore in `counsel--async-filter'.")
  184. (defvar counsel--async-last-command nil
  185. "Store the last command ran by `counsel--async-command-1'.")
  186. (defun counsel--async-command-1 (cmd &optional sentinel filter name)
  187. "Start and return new counsel process by calling CMD.
  188. CMD can be either a shell command as a string, or a list of the
  189. program name to be called directly, followed by its arguments.
  190. If the default counsel process or one with NAME already exists,
  191. kill it and its associated buffer before starting a new one.
  192. Give the process the functions SENTINEL and FILTER, which default
  193. to `counsel--async-sentinel' and `counsel--async-filter',
  194. respectively."
  195. (counsel-delete-process name)
  196. (setq name (or name " *counsel*"))
  197. (when (get-buffer name)
  198. (kill-buffer name))
  199. (setq counsel--async-last-command cmd)
  200. (let* ((buf (get-buffer-create name))
  201. (proc (if (listp cmd)
  202. (apply #'start-file-process name buf cmd)
  203. (start-file-process-shell-command name buf cmd))))
  204. (setq counsel--async-time (current-time))
  205. (setq counsel--async-start counsel--async-time)
  206. (set-process-sentinel proc (or sentinel #'counsel--async-sentinel))
  207. (set-process-filter proc (or filter #'counsel--async-filter))
  208. proc))
  209. (defcustom counsel-async-command-delay 0
  210. "Number of seconds to wait before spawning another async command."
  211. :type 'number)
  212. (defun counsel--async-command (&rest args)
  213. "Like `counsel--async-command-1', with same ARGS, but debounced.
  214. Calls to `counsel--async-command-1' are separated by at least
  215. `counsel-async-command-delay' seconds, so as to avoid issues
  216. caused by spawning too many subprocesses too quickly."
  217. (if (zerop counsel-async-command-delay)
  218. (apply #'counsel--async-command-1 args)
  219. (when counsel--async-timer
  220. (cancel-timer counsel--async-timer))
  221. (setq counsel--async-timer
  222. (apply #'run-with-timer
  223. counsel-async-command-delay
  224. nil
  225. #'counsel--async-command-1
  226. args))))
  227. (defun counsel--split-string (&optional str)
  228. (split-string
  229. (or str (buffer-string))
  230. (ivy-alist-setting counsel-async-split-string-re-alist)
  231. t))
  232. (defun counsel--sync-sentinel-on-exit (process)
  233. (if (zerop (process-exit-status process))
  234. (let ((cur (ivy-state-current ivy-last)))
  235. (ivy--set-candidates
  236. (ivy--sort-maybe
  237. (with-current-buffer (process-buffer process)
  238. (counsel--split-string))))
  239. (when counsel--async-start
  240. (setq counsel--async-duration
  241. (time-to-seconds (time-since counsel--async-start))))
  242. (let ((re (ivy-re-to-str ivy-regex)))
  243. (if ivy--old-cands
  244. (if (eq (ivy-alist-setting ivy-index-functions-alist) 'ivy-recompute-index-zero)
  245. (ivy-set-index 0)
  246. (ivy--recompute-index re ivy--all-candidates))
  247. ;; index was changed before a long-running query exited
  248. (unless (string= cur (nth ivy--index ivy--all-candidates))
  249. (let ((func (ivy-alist-setting ivy-index-functions-alist)))
  250. (if func
  251. (funcall func re ivy--all-candidates)
  252. (ivy--preselect-index
  253. (if (> (length re) 0)
  254. cur
  255. (ivy-state-preselect ivy-last))
  256. ivy--all-candidates))))))
  257. (setq ivy--old-cands ivy--all-candidates)
  258. (if ivy--all-candidates
  259. (ivy--exhibit)
  260. (ivy--insert-minibuffer "")))
  261. (setq counsel--async-last-error-string
  262. (with-current-buffer (process-buffer process) (buffer-string)))
  263. (setq ivy--all-candidates
  264. (let ((status (process-exit-status process))
  265. (plist (plist-get counsel--async-exit-code-plist
  266. (ivy-state-caller ivy-last))))
  267. (list (or (plist-get plist status)
  268. (format "error code %d" status)))))
  269. (setq ivy--old-cands ivy--all-candidates)
  270. (ivy--exhibit)))
  271. (defun counsel--async-sentinel (process _msg)
  272. "Sentinel function for an asynchronous counsel PROCESS."
  273. (when (eq (process-status process) 'exit)
  274. (counsel--sync-sentinel-on-exit process)))
  275. (defcustom counsel-async-filter-update-time 500000
  276. "The amount of microseconds to wait until updating `counsel--async-filter'."
  277. :type 'integer)
  278. (defun counsel--async-filter (process str)
  279. "Receive from PROCESS the output STR.
  280. Update the minibuffer with the amount of lines collected every
  281. `counsel-async-filter-update-time' microseconds since the last update."
  282. (with-current-buffer (process-buffer process)
  283. (insert str))
  284. (when (time-less-p (list 0 0 counsel-async-filter-update-time)
  285. (time-since counsel--async-time))
  286. (let (numlines)
  287. (with-current-buffer (process-buffer process)
  288. (setq numlines (count-lines (point-min) (point-max)))
  289. (ivy--set-candidates
  290. (let ((lines (counsel--split-string))
  291. (ignore-re (ivy-alist-setting counsel-async-ignore-re-alist)))
  292. (if (stringp ignore-re)
  293. (cl-remove-if (lambda (line)
  294. (string-match-p ignore-re line))
  295. lines)
  296. lines))))
  297. (let ((ivy--prompt (format "%d++ %s" numlines (ivy-state-prompt ivy-last))))
  298. (ivy--insert-minibuffer (ivy--format ivy--all-candidates)))
  299. (setq counsel--async-time (current-time)))))
  300. (defun counsel-delete-process (&optional name)
  301. "Delete current counsel process or that with NAME."
  302. (let ((process (get-process (or name " *counsel*"))))
  303. (when process
  304. (delete-process process))))
  305. ;;* Completion at point
  306. (define-obsolete-function-alias 'counsel-el 'complete-symbol "<2020-05-20 Wed>")
  307. (define-obsolete-function-alias 'counsel-cl 'complete-symbol "<2020-05-20 Wed>")
  308. (define-obsolete-function-alias 'counsel-jedi 'complete-symbol "<2020-05-20 Wed>")
  309. (define-obsolete-function-alias 'counsel-clj 'complete-symbol "<2020-05-20 Wed>")
  310. ;;** `counsel-company'
  311. (defvar company-candidates)
  312. (defvar company-common)
  313. (defvar company-prefix)
  314. (declare-function company-abort "ext:company")
  315. (declare-function company-complete "ext:company")
  316. (declare-function company-mode "ext:company")
  317. (declare-function company-call-backend "ext:company")
  318. (declare-function company--clean-string "ext:company")
  319. ;;;###autoload
  320. (defun counsel-company ()
  321. "Complete using `company-candidates'."
  322. (interactive)
  323. (company-mode 1)
  324. (unless company-candidates
  325. (company-complete))
  326. (let ((len (cond ((let (l)
  327. (and company-common
  328. (string= company-common
  329. (buffer-substring
  330. (- (point) (setq l (length company-common)))
  331. (point)))
  332. l)))
  333. (company-prefix
  334. (length company-prefix)))))
  335. (when len
  336. (setq ivy-completion-beg (- (point) len))
  337. (setq ivy-completion-end (point))
  338. (ivy-read "Candidate: " company-candidates
  339. :action #'ivy-completion-in-region-action
  340. :caller 'counsel-company))))
  341. (ivy-configure 'counsel-company
  342. :display-transformer-fn #'counsel--company-display-transformer
  343. :unwind-fn #'company-abort)
  344. (defun counsel--company-display-transformer (s)
  345. (concat s (let ((annot (company-call-backend 'annotation s)))
  346. (when annot
  347. (company--clean-string annot)))))
  348. ;;** `counsel-irony'
  349. (declare-function irony-completion-candidates-async "ext:irony-completion")
  350. (declare-function irony-completion-symbol-bounds "ext:irony-completion")
  351. (declare-function irony-completion-annotation "ext:irony-completion")
  352. ;;;###autoload
  353. (defun counsel-irony ()
  354. "Inline C/C++ completion using Irony."
  355. (interactive)
  356. (irony-completion-candidates-async 'counsel-irony-callback))
  357. (defun counsel-irony-callback (candidates)
  358. "Callback function for Irony to search among CANDIDATES."
  359. (interactive)
  360. (let* ((symbol-bounds (irony-completion-symbol-bounds))
  361. (beg (car symbol-bounds))
  362. (end (cdr symbol-bounds))
  363. (prefix (buffer-substring-no-properties beg end)))
  364. (setq ivy-completion-beg beg
  365. ivy-completion-end end)
  366. (ivy-read "code: " (mapcar #'counsel-irony-annotate candidates)
  367. :predicate (lambda (candidate)
  368. (string-prefix-p prefix (car candidate)))
  369. :caller 'counsel-irony
  370. :action #'ivy-completion-in-region-action)))
  371. (defun counsel-irony-annotate (x)
  372. "Make Ivy candidate from Irony candidate X."
  373. (cons (concat (car x) (irony-completion-annotation x))
  374. (car x)))
  375. (ivy-configure #'counsel-irony
  376. :display-fn #'ivy-display-function-overlay)
  377. ;;* Elisp symbols
  378. ;;** `counsel-describe-variable'
  379. (defvar counsel-describe-map
  380. (let ((map (make-sparse-keymap)))
  381. (define-key map (kbd "C-.") #'counsel-find-symbol)
  382. (define-key map (kbd "C-,") #'counsel--info-lookup-symbol)
  383. map))
  384. (ivy-set-actions
  385. 'counsel-describe-variable
  386. '(("I" counsel-info-lookup-symbol "info")
  387. ("d" counsel--find-symbol "definition")))
  388. (defvar counsel-describe-symbol-history ()
  389. "History list for variable and function names.
  390. Used by commands `counsel-describe-symbol',
  391. `counsel-describe-variable', and `counsel-describe-function'.")
  392. (defun counsel-find-symbol ()
  393. "Jump to the definition of the current symbol."
  394. (interactive)
  395. (ivy-exit-with-action #'counsel--find-symbol))
  396. (put 'counsel-find-symbol 'no-counsel-M-x t)
  397. (defun counsel--info-lookup-symbol ()
  398. "Lookup the current symbol in the info docs."
  399. (interactive)
  400. (ivy-exit-with-action #'counsel-info-lookup-symbol))
  401. (defvar find-tag-marker-ring)
  402. (declare-function xref-push-marker-stack "xref")
  403. (defalias 'counsel--push-xref-marker
  404. ;; Added in Emacs 25.1.
  405. (if (require 'xref nil t)
  406. #'xref-push-marker-stack
  407. (require 'etags)
  408. (lambda (&optional m)
  409. (ring-insert (with-no-warnings find-tag-marker-ring) (or m (point-marker)))))
  410. "Compatibility shim for `xref-push-marker-stack'.")
  411. (defun counsel--find-symbol (x)
  412. "Find symbol definition that corresponds to string X."
  413. (with-ivy-window
  414. (counsel--push-xref-marker)
  415. (let ((full-name (get-text-property 0 'full-name x)))
  416. (if full-name
  417. (find-library full-name)
  418. (let ((sym (read x)))
  419. (cond ((and (eq (ivy-state-caller ivy-last)
  420. 'counsel-describe-variable)
  421. (boundp sym))
  422. (find-variable sym))
  423. ((fboundp sym)
  424. (find-function sym))
  425. ((boundp sym)
  426. (find-variable sym))
  427. ((or (featurep sym)
  428. (locate-library
  429. (prin1-to-string sym)))
  430. (find-library
  431. (prin1-to-string sym)))
  432. (t
  433. (error "Couldn't find definition of %s"
  434. sym))))))))
  435. (defun counsel--variable-p (symbol)
  436. "Return non-nil if SYMBOL is a bound or documented variable."
  437. (or (and (boundp symbol)
  438. (not (keywordp symbol)))
  439. (get symbol 'variable-documentation)))
  440. (defcustom counsel-describe-variable-function #'describe-variable
  441. "Function to call to describe a variable passed as parameter."
  442. :type 'function)
  443. (defun counsel-describe-variable-transformer (var)
  444. "Propertize VAR if it's a custom variable."
  445. (if (custom-variable-p (intern var))
  446. (ivy-append-face var 'ivy-highlight-face)
  447. var))
  448. ;;;###autoload
  449. (defun counsel-describe-variable ()
  450. "Forward to `describe-variable'.
  451. Variables declared using `defcustom' are highlighted according to
  452. `ivy-highlight-face'."
  453. (interactive)
  454. (let ((enable-recursive-minibuffers t))
  455. (ivy-read "Describe variable: " obarray
  456. :predicate #'counsel--variable-p
  457. :require-match t
  458. :history 'counsel-describe-symbol-history
  459. :keymap counsel-describe-map
  460. :preselect (ivy-thing-at-point)
  461. :action (lambda (x)
  462. (funcall counsel-describe-variable-function (intern x)))
  463. :caller 'counsel-describe-variable)))
  464. (ivy-configure 'counsel-describe-variable
  465. :parent 'counsel-describe-symbol
  466. :display-transformer-fn #'counsel-describe-variable-transformer)
  467. ;;** `counsel-describe-function'
  468. (ivy-set-actions
  469. 'counsel-describe-function
  470. '(("I" counsel-info-lookup-symbol "info")
  471. ("d" counsel--find-symbol "definition")))
  472. (defcustom counsel-describe-function-function #'describe-function
  473. "Function to call to describe a function passed as parameter."
  474. :type 'function)
  475. (defun counsel-describe-function-transformer (function-name)
  476. "Propertize FUNCTION-NAME if it's an interactive function."
  477. (if (commandp (intern function-name))
  478. (ivy-append-face function-name 'ivy-highlight-face)
  479. function-name))
  480. (defun ivy-function-called-at-point ()
  481. (let ((f (function-called-at-point)))
  482. (and f (symbol-name f))))
  483. (defcustom counsel-describe-function-preselect #'ivy-thing-at-point
  484. "Determine what `counsel-describe-function' should preselect."
  485. :type '(radio
  486. (function-item ivy-thing-at-point)
  487. (function-item ivy-function-called-at-point)))
  488. ;;;###autoload
  489. (defun counsel-describe-function ()
  490. "Forward to `describe-function'.
  491. Interactive functions (i.e., commands) are highlighted according
  492. to `ivy-highlight-face'."
  493. (interactive)
  494. (let ((enable-recursive-minibuffers t))
  495. (ivy-read "Describe function: " obarray
  496. :predicate (lambda (sym)
  497. (or (fboundp sym)
  498. (get sym 'function-documentation)))
  499. :require-match t
  500. :history 'counsel-describe-symbol-history
  501. :keymap counsel-describe-map
  502. :preselect (funcall counsel-describe-function-preselect)
  503. :action (lambda (x)
  504. (funcall counsel-describe-function-function (intern x)))
  505. :caller 'counsel-describe-function)))
  506. (ivy-configure 'counsel-describe-function
  507. :parent 'counsel-describe-symbol
  508. :display-transformer-fn #'counsel-describe-function-transformer)
  509. ;;** `counsel-describe-symbol'
  510. (defcustom counsel-describe-symbol-function #'describe-symbol
  511. "Function to call to describe a symbol passed as parameter."
  512. :type 'function)
  513. ;;;###autoload
  514. (defun counsel-describe-symbol ()
  515. "Forward to `describe-symbol'."
  516. (interactive)
  517. (unless (functionp 'describe-symbol)
  518. (user-error "This command requires Emacs 25.1 or later"))
  519. (require 'help-mode)
  520. (let ((enable-recursive-minibuffers t))
  521. (ivy-read "Describe symbol: " obarray
  522. :predicate (lambda (sym)
  523. (cl-some (lambda (backend)
  524. (funcall (cadr backend) sym))
  525. describe-symbol-backends))
  526. :require-match t
  527. :history 'counsel-describe-symbol-history
  528. :keymap counsel-describe-map
  529. :preselect (ivy-thing-at-point)
  530. :action (lambda (x)
  531. (funcall counsel-describe-symbol-function (intern x)))
  532. :caller 'counsel-describe-symbol)))
  533. (ivy-configure 'counsel-describe-symbol
  534. :initial-input "^"
  535. :sort-fn #'ivy-string<)
  536. (ivy-set-actions
  537. 'counsel-describe-symbol
  538. `(("I" ,#'counsel-info-lookup-symbol "info")
  539. ("d" ,#'counsel--find-symbol "definition")))
  540. ;;** `counsel-set-variable'
  541. (defvar counsel-set-variable-history nil
  542. "Store history for `counsel-set-variable'.")
  543. (defun counsel-read-setq-expression (sym)
  544. "Read and eval a setq expression for SYM."
  545. (setq this-command 'eval-expression)
  546. (let* ((sym-value (symbol-value sym))
  547. (init (format "(setq %s%S)"
  548. (if (or (consp sym-value)
  549. (and sym-value (symbolp sym-value)))
  550. "'"
  551. "")
  552. sym-value)))
  553. ;; Most of this duplicates `read--expression'.
  554. (minibuffer-with-setup-hook
  555. (lambda ()
  556. (set-syntax-table emacs-lisp-mode-syntax-table)
  557. ;; Added in Emacs 25.1.
  558. (when (fboundp 'elisp-completion-at-point)
  559. (add-hook 'completion-at-point-functions
  560. #'elisp-completion-at-point nil t))
  561. ;; Emacs 27+ already sets up ElDoc in this hook. Emacs 25 added
  562. ;; `elisp-eldoc-documentation-function' and Emacs 28 obsoletes it.
  563. (when (< emacs-major-version 27)
  564. (when (fboundp 'elisp-eldoc-documentation-function)
  565. (add-function :before-until (local 'eldoc-documentation-function)
  566. #'elisp-eldoc-documentation-function))
  567. (eldoc-mode))
  568. (run-hooks 'eval-expression-minibuffer-setup-hook)
  569. ;; The following diverges from `read--expression'.
  570. (goto-char (minibuffer-prompt-end))
  571. (forward-char 6)
  572. (insert (format "%S " sym)))
  573. (read-from-minibuffer "Eval: " init read-expression-map t
  574. 'read-expression-history))))
  575. (defun counsel--setq-doconst (x)
  576. "Return a cons of description and value for X.
  577. X is an item of a radio- or choice-type defcustom."
  578. (when (listp x)
  579. (let ((v (car-safe (last x)))
  580. (tag (and (eq (car x) 'const)
  581. (plist-get (cdr x) :tag))))
  582. (when (and (or v tag) (not (eq v 'function)))
  583. (cons
  584. (concat
  585. (when tag
  586. (concat tag ": "))
  587. (if (stringp v) v (prin1-to-string v)))
  588. (if (symbolp v)
  589. (list 'quote v)
  590. v))))))
  591. (declare-function lv-message "ext:lv")
  592. (declare-function lv-delete-window "ext:lv")
  593. (declare-function custom-variable-documentation "cus-edit")
  594. (defface counsel-variable-documentation
  595. '((t :inherit font-lock-comment-face))
  596. "Face for displaying Lisp documentation."
  597. :group 'ivy-faces)
  598. ;;;###autoload
  599. (defun counsel-set-variable (sym)
  600. "Set a variable SYM, with completion.
  601. When the selected variable is a `defcustom' with the type boolean
  602. or radio, offer completion of all possible values.
  603. Otherwise, offer a variant of `eval-expression', with the initial
  604. input corresponding to the chosen variable.
  605. With a prefix arg, restrict list to variables defined using
  606. `defcustom'."
  607. (interactive (list (intern
  608. (ivy-read "Set variable: " obarray
  609. :predicate (if current-prefix-arg
  610. #'custom-variable-p
  611. #'counsel--variable-p)
  612. :history 'counsel-set-variable-history
  613. :preselect (ivy-thing-at-point)))))
  614. (let ((doc (and (require 'cus-edit)
  615. (require 'lv nil t)
  616. (not (string= "nil" (custom-variable-documentation sym)))
  617. (propertize (custom-variable-documentation sym)
  618. 'face 'counsel-variable-documentation)))
  619. sym-type
  620. cands)
  621. (unwind-protect
  622. (progn
  623. (when doc
  624. (lv-message (ivy--quote-format-string doc)))
  625. (if (and (boundp sym)
  626. (setq sym-type (get sym 'custom-type))
  627. (cond
  628. ((and (consp sym-type)
  629. (memq (car sym-type) '(choice radio)))
  630. (setq cands (delq nil (mapcar #'counsel--setq-doconst
  631. (cdr sym-type)))))
  632. ((eq sym-type 'boolean)
  633. (setq cands '(("nil" . nil) ("t" . t))))
  634. (t nil)))
  635. (let* ((sym-val (symbol-value sym))
  636. (res (ivy-read (format "Set (%S <%s>): " sym sym-val)
  637. cands
  638. :preselect (prin1-to-string sym-val))))
  639. (when res
  640. (setq res
  641. (if (assoc res cands)
  642. (cdr (assoc res cands))
  643. (read res)))
  644. (kill-new (format "(setq %S %S)" sym res))
  645. (set sym (if (and (listp res) (eq (car res) 'quote))
  646. (cadr res)
  647. res))))
  648. (unless (boundp sym)
  649. (set sym nil))
  650. (let ((expr (counsel-read-setq-expression sym)))
  651. (kill-new (format "%S" expr))
  652. (eval-expression expr))))
  653. (when doc
  654. (lv-delete-window)))))
  655. ;;** `counsel-apropos'
  656. ;;;###autoload
  657. (defun counsel-apropos ()
  658. "Show all matching symbols.
  659. See `apropos' for further information on what is considered
  660. a symbol and how to search for them."
  661. (interactive)
  662. (ivy-read "Search for symbol (word list or regexp): " obarray
  663. :predicate (lambda (sym)
  664. (or (fboundp sym)
  665. (boundp sym)
  666. (facep sym)
  667. (symbol-plist sym)))
  668. :history 'counsel-apropos-history
  669. :preselect (ivy-thing-at-point)
  670. :action (lambda (pattern)
  671. (when (string= pattern "")
  672. (user-error "Please specify a pattern"))
  673. ;; If the user selected a candidate form the list, we use
  674. ;; a pattern which matches only the selected symbol.
  675. (if (memq this-command '(ivy-immediate-done ivy-alt-done))
  676. ;; Regexp pattern are passed verbatim, other input is
  677. ;; split into words.
  678. (if (string= (regexp-quote pattern) pattern)
  679. (apropos (split-string pattern "[ \t]+" t))
  680. (apropos pattern))
  681. (apropos (concat "\\`" pattern "\\'"))))
  682. :caller 'counsel-apropos))
  683. (ivy-configure 'counsel-apropos
  684. :sort-fn #'ivy-string<)
  685. ;;** `counsel-info-lookup-symbol'
  686. (defvar info-lookup-mode)
  687. (declare-function info-lookup-guess-default "info-look")
  688. (declare-function info-lookup->completions "info-look")
  689. (declare-function info-lookup->mode-value "info-look")
  690. (declare-function info-lookup-select-mode "info-look")
  691. (declare-function info-lookup-change-mode "info-look")
  692. (declare-function info-lookup "info-look")
  693. ;;;###autoload
  694. (defun counsel-info-lookup-symbol (symbol &optional mode)
  695. "Forward SYMBOL to `info-lookup-symbol' with ivy completion.
  696. With prefix arg MODE a query for the symbol help mode is offered."
  697. (interactive
  698. (progn
  699. (require 'info-look)
  700. ;; Courtesy of `info-lookup-interactive-arguments'
  701. (let* ((topic 'symbol)
  702. (mode (cond (current-prefix-arg
  703. (info-lookup-change-mode topic))
  704. ((info-lookup->mode-value
  705. topic (info-lookup-select-mode))
  706. info-lookup-mode)
  707. ((info-lookup-change-mode topic))))
  708. (enable-recursive-minibuffers t))
  709. (list (ivy-read "Describe symbol: " (info-lookup->completions topic mode)
  710. :history 'info-lookup-history
  711. :preselect (info-lookup-guess-default topic mode)
  712. :caller 'counsel-info-lookup-symbol)
  713. mode))))
  714. (info-lookup-symbol symbol mode))
  715. (ivy-configure 'counsel-info-lookup-symbol
  716. :sort-fn #'ivy-string<)
  717. ;;** `counsel-M-x'
  718. (defface counsel-key-binding
  719. '((t :inherit font-lock-keyword-face))
  720. "Face used by `counsel-M-x' for key bindings."
  721. :group 'ivy-faces)
  722. (defface counsel-active-mode
  723. '((t :inherit font-lock-builtin-face))
  724. "Face used by `counsel-M-x' for activated modes."
  725. :group 'ivy-faces)
  726. (defcustom counsel-alias-expand t
  727. "When non-nil, show the expansion of aliases in `counsel-M-x'."
  728. :type 'boolean
  729. :group 'ivy)
  730. (defun counsel-M-x-transformer (cmd)
  731. "Return CMD annotated with its active key binding, if any."
  732. (let* ((sym (intern cmd))
  733. (alias (symbol-function sym))
  734. (key (where-is-internal sym nil t)))
  735. (when (or (eq sym major-mode)
  736. (and
  737. (memq sym minor-mode-list)
  738. (boundp sym)
  739. (buffer-local-value sym (ivy-state-buffer ivy-last))))
  740. (setq cmd (propertize cmd 'face 'counsel-active-mode)))
  741. (concat cmd
  742. (when (and (symbolp alias) counsel-alias-expand)
  743. (format " (%s)" alias))
  744. (when key
  745. ;; Prefer `<f2>' over `C-x 6' where applicable
  746. (let ((i (cl-search [?\C-x ?6] key)))
  747. (when i
  748. (let ((dup (vconcat (substring key 0 i) [f2] (substring key (+ i 2))))
  749. (map (current-global-map)))
  750. (when (equal (lookup-key map key)
  751. (lookup-key map dup))
  752. (setq key dup)))))
  753. (setq key (key-description key))
  754. (put-text-property 0 (length key) 'face 'counsel-key-binding key)
  755. (format " (%s)" key)))))
  756. (defvar amx-initialized)
  757. (defvar amx-cache)
  758. (declare-function amx-initialize "ext:amx")
  759. (declare-function amx-detect-new-commands "ext:amx")
  760. (declare-function amx-update "ext:amx")
  761. (declare-function amx-rank "ext:amx")
  762. (defvar smex-initialized-p)
  763. (defvar smex-ido-cache)
  764. (declare-function smex-initialize "ext:smex")
  765. (declare-function smex-detect-new-commands "ext:smex")
  766. (declare-function smex-update "ext:smex")
  767. (declare-function smex-rank "ext:smex")
  768. (defun counsel--M-x-externs ()
  769. "Return `counsel-M-x' candidates from external packages.
  770. The return value is a list of strings. The currently supported
  771. packages are, in order of precedence, `amx' and `smex'."
  772. (cond ((require 'amx nil t)
  773. (unless amx-initialized
  774. (amx-initialize))
  775. (when (amx-detect-new-commands)
  776. (amx-update))
  777. (mapcar (lambda (entry)
  778. (symbol-name (car entry)))
  779. amx-cache))
  780. ((require 'smex nil t)
  781. (unless smex-initialized-p
  782. (smex-initialize))
  783. (when (smex-detect-new-commands)
  784. (smex-update))
  785. smex-ido-cache)))
  786. (defun counsel--M-x-externs-predicate (cand)
  787. "Return non-nil if `counsel-M-x' should complete CAND.
  788. CAND is a string returned by `counsel--M-x-externs'."
  789. (not (get (intern cand) 'no-counsel-M-x)))
  790. (defun counsel--M-x-make-predicate ()
  791. "Return a predicate for `counsel-M-x' in the current buffer."
  792. (defvar read-extended-command-predicate)
  793. (let ((buf (current-buffer)))
  794. (lambda (sym)
  795. (and (commandp sym)
  796. (not (get sym 'byte-obsolete-info))
  797. (not (get sym 'no-counsel-M-x))
  798. (or (not (bound-and-true-p read-extended-command-predicate))
  799. (and (functionp read-extended-command-predicate)
  800. (funcall read-extended-command-predicate sym buf)))))))
  801. (defun counsel--M-x-prompt ()
  802. "String for `M-x' plus the string representation of `current-prefix-arg'."
  803. (concat (cond ((null current-prefix-arg)
  804. nil)
  805. ((eq current-prefix-arg '-)
  806. "- ")
  807. ((integerp current-prefix-arg)
  808. (format "%d " current-prefix-arg))
  809. ((= (car current-prefix-arg) 4)
  810. "C-u ")
  811. (t
  812. (format "%d " (car current-prefix-arg))))
  813. "M-x "))
  814. (defvar counsel-M-x-history nil
  815. "History for `counsel-M-x'.")
  816. (defun counsel-M-x-action (cmd)
  817. "Execute CMD."
  818. (setq cmd (intern
  819. (subst-char-in-string ?\s ?- (string-remove-prefix "^" cmd))))
  820. (cond ((bound-and-true-p amx-initialized)
  821. (amx-rank cmd))
  822. ((bound-and-true-p smex-initialized-p)
  823. (smex-rank cmd)))
  824. (setq prefix-arg current-prefix-arg)
  825. (setq this-command cmd)
  826. (setq real-this-command cmd)
  827. (command-execute cmd 'record))
  828. ;;;###autoload
  829. (defun counsel-M-x (&optional initial-input)
  830. "Ivy version of `execute-extended-command'.
  831. Optional INITIAL-INPUT is the initial input in the minibuffer.
  832. This function integrates with either the `amx' or `smex' package
  833. when available, in that order of precedence."
  834. (interactive)
  835. ;; When `counsel-M-x' returns, `last-command' would be set to
  836. ;; `counsel-M-x' because :action hasn't been invoked yet.
  837. ;; Instead, preserve the old value of `this-command'.
  838. (setq this-command last-command)
  839. (setq real-this-command real-last-command)
  840. (let ((externs (counsel--M-x-externs)))
  841. (ivy-read (counsel--M-x-prompt) (or externs obarray)
  842. :predicate (if externs
  843. #'counsel--M-x-externs-predicate
  844. (counsel--M-x-make-predicate))
  845. :require-match t
  846. :history 'counsel-M-x-history
  847. :action #'counsel-M-x-action
  848. :keymap counsel-describe-map
  849. :initial-input initial-input
  850. :caller 'counsel-M-x)))
  851. (ivy-configure 'counsel-M-x
  852. :initial-input "^"
  853. :display-transformer-fn #'counsel-M-x-transformer)
  854. (ivy-set-actions
  855. 'counsel-M-x
  856. `(("d" counsel--find-symbol "definition")
  857. ("h" ,(lambda (x) (funcall counsel-describe-function-function (intern x))) "help")))
  858. ;;** `counsel-command-history'
  859. (defun counsel-command-history-action-eval (cmd)
  860. "Eval the command CMD."
  861. (eval (read cmd)))
  862. (defun counsel-command-history-action-edit-and-eval (cmd)
  863. "Edit and eval the command CMD."
  864. (edit-and-eval-command "Eval: " (read cmd)))
  865. (ivy-set-actions
  866. 'counsel-command-history
  867. '(("r" counsel-command-history-action-eval "eval command")
  868. ("e" counsel-command-history-action-edit-and-eval "edit and eval command")))
  869. ;;;###autoload
  870. (defun counsel-command-history ()
  871. "Show the history of commands."
  872. (interactive)
  873. (ivy-read "Command: " (mapcar #'prin1-to-string command-history)
  874. :require-match t
  875. :action #'counsel-command-history-action-eval
  876. :caller 'counsel-command-history))
  877. ;;** `counsel-load-library'
  878. (defun counsel-library-candidates ()
  879. "Return a list of completion candidates for `counsel-load-library'."
  880. (let ((suffix (concat (regexp-opt '(".el" ".el.gz") t) "\\'"))
  881. (cands (make-hash-table :test #'equal))
  882. short-name
  883. old-val
  884. dir-parent
  885. res)
  886. (dolist (dir load-path)
  887. (setq dir (or dir default-directory)) ;; interpret nil in load-path as default-directory
  888. (when (file-directory-p dir)
  889. (dolist (file (file-name-all-completions "" dir))
  890. (when (string-match suffix file)
  891. (unless (string-match "pkg.elc?$" file)
  892. (setq short-name (substring file 0 (match-beginning 0)))
  893. (if (setq old-val (gethash short-name cands))
  894. (progn
  895. ;; assume going up directory once will resolve name clash
  896. (setq dir-parent (counsel-directory-name (cdr old-val)))
  897. (puthash short-name
  898. (cons
  899. (counsel-string-compose dir-parent (car old-val))
  900. (cdr old-val))
  901. cands)
  902. (setq dir-parent (counsel-directory-name dir))
  903. (puthash (concat dir-parent short-name)
  904. (cons
  905. (propertize
  906. (counsel-string-compose
  907. dir-parent short-name)
  908. 'full-name (expand-file-name file dir))
  909. dir)
  910. cands))
  911. (puthash short-name
  912. (cons (propertize
  913. short-name
  914. 'full-name (expand-file-name file dir))
  915. dir)
  916. cands)))))))
  917. (maphash (lambda (_k v) (push (car v) res)) cands)
  918. (nreverse res)))
  919. ;;;###autoload
  920. (defun counsel-load-library ()
  921. "Load a selected the Emacs Lisp library.
  922. The libraries are offered from `load-path'."
  923. (interactive)
  924. (let ((cands (counsel-library-candidates)))
  925. (ivy-read "Load library: " cands
  926. :action (lambda (x)
  927. (load-library
  928. (get-text-property 0 'full-name x)))
  929. :keymap counsel-describe-map)))
  930. (ivy-set-actions
  931. 'counsel-load-library
  932. '(("d" counsel--find-symbol "definition")))
  933. ;;** `counsel-find-library'
  934. (declare-function find-library-name "find-func")
  935. (defun counsel-find-library-other-window (library)
  936. (let ((buf (find-file-noselect (find-library-name library))))
  937. (pop-to-buffer buf 'other-window)))
  938. (defun counsel-find-library-other-frame (library)
  939. (let ((buf (find-file-noselect (find-library-name library))))
  940. (condition-case nil
  941. (switch-to-buffer-other-frame buf)
  942. (error (pop-to-buffer buf)))))
  943. (ivy-set-actions
  944. 'counsel-find-library
  945. '(("j" counsel-find-library-other-window "other window")
  946. ("f" counsel-find-library-other-frame "other frame")))
  947. ;;;###autoload
  948. (defun counsel-find-library ()
  949. "Visit a selected the Emacs Lisp library.
  950. The libraries are offered from `load-path'."
  951. (interactive)
  952. (let ((cands (counsel-library-candidates)))
  953. (ivy-read "Find library: " cands
  954. :action #'counsel--find-symbol
  955. :keymap counsel-describe-map
  956. :caller 'counsel-find-library)))
  957. ;;** `counsel-load-theme'
  958. (declare-function powerline-reset "ext:powerline")
  959. (defun counsel-load-theme-action (x)
  960. "Disable current themes and load theme X."
  961. (condition-case nil
  962. (progn
  963. (mapc #'disable-theme custom-enabled-themes)
  964. (load-theme (intern x) t)
  965. (when (fboundp 'powerline-reset)
  966. (powerline-reset)))
  967. (error "Problem loading theme %s" x)))
  968. ;;;###autoload
  969. (defun counsel-load-theme ()
  970. "Forward to `load-theme'.
  971. Usable with `ivy-resume', `ivy-next-line-and-call' and
  972. `ivy-previous-line-and-call'."
  973. (interactive)
  974. (ivy-read "Load custom theme: "
  975. (mapcar 'symbol-name
  976. (custom-available-themes))
  977. :action #'counsel-load-theme-action
  978. :caller 'counsel-load-theme))
  979. ;;** `counsel-descbinds'
  980. (ivy-set-actions
  981. 'counsel-descbinds
  982. '(("d" counsel-descbinds-action-find "definition")
  983. ("I" counsel-descbinds-action-info "info")
  984. ("x" counsel-descbinds-action-exec "execute")))
  985. (defvar counsel-descbinds-history nil
  986. "History for `counsel-descbinds'.")
  987. (defun counsel--descbinds-cands (&optional prefix buffer)
  988. "Get key bindings starting with PREFIX in BUFFER.
  989. See `describe-buffer-bindings' for further information."
  990. (let ((buffer (or buffer (current-buffer)))
  991. (re-exclude (regexp-opt
  992. '("<vertical-line>" "<bottom-divider>" "<right-divider>"
  993. "<mode-line>" "<C-down-mouse-2>" "<left-fringe>"
  994. "<right-fringe>" "<header-line>"
  995. "<vertical-scroll-bar>" "<horizontal-scroll-bar>")))
  996. res)
  997. (with-temp-buffer
  998. (let ((indent-tabs-mode t))
  999. (describe-buffer-bindings buffer prefix))
  1000. (goto-char (point-min))
  1001. ;; Skip the "Key translations" section
  1002. (skip-chars-forward "^\C-l")
  1003. (forward-char 2)
  1004. (while (not (eobp))
  1005. (when (looking-at "^\\([^\t\n]+\\)[\t ]*\\(.*\\)$")
  1006. (let ((key (match-string 1))
  1007. (fun (match-string 2))
  1008. cmd)
  1009. (unless (or (member fun '("??" "self-insert-command"))
  1010. (string-match-p re-exclude key)
  1011. (not (or (commandp (setq cmd (intern-soft fun)))
  1012. (equal fun "Prefix Command"))))
  1013. (push
  1014. (cons (format
  1015. "%-15s %s"
  1016. (propertize key 'face 'counsel-key-binding)
  1017. fun)
  1018. (cons key cmd))
  1019. res))))
  1020. (forward-line)))
  1021. (nreverse res)))
  1022. (defcustom counsel-descbinds-function #'describe-function
  1023. "Function to call to describe a function passed as parameter."
  1024. :type 'function)
  1025. (defun counsel-descbinds-action-describe (x)
  1026. "Describe function of candidate X.
  1027. See `describe-function' for further information."
  1028. (let ((cmd (cddr x)))
  1029. (funcall counsel-descbinds-function cmd)))
  1030. (defun counsel-descbinds-action-exec (x)
  1031. "Run candidate X.
  1032. See `execute-extended-command' for further information."
  1033. (let ((cmd (cddr x)))
  1034. (command-execute cmd 'record)))
  1035. (defun counsel-descbinds-action-find (x)
  1036. "Find symbol definition of candidate X.
  1037. See `counsel--find-symbol' for further information."
  1038. (let ((cmd (cddr x)))
  1039. (counsel--find-symbol (symbol-name cmd))))
  1040. (defun counsel-descbinds-action-info (x)
  1041. "Display symbol definition of candidate X, as found in the relevant manual.
  1042. See `info-lookup-symbol' for further information."
  1043. (let ((cmd (cddr x)))
  1044. (counsel-info-lookup-symbol (symbol-name cmd))))
  1045. ;;;###autoload
  1046. (defun counsel-descbinds (&optional prefix buffer)
  1047. "Show a list of all defined keys and their definitions.
  1048. If non-nil, show only bindings that start with PREFIX.
  1049. BUFFER defaults to the current one."
  1050. (interactive)
  1051. (ivy-read "Bindings: " (counsel--descbinds-cands prefix buffer)
  1052. :action #'counsel-descbinds-action-describe
  1053. :history 'counsel-descbinds-history
  1054. :caller 'counsel-descbinds))
  1055. ;;** `counsel-describe-face'
  1056. (defcustom counsel-describe-face-function #'describe-face
  1057. "Function to call to describe a face or face name argument."
  1058. :type 'function)
  1059. (defun counsel--face-at-point ()
  1060. "Return name of face around point.
  1061. Try detecting a face name in the text around point before falling
  1062. back to the face of the character after point, and finally the
  1063. `default' face."
  1064. (symbol-name (or (face-at-point t) 'default)))
  1065. ;;;###autoload
  1066. (defun counsel-describe-face ()
  1067. "Completion for `describe-face'."
  1068. (interactive)
  1069. (ivy-read "Face: " (face-list)
  1070. :require-match t
  1071. :history 'face-name-history
  1072. :preselect (counsel--face-at-point)
  1073. :action counsel-describe-face-function
  1074. :caller 'counsel-describe-face))
  1075. (ivy-configure 'counsel-describe-face
  1076. :sort-fn #'ivy-string<)
  1077. (defun counsel-customize-face (name)
  1078. "Customize face with NAME."
  1079. (customize-face (intern name)))
  1080. (defun counsel-customize-face-other-window (name)
  1081. "Customize face with NAME in another window."
  1082. (customize-face-other-window (intern name)))
  1083. (declare-function hi-lock-set-pattern "hi-lock")
  1084. (defun counsel-highlight-with-face (face)
  1085. "Highlight thing-at-point with FACE."
  1086. (hi-lock-mode 1)
  1087. (let ((thing (ivy-thing-at-point)))
  1088. (when (use-region-p)
  1089. (deactivate-mark))
  1090. (hi-lock-set-pattern (regexp-quote thing) (intern face))))
  1091. (ivy-set-actions
  1092. 'counsel-describe-face
  1093. '(("c" counsel-customize-face "customize")
  1094. ("C" counsel-customize-face-other-window "customize other window")))
  1095. ;;** `counsel-faces'
  1096. (defvar counsel--faces-format "%-40s %s")
  1097. (defun counsel--faces-format-function (names)
  1098. "Format NAMES according to `counsel--faces-format'."
  1099. (let ((formatter
  1100. (lambda (name)
  1101. (format counsel--faces-format name
  1102. (propertize list-faces-sample-text
  1103. 'face (intern name))))))
  1104. (ivy--format-function-generic
  1105. (lambda (name)
  1106. (funcall formatter (ivy--add-face name 'ivy-current-match)))
  1107. formatter names "\n")))
  1108. ;;;###autoload
  1109. (defun counsel-faces ()
  1110. "Complete faces with preview.
  1111. Actions are provided by default for describing or customizing the
  1112. selected face."
  1113. (interactive)
  1114. (let* ((names (mapcar #'symbol-name (face-list)))
  1115. (counsel--faces-format
  1116. (format "%%-%ds %%s"
  1117. (apply #'max 0 (mapcar #'string-width names)))))
  1118. (ivy-read "Face: " names
  1119. :require-match t
  1120. :history 'face-name-history
  1121. :preselect (counsel--face-at-point)
  1122. :action counsel-describe-face-function
  1123. :caller 'counsel-faces)))
  1124. (ivy-configure 'counsel-faces
  1125. :parent 'counsel-describe-face
  1126. :format-fn #'counsel--faces-format-function)
  1127. (ivy-set-actions
  1128. 'counsel-faces
  1129. '(("c" counsel-customize-face "customize")
  1130. ("C" counsel-customize-face-other-window "customize other window")
  1131. ("h" counsel-highlight-with-face "highlight")))
  1132. ;;* Git
  1133. ;;** `counsel-git'
  1134. (defvar counsel-git-cmd "git ls-files -z --full-name --"
  1135. "Command for `counsel-git'.")
  1136. (ivy-set-actions
  1137. 'counsel-git
  1138. '(("j" find-file-other-window "other window")
  1139. ("x" counsel-find-file-extern "open externally")))
  1140. (defun counsel--dominating-file (file &optional dir)
  1141. "Look up directory hierarchy for FILE, starting in DIR.
  1142. Like `locate-dominating-file', but DIR defaults to
  1143. `default-directory' and the return value is expanded."
  1144. (and (setq dir (locate-dominating-file (or dir default-directory) file))
  1145. (expand-file-name dir)))
  1146. (defun counsel-locate-git-root ()
  1147. "Return the root of the Git repository containing the current buffer."
  1148. (or (counsel--git-root)
  1149. (error "Not in a Git repository")))
  1150. (defun counsel-git-cands (dir)
  1151. (let ((default-directory dir))
  1152. (split-string
  1153. (shell-command-to-string counsel-git-cmd)
  1154. "\0"
  1155. t)))
  1156. ;;;###autoload
  1157. (defun counsel-git (&optional initial-input)
  1158. "Find file in the current Git repository.
  1159. INITIAL-INPUT can be given as the initial minibuffer input."
  1160. (interactive)
  1161. (counsel-require-program counsel-git-cmd)
  1162. (let ((default-directory (counsel-locate-git-root)))
  1163. (ivy-read "Find file: " (counsel-git-cands default-directory)
  1164. :initial-input initial-input
  1165. :action #'counsel-git-action
  1166. :caller 'counsel-git)))
  1167. (ivy-configure 'counsel-git
  1168. :occur #'counsel-git-occur)
  1169. (defun counsel-git-action (x)
  1170. "Find file X in current Git repository."
  1171. (with-ivy-window
  1172. (let ((default-directory (ivy-state-directory ivy-last)))
  1173. (find-file x))))
  1174. (defun counsel-git-occur (&optional _cands)
  1175. "Occur function for `counsel-git' using `counsel-cmd-to-dired'."
  1176. (cd (ivy-state-directory ivy-last))
  1177. (counsel-cmd-to-dired
  1178. (counsel--expand-ls
  1179. (format "%s | %s | xargs ls"
  1180. (replace-regexp-in-string "\\(-0\\)\\|\\(-z\\)" "" counsel-git-cmd)
  1181. (counsel--file-name-filter)))))
  1182. (defvar counsel-dired-listing-switches "-alh"
  1183. "Switches passed to `ls' for `counsel-cmd-to-dired'.")
  1184. (defun counsel-cmd-to-dired (full-cmd &optional filter)
  1185. "Adapted from `find-dired'."
  1186. (let ((inhibit-read-only t))
  1187. (erase-buffer)
  1188. (dired-mode default-directory counsel-dired-listing-switches)
  1189. (insert " " default-directory ":\n")
  1190. (let ((point (point)))
  1191. (insert " " full-cmd "\n")
  1192. (dired-insert-set-properties point (point)))
  1193. (setq-local dired-sort-inhibit t)
  1194. (setq-local revert-buffer-function
  1195. (lambda (_1 _2) (counsel-cmd-to-dired full-cmd)))
  1196. (setq-local dired-subdir-alist
  1197. (list (cons default-directory (point-min-marker))))
  1198. (let ((proc (start-process-shell-command
  1199. "counsel-cmd" (current-buffer) full-cmd)))
  1200. (set-process-filter proc filter)
  1201. (set-process-sentinel
  1202. proc
  1203. (lambda (process _msg)
  1204. (when (and (eq (process-status process) 'exit)
  1205. (zerop (process-exit-status process)))
  1206. (goto-char (point-min))
  1207. (forward-line 2)
  1208. (dired-move-to-filename)))))))
  1209. ;;** `counsel-git-grep'
  1210. (defvar counsel-git-grep-map
  1211. (let ((map (make-sparse-keymap)))
  1212. (define-key map (kbd "C-l") 'ivy-call-and-recenter)
  1213. (define-key map (kbd "M-q") 'counsel-git-grep-query-replace)
  1214. (define-key map (kbd "C-c C-m") 'counsel-git-grep-switch-cmd)
  1215. (define-key map (kbd "C-x C-d") 'counsel-cd)
  1216. map))
  1217. (defvar counsel-git-grep-cmd-default "git --no-pager grep -n --no-color -I -e \"%s\""
  1218. "Initial command for `counsel-git-grep'.")
  1219. (defvar counsel-git-grep-cmd nil
  1220. "Store the command for `counsel-git-grep'.")
  1221. (defvar counsel-git-grep-history nil
  1222. "History for `counsel-git-grep'.")
  1223. (defvar counsel-git-grep-cmd-history
  1224. (list counsel-git-grep-cmd-default)
  1225. "History for `counsel-git-grep' shell commands.")
  1226. (defcustom counsel-grep-post-action-hook nil
  1227. "Hook that runs after the point moves to the next candidate.
  1228. Typical value: '(recenter)."
  1229. :type 'hook)
  1230. (defcustom counsel-git-grep-cmd-function #'counsel-git-grep-cmd-function-default
  1231. "How a git-grep shell call is built from the input.
  1232. This function should set `ivy--old-re'."
  1233. :type '(radio
  1234. (function-item counsel-git-grep-cmd-function-default)
  1235. (function-item counsel-git-grep-cmd-function-ignore-order)
  1236. (function :tag "Other")))
  1237. (defun counsel-git-grep-cmd-function-default (str)
  1238. (format counsel-git-grep-cmd
  1239. (setq ivy--old-re
  1240. (if (eq ivy--regex-function #'ivy--regex-fuzzy)
  1241. (replace-regexp-in-string
  1242. "\n" "" (ivy--regex-fuzzy str))
  1243. (ivy--regex str t)))))
  1244. (defun counsel-git-grep-cmd-function-ignore-order (str)
  1245. (setq ivy--old-re (ivy--regex str t))
  1246. (let ((parts (split-string str " " t)))
  1247. (concat
  1248. "git --no-pager grep --full-name -n --no-color -i -e "
  1249. (mapconcat #'shell-quote-argument parts " --and -e "))))
  1250. (defun counsel-git-grep-function (string)
  1251. "Grep in the current Git repository for STRING."
  1252. (or
  1253. (ivy-more-chars)
  1254. (progn
  1255. (counsel--async-command
  1256. (concat
  1257. (funcall counsel-git-grep-cmd-function string)
  1258. (if (ivy--case-fold-p string) " -i" "")))
  1259. nil)))
  1260. (defun counsel-git-grep-action (x)
  1261. "Go to occurrence X in current Git repository."
  1262. (when (string-match "\\`\\(.*?\\):\\([0-9]+\\):\\(.*\\)\\'" x)
  1263. (let ((file-name (match-string-no-properties 1 x))
  1264. (line-number (match-string-no-properties 2 x)))
  1265. (find-file (expand-file-name
  1266. file-name
  1267. (ivy-state-directory ivy-last)))
  1268. (goto-char (point-min))
  1269. (forward-line (1- (string-to-number line-number)))
  1270. (when (re-search-forward (ivy--regex ivy-text t) (line-end-position) t)
  1271. (when swiper-goto-start-of-match
  1272. (goto-char (match-beginning 0))))
  1273. (swiper--ensure-visible)
  1274. (run-hooks 'counsel-grep-post-action-hook)
  1275. (unless (eq ivy-exit 'done)
  1276. (swiper--cleanup)
  1277. (swiper--add-overlays (ivy--regex ivy-text))))))
  1278. (defun counsel-git-grep-transformer (str)
  1279. "Highlight file and line number in STR."
  1280. (when (string-match "\\`\\([^:]+\\):\\([^:]+\\):" str)
  1281. (add-face-text-property (match-beginning 1) (match-end 1)
  1282. 'ivy-grep-info nil str)
  1283. (add-face-text-property (match-beginning 2) (match-end 2)
  1284. 'ivy-grep-line-number nil str))
  1285. str)
  1286. (defvar counsel-git-grep-projects-alist nil
  1287. "An alist of project directory to \"git-grep\" command.
  1288. Allows to automatically use a custom \"git-grep\" command for all
  1289. files in a project.")
  1290. (defun counsel--git-grep-cmd-and-proj (cmd)
  1291. (let ((dd (expand-file-name default-directory))
  1292. proj)
  1293. (cond
  1294. ((stringp cmd))
  1295. (current-prefix-arg
  1296. (if (setq proj
  1297. (cl-find-if
  1298. (lambda (x)
  1299. (string-match (car x) dd))
  1300. counsel-git-grep-projects-alist))
  1301. (setq cmd (cdr proj))
  1302. (setq cmd
  1303. (ivy-read "cmd: " counsel-git-grep-cmd-history
  1304. :history 'counsel-git-grep-cmd-history
  1305. :re-builder #'ivy--regex))
  1306. (setq counsel-git-grep-cmd-history
  1307. (delete-dups counsel-git-grep-cmd-history))))
  1308. (t
  1309. (setq cmd counsel-git-grep-cmd-default)))
  1310. (cons proj cmd)))
  1311. (defun counsel--call (command &optional result-fn)
  1312. "Synchronously call COMMAND and return its output as a string.
  1313. COMMAND comprises the program name followed by its arguments, as
  1314. in `make-process'. Signal `file-error' and emit a warning if
  1315. COMMAND fails. Obey file handlers based on `default-directory'.
  1316. On success, RESULT-FN is called in output buffer with no arguments."
  1317. (let ((stderr (make-temp-file "counsel-call-stderr-"))
  1318. status)
  1319. (unwind-protect
  1320. (with-temp-buffer
  1321. (setq status (apply #'process-file (car command) nil
  1322. (list t stderr) nil (cdr command)))
  1323. (if (eq status 0)
  1324. (if result-fn
  1325. (funcall result-fn)
  1326. ;; Return all output except trailing newline.
  1327. (buffer-substring (point-min)
  1328. (- (point)
  1329. (if (eq (bobp) (bolp))
  1330. 0
  1331. 1))))
  1332. ;; Convert process status into error list.
  1333. (setq status (list 'file-error
  1334. (mapconcat #'identity `(,@command "failed") " ")
  1335. status))
  1336. ;; Print stderr contents, if any, to *Warnings* buffer.
  1337. (let ((msg (condition-case err
  1338. (unless (zerop (cadr (insert-file-contents
  1339. stderr nil nil nil t)))
  1340. (buffer-string))
  1341. (error (error-message-string err)))))
  1342. (lwarn 'ivy :warning "%s" (apply #'concat
  1343. (error-message-string status)
  1344. (and msg (list "\n" msg)))))
  1345. ;; Signal `file-error' with process status.
  1346. (signal (car status) (cdr status))))
  1347. (delete-file stderr))))
  1348. (defun counsel--command (&rest command)
  1349. "Forward COMMAND to `counsel--call'."
  1350. (counsel--call command))
  1351. (defun counsel--grep-unwind ()
  1352. (counsel-delete-process)
  1353. (swiper--cleanup))
  1354. ;;;###autoload
  1355. (defun counsel-git-grep (&optional initial-input initial-directory cmd)
  1356. "Grep for a string in the current Git repository.
  1357. INITIAL-INPUT can be given as the initial minibuffer input.
  1358. INITIAL-DIRECTORY, if non-nil, is used as the root directory for search.
  1359. When CMD is a string, use it as a \"git grep\" command.
  1360. When CMD is non-nil, prompt for a specific \"git grep\" command."
  1361. (interactive)
  1362. (let ((proj-and-cmd (counsel--git-grep-cmd-and-proj cmd))
  1363. proj)
  1364. (setq proj (car proj-and-cmd))
  1365. (setq counsel-git-grep-cmd (cdr proj-and-cmd))
  1366. (counsel-require-program counsel-git-grep-cmd)
  1367. (let ((collection-function
  1368. (if proj
  1369. #'counsel-git-grep-proj-function
  1370. #'counsel-git-grep-function))
  1371. (default-directory (or initial-directory
  1372. (if proj
  1373. (car proj)
  1374. (counsel-locate-git-root)))))
  1375. (ivy-read "git grep: " collection-function
  1376. :initial-input initial-input
  1377. :dynamic-collection t
  1378. :keymap counsel-git-grep-map
  1379. :action #'counsel-git-grep-action
  1380. :history 'counsel-git-grep-history
  1381. :require-match t
  1382. :caller 'counsel-git-grep))))
  1383. (defun counsel--git-grep-index (_re-str cands)
  1384. (let (name ln)
  1385. (cond
  1386. (ivy--old-cands
  1387. (ivy-recompute-index-swiper-async nil cands))
  1388. ((unless (with-ivy-window
  1389. (when buffer-file-name
  1390. (setq ln (line-number-at-pos))
  1391. (setq name (file-name-nondirectory buffer-file-name))))
  1392. 0))
  1393. ;; Closest to current line going forwards.
  1394. ((let ((beg (1+ (length name))))
  1395. (cl-position-if (lambda (x)
  1396. (and (string-prefix-p name x)
  1397. (>= (string-to-number (substring x beg)) ln)))
  1398. cands)))
  1399. ;; Closest to current line going backwards.
  1400. ((cl-position-if (lambda (x)
  1401. (string-prefix-p name x))
  1402. cands
  1403. :from-end t))
  1404. (t 0))))
  1405. (ivy-configure 'counsel-git-grep
  1406. :occur #'counsel-git-grep-occur
  1407. :unwind-fn #'counsel--grep-unwind
  1408. :index-fn #'counsel--git-grep-index
  1409. :display-transformer-fn #'counsel-git-grep-transformer
  1410. :grep-p t
  1411. :exit-codes '(1 "No matches found"))
  1412. (defun counsel-git-grep-proj-function (str)
  1413. "Grep for STR in the current Git repository."
  1414. (or
  1415. (ivy-more-chars)
  1416. (let ((regex (setq ivy--old-re
  1417. (ivy--regex str t))))
  1418. (counsel--async-command
  1419. (concat
  1420. (format counsel-git-grep-cmd regex)
  1421. (if (ivy--case-fold-p str) " -i" "")))
  1422. nil)))
  1423. (defun counsel-git-grep-switch-cmd ()
  1424. "Set `counsel-git-grep-cmd' to a different value."
  1425. (interactive)
  1426. (setq counsel-git-grep-cmd
  1427. (ivy-read "cmd: " counsel-git-grep-cmd-history
  1428. :history 'counsel-git-grep-cmd-history))
  1429. (setq counsel-git-grep-cmd-history
  1430. (delete-dups counsel-git-grep-cmd-history))
  1431. (unless (ivy-state-dynamic-collection ivy-last)
  1432. (setq ivy--all-candidates
  1433. (all-completions "" 'counsel-git-grep-function))))
  1434. (defun counsel--normalize-grep-match (str)
  1435. ;; Prepend ./ if necessary:
  1436. (unless (ivy--starts-with-dotslash str)
  1437. (setq str (concat "./" str)))
  1438. ;; Remove column info if any:
  1439. (save-match-data
  1440. (when (string-match
  1441. "[^\n:]+?[^\n/:]:[\t ]*[1-9][0-9]*[\t ]*:\\([1-9][0-9]*:\\)"
  1442. str)
  1443. (setq str (replace-match "" t t str 1))))
  1444. str)
  1445. (defun counsel--git-grep-occur-cmd (input)
  1446. (let* ((regex ivy--old-re)
  1447. (positive-pattern (replace-regexp-in-string
  1448. ;; git-grep can't handle .*?
  1449. "\\.\\*\\?" ".*"
  1450. (ivy-re-to-str regex)))
  1451. (negative-patterns
  1452. (if (stringp regex) ""
  1453. (mapconcat (lambda (x)
  1454. (and (null (cdr x))
  1455. (format "| grep -v %s" (car x))))
  1456. regex
  1457. " "))))
  1458. (concat
  1459. (format counsel-git-grep-cmd positive-pattern)
  1460. negative-patterns
  1461. (if (ivy--case-fold-p input) " -i" ""))))
  1462. (defun counsel-git-grep-occur (&optional _cands)
  1463. "Generate a custom occur buffer for `counsel-git-grep'."
  1464. (counsel-grep-like-occur #'counsel--git-grep-occur-cmd))
  1465. (defun counsel-git-grep-query-replace ()
  1466. "Start `query-replace' with string to replace from last search string."
  1467. (interactive)
  1468. (unless (window-minibuffer-p)
  1469. (user-error
  1470. "Should only be called in the minibuffer through `counsel-git-grep-map'"))
  1471. (let* ((enable-recursive-minibuffers t)
  1472. (from (ivy--regex ivy-text))
  1473. (to (query-replace-read-to from "Query replace" t)))
  1474. (ivy-exit-with-action
  1475. (lambda (_)
  1476. (let (done-buffers)
  1477. (dolist (cand ivy--old-cands)
  1478. (when (string-match "\\`\\(.*?\\):\\([0-9]+\\):\\(.*\\)\\'" cand)
  1479. (with-ivy-window
  1480. (let ((file-name (match-string-no-properties 1 cand)))
  1481. (setq file-name (expand-file-name
  1482. file-name
  1483. (ivy-state-directory ivy-last)))
  1484. (unless (member file-name done-buffers)
  1485. (push file-name done-buffers)
  1486. (find-file file-name)
  1487. (goto-char (point-min)))
  1488. (perform-replace from to t t nil))))))))))
  1489. ;;** `counsel-git-stash'
  1490. (defun counsel-git-stash-kill-action (x)
  1491. "Add git stash command to kill ring.
  1492. The git command applies the stash entry where candidate X was found in."
  1493. (when (string-match "\\([^:]+\\):" x)
  1494. (kill-new (message (format "git stash apply %s" (match-string 1 x))))))
  1495. ;;;###autoload
  1496. (defun counsel-git-stash ()
  1497. "Search through all available git stashes."
  1498. (interactive)
  1499. (let* ((default-directory (counsel-locate-git-root))
  1500. (cands (split-string (shell-command-to-string
  1501. "IFS=$'\n'
  1502. for i in `git stash list --format=\"%gd\"`; do
  1503. git stash show -p $i | grep -H --label=\"$i\" \"$1\"
  1504. done") "\n" t)))
  1505. (ivy-read "git stash: " cands
  1506. :action #'counsel-git-stash-kill-action
  1507. :caller 'counsel-git-stash)))
  1508. ;;** `counsel-git-log'
  1509. (defvar counsel-git-log-cmd "GIT_PAGER=cat git log --no-color --grep '%s'"
  1510. "Command used for \"git log\".")
  1511. (defun counsel-git-log-function (_)
  1512. "Search for `ivy-regex' in git log."
  1513. (or
  1514. (ivy-more-chars)
  1515. (progn
  1516. ;; `counsel--yank-pop-format-function' uses this
  1517. (setq ivy--old-re ivy-regex)
  1518. (counsel--async-command
  1519. ;; "git log --grep" likes to have groups quoted e.g. \(foo\).
  1520. ;; But it doesn't like the non-greedy ".*?".
  1521. (format counsel-git-log-cmd
  1522. (replace-regexp-in-string "\\.\\*\\?" ".*"
  1523. (ivy-re-to-str ivy--old-re))))
  1524. nil)))
  1525. (defun counsel-git-log-action (x)
  1526. "Add candidate X to kill ring."
  1527. (message "%S" (kill-new x)))
  1528. (declare-function magit-show-commit "ext:magit-diff")
  1529. (defun counsel-git-log-show-commit-action (log-entry)
  1530. "Visit the commit corresponding to LOG-ENTRY."
  1531. (require 'magit-diff)
  1532. (let ((commit (substring-no-properties log-entry 0 (string-match-p "\\W" log-entry))))
  1533. (magit-show-commit commit)))
  1534. (ivy-set-actions
  1535. 'counsel-git-log
  1536. '(("v" counsel-git-log-show-commit-action "visit commit")))
  1537. ;;** `counsel-git-change-worktree'
  1538. (defun counsel-git-change-worktree-action (git-root-dir tree)
  1539. "Find the corresponding file in the worktree located at tree.
  1540. The current buffer is assumed to be in a subdirectory of GIT-ROOT-DIR.
  1541. TREE is the selected candidate."
  1542. (let* ((new-root-dir (counsel-git-worktree-parse-root tree))
  1543. (tree-filename (file-relative-name buffer-file-name git-root-dir))
  1544. (file-name (expand-file-name tree-filename new-root-dir)))
  1545. (find-file file-name)))
  1546. (defun counsel-git-worktree-list ()
  1547. "List worktrees in the Git repository containing the current buffer."
  1548. (let ((default-directory (counsel-locate-git-root)))
  1549. (split-string (shell-command-to-string "git worktree list") "\n" t)))
  1550. (defun counsel-git-worktree-parse-root (tree)
  1551. "Return worktree from candidate TREE."
  1552. (substring tree 0 (string-match-p " " tree)))
  1553. (defun counsel-git-close-worktree-files-action (root-dir)
  1554. "Close all buffers from the worktree located at ROOT-DIR."
  1555. (setq root-dir (counsel-git-worktree-parse-root root-dir))
  1556. (save-excursion
  1557. (dolist (buf (buffer-list))
  1558. (set-buffer buf)
  1559. (and buffer-file-name
  1560. (string= "." (file-relative-name root-dir (counsel-locate-git-root)))
  1561. (kill-buffer buf)))))
  1562. (ivy-set-actions
  1563. 'counsel-git-change-worktree
  1564. '(("k" counsel-git-close-worktree-files-action "kill all")))
  1565. ;;;###autoload
  1566. (defun counsel-git-change-worktree ()
  1567. "Find the file corresponding to the current buffer on a different worktree."
  1568. (interactive)
  1569. (let ((default-directory (counsel-locate-git-root)))
  1570. (ivy-read "Select worktree: "
  1571. (or (cl-delete default-directory (counsel-git-worktree-list)
  1572. :key #'counsel-git-worktree-parse-root :test #'string=)
  1573. (error "No other worktrees"))
  1574. :action (lambda (tree)
  1575. (counsel-git-change-worktree-action
  1576. (ivy-state-directory ivy-last) tree))
  1577. :require-match t
  1578. :caller 'counsel-git-change-worktree)))
  1579. ;;** `counsel-git-checkout'
  1580. (defun counsel-git-checkout-action (branch)
  1581. "Switch branch by invoking git-checkout(1).
  1582. The command is passed a single argument comprising all characters
  1583. in BRANCH up to, but not including, the first space
  1584. character (#x20), or the string's end if it lacks a space."
  1585. (shell-command
  1586. (format "git checkout %s"
  1587. (shell-quote-argument
  1588. (substring branch 0 (string-match-p " " branch))))))
  1589. (defun counsel-git-branch-list ()
  1590. "Return list of branches in the current Git repository.
  1591. Value comprises all local and remote branches bar the one
  1592. currently checked out."
  1593. (cl-mapcan (lambda (line)
  1594. (and (string-match "\\`[[:blank:]]+" line)
  1595. (list (substring line (match-end 0)))))
  1596. (let ((default-directory (counsel-locate-git-root)))
  1597. (split-string (shell-command-to-string "git branch -vv --all")
  1598. "\n" t))))
  1599. ;;;###autoload
  1600. (defun counsel-git-checkout ()
  1601. "Call the \"git checkout\" command."
  1602. (interactive)
  1603. (ivy-read "Checkout branch: " (counsel-git-branch-list)
  1604. :action #'counsel-git-checkout-action
  1605. :caller 'counsel-git-checkout))
  1606. (defvar counsel-yank-pop-truncate-radius)
  1607. (defun counsel--git-log-format-function (str)
  1608. (let ((counsel-yank-pop-truncate-radius 5))
  1609. (counsel--yank-pop-format-function str)))
  1610. ;;;###autoload
  1611. (defun counsel-git-log ()
  1612. "Call the \"git log --grep\" shell command."
  1613. (interactive)
  1614. (ivy-read "Grep log: " #'counsel-git-log-function
  1615. :dynamic-collection t
  1616. :action #'counsel-git-log-action
  1617. :caller 'counsel-git-log))
  1618. (ivy-configure 'counsel-git-log
  1619. :height 4
  1620. :unwind-fn #'counsel-delete-process
  1621. :format-fn #'counsel--git-log-format-function)
  1622. (add-to-list 'counsel-async-split-string-re-alist '(counsel-git-log . "^commit "))
  1623. (add-to-list 'counsel-async-ignore-re-alist '(counsel-git-log . "^[ \n]*$"))
  1624. ;;* File
  1625. ;;** `counsel-find-file'
  1626. (defvar counsel-find-file-map
  1627. (let ((map (make-sparse-keymap)))
  1628. (define-key map (kbd "C-DEL") 'counsel-up-directory)
  1629. (define-key map (kbd "C-<backspace>") 'counsel-up-directory)
  1630. (define-key map (kbd "`") #'counsel-file-jump-from-find)
  1631. (define-key map (kbd "C-`") (ivy-make-magic-action 'counsel-find-file "b"))
  1632. (define-key map [remap undo] 'counsel-find-file-undo)
  1633. map))
  1634. (defun counsel-file-jump-from-find ()
  1635. "Switch to `counsel-file-jump' from `counsel-find-file'."
  1636. (interactive)
  1637. (ivy-quit-and-run
  1638. (counsel-file-jump ivy-text (ivy-state-directory ivy-last))))
  1639. (when (executable-find "git")
  1640. (add-to-list 'ivy-ffap-url-functions 'counsel-github-url-p)
  1641. (add-to-list 'ivy-ffap-url-functions 'counsel-emacs-url-p))
  1642. (add-to-list 'ivy-ffap-url-functions 'counsel-url-expand)
  1643. (defun counsel-find-file-cd-bookmark-action (_)
  1644. "Reset `counsel-find-file' from selected directory."
  1645. (ivy-read "cd: "
  1646. (progn
  1647. (ivy--virtual-buffers)
  1648. (delete-dups
  1649. (mapcar (lambda (x) (file-name-directory (cdr x)))
  1650. ivy--virtual-buffers)))
  1651. :action (lambda (x)
  1652. (let ((default-directory (file-name-directory x)))
  1653. (counsel-find-file)))))
  1654. (defcustom counsel-root-command "sudo"
  1655. "Command to gain root privileges."
  1656. :type 'string)
  1657. (defun counsel-find-file-as-root (x)
  1658. "Find file X with root privileges."
  1659. (counsel-require-program counsel-root-command)
  1660. (let* ((host (file-remote-p x 'host))
  1661. (file-name (format "/%s:%s:%s"
  1662. counsel-root-command
  1663. (or host "")
  1664. (expand-file-name
  1665. (if host
  1666. (file-remote-p x 'localname)
  1667. x)))))
  1668. ;; If the current buffer visits the same file we are about to open,
  1669. ;; replace the current buffer with the new one.
  1670. (if (eq (current-buffer) (get-file-buffer x))
  1671. (find-alternate-file file-name)
  1672. (find-file file-name))))
  1673. (defun counsel--yes-or-no-p (fmt &rest args)
  1674. "Ask user a yes or no question created using FMT and ARGS.
  1675. If Emacs 26 user option `read-answer-short' is bound, use it to
  1676. choose between `yes-or-no-p' and `y-or-n-p'; otherwise default to
  1677. `yes-or-no-p'."
  1678. (funcall (if (and (boundp 'read-answer-short)
  1679. (cond ((eq read-answer-short t))
  1680. ((eq read-answer-short 'auto)
  1681. (eq (symbol-function 'yes-or-no-p) 'y-or-n-p))))
  1682. #'y-or-n-p
  1683. #'yes-or-no-p)
  1684. (apply #'format fmt args)))
  1685. (defun counsel-find-file-copy (x)
  1686. "Copy file X."
  1687. (require 'dired-aux)
  1688. (counsel--find-file-1 "Copy file to: "
  1689. ivy--directory
  1690. (lambda (new-name)
  1691. (dired-copy-file x new-name 1))
  1692. 'counsel-find-file-copy))
  1693. (defun counsel-find-file-delete (x)
  1694. "Delete file X."
  1695. (when (or delete-by-moving-to-trash
  1696. ;; `dired-delete-file', which see, already prompts for directories
  1697. (eq t (car (file-attributes x)))
  1698. (counsel--yes-or-no-p "Delete %s? " x))
  1699. (dired-delete-file x dired-recursive-deletes delete-by-moving-to-trash)
  1700. (dired-clean-up-after-deletion x)
  1701. (let ((win (and (not (eq ivy-exit 'done))
  1702. (active-minibuffer-window))))
  1703. (when win (with-selected-window win (ivy--cd ivy--directory))))))
  1704. (defun counsel-find-file-move (x)
  1705. "Move or rename file X."
  1706. (require 'dired-aux)
  1707. (counsel--find-file-1 "Rename file to: "
  1708. ivy--directory
  1709. (lambda (new-name)
  1710. (dired-rename-file x new-name 1))
  1711. 'counsel-find-file-move))
  1712. (defun counsel-find-file-mkdir-action (_x)
  1713. "Create a directory and any nonexistent parent dirs from `ivy-text'."
  1714. (let ((dir (file-name-as-directory
  1715. (expand-file-name ivy-text ivy--directory)))
  1716. (win (and (not (eq ivy-exit 'done))
  1717. (active-minibuffer-window))))
  1718. (make-directory dir t)
  1719. (when win (with-selected-window win (ivy--cd dir)))))
  1720. (ivy-set-actions
  1721. 'counsel-find-file
  1722. '(("j" find-file-other-window "other window")
  1723. ("f" find-file-other-frame "other frame")
  1724. ("b" counsel-find-file-cd-bookmark-action "cd bookmark")
  1725. ("x" counsel-find-file-extern "open externally")
  1726. ("r" counsel-find-file-as-root "open as root")
  1727. ("R" find-file-read-only "read only")
  1728. ("l" find-file-literally "open literally")
  1729. ("k" counsel-find-file-delete "delete")
  1730. ("c" counsel-find-file-copy "copy file")
  1731. ("m" counsel-find-file-move "move or rename")
  1732. ("d" counsel-find-file-mkdir-action "mkdir")))
  1733. (defcustom counsel-find-file-at-point nil
  1734. "When non-nil, add file-at-point to the list of candidates."
  1735. :type 'boolean)
  1736. (defcustom counsel-preselect-current-file nil
  1737. "When non-nil, preselect current file in list of candidates."
  1738. :type 'boolean)
  1739. (defcustom counsel-find-file-ignore-regexp nil
  1740. "A regexp of files to ignore while in `counsel-find-file'.
  1741. These files are un-ignored if `ivy-text' matches them. The
  1742. common way to show all files is to start `ivy-text' with a dot.
  1743. Example value: \"\\(?:\\`[#.]\\)\\|\\(?:[#~]\\'\\)\". This will hide
  1744. temporary and lock files.
  1745. \\<ivy-minibuffer-map>
  1746. Choosing the dotfiles option, \"\\`\\.\", might be convenient,
  1747. since you can still access the dotfiles if your input starts with
  1748. a dot. The generic way to toggle ignored files is \\[ivy-toggle-ignore],
  1749. but the leading dot is a lot faster."
  1750. :type `(choice
  1751. (const :tag "None" nil)
  1752. (const :tag "Dotfiles and Lockfiles" "\\(?:\\`\\|[/\\]\\)\\(?:[#.]\\)")
  1753. (const :tag "Ignored Extensions"
  1754. ,(regexp-opt completion-ignored-extensions))
  1755. (regexp :tag "Regex")))
  1756. (defvar counsel--find-file-predicate nil
  1757. "When non-nil, `counsel--find-file-matcher' will use this predicate.")
  1758. (defun counsel--find-file-matcher (regexp candidates)
  1759. "Return REGEXP matching CANDIDATES.
  1760. Skip some dotfiles unless `ivy-text' requires them."
  1761. (let ((res
  1762. (ivy--re-filter
  1763. regexp candidates
  1764. (lambda (re-str)
  1765. (lambda (x)
  1766. (string-match re-str (directory-file-name x)))))))
  1767. (when counsel--find-file-predicate
  1768. (let ((default-directory ivy--directory))
  1769. (setq res (cl-remove-if-not counsel--find-file-predicate res))))
  1770. (if (or (null ivy-use-ignore)
  1771. (null counsel-find-file-ignore-regexp)
  1772. (string-match-p counsel-find-file-ignore-regexp ivy-text))
  1773. res
  1774. (or (cl-remove-if
  1775. (lambda (x)
  1776. (and
  1777. (string-match-p counsel-find-file-ignore-regexp x)
  1778. (not (member x ivy-extra-directories))))
  1779. res)
  1780. res))))
  1781. (declare-function ffap-guesser "ffap")
  1782. (defvar counsel-find-file-speedup-remote t
  1783. "Speed up opening remote files by disabling `find-file-hook' for them.")
  1784. (defcustom counsel-find-file-extern-extensions '("mp4" "mkv" "xlsx")
  1785. "List of extensions that make `counsel-find-file' use `counsel-find-file-extern'."
  1786. :type '(repeat string))
  1787. (defun counsel-find-file-action (x)
  1788. "Find file X."
  1789. (cond ((and counsel-find-file-speedup-remote
  1790. (file-remote-p ivy--directory))
  1791. (let ((find-file-hook nil))
  1792. (find-file (expand-file-name x ivy--directory))))
  1793. ((member (file-name-extension x) counsel-find-file-extern-extensions)
  1794. (counsel-find-file-extern x))
  1795. (t
  1796. (find-file (expand-file-name x ivy--directory)))))
  1797. (defun counsel--preselect-file ()
  1798. "Return candidate to preselect during filename completion.
  1799. The preselect behavior can be customized via user options
  1800. `counsel-find-file-at-point' and
  1801. `counsel-preselect-current-file', which see."
  1802. (or
  1803. (when counsel-find-file-at-point
  1804. (require 'ffap)
  1805. (let ((f (ffap-guesser)))
  1806. (when (and f (not (ivy-ffap-url-p f)))
  1807. (expand-file-name f))))
  1808. (and counsel-preselect-current-file
  1809. buffer-file-name
  1810. (file-name-nondirectory buffer-file-name))))
  1811. (defun counsel--find-file-1 (prompt initial-input action caller)
  1812. (let ((default-directory
  1813. (if (eq major-mode 'dired-mode)
  1814. (dired-current-directory)
  1815. default-directory)))
  1816. (ivy-read prompt #'read-file-name-internal
  1817. :matcher #'counsel--find-file-matcher
  1818. :initial-input initial-input
  1819. :action action
  1820. :preselect (counsel--preselect-file)
  1821. :require-match 'confirm-after-completion
  1822. :history 'file-name-history
  1823. :keymap counsel-find-file-map
  1824. :caller caller)))
  1825. ;;;###autoload
  1826. (defun counsel-find-file (&optional initial-input initial-directory)
  1827. "Forward to `find-file'.
  1828. When INITIAL-INPUT is non-nil, use it in the minibuffer during completion."
  1829. (interactive)
  1830. (let ((default-directory (or initial-directory default-directory)))
  1831. (counsel--find-file-1 "Find file: " initial-input
  1832. #'counsel-find-file-action
  1833. 'counsel-find-file)))
  1834. (ivy-configure 'counsel-find-file
  1835. :parent 'read-file-name-internal
  1836. :occur #'counsel-find-file-occur)
  1837. (defvar counsel-find-file-occur-cmd "ls -a | %s | xargs -d '\\n' ls -d --group-directories-first"
  1838. "Format string for `counsel-find-file-occur'.")
  1839. (defvar counsel-find-file-occur-use-find (not (eq system-type 'gnu/linux))
  1840. "When non-nil, `counsel-find-file-occur' will use \"find\" as the base cmd.")
  1841. (defun counsel--expand-ls (cmd)
  1842. "Expand CMD that ends in \"ls\" with switches."
  1843. (concat cmd " " counsel-dired-listing-switches " | sed -e \"s/^/ /\""))
  1844. (defvar counsel-file-name-filter-alist
  1845. '(("ag -i '%s'" . t)
  1846. ("ack -i '%s'" . t)
  1847. ("perl -ne '/(.*%s.*)/i && print \"$1\\n\";'" . t)
  1848. ("grep -i -E '%s'"))
  1849. "Alist of file name filtering commands.
  1850. The car is a shell command and the cdr is t when the shell
  1851. command supports look-arounds. The executable for the commands
  1852. will be checked for existence via `executable-find'. The first
  1853. one that exists will be used.")
  1854. (defun counsel--file-name-filter (&optional use-ignore)
  1855. "Return a command that filters a file list to match ivy candidates.
  1856. If USE-IGNORE is non-nil, try to generate a command that respects
  1857. `counsel-find-file-ignore-regexp'."
  1858. (let ((regex ivy--old-re))
  1859. (if (= 0 (length regex))
  1860. "cat"
  1861. (let ((filter-cmd (cl-find-if
  1862. (lambda (x)
  1863. (executable-find
  1864. (car (split-string (car x)))))
  1865. counsel-file-name-filter-alist))
  1866. cmd)
  1867. (when (and use-ignore ivy-use-ignore
  1868. counsel-find-file-ignore-regexp
  1869. (cdr filter-cmd)
  1870. (not (string-match-p counsel-find-file-ignore-regexp ivy-text))
  1871. (not (string-match-p counsel-find-file-ignore-regexp
  1872. (or (car ivy--old-cands) ""))))
  1873. (let ((ignore-re (list (counsel--elisp-to-pcre
  1874. counsel-find-file-ignore-regexp))))
  1875. (setq regex (if (stringp regex)
  1876. (list ignore-re (cons regex t))
  1877. (cons ignore-re regex)))))
  1878. (setq cmd (format (car filter-cmd)
  1879. (counsel--elisp-to-pcre regex (cdr filter-cmd))))
  1880. (if (string-match-p "csh\\'" shell-file-name)
  1881. (replace-regexp-in-string "\\?!" "?\\\\!" cmd)
  1882. cmd)))))
  1883. (defun counsel--occur-cmd-find ()
  1884. (let ((cmd (format
  1885. "find . -maxdepth 1 | %s | xargs -I {} find {} -maxdepth 0 -ls"
  1886. (counsel--file-name-filter t))))
  1887. (concat
  1888. (counsel--cmd-to-dired-by-type "d" cmd)
  1889. " && "
  1890. (counsel--cmd-to-dired-by-type "f" cmd))))
  1891. (defun counsel--cmd-to-dired-by-type (type cmd)
  1892. (let ((exclude-dots
  1893. (if (string-match "^\\." ivy-text)
  1894. ""
  1895. " | grep -v '/\\\\.'")))
  1896. (replace-regexp-in-string
  1897. " | grep"
  1898. (concat " -type " type exclude-dots " | grep") cmd)))
  1899. (defun counsel-find-file-occur (&optional _cands)
  1900. (require 'find-dired)
  1901. (cd ivy--directory)
  1902. (if counsel-find-file-occur-use-find
  1903. (counsel-cmd-to-dired
  1904. (counsel--occur-cmd-find)
  1905. 'find-dired-filter)
  1906. (counsel-cmd-to-dired
  1907. (counsel--expand-ls
  1908. (format counsel-find-file-occur-cmd
  1909. (if (string-match-p "grep" counsel-find-file-occur-cmd)
  1910. ;; for backwards compatibility
  1911. (counsel--elisp-to-pcre ivy--old-re)
  1912. (counsel--file-name-filter t)))))))
  1913. (defvar counsel-up-directory-level t
  1914. "Control whether `counsel-up-directory' goes up a level or always a directory.
  1915. If non-nil, then `counsel-up-directory' will remove the final level of the path.
  1916. For example: /a/long/path/file.jpg => /a/long/path/
  1917. /a/long/path/ => /a/long/
  1918. If nil, then `counsel-up-directory' will go up a directory.
  1919. For example: /a/long/path/file.jpg => /a/long/
  1920. /a/long/path/ => /a/long/")
  1921. (defun counsel-up-directory ()
  1922. "Go to the parent directory preselecting the current one.
  1923. If the current directory is remote and it's not possible to go up any
  1924. further, make the remote prefix editable.
  1925. See variable `counsel-up-directory-level'."
  1926. (interactive)
  1927. (let* ((cur-dir (directory-file-name (expand-file-name ivy--directory)))
  1928. (up-dir (file-name-directory cur-dir)))
  1929. (if (and (file-remote-p cur-dir) (string-equal cur-dir up-dir))
  1930. (progn
  1931. ;; make the remote prefix editable
  1932. (setq ivy--old-cands nil)
  1933. (setq ivy--old-re nil)
  1934. (ivy-set-index 0)
  1935. (setq ivy--directory "")
  1936. (setq ivy--all-candidates nil)
  1937. (ivy-set-text "")
  1938. (delete-minibuffer-contents)
  1939. (insert up-dir))
  1940. (if (and counsel-up-directory-level (not (string= ivy-text "")))
  1941. (delete-region (line-beginning-position) (line-end-position))
  1942. (ivy--cd up-dir)
  1943. (setf (ivy-state-preselect ivy-last)
  1944. (file-name-as-directory (file-name-nondirectory cur-dir)))))))
  1945. (defun counsel-down-directory ()
  1946. "Descend into the current directory."
  1947. (interactive)
  1948. (ivy--directory-enter))
  1949. (defun counsel-find-file-undo ()
  1950. (interactive)
  1951. (if (string= ivy-text "")
  1952. (let ((dir (progn
  1953. (pop ivy--directory-hist)
  1954. (pop ivy--directory-hist))))
  1955. (when dir
  1956. (ivy--cd dir)))
  1957. (undo)))
  1958. (defun counsel-at-git-issue-p ()
  1959. "When point is at an issue in a Git-versioned file, return the issue string."
  1960. (and (looking-at "#[0-9]+")
  1961. (or (eq (vc-backend buffer-file-name) 'Git)
  1962. (memq major-mode '(magit-commit-mode vc-git-log-view-mode))
  1963. (bound-and-true-p magit-commit-mode))
  1964. (match-string-no-properties 0)))
  1965. (defun counsel-github-url-p ()
  1966. "Return a Github issue URL at point."
  1967. (counsel-require-program "git")
  1968. (let ((url (counsel-at-git-issue-p)))
  1969. (when url
  1970. (let ((origin (shell-command-to-string
  1971. "git remote get-url origin"))
  1972. user repo)
  1973. (cond ((string-match "\\`git@github.com:\\([^/]+\\)/\\(.*\\)\\.git$"
  1974. origin)
  1975. (setq user (match-string 1 origin))
  1976. (setq repo (match-string 2 origin)))
  1977. ((string-match "\\`https://github.com/\\([^/]+\\)/\\(.*\\)$"
  1978. origin)
  1979. (setq user (match-string 1 origin))
  1980. (setq repo (match-string 2 origin))))
  1981. (when user
  1982. (setq url (format "https://github.com/%s/%s/issues/%s"
  1983. user repo (substring url 1))))))))
  1984. (defun counsel-emacs-url-p ()
  1985. "Return a Debbugs issue URL at point."
  1986. (counsel-require-program "git")
  1987. (let ((url (counsel-at-git-issue-p)))
  1988. (when url
  1989. (let ((origin (shell-command-to-string
  1990. "git remote get-url origin")))
  1991. (when (string-match "git.sv.gnu.org:/srv/git/emacs.git" origin)
  1992. (format "https://debbugs.gnu.org/cgi/bugreport.cgi?bug=%s"
  1993. (substring url 1)))))))
  1994. (defvar counsel-url-expansions-alist nil
  1995. "Map of regular expressions to expansions.
  1996. This variable should take the form of a list of (REGEXP . FORMAT)
  1997. pairs.
  1998. `counsel-url-expand' will expand the word at point according to
  1999. FORMAT for the first matching REGEXP. FORMAT can be either a
  2000. string or a function. If it is a string, it will be used as the
  2001. format string for the `format' function, with the word at point
  2002. as the next argument. If it is a function, it will be called
  2003. with the word at point as the sole argument.
  2004. For example, a pair of the form:
  2005. '(\"\\`BSERV-[[:digit:]]+\\'\" . \"https://jira.atlassian.com/browse/%s\")
  2006. will expand to URL `https://jira.atlassian.com/browse/BSERV-100'
  2007. when the word at point is BSERV-100.
  2008. If the format element is a function, more powerful
  2009. transformations are possible. As an example,
  2010. '(\"\\`issue\\([[:digit:]]+\\)\\'\" .
  2011. (lambda (word)
  2012. (concat \"https://debbugs.gnu.org/cgi/bugreport.cgi?bug=\"
  2013. (match-string 1 word))))
  2014. trims the \"issue\" prefix from the word at point before creating the URL.")
  2015. (defun counsel-url-expand ()
  2016. "Expand word at point using `counsel-url-expansions-alist'.
  2017. The first pair in the list whose regexp matches the word at point
  2018. will be expanded according to its format. This function is
  2019. intended to be used in `ivy-ffap-url-functions' to browse the
  2020. result as a URL."
  2021. (let ((word-at-point (current-word)))
  2022. (when word-at-point
  2023. (cl-some
  2024. (lambda (pair)
  2025. (let ((regexp (car pair))
  2026. (formatter (cdr pair)))
  2027. (when (string-match regexp word-at-point)
  2028. (if (functionp formatter)
  2029. (funcall formatter word-at-point)
  2030. (format formatter word-at-point)))))
  2031. counsel-url-expansions-alist))))
  2032. ;;** `counsel-dired'
  2033. (declare-function dired "dired")
  2034. ;;;###autoload
  2035. (defun counsel-dired (&optional initial-input)
  2036. "Forward to `dired'.
  2037. When INITIAL-INPUT is non-nil, use it in the minibuffer during completion."
  2038. (interactive)
  2039. (let ((counsel--find-file-predicate #'file-directory-p))
  2040. (counsel--find-file-1
  2041. "Dired (directory): " initial-input
  2042. (lambda (d) (dired (expand-file-name d)))
  2043. 'counsel-dired)))
  2044. (ivy-configure 'counsel-dired
  2045. :parent 'read-file-name-internal)
  2046. ;;** `counsel-recentf'
  2047. (defvar recentf-list)
  2048. (declare-function recentf-mode "recentf")
  2049. (defcustom counsel-recentf-include-xdg-list nil
  2050. "Include recently used files listed by XDG-compliant environments.
  2051. Examples of such environments are GNOME and KDE. See the URL
  2052. `https://www.freedesktop.org/wiki/Specifications/desktop-bookmark-spec'."
  2053. :type 'boolean
  2054. :link '(url-link "\
  2055. https://www.freedesktop.org/wiki/Specifications/desktop-bookmark-spec"))
  2056. ;;;###autoload
  2057. (defun counsel-recentf ()
  2058. "Find a file on `recentf-list'."
  2059. (interactive)
  2060. (require 'recentf)
  2061. (recentf-mode)
  2062. (ivy-read "Recentf: " (counsel-recentf-candidates)
  2063. :action (lambda (f)
  2064. (with-ivy-window
  2065. (find-file f)))
  2066. :require-match t
  2067. :caller 'counsel-recentf))
  2068. (ivy-set-actions
  2069. 'counsel-recentf
  2070. `(("j" find-file-other-window "other window")
  2071. ("f" find-file-other-frame "other frame")
  2072. ("x" counsel-find-file-extern "open externally")
  2073. ("d" ,(lambda (file) (setq recentf-list (delete file recentf-list)))
  2074. "delete from recentf")))
  2075. (defun counsel-recentf-candidates ()
  2076. "Return candidates for `counsel-recentf'.
  2077. When `counsel-recentf-include-xdg-list' is non-nil, also include
  2078. the files in said list, sorting the combined list by file access
  2079. time."
  2080. (if (and counsel-recentf-include-xdg-list
  2081. (>= emacs-major-version 26))
  2082. (delete-dups
  2083. (sort (nconc (mapcar #'substring-no-properties recentf-list)
  2084. (counsel--recentf-get-xdg-recent-files))
  2085. (lambda (file1 file2)
  2086. (cond ((file-remote-p file1)
  2087. nil)
  2088. ((file-remote-p file2))
  2089. (t
  2090. ;; Added in Emacs 26.1.
  2091. (declare-function file-attribute-access-time "files"
  2092. (attributes))
  2093. (time-less-p (file-attribute-access-time
  2094. (file-attributes file2))
  2095. (file-attribute-access-time
  2096. (file-attributes file1))))))))
  2097. (mapcar #'substring-no-properties recentf-list)))
  2098. (defalias 'counsel--xml-parse-region
  2099. (if (cond ((fboundp 'libxml-available-p)
  2100. ;; Added in Emacs 27.1.
  2101. (libxml-available-p))
  2102. ((fboundp 'libxml-parse-xml-region)
  2103. ;; Checking for `fboundp' is not enough on Windows, where it
  2104. ;; will return non-nil even if the library is not installed.
  2105. (with-temp-buffer
  2106. (insert "<xml/>")
  2107. (libxml-parse-xml-region (point-min) (point-max)))))
  2108. (lambda (&optional beg end)
  2109. (libxml-parse-xml-region (or beg (point-min)) (or end (point-max))))
  2110. #'xml-parse-region)
  2111. "Compatibility shim for `libxml-parse-xml-region'.
  2112. For convenience, BEG and END default to `point-min' and
  2113. `point-max', respectively.
  2114. \(fn &optional BEG END)")
  2115. (defun counsel--recentf-get-xdg-recent-files ()
  2116. "Return list of XDG recent files.
  2117. This information is parsed from the file \"recently-used.xbel\",
  2118. which lists both files and directories, under `xdg-data-home'.
  2119. This function uses the `dom' library from Emacs 25.1 or later."
  2120. (unless (require 'dom nil t)
  2121. (user-error "This function requires Emacs 25.1 or later"))
  2122. (declare-function dom-attr "dom" (node attr))
  2123. (declare-function dom-by-tag "dom" (dom tag))
  2124. (let ((file-of-recent-files
  2125. (expand-file-name "recently-used.xbel" (counsel--xdg-data-home))))
  2126. (unless (file-readable-p file-of-recent-files)
  2127. (user-error "List of XDG recent files not found: %s"
  2128. file-of-recent-files))
  2129. (cl-mapcan (lambda (bookmark-node)
  2130. (let* ((file (dom-attr bookmark-node 'href))
  2131. (file (string-remove-prefix "file://" file))
  2132. (file (url-unhex-string file t))
  2133. (file (decode-coding-string file 'utf-8 t)))
  2134. (and (file-exists-p file)
  2135. (list file))))
  2136. (let ((dom (with-temp-buffer
  2137. (insert-file-contents file-of-recent-files)
  2138. (counsel--xml-parse-region))))
  2139. (nreverse (dom-by-tag dom 'bookmark))))))
  2140. (defun counsel-buffer-or-recentf-candidates ()
  2141. "Return candidates for `counsel-buffer-or-recentf'."
  2142. (require 'recentf)
  2143. (recentf-mode)
  2144. (let ((buffers
  2145. (delq nil
  2146. (mapcar (lambda (b)
  2147. (when (buffer-file-name b)
  2148. (buffer-file-name b)))
  2149. (buffer-list)))))
  2150. (append
  2151. buffers
  2152. (cl-remove-if (lambda (f) (member f buffers))
  2153. (counsel-recentf-candidates)))))
  2154. ;;;###autoload
  2155. (defun counsel-buffer-or-recentf ()
  2156. "Find a buffer visiting a file or file on `recentf-list'."
  2157. (interactive)
  2158. (ivy-read "Buffer File or Recentf: " (counsel-buffer-or-recentf-candidates)
  2159. :action (lambda (s)
  2160. (with-ivy-window
  2161. (if (bufferp s)
  2162. (switch-to-buffer s)
  2163. (find-file s))))
  2164. :require-match t
  2165. :caller 'counsel-buffer-or-recentf))
  2166. (ivy-configure 'counsel-buffer-or-recentf
  2167. :display-transformer-fn #'counsel-buffer-or-recentf-transformer)
  2168. (ivy-set-actions
  2169. 'counsel-buffer-or-recentf
  2170. '(("j" find-file-other-window "other window")
  2171. ("f" find-file-other-frame "other frame")
  2172. ("x" counsel-find-file-extern "open externally")))
  2173. (defun counsel-buffer-or-recentf-transformer (var)
  2174. "Propertize VAR if it's a buffer visiting a file."
  2175. (if (member var (mapcar #'buffer-file-name (buffer-list)))
  2176. (ivy-append-face var 'ivy-highlight-face)
  2177. var))
  2178. ;;** `counsel-bookmark'
  2179. (defcustom counsel-bookmark-avoid-dired nil
  2180. "If non-nil, open directory bookmarks with `counsel-find-file'.
  2181. By default `counsel-bookmark' opens a dired buffer for directories."
  2182. :type 'boolean)
  2183. (defvar bookmark-alist)
  2184. (declare-function bookmark-location "bookmark")
  2185. (declare-function bookmark-all-names "bookmark")
  2186. (declare-function bookmark-get-filename "bookmark")
  2187. (declare-function bookmark-maybe-load-default-file "bookmark")
  2188. ;;;###autoload
  2189. (defun counsel-bookmark ()
  2190. "Forward to `bookmark-jump' or `bookmark-set' if bookmark doesn't exist."
  2191. (interactive)
  2192. (require 'bookmark)
  2193. (ivy-read "Create or jump to bookmark: "
  2194. (bookmark-all-names)
  2195. :history 'bookmark-history
  2196. :action (lambda (x)
  2197. (cond ((and counsel-bookmark-avoid-dired
  2198. (member x (bookmark-all-names))
  2199. (file-directory-p (bookmark-location x)))
  2200. (with-ivy-window
  2201. (let ((default-directory (bookmark-location x)))
  2202. (counsel-find-file))))
  2203. ((member x (bookmark-all-names))
  2204. (with-ivy-window
  2205. (bookmark-jump x)))
  2206. (t
  2207. (bookmark-set x))))
  2208. :caller 'counsel-bookmark))
  2209. (defun counsel--apply-bookmark-fn (fn)
  2210. "Return a function applying FN to a bookmark's location."
  2211. (lambda (bookmark)
  2212. (funcall fn (bookmark-location bookmark))))
  2213. (ivy-set-actions
  2214. 'counsel-bookmark
  2215. `(("d" bookmark-delete "delete")
  2216. ("e" bookmark-rename "edit")
  2217. ("s" bookmark-set "overwrite")
  2218. ("x" ,(counsel--apply-bookmark-fn #'counsel-find-file-extern)
  2219. "open externally")
  2220. ("r" ,(counsel--apply-bookmark-fn #'counsel-find-file-as-root)
  2221. "open as root")))
  2222. ;;** `counsel-bookmarked-directory'
  2223. (defun counsel-bookmarked-directory--candidates ()
  2224. "Get a list of bookmarked directories sorted by file path."
  2225. (bookmark-maybe-load-default-file)
  2226. (sort (cl-remove-if-not
  2227. #'ivy--dirname-p
  2228. (delq nil (mapcar #'bookmark-get-filename bookmark-alist)))
  2229. #'string<))
  2230. ;;;###autoload
  2231. (defun counsel-bookmarked-directory ()
  2232. "Ivy interface for bookmarked directories.
  2233. With a prefix argument, this command creates a new bookmark which points to the
  2234. current value of `default-directory'."
  2235. (interactive)
  2236. (require 'bookmark)
  2237. (ivy-read "Bookmarked directory: "
  2238. (counsel-bookmarked-directory--candidates)
  2239. :caller 'counsel-bookmarked-directory
  2240. :action #'dired))
  2241. (ivy-set-actions 'counsel-bookmarked-directory
  2242. `(("j" dired-other-window "other window")
  2243. ("x" counsel-find-file-extern "open externally")
  2244. ("r" counsel-find-file-as-root "open as root")
  2245. ("f" ,(lambda (dir)
  2246. (let ((default-directory dir))
  2247. (call-interactively #'find-file)))
  2248. "find-file")))
  2249. ;;** `counsel-file-register'
  2250. ;;;###autoload
  2251. (defun counsel-file-register ()
  2252. "Search file in register.
  2253. You cannot use Emacs' normal register commands to create file
  2254. registers. Instead you must use the `set-register' function like
  2255. so: `(set-register ?i \"/home/eric/.emacs.d/init.el\")'. Now you
  2256. can use `C-x r j i' to open that file."
  2257. (interactive)
  2258. (ivy-read "File Register: "
  2259. ;; Use the `register-alist' variable to filter out file
  2260. ;; registers. Each entry for a file register will have the
  2261. ;; following layout:
  2262. ;;
  2263. ;; (NUMBER 'file . "string/path/to/file")
  2264. ;;
  2265. ;; So we go through each entry and see if the `cadr' is
  2266. ;; `eq' to the symbol `file'. If so then add the filename
  2267. ;; (`cddr') which `ivy-read' will use for its choices.
  2268. (mapcar (lambda (register-alist-entry)
  2269. (if (eq 'file (cadr register-alist-entry))
  2270. (cddr register-alist-entry)))
  2271. register-alist)
  2272. :require-match t
  2273. :history 'counsel-file-register
  2274. :caller 'counsel-file-register
  2275. :action (lambda (register-file)
  2276. (with-ivy-window (find-file register-file)))))
  2277. (ivy-configure 'counsel-file-register
  2278. :sort-fn #'ivy-string<)
  2279. (ivy-set-actions
  2280. 'counsel-file-register
  2281. '(("j" find-file-other-window "other window")))
  2282. ;;** `counsel-locate'
  2283. (defcustom counsel-locate-cmd (cond ((memq system-type '(darwin berkeley-unix))
  2284. #'counsel-locate-cmd-noregex)
  2285. ((and (eq system-type 'windows-nt)
  2286. (executable-find "es.exe"))
  2287. #'counsel-locate-cmd-es)
  2288. (t
  2289. #'counsel-locate-cmd-default))
  2290. "The function for producing a `locate' command string from the input.
  2291. The function takes a string - the current input, and returns a
  2292. string - the full shell command to run."
  2293. :type '(choice
  2294. (const :tag "Default" counsel-locate-cmd-default)
  2295. (const :tag "No regex" counsel-locate-cmd-noregex)
  2296. (const :tag "mdfind" counsel-locate-cmd-mdfind)
  2297. (const :tag "everything" counsel-locate-cmd-es)
  2298. (function :tag "Custom")))
  2299. (ivy-set-actions
  2300. 'counsel-locate
  2301. '(("x" counsel-locate-action-extern "xdg-open")
  2302. ("r" counsel-find-file-as-root "open as root")
  2303. ("d" counsel-locate-action-dired "dired")))
  2304. (defvar counsel-locate-history nil
  2305. "History for `counsel-locate'.")
  2306. ;;;###autoload
  2307. (defun counsel-locate-action-extern (x)
  2308. "Pass X to `xdg-open' or equivalent command via the shell."
  2309. (interactive "FFile: ")
  2310. (if (and (eq system-type 'windows-nt)
  2311. (fboundp 'w32-shell-execute))
  2312. (w32-shell-execute "open" x)
  2313. (call-process-shell-command (format "%s %s"
  2314. (cl-case system-type
  2315. (darwin "open")
  2316. (cygwin "cygstart")
  2317. (t "xdg-open"))
  2318. (shell-quote-argument x))
  2319. nil 0)))
  2320. (defalias 'counsel-find-file-extern #'counsel-locate-action-extern)
  2321. (declare-function dired-jump "dired-x")
  2322. (defun counsel-locate-action-dired (x)
  2323. "Use `dired-jump' on X."
  2324. (dired-jump nil x))
  2325. (defun counsel-locate-cmd-default (input)
  2326. "Return a `locate' shell command based on regexp INPUT."
  2327. (counsel-require-program "locate")
  2328. (format "locate -i --regex %s"
  2329. (shell-quote-argument
  2330. (counsel--elisp-to-pcre
  2331. (ivy--regex input)))))
  2332. (defun counsel-locate-cmd-noregex (input)
  2333. "Return a `locate' shell command based on INPUT."
  2334. (counsel-require-program "locate")
  2335. (format "locate -i %s" (shell-quote-argument input)))
  2336. (defun counsel-locate-cmd-mdfind (input)
  2337. "Return a `mdfind' shell command based on INPUT."
  2338. (counsel-require-program "mdfind")
  2339. (format "mdfind -name %s" (shell-quote-argument input)))
  2340. (defun counsel-locate-cmd-es (input)
  2341. "Return a `es' shell command based on INPUT."
  2342. (defvar w32-ansi-code-page)
  2343. (counsel-require-program "es.exe")
  2344. (let ((raw-string (format "es.exe -i -p -r %s"
  2345. (counsel--elisp-to-pcre
  2346. (ivy--regex input t)))))
  2347. ;; W32 doesn't use Unicode by default, so we encode search command
  2348. ;; to local codepage to support searching file names containing
  2349. ;; non-ASCII characters.
  2350. (if (and (eq system-type 'windows-nt)
  2351. (boundp 'w32-ansi-code-page))
  2352. (encode-coding-string raw-string
  2353. (intern (format "cp%d" w32-ansi-code-page)))
  2354. raw-string)))
  2355. (defun counsel-locate-function (input)
  2356. "Call a \"locate\" style shell command with INPUT."
  2357. (or
  2358. (ivy-more-chars)
  2359. (progn
  2360. (counsel--async-command
  2361. (funcall counsel-locate-cmd input))
  2362. '("" "working..."))))
  2363. (defcustom counsel-locate-db-path "~/.local/mlocate.db"
  2364. "Location where to put the locatedb in case your home folder is encrypted."
  2365. :type 'file)
  2366. (defun counsel-file-stale-p (fname seconds)
  2367. "Return non-nil if FNAME was modified more than SECONDS ago."
  2368. (> (float-time (time-subtract nil (nth 5 (file-attributes fname))))
  2369. seconds))
  2370. (defun counsel--locate-updatedb ()
  2371. (when (file-exists-p "~/.Private")
  2372. (let ((db-fname (expand-file-name counsel-locate-db-path)))
  2373. (setenv "LOCATE_PATH" db-fname)
  2374. (when (or (not (file-exists-p db-fname))
  2375. (counsel-file-stale-p db-fname 60))
  2376. (message "Updating %s..." db-fname)
  2377. (counsel--command
  2378. "updatedb" "-l" "0" "-o" db-fname "-U" (expand-file-name "~"))))))
  2379. ;;;###autoload
  2380. (defun counsel-locate (&optional initial-input)
  2381. "Call a \"locate\" style shell command.
  2382. INITIAL-INPUT can be given as the initial minibuffer input."
  2383. (interactive)
  2384. (counsel--locate-updatedb)
  2385. (ivy-read "Locate: " #'counsel-locate-function
  2386. :initial-input initial-input
  2387. :dynamic-collection t
  2388. :history 'counsel-locate-history
  2389. :action (lambda (file)
  2390. (when file
  2391. (with-ivy-window
  2392. (find-file
  2393. (concat (file-remote-p default-directory) file)))))
  2394. :caller 'counsel-locate))
  2395. (ivy-configure 'counsel-locate
  2396. :unwind-fn #'counsel-delete-process
  2397. :exit-codes '(1 "Nothing found"))
  2398. ;;** `counsel-tracker'
  2399. (defun counsel-tracker-function (input)
  2400. "Call the \"tracker\" shell command with INPUT."
  2401. (or
  2402. (ivy-more-chars)
  2403. (progn
  2404. (counsel--async-command
  2405. (format
  2406. "tracker sparql -q \"SELECT ?url WHERE { ?s a nfo:FileDataObject ; nie:url ?url . FILTER (STRSTARTS (?url, 'file://$HOME/')) . FILTER regex(?url, '%s') }\" | tail -n +2 | head -n -1"
  2407. (counsel--elisp-to-pcre (funcall ivy--regex-function input))))
  2408. '("" "working..."))))
  2409. (defun counsel-tracker-transformer (str)
  2410. (if (string-match "file:///" str)
  2411. (decode-coding-string (url-unhex-string (substring str 9)) 'utf-8)
  2412. str))
  2413. ;;;###autoload
  2414. (defun counsel-tracker ()
  2415. (interactive)
  2416. (ivy-read "Tracker: " 'counsel-tracker-function
  2417. :dynamic-collection t
  2418. :action (lambda (s) (find-file (counsel-tracker-transformer s)))
  2419. :caller 'counsel-tracker))
  2420. (ivy-configure 'counsel-tracker
  2421. :display-transformer-fn #'counsel-tracker-transformer
  2422. :unwind-fn #'counsel-delete-process)
  2423. ;;** `counsel-fzf'
  2424. (defvar counsel-fzf-cmd "fzf -f \"%s\""
  2425. "Command for `counsel-fzf'.")
  2426. (defvar counsel--fzf-dir nil
  2427. "Store the base fzf directory.")
  2428. (defvar counsel-fzf-dir-function 'counsel-fzf-dir-function-projectile
  2429. "Function that returns a directory for fzf to use.")
  2430. (defun counsel-fzf-dir-function-projectile ()
  2431. (if (and
  2432. (fboundp 'projectile-project-p)
  2433. (fboundp 'projectile-project-root)
  2434. (projectile-project-p))
  2435. (projectile-project-root)
  2436. default-directory))
  2437. (defun counsel-fzf-function (str)
  2438. (let ((default-directory counsel--fzf-dir))
  2439. (setq ivy--old-re (ivy--regex-fuzzy str))
  2440. (counsel--async-command
  2441. (format counsel-fzf-cmd str)))
  2442. nil)
  2443. ;;;###autoload
  2444. (defun counsel-fzf (&optional initial-input initial-directory fzf-prompt)
  2445. "Open a file using the fzf shell command.
  2446. INITIAL-INPUT can be given as the initial minibuffer input.
  2447. INITIAL-DIRECTORY, if non-nil, is used as the root directory for search.
  2448. FZF-PROMPT, if non-nil, is passed as `ivy-read' prompt argument."
  2449. (interactive
  2450. (let ((fzf-basename (car (split-string counsel-fzf-cmd))))
  2451. (list nil
  2452. (when current-prefix-arg
  2453. (counsel-read-directory-name (concat
  2454. fzf-basename
  2455. " in directory: "))))))
  2456. (counsel-require-program counsel-fzf-cmd)
  2457. (setq counsel--fzf-dir
  2458. (or initial-directory
  2459. (funcall counsel-fzf-dir-function)))
  2460. (ivy-read (or fzf-prompt "fzf: ")
  2461. #'counsel-fzf-function
  2462. :initial-input initial-input
  2463. :re-builder #'ivy--regex-fuzzy
  2464. :dynamic-collection t
  2465. :action #'counsel-fzf-action
  2466. :caller 'counsel-fzf))
  2467. (ivy-configure 'counsel-fzf
  2468. :occur #'counsel-fzf-occur
  2469. :unwind-fn #'counsel-delete-process
  2470. :exit-codes '(1 "Nothing found"))
  2471. (defun counsel-fzf-action (x)
  2472. "Find file X in current fzf directory."
  2473. (with-ivy-window
  2474. (let ((default-directory counsel--fzf-dir))
  2475. (find-file x))))
  2476. (defun counsel-fzf-occur (&optional _cands)
  2477. "Occur function for `counsel-fzf' using `counsel-cmd-to-dired'."
  2478. (cd counsel--fzf-dir)
  2479. (counsel-cmd-to-dired
  2480. (counsel--expand-ls
  2481. (format
  2482. "%s --print0 | xargs -0 ls"
  2483. (format counsel-fzf-cmd ivy-text)))))
  2484. (ivy-set-actions
  2485. 'counsel-fzf
  2486. '(("x" counsel-locate-action-extern "xdg-open")
  2487. ("d" counsel-locate-action-dired "dired")))
  2488. ;;** `counsel-dpkg'
  2489. ;;;###autoload
  2490. (defun counsel-dpkg ()
  2491. "Call the \"dpkg\" shell command."
  2492. (interactive)
  2493. (counsel-require-program "dpkg")
  2494. (let ((cands (mapcar
  2495. (lambda (x)
  2496. (let ((y (split-string x " +")))
  2497. (cons (format "%-40s %s"
  2498. (ivy--truncate-string
  2499. (nth 1 y) 40)
  2500. (nth 4 y))
  2501. (mapconcat #'identity y " "))))
  2502. (split-string
  2503. (shell-command-to-string "dpkg -l | tail -n+6") "\n" t))))
  2504. (ivy-read "dpkg: " cands
  2505. :action (lambda (x)
  2506. (message (cdr x)))
  2507. :caller 'counsel-dpkg)))
  2508. ;;** `counsel-rpm'
  2509. ;;;###autoload
  2510. (defun counsel-rpm ()
  2511. "Call the \"rpm\" shell command."
  2512. (interactive)
  2513. (counsel-require-program "rpm")
  2514. (let ((cands (mapcar
  2515. (lambda (x)
  2516. (let ((y (split-string x "|")))
  2517. (cons (format "%-40s %s"
  2518. (ivy--truncate-string
  2519. (nth 0 y) 40)
  2520. (nth 1 y))
  2521. (mapconcat #'identity y " "))))
  2522. (split-string
  2523. (shell-command-to-string "rpm -qa --qf \"%{NAME}|%{SUMMARY}\\n\"") "\n" t))))
  2524. (ivy-read "rpm: " cands
  2525. :action (lambda (x)
  2526. (message (cdr x)))
  2527. :caller 'counsel-rpm)))
  2528. (defun counsel--find-return-list (args)
  2529. (unless (listp args)
  2530. (user-error
  2531. "`counsel-file-jump-args' is a list now; please customize accordingly"))
  2532. (counsel--call
  2533. (cons find-program args)
  2534. (lambda ()
  2535. (let (files)
  2536. (goto-char (point-min))
  2537. (while (< (point) (point-max))
  2538. (when (looking-at "\\./")
  2539. (goto-char (match-end 0)))
  2540. (push (buffer-substring (point) (line-end-position)) files)
  2541. (beginning-of-line 2))
  2542. (nreverse files)))))
  2543. (defcustom counsel-file-jump-args (split-string ". -name .git -prune -o -type f -print")
  2544. "Arguments for the `find-command' when using `counsel-file-jump'."
  2545. :type '(repeat string))
  2546. ;;** `counsel-file-jump'
  2547. (defvar counsel-file-jump-map
  2548. (let ((map (make-sparse-keymap)))
  2549. (define-key map (kbd "`") #'counsel-find-file-from-jump)
  2550. map)
  2551. "Key bindings to be used when in a file-jump minibuffer.")
  2552. (defun counsel-find-file-from-jump ()
  2553. "Switch to `counsel-find-file' from `counsel-file-jump'."
  2554. (interactive)
  2555. (ivy-quit-and-run
  2556. (counsel-find-file ivy-text (ivy-state-directory ivy-last))))
  2557. ;;;###autoload
  2558. (defun counsel-file-jump (&optional initial-input initial-directory)
  2559. "Jump to a file below the current directory.
  2560. List all files within the current directory or any of its sub-directories.
  2561. INITIAL-INPUT can be given as the initial minibuffer input.
  2562. INITIAL-DIRECTORY, if non-nil, is used as the root directory for search."
  2563. (interactive
  2564. (list nil
  2565. (when current-prefix-arg
  2566. (counsel-read-directory-name "From directory: "))))
  2567. (counsel-require-program find-program)
  2568. (let ((default-directory (or initial-directory default-directory)))
  2569. (ivy-read "Find file: "
  2570. (counsel--find-return-list counsel-file-jump-args)
  2571. :matcher #'counsel--find-file-matcher
  2572. :initial-input initial-input
  2573. :action #'find-file
  2574. :preselect (counsel--preselect-file)
  2575. :require-match 'confirm-after-completion
  2576. :history 'file-name-history
  2577. :keymap counsel-file-jump-map
  2578. :caller 'counsel-file-jump)))
  2579. (ivy-set-actions
  2580. 'counsel-file-jump
  2581. `(("d" ,(lambda (x)
  2582. (dired (or (file-name-directory x) default-directory)))
  2583. "open in dired")))
  2584. (defcustom counsel-dired-jump-args (split-string ". -name .git -prune -o -type d -print")
  2585. "Arguments for the `find-command' when using `counsel-dired-jump'."
  2586. :type '(repeat string))
  2587. ;;** `counsel-dired-jump'
  2588. ;;;###autoload
  2589. (defun counsel-dired-jump (&optional initial-input initial-directory)
  2590. "Jump to a directory (see `dired-jump') below the current directory.
  2591. List all sub-directories within the current directory.
  2592. INITIAL-INPUT can be given as the initial minibuffer input.
  2593. INITIAL-DIRECTORY, if non-nil, is used as the root directory for search."
  2594. (interactive
  2595. (list nil
  2596. (when current-prefix-arg
  2597. (counsel-read-directory-name "From directory: "))))
  2598. (counsel-require-program find-program)
  2599. (let ((default-directory (or initial-directory default-directory)))
  2600. (ivy-read "Find directory: "
  2601. (cdr
  2602. (counsel--find-return-list counsel-dired-jump-args))
  2603. :matcher #'counsel--find-file-matcher
  2604. :initial-input initial-input
  2605. :action (lambda (d) (dired-jump nil (expand-file-name d)))
  2606. :history 'file-name-history
  2607. :keymap counsel-find-file-map
  2608. :caller 'counsel-dired-jump)))
  2609. ;;* Grep
  2610. ;;** `counsel-ag'
  2611. (defvar counsel-ag-map
  2612. (let ((map (make-sparse-keymap)))
  2613. (define-key map (kbd "C-l") 'ivy-call-and-recenter)
  2614. (define-key map (kbd "M-q") 'counsel-git-grep-query-replace)
  2615. (define-key map (kbd "C-'") 'swiper-avy)
  2616. (define-key map (kbd "C-x C-d") 'counsel-cd)
  2617. map))
  2618. (defcustom counsel-ag-base-command "ag --vimgrep %s"
  2619. "Format string to use in `counsel-ag-function' to construct the command.
  2620. The %s will be replaced by optional extra ag arguments followed by the
  2621. regex string."
  2622. :type '(radio
  2623. (const "ag --vimgrep %s")
  2624. (const "ag --nocolor --nogroup %s")
  2625. (string :tag "custom")))
  2626. (defvar counsel-ag-command nil)
  2627. (defvar counsel--grep-tool-look-around t)
  2628. (defvar counsel--regex-look-around nil)
  2629. (defconst counsel--command-args-separator " -- ")
  2630. (defun counsel--split-command-args (arguments)
  2631. "Split ARGUMENTS into its switches and search-term parts.
  2632. Return pair of corresponding strings (SWITCHES . SEARCH-TERM)."
  2633. (if (string-match counsel--command-args-separator arguments)
  2634. (let ((args (substring arguments (match-end 0)))
  2635. (search-term (substring arguments 0 (match-beginning 0))))
  2636. (if (string-prefix-p "-" arguments)
  2637. (cons search-term args)
  2638. (cons args search-term)))
  2639. (cons "" arguments)))
  2640. (defun counsel--format-ag-command (extra-args needle)
  2641. "Construct a complete `counsel-ag-command' as a string.
  2642. EXTRA-ARGS is a string of the additional arguments.
  2643. NEEDLE is the search string."
  2644. (counsel--format counsel-ag-command
  2645. (if (listp counsel-ag-command)
  2646. (if (string-match " \\(--\\) " extra-args)
  2647. (counsel--format
  2648. (split-string (replace-match "%s" t t extra-args 1))
  2649. needle)
  2650. (nconc (split-string extra-args) needle))
  2651. (if (string-match " \\(--\\) " extra-args)
  2652. (replace-match needle t t extra-args 1)
  2653. (concat extra-args " " needle)))))
  2654. (defun counsel--grep-regex (str)
  2655. (counsel--elisp-to-pcre
  2656. (setq ivy--old-re
  2657. (funcall (ivy-state-re-builder ivy-last) str))
  2658. counsel--regex-look-around))
  2659. (defun counsel--ag-extra-switches (regex)
  2660. "Get additional switches needed for look-arounds."
  2661. (and (stringp counsel--regex-look-around)
  2662. ;; using look-arounds
  2663. (string-match-p "\\`\\^(\\?[=!]" regex)
  2664. (concat " " counsel--regex-look-around " ")))
  2665. (defun counsel-ag-function (string)
  2666. "Grep in the current directory for STRING."
  2667. (let* ((command-args (counsel--split-command-args string))
  2668. (search-term (cdr command-args)))
  2669. (or
  2670. (let ((ivy-text search-term))
  2671. (ivy-more-chars))
  2672. (let* ((default-directory (ivy-state-directory ivy-last))
  2673. (regex (counsel--grep-regex search-term))
  2674. (switches (concat (if (ivy--case-fold-p string)
  2675. " -i "
  2676. " -s ")
  2677. (counsel--ag-extra-switches regex)
  2678. (car command-args))))
  2679. (counsel--async-command (counsel--format-ag-command
  2680. switches
  2681. (funcall (if (listp counsel-ag-command) #'identity
  2682. #'shell-quote-argument)
  2683. regex)))
  2684. nil))))
  2685. ;;;###autoload
  2686. (cl-defun counsel-ag (&optional initial-input initial-directory extra-ag-args ag-prompt
  2687. &key caller)
  2688. "Grep for a string in a root directory using ag.
  2689. By default, the root directory is the first directory containing a .git subdirectory.
  2690. INITIAL-INPUT can be given as the initial minibuffer input.
  2691. INITIAL-DIRECTORY, if non-nil, is used as the root directory for search.
  2692. EXTRA-AG-ARGS, if non-nil, is appended to `counsel-ag-base-command'.
  2693. AG-PROMPT, if non-nil, is passed as `ivy-read' prompt argument.
  2694. CALLER is passed to `ivy-read'.
  2695. With a `\\[universal-argument]' prefix argument, prompt for INITIAL-DIRECTORY.
  2696. With a `\\[universal-argument] \\[universal-argument]' prefix argument, \
  2697. prompt additionally for EXTRA-AG-ARGS."
  2698. (interactive)
  2699. (setq counsel-ag-command counsel-ag-base-command)
  2700. (setq counsel--regex-look-around counsel--grep-tool-look-around)
  2701. (counsel-require-program counsel-ag-command)
  2702. (let ((prog-name (car (if (listp counsel-ag-command) counsel-ag-command
  2703. (split-string counsel-ag-command))))
  2704. (arg (prefix-numeric-value current-prefix-arg)))
  2705. (when (>= arg 4)
  2706. (setq initial-directory
  2707. (or initial-directory
  2708. (counsel-read-directory-name (concat
  2709. prog-name
  2710. " in directory: ")))))
  2711. (when (>= arg 16)
  2712. (setq extra-ag-args
  2713. (or extra-ag-args
  2714. (read-from-minibuffer (format "%s args: " prog-name)))))
  2715. (setq counsel-ag-command (counsel--format-ag-command (or extra-ag-args "") "%s"))
  2716. (let ((default-directory (or initial-directory
  2717. (counsel--git-root)
  2718. default-directory)))
  2719. (ivy-read (or ag-prompt
  2720. (concat prog-name ": "))
  2721. #'counsel-ag-function
  2722. :initial-input initial-input
  2723. :dynamic-collection t
  2724. :keymap counsel-ag-map
  2725. :history 'counsel-git-grep-history
  2726. :action #'counsel-git-grep-action
  2727. :require-match t
  2728. :caller (or caller 'counsel-ag)))))
  2729. (ivy-configure 'counsel-ag
  2730. :occur #'counsel-ag-occur
  2731. :unwind-fn #'counsel--grep-unwind
  2732. :display-transformer-fn #'counsel-git-grep-transformer
  2733. :grep-p t
  2734. :exit-codes '(1 "No matches found"))
  2735. (defun counsel-read-directory-name (prompt &optional default)
  2736. "Read a directory name from user, a (partial) replacement of `read-directory-name'."
  2737. (let ((counsel--find-file-predicate #'file-directory-p))
  2738. (ivy-read prompt
  2739. #'read-file-name-internal
  2740. :matcher #'counsel--find-file-matcher
  2741. :def default
  2742. :history 'file-name-history
  2743. :keymap counsel-find-file-map
  2744. :caller 'counsel-read-directory-name)))
  2745. (ivy-configure 'counsel-read-directory-name
  2746. :parent 'read-file-name-internal)
  2747. (defun counsel-cd ()
  2748. "Change the directory for the currently running Ivy grep-like command.
  2749. Works for `counsel-git-grep', `counsel-ag', etc."
  2750. (interactive)
  2751. (counsel-delete-process)
  2752. (let* ((input ivy-text)
  2753. (enable-recursive-minibuffers t)
  2754. (def-dir (buffer-file-name (ivy-state-buffer ivy-last)))
  2755. (def-dir (and def-dir (file-name-directory def-dir)))
  2756. (new-dir (counsel-read-directory-name "cd: " def-dir)))
  2757. (ivy-quit-and-run
  2758. (funcall (ivy-state-caller ivy-last) input new-dir))))
  2759. (defun counsel--grep-smart-case-flag ()
  2760. (if (ivy--case-fold-p ivy-text)
  2761. "-i"
  2762. (if (and (stringp counsel-ag-base-command)
  2763. (string-match-p "\\`pt" counsel-ag-base-command))
  2764. "-S"
  2765. "-s")))
  2766. (defun counsel-grep-like-occur (cmd-template)
  2767. (unless (eq major-mode 'ivy-occur-grep-mode)
  2768. (ivy-occur-grep-mode)
  2769. (setq default-directory (ivy-state-directory ivy-last)))
  2770. (ivy-set-text
  2771. (if (string-match "\"\\(.*\\)\"" (buffer-name))
  2772. (match-string 1 (buffer-name))
  2773. (ivy-state-text ivy-occur-last)))
  2774. (let* ((cmd
  2775. (if (functionp cmd-template)
  2776. (funcall cmd-template ivy-text)
  2777. (let* ((command-args (counsel--split-command-args ivy-text))
  2778. (regex (counsel--grep-regex (cdr command-args)))
  2779. (extra-switches (counsel--ag-extra-switches regex))
  2780. (all-args (append
  2781. (when (car command-args)
  2782. (split-string (car command-args)))
  2783. (when extra-switches
  2784. (split-string extra-switches))
  2785. (list
  2786. (counsel--grep-smart-case-flag)
  2787. regex))))
  2788. (if (stringp cmd-template)
  2789. (counsel--format
  2790. cmd-template
  2791. (mapconcat #'shell-quote-argument all-args " "))
  2792. (cl-mapcan
  2793. (lambda (x) (if (string= x "%s") (copy-sequence all-args) (list x)))
  2794. cmd-template)))))
  2795. (cands (counsel--split-string
  2796. (if (stringp cmd)
  2797. (shell-command-to-string cmd)
  2798. (counsel--call cmd)))))
  2799. (swiper--occur-insert-lines (mapcar #'counsel--normalize-grep-match cands))))
  2800. (defun counsel-ag-occur (&optional _cands)
  2801. "Generate a custom occur buffer for `counsel-ag'."
  2802. (counsel-grep-like-occur
  2803. counsel-ag-command))
  2804. ;;** `counsel-pt'
  2805. (defcustom counsel-pt-base-command "pt --nocolor --nogroup -e %s"
  2806. "Alternative to `counsel-ag-base-command' using pt."
  2807. :type 'string)
  2808. ;;;###autoload
  2809. (defun counsel-pt (&optional initial-input)
  2810. "Grep for a string in the current directory using pt.
  2811. INITIAL-INPUT can be given as the initial minibuffer input.
  2812. This uses `counsel-ag' with `counsel-pt-base-command' instead of
  2813. `counsel-ag-base-command'."
  2814. (interactive)
  2815. (let ((counsel-ag-base-command counsel-pt-base-command)
  2816. (counsel--grep-tool-look-around nil))
  2817. (counsel-ag initial-input nil nil nil :caller 'counsel-pt)))
  2818. (ivy-configure 'counsel-pt
  2819. :unwind-fn #'counsel--grep-unwind
  2820. :display-transformer-fn #'counsel-git-grep-transformer
  2821. :grep-p t)
  2822. ;;** `counsel-ack'
  2823. (defcustom counsel-ack-base-command
  2824. (concat
  2825. (file-name-nondirectory
  2826. (or (executable-find "ack-grep") "ack"))
  2827. " --nocolor --nogroup %s")
  2828. "Alternative to `counsel-ag-base-command' using ack."
  2829. :type 'string)
  2830. ;;;###autoload
  2831. (defun counsel-ack (&optional initial-input)
  2832. "Grep for a string in the current directory using ack.
  2833. INITIAL-INPUT can be given as the initial minibuffer input.
  2834. This uses `counsel-ag' with `counsel-ack-base-command' replacing
  2835. `counsel-ag-base-command'."
  2836. (interactive)
  2837. (let ((counsel-ag-base-command counsel-ack-base-command)
  2838. (counsel--grep-tool-look-around t))
  2839. (counsel-ag
  2840. initial-input nil nil nil
  2841. :caller 'counsel-ack)))
  2842. ;;** `counsel-rg'
  2843. (defcustom counsel-rg-base-command
  2844. (split-string
  2845. (if (memq system-type '(ms-dos windows-nt))
  2846. "rg -M 240 --with-filename --no-heading --line-number --color never %s --path-separator / ."
  2847. "rg -M 240 --with-filename --no-heading --line-number --color never %s"))
  2848. "Alternative to `counsel-ag-base-command' using ripgrep.
  2849. Note: don't use single quotes for the regex."
  2850. :type '(choice
  2851. (repeat :tag "List to be used in `process-file'." string)
  2852. (string :tag "String to be used in `shell-command-to-string'.")))
  2853. (defun counsel--rg-targets ()
  2854. "Return a list of files to operate on, based on `dired-mode' marks."
  2855. (when (eq major-mode 'dired-mode)
  2856. (let ((files
  2857. (dired-get-marked-files 'no-dir nil nil t)))
  2858. (when (or (cdr files)
  2859. (when (string-match-p "\\*ivy-occur" (buffer-name))
  2860. (dired-toggle-marks)
  2861. (setq files (dired-get-marked-files 'no-dir))
  2862. (dired-toggle-marks)
  2863. t))
  2864. (delq t files)))))
  2865. ;;;###autoload
  2866. (defun counsel-rg (&optional initial-input initial-directory extra-rg-args rg-prompt)
  2867. "Grep for a string in the current directory using rg.
  2868. INITIAL-INPUT can be given as the initial minibuffer input.
  2869. INITIAL-DIRECTORY, if non-nil, is used as the root directory for search.
  2870. EXTRA-RG-ARGS string, if non-nil, is appended to `counsel-rg-base-command'.
  2871. RG-PROMPT, if non-nil, is passed as `ivy-read' prompt argument.
  2872. Example input with inclusion and exclusion file patterns:
  2873. require i -- -g*.el"
  2874. (interactive)
  2875. (let ((counsel-ag-base-command
  2876. (if (listp counsel-rg-base-command)
  2877. (append counsel-rg-base-command (counsel--rg-targets))
  2878. (concat counsel-rg-base-command " "
  2879. (mapconcat #'shell-quote-argument (counsel--rg-targets) " "))))
  2880. (counsel--grep-tool-look-around
  2881. (let ((rg (car (if (listp counsel-rg-base-command) counsel-rg-base-command
  2882. (split-string counsel-rg-base-command))))
  2883. (switch "--pcre2"))
  2884. (and (eq 0 (call-process rg nil nil nil switch "--pcre2-version"))
  2885. switch))))
  2886. (counsel-ag initial-input initial-directory extra-rg-args rg-prompt
  2887. :caller 'counsel-rg)))
  2888. (ivy-configure 'counsel-rg
  2889. :occur #'counsel-ag-occur
  2890. :unwind-fn #'counsel--grep-unwind
  2891. :display-transformer-fn #'counsel-git-grep-transformer
  2892. :grep-p t
  2893. :exit-codes '(1 "No matches found"))
  2894. ;;** `counsel-grep'
  2895. (defvar counsel-grep-map
  2896. (let ((map (make-sparse-keymap)))
  2897. (define-key map (kbd "C-l") 'ivy-call-and-recenter)
  2898. (define-key map (kbd "M-q") 'swiper-query-replace)
  2899. (define-key map (kbd "C-'") 'swiper-avy)
  2900. map))
  2901. (defcustom counsel-grep-base-command "grep -E -n -e %s %s"
  2902. "Format string used by `counsel-grep' to build a shell command.
  2903. It should contain two %-sequences (see function `format') to be
  2904. substituted by the search regexp and file, respectively. Neither
  2905. %-sequence should be contained in single quotes."
  2906. :type 'string)
  2907. (defvar counsel-grep-command nil)
  2908. (defun counsel-grep-function (string)
  2909. "Grep in the current directory for STRING."
  2910. (or
  2911. (ivy-more-chars)
  2912. (let* ((regex (counsel--grep-regex string))
  2913. (cmd (counsel--format
  2914. counsel-grep-command
  2915. (funcall (if (listp counsel-grep-command) #'identity
  2916. #'shell-quote-argument)
  2917. regex))))
  2918. (counsel--async-command
  2919. (if (ivy--case-fold-p regex)
  2920. (if (listp cmd) (nconc (list (car cmd) "-i") (cdr cmd))
  2921. (string-match " " cmd)
  2922. (replace-match " -i " nil nil cmd))
  2923. cmd))
  2924. nil)))
  2925. (defvar counsel--grep-last-pos nil
  2926. "Store the last point and line that `counsel-grep-action' scrolled to.
  2927. This speeds up scrolling: instead of going to `point-min' and
  2928. `forward-line' with a huge arg (e.g. to scroll 50K lines), scroll
  2929. relative to the last position stored here.")
  2930. (defun counsel-grep-action (x)
  2931. "Go to candidate X."
  2932. (with-ivy-window
  2933. (swiper--cleanup)
  2934. (let ((default-directory
  2935. (file-name-directory
  2936. (ivy-state-directory ivy-last)))
  2937. file-name line-number)
  2938. (when (cond ((string-match "\\`\\([0-9]+\\):\\(.*\\)\\'" x)
  2939. (setq file-name (buffer-file-name (ivy-state-buffer ivy-last)))
  2940. (setq line-number (match-string-no-properties 1 x)))
  2941. ((string-match "\\`\\([^:]+\\):\\([0-9]+\\):\\(.*\\)\\'" x)
  2942. (setq file-name (match-string-no-properties 1 x))
  2943. (setq line-number (match-string-no-properties 2 x))))
  2944. ;; If the file buffer is already open, just get it. Prevent doing
  2945. ;; `find-file', as that file could have already been opened using
  2946. ;; `find-file-literally'.
  2947. (with-current-buffer (or (get-file-buffer file-name)
  2948. (find-file file-name))
  2949. (setq line-number (string-to-number line-number))
  2950. (if (and counsel--grep-last-pos (= (point) (car counsel--grep-last-pos)))
  2951. (forward-line (- line-number (cdr counsel--grep-last-pos)))
  2952. (goto-char (point-min))
  2953. (forward-line (1- line-number)))
  2954. (setq counsel--grep-last-pos (cons (point) line-number))
  2955. (when (re-search-forward (ivy--regex ivy-text t) (line-end-position) t)
  2956. (when swiper-goto-start-of-match
  2957. (goto-char (match-beginning 0))))
  2958. (run-hooks 'counsel-grep-post-action-hook)
  2959. (if (eq ivy-exit 'done)
  2960. (swiper--ensure-visible)
  2961. (isearch-range-invisible (line-beginning-position)
  2962. (line-end-position))
  2963. (swiper--add-overlays (ivy--regex ivy-text))))))))
  2964. (defun counsel-grep-occur (&optional _cands)
  2965. "Generate a custom occur buffer for `counsel-grep'."
  2966. (counsel-grep-like-occur
  2967. (format
  2968. "grep -niE %%s %s /dev/null"
  2969. (shell-quote-argument
  2970. (file-name-nondirectory
  2971. (buffer-file-name
  2972. (ivy-state-buffer ivy-last)))))))
  2973. (defvar counsel-grep-history nil
  2974. "History for `counsel-grep'.")
  2975. ;;;###autoload
  2976. (defun counsel-grep (&optional initial-input)
  2977. "Grep for a string in the file visited by the current buffer.
  2978. When non-nil, INITIAL-INPUT is the initial search pattern."
  2979. (interactive)
  2980. (unless buffer-file-name
  2981. (user-error "Current buffer is not visiting a file"))
  2982. (counsel-require-program counsel-grep-base-command)
  2983. (setq counsel-grep-command
  2984. (counsel--format counsel-grep-base-command "%s"
  2985. (funcall (if (listp counsel-grep-base-command) #'identity
  2986. #'shell-quote-argument)
  2987. (file-name-nondirectory
  2988. buffer-file-name))))
  2989. (let ((default-directory (file-name-directory buffer-file-name))
  2990. (init-point (point))
  2991. res)
  2992. (unwind-protect
  2993. (setq res (ivy-read "grep: " #'counsel-grep-function
  2994. :initial-input initial-input
  2995. :dynamic-collection t
  2996. :require-match t
  2997. :preselect
  2998. (when (< (- (line-end-position) (line-beginning-position)) 300)
  2999. (format "%d:%s"
  3000. (line-number-at-pos)
  3001. (regexp-quote
  3002. (buffer-substring-no-properties
  3003. (line-beginning-position)
  3004. (line-end-position)))))
  3005. :keymap counsel-grep-map
  3006. :history 'counsel-grep-history
  3007. :re-builder #'ivy--regex
  3008. :action #'counsel-grep-action
  3009. :caller 'counsel-grep))
  3010. (unless res
  3011. (goto-char init-point)))))
  3012. (ivy-configure 'counsel-grep
  3013. :update-fn 'auto
  3014. :unwind-fn #'counsel--grep-unwind
  3015. :index-fn #'ivy-recompute-index-swiper-async
  3016. :occur #'counsel-grep-occur
  3017. :more-chars 2
  3018. :grep-p t
  3019. :exit-codes '(1 ""))
  3020. ;;;###autoload
  3021. (defun counsel-grep-backward (&optional initial-input)
  3022. "Grep for a string in the file visited by the current buffer going
  3023. backward similar to `swiper-backward'. When non-nil, INITIAL-INPUT is
  3024. the initial search pattern."
  3025. (interactive)
  3026. (let ((ivy-index-functions-alist
  3027. '((counsel-grep . ivy-recompute-index-swiper-async-backward))))
  3028. (counsel-grep initial-input)))
  3029. ;;** `counsel-grep-or-swiper'
  3030. (defcustom counsel-grep-swiper-limit 300000
  3031. "Buffer size threshold for `counsel-grep-or-swiper'.
  3032. When the number of characters in a buffer exceeds this threshold,
  3033. `counsel-grep' will be used instead of `swiper'."
  3034. :type 'integer)
  3035. (defcustom counsel-grep-use-swiper-p #'counsel-grep-use-swiper-p-default
  3036. "When this function returns non-nil, call `swiper', else `counsel-grep'."
  3037. :type '(choice
  3038. (const :tag "Rely on `counsel-grep-swiper-limit'."
  3039. counsel-grep-use-swiper-p-default)
  3040. (const :tag "Always use `counsel-grep'." ignore)
  3041. (function :tag "Custom")))
  3042. (defun counsel-grep-use-swiper-p-default ()
  3043. (<= (buffer-size)
  3044. (/ counsel-grep-swiper-limit
  3045. (if (eq major-mode 'org-mode) 4 1))))
  3046. ;;;###autoload
  3047. (defun counsel-grep-or-swiper (&optional initial-input)
  3048. "Call `swiper' for small buffers and `counsel-grep' for large ones.
  3049. When non-nil, INITIAL-INPUT is the initial search pattern."
  3050. (interactive)
  3051. (if (or (not buffer-file-name)
  3052. (buffer-narrowed-p)
  3053. (ignore-errors
  3054. (file-remote-p buffer-file-name))
  3055. (jka-compr-get-compression-info buffer-file-name)
  3056. (funcall counsel-grep-use-swiper-p))
  3057. (swiper initial-input)
  3058. (when (file-writable-p buffer-file-name)
  3059. (save-buffer))
  3060. (counsel-grep initial-input)))
  3061. ;;** `counsel-grep-or-swiper-backward'
  3062. ;;;###autoload
  3063. (defun counsel-grep-or-swiper-backward (&optional initial-input)
  3064. "Call `swiper-backward' for small buffers and `counsel-grep-backward' for
  3065. large ones. When non-nil, INITIAL-INPUT is the initial search pattern."
  3066. (interactive)
  3067. (let ((ivy-index-functions-alist
  3068. '((swiper . ivy-recompute-index-swiper-backward)
  3069. (counsel-grep . ivy-recompute-index-swiper-async-backward))))
  3070. (counsel-grep-or-swiper initial-input)))
  3071. ;;** `counsel-recoll'
  3072. (defun counsel-recoll-function (str)
  3073. "Run recoll for STR."
  3074. (or
  3075. (ivy-more-chars)
  3076. (progn
  3077. (counsel--async-command
  3078. (format "recoll -t -b %s"
  3079. (shell-quote-argument str)))
  3080. nil)))
  3081. ;; This command uses the recollq command line tool that comes together
  3082. ;; with the recoll (the document indexing database) source:
  3083. ;; https://www.lesbonscomptes.com/recoll/download.html
  3084. ;; You need to build it yourself (together with recoll):
  3085. ;; cd ./query && make && sudo cp recollq /usr/local/bin
  3086. ;; You can try the GUI version of recoll with:
  3087. ;; sudo apt-get install recoll
  3088. ;; Unfortunately, that does not install recollq.
  3089. ;;;###autoload
  3090. (defun counsel-recoll (&optional initial-input)
  3091. "Search for a string in the recoll database.
  3092. You'll be given a list of files that match.
  3093. Selecting a file will launch `swiper' for that file.
  3094. INITIAL-INPUT can be given as the initial minibuffer input."
  3095. (interactive)
  3096. (counsel-require-program "recoll")
  3097. (ivy-read "recoll: " 'counsel-recoll-function
  3098. :initial-input initial-input
  3099. :dynamic-collection t
  3100. :history 'counsel-git-grep-history
  3101. :action (lambda (x)
  3102. (when (string-match "file://\\(.*\\)\\'" x)
  3103. (let ((file-name (match-string 1 x)))
  3104. (find-file file-name)
  3105. (unless (string-match "pdf$" x)
  3106. (swiper ivy-text)))))
  3107. :caller 'counsel-recoll))
  3108. (ivy-configure 'counsel-recoll
  3109. :unwind-fn #'counsel-delete-process)
  3110. ;;* Org
  3111. ;;** `counsel-org-tag'
  3112. (defvar counsel-org-tags nil
  3113. "Store the current list of tags.")
  3114. (defvar org-outline-regexp)
  3115. (defvar org-indent-mode)
  3116. (defvar org-indent-indentation-per-level)
  3117. (defvar org-tags-column)
  3118. (declare-function org-get-tags-string "org")
  3119. (declare-function org-get-tags "org")
  3120. (declare-function org-make-tag-string "org")
  3121. (declare-function org-move-to-column "org-compat")
  3122. (defun counsel--org-make-tag-string ()
  3123. (if (fboundp #'org-make-tag-string)
  3124. ;; >= Org 9.2
  3125. (org-make-tag-string (counsel--org-get-tags))
  3126. (with-no-warnings
  3127. (org-get-tags-string))))
  3128. (defun counsel-org-change-tags (tags)
  3129. "Change tags of current org headline to TAGS."
  3130. (let ((current (counsel--org-make-tag-string))
  3131. (col (current-column))
  3132. level)
  3133. ;; Insert new tags at the correct column
  3134. (beginning-of-line 1)
  3135. (setq level (or (and (looking-at org-outline-regexp)
  3136. (- (match-end 0) (point) 1))
  3137. 1))
  3138. (cond
  3139. ((and (equal current "") (equal tags "")))
  3140. ((re-search-forward
  3141. (concat "\\([ \t]*" (regexp-quote current) "\\)[ \t]*$")
  3142. (line-end-position) t)
  3143. (if (equal tags "")
  3144. (delete-region
  3145. (match-beginning 0)
  3146. (match-end 0))
  3147. (goto-char (match-beginning 0))
  3148. (let* ((c0 (current-column))
  3149. ;; compute offset for the case of org-indent-mode active
  3150. (di (if (bound-and-true-p org-indent-mode)
  3151. (* (1- org-indent-indentation-per-level) (1- level))
  3152. 0))
  3153. (p0 (if (equal (char-before) ?*) (1+ (point)) (point)))
  3154. (tc (+ org-tags-column (if (> org-tags-column 0) (- di) di)))
  3155. (c1 (max (1+ c0) (if (> tc 0) tc (- (- tc) (string-width tags)))))
  3156. (rpl (concat (make-string (max 0 (- c1 c0)) ?\ ) tags)))
  3157. (replace-match rpl t t)
  3158. (and c0 indent-tabs-mode (tabify p0 (point)))
  3159. tags)))
  3160. (t (error "Tags alignment failed")))
  3161. (org-move-to-column col)))
  3162. (defun counsel-org--set-tags ()
  3163. "Set tags of current org headline to `counsel-org-tags'."
  3164. (counsel-org-change-tags
  3165. (if counsel-org-tags
  3166. (format ":%s:"
  3167. (mapconcat #'identity counsel-org-tags ":"))
  3168. "")))
  3169. (defvar org-agenda-bulk-marked-entries)
  3170. (declare-function org-get-at-bol "org")
  3171. (declare-function org-agenda-error "org-agenda")
  3172. (defun counsel-org-tag-action (x)
  3173. "Add tag X to `counsel-org-tags'.
  3174. If X is already part of the list, remove it instead. Quit the selection if
  3175. X is selected by either `ivy-done', `ivy-alt-done' or `ivy-immediate-done',
  3176. otherwise continue prompting for tags."
  3177. (if (member x counsel-org-tags)
  3178. (progn
  3179. (setq counsel-org-tags (delete x counsel-org-tags)))
  3180. (unless (equal x "")
  3181. (setq counsel-org-tags (append counsel-org-tags (list x)))
  3182. (unless (member x ivy--all-candidates)
  3183. (setq ivy--all-candidates (append ivy--all-candidates (list x))))))
  3184. (let ((prompt (counsel-org-tag-prompt)))
  3185. (setf (ivy-state-prompt ivy-last) prompt)
  3186. (setq ivy--prompt (concat "%-4d " prompt)))
  3187. (cond ((memq this-command '(ivy-done
  3188. ivy-alt-done
  3189. ivy-immediate-done))
  3190. (if (eq major-mode 'org-agenda-mode)
  3191. (if (null org-agenda-bulk-marked-entries)
  3192. (let ((hdmarker (or (org-get-at-bol 'org-hd-marker)
  3193. (org-agenda-error))))
  3194. (with-current-buffer (marker-buffer hdmarker)
  3195. (goto-char hdmarker)
  3196. (counsel-org--set-tags)))
  3197. (let ((add-tags (copy-sequence counsel-org-tags)))
  3198. (dolist (m org-agenda-bulk-marked-entries)
  3199. (with-current-buffer (marker-buffer m)
  3200. (save-excursion
  3201. (goto-char m)
  3202. (setq counsel-org-tags
  3203. (delete-dups
  3204. (append (counsel--org-get-tags) add-tags)))
  3205. (counsel-org--set-tags))))))
  3206. (counsel-org--set-tags)
  3207. (unless (member x counsel-org-tags)
  3208. (message "Tag %S has been removed." x))))
  3209. ((eq this-command 'ivy-call)
  3210. (with-selected-window (active-minibuffer-window)
  3211. (delete-minibuffer-contents)))))
  3212. (defun counsel-org-tag-prompt ()
  3213. "Return prompt for `counsel-org-tag'."
  3214. (format "Tags (%s): "
  3215. (mapconcat #'identity counsel-org-tags ", ")))
  3216. (defvar org-setting-tags)
  3217. (defvar org-last-tags-completion-table)
  3218. (defvar org-tag-persistent-alist)
  3219. (defvar org-tag-alist)
  3220. (defvar org-complete-tags-always-offer-all-agenda-tags)
  3221. (declare-function org-at-heading-p "org")
  3222. (declare-function org-back-to-heading "org")
  3223. (declare-function org-get-buffer-tags "org")
  3224. (declare-function org-global-tags-completion-table "org")
  3225. (declare-function org-agenda-files "org")
  3226. (declare-function org-agenda-set-tags "org-agenda")
  3227. (declare-function org-tags-completion-function "org")
  3228. ;;;###autoload
  3229. (defun counsel--org-get-tags ()
  3230. (delete "" (condition-case nil
  3231. (org-get-tags nil t)
  3232. (error (org-get-tags)))))
  3233. ;;;###autoload
  3234. (defun counsel-org-tag ()
  3235. "Add or remove tags in `org-mode'."
  3236. (interactive)
  3237. (save-excursion
  3238. (if (eq major-mode 'org-agenda-mode)
  3239. (if org-agenda-bulk-marked-entries
  3240. (setq counsel-org-tags nil)
  3241. (let ((hdmarker (or (org-get-at-bol 'org-hd-marker)
  3242. (org-agenda-error))))
  3243. (with-current-buffer (marker-buffer hdmarker)
  3244. (goto-char hdmarker)
  3245. (setq counsel-org-tags (counsel--org-get-tags)))))
  3246. (unless (org-at-heading-p)
  3247. (org-back-to-heading t))
  3248. (setq counsel-org-tags (counsel--org-get-tags)))
  3249. (let ((org-last-tags-completion-table
  3250. (append (and (or org-complete-tags-always-offer-all-agenda-tags
  3251. (eq major-mode 'org-agenda-mode))
  3252. (org-global-tags-completion-table
  3253. (org-agenda-files)))
  3254. (unless (boundp 'org-current-tag-alist)
  3255. org-tag-persistent-alist)
  3256. (or (if (boundp 'org-current-tag-alist)
  3257. org-current-tag-alist
  3258. org-tag-alist)
  3259. (org-get-buffer-tags)))))
  3260. (ivy-read (counsel-org-tag-prompt)
  3261. (lambda (str _pred _action)
  3262. (delete-dups
  3263. (all-completions str #'org-tags-completion-function)))
  3264. :history 'org-tags-history
  3265. :action #'counsel-org-tag-action
  3266. :caller 'counsel-org-tag))))
  3267. (defvar org-version)
  3268. ;;;###autoload
  3269. (defun counsel-org-tag-agenda ()
  3270. "Set tags for the current agenda item."
  3271. (interactive)
  3272. (cl-letf (((symbol-function (if (version< org-version "9.2")
  3273. 'org-set-tags
  3274. 'org-set-tags-command))
  3275. #'counsel-org-tag))
  3276. (org-agenda-set-tags)))
  3277. (defcustom counsel-org-headline-display-tags nil
  3278. "If non-nil, display tags in matched `org-mode' headlines."
  3279. :type 'boolean)
  3280. (defcustom counsel-org-headline-display-todo nil
  3281. "If non-nil, display todo keywords in matched `org-mode' headlines."
  3282. :type 'boolean)
  3283. (defcustom counsel-org-headline-display-priority nil
  3284. "If non-nil, display priorities in matched `org-mode' headlines."
  3285. :type 'boolean)
  3286. (defcustom counsel-org-headline-display-comment nil
  3287. "If non-nil, display COMMENT string in matched `org-mode' headlines."
  3288. :type 'boolean)
  3289. (defcustom counsel-org-headline-display-statistics nil
  3290. "If non-nil, display statistics cookie in matched `org-mode' headlines."
  3291. :type 'boolean)
  3292. (declare-function org-get-heading "org")
  3293. (declare-function org-goto-marker-or-bmk "org")
  3294. (declare-function outline-next-heading "outline")
  3295. ;;;###autoload
  3296. (defalias 'counsel-org-goto #'counsel-outline)
  3297. (defcustom counsel-org-goto-all-outline-path-prefix nil
  3298. "Prefix for outline candidates in `counsel-org-goto-all'."
  3299. :type '(choice
  3300. (const :tag "None" nil)
  3301. (const :tag "File name" file-name)
  3302. (const :tag "File name (nondirectory part)" file-name-nondirectory)
  3303. (const :tag "Buffer name" buffer-name)))
  3304. (defun counsel-org-goto-all--outline-path-prefix ()
  3305. (cl-case counsel-org-goto-all-outline-path-prefix
  3306. (file-name buffer-file-name)
  3307. (file-name-nondirectory (file-name-nondirectory buffer-file-name))
  3308. (buffer-name (buffer-name))))
  3309. (defvar counsel-outline-settings
  3310. '((emacs-lisp-mode
  3311. :outline-regexp ";;[;*]+[\s\t]+"
  3312. :outline-level counsel-outline-level-emacs-lisp)
  3313. (org-mode
  3314. :outline-title counsel-outline-title-org
  3315. :action counsel-org-goto-action
  3316. :history counsel-org-goto-history
  3317. :caller counsel-org-goto)
  3318. ;; markdown-mode package
  3319. (markdown-mode
  3320. :outline-title counsel-outline-title-markdown)
  3321. ;; Built-in mode or AUCTeX package
  3322. (latex-mode
  3323. :outline-title counsel-outline-title-latex))
  3324. "Alist mapping major modes to their `counsel-outline' settings.
  3325. Each entry is a pair (MAJOR-MODE . PLIST). `counsel-outline'
  3326. checks whether an entry exists for the current buffer's
  3327. MAJOR-MODE and, if so, loads the settings specified by PLIST
  3328. instead of the default settings. The following settings are
  3329. recognized:
  3330. - `:outline-regexp' is a regexp to match the beginning of an
  3331. outline heading. It is only checked at the start of a line and
  3332. so need not start with \"^\".
  3333. Defaults to the value of the variable `outline-regexp'.
  3334. - `:outline-level' is a function of no arguments which computes
  3335. the level of an outline heading. It is called with point at
  3336. the beginning of `outline-regexp' and with the match data
  3337. corresponding to `outline-regexp'.
  3338. Defaults to the value of the variable `outline-level'.
  3339. - `:outline-title' is a function of no arguments which returns
  3340. the title of an outline heading. It is called with point at
  3341. the end of `outline-regexp' and with the match data
  3342. corresponding to `outline-regexp'.
  3343. Defaults to the function `counsel-outline-title'.
  3344. - `:action' is a function of one argument, the selected outline
  3345. heading to jump to. This setting corresponds directly to its
  3346. eponymous `ivy-read' keyword, as used by `counsel-outline', so
  3347. the type of the function's argument depends on the value
  3348. returned by `counsel-outline-candidates'.
  3349. Defaults to the function `counsel-outline-action'.
  3350. - `:history' is a history list, usually a symbol representing a
  3351. history list variable. It corresponds directly to its
  3352. eponymous `ivy-read' keyword, as used by `counsel-outline'.
  3353. Defaults to the symbol `counsel-outline-history'.
  3354. - `:caller' is a symbol to uniquely identify the caller to
  3355. `ivy-read'. It corresponds directly to its eponymous
  3356. `ivy-read' keyword, as used by `counsel-outline'.
  3357. Defaults to the symbol `counsel-outline'.
  3358. - `:display-style' overrides the variable
  3359. `counsel-outline-display-style'.
  3360. - `:path-separator' overrides the variable
  3361. `counsel-outline-path-separator'.
  3362. - `:face-style' overrides the variable
  3363. `counsel-outline-face-style'.
  3364. - `:custom-faces' overrides the variable
  3365. `counsel-outline-custom-faces'.")
  3366. ;;;###autoload
  3367. (defun counsel-org-goto-all ()
  3368. "Go to a different location in any org file."
  3369. (interactive)
  3370. (let (entries)
  3371. (dolist (b (buffer-list))
  3372. (with-current-buffer b
  3373. (when (derived-mode-p 'org-mode)
  3374. (setq entries
  3375. (nconc entries
  3376. (counsel-outline-candidates
  3377. (cdr (assq 'org-mode counsel-outline-settings))
  3378. (counsel-org-goto-all--outline-path-prefix)))))))
  3379. (ivy-read "Goto: " entries
  3380. :history 'counsel-org-goto-history
  3381. :action #'counsel-org-goto-action
  3382. :caller 'counsel-org-goto-all)))
  3383. (defun counsel-org-goto-action (x)
  3384. "Go to headline in candidate X."
  3385. (org-goto-marker-or-bmk (cdr x)))
  3386. (defun counsel--org-get-heading-args ()
  3387. "Return list of arguments for `org-get-heading'.
  3388. Try to return the right number of arguments for the current Org
  3389. version. Argument values are based on the
  3390. `counsel-org-headline-display-*' user options."
  3391. (nbutlast (mapcar #'not (list counsel-org-headline-display-tags
  3392. counsel-org-headline-display-todo
  3393. counsel-org-headline-display-priority
  3394. counsel-org-headline-display-comment))
  3395. ;; Added in Emacs 26.1.
  3396. (if (if (fboundp 'func-arity)
  3397. (< (cdr (func-arity #'org-get-heading)) 3)
  3398. (version< org-version "9.1.1"))
  3399. 2 0)))
  3400. ;;** `counsel-org-file'
  3401. (declare-function org-attach-dir "org-attach")
  3402. (declare-function org-attach-file-list "org-attach")
  3403. (defvar org-attach-directory)
  3404. (defun counsel-org-files ()
  3405. "Return list of all files under current Org attachment directories.
  3406. Filenames returned are relative to `default-directory'. For each
  3407. attachment directory associated with the current buffer, all
  3408. contained files are listed, so the return value could conceivably
  3409. include attachments of other Org buffers."
  3410. (require 'org-attach)
  3411. (let (dirs)
  3412. (save-excursion
  3413. (goto-char (point-min))
  3414. (while (re-search-forward ":\\(?:ATTACH_DIR\\|ID\\):[\t ]+.*$" nil t)
  3415. (let ((dir (org-attach-dir)))
  3416. (when dir
  3417. (push dir dirs)))))
  3418. (cl-mapcan
  3419. (lambda (dir)
  3420. (mapcar (lambda (file)
  3421. (file-relative-name (expand-file-name file dir)))
  3422. (org-attach-file-list dir)))
  3423. (nreverse dirs))))
  3424. ;;;###autoload
  3425. (defun counsel-org-file ()
  3426. "Browse all attachments for current Org file."
  3427. (interactive)
  3428. (ivy-read "file: " (counsel-org-files)
  3429. :action #'counsel-locate-action-dired
  3430. :caller 'counsel-org-file))
  3431. ;;** `counsel-org-entity'
  3432. (defvar org-entities)
  3433. (defvar org-entities-user)
  3434. ;;;###autoload
  3435. (defun counsel-org-entity ()
  3436. "Complete Org entities using Ivy."
  3437. (interactive)
  3438. (require 'org)
  3439. (ivy-read "Entity: " (cl-loop for element in (append org-entities org-entities-user)
  3440. unless (stringp element)
  3441. collect (cons
  3442. (format "%20s | %20s | %20s | %s"
  3443. (cl-first element) ; name
  3444. (cl-second element) ; latex
  3445. (cl-fourth element) ; html
  3446. (cl-seventh element)) ; utf-8
  3447. element))
  3448. :require-match t
  3449. :action '(1
  3450. ("u" (lambda (candidate)
  3451. (insert (cl-seventh (cdr candidate)))) "utf-8")
  3452. ("o" (lambda (candidate)
  3453. (insert "\\" (cl-first (cdr candidate)))) "org-entity")
  3454. ("l" (lambda (candidate)
  3455. (insert (cl-second (cdr candidate)))) "latex")
  3456. ("h" (lambda (candidate)
  3457. (insert (cl-fourth (cdr candidate)))) "html")
  3458. ("a" (lambda (candidate)
  3459. (insert (cl-fifth (cdr candidate)))) "ascii")
  3460. ("L" (lambda (candidate)
  3461. (insert (cl-sixth (cdr candidate))) "Latin-1")))))
  3462. ;;** `counsel-org-capture'
  3463. (defvar org-capture-templates)
  3464. (defvar org-capture-templates-contexts)
  3465. (declare-function org-contextualize-keys "org")
  3466. (declare-function org-capture-goto-last-stored "org-capture")
  3467. (declare-function org-capture-goto-target "org-capture")
  3468. (declare-function org-capture-upgrade-templates "org-capture")
  3469. ;;;###autoload
  3470. (defun counsel-org-capture ()
  3471. "Capture something."
  3472. (interactive)
  3473. (require 'org-capture)
  3474. (ivy-read "Capture template: "
  3475. ;; We build the list of capture templates as in `org-capture-select-template':
  3476. (let (prefixes)
  3477. (cl-mapcan
  3478. (lambda (x)
  3479. (let ((x-keys (car x)))
  3480. ;; Remove prefixed keys until we get one that matches the current item.
  3481. (while (and prefixes
  3482. (let ((p1-keys (caar prefixes)))
  3483. (or
  3484. (<= (length x-keys) (length p1-keys))
  3485. (not (string-prefix-p p1-keys x-keys)))))
  3486. (pop prefixes))
  3487. (if (> (length x) 2)
  3488. (let ((desc (mapconcat #'cadr (reverse (cons x prefixes)) " | ")))
  3489. (list (format "%-5s %s" x-keys desc)))
  3490. (push x prefixes)
  3491. nil)))
  3492. (or (org-contextualize-keys
  3493. (org-capture-upgrade-templates org-capture-templates)
  3494. org-capture-templates-contexts)
  3495. '(("t" "Task" entry (file+headline "" "Tasks")
  3496. "* TODO %?\n %u\n %a")))))
  3497. :require-match t
  3498. :action (lambda (x)
  3499. (org-capture nil (car (split-string x))))
  3500. :caller 'counsel-org-capture))
  3501. (ivy-configure 'counsel-org-capture
  3502. :initial-input "^")
  3503. (ivy-set-actions
  3504. 'counsel-org-capture
  3505. `(("t" ,(lambda (x)
  3506. (org-capture-goto-target (car (split-string x))))
  3507. "go to target")
  3508. ("l" ,(lambda (_x)
  3509. (org-capture-goto-last-stored))
  3510. "go to last stored")
  3511. ("p" ,(lambda (x)
  3512. (org-capture 0 (car (split-string x))))
  3513. "insert template at point")
  3514. ("c" ,(lambda (_x)
  3515. (customize-variable 'org-capture-templates))
  3516. "customize org-capture-templates")))
  3517. ;;** `counsel-org-agenda-headlines'
  3518. (defvar org-odd-levels-only)
  3519. (declare-function org-set-startup-visibility "org")
  3520. (declare-function org-show-entry "org")
  3521. (declare-function org-map-entries "org")
  3522. (declare-function org-heading-components "org")
  3523. (defun counsel-org-agenda-headlines-action-goto (headline)
  3524. "Go to the `org-mode' agenda HEADLINE."
  3525. (find-file (nth 1 headline))
  3526. (org-set-startup-visibility)
  3527. (goto-char (nth 2 headline))
  3528. (org-show-entry))
  3529. (ivy-set-actions
  3530. 'counsel-org-agenda-headlines
  3531. '(("g" counsel-org-agenda-headlines-action-goto "goto headline")))
  3532. (defvar counsel-org-agenda-headlines-history nil
  3533. "History for `counsel-org-agenda-headlines'.")
  3534. (defcustom counsel-outline-display-style 'path
  3535. "The style used when displaying matched outline headings.
  3536. If `headline', the title is displayed with leading stars
  3537. indicating the outline level.
  3538. If `path', the path hierarchy is displayed. For each entry the
  3539. title is shown. Entries are separated with
  3540. `counsel-outline-path-separator'.
  3541. If `title' or any other value, only the title of the heading is
  3542. displayed.
  3543. For displaying tags and TODO keywords in `org-mode' buffers, see
  3544. `counsel-org-headline-display-tags' and
  3545. `counsel-org-headline-display-todo', respectively."
  3546. :type '(choice
  3547. (const :tag "Title only" title)
  3548. (const :tag "Headline" headline)
  3549. (const :tag "Path" path)))
  3550. (defcustom counsel-outline-path-separator "/"
  3551. "String separating path entries in matched outline headings.
  3552. This variable has no effect unless
  3553. `counsel-outline-display-style' is set to `path'."
  3554. :type 'string)
  3555. (declare-function org-get-outline-path "org")
  3556. (defun counsel-org-agenda-headlines--candidates ()
  3557. "Return a list of completion candidates for `counsel-org-agenda-headlines'."
  3558. (org-map-entries
  3559. (lambda ()
  3560. (let* ((components (org-heading-components))
  3561. (level (and (eq counsel-outline-display-style 'headline)
  3562. (make-string
  3563. (if org-odd-levels-only
  3564. (nth 1 components)
  3565. (nth 0 components))
  3566. ?*)))
  3567. (todo (and counsel-org-headline-display-todo
  3568. (nth 2 components)))
  3569. (path (and (eq counsel-outline-display-style 'path)
  3570. (org-get-outline-path)))
  3571. (priority (and counsel-org-headline-display-priority
  3572. (nth 3 components)))
  3573. (text (nth 4 components))
  3574. (tags (and counsel-org-headline-display-tags
  3575. (nth 5 components))))
  3576. (list
  3577. (mapconcat
  3578. 'identity
  3579. (cl-remove-if 'null
  3580. (list
  3581. level
  3582. todo
  3583. (and priority (format "[#%c]" priority))
  3584. (mapconcat 'identity
  3585. (append path (list text))
  3586. counsel-outline-path-separator)
  3587. tags))
  3588. " ")
  3589. buffer-file-name
  3590. (point))))
  3591. nil
  3592. 'agenda))
  3593. ;;;###autoload
  3594. (defun counsel-org-agenda-headlines ()
  3595. "Choose from headers of `org-mode' files in the agenda."
  3596. (interactive)
  3597. (require 'org)
  3598. (let ((minibuffer-allow-text-properties t))
  3599. (ivy-read "Org headline: "
  3600. (counsel-org-agenda-headlines--candidates)
  3601. :action #'counsel-org-agenda-headlines-action-goto
  3602. :history 'counsel-org-agenda-headlines-history
  3603. :caller 'counsel-org-agenda-headlines)))
  3604. ;;** `counsel-org-link'
  3605. (declare-function org-insert-link "ol")
  3606. (declare-function org-id-get-create "org-id")
  3607. (defun counsel-org-link-action (x)
  3608. "Insert a link to X."
  3609. (let ((id (save-excursion
  3610. (goto-char (cdr x))
  3611. (org-id-get-create))))
  3612. (org-insert-link nil (concat "id:" id) (car x))))
  3613. ;;;###autoload
  3614. (defun counsel-org-link ()
  3615. "Insert a link to an headline with completion."
  3616. (interactive)
  3617. (ivy-read "Link: " (counsel-outline-candidates
  3618. '(:outline-title counsel-outline-title-org ))
  3619. :action #'counsel-org-link-action
  3620. :history 'counsel-org-link-history
  3621. :caller 'counsel-org-link))
  3622. ;; Misc. Emacs
  3623. ;;** `counsel-mark-ring'
  3624. (defface counsel--mark-ring-highlight
  3625. '((t :inherit highlight))
  3626. "Face for current `counsel-mark-ring' line."
  3627. :group 'ivy-faces)
  3628. (defvar counsel--mark-ring-overlay nil
  3629. "Internal overlay to highlight line by candidate of `counsel-mark-ring'.")
  3630. (defun counsel--mark-ring-add-highlight ()
  3631. "Add highlight to current line."
  3632. (setq counsel--mark-ring-overlay
  3633. (make-overlay (line-beginning-position) (1+ (line-end-position))))
  3634. (with-ivy-window
  3635. (overlay-put counsel--mark-ring-overlay 'face
  3636. 'counsel--mark-ring-highlight)))
  3637. (defun counsel--mark-ring-delete-highlight ()
  3638. "If `counsel-mark-ring' have highlight, delete highlight."
  3639. (if counsel--mark-ring-overlay (delete-overlay counsel--mark-ring-overlay)))
  3640. (defvar counsel--mark-ring-calling-point 0
  3641. "Internal variable to remember calling position.")
  3642. (defun counsel--mark-ring-unwind ()
  3643. "Return back to calling position of `counsel-mark-ring'."
  3644. (goto-char counsel--mark-ring-calling-point)
  3645. (counsel--mark-ring-delete-highlight))
  3646. (defun counsel--mark-ring-update-fn ()
  3647. "Show preview by candidate."
  3648. (let ((pos (get-text-property 0 'point (ivy-state-current ivy-last))))
  3649. (counsel--mark-ring-delete-highlight)
  3650. (with-ivy-window
  3651. (goto-char pos)
  3652. (counsel--mark-ring-add-highlight))))
  3653. ;;;###autoload
  3654. (defun counsel-mark-ring ()
  3655. "Browse `mark-ring' interactively.
  3656. Obeys `widen-automatically', which see."
  3657. (interactive)
  3658. (let* ((counsel--mark-ring-calling-point (point))
  3659. (marks (copy-sequence mark-ring))
  3660. (marks (delete-dups marks))
  3661. (marks
  3662. ;; mark-marker is empty?
  3663. (if (equal (mark-marker) (make-marker))
  3664. marks
  3665. (cons (copy-marker (mark-marker)) marks)))
  3666. (candidates (counsel-mark--get-candidates marks)))
  3667. (if candidates
  3668. (counsel-mark--ivy-read "Mark: " candidates 'counsel-mark-ring)
  3669. (message "Mark ring is empty"))))
  3670. (defun counsel-mark--get-candidates (marks)
  3671. "Convert a list of MARKS into mark candidates.
  3672. candidates are simply strings formatted to have the line number of the
  3673. associated mark prepended to them and having an extra text property of
  3674. point to indicarte where the candidate mark is."
  3675. (when marks
  3676. (save-excursion
  3677. (save-restriction
  3678. ;; Widen, both to save `line-number-at-pos' the trouble
  3679. ;; and for `buffer-substring' to work.
  3680. (widen)
  3681. (let* ((width (length (number-to-string (line-number-at-pos (point-max)))))
  3682. (fmt (format "%%%dd %%s" width)))
  3683. (mapcar (lambda (mark)
  3684. (goto-char (marker-position mark))
  3685. (let ((linum (line-number-at-pos))
  3686. (line (buffer-substring
  3687. (line-beginning-position) (line-end-position))))
  3688. (propertize (format fmt linum line) 'point (point))))
  3689. marks))))))
  3690. (defun counsel-mark--ivy-read (prompt candidates caller)
  3691. "call `ivy-read' with sane defaults for traversing marks.
  3692. CANDIDATES should be an alist with the `car' of the list being
  3693. the string displayed by ivy and the `cdr' being the point that
  3694. mark should take you to.
  3695. NOTE This has been abstracted out into it's own method so it can
  3696. be used by both `counsel-mark-ring' and `counsel-evil-marks'"
  3697. (ivy-read prompt candidates
  3698. :require-match t
  3699. :update-fn #'counsel--mark-ring-update-fn
  3700. :action (lambda (cand)
  3701. (let ((pos (get-text-property 0 'point cand)))
  3702. (when pos
  3703. (unless (<= (point-min) pos (point-max))
  3704. (if widen-automatically
  3705. (widen)
  3706. (error "\
  3707. Position of selected mark outside accessible part of buffer")))
  3708. (goto-char pos))))
  3709. :unwind #'counsel--mark-ring-unwind
  3710. :caller caller))
  3711. (ivy-configure 'counsel-mark-ring
  3712. :update-fn #'counsel--mark-ring-update-fn
  3713. :unwind-fn #'counsel--mark-ring-unwind
  3714. :sort-fn #'ivy-string<)
  3715. ;;** `counsel-evil-marks'
  3716. (defvar counsel-evil-marks-exclude-registers nil
  3717. "List of evil registers to not display in `counsel-evil-marks' by default.
  3718. Each member of the list should be a character (stored as an integer).")
  3719. (defvar evil-markers-alist)
  3720. (declare-function evil-global-marker-p "ext:evil-common")
  3721. (defun counsel-mark--get-evil-candidates (all-markers-p)
  3722. "Convert all evil MARKS in the current buffer to mark candidates.
  3723. Works like `counsel-mark--get-candidates' but also prepends the
  3724. register tied to a mark in the message string."
  3725. ;; evil doesn't provide a standalone method to access the list of
  3726. ;; marks in the current buffer, as it does with registers.
  3727. (let* ((all-markers
  3728. (append
  3729. (cl-remove-if (lambda (m)
  3730. (or (evil-global-marker-p (car m))
  3731. (not (markerp (cdr m)))))
  3732. evil-markers-alist)
  3733. (cl-remove-if (lambda (m)
  3734. (or (not (evil-global-marker-p (car m)))
  3735. (not (markerp (cdr m)))))
  3736. (default-value 'evil-markers-alist))))
  3737. (all-markers
  3738. ;; with prefix, ignore register exclusion list.
  3739. (if all-markers-p
  3740. all-markers
  3741. (cl-remove-if-not
  3742. (lambda (x) (not (member (car x) counsel-evil-marks-exclude-registers)))
  3743. all-markers)))
  3744. ;; separate the markers from the evil registers
  3745. ;; for call to `counsel-mark--get-candidates'
  3746. (registers (mapcar #'car all-markers))
  3747. (markers (mapcar #'cdr all-markers))
  3748. (candidates (counsel-mark--get-candidates markers)))
  3749. (when candidates
  3750. (let (register candidate result)
  3751. (while (and (setq register (pop registers))
  3752. (setq candidate (pop candidates)))
  3753. (let ((point (get-text-property 0 'point candidate))
  3754. (evil-candidate
  3755. (format "[%s]: %s"
  3756. (propertize (char-to-string register)
  3757. 'face 'counsel-evil-register-face)
  3758. candidate)))
  3759. (push (propertize evil-candidate 'point point) result)))
  3760. result))))
  3761. ;;;###autoload
  3762. (defun counsel-evil-marks (&optional arg)
  3763. "Ivy replacement for `evil-show-marks'.
  3764. By default, this function respects `counsel-evil-marks-exclude-registers'.
  3765. When ARG is non-nil, display all active evil registers."
  3766. (interactive "P")
  3767. (if (and (boundp 'evil-markers-alist)
  3768. (fboundp 'evil-global-marker-p))
  3769. (let* ((counsel--mark-ring-calling-point (point))
  3770. (candidates (counsel-mark--get-evil-candidates arg)))
  3771. (if candidates
  3772. (counsel-mark--ivy-read "Evil mark: " candidates 'counsel-evil-marks)
  3773. (message "No evil marks are active")))
  3774. (user-error "Required feature `evil' not installed or loaded")))
  3775. ;;** `counsel-package'
  3776. (defvar package--initialized)
  3777. (defvar package-alist)
  3778. (defvar package-archive-contents)
  3779. (defvar package-archives)
  3780. (defvar package-user-dir)
  3781. (declare-function package-installed-p "package")
  3782. (declare-function package-delete "package")
  3783. (declare-function package-desc-extras "package")
  3784. (defvar counsel-package-history nil
  3785. "History for `counsel-package'.")
  3786. (defun counsel--package-candidates ()
  3787. "Return completion alist for `counsel-package'."
  3788. (unless package--initialized
  3789. (package-initialize t))
  3790. (if (or (not package-archive-contents)
  3791. (cl-find-if (lambda (package-archive)
  3792. (let ((fname
  3793. (format
  3794. "%s/archives/%s/archive-contents"
  3795. package-user-dir (car package-archive))))
  3796. (or (not (file-exists-p fname))
  3797. (counsel-file-stale-p fname (* 4 60 60)))))
  3798. package-archives))
  3799. (package-refresh-contents))
  3800. (sort (mapcar (lambda (entry)
  3801. (cons (let ((pkg (car entry)))
  3802. (concat (if (package-installed-p pkg) "-" "+")
  3803. (symbol-name pkg)))
  3804. entry))
  3805. package-archive-contents)
  3806. #'counsel--package-sort))
  3807. ;;;###autoload
  3808. (defun counsel-package ()
  3809. "Install or delete packages.
  3810. Packages not currently installed are prefixed with \"+\", and
  3811. selecting one of these will try to install it.
  3812. Packages currently installed are prefixed with \"-\", and
  3813. selecting one of these will try to delete it.
  3814. Additional actions:\\<ivy-minibuffer-map>
  3815. \\[ivy-dispatching-done] d: Describe package
  3816. \\[ivy-dispatching-done] h: Visit package's homepage"
  3817. (interactive)
  3818. (require 'package)
  3819. (ivy-read "Packages (install +pkg or delete -pkg): "
  3820. (counsel--package-candidates)
  3821. :action #'counsel-package-action
  3822. :require-match t
  3823. :history 'counsel-package-history
  3824. :caller 'counsel-package))
  3825. (ivy-configure 'counsel-package
  3826. :initial-input "^+")
  3827. (defun counsel-package-action (package)
  3828. "Delete or install PACKAGE."
  3829. (setq package (cadr package))
  3830. (if (package-installed-p package)
  3831. (package-delete (cadr (assq package package-alist)))
  3832. (package-install package)))
  3833. (defun counsel-package-action-describe (package)
  3834. "Call `describe-package' on PACKAGE."
  3835. (describe-package (cadr package)))
  3836. (defun counsel-package-action-homepage (package)
  3837. "Open homepage for PACKAGE in a WWW browser."
  3838. (let ((url (cdr (assq :url (package-desc-extras (nth 2 package))))))
  3839. (if url
  3840. (browse-url url)
  3841. (message "No homepage specified for package `%s'" (nth 1 package)))))
  3842. (defun counsel--package-sort (a b)
  3843. "Sort function for `counsel-package' candidates."
  3844. (let* ((a (car a))
  3845. (b (car b))
  3846. (a-inst (= (string-to-char a) ?+))
  3847. (b-inst (= (string-to-char b) ?+)))
  3848. (or (and a-inst (not b-inst))
  3849. (and (eq a-inst b-inst) (string-lessp a b)))))
  3850. (ivy-set-actions
  3851. 'counsel-package
  3852. '(("d" counsel-package-action-describe "describe package")
  3853. ("h" counsel-package-action-homepage "open package homepage")))
  3854. ;;** `counsel-tmm'
  3855. (defvar tmm-km-list nil)
  3856. (declare-function tmm-get-keymap "tmm")
  3857. (declare-function tmm--completion-table "tmm")
  3858. (declare-function tmm-get-keybind "tmm")
  3859. (defun counsel-tmm-prompt (menu)
  3860. "Select and call an item from the MENU keymap."
  3861. (let (out
  3862. choice
  3863. chosen-string)
  3864. (setq tmm-km-list nil)
  3865. (map-keymap (lambda (k v) (tmm-get-keymap (cons k v))) menu)
  3866. (setq tmm-km-list (nreverse tmm-km-list))
  3867. (setq out (ivy-read "Menu bar: " (tmm--completion-table tmm-km-list)
  3868. :require-match t))
  3869. (setq choice (cdr (assoc out tmm-km-list)))
  3870. (setq chosen-string (car choice))
  3871. (setq choice (cdr choice))
  3872. (cond ((keymapp choice)
  3873. (counsel-tmm-prompt choice))
  3874. ((and choice chosen-string)
  3875. (setq last-command-event chosen-string)
  3876. (call-interactively choice)))))
  3877. (defvar tmm-table-undef)
  3878. ;;;###autoload
  3879. (defun counsel-tmm ()
  3880. "Text-mode emulation of looking and choosing from a menu bar."
  3881. (interactive)
  3882. (require 'tmm)
  3883. (run-hooks 'menu-bar-update-hook)
  3884. (setq tmm-table-undef nil)
  3885. (counsel-tmm-prompt (tmm-get-keybind [menu-bar])))
  3886. ;;** `counsel-yank-pop'
  3887. (defcustom counsel-yank-pop-truncate-radius 2
  3888. "Number of context lines around `counsel-yank-pop' candidates."
  3889. :type 'integer)
  3890. (defun counsel--yank-pop-truncate (str)
  3891. "Truncate STR for use in `counsel-yank-pop'."
  3892. (condition-case nil
  3893. (let* ((lines (split-string str "\n" t))
  3894. (n (length lines))
  3895. (re (ivy-re-to-str ivy--old-re))
  3896. (first-match (cl-position-if
  3897. (lambda (s) (string-match re s))
  3898. lines))
  3899. (beg (max 0 (- first-match
  3900. counsel-yank-pop-truncate-radius)))
  3901. (end (min n (+ first-match
  3902. counsel-yank-pop-truncate-radius
  3903. 1)))
  3904. (seq (cl-subseq lines beg end)))
  3905. (if (null first-match)
  3906. (error "Could not match %s" str)
  3907. (when (> beg 0)
  3908. (setcar seq (concat "[...] " (car seq))))
  3909. (when (< end n)
  3910. (setcar (last seq)
  3911. (concat (car (last seq)) " [...]")))
  3912. (mapconcat #'identity seq "\n")))
  3913. (error str)))
  3914. (defcustom counsel-yank-pop-separator "\n"
  3915. "Separator for the kill ring strings in `counsel-yank-pop'."
  3916. :type '(choice
  3917. (const :tag "Plain" "\n")
  3918. (const :tag "Dashes" "\n----\n")
  3919. string))
  3920. (defun counsel--yank-pop-format-function (cand-pairs)
  3921. "Transform CAND-PAIRS into a string for `counsel-yank-pop'."
  3922. (ivy--format-function-generic
  3923. (lambda (str)
  3924. (mapconcat
  3925. (lambda (s)
  3926. (ivy--add-face s 'ivy-current-match))
  3927. (split-string
  3928. (counsel--yank-pop-truncate str) "\n" t)
  3929. "\n"))
  3930. (lambda (str)
  3931. (counsel--yank-pop-truncate str))
  3932. cand-pairs
  3933. (propertize counsel-yank-pop-separator 'face 'ivy-separator)))
  3934. (defun counsel--yank-pop-position (s)
  3935. "Return position of S in `kill-ring' relative to last yank."
  3936. (or (cl-position s kill-ring-yank-pointer :test #'equal-including-properties)
  3937. (cl-position s kill-ring-yank-pointer :test #'equal)
  3938. (+ (or (cl-position s kill-ring :test #'equal-including-properties)
  3939. (cl-position s kill-ring :test #'equal))
  3940. (- (length kill-ring-yank-pointer)
  3941. (length kill-ring)))))
  3942. (defun counsel-string-non-blank-p (s)
  3943. "Return non-nil if S includes non-blank characters.
  3944. Newlines and carriage returns are considered blank."
  3945. (not (string-match-p "\\`[\n\r[:blank:]]*\\'" s)))
  3946. (defcustom counsel-yank-pop-filter #'counsel-string-non-blank-p
  3947. "Unary filter function applied to `counsel-yank-pop' candidates.
  3948. All elements of `kill-ring' for which this function returns nil
  3949. will be destructively removed from `kill-ring' before completion.
  3950. All blank strings are deleted from `kill-ring' by default."
  3951. :type '(radio
  3952. (function-item counsel-string-non-blank-p)
  3953. (function-item identity)
  3954. (function :tag "Other")))
  3955. (defun counsel--yank-pop-kills ()
  3956. "Return filtered `kill-ring' for `counsel-yank-pop' completion.
  3957. Both `kill-ring' and `kill-ring-yank-pointer' may be
  3958. destructively modified to eliminate duplicates under
  3959. `equal-including-properties', satisfy `counsel-yank-pop-filter',
  3960. and incorporate `interprogram-paste-function'."
  3961. ;; Protect against `kill-ring' and result of
  3962. ;; `interprogram-paste-function' both being nil
  3963. (ignore-errors (current-kill 0))
  3964. ;; Keep things consistent with the rest of Emacs
  3965. (dolist (sym '(kill-ring kill-ring-yank-pointer))
  3966. (set sym (cl-delete-duplicates
  3967. (cl-delete-if-not counsel-yank-pop-filter (symbol-value sym))
  3968. :test #'equal-including-properties :from-end t)))
  3969. kill-ring)
  3970. (defcustom counsel-yank-pop-after-point nil
  3971. "Whether `counsel-yank-pop' yanks after point.
  3972. Nil means `counsel-yank-pop' puts point at the end of the yanked
  3973. text and mark at its beginning, as per the default \\[yank].
  3974. Non-nil means `counsel-yank-pop' swaps the resulting point and
  3975. mark, as per \\[universal-argument] \\[yank]."
  3976. :type 'boolean)
  3977. (defun counsel-yank-pop-action (s)
  3978. "Like `yank-pop', but insert the kill corresponding to S.
  3979. Signal a `buffer-read-only' error if called from a read-only
  3980. buffer position."
  3981. (with-ivy-window
  3982. (barf-if-buffer-read-only)
  3983. (setq yank-window-start (window-start))
  3984. (unless (eq last-command 'yank)
  3985. ;; Avoid unexpected deletions with `yank-handler' properties.
  3986. (setq yank-undo-function nil))
  3987. (condition-case nil
  3988. (let (;; Deceive `yank-pop'.
  3989. (last-command 'yank)
  3990. ;; Avoid unexpected additions to `kill-ring'.
  3991. interprogram-paste-function)
  3992. (yank-pop (counsel--yank-pop-position s)))
  3993. (error
  3994. ;; Support strings not present in the kill ring.
  3995. (insert s)))
  3996. (when (funcall (if counsel-yank-pop-after-point #'> #'<)
  3997. (point) (mark t))
  3998. (exchange-point-and-mark t))))
  3999. (defun counsel-yank-pop-action-remove (s)
  4000. "Remove all occurrences of S from the kill ring."
  4001. (dolist (sym '(kill-ring kill-ring-yank-pointer))
  4002. (set sym (cl-delete s (symbol-value sym)
  4003. :test #'equal-including-properties)))
  4004. ;; Update collection and preselect for next `ivy-call'
  4005. (setf (ivy-state-collection ivy-last) kill-ring)
  4006. (setf (ivy-state-preselect ivy-last)
  4007. (nth (min ivy--index (1- (length kill-ring)))
  4008. kill-ring))
  4009. (ivy--reset-state ivy-last))
  4010. (defun counsel-yank-pop-action-rotate (s)
  4011. "Rotate the yanking point to S in the kill ring.
  4012. See `current-kill' for how this interacts with the window system
  4013. selection."
  4014. (let ((i (counsel--yank-pop-position s)))
  4015. ;; Avoid unexpected additions to `kill-ring'
  4016. (let (interprogram-paste-function)
  4017. (setf (ivy-state-preselect ivy-last) (current-kill i)))
  4018. ;; Manually change window system selection because `current-kill' won't
  4019. (when (and (zerop i)
  4020. yank-pop-change-selection
  4021. interprogram-cut-function)
  4022. (funcall interprogram-cut-function (car kill-ring-yank-pointer))))
  4023. (ivy--reset-state ivy-last))
  4024. (defcustom counsel-yank-pop-preselect-last nil
  4025. "Whether `counsel-yank-pop' preselects the last kill by default.
  4026. The command `counsel-yank-pop' always preselects the same kill
  4027. that `yank-pop' would have inserted, given the same prefix
  4028. argument.
  4029. When `counsel-yank-pop-preselect-last' is nil (the default), the
  4030. prefix argument of `counsel-yank-pop' defaults to 1 (as per
  4031. `yank-pop'), which causes the next-to-last kill to be
  4032. preselected. Otherwise, the prefix argument defaults to 0, which
  4033. results in the most recent kill being preselected."
  4034. :type 'boolean)
  4035. ;; Moved to subr.el in Emacs 27.1.
  4036. (autoload 'xor "array")
  4037. ;;;###autoload
  4038. (defun counsel-yank-pop (&optional arg)
  4039. "Ivy replacement for `yank-pop'.
  4040. With a plain prefix argument (\\[universal-argument]),
  4041. temporarily toggle the value of `counsel-yank-pop-after-point'.
  4042. Any other value of ARG has the same meaning as in `yank-pop', but
  4043. `counsel-yank-pop-preselect-last' determines its default value.
  4044. See also `counsel-yank-pop-filter' for how to filter candidates.
  4045. Note: Duplicate elements of `kill-ring' are always deleted."
  4046. ;; Do not specify `*' to allow browsing `kill-ring' in read-only buffers
  4047. (interactive "P")
  4048. (let ((kills (or (counsel--yank-pop-kills)
  4049. (error "Kill ring is empty or blank")))
  4050. (preselect (let (interprogram-paste-function)
  4051. (current-kill (cond ((nlistp arg)
  4052. (prefix-numeric-value arg))
  4053. (counsel-yank-pop-preselect-last 0)
  4054. (t 1))
  4055. t)))
  4056. (counsel-yank-pop-after-point
  4057. (xor (consp arg) counsel-yank-pop-after-point)))
  4058. (unless (eq last-command 'yank)
  4059. (push-mark))
  4060. (ivy-read "kill-ring: " kills
  4061. :require-match t
  4062. :preselect preselect
  4063. :action #'counsel-yank-pop-action
  4064. :caller 'counsel-yank-pop)))
  4065. (ivy-configure 'counsel-yank-pop
  4066. :height 5
  4067. :format-fn #'counsel--yank-pop-format-function)
  4068. (ivy-set-actions
  4069. 'counsel-yank-pop
  4070. '(("d" counsel-yank-pop-action-remove "delete")
  4071. ("r" counsel-yank-pop-action-rotate "rotate")))
  4072. ;;** `counsel-register'
  4073. (defvar counsel-register-actions
  4074. '(("\\`buffer" . jump-to-register)
  4075. ("\\`text" . insert-register)
  4076. ("\\`rectangle" . insert-register)
  4077. ("\\`window" . jump-to-register)
  4078. ("\\`frame" . jump-to-register)
  4079. ("\\`[-+]?[0-9]+\\(?:\\.[0-9]\\)?\\'" . insert-register)
  4080. ("\\`\\(?:the \\)?file " . jump-to-register)
  4081. ("\\`keyboard" . jump-to-register)
  4082. ("\\`file-query" . jump-to-register))
  4083. "Alist of (REGEXP . FUNCTION) pairs for `counsel-register'.
  4084. Selecting a register whose description matches REGEXP specifies
  4085. FUNCTION as the action to take on the register.")
  4086. (defvar counsel-register-history nil
  4087. "History for `counsel-register'.")
  4088. (defun counsel-register-action (register)
  4089. "Default action for `counsel-register'.
  4090. Call a function on REGISTER. The function is determined by
  4091. matching the register's value description against a regexp in
  4092. `counsel-register-actions'."
  4093. (let* ((val (get-text-property 0 'register register))
  4094. (desc (register-describe-oneline val))
  4095. (action (cdr (cl-assoc-if (lambda (re) (string-match-p re desc))
  4096. counsel-register-actions))))
  4097. (if action
  4098. (funcall action val)
  4099. (error "No action was found for register %s"
  4100. (single-key-description val)))))
  4101. ;;;###autoload
  4102. (defun counsel-register ()
  4103. "Interactively choose a register."
  4104. (interactive)
  4105. (ivy-read "Register: "
  4106. (cl-mapcan
  4107. (lambda (reg)
  4108. (let ((s (funcall register-preview-function reg)))
  4109. (setq s (substring s 0 (string-match-p "[ \t\n\r]+\\'" s)))
  4110. (unless (string= s "")
  4111. (put-text-property 0 1 'register (car reg) s)
  4112. (list s))))
  4113. register-alist)
  4114. :require-match t
  4115. :history 'counsel-register-history
  4116. :action #'counsel-register-action
  4117. :caller 'counsel-register))
  4118. (ivy-configure 'counsel-register
  4119. :sort-fn #'ivy-string<)
  4120. ;;** `counsel-evil-registers'
  4121. (defface counsel-evil-register-face
  4122. '((t :inherit counsel-outline-1))
  4123. "Face for highlighting `evil' registers in ivy."
  4124. :group 'ivy-faces)
  4125. ;;;###autoload
  4126. (defun counsel-evil-registers ()
  4127. "Ivy replacement for `evil-show-registers'."
  4128. (interactive)
  4129. (if (fboundp 'evil-register-list)
  4130. (ivy-read "evil-registers: "
  4131. (cl-loop for (key . val) in (evil-register-list)
  4132. collect (format "[%s]: %s"
  4133. (propertize (char-to-string key)
  4134. 'face 'counsel-evil-register-face)
  4135. (if (stringp val) val "")))
  4136. :require-match t
  4137. :action #'counsel-evil-registers-action
  4138. :caller 'counsel-evil-registers)
  4139. (user-error "Required feature `evil' not installed")))
  4140. (ivy-configure 'counsel-evil-registers
  4141. :height 5
  4142. :format-fn #'counsel--yank-pop-format-function)
  4143. (defun counsel-evil-registers-action (s)
  4144. "Paste contents of S, trimming the register part.
  4145. S will be of the form \"[register]: content\"."
  4146. (with-ivy-window
  4147. (insert
  4148. (replace-regexp-in-string "\\`\\[.*?\\]: " "" s))))
  4149. ;;** `counsel-imenu'
  4150. (defvar imenu-auto-rescan)
  4151. (defvar imenu-auto-rescan-maxout)
  4152. (declare-function imenu--subalist-p "imenu")
  4153. (declare-function imenu--make-index-alist "imenu")
  4154. (defun counsel--imenu-candidates ()
  4155. (require 'imenu)
  4156. (let* ((imenu-auto-rescan t)
  4157. (imenu-auto-rescan-maxout (if current-prefix-arg
  4158. (buffer-size)
  4159. imenu-auto-rescan-maxout))
  4160. (items (imenu--make-index-alist t))
  4161. (items (delete (assoc "*Rescan*" items) items))
  4162. (items (if (eq major-mode 'emacs-lisp-mode)
  4163. (counsel-imenu-categorize-functions items)
  4164. items)))
  4165. (counsel-imenu-get-candidates-from items)))
  4166. (defun counsel-imenu-get-candidates-from (alist &optional prefix)
  4167. "Create a list of (key . value) from ALIST.
  4168. PREFIX is used to create the key."
  4169. (cl-mapcan
  4170. (lambda (elm)
  4171. (if (imenu--subalist-p elm)
  4172. (counsel-imenu-get-candidates-from
  4173. (cl-loop for (e . v) in (cdr elm) collect
  4174. (cons e (if (integerp v) (copy-marker v) v)))
  4175. ;; pass the prefix to next recursive call
  4176. (concat prefix (if prefix ".") (car elm)))
  4177. (let ((key (concat
  4178. (when prefix
  4179. (concat
  4180. (propertize prefix 'face 'ivy-grep-info)
  4181. ": "))
  4182. (car elm))))
  4183. (list (cons key
  4184. (cons key (if (overlayp (cdr elm))
  4185. (overlay-start (cdr elm))
  4186. (cdr elm))))))))
  4187. alist))
  4188. (defvar counsel-imenu-map
  4189. (let ((map (make-sparse-keymap)))
  4190. (define-key map (kbd "C-l") 'ivy-call-and-recenter)
  4191. map))
  4192. (defun counsel-imenu-categorize-functions (items)
  4193. "Categorize all the functions of imenu."
  4194. (let ((fns (cl-remove-if #'listp items :key #'cdr)))
  4195. (if fns
  4196. (nconc (cl-remove-if #'nlistp items :key #'cdr)
  4197. `(("Functions" ,@fns)))
  4198. items)))
  4199. (defun counsel-imenu-action (x)
  4200. (with-ivy-window
  4201. (imenu (cdr x))))
  4202. (defvar counsel-imenu-history nil
  4203. "History for `counsel-imenu'.")
  4204. ;;;###autoload
  4205. (defun counsel-imenu ()
  4206. "Jump to a buffer position indexed by imenu."
  4207. (interactive)
  4208. (ivy-read "imenu items: " (counsel--imenu-candidates)
  4209. :preselect (thing-at-point 'symbol)
  4210. :require-match t
  4211. :action #'counsel-imenu-action
  4212. :keymap counsel-imenu-map
  4213. :history 'counsel-imenu-history
  4214. :caller 'counsel-imenu))
  4215. ;;** `counsel-list-processes'
  4216. (defun counsel-list-processes-action-delete (x)
  4217. "Delete process X."
  4218. (delete-process x)
  4219. (setf (ivy-state-collection ivy-last)
  4220. (setq ivy--all-candidates
  4221. (delete x ivy--all-candidates))))
  4222. (defun counsel-list-processes-action-switch (x)
  4223. "Switch to buffer of process X."
  4224. (let* ((proc (get-process x))
  4225. (buf (and proc (process-buffer proc))))
  4226. (if buf
  4227. (switch-to-buffer buf)
  4228. (message "Process %s doesn't have a buffer" x))))
  4229. ;;;###autoload
  4230. (defun counsel-list-processes ()
  4231. "Offer completion for `process-list'.
  4232. The default action deletes the selected process.
  4233. An extra action allows to switch to the process buffer."
  4234. (interactive)
  4235. (with-temp-buffer
  4236. (list-processes--refresh))
  4237. (ivy-read "Process: " (mapcar #'process-name (process-list))
  4238. :require-match t
  4239. :action
  4240. '(1
  4241. ("o" counsel-list-processes-action-delete "kill")
  4242. ("s" counsel-list-processes-action-switch "switch"))
  4243. :caller 'counsel-list-processes))
  4244. ;;** `counsel-ace-link'
  4245. (defun counsel-ace-link ()
  4246. "Use Ivy completion for `ace-link'."
  4247. (interactive)
  4248. (let (collection action)
  4249. (cond ((eq major-mode 'Info-mode)
  4250. (setq collection 'ace-link--info-collect)
  4251. (setq action 'ace-link--info-action))
  4252. ((eq major-mode 'help-mode)
  4253. (setq collection 'ace-link--help-collect)
  4254. (setq action 'ace-link--help-action))
  4255. ((eq major-mode 'woman-mode)
  4256. (setq collection 'ace-link--woman-collect)
  4257. (setq action 'ace-link--woman-action))
  4258. ((eq major-mode 'eww-mode)
  4259. (setq collection 'ace-link--eww-collect)
  4260. (setq action 'ace-link--eww-action))
  4261. ((eq major-mode 'compilation-mode)
  4262. (setq collection 'ace-link--eww-collect)
  4263. (setq action 'ace-link--compilation-action))
  4264. ((eq major-mode 'org-mode)
  4265. (setq collection 'ace-link--org-collect)
  4266. (setq action 'ace-link--org-action)))
  4267. (if (null collection)
  4268. (error "%S is not supported" major-mode)
  4269. (ivy-read "Ace-Link: " (funcall collection)
  4270. :action (lambda (x) (funcall action (cdr x)))
  4271. :require-match t
  4272. :caller 'counsel-ace-link))))
  4273. ;;** `counsel-minibuffer-history'
  4274. ;;;###autoload
  4275. (defun counsel-minibuffer-history ()
  4276. "Browse minibuffer history."
  4277. (interactive)
  4278. (let ((enable-recursive-minibuffers t))
  4279. (ivy-read "History: " (ivy-history-contents minibuffer-history-variable)
  4280. :keymap ivy-reverse-i-search-map
  4281. :action (lambda (x)
  4282. (insert (substring-no-properties (car x))))
  4283. :caller 'counsel-minibuffer-history)))
  4284. ;;** `counsel-esh-history'
  4285. (defvar comint-input-ring-index)
  4286. (defvar eshell-history-index)
  4287. (defvar slime-repl-input-history-position)
  4288. (defvar counsel-esh--index-last nil
  4289. "Index corresponding to last selection with `counsel-esh-history'.")
  4290. (defvar counsel-shell-history--index-last nil
  4291. "Index corresponding to last selection with `counsel-shell-history'.")
  4292. (defun counsel--browse-history-action (pair)
  4293. (let ((snd (cdr pair)))
  4294. (cl-case (ivy-state-caller ivy-last)
  4295. (counsel-esh-history
  4296. (setq eshell-history-index snd
  4297. counsel-esh--index-last snd))
  4298. (counsel-shell-history
  4299. (setq comint-input-ring-index snd
  4300. counsel-shell-history--index-last snd))
  4301. ;; Leave this as a no-op. If someone decides to patch
  4302. ;; `slime-repl-previous-input' or one of its utility functions,
  4303. ;; or to add history-replay to Slime, then this section can be
  4304. ;; updated to add the relevant support for those commands.
  4305. (counsel-slime-repl-history
  4306. nil))
  4307. (ivy-completion-in-region-action (car pair))))
  4308. (cl-defun counsel--browse-history (ring &key caller)
  4309. "Use Ivy to navigate through RING."
  4310. (let* ((proc (get-buffer-process (current-buffer)))
  4311. (end (point))
  4312. (beg (if proc
  4313. (min (process-mark proc) end)
  4314. end))
  4315. (input (when (< beg end)
  4316. (concat "^" (buffer-substring beg end)))))
  4317. (setq ivy-completion-beg beg)
  4318. (setq ivy-completion-end end)
  4319. (ivy-read "History: " (ivy-history-contents ring)
  4320. :keymap ivy-reverse-i-search-map
  4321. :initial-input input
  4322. :action #'counsel--browse-history-action
  4323. :caller caller)))
  4324. (defvar eshell-history-ring)
  4325. (defvar eshell-matching-input-from-input-string)
  4326. ;;;###autoload
  4327. (defun counsel-esh-history ()
  4328. "Browse Eshell history."
  4329. (interactive)
  4330. (require 'em-hist)
  4331. (counsel--browse-history eshell-history-ring
  4332. :caller #'counsel-esh-history))
  4333. (defadvice eshell-previous-matching-input (before
  4334. counsel-set-eshell-history-index
  4335. activate)
  4336. "Reassign `eshell-history-index'."
  4337. (when (and (memq last-command '(ivy-alt-done ivy-done))
  4338. (equal (ivy-state-caller ivy-last) 'counsel-esh-history))
  4339. (setq eshell-history-index counsel-esh--index-last)))
  4340. (defvar comint-input-ring)
  4341. (defvar comint-matching-input-from-input-string)
  4342. ;;;###autoload
  4343. (defun counsel-shell-history ()
  4344. "Browse shell history."
  4345. (interactive)
  4346. (require 'comint)
  4347. (counsel--browse-history comint-input-ring
  4348. :caller #'counsel-shell-history))
  4349. (defadvice comint-previous-matching-input (before
  4350. counsel-set-comint-history-index
  4351. activate)
  4352. "Reassign `comint-input-ring-index'."
  4353. (when (and (memq last-command '(ivy-alt-done ivy-done))
  4354. (equal (ivy-state-caller ivy-last) 'counsel-shell-history))
  4355. (setq comint-input-ring-index counsel-shell-history--index-last)))
  4356. (defvar slime-repl-input-history)
  4357. ;;;###autoload
  4358. (defun counsel-slime-repl-history ()
  4359. "Browse Slime REPL history."
  4360. (interactive)
  4361. (require 'slime-repl)
  4362. (counsel--browse-history slime-repl-input-history
  4363. :caller #'counsel-slime-repl-history))
  4364. ;; TODO: add advice for slime-repl-input-previous/next to properly
  4365. ;; reassign the ring index and match string. This requires a case for
  4366. ;; `counsel-slime-repl-history' within
  4367. ;; `counsel--browse-history-action'.
  4368. ;;** `counsel-hydra-heads'
  4369. (defvar hydra-curr-body-fn)
  4370. (declare-function hydra-keyboard-quit "ext:hydra")
  4371. ;;;###autoload
  4372. (defun counsel-hydra-heads ()
  4373. "Call a head of the current/last hydra."
  4374. (interactive)
  4375. (let* ((base (substring
  4376. (prin1-to-string hydra-curr-body-fn)
  4377. 0 -4))
  4378. (heads (eval (intern (concat base "heads"))))
  4379. (keymap (eval (intern (concat base "keymap"))))
  4380. (head-names
  4381. (mapcar (lambda (x)
  4382. (cons
  4383. (if (nth 2 x)
  4384. (format "[%s] %S (%s)" (nth 0 x) (nth 1 x) (nth 2 x))
  4385. (format "[%s] %S" (nth 0 x) (nth 1 x)))
  4386. (lookup-key keymap (kbd (nth 0 x)))))
  4387. heads)))
  4388. (ivy-read "head: " head-names
  4389. :action (lambda (x) (call-interactively (cdr x))))
  4390. (hydra-keyboard-quit)))
  4391. ;;** `counsel-semantic'
  4392. (declare-function semantic-tag-start "semantic/tag")
  4393. (declare-function semantic-tag-class "semantic/tag")
  4394. (declare-function semantic-tag-name "semantic/tag")
  4395. (declare-function semantic-tag-put-attribute "semantic/tag")
  4396. (declare-function semantic-tag-get-attribute "semantic/tag")
  4397. (declare-function semantic-fetch-tags "semantic")
  4398. (declare-function semantic-format-tag-summarize "semantic/format")
  4399. (declare-function semantic-active-p "semantic/fw")
  4400. (defun counsel-semantic-action (x)
  4401. "Got to semantic TAG."
  4402. (goto-char (semantic-tag-start (cdr x))))
  4403. (defvar counsel-semantic-history nil
  4404. "History for `counsel-semantic'.")
  4405. (defun counsel-semantic-format-tag (tag)
  4406. "Return a pretty string representation of TAG."
  4407. (let ((depth (or (semantic-tag-get-attribute tag :depth) 0))
  4408. (parent (semantic-tag-get-attribute tag :parent)))
  4409. (concat (make-string (* depth 2) ?\ )
  4410. (if parent
  4411. (concat "(" parent ") ")
  4412. "")
  4413. (semantic-format-tag-summarize tag nil t))))
  4414. (defun counsel-flatten-forest (func treep forest)
  4415. "Use FUNC and TREEP to flatten FOREST.
  4416. FUNC is applied to each node.
  4417. TREEP is used to expand internal nodes."
  4418. (cl-labels ((reducer (forest out depth)
  4419. (dolist (tree forest)
  4420. (let ((this (cons (funcall func tree depth) out))
  4421. (leafs (funcall treep tree)))
  4422. (setq out
  4423. (if leafs
  4424. (reducer leafs this (1+ depth))
  4425. this))))
  4426. out))
  4427. (nreverse (reducer forest nil 0))))
  4428. (defun counsel-semantic-tags ()
  4429. "Fetch semantic tags."
  4430. (counsel-flatten-forest
  4431. (lambda (tree depth)
  4432. (semantic-tag-put-attribute tree :depth depth))
  4433. (lambda (tag)
  4434. (when (eq (semantic-tag-class tag) 'type)
  4435. (let ((name (semantic-tag-name tag)))
  4436. (mapcar
  4437. (lambda (x) (semantic-tag-put-attribute x :parent name))
  4438. (semantic-tag-get-attribute tag :members)))))
  4439. (semantic-fetch-tags)))
  4440. ;;;###autoload
  4441. (defun counsel-semantic ()
  4442. "Jump to a semantic tag in the current buffer."
  4443. (interactive)
  4444. (let ((tags (mapcar
  4445. (lambda (x)
  4446. (cons
  4447. (counsel-semantic-format-tag x)
  4448. x))
  4449. (counsel-semantic-tags))))
  4450. (ivy-read "tag: " tags
  4451. :action #'counsel-semantic-action
  4452. :history 'counsel-semantic-history
  4453. :caller 'counsel-semantic)))
  4454. ;;;###autoload
  4455. (defun counsel-semantic-or-imenu ()
  4456. (interactive)
  4457. (require 'semantic/fw)
  4458. (if (semantic-active-p)
  4459. (counsel-semantic)
  4460. (counsel-imenu)))
  4461. ;;** `counsel-outline'
  4462. (declare-function org-trim "org-macs")
  4463. (defcustom counsel-outline-face-style nil
  4464. "Determines how to style outline headings during completion.
  4465. If `org', the faces `counsel-outline-1' through
  4466. `counsel-outline-8' are applied in a similar way to Org.
  4467. Note that no cycling is performed, so headings on levels 9 and
  4468. higher are not styled.
  4469. If `verbatim', the faces used in the buffer are applied. For
  4470. simple headlines in `org-mode' buffers, this is usually the same
  4471. as the `org' setting, except that it depends on how much of the
  4472. buffer has been completely fontified. If your buffer exceeds a
  4473. certain size, headlines are styled lazily depending on which
  4474. parts of the tree are visible. Headlines which are not yet
  4475. styled in the buffer will appear unstyled in the minibuffer as
  4476. well. If your headlines contain parts which are fontified
  4477. differently than the headline itself (e.g. TODO keywords, tags,
  4478. links) and you want these parts to be styled properly, verbatim
  4479. is the way to go; otherwise you are probably better off using the
  4480. `org' setting instead.
  4481. If `custom', the faces defined in `counsel-outline-custom-faces'
  4482. are applied. Note that no cycling is performed, so if there is
  4483. no face defined for a certain level, headlines on that level will
  4484. not be styled.
  4485. If `nil', all headlines are highlighted using
  4486. `counsel-outline-default'.
  4487. For displaying tags and TODO keywords in `org-mode' buffers, see
  4488. `counsel-org-headline-display-tags' and
  4489. `counsel-org-headline-display-todo', respectively."
  4490. :type '(choice
  4491. (const :tag "Same as org-mode" org)
  4492. (const :tag "Verbatim" verbatim)
  4493. (const :tag "Custom" custom)
  4494. (const :tag "No style" nil)))
  4495. (defcustom counsel-outline-custom-faces nil
  4496. "List of faces for custom display of outline headings.
  4497. Headlines on level N are fontified with the Nth entry of this
  4498. list, starting with N = 1. Headline levels with no corresponding
  4499. entry in this list will not be styled.
  4500. This variable has no effect unless `counsel-outline-face-style'
  4501. is set to `custom'."
  4502. :type '(repeat face))
  4503. (defun counsel-outline-title ()
  4504. "Return title of current outline heading.
  4505. Intended as a value for the `:outline-title' setting in
  4506. `counsel-outline-settings', which see."
  4507. (buffer-substring (point) (line-end-position)))
  4508. (defun counsel-outline-title-org ()
  4509. "Return title of current outline heading.
  4510. Like `counsel-outline-title' (which see), but for `org-mode'
  4511. buffers."
  4512. (let ((statistics-re "\\[[0-9]*\\(?:%\\|/[0-9]*\\)]")
  4513. (heading (apply #'org-get-heading (counsel--org-get-heading-args))))
  4514. (cond (counsel-org-headline-display-statistics
  4515. heading)
  4516. (heading
  4517. (org-trim (replace-regexp-in-string statistics-re " " heading))))))
  4518. (defun counsel-outline-title-markdown ()
  4519. "Return title of current outline heading.
  4520. Like `counsel-outline-title' (which see), but for
  4521. `markdown-mode' (from the eponymous package) buffers."
  4522. ;; `outline-regexp' is set by `markdown-mode' to match both setext
  4523. ;; (underline) and atx (hash) headings (see
  4524. ;; `markdown-regex-header').
  4525. (or (match-string 1) ; setext heading title
  4526. (match-string 5))) ; atx heading title
  4527. (defun counsel-outline-title-latex ()
  4528. "Return title of current outline heading.
  4529. Like `counsel-outline-title' (which see), but for `latex-mode'
  4530. buffers."
  4531. ;; `outline-regexp' is set by `latex-mode' (see variable
  4532. ;; `latex-section-alist' for the built-in mode or function
  4533. ;; `LaTeX-outline-regexp' for the AUCTeX package) to match section
  4534. ;; macros, in which case we get the section name, as well as
  4535. ;; `\appendix', `\documentclass', `\begin{document}', and
  4536. ;; `\end{document}', in which case we simply return that.
  4537. (if (and (assoc (match-string 1) ; Macro name
  4538. (or (bound-and-true-p LaTeX-section-list) ; AUCTeX
  4539. (bound-and-true-p latex-section-alist))) ; Built-in
  4540. (progn
  4541. ;; Point is at end of macro name, skip stars and optional args
  4542. (skip-chars-forward "*")
  4543. (while (looking-at-p "\\[")
  4544. (forward-list))
  4545. ;; First mandatory arg should be section title
  4546. (looking-at-p "{")))
  4547. (buffer-substring (1+ (point)) (1- (progn (forward-list) (point))))
  4548. (buffer-substring (line-beginning-position) (point))))
  4549. (defun counsel-outline-level-emacs-lisp ()
  4550. "Return level of current outline heading.
  4551. Like `lisp-outline-level', but adapted for the `:outline-level'
  4552. setting in `counsel-outline-settings', which see."
  4553. (if (looking-at ";;\\([;*]+\\)")
  4554. (- (match-end 1) (match-beginning 1))
  4555. (funcall outline-level)))
  4556. (defvar counsel-outline--preselect 0
  4557. "Index of the preselected candidate in `counsel-outline'.")
  4558. (defun counsel-outline-candidates (&optional settings prefix)
  4559. "Return an alist of outline heading completion candidates.
  4560. Each element is a pair (HEADING . MARKER), where the string
  4561. HEADING is located at the position of MARKER. SETTINGS is a
  4562. plist entry from `counsel-outline-settings', which see.
  4563. PREFIX is a string prepended to all candidates."
  4564. (let* ((bol-regex (concat "^\\(?:"
  4565. (or (plist-get settings :outline-regexp)
  4566. outline-regexp)
  4567. "\\)"))
  4568. (outline-title-fn (or (plist-get settings :outline-title)
  4569. #'counsel-outline-title))
  4570. (outline-level-fn (or (plist-get settings :outline-level)
  4571. outline-level))
  4572. (display-style (or (plist-get settings :display-style)
  4573. counsel-outline-display-style))
  4574. (path-separator (or (plist-get settings :path-separator)
  4575. counsel-outline-path-separator))
  4576. (face-style (or (plist-get settings :face-style)
  4577. counsel-outline-face-style))
  4578. (custom-faces (or (plist-get settings :custom-faces)
  4579. counsel-outline-custom-faces))
  4580. (stack-level 0)
  4581. (orig-point (point))
  4582. (stack (and prefix (list (counsel-outline--add-face
  4583. prefix 0 face-style custom-faces))))
  4584. cands name level marker)
  4585. (save-excursion
  4586. (setq counsel-outline--preselect 0)
  4587. (goto-char (point-min))
  4588. (while (re-search-forward bol-regex nil t)
  4589. (save-excursion
  4590. (setq name (or (save-match-data
  4591. (funcall outline-title-fn))
  4592. ""))
  4593. (goto-char (match-beginning 0))
  4594. (setq marker (point-marker))
  4595. (setq level (funcall outline-level-fn))
  4596. (cond ((eq display-style 'path)
  4597. ;; Update stack. The empty entry guards against incorrect
  4598. ;; headline hierarchies, e.g. a level 3 headline
  4599. ;; immediately following a level 1 entry.
  4600. (while (<= level stack-level)
  4601. (pop stack)
  4602. (cl-decf stack-level))
  4603. (while (> level stack-level)
  4604. (push "" stack)
  4605. (cl-incf stack-level))
  4606. (setf (car stack)
  4607. (counsel-outline--add-face
  4608. name level face-style custom-faces))
  4609. (setq name (mapconcat #'identity
  4610. (reverse stack)
  4611. path-separator)))
  4612. (t
  4613. (when (eq display-style 'headline)
  4614. (setq name (concat (make-string level ?*) " " name)))
  4615. (setq name (counsel-outline--add-face
  4616. name level face-style custom-faces))))
  4617. (push (cons name marker) cands))
  4618. (unless (or (string= name "")
  4619. (< orig-point marker))
  4620. (cl-incf counsel-outline--preselect))))
  4621. (nreverse cands)))
  4622. (defun counsel-outline--add-face (name level &optional face-style custom-faces)
  4623. "Set the `face' property on headline NAME according to LEVEL.
  4624. FACE-STYLE and CUSTOM-FACES override `counsel-outline-face-style'
  4625. and `counsel-outline-custom-faces', respectively, which determine
  4626. the face to apply."
  4627. (let ((face (cl-case (or face-style counsel-outline-face-style)
  4628. (verbatim)
  4629. (custom (nth (1- level)
  4630. (or custom-faces counsel-outline-custom-faces)))
  4631. (org (format "counsel-outline-%d" level))
  4632. (t 'counsel-outline-default))))
  4633. (when face
  4634. (put-text-property 0 (length name) 'face face name)))
  4635. name)
  4636. (defun counsel-outline-action (x)
  4637. "Go to outline X."
  4638. (goto-char (cdr x)))
  4639. ;;;###autoload
  4640. (defun counsel-outline ()
  4641. "Jump to an outline heading with completion."
  4642. (interactive)
  4643. (let ((settings (cdr (assq major-mode counsel-outline-settings))))
  4644. (ivy-read "Outline: " (counsel-outline-candidates settings)
  4645. :action (or (plist-get settings :action)
  4646. #'counsel-outline-action)
  4647. :history (or (plist-get settings :history)
  4648. 'counsel-outline-history)
  4649. :preselect (max (1- counsel-outline--preselect) 0)
  4650. :caller (or (plist-get settings :caller)
  4651. 'counsel-outline))))
  4652. ;;** `counsel-ibuffer'
  4653. (defvar counsel-ibuffer--buffer-name nil
  4654. "Name of the buffer to use for `counsel-ibuffer'.")
  4655. ;;;###autoload
  4656. (defun counsel-ibuffer (&optional name)
  4657. "Use ibuffer to switch to another buffer.
  4658. NAME specifies the name of the buffer (defaults to \"*Ibuffer*\")."
  4659. (interactive)
  4660. (setq counsel-ibuffer--buffer-name (or name "*Ibuffer*"))
  4661. (ivy-read "Switch to buffer: " (counsel-ibuffer--get-buffers)
  4662. :history 'counsel-ibuffer-history
  4663. :action #'counsel-ibuffer-visit-buffer
  4664. :caller 'counsel-ibuffer))
  4665. (declare-function ibuffer-update "ibuffer")
  4666. (declare-function ibuffer-current-buffer "ibuffer")
  4667. (declare-function ibuffer-forward-line "ibuffer")
  4668. (defvar ibuffer-movement-cycle)
  4669. (defun counsel-ibuffer--get-buffers ()
  4670. "Return list of buffer-related lines in Ibuffer as strings."
  4671. (let ((oldbuf (get-buffer counsel-ibuffer--buffer-name)))
  4672. (unless oldbuf
  4673. ;; Avoid messing with the user's precious window/frame configuration.
  4674. (save-window-excursion
  4675. (let ((display-buffer-overriding-action
  4676. '(display-buffer-same-window (inhibit-same-window . nil))))
  4677. (ibuffer nil counsel-ibuffer--buffer-name nil t))))
  4678. (with-current-buffer counsel-ibuffer--buffer-name
  4679. (when oldbuf
  4680. ;; Forcibly update possibly stale existing buffer.
  4681. (ibuffer-update nil t))
  4682. (goto-char (point-min))
  4683. (let ((ibuffer-movement-cycle nil)
  4684. entries)
  4685. (while (not (eobp))
  4686. (ibuffer-forward-line 1 t)
  4687. (let ((buf (ibuffer-current-buffer)))
  4688. ;; We are only interested in buffers we can actually visit.
  4689. ;; This filters out headings and other unusable entries.
  4690. (when (buffer-live-p buf)
  4691. (push (cons (buffer-substring-no-properties
  4692. (line-beginning-position)
  4693. (line-end-position))
  4694. buf)
  4695. entries))))
  4696. (nreverse entries)))))
  4697. (defun counsel-ibuffer-visit-buffer (x)
  4698. "Switch to buffer of candidate X."
  4699. (switch-to-buffer (cdr x)))
  4700. (defun counsel-ibuffer-visit-buffer-other-window (x)
  4701. "Switch to buffer of candidate X in another window."
  4702. (switch-to-buffer-other-window (cdr x)))
  4703. (defun counsel-ibuffer-visit-ibuffer (_)
  4704. "Switch to Ibuffer buffer."
  4705. (switch-to-buffer counsel-ibuffer--buffer-name))
  4706. (ivy-set-actions
  4707. 'counsel-ibuffer
  4708. '(("j" counsel-ibuffer-visit-buffer-other-window "other window")
  4709. ("v" counsel-ibuffer-visit-ibuffer "switch to Ibuffer")))
  4710. ;;** `counsel-switch-to-shell-buffer'
  4711. (defun counsel--buffers-with-mode (mode)
  4712. "Return names of buffers with MODE as their `major-mode'."
  4713. (let (bufs)
  4714. (dolist (buf (buffer-list))
  4715. (when (eq (buffer-local-value 'major-mode buf) mode)
  4716. (push (buffer-name buf) bufs)))
  4717. (nreverse bufs)))
  4718. (declare-function shell-mode "shell")
  4719. ;;;###autoload
  4720. (defun counsel-switch-to-shell-buffer ()
  4721. "Switch to a shell buffer, or create one."
  4722. (interactive)
  4723. (ivy-read "Shell buffer: " (counsel--buffers-with-mode #'shell-mode)
  4724. :action #'counsel--switch-to-shell
  4725. :caller 'counsel-switch-to-shell-buffer))
  4726. (defun counsel--switch-to-shell (name)
  4727. "Display shell buffer with NAME and select its window.
  4728. Reuse any existing window already displaying the named buffer.
  4729. If there is no such buffer, start a new `shell' with NAME."
  4730. (if (get-buffer name)
  4731. (pop-to-buffer name '((display-buffer-reuse-window
  4732. display-buffer-same-window)
  4733. (inhibit-same-window . nil)
  4734. (reusable-frames . visible)))
  4735. (shell name)))
  4736. ;;** `counsel-unicode-char'
  4737. (defvar counsel-unicode-char-history nil
  4738. "History for `counsel-unicode-char'.")
  4739. (defun counsel--unicode-names ()
  4740. "Return formatted and sorted list of `ucs-names'.
  4741. The result of `ucs-names' is mostly, but not completely, sorted,
  4742. so this function ensures lexicographic order."
  4743. (let* (cands
  4744. (table (ucs-names)) ; Either hash map or alist
  4745. (fmt (lambda (name code) ; Common format function
  4746. (let ((cand (format "%06X %-58s %c" code name code)))
  4747. (put-text-property 0 1 'code code cand)
  4748. (push cand cands)))))
  4749. (if (not (hash-table-p table))
  4750. ;; Support `ucs-names' returning an alist in Emacs < 26.
  4751. ;; The result of `ucs-names' comes pre-reversed so no need to repeat.
  4752. (dolist (entry table)
  4753. (funcall fmt (car entry) (cdr entry)))
  4754. (maphash fmt table)
  4755. ;; Reverse to speed up sorting
  4756. (setq cands (nreverse cands)))
  4757. (sort cands #'string-lessp)))
  4758. (defvar counsel--unicode-table
  4759. (lazy-completion-table counsel--unicode-table counsel--unicode-names)
  4760. "Lazy completion table for `counsel-unicode-char'.
  4761. Candidates comprise `counsel--unicode-names', which see.")
  4762. ;;;###autoload
  4763. (defun counsel-unicode-char (&optional count)
  4764. "Insert COUNT copies of a Unicode character at point.
  4765. COUNT defaults to 1."
  4766. (interactive "p")
  4767. (setq ivy-completion-beg (point))
  4768. (setq ivy-completion-end (point))
  4769. (ivy-read "Unicode name: " counsel--unicode-table
  4770. :history 'counsel-unicode-char-history
  4771. :action (lambda (name)
  4772. (with-ivy-window
  4773. (delete-region ivy-completion-beg ivy-completion-end)
  4774. (setq ivy-completion-beg (point))
  4775. (insert-char (get-text-property 0 'code name) count)
  4776. (setq ivy-completion-end (point))))
  4777. :caller 'counsel-unicode-char))
  4778. (ivy-configure 'counsel-unicode-char
  4779. :sort-fn #'ivy-string<)
  4780. (defun counsel-unicode-copy (name)
  4781. "Ivy action to copy the unicode from NAME to the kill ring."
  4782. (kill-new (char-to-string (get-text-property 0 'code name))))
  4783. (ivy-set-actions
  4784. 'counsel-unicode-char
  4785. '(("w" counsel-unicode-copy "copy")))
  4786. ;;** `counsel-colors'
  4787. (defun counsel-colors-action-insert-hex (color)
  4788. "Insert the hexadecimal RGB value of COLOR."
  4789. (insert (get-text-property 0 'hex color)))
  4790. (defun counsel-colors-action-kill-hex (color)
  4791. "Kill the hexadecimal RGB value of COLOR."
  4792. (kill-new (get-text-property 0 'hex color)))
  4793. ;;** `counsel-colors-emacs'
  4794. (defvar counsel-colors-emacs-history ()
  4795. "History for `counsel-colors-emacs'.")
  4796. (defun counsel-colors--name-to-hex (name)
  4797. "Return hexadecimal RGB value of color with NAME.
  4798. Return nil if NAME does not designate a valid color."
  4799. (let ((rgb (color-name-to-rgb name)))
  4800. (when rgb
  4801. (apply #'color-rgb-to-hex rgb))))
  4802. (defvar shr-color-visible-luminance-min)
  4803. (declare-function shr-color-visible "shr-color")
  4804. (defvar counsel--colors-format "%-20s %s %s%s")
  4805. (defun counsel--colors-emacs-format-function (colors)
  4806. "Format function for `counsel-colors-emacs'."
  4807. (require 'shr-color)
  4808. (let* ((blank (make-string 10 ?\s))
  4809. (formatter
  4810. (lambda (color)
  4811. (let ((fg (list :foreground color)))
  4812. (format counsel--colors-format color
  4813. (propertize (get-text-property 0 'hex color) 'face fg)
  4814. (propertize blank 'face (list :background color))
  4815. (propertize (mapconcat (lambda (dup)
  4816. (concat " " dup))
  4817. (get-text-property 0 'dups color)
  4818. ",")
  4819. 'face fg))))))
  4820. (ivy--format-function-generic
  4821. (lambda (color)
  4822. (let* ((hex (get-text-property 0 'hex color))
  4823. (shr-color-visible-luminance-min 100)
  4824. (fg (cadr (shr-color-visible hex "black" t))))
  4825. (propertize (funcall formatter color)
  4826. 'face (list :foreground fg :background hex))))
  4827. formatter colors "\n")))
  4828. (defun counsel--colors-web-format-function (colors)
  4829. "Format function for `counsel-colors-web'."
  4830. (require 'shr-color)
  4831. (let* ((blank (make-string 10 ?\s))
  4832. (formatter (lambda (color)
  4833. (let ((hex (get-text-property 0 'hex color)))
  4834. (format counsel--colors-format color
  4835. (propertize hex 'face (list :foreground hex))
  4836. (propertize blank 'face (list :background hex)))))))
  4837. (ivy--format-function-generic
  4838. (lambda (color)
  4839. (let* ((hex (get-text-property 0 'hex color))
  4840. (shr-color-visible-luminance-min 100)
  4841. (fg (cadr (shr-color-visible hex "black" t))))
  4842. (propertize (funcall formatter color)
  4843. 'face (list :foreground fg :background hex))))
  4844. formatter colors "\n")))
  4845. ;;;###autoload
  4846. (defun counsel-colors-emacs ()
  4847. "Show a list of all supported colors for a particular frame.
  4848. You can insert or kill the name or hexadecimal RGB value of the
  4849. selected color."
  4850. (interactive)
  4851. (let* ((colors
  4852. (delete nil
  4853. (mapcar (lambda (cell)
  4854. (let* ((name (car cell))
  4855. (dups (cdr cell))
  4856. (hex (counsel-colors--name-to-hex name)))
  4857. (when hex
  4858. (propertize name 'hex hex 'dups dups))))
  4859. (list-colors-duplicates))))
  4860. (counsel--colors-format
  4861. (format "%%-%ds %%s %%s%%s"
  4862. (apply #'max 0 (mapcar #'string-width colors)))))
  4863. (ivy-read "Emacs color: " colors
  4864. :require-match t
  4865. :history 'counsel-colors-emacs-history
  4866. :action #'insert
  4867. :caller 'counsel-colors-emacs)))
  4868. (ivy-configure 'counsel-colors-emacs
  4869. :format-fn #'counsel--colors-emacs-format-function)
  4870. (ivy-set-actions
  4871. 'counsel-colors-emacs
  4872. '(("h" counsel-colors-action-insert-hex "insert hexadecimal value")
  4873. ("H" counsel-colors-action-kill-hex "kill hexadecimal value")))
  4874. ;;** `counsel-colors-web'
  4875. (defvar shr-color-html-colors-alist)
  4876. (defun counsel-colors--web-alist ()
  4877. "Return list of CSS colors for `counsel-colors-web'."
  4878. (require 'shr-color)
  4879. (let* ((alist (copy-alist shr-color-html-colors-alist))
  4880. (mp (assoc "MediumPurple" alist))
  4881. (pvr (assoc "PaleVioletRed" alist))
  4882. (rp (assoc "RebeccaPurple" alist)))
  4883. ;; Backport GNU Emacs bug#30377
  4884. (when mp (setcdr mp "#9370db"))
  4885. (when pvr (setcdr pvr "#db7093"))
  4886. (unless rp (push (cons "rebeccapurple" "#663399") alist))
  4887. (sort (mapcar (lambda (cell)
  4888. (propertize (downcase (car cell))
  4889. 'hex (downcase (cdr cell))))
  4890. alist)
  4891. #'string-lessp)))
  4892. (defvar counsel-colors-web-history ()
  4893. "History for `counsel-colors-web'.")
  4894. ;;;###autoload
  4895. (defun counsel-colors-web ()
  4896. "Show a list of all W3C web colors for use in CSS.
  4897. You can insert or kill the name or hexadecimal RGB value of the
  4898. selected color."
  4899. (interactive)
  4900. (let* ((colors (counsel-colors--web-alist))
  4901. (counsel--colors-format
  4902. (format "%%-%ds %%s %%s"
  4903. (apply #'max 0 (mapcar #'string-width colors)))))
  4904. (ivy-read "Web color: " colors
  4905. :require-match t
  4906. :history 'counsel-colors-web-history
  4907. :action #'insert
  4908. :caller 'counsel-colors-web)))
  4909. (ivy-configure 'counsel-colors-web
  4910. :sort-fn #'ivy-string<
  4911. :format-fn #'counsel--colors-web-format-function)
  4912. (ivy-set-actions
  4913. 'counsel-colors-web
  4914. '(("h" counsel-colors-action-insert-hex "insert hexadecimal value")
  4915. ("H" counsel-colors-action-kill-hex "kill hexadecimal value")))
  4916. ;;** `counsel-fonts'
  4917. (defvar counsel-fonts-history ()
  4918. "History for `counsel-fonts'.")
  4919. ;;;###autoload
  4920. (defun counsel-fonts ()
  4921. "Show a list of all supported font families for a particular frame.
  4922. You can insert or kill the name of the selected font."
  4923. (interactive)
  4924. (let ((current-font
  4925. (symbol-name (font-get (face-attribute 'default :font) :family))))
  4926. (ivy-read "Font: " (delete-dups (font-family-list))
  4927. :preselect current-font
  4928. :require-match t
  4929. :history 'counsel-fonts-history
  4930. :action #'insert
  4931. :caller 'counsel-fonts)))
  4932. (ivy-configure 'counsel-fonts
  4933. :display-transformer-fn #'counsel--font-with-sample)
  4934. (defun counsel--font-with-sample (font-name)
  4935. "Format function for `counsel-fonts'."
  4936. (format "%-75s%s" font-name
  4937. (propertize "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  4938. 'face (list :family font-name))))
  4939. ;;** `counsel-kmacro'
  4940. (defvar counsel-kmacro-map
  4941. (let ((map (make-sparse-keymap)))
  4942. (define-key map (kbd "C-k") #'counsel-kmacro-kill)
  4943. map))
  4944. (defun counsel-kmacro-kill ()
  4945. "Kill the line, or delete the keyboard macro."
  4946. (interactive)
  4947. (if (not (eolp))
  4948. (ivy-kill-line)
  4949. (counsel-kmacro-action-delete-kmacro
  4950. (assoc
  4951. (ivy-state-current ivy-last)
  4952. (ivy-state-collection ivy-last)))
  4953. (ivy--kill-current-candidate)))
  4954. ;;;###autoload
  4955. (defun counsel-kmacro ()
  4956. "Interactively choose and run a keyboard macro.
  4957. With prefix argument, run macro that many times.
  4958. Macros are run using the current value of `kmacro-counter-value'
  4959. and their respective counter format. Displayed next to each macro is
  4960. the counter's format and initial value.
  4961. One can use actions to copy the counter format or initial counter
  4962. value of a macro, using them for a new macro."
  4963. (interactive)
  4964. (if (or last-kbd-macro kmacro-ring)
  4965. (ivy-read
  4966. (concat "Execute macro (counter at "
  4967. (number-to-string (or kmacro-initial-counter-value kmacro-counter))
  4968. "): ")
  4969. (counsel--kmacro-candidates)
  4970. :keymap counsel-kmacro-map
  4971. :require-match t
  4972. :action #'counsel-kmacro-action-run
  4973. :caller 'counsel-kmacro)
  4974. (user-error "No keyboard macros defined")))
  4975. (ivy-configure 'counsel-kmacro
  4976. :format-fn #'counsel--kmacro-format-function)
  4977. (defcustom counsel-kmacro-separator "\n------------------------\n"
  4978. "Separator displayed between keyboard macros in `counsel-kmacro'."
  4979. :type 'string)
  4980. (defun counsel--kmacro-format-function (formatted-kmacro)
  4981. "Transform FORMATTED-KMACRO into a string for `counsel-kmacro'."
  4982. (ivy--format-function-generic
  4983. (lambda (str) (ivy--add-face str 'ivy-current-match))
  4984. (lambda (str) str)
  4985. formatted-kmacro
  4986. (propertize counsel-kmacro-separator 'face 'ivy-separator)))
  4987. (defun counsel--kmacro-candidates ()
  4988. "Create the list of keyboard macros used by `counsel-kmacro'.
  4989. This is a combination of `kmacro-ring' and, together in a list, `last-kbd-macro',
  4990. `kmacro-counter-format-start', and `kmacro-counter-value-start'."
  4991. (mapcar
  4992. (lambda (kmacro)
  4993. (cons
  4994. (concat "(" (nth 2 kmacro) "," (number-to-string (nth 1 kmacro)) "): "
  4995. (condition-case nil
  4996. (format-kbd-macro (if (listp kmacro) (car kmacro) kmacro) 1)
  4997. ;; Recover from error from `edmacro-fix-menu-commands'.
  4998. (error "Warning: Cannot display macros containing mouse clicks")))
  4999. kmacro))
  5000. (cons
  5001. (if (listp last-kbd-macro)
  5002. last-kbd-macro
  5003. (list
  5004. last-kbd-macro
  5005. kmacro-counter-value-start
  5006. kmacro-counter-format-start))
  5007. kmacro-ring)))
  5008. (defun counsel-kmacro-action-run (x)
  5009. "Run keyboard macro."
  5010. (let* ((actual-kmacro (cdr x))
  5011. (kmacro-keys (nth 0 actual-kmacro))
  5012. (kmacro-counter-format-start (nth 2 actual-kmacro)))
  5013. ;; With prefix argument, call the macro that many times.
  5014. (kmacro-call-macro (or current-prefix-arg 1) t nil kmacro-keys)))
  5015. (defun counsel-kmacro-action-delete-kmacro (x)
  5016. "Delete a keyboard macro from within `counsel-kmacro'.
  5017. Either delete a macro from `kmacro-ring', or set `last-kbd-macro'
  5018. to the popped head of the ring."
  5019. (let ((actual-macro (cdr x)))
  5020. (if (eq (nth 0 actual-macro) last-kbd-macro)
  5021. (setq last-kbd-macro
  5022. (if (eq kmacro-ring nil)
  5023. nil
  5024. (let ((prev-macro (pop kmacro-ring)))
  5025. (if (listp prev-macro)
  5026. (nth 0 prev-macro)
  5027. prev-macro))))
  5028. (setq kmacro-ring (delq actual-macro kmacro-ring)))))
  5029. (defun counsel-kmacro-action-copy-initial-counter-value (x)
  5030. "Pass an existing keyboard macro's original value to `kmacro-set-counter'.
  5031. This value will be used by the next executed macro, or as an
  5032. initial value by the next macro defined.
  5033. Note that calling an existing macro that itself uses a counter
  5034. effectively resets the initial counter value for the next defined macro
  5035. to 0."
  5036. ;; NOTE:
  5037. ;; Calling `kmacro-start-macro' without an argument sets `kmacro-counter'
  5038. ;; to 0 if `kmacro-initial-counter'is nil, and sets `kmacro-initial-counter'
  5039. ;; to nil regardless.
  5040. ;; Using `kmacro-insert-counter' sets `kmacro-initial-counter' to nil.
  5041. (let* ((actual-kmacro (cdr x))
  5042. (number (nth 1 actual-kmacro)))
  5043. (kmacro-set-counter number)))
  5044. (defun counsel-kmacro-action-copy-counter-format-for-new-macro (x)
  5045. "Set `kmacro-default-counter-format' to an existing keyboard macro's counter format.
  5046. This will apply to the next macro a user defines."
  5047. (let* ((actual-kmacro (cdr x))
  5048. (format (nth 2 actual-kmacro)))
  5049. (kmacro-set-format format)))
  5050. (defun counsel-kmacro-action-cycle-ring-to-macro (x)
  5051. "Cycle `kmacro-ring' until `last-kbd-macro' is the selected macro.
  5052. This is convenient when using \\[kmacro-end-or-call-macro] to call macros.
  5053. Note that cycling the ring changes the starting value of the current macro
  5054. to changes the current macro counter."
  5055. (let ((actual-kmacro (cdr x)))
  5056. (unless (equal last-kbd-macro
  5057. (if (listp last-kbd-macro)
  5058. last-kbd-macro
  5059. (car actual-kmacro)))
  5060. (while (not (equal actual-kmacro
  5061. (car kmacro-ring)))
  5062. (kmacro-cycle-ring-previous))
  5063. ;; Once selected macro is at the head of the ring,
  5064. ;; cycle one last time.
  5065. (kmacro-cycle-ring-previous))))
  5066. (defun counsel-kmacro-action-set-saved-starting-counter (x)
  5067. "Set the starting counter value of the chosen macro.
  5068. By default, sets to current value of the counter. It has no
  5069. effect when selecting the current macro.
  5070. Normally, when cycling keyboard macro ring with \\[kmacro-cycle-ring-previous]
  5071. or \\[kmacro-cycle-ring-next], the current value of the macro counter is
  5072. included with the current macro definition. Then, when cycling
  5073. back, that counter value is restored. This function is meant to
  5074. achieve something similar when cycling macros in the context of
  5075. using `counsel-kmacro', which does not use different counter
  5076. values when running different macros."
  5077. (let ((actual-kmacro (cdr x))
  5078. (default-kmacro-counter-string (number-to-string kmacro-counter)))
  5079. (setq kmacro-ring (mapcar (lambda (this-macro-in-ring)
  5080. (if (equal this-macro-in-ring actual-kmacro)
  5081. (list (car this-macro-in-ring)
  5082. (read-from-minibuffer (concat "Set initial counter for macro (default: "
  5083. default-kmacro-counter-string
  5084. "): ")
  5085. nil nil t nil
  5086. default-kmacro-counter-string)
  5087. (cl-caddr this-macro-in-ring))
  5088. this-macro-in-ring))
  5089. kmacro-ring))))
  5090. (defun counsel-kmacro-action-execute-after-prompt (x)
  5091. "Execute an existing keyboard macro, prompting for a starting counter value, a
  5092. counter format, and the number of times to execute the macro.
  5093. If called with a prefix, will suggest that value for both the
  5094. counter value and iteration amount."
  5095. (let* ((default-string (if current-prefix-arg
  5096. (number-to-string current-prefix-arg)
  5097. nil))
  5098. (actual-kmacro (cdr x))
  5099. (kmacro-keys (nth 0 actual-kmacro))
  5100. (kmacro-starting-counter (number-to-string (nth 1 actual-kmacro)))
  5101. (kmacro-starting-format (nth 2 actual-kmacro))
  5102. (number-of-iterations
  5103. (read-from-minibuffer
  5104. (concat "Enter number of iterations for macro (default: "
  5105. (or default-string (number-to-string 2))
  5106. "): ")
  5107. nil nil t nil
  5108. (or default-string (number-to-string 2))))
  5109. (kmacro-initial-counter-value
  5110. (read-from-minibuffer
  5111. (concat "Enter a starting counter for macro (default: "
  5112. (or default-string kmacro-starting-counter)
  5113. "): ")
  5114. nil nil t nil
  5115. (or default-string kmacro-starting-counter)))
  5116. (kmacro-counter-format-start
  5117. (symbol-name (read-from-minibuffer
  5118. (concat "Enter format for macro counter (default: "
  5119. kmacro-starting-format
  5120. "): ")
  5121. nil nil t nil
  5122. kmacro-starting-format))))
  5123. (kmacro-call-macro number-of-iterations t nil kmacro-keys)))
  5124. (ivy-set-actions
  5125. 'counsel-kmacro
  5126. '(("c" counsel-kmacro-action-cycle-ring-to-macro "cycle to")
  5127. ("d" counsel-kmacro-action-delete-kmacro "delete")
  5128. ("e" counsel-kmacro-action-execute-after-prompt "execute after prompt")
  5129. ("f" counsel-kmacro-action-copy-counter-format-for-new-macro "copy counter format for new macro")
  5130. ("s" counsel-kmacro-action-set-saved-starting-counter "set this counter value")
  5131. ("v" counsel-kmacro-action-copy-initial-counter-value "copy initial counter value")))
  5132. ;;** `counsel-geiser-doc-look-up-manual'
  5133. (declare-function geiser-doc-manual-for-symbol "ext:geiser-doc")
  5134. (defvar geiser-completion-symbol-list-func)
  5135. (defvar counsel-geiser-doc-look-up-manual-history ()
  5136. "History for `counsel-geiser-doc-look-up-manual'.")
  5137. ;;;###autoload
  5138. (defun counsel-geiser-doc-look-up-manual ()
  5139. "Search Scheme documentation."
  5140. (interactive)
  5141. (ivy-read "Symbol: " geiser-completion-symbol-list-func
  5142. :require-match t
  5143. :history 'counsel-geiser-doc-look-up-manual-history
  5144. :action (lambda (cand)
  5145. (geiser-doc-manual-for-symbol (intern cand)))
  5146. :caller 'counsel-geiser-doc-look-up-manual))
  5147. ;;* Misc. OS
  5148. ;;** `counsel-rhythmbox'
  5149. (declare-function dbus-call-method "dbus")
  5150. (declare-function dbus-get-property "dbus")
  5151. (defun counsel--run (&rest program-and-args)
  5152. (let ((name (mapconcat #'identity program-and-args " ")))
  5153. (apply #'start-process name nil program-and-args)
  5154. name))
  5155. (defun counsel--sl (cmd)
  5156. "Shell command to list."
  5157. (split-string (shell-command-to-string cmd) "\n" t))
  5158. (defun counsel-rhythmbox-play-song (song)
  5159. "Let Rhythmbox play SONG."
  5160. (let ((first (string= (shell-command-to-string "pidof rhythmbox") ""))
  5161. (service "org.gnome.Rhythmbox3")
  5162. (path "/org/mpris/MediaPlayer2")
  5163. (interface "org.mpris.MediaPlayer2.Player"))
  5164. (when first
  5165. (counsel--run "nohup" "rhythmbox")
  5166. (sit-for 1.5))
  5167. (dbus-call-method :session service path interface
  5168. "OpenUri" (cdr song))
  5169. (let ((id (and first
  5170. (cdr (counsel--wmctrl-parse
  5171. (shell-command-to-string
  5172. "wmctrl -l -p | grep $(pidof rhythmbox)"))))))
  5173. (when id
  5174. (sit-for 0.2)
  5175. (counsel--run "wmctrl" "-ic" id)))))
  5176. (defun counsel-rhythmbox-enqueue-song (song)
  5177. "Let Rhythmbox enqueue SONG."
  5178. (let ((service "org.gnome.Rhythmbox3")
  5179. (path "/org/gnome/Rhythmbox3/PlayQueue")
  5180. (interface "org.gnome.Rhythmbox3.PlayQueue"))
  5181. (dbus-call-method :session service path interface
  5182. "AddToQueue" (cdr song))))
  5183. (defun counsel-rhythmbox-playpause-current-song ()
  5184. "Play/pause the current song."
  5185. (interactive)
  5186. (let ((service "org.gnome.Rhythmbox3")
  5187. (path "/org/mpris/MediaPlayer2")
  5188. (interface "org.mpris.MediaPlayer2.Player"))
  5189. (dbus-call-method :session service path interface
  5190. "PlayPause")))
  5191. (defun counsel-rhythmbox-toggle-shuffle (_song)
  5192. "Toggle Rhythmbox shuffle setting."
  5193. (let* ((old-order (counsel--command "dconf" "read" "/org/gnome/rhythmbox/player/play-order"))
  5194. (new-order (if (string= old-order "'shuffle'")
  5195. "'linear'"
  5196. "'shuffle'")))
  5197. (counsel--command
  5198. "dconf"
  5199. "write"
  5200. "/org/gnome/rhythmbox/player/play-order"
  5201. new-order)
  5202. (message (if (string= new-order "'shuffle'")
  5203. "shuffle on"
  5204. "shuffle off"))))
  5205. (defvar counsel-rhythmbox-history nil
  5206. "History for `counsel-rhythmbox'.")
  5207. (defvar counsel-rhythmbox-songs nil)
  5208. (defun counsel-rhythmbox-current-song ()
  5209. "Return the currently playing song title."
  5210. (ignore-errors
  5211. (let* ((entry (dbus-get-property
  5212. :session
  5213. "org.mpris.MediaPlayer2.rhythmbox"
  5214. "/org/mpris/MediaPlayer2"
  5215. "org.mpris.MediaPlayer2.Player"
  5216. "Metadata"))
  5217. (artist (caar (cadr (assoc "xesam:artist" entry))))
  5218. (album (cl-caadr (assoc "xesam:album" entry)))
  5219. (title (cl-caadr (assoc "xesam:title" entry))))
  5220. (format "%s - %s - %s" artist album title))))
  5221. ;;;###autoload
  5222. (defun counsel-rhythmbox (&optional arg)
  5223. "Choose a song from the Rhythmbox library to play or enqueue."
  5224. (interactive "P")
  5225. (require 'dbus)
  5226. (when (or arg (null counsel-rhythmbox-songs))
  5227. (let* ((service "org.gnome.Rhythmbox3")
  5228. (path "/org/gnome/UPnP/MediaServer2/Library/all")
  5229. (interface "org.gnome.UPnP.MediaContainer2")
  5230. (nb-songs (dbus-get-property
  5231. :session service path interface "ChildCount")))
  5232. (if (not nb-songs)
  5233. (error "Couldn't connect to Rhythmbox")
  5234. (setq counsel-rhythmbox-songs
  5235. (mapcar (lambda (x)
  5236. (cons
  5237. (format
  5238. "%s - %s - %s"
  5239. (cl-caadr (assoc "Artist" x))
  5240. (cl-caadr (assoc "Album" x))
  5241. (cl-caadr (assoc "DisplayName" x)))
  5242. (cl-caaadr (assoc "URLs" x))))
  5243. (dbus-call-method
  5244. :session service path interface "ListChildren"
  5245. 0 nb-songs '("*")))))))
  5246. (ivy-read "Rhythmbox: " counsel-rhythmbox-songs
  5247. :require-match t
  5248. :history 'counsel-rhythmbox-history
  5249. :preselect (counsel-rhythmbox-current-song)
  5250. :action
  5251. '(1
  5252. ("p" counsel-rhythmbox-play-song "Play song")
  5253. ("e" counsel-rhythmbox-enqueue-song "Enqueue song")
  5254. ("s" counsel-rhythmbox-toggle-shuffle "Shuffle on/off"))
  5255. :caller 'counsel-rhythmbox))
  5256. ;;** `counsel-linux-app'
  5257. ;; Added in Emacs 26.1.
  5258. (require 'xdg nil t)
  5259. (defalias 'counsel--xdg-data-home
  5260. (if (fboundp 'xdg-data-home)
  5261. #'xdg-data-home
  5262. (lambda ()
  5263. (let ((directory (getenv "XDG_DATA_HOME")))
  5264. (if (or (null directory) (string= directory ""))
  5265. "~/.local/share"
  5266. directory))))
  5267. "Compatibility shim for `xdg-data-home'.")
  5268. (defalias 'counsel--xdg-data-dirs
  5269. (if (fboundp 'xdg-data-dirs)
  5270. #'xdg-data-dirs
  5271. (lambda ()
  5272. (let ((path (getenv "XDG_DATA_DIRS")))
  5273. (if (or (null path) (string= path ""))
  5274. '("/usr/local/share" "/usr/share")
  5275. (parse-colon-path path)))))
  5276. "Compatibility shim for `xdg-data-dirs'.")
  5277. (defcustom counsel-linux-apps-directories
  5278. (mapcar (lambda (dir) (expand-file-name "applications" dir))
  5279. (cons (counsel--xdg-data-home)
  5280. (counsel--xdg-data-dirs)))
  5281. "Directories in which to search for applications (.desktop files)."
  5282. :type '(repeat directory))
  5283. (defcustom counsel-linux-app-format-function #'counsel-linux-app-format-function-default
  5284. "Function to format Linux application names the `counsel-linux-app' menu.
  5285. The format function will be passed the application's name, comment, and command
  5286. as arguments."
  5287. :type '(choice
  5288. (const :tag "Command : Name - Comment" counsel-linux-app-format-function-default)
  5289. (const :tag "Name - Comment (Command)" counsel-linux-app-format-function-name-first)
  5290. (const :tag "Name - Comment" counsel-linux-app-format-function-name-only)
  5291. (const :tag "Name - Comment (Pretty)" counsel-linux-app-format-function-name-pretty)
  5292. (const :tag "Command" counsel-linux-app-format-function-command-only)
  5293. (function :tag "Custom")))
  5294. (defface counsel-application-name
  5295. '((t :inherit font-lock-builtin-face))
  5296. "Face for displaying executable names."
  5297. :group 'ivy-faces)
  5298. (defface counsel-outline-1
  5299. '((t :inherit org-level-1))
  5300. "Face for displaying level 1 headings."
  5301. :group 'ivy-faces)
  5302. (defface counsel-outline-2
  5303. '((t :inherit org-level-2))
  5304. "Face for displaying level 2 headings."
  5305. :group 'ivy-faces)
  5306. (defface counsel-outline-3
  5307. '((t :inherit org-level-3))
  5308. "Face for displaying level 3 headings."
  5309. :group 'ivy-faces)
  5310. (defface counsel-outline-4
  5311. '((t :inherit org-level-4))
  5312. "Face for displaying level 4 headings."
  5313. :group 'ivy-faces)
  5314. (defface counsel-outline-5
  5315. '((t :inherit org-level-5))
  5316. "Face for displaying level 5 headings."
  5317. :group 'ivy-faces)
  5318. (defface counsel-outline-6
  5319. '((t :inherit org-level-6))
  5320. "Face for displaying level 6 headings."
  5321. :group 'ivy-faces)
  5322. (defface counsel-outline-7
  5323. '((t :inherit org-level-7))
  5324. "Face for displaying level 7 headings."
  5325. :group 'ivy-faces)
  5326. (defface counsel-outline-8
  5327. '((t :inherit org-level-8))
  5328. "Face for displaying level 8 headings."
  5329. :group 'ivy-faces)
  5330. (defface counsel-outline-default
  5331. '((t :inherit minibuffer-prompt))
  5332. "Face for displaying headings."
  5333. :group 'ivy-faces)
  5334. (defvar counsel-linux-apps-faulty nil
  5335. "List of faulty desktop files.")
  5336. (defvar counsel--linux-apps-cache nil
  5337. "Cache of desktop files data.")
  5338. (defvar counsel--linux-apps-cached-files nil
  5339. "List of cached desktop files.")
  5340. (defvar counsel--linux-apps-cache-timestamp nil
  5341. "Time when we last updated the cached application list.")
  5342. (defvar counsel--linux-apps-cache-format-function nil
  5343. "The function used to format the cached Linux application menu.")
  5344. (defun counsel-linux-app-format-function-default (name comment exec)
  5345. "Default Linux application name formatter.
  5346. NAME is the name of the application, COMMENT its comment and EXEC
  5347. the command to launch it."
  5348. (format "% -45s: %s%s"
  5349. (propertize
  5350. (ivy--truncate-string
  5351. (replace-regexp-in-string "env +[^ ]+ +" "" exec)
  5352. 45)
  5353. 'face 'counsel-application-name)
  5354. name
  5355. (if comment
  5356. (concat " - " comment)
  5357. "")))
  5358. (defun counsel-linux-app-format-function-name-first (name comment exec)
  5359. "Format Linux application names with the NAME (and COMMENT) first.
  5360. EXEC is the command to launch the application."
  5361. (format "%s%s (%s)"
  5362. name
  5363. (if comment
  5364. (concat " - " comment)
  5365. "")
  5366. (propertize exec 'face 'counsel-application-name)))
  5367. (defun counsel-linux-app-format-function-name-only (name comment _exec)
  5368. "Format Linux application names with the NAME (and COMMENT) only."
  5369. (format "%s%s"
  5370. name
  5371. (if comment
  5372. (concat " - " comment)
  5373. "")))
  5374. (defun counsel-linux-app-format-function-command-only (_name _comment exec)
  5375. "Display only the command EXEC when formatting Linux application names."
  5376. exec)
  5377. (defun counsel-linux-app-format-function-name-pretty (name comment _exec)
  5378. "Format Linux application names with the NAME (and COMMENT) only, but pretty."
  5379. (format "% -45s%s"
  5380. (propertize
  5381. (ivy--truncate-string name 45)
  5382. 'face 'counsel-application-name)
  5383. (if comment
  5384. (concat ": " comment)
  5385. "")))
  5386. (defun counsel-linux-apps-list-desktop-files ()
  5387. "Return an alist of all Linux applications.
  5388. Each list entry is a pair of (desktop-name . desktop-file).
  5389. This function always returns its elements in a stable order."
  5390. (let ((hash (make-hash-table :test #'equal))
  5391. result)
  5392. (dolist (dir counsel-linux-apps-directories)
  5393. (when (file-exists-p dir)
  5394. (let ((dir (file-name-as-directory dir)))
  5395. ;; Function `directory-files-recursively' added in Emacs 25.1.
  5396. (dolist (file (directory-files-recursively dir ".*\\.desktop$"))
  5397. (let ((id (subst-char-in-string ?/ ?- (file-relative-name file dir))))
  5398. (when (and (not (gethash id hash)) (file-readable-p file))
  5399. (push (cons id file) result)
  5400. (puthash id file hash)))))))
  5401. result))
  5402. (defun counsel-linux-app--parse-file (file)
  5403. (with-temp-buffer
  5404. (insert-file-contents file)
  5405. (goto-char (point-min))
  5406. (let ((start (re-search-forward "^\\[Desktop Entry\\] *$" nil t))
  5407. (end (re-search-forward "^\\[" nil t))
  5408. (visible t)
  5409. name comment exec)
  5410. (catch 'break
  5411. (unless start
  5412. (push file counsel-linux-apps-faulty)
  5413. (message "Warning: File %s has no [Desktop Entry] group" file)
  5414. (throw 'break nil))
  5415. (goto-char start)
  5416. (when (re-search-forward "^\\(Hidden\\|NoDisplay\\) *= *\\(1\\|true\\) *$" end t)
  5417. (setq visible nil))
  5418. (setq name (match-string 1))
  5419. (goto-char start)
  5420. (unless (re-search-forward "^Type *= *Application *$" end t)
  5421. (throw 'break nil))
  5422. (setq name (match-string 1))
  5423. (goto-char start)
  5424. (unless (re-search-forward "^Name *= *\\(.+\\)$" end t)
  5425. (push file counsel-linux-apps-faulty)
  5426. (message "Warning: File %s has no Name" file)
  5427. (throw 'break nil))
  5428. (setq name (match-string 1))
  5429. (goto-char start)
  5430. (when (re-search-forward "^Comment *= *\\(.+\\)$" end t)
  5431. (setq comment (match-string 1)))
  5432. (goto-char start)
  5433. (unless (re-search-forward "^Exec *= *\\(.+\\)$" end t)
  5434. ;; Don't warn because this can technically be a valid desktop file.
  5435. (throw 'break nil))
  5436. (setq exec (match-string 1))
  5437. (goto-char start)
  5438. (when (re-search-forward "^TryExec *= *\\(.+\\)$" end t)
  5439. (let ((try-exec (match-string 1)))
  5440. (unless (locate-file try-exec exec-path nil #'file-executable-p)
  5441. (throw 'break nil))))
  5442. (propertize
  5443. (funcall counsel-linux-app-format-function name comment exec)
  5444. 'visible visible)))))
  5445. (defun counsel-linux-apps-parse (desktop-entries-alist)
  5446. "Parse the given alist of Linux desktop entries.
  5447. Each entry in DESKTOP-ENTRIES-ALIST is a pair of ((id . file-name)).
  5448. Any desktop entries that fail to parse are recorded in
  5449. `counsel-linux-apps-faulty'."
  5450. (let (result)
  5451. (setq counsel-linux-apps-faulty nil)
  5452. (dolist (entry desktop-entries-alist result)
  5453. (let* ((id (car entry))
  5454. (file (cdr entry))
  5455. (r (counsel-linux-app--parse-file file)))
  5456. (when r
  5457. (push (cons r id) result))))))
  5458. (defun counsel-linux-apps-list ()
  5459. "Return list of all Linux desktop applications."
  5460. (let* ((new-desktop-alist (counsel-linux-apps-list-desktop-files))
  5461. (new-files (mapcar 'cdr new-desktop-alist)))
  5462. (unless (and
  5463. (eq counsel-linux-app-format-function
  5464. counsel--linux-apps-cache-format-function)
  5465. (equal new-files counsel--linux-apps-cached-files)
  5466. (null (cl-find-if
  5467. (lambda (file)
  5468. (time-less-p
  5469. counsel--linux-apps-cache-timestamp
  5470. (nth 5 (file-attributes file))))
  5471. new-files)))
  5472. (setq counsel--linux-apps-cache (counsel-linux-apps-parse new-desktop-alist))
  5473. (setq counsel--linux-apps-cache-format-function counsel-linux-app-format-function)
  5474. (setq counsel--linux-apps-cache-timestamp (current-time))
  5475. (setq counsel--linux-apps-cached-files new-files)))
  5476. counsel--linux-apps-cache)
  5477. (defun counsel-linux-app-action-default (desktop-shortcut)
  5478. "Launch DESKTOP-SHORTCUT."
  5479. (call-process "gtk-launch" nil 0 nil (cdr desktop-shortcut)))
  5480. (defun counsel-linux-app-action-file (desktop-shortcut)
  5481. "Launch DESKTOP-SHORTCUT with a selected file."
  5482. (call-process "gtk-launch" nil 0 nil
  5483. (cdr desktop-shortcut)
  5484. (read-file-name "File: ")))
  5485. (defun counsel-linux-app-action-open-desktop (desktop-shortcut)
  5486. "Open DESKTOP-SHORTCUT."
  5487. (let* ((app (cdr desktop-shortcut))
  5488. (file (cdr (assoc app (counsel-linux-apps-list-desktop-files)))))
  5489. (if file
  5490. (find-file file)
  5491. (error "Could not find location of file %s" app))))
  5492. (ivy-set-actions
  5493. 'counsel-linux-app
  5494. '(("f" counsel-linux-app-action-file "run on a file")
  5495. ("d" counsel-linux-app-action-open-desktop "open desktop file")))
  5496. ;;;###autoload
  5497. (defun counsel-linux-app (&optional arg)
  5498. "Launch a Linux desktop application, similar to Alt-<F2>.
  5499. When ARG is non-nil, ignore NoDisplay property in *.desktop files."
  5500. (interactive "P")
  5501. (ivy-read "Run application: " (counsel-linux-apps-list)
  5502. :predicate (unless arg (lambda (x) (get-text-property 0 'visible (car x))))
  5503. :action #'counsel-linux-app-action-default
  5504. :caller 'counsel-linux-app))
  5505. ;;** `counsel-wmctrl'
  5506. (defun counsel-wmctrl-action (x)
  5507. "Select the desktop window that corresponds to X."
  5508. (counsel--run "wmctrl" "-i" "-a" (cdr x)))
  5509. (defvar counsel-wmctrl-ignore '("XdndCollectionWindowImp"
  5510. "unity-launcher" "unity-panel" "unity-dash"
  5511. "Hud" "Desktop")
  5512. "List of window titles to ignore for `counsel-wmctrl'.")
  5513. (defun counsel--wmctrl-parse (s)
  5514. (when (string-match "\\`\\([0-9a-fx]+\\) +\\([-0-9]+\\) +\\(?:[0-9]+\\) +\\([^ ]+\\) \\(.+\\)$" s)
  5515. (let ((title (match-string 4 s))
  5516. (id (match-string 1 s)))
  5517. (unless (member title counsel-wmctrl-ignore)
  5518. (cons title id)))))
  5519. ;;;###autoload
  5520. (defun counsel-wmctrl ()
  5521. "Select a desktop window using wmctrl."
  5522. (interactive)
  5523. (let* ((cands1 (counsel--sl "wmctrl -l -p"))
  5524. (cands2 (delq nil (mapcar #'counsel--wmctrl-parse cands1))))
  5525. (ivy-read "window: " cands2
  5526. :action #'counsel-wmctrl-action
  5527. :caller 'counsel-wmctrl)))
  5528. (defvar counsel--switch-buffer-temporary-buffers nil
  5529. "Internal.")
  5530. (defvar counsel--switch-buffer-previous-buffers nil
  5531. "Internal.")
  5532. (defun counsel--switch-buffer-unwind ()
  5533. "Clear temporary file buffers and restore `buffer-list'.
  5534. The buffers are those opened during a session of `counsel-switch-buffer'."
  5535. (mapc #'kill-buffer counsel--switch-buffer-temporary-buffers)
  5536. (mapc #'bury-buffer (cl-remove-if-not
  5537. #'buffer-live-p
  5538. counsel--switch-buffer-previous-buffers))
  5539. (setq counsel--switch-buffer-temporary-buffers nil
  5540. counsel--switch-buffer-previous-buffers nil))
  5541. (defcustom counsel-switch-buffer-preview-virtual-buffers t
  5542. "When non-nil, `counsel-switch-buffer' will preview virtual buffers."
  5543. :type 'boolean)
  5544. (defun counsel--switch-buffer-update-fn ()
  5545. (unless counsel--switch-buffer-previous-buffers
  5546. (setq counsel--switch-buffer-previous-buffers (buffer-list)))
  5547. (let* ((virtual (assoc (ivy-state-current ivy-last) ivy--virtual-buffers)))
  5548. (when (member (ivy-state-current ivy-last) ivy-marked-candidates)
  5549. (setf (ivy-state-current ivy-last)
  5550. (substring (ivy-state-current ivy-last) (length ivy-mark-prefix))))
  5551. (cond
  5552. ((get-buffer (ivy-state-current ivy-last))
  5553. (let ((ivy-marked-candidates nil))
  5554. (ivy-call)))
  5555. ((and counsel-switch-buffer-preview-virtual-buffers virtual (file-exists-p (cdr virtual)))
  5556. (let ((buf (ignore-errors
  5557. ;; may not open due to `large-file-warning-threshold' etc.
  5558. (find-file-noselect (cdr virtual)))))
  5559. (if buf
  5560. (progn
  5561. (push buf counsel--switch-buffer-temporary-buffers)
  5562. (ivy-call))
  5563. ;; clean up the minibuffer so that there's no delay before
  5564. ;; the Ivy candidates are displayed once again
  5565. (message ""))))
  5566. (t
  5567. (with-ivy-window
  5568. (switch-to-buffer (ivy-state-buffer ivy-last)))))))
  5569. ;;;###autoload
  5570. (defun counsel-switch-buffer ()
  5571. "Switch to another buffer.
  5572. Display a preview of the selected ivy completion candidate buffer
  5573. in the current window."
  5574. (interactive)
  5575. (let ((ivy-update-fns-alist
  5576. '((ivy-switch-buffer . counsel--switch-buffer-update-fn)))
  5577. (ivy-unwind-fns-alist
  5578. '((ivy-switch-buffer . counsel--switch-buffer-unwind))))
  5579. (ivy-switch-buffer)))
  5580. ;;;###autoload
  5581. (defun counsel-switch-buffer-other-window ()
  5582. "Switch to another buffer in another window.
  5583. Display a preview of the selected ivy completion candidate buffer
  5584. in the current window."
  5585. (interactive)
  5586. (let ((ivy-update-fns-alist
  5587. '((ivy-switch-buffer-other-window . counsel--switch-buffer-update-fn)))
  5588. (ivy-unwind-fns-alist
  5589. '((ivy-switch-buffer-other-window . counsel--switch-buffer-unwind))))
  5590. (ivy-switch-buffer-other-window)))
  5591. (defun counsel-open-buffer-file-externally (buffer)
  5592. "Open the file associated with BUFFER with an external program."
  5593. (when (zerop (length buffer))
  5594. (user-error "Can't open that"))
  5595. (let* ((virtual (assoc buffer ivy--virtual-buffers))
  5596. (filename (if virtual
  5597. (cdr virtual)
  5598. (buffer-file-name (get-buffer buffer)))))
  5599. (unless filename
  5600. (user-error "Can't open `%s' externally" buffer))
  5601. (counsel-locate-action-extern (expand-file-name filename))))
  5602. (ivy-add-actions
  5603. 'ivy-switch-buffer
  5604. '(("x" counsel-open-buffer-file-externally "open externally")))
  5605. (ivy-set-actions
  5606. 'counsel-switch-buffer
  5607. '(("x" counsel-open-buffer-file-externally "open externally")
  5608. ("j" ivy--switch-buffer-other-window-action "other window")))
  5609. ;;** `counsel-compile'
  5610. (defvar counsel-compile-history nil
  5611. "History for `counsel-compile'.
  5612. This is a list of strings with additional properties which allow
  5613. the history to be filtered depending on the context of the call.
  5614. The properties include:
  5615. `srcdir'
  5616. the root directory of the source code
  5617. `blddir'
  5618. the root directory of the build (in or outside the `srcdir')
  5619. `bldenv'
  5620. the build environment as passed to `compilation-environment'
  5621. `recursive'
  5622. the completion should be run again in `blddir' of this result
  5623. `cmd'
  5624. if set, pass only the substring with this property to `compile'
  5625. This variable is suitable for addition to
  5626. `savehist-additional-variables'.")
  5627. (defvar counsel-compile-root-functions
  5628. '(counsel--projectile-root
  5629. counsel--project-current
  5630. counsel--configure-root
  5631. counsel--git-root
  5632. counsel--dir-locals-root)
  5633. "Special hook to find the project root for compile commands.
  5634. Each function on this hook is called in turn with no arguments
  5635. and should return either a directory, or nil if no root was
  5636. found.")
  5637. (defun counsel--compile-root ()
  5638. "Return root of current project or signal an error on failure.
  5639. The root is determined by `counsel-compile-root-functions'."
  5640. (or (run-hook-with-args-until-success 'counsel-compile-root-functions)
  5641. (error "Couldn't find project root")))
  5642. (defun counsel--projectile-root ()
  5643. "Return root of current projectile project or nil on failure.
  5644. Use `projectile-project-root' to determine the root."
  5645. (and (fboundp 'projectile-project-root)
  5646. (projectile-project-root)))
  5647. (defun counsel--project-current ()
  5648. "Return root of current project or nil on failure.
  5649. Use `project-current' to determine the root."
  5650. (and (fboundp 'project-current)
  5651. (cdr (project-current))))
  5652. (defun counsel--configure-root ()
  5653. "Return root of current project or nil on failure.
  5654. Use the presence of a \"configure\" file to determine the root."
  5655. (counsel--dominating-file "configure"))
  5656. (defun counsel--git-root ()
  5657. "Return root of current project or nil on failure.
  5658. Use the presence of a \".git\" file to determine the root."
  5659. (counsel--dominating-file ".git"))
  5660. (defun counsel--dir-locals-root ()
  5661. "Return root of current project or nil on failure.
  5662. Use the presence of a `dir-locals-file' to determine the root."
  5663. (counsel--dominating-file dir-locals-file))
  5664. (defvar counsel-compile-local-builds
  5665. '(counsel-compile-get-filtered-history
  5666. counsel-compile-get-build-directories
  5667. counsel-compile-get-make-invocation
  5668. counsel-compile-get-make-help-invocations)
  5669. "Additional compile invocations to feed into `counsel-compile'.
  5670. This can either be a list of compile invocation strings or
  5671. functions that will provide such a list. You should customize
  5672. this if you want to provide specific non-standard build types to
  5673. `counsel-compile'. The default helpers are set up to handle
  5674. common build environments.")
  5675. (defcustom counsel-compile-make-args "-k"
  5676. "Additional arguments for make.
  5677. You may, for example, want to add \"-jN\" for the number of cores
  5678. N in your system."
  5679. :type 'string)
  5680. (defcustom counsel-compile-env nil
  5681. "List of environment variables for compilation to inherit.
  5682. Each element should be a string of the form ENVVARNAME=VALUE. This
  5683. list is passed to `compilation-environment'."
  5684. :type '(repeat (string :tag "ENVVARNAME=VALUE")))
  5685. (defvar counsel-compile-env-history nil
  5686. "History for `counsel-compile-env'.")
  5687. (defvar counsel-compile-env-pattern
  5688. "[_[:digit:][:upper:]]+=[/[:alnum:]]*"
  5689. "Pattern to match valid environment variables.")
  5690. (defcustom counsel-compile-make-pattern "\\`\\(?:GNUm\\|[Mm]\\)akefile\\'"
  5691. "Regexp for matching the names of Makefiles."
  5692. :type 'regexp)
  5693. (defcustom counsel-compile-build-directories
  5694. '("build" "builds" "bld" ".build")
  5695. "List of potential build subdirectory names to check for."
  5696. :type '(repeat directory))
  5697. (defvar counsel-compile-phony-pattern "^\\.PHONY:[\t ]+\\(.+\\)$"
  5698. "Regexp for extracting phony targets from Makefiles.")
  5699. (defvar counsel-compile-help-pattern
  5700. "\\(?:^\\(\\*\\)?[[:space:]]+\\([^[:space:]]+\\)[[:space:]]+-\\)"
  5701. "Regexp for extracting help targets from a make help call.")
  5702. ;; This is loosely based on the Bash Make completion code which
  5703. ;; relies on GNUMake having the following return codes:
  5704. ;; 0 = no-rebuild, -q & 1 needs rebuild, 2 error
  5705. (defun counsel-compile--probe-make-targets (dir)
  5706. "Return a list of Make targets for DIR.
  5707. Return a single blank target (so we invoke the default target)
  5708. if Make exits with an error. This might happen because some sort
  5709. of configuration needs to be done first or the source tree is
  5710. pristine and being used for multiple build trees."
  5711. (with-temp-buffer
  5712. (let* ((default-directory dir)
  5713. (res (call-process "make" nil t nil "-nqp"))
  5714. targets)
  5715. (if (or (not (numberp res)) (> res 1))
  5716. (list "")
  5717. (goto-char (point-min))
  5718. (while (re-search-forward counsel-compile-phony-pattern nil t)
  5719. (push (split-string (match-string-no-properties 1)) targets))
  5720. (sort (apply #'nconc targets) #'string-lessp)))))
  5721. (defun counsel-compile--pretty-propertize (leader text face)
  5722. "Return a pretty string of the form \" LEADER TEXT\".
  5723. LEADER is propertized with a warning face and the remaining
  5724. text with FACE."
  5725. (concat (propertize (concat " " leader " ")
  5726. 'face
  5727. 'font-lock-warning-face)
  5728. (propertize text 'face face)))
  5729. (defun counsel--compile-get-make-targets (probe-fn srcdir &optional blddir)
  5730. "Return propertized make targets returned by PROBE-FN in SRCDIR.
  5731. The optional BLDDIR allows for handling build directories. We
  5732. search the Makefile for a list of phony targets which are
  5733. generally the top level targets a Make system provides. The
  5734. resulting strings are tagged with properties that
  5735. `counsel-compile-history' can use for filtering results."
  5736. (let ((fmt (format (propertize "make %s %%s" 'cmd t)
  5737. counsel-compile-make-args))
  5738. (suffix (and blddir
  5739. (counsel-compile--pretty-propertize "in" blddir
  5740. 'dired-directory)))
  5741. (build-env (and counsel-compile-env
  5742. (counsel-compile--pretty-propertize
  5743. "with"
  5744. (mapconcat #'identity counsel-compile-env " ")
  5745. 'font-lock-variable-name-face)))
  5746. (props `(srcdir ,srcdir blddir ,blddir bldenv ,counsel-compile-env)))
  5747. (mapcar (lambda (target)
  5748. (setq target (concat (format fmt target) suffix build-env))
  5749. (add-text-properties 0 (length target) props target)
  5750. target)
  5751. (funcall probe-fn (or blddir srcdir)))))
  5752. (defun counsel-compile-get-make-invocation (&optional blddir)
  5753. "Have a look in the root directory for any build control files.
  5754. The optional BLDDIR is useful for other helpers that have found
  5755. sub-directories that builds may be invoked in."
  5756. (let ((srcdir (counsel--compile-root)))
  5757. (when (directory-files (or blddir srcdir) nil
  5758. counsel-compile-make-pattern t)
  5759. (counsel--compile-get-make-targets
  5760. #'counsel-compile--probe-make-targets srcdir blddir))))
  5761. (defun counsel-compile--probe-make-help (dir)
  5762. "Return a list of Make targets based on help for DIR.
  5763. It is quite common for a 'make help' invocation to return a human
  5764. readable list of targets. Often common targets are marked with a
  5765. leading asterisk. The exact search pattern is controlled by
  5766. `counsel-compile-help-pattern'."
  5767. (let ((default-directory dir)
  5768. primary-targets targets)
  5769. ;; Only proceed if the help target exists.
  5770. (when (eql 1 (apply #'call-process "make" nil nil nil "-q" "help"
  5771. counsel-compile-env))
  5772. (with-temp-buffer
  5773. (when (eql 0 (apply #'call-process "make" nil t nil "help"
  5774. counsel-compile-env))
  5775. (goto-char (point-min))
  5776. (while (re-search-forward counsel-compile-help-pattern nil t)
  5777. (push (match-string 2)
  5778. (if (match-beginning 1) primary-targets targets)))
  5779. (nconc (sort primary-targets #'string-lessp)
  5780. (sort targets #'string-lessp)))))))
  5781. (defun counsel-compile-get-make-help-invocations (&optional blddir)
  5782. "Query the root directory for makefiles with help output.
  5783. The optional BLDDIR is useful for other helpers that have found
  5784. sub-directories that builds may be invoked in."
  5785. (let ((srcdir (counsel--compile-root)))
  5786. (when (directory-files (or blddir srcdir) nil
  5787. counsel-compile-make-pattern t)
  5788. (counsel--compile-get-make-targets
  5789. #'counsel-compile--probe-make-help srcdir blddir))))
  5790. (defun counsel--find-build-subdir (srcdir)
  5791. "Return builds subdirectory of SRCDIR, if one exists."
  5792. (cl-some (lambda (dir)
  5793. (setq dir (expand-file-name dir srcdir))
  5794. (and (file-directory-p dir) dir))
  5795. counsel-compile-build-directories))
  5796. (defun counsel--get-build-subdirs (blddir)
  5797. "Return all subdirs under BLDDIR sorted by modification time.
  5798. If there are non-directory files in BLDDIR, include BLDDIR in the
  5799. list as it may also be a build directory."
  5800. (let* ((files (directory-files-and-attributes
  5801. blddir t directory-files-no-dot-files-regexp t))
  5802. (dirs (cl-remove-if-not #'cl-second files)))
  5803. ;; Any non-dir files?
  5804. (when (< (length dirs)
  5805. (length files))
  5806. (push (cons blddir (file-attributes blddir)) dirs))
  5807. (mapcar #'car (sort dirs (lambda (x y)
  5808. (time-less-p (nth 6 y) (nth 6 x)))))))
  5809. (defun counsel-compile-get-build-directories (&optional dir)
  5810. "Return a list of potential build directories."
  5811. (let* ((srcdir (or dir (counsel--compile-root)))
  5812. (blddir (counsel--find-build-subdir srcdir))
  5813. (props `(srcdir ,srcdir recursive t))
  5814. (fmt (concat (propertize "Select build in "
  5815. 'face 'font-lock-warning-face)
  5816. (propertize "%s" 'face 'dired-directory))))
  5817. (mapcar (lambda (subdir)
  5818. (let ((s (format fmt subdir)))
  5819. (add-text-properties 0 (length s) `(blddir ,subdir ,@props) s)
  5820. s))
  5821. (and blddir (counsel--get-build-subdirs blddir)))))
  5822. ;; This is a workaround for the fact there is no concept of "project"
  5823. ;; local variables (as opposed to for example buffer-local). So we
  5824. ;; store all our history in a global list filter out the results we
  5825. ;; don't want.
  5826. (defun counsel-compile-get-filtered-history (&optional dir)
  5827. "Return a compile history relevant to current project."
  5828. (let ((root (or dir (counsel--compile-root)))
  5829. history)
  5830. (dolist (item counsel-compile-history)
  5831. (let ((srcdir (get-text-property 0 'srcdir item))
  5832. (blddir (get-text-property 0 'blddir item)))
  5833. (when (or (and srcdir (file-in-directory-p srcdir root))
  5834. (and blddir (file-in-directory-p blddir root)))
  5835. (push item history))))
  5836. (nreverse history)))
  5837. (defun counsel--get-compile-candidates (&optional dir)
  5838. "Return the list of compile commands.
  5839. This is determined by `counsel-compile-local-builds', which see."
  5840. (let (cands)
  5841. (dolist (cmds counsel-compile-local-builds)
  5842. (when (functionp cmds)
  5843. (setq cmds (funcall cmds dir)))
  5844. (when cmds
  5845. (push (if (listp cmds) cmds (list cmds)) cands)))
  5846. (apply #'append (nreverse cands))))
  5847. ;; This is a workaround to ensure we tag all the relevant metadata in
  5848. ;; our compile history. This also allows M-x compile to do fancy
  5849. ;; things like infer `default-directory' from 'cd's in the string.
  5850. (defun counsel-compile--update-history (_proc)
  5851. "Update `counsel-compile-history' from the compilation state."
  5852. (let* ((srcdir (counsel--compile-root))
  5853. (blddir default-directory)
  5854. (bldenv compilation-environment)
  5855. (cmd (concat
  5856. (propertize (car compilation-arguments) 'cmd t)
  5857. (unless (file-equal-p blddir srcdir)
  5858. (counsel-compile--pretty-propertize "in" blddir
  5859. 'dired-directory))
  5860. (when bldenv
  5861. (counsel-compile--pretty-propertize "with"
  5862. (mapconcat #'identity bldenv " ")
  5863. 'font-lock-variable-name-face)))))
  5864. (add-text-properties 0 (length cmd)
  5865. `(srcdir ,srcdir blddir ,blddir bldenv ,bldenv) cmd)
  5866. (add-to-history 'counsel-compile-history cmd)))
  5867. (defvar counsel-compile--current-build-dir nil
  5868. "Tracks the last directory `counsel-compile' was called with.
  5869. This state allows us to set it correctly if the user has manually
  5870. edited the command, thus losing our embedded state.")
  5871. (defun counsel-compile--action (cmd)
  5872. "Process CMD to call `compile'.
  5873. If CMD has the `recursive' property set we call `counsel-compile'
  5874. again to further refine the compile options in the directory
  5875. specified by the `blddir' property."
  5876. (let ((blddir (get-text-property 0 'blddir cmd))
  5877. (bldenv (get-text-property 0 'bldenv cmd)))
  5878. (if (get-text-property 0 'recursive cmd)
  5879. (counsel-compile blddir)
  5880. (when (get-char-property 0 'cmd cmd)
  5881. (setq cmd (substring-no-properties
  5882. cmd 0 (next-single-property-change 0 'cmd cmd))))
  5883. (let ((default-directory (or blddir
  5884. counsel-compile--current-build-dir
  5885. default-directory))
  5886. (compilation-environment bldenv))
  5887. ;; No need to specify `:history' because of this hook.
  5888. (add-hook 'compilation-start-hook #'counsel-compile--update-history)
  5889. (unwind-protect
  5890. (compile cmd)
  5891. (remove-hook 'compilation-start-hook #'counsel-compile--update-history))))))
  5892. (defun counsel-compile-edit-command ()
  5893. "Insert current compile command into the minibuffer for editing.
  5894. This mirrors the behavior of `ivy-insert-current' but with specific
  5895. handling for the `counsel-compile' metadata."
  5896. (interactive)
  5897. (delete-minibuffer-contents)
  5898. (let* ((cmd (ivy-state-current ivy-last))
  5899. (blddir (get-text-property 0 'blddir cmd)))
  5900. (when blddir
  5901. (setq counsel-compile--current-build-dir blddir))
  5902. (insert (substring-no-properties
  5903. cmd 0 (and (get-text-property 0 'cmd cmd)
  5904. (next-single-property-change 0 'cmd cmd))))))
  5905. ;; Currently the only thing we do is override ivy's default insert
  5906. ;; operation which doesn't include the metadata we want.
  5907. (defvar counsel-compile-map
  5908. (let ((map (make-sparse-keymap)))
  5909. (define-key map [remap ivy-insert-current] #'counsel-compile-edit-command)
  5910. map)
  5911. "Additional ivy keybindings during command selection.")
  5912. ;;;###autoload
  5913. (defun counsel-compile (&optional dir)
  5914. "Call `compile' completing with smart suggestions, optionally for DIR.
  5915. Additional actions:
  5916. \\{counsel-compile-map}"
  5917. (interactive)
  5918. (setq counsel-compile--current-build-dir (or dir
  5919. (counsel--compile-root)
  5920. default-directory))
  5921. (ivy-read "Compile command: "
  5922. (delete-dups (counsel--get-compile-candidates dir))
  5923. :action #'counsel-compile--action
  5924. :keymap counsel-compile-map
  5925. :caller 'counsel-compile))
  5926. (ivy-add-actions
  5927. 'counsel-compile
  5928. '(("d" counsel-compile-forget-command "delete")))
  5929. (defun counsel-compile-forget-command (cmd)
  5930. "Delete CMD from `counsel-compile-history'."
  5931. (setq counsel-compile-history
  5932. (delete cmd counsel-compile-history)))
  5933. (defun counsel-compile-env--format-hint (cands)
  5934. "Return a formatter for compile-env CANDS."
  5935. (let ((rmstr
  5936. (propertize "remove" 'face 'font-lock-warning-face))
  5937. (addstr
  5938. (propertize "add" 'face 'font-lock-variable-name-face)))
  5939. (ivy--format-function-generic
  5940. (lambda (selected)
  5941. (format "%s %s"
  5942. (if (member selected counsel-compile-env) rmstr addstr)
  5943. selected))
  5944. #'identity
  5945. cands
  5946. "\n")))
  5947. (defun counsel-compile-env--update (var)
  5948. "Update `counsel-compile-env' either adding or removing VAR."
  5949. (cond ((member var counsel-compile-env)
  5950. (setq counsel-compile-env (delete var counsel-compile-env)))
  5951. ((string-match-p counsel-compile-env-pattern var)
  5952. (push var counsel-compile-env))
  5953. (t (user-error "Ignoring malformed variable: '%s'" var))))
  5954. ;;;###autoload
  5955. (defun counsel-compile-env ()
  5956. "Update `counsel-compile-env' interactively."
  5957. (interactive)
  5958. (ivy-read "Compile environment variable: "
  5959. (delete-dups (append
  5960. counsel-compile-env counsel-compile-env-history))
  5961. :action #'counsel-compile-env--update
  5962. :predicate (lambda (cand)
  5963. (string-match-p counsel-compile-env-pattern
  5964. cand))
  5965. :history 'counsel-compile-env-history
  5966. :caller 'counsel-compile-env))
  5967. (ivy-configure 'counsel-compile-env
  5968. :format-fn #'counsel-compile-env--format-hint)
  5969. ;;** `counsel-minor'
  5970. (defvar counsel-minor-history nil
  5971. "History for `counsel-minor'.")
  5972. (defun counsel--minor-candidates ()
  5973. "Return completion alist for `counsel-minor'.
  5974. The alist element is cons of minor mode string with its lighter
  5975. and minor mode symbol."
  5976. (delq nil
  5977. (mapcar
  5978. (lambda (mode)
  5979. (when (and (boundp mode) (commandp mode))
  5980. (let ((lighter (cdr (assq mode minor-mode-alist))))
  5981. (cons (concat
  5982. (if (symbol-value mode) "-" "+")
  5983. (symbol-name mode)
  5984. (propertize
  5985. (if lighter
  5986. (format " \"%s\""
  5987. (format-mode-line (cons t lighter)))
  5988. "")
  5989. 'face font-lock-string-face))
  5990. mode))))
  5991. minor-mode-list)))
  5992. ;;;###autoload
  5993. (defun counsel-minor ()
  5994. "Enable or disable minor mode.
  5995. Disabled minor modes are prefixed with \"+\", and
  5996. selecting one of these will enable it.
  5997. Enabled minor modes are prefixed with \"-\", and
  5998. selecting one of these will enable it.
  5999. Additional actions:\\<ivy-minibuffer-map>
  6000. \\[ivy-dispatching-done] d: Go to minor mode definition
  6001. \\[ivy-dispatching-done] h: Describe minor mode"
  6002. (interactive)
  6003. (ivy-read "Minor modes (enable +mode or disable -mode): "
  6004. (counsel--minor-candidates)
  6005. :require-match t
  6006. :history 'counsel-minor-history
  6007. :action (lambda (x)
  6008. (call-interactively (cdr x)))))
  6009. (ivy-configure 'counsel-minor
  6010. :initial-input "^+"
  6011. :sort-fn #'ivy-string<)
  6012. (ivy-set-actions
  6013. 'counsel-minor
  6014. `(("d" ,(lambda (x) (find-function (cdr x))) "definition")
  6015. ("h" ,(lambda (x) (describe-function (cdr x))) "help")))
  6016. ;;;###autoload
  6017. (defun counsel-major ()
  6018. (interactive)
  6019. (ivy-read "Major modes: " obarray
  6020. :predicate (lambda (f)
  6021. (and (commandp f) (string-match "-mode$" (symbol-name f))
  6022. (or (and (autoloadp (symbol-function f))
  6023. (let ((doc-split (help-split-fundoc (documentation f) f)))
  6024. ;; major mode starters have no arguments
  6025. (and doc-split (null (cdr (read (car doc-split)))))))
  6026. (null (help-function-arglist f)))))
  6027. :action #'counsel-M-x-action
  6028. :caller 'counsel-major))
  6029. ;;** `counsel-search'
  6030. (declare-function request "ext:request")
  6031. (defcustom counsel-search-engine 'ddg
  6032. "The search engine choice in `counsel-search-engines-alist'."
  6033. :type '(choice
  6034. (const ddg)
  6035. (const google)))
  6036. (defcustom counsel-search-engines-alist
  6037. '((google
  6038. "http://suggestqueries.google.com/complete/search"
  6039. "https://www.google.com/search?q="
  6040. counsel--search-request-data-google)
  6041. (ddg
  6042. "https://duckduckgo.com/ac/"
  6043. "https://duckduckgo.com/html/?q="
  6044. counsel--search-request-data-ddg))
  6045. "Search engine parameters for `counsel-search'."
  6046. :type '(list))
  6047. (defun counsel--search-request-data-google (data)
  6048. (mapcar #'identity (aref data 1)))
  6049. (defun counsel--search-request-data-ddg (data)
  6050. (mapcar #'cdar data))
  6051. (defun counsel-search-function (input)
  6052. "Create a request to a search engine with INPUT.
  6053. Return 0 tells `ivy--exhibit' not to update the minibuffer.
  6054. We update it in the callback with `ivy-update-candidates'."
  6055. (or
  6056. (ivy-more-chars)
  6057. (let ((engine (cdr (assoc counsel-search-engine counsel-search-engines-alist))))
  6058. (request
  6059. (nth 0 engine)
  6060. :type "GET"
  6061. :params (list
  6062. (cons "client" "firefox")
  6063. (cons "q" input))
  6064. :parser 'json-read
  6065. :success (cl-function
  6066. (lambda (&key data &allow-other-keys)
  6067. (ivy-update-candidates
  6068. (funcall (nth 2 engine) data)))))
  6069. 0)))
  6070. (defun counsel-search-action (x)
  6071. "Search for X."
  6072. (browse-url
  6073. (concat
  6074. (nth 2 (assoc counsel-search-engine counsel-search-engines-alist))
  6075. (url-hexify-string x))))
  6076. (defun counsel-search ()
  6077. "Ivy interface for dynamically querying a search engine."
  6078. (interactive)
  6079. (require 'request)
  6080. (require 'json)
  6081. (ivy-read "search: " #'counsel-search-function
  6082. :action #'counsel-search-action
  6083. :dynamic-collection t
  6084. :caller 'counsel-search))
  6085. (define-obsolete-function-alias 'counsel-google
  6086. 'counsel-search "<2019-10-17 Thu>")
  6087. ;;** `counsel-compilation-errors'
  6088. (defun counsel--compilation-errors-buffer (buf)
  6089. (with-current-buffer buf
  6090. (let ((res nil)
  6091. (pt (point-min)))
  6092. (save-excursion
  6093. (while (setq pt (compilation-next-single-property-change
  6094. pt 'compilation-message))
  6095. (let ((loc (get-text-property pt 'compilation-message)))
  6096. (when (and loc (setq loc (compilation--message->loc loc)))
  6097. (goto-char pt)
  6098. (push
  6099. (propertize
  6100. (buffer-substring-no-properties pt (line-end-position))
  6101. 'pt pt
  6102. 'buffer buf)
  6103. res)))))
  6104. (nreverse res))))
  6105. (defun counsel-compilation-errors-cands ()
  6106. (cl-loop
  6107. for buf in (buffer-list)
  6108. when (compilation-buffer-p buf)
  6109. nconc (counsel--compilation-errors-buffer buf)))
  6110. (defun counsel-compilation-errors-action (x)
  6111. (pop-to-buffer (get-text-property 0 'buffer x))
  6112. (goto-char (get-text-property 0 'pt x))
  6113. (compile-goto-error))
  6114. ;;;###autoload
  6115. (defun counsel-compilation-errors ()
  6116. "Compilation errors."
  6117. (interactive)
  6118. (ivy-read "compilation errors: " (counsel-compilation-errors-cands)
  6119. :require-match t
  6120. :action #'counsel-compilation-errors-action
  6121. :history 'counsel-compilation-errors-history))
  6122. ;;** `counsel-flycheck'
  6123. (defvar flycheck-current-errors)
  6124. (declare-function flycheck-error-filename "ext:flycheck")
  6125. (declare-function flycheck-error-line "ext:flycheck")
  6126. (declare-function flycheck-error-message "ext:flycheck")
  6127. (declare-function flycheck-jump-to-error "ext:flycheck")
  6128. (defun counsel-flycheck-errors-cands ()
  6129. (mapcar
  6130. (lambda (err)
  6131. (propertize
  6132. (format "%s:%d:%s"
  6133. (file-name-base (flycheck-error-filename err))
  6134. (flycheck-error-line err)
  6135. (flycheck-error-message err)) 'error err))
  6136. flycheck-current-errors))
  6137. (defun counsel-flycheck-occur (cands)
  6138. "Generate a custom occur buffer for `counsel-flycheck'."
  6139. (unless (eq major-mode 'ivy-occur-grep-mode)
  6140. (ivy-occur-grep-mode)
  6141. (setq default-directory (ivy-state-directory ivy-last)))
  6142. (swiper--occur-insert-lines
  6143. (mapcar
  6144. (lambda (cand)
  6145. (let ((err (get-text-property 0 'error cand)))
  6146. (propertize
  6147. (format
  6148. "%s:%d:%s"
  6149. (flycheck-error-filename err)
  6150. (flycheck-error-line err)
  6151. cand)
  6152. 'error err)))
  6153. cands)))
  6154. (defun counsel-flycheck-errors-action (err)
  6155. (flycheck-jump-to-error (get-text-property 0 'error err)))
  6156. (ivy-configure 'counsel-flycheck
  6157. :occur #'counsel-flycheck-occur)
  6158. ;;;###autoload
  6159. (defun counsel-flycheck ()
  6160. "Flycheck errors."
  6161. (interactive)
  6162. (require 'flycheck)
  6163. (ivy-read "flycheck errors: " (counsel-flycheck-errors-cands)
  6164. :require-match t
  6165. :action #'counsel-flycheck-errors-action
  6166. :history 'counsel-flycheck-errors-history))
  6167. ;;* `counsel-mode'
  6168. (defvar counsel-mode-map
  6169. (let ((map (make-sparse-keymap)))
  6170. (dolist (binding
  6171. '((execute-extended-command . counsel-M-x)
  6172. (describe-bindings . counsel-descbinds)
  6173. (describe-function . counsel-describe-function)
  6174. (describe-variable . counsel-describe-variable)
  6175. (describe-symbol . counsel-describe-symbol)
  6176. (apropos-command . counsel-apropos)
  6177. (describe-face . counsel-describe-face)
  6178. (list-faces-display . counsel-faces)
  6179. (find-file . counsel-find-file)
  6180. (find-library . counsel-find-library)
  6181. (imenu . counsel-imenu)
  6182. (load-library . counsel-load-library)
  6183. (load-theme . counsel-load-theme)
  6184. (yank-pop . counsel-yank-pop)
  6185. (info-lookup-symbol . counsel-info-lookup-symbol)
  6186. (pop-to-mark-command . counsel-mark-ring)
  6187. (geiser-doc-look-up-manual . counsel-geiser-doc-look-up-manual)
  6188. (bookmark-jump . counsel-bookmark)))
  6189. (define-key map (vector 'remap (car binding)) (cdr binding)))
  6190. map)
  6191. "Map for `counsel-mode'.
  6192. Remaps built-in functions to counsel replacements.")
  6193. (defcustom counsel-mode-override-describe-bindings nil
  6194. "Whether to override `describe-bindings' when `counsel-mode' is active."
  6195. :type 'boolean)
  6196. ;;;###autoload
  6197. (define-minor-mode counsel-mode
  6198. "Toggle Counsel mode on or off.
  6199. Turn Counsel mode on if ARG is positive, off otherwise. Counsel
  6200. mode remaps built-in emacs functions that have counsel
  6201. replacements.
  6202. Local bindings (`counsel-mode-map'):
  6203. \\{counsel-mode-map}"
  6204. :global t
  6205. :keymap counsel-mode-map
  6206. :lighter " counsel"
  6207. (if counsel-mode
  6208. (progn
  6209. (when counsel-mode-override-describe-bindings
  6210. (advice-add #'describe-bindings :override #'counsel-descbinds))
  6211. (define-key minibuffer-local-map (kbd "C-r")
  6212. 'counsel-minibuffer-history))
  6213. (advice-remove #'describe-bindings #'counsel-descbinds)))
  6214. (provide 'counsel)
  6215. ;;; counsel.el ends here