[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/counsel ad0e98e 1/2: Merge branch 'master' into externa
From: |
Basil L. Contovounesios |
Subject: |
[elpa] externals/counsel ad0e98e 1/2: Merge branch 'master' into externals/counsel |
Date: |
Tue, 9 Mar 2021 14:40:00 -0500 (EST) |
branch: externals/counsel
commit ad0e98ee4f11695e8ee3d6c9768c3f0e6d991791
Merge: 52b9abf e005666
Author: Basil L. Contovounesios <contovob@tcd.ie>
Commit: Basil L. Contovounesios <contovob@tcd.ie>
Merge branch 'master' into externals/counsel
---
.dir-locals.el | 2 +-
counsel.el | 2012 +++++++++++++++++++++++++++++++++++++++++---------------
2 files changed, 1488 insertions(+), 526 deletions(-)
diff --git a/.dir-locals.el b/.dir-locals.el
index 3d5e818..4e7d231 100644
--- a/.dir-locals.el
+++ b/.dir-locals.el
@@ -8,7 +8,7 @@
(sentence-end-double-space . t))
(emacs-lisp-mode
(indent-tabs-mode . nil)
- (outline-regexp . ";;[;*]+[\s\t]+")
+ (outline-regexp . ";;\\([;*]+ [^\s\t\n]\\|###autoload\\)\\|(")
;; extra config here:
https://github.com/abo-abo/oremacs/blob/github/modes/ora-elisp-style-guide.el
;; (lisp-indent-function . common-lisp-indent-function)
))
diff --git a/counsel.el b/counsel.el
index 3cb817f..fe48bac 100644
--- a/counsel.el
+++ b/counsel.el
@@ -1,11 +1,11 @@
;;; counsel.el --- Various completion functions using Ivy -*- lexical-binding:
t -*-
-;; Copyright (C) 2015-2019 Free Software Foundation, Inc.
+;; Copyright (C) 2015-2021 Free Software Foundation, Inc.
;; Author: Oleh Krehel <ohwoeowho@gmail.com>
;; URL: https://github.com/abo-abo/swiper
-;; Version: 0.13.1
-;; Package-Requires: ((emacs "24.5") (swiper "0.13.1"))
+;; Version: 0.13.2
+;; Package-Requires: ((emacs "24.5") (ivy "0.13.2") (swiper "0.13.2"))
;; Keywords: convenience, matching, tools
;; This file is part of GNU Emacs.
@@ -40,10 +40,15 @@
;;; Code:
+(require 'ivy)
(require 'swiper)
+
(require 'compile)
(require 'dired)
+(eval-when-compile
+ (require 'subr-x))
+
(defgroup counsel nil
"Completion functions using Ivy."
:group 'matching
@@ -110,17 +115,25 @@ complex regexes."
str)
str))
+(defalias 'counsel--executable-find
+ ;; Gained optional argument in 27.1.
+ (if (>= emacs-major-version 27)
+ #'executable-find
+ (lambda (command &optional _remote)
+ (executable-find command)))
+ "Compatibility shim for `executable-find'.")
+
(defun counsel-require-program (cmd)
"Check system for program used in CMD, printing error if not found.
CMD is either a string or a list of strings.
To skip the `executable-find' check, start the string with a space."
- (unless (and (stringp cmd) (string-match-p "^ " cmd))
+ (unless (and (stringp cmd) (string-prefix-p " " cmd))
(let ((program (if (listp cmd)
(car cmd)
(car (split-string cmd)))))
(or (and (stringp program)
(not (string= program ""))
- (executable-find program))
+ (counsel--executable-find program t))
(user-error "Required program \"%s\" not found in your path"
program)))))
(declare-function eshell-split-path "esh-util")
@@ -135,14 +148,44 @@ To skip the `executable-find' check, start the string
with a space."
(replace-regexp-in-string ; Insert dir before any trailing colon.
"\\(?:: ?\\)?\\'" dir (ivy-state-prompt ivy-last) t t))))
+(defalias 'counsel--flatten
+ ;; Added in Emacs 27.1
+ (if (fboundp 'flatten-tree)
+ #'flatten-tree
+ (lambda (tree)
+ (let (elems)
+ (while (consp tree)
+ (let ((elem (pop tree)))
+ (while (consp elem)
+ (push (cdr elem) tree)
+ (setq elem (car elem)))
+ (if elem (push elem elems))))
+ (if tree (push tree elems))
+ (nreverse elems))))
+ "Compatibility shim for `flatten-tree'.")
+
+(defun counsel--format (formatter &rest args)
+ "Like `format' but FORMATTER can be a list.
+When FORMATTER is a list, only `%s' is replaced with ARGS.
+
+Return a list or string depending on input."
+ (cond
+ ((listp formatter)
+ (counsel--flatten (mapcar
+ (lambda (it) (if (equal it "%s") (pop args) it))
+ formatter)))
+ (t (apply #'format formatter args))))
+
;;* Async Utility
(defvar counsel--async-time nil
"Store the time when a new process was started.
Or the time of the last minibuffer update.")
(defvar counsel--async-start nil
- "Store the time when a new process was started.
-Or the time of the last minibuffer update.")
+ "Store the time when a new process was started.")
+
+(defvar counsel--async-timer nil
+ "Timer used to dispose `counsel--async-command.")
(defvar counsel--async-duration nil
"Store the time a process takes to gather all its candidates.
@@ -164,16 +207,16 @@ descriptions.")
cmd
(plist-put plist number str)))))
-(defvar counsel-async-split-string-re-alist '((t . "\n"))
+(defvar counsel-async-split-string-re-alist '((t . "[\r\n]"))
"Store the regexp for splitting shell command output.")
(defvar counsel-async-ignore-re-alist nil
"An alist of regexp matching candidates to ignore in
`counsel--async-filter'.")
(defvar counsel--async-last-command nil
- "Store the last command ran by `counsel--async-command'.")
+ "Store the last command ran by `counsel--async-command-1'.")
-(defun counsel--async-command (cmd &optional sentinel filter name)
+(defun counsel--async-command-1 (cmd &optional sentinel filter name)
"Start and return new counsel process by calling CMD.
CMD can be either a shell command as a string, or a list of the
program name to be called directly, followed by its arguments.
@@ -197,48 +240,76 @@ respectively."
(set-process-filter proc (or filter #'counsel--async-filter))
proc))
+(defcustom counsel-async-command-delay 0
+ "Number of seconds to wait before spawning another async command."
+ :type 'number)
+
+(defun counsel--async-command (&rest args)
+ "Like `counsel--async-command-1', with same ARGS, but debounced.
+Calls to `counsel--async-command-1' are separated by at least
+`counsel-async-command-delay' seconds, so as to avoid issues
+caused by spawning too many subprocesses too quickly."
+ (if (zerop counsel-async-command-delay)
+ (apply #'counsel--async-command-1 args)
+ (when counsel--async-timer
+ (cancel-timer counsel--async-timer))
+ (setq counsel--async-timer
+ (apply #'run-with-timer
+ counsel-async-command-delay
+ nil
+ #'counsel--async-command-1
+ args))))
+
(defun counsel--split-string (&optional str)
(split-string
(or str (buffer-string))
(ivy-alist-setting counsel-async-split-string-re-alist)
t))
+(defun counsel--sync-sentinel-on-exit (process)
+ (if (zerop (process-exit-status process))
+ (let ((cur (ivy-state-current ivy-last)))
+ (ivy--set-candidates
+ (ivy--sort-maybe
+ (with-current-buffer (process-buffer process)
+ (counsel--split-string))))
+ (when counsel--async-start
+ (setq counsel--async-duration
+ (time-to-seconds (time-since counsel--async-start))))
+ (let ((re (ivy-re-to-str ivy-regex)))
+ (if ivy--old-cands
+ (if (eq (ivy-alist-setting ivy-index-functions-alist)
'ivy-recompute-index-zero)
+ (ivy-set-index 0)
+ (ivy--recompute-index re ivy--all-candidates))
+ ;; index was changed before a long-running query exited
+ (unless (string= cur (nth ivy--index ivy--all-candidates))
+ (let ((func (ivy-alist-setting ivy-index-functions-alist)))
+ (if func
+ (funcall func re ivy--all-candidates)
+ (ivy--preselect-index
+ (if (> (length re) 0)
+ cur
+ (ivy-state-preselect ivy-last))
+ ivy--all-candidates))))))
+ (setq ivy--old-cands ivy--all-candidates)
+ (if ivy--all-candidates
+ (ivy--exhibit)
+ (ivy--insert-minibuffer "")))
+ (setq counsel--async-last-error-string
+ (with-current-buffer (process-buffer process) (buffer-string)))
+ (setq ivy--all-candidates
+ (let ((status (process-exit-status process))
+ (plist (plist-get counsel--async-exit-code-plist
+ (ivy-state-caller ivy-last))))
+ (list (or (plist-get plist status)
+ (format "error code %d" status)))))
+ (setq ivy--old-cands ivy--all-candidates)
+ (ivy--exhibit)))
+
(defun counsel--async-sentinel (process _msg)
"Sentinel function for an asynchronous counsel PROCESS."
(when (eq (process-status process) 'exit)
- (if (zerop (process-exit-status process))
- (progn
- (ivy--set-candidates
- (ivy--sort-maybe
- (with-current-buffer (process-buffer process)
- (counsel--split-string))))
- (when counsel--async-start
- (setq counsel--async-duration
- (time-to-seconds (time-since counsel--async-start))))
- (let ((re (ivy-re-to-str (funcall ivy--regex-function ivy-text))))
- (if ivy--old-cands
- (if (eq (ivy-alist-setting ivy-index-functions-alist)
'ivy-recompute-index-zero)
- (ivy-set-index 0)
- (ivy--recompute-index ivy-text re ivy--all-candidates))
- (unless (ivy-set-index
- (ivy--preselect-index
- (ivy-state-preselect ivy-last)
- ivy--all-candidates))
- (ivy--recompute-index ivy-text re ivy--all-candidates))))
- (setq ivy--old-cands ivy--all-candidates)
- (if ivy--all-candidates
- (ivy--exhibit)
- (ivy--insert-minibuffer "")))
- (setq counsel--async-last-error-string
- (with-current-buffer (process-buffer process) (buffer-string)))
- (setq ivy--all-candidates
- (let ((status (process-exit-status process))
- (plist (plist-get counsel--async-exit-code-plist
- (ivy-state-caller ivy-last))))
- (list (or (plist-get plist status)
- (format "error code %d" status)))))
- (setq ivy--old-cands ivy--all-candidates)
- (ivy--exhibit))))
+ (counsel--sync-sentinel-on-exit process)))
(defcustom counsel-async-filter-update-time 500000
"The amount of microseconds to wait until updating `counsel--async-filter'."
@@ -274,113 +345,10 @@ Update the minibuffer with the amount of lines collected
every
(delete-process process))))
;;* Completion at point
-;;** `counsel-el'
-;;;###autoload
-(defun counsel-el ()
- "Elisp completion at point."
- (interactive)
- (let* ((bnd (unless (and (looking-at ")")
- (eq (char-before) ?\())
- (bounds-of-thing-at-point 'symbol)))
- (str (if bnd
- (buffer-substring-no-properties
- (car bnd)
- (cdr bnd))
- ""))
- (pred (and (eq (char-before (car bnd)) ?\()
- #'fboundp))
- symbol-names)
- (setq ivy-completion-beg (car bnd))
- (setq ivy-completion-end (cdr bnd))
- (if (string= str "")
- (mapatoms
- (lambda (x)
- (when (and (symbolp x) (funcall pred x))
- (push (symbol-name x) symbol-names))))
- (setq symbol-names (all-completions str obarray pred)))
- (ivy-read "Symbol name: " symbol-names
- :initial-input str
- :action #'ivy-completion-in-region-action
- :caller 'counsel-el)))
-
-(ivy-configure 'counsel-el
- :height 7)
-
-;;** `counsel-cl'
-(declare-function slime-symbol-start-pos "ext:slime")
-(declare-function slime-symbol-end-pos "ext:slime")
-(declare-function slime-contextual-completions "ext:slime-c-p-c")
-
-;;;###autoload
-(defun counsel-cl ()
- "Common Lisp completion at point."
- (interactive)
- (setq ivy-completion-beg (slime-symbol-start-pos))
- (setq ivy-completion-end (slime-symbol-end-pos))
- (ivy-read "Symbol name: "
- (car (slime-contextual-completions
- ivy-completion-beg
- ivy-completion-end))
- :action #'ivy-completion-in-region-action))
-
-;;** `counsel-jedi'
-(declare-function deferred:sync! "ext:deferred")
-(declare-function jedi:complete-request "ext:jedi-core")
-(declare-function jedi:ac-direct-matches "ext:jedi")
-
-;;;###autoload
-(defun counsel-jedi ()
- "Python completion at point."
- (interactive)
- (let ((bnd (bounds-of-thing-at-point 'symbol)))
- (setq ivy-completion-beg (car bnd))
- (setq ivy-completion-end (cdr bnd)))
- (deferred:sync!
- (jedi:complete-request))
- (ivy-read "Symbol name: " (jedi:ac-direct-matches)
- :action #'counsel--py-action))
-
-(defun counsel--py-action (symbol-name)
- "Insert SYMBOL-NAME, erasing the previous one."
- (when (stringp symbol-name)
- (with-ivy-window
- (when ivy-completion-beg
- (delete-region
- ivy-completion-beg
- ivy-completion-end))
- (setq ivy-completion-beg (point))
- (insert symbol-name)
- (setq ivy-completion-end (point)))))
-
-;;** `counsel-clj'
-(declare-function cider-sync-request:complete "ext:cider-client")
-(defun counsel--generic (completion-fn)
- "Complete thing at point with COMPLETION-FN."
- (let* ((bnd (or (bounds-of-thing-at-point 'symbol)
- (cons (point) (point))))
- (str (buffer-substring-no-properties
- (car bnd) (cdr bnd)))
- (candidates (funcall completion-fn str))
- (res (ivy-read (format "pattern (%s): " str)
- candidates
- :caller 'counsel--generic)))
- (when (stringp res)
- (when bnd
- (delete-region (car bnd) (cdr bnd)))
- (insert res))))
-
-(ivy-configure 'counsel--generic
- :height 7)
-
-;;;###autoload
-(defun counsel-clj ()
- "Clojure completion at point."
- (interactive)
- (counsel--generic
- (lambda (str)
- (mapcar
- #'cl-caddr
- (cider-sync-request:complete str ":same")))))
+(define-obsolete-function-alias 'counsel-el 'complete-symbol "<2020-05-20
Wed>")
+(define-obsolete-function-alias 'counsel-cl 'complete-symbol "<2020-05-20
Wed>")
+(define-obsolete-function-alias 'counsel-jedi 'complete-symbol "<2020-05-20
Wed>")
+(define-obsolete-function-alias 'counsel-clj 'complete-symbol "<2020-05-20
Wed>")
;;** `counsel-company'
(defvar company-candidates)
@@ -389,6 +357,8 @@ Update the minibuffer with the amount of lines collected
every
(declare-function company-abort "ext:company")
(declare-function company-complete "ext:company")
(declare-function company-mode "ext:company")
+(declare-function company-call-backend "ext:company")
+(declare-function company--clean-string "ext:company")
;;;###autoload
(defun counsel-company ()
@@ -397,8 +367,13 @@ Update the minibuffer with the amount of lines collected
every
(company-mode 1)
(unless company-candidates
(company-complete))
- (let ((len (cond (company-common
- (length company-common))
+ (let ((len (cond ((let (l)
+ (and company-common
+ (string= company-common
+ (buffer-substring
+ (- (point) (setq l (length
company-common)))
+ (point)))
+ l)))
(company-prefix
(length company-prefix)))))
(when len
@@ -409,8 +384,14 @@ Update the minibuffer with the amount of lines collected
every
:caller 'counsel-company))))
(ivy-configure 'counsel-company
+ :display-transformer-fn #'counsel--company-display-transformer
:unwind-fn #'company-abort)
+(defun counsel--company-display-transformer (s)
+ (concat s (let ((annot (company-call-backend 'annotation s)))
+ (when annot
+ (company--clean-string annot)))))
+
;;** `counsel-irony'
(declare-function irony-completion-candidates-async "ext:irony-completion")
(declare-function irony-completion-symbol-bounds "ext:irony-completion")
@@ -442,7 +423,8 @@ Update the minibuffer with the amount of lines collected
every
(cons (concat (car x) (irony-completion-annotation x))
(car x)))
-(add-to-list 'ivy-display-functions-alist '(counsel-irony .
ivy-display-function-overlay))
+(ivy-configure #'counsel-irony
+ :display-fn #'ivy-display-function-overlay)
;;* Elisp symbols
;;** `counsel-describe-variable'
@@ -459,8 +441,8 @@ Update the minibuffer with the amount of lines collected
every
(defvar counsel-describe-symbol-history ()
"History list for variable and function names.
-Used by commands `counsel-describe-variable' and
-`counsel-describe-function'.")
+Used by commands `counsel-describe-symbol',
+`counsel-describe-variable', and `counsel-describe-function'.")
(defun counsel-find-symbol ()
"Jump to the definition of the current symbol."
@@ -477,6 +459,7 @@ Used by commands `counsel-describe-variable' and
(declare-function xref-push-marker-stack "xref")
(defalias 'counsel--push-xref-marker
+ ;; Added in Emacs 25.1.
(if (require 'xref nil t)
#'xref-push-marker-stack
(require 'etags)
@@ -544,9 +527,8 @@ Variables declared using `defcustom' are highlighted
according to
:caller 'counsel-describe-variable)))
(ivy-configure 'counsel-describe-variable
- :initial-input "^"
- :display-transformer-fn #'counsel-describe-variable-transformer
- :sort-fn #'ivy-string<)
+ :parent 'counsel-describe-symbol
+ :display-transformer-fn #'counsel-describe-variable-transformer)
;;** `counsel-describe-function'
(ivy-set-actions
@@ -595,10 +577,44 @@ to `ivy-highlight-face'."
:caller 'counsel-describe-function)))
(ivy-configure 'counsel-describe-function
+ :parent 'counsel-describe-symbol
+ :display-transformer-fn #'counsel-describe-function-transformer)
+
+;;** `counsel-describe-symbol'
+(defcustom counsel-describe-symbol-function #'describe-symbol
+ "Function to call to describe a symbol passed as parameter."
+ :type 'function)
+
+;;;###autoload
+(defun counsel-describe-symbol ()
+ "Forward to `describe-symbol'."
+ (interactive)
+ (unless (functionp 'describe-symbol)
+ (user-error "This command requires Emacs 25.1 or later"))
+ (require 'help-mode)
+ (let ((enable-recursive-minibuffers t))
+ (ivy-read "Describe symbol: " obarray
+ :predicate (lambda (sym)
+ (cl-some (lambda (backend)
+ (funcall (cadr backend) sym))
+ describe-symbol-backends))
+ :require-match t
+ :history 'counsel-describe-symbol-history
+ :keymap counsel-describe-map
+ :preselect (ivy-thing-at-point)
+ :action (lambda (x)
+ (funcall counsel-describe-symbol-function (intern x)))
+ :caller 'counsel-describe-symbol)))
+
+(ivy-configure 'counsel-describe-symbol
:initial-input "^"
- :display-transformer-fn #'counsel-describe-function-transformer
:sort-fn #'ivy-string<)
+(ivy-set-actions
+ 'counsel-describe-symbol
+ `(("I" ,#'counsel-info-lookup-symbol "info")
+ ("d" ,#'counsel--find-symbol "definition")))
+
;;** `counsel-set-variable'
(defvar counsel-set-variable-history nil
"Store history for `counsel-set-variable'.")
@@ -606,26 +622,35 @@ to `ivy-highlight-face'."
(defun counsel-read-setq-expression (sym)
"Read and eval a setq expression for SYM."
(setq this-command 'eval-expression)
- (let* ((minibuffer-completing-symbol t)
- (sym-value (symbol-value sym))
- (expr (minibuffer-with-setup-hook
- (lambda ()
- (add-function :before-until (local
'eldoc-documentation-function)
- #'elisp-eldoc-documentation-function)
- (add-hook 'completion-at-point-functions
#'elisp-completion-at-point nil t)
- (run-hooks 'eval-expression-minibuffer-setup-hook)
- (goto-char (minibuffer-prompt-end))
- (forward-char 6)
- (insert (format "%S " sym)))
- (read-from-minibuffer "Eval: "
- (format
- (if (and sym-value (consp sym-value))
- "(setq '%S)"
- "(setq %S)")
- sym-value)
- read-expression-map t
- 'read-expression-history))))
- (eval-expression expr)))
+ (let* ((sym-value (symbol-value sym))
+ (init (format "(setq %s%S)"
+ (if (or (consp sym-value)
+ (and sym-value (symbolp sym-value)))
+ "'"
+ "")
+ sym-value)))
+ ;; Most of this duplicates `read--expression'.
+ (minibuffer-with-setup-hook
+ (lambda ()
+ (set-syntax-table emacs-lisp-mode-syntax-table)
+ ;; Added in Emacs 25.1.
+ (when (fboundp 'elisp-completion-at-point)
+ (add-hook 'completion-at-point-functions
+ #'elisp-completion-at-point nil t))
+ ;; Emacs 27+ already sets up ElDoc in this hook. Emacs 25 added
+ ;; `elisp-eldoc-documentation-function' and Emacs 28 obsoletes it.
+ (when (< emacs-major-version 27)
+ (when (fboundp 'elisp-eldoc-documentation-function)
+ (add-function :before-until (local 'eldoc-documentation-function)
+ #'elisp-eldoc-documentation-function))
+ (eldoc-mode))
+ (run-hooks 'eval-expression-minibuffer-setup-hook)
+ ;; The following diverges from `read--expression'.
+ (goto-char (minibuffer-prompt-end))
+ (forward-char 6)
+ (insert (format "%S " sym)))
+ (read-from-minibuffer "Eval: " init read-expression-map t
+ 'read-expression-history))))
(defun counsel--setq-doconst (x)
"Return a cons of description and value for X.
@@ -702,12 +727,15 @@ With a prefix arg, restrict list to variables defined
using
(if (assoc res cands)
(cdr (assoc res cands))
(read res)))
+ (kill-new (format "(setq %S %S)" sym res))
(set sym (if (and (listp res) (eq (car res) 'quote))
(cadr res)
res))))
(unless (boundp sym)
(set sym nil))
- (counsel-read-setq-expression sym)))
+ (let ((expr (counsel-read-setq-expression sym)))
+ (kill-new (format "%S" expr))
+ (eval-expression expr))))
(when doc
(lv-delete-window)))))
@@ -853,6 +881,23 @@ packages are, in order of precedence, `amx' and `smex'."
(smex-update))
smex-ido-cache)))
+(defun counsel--M-x-externs-predicate (cand)
+ "Return non-nil if `counsel-M-x' should complete CAND.
+CAND is a string returned by `counsel--M-x-externs'."
+ (not (get (intern cand) 'no-counsel-M-x)))
+
+(defun counsel--M-x-make-predicate ()
+ "Return a predicate for `counsel-M-x' in the current buffer."
+ (defvar read-extended-command-predicate)
+ (let ((buf (current-buffer)))
+ (lambda (sym)
+ (and (commandp sym)
+ (not (get sym 'byte-obsolete-info))
+ (not (get sym 'no-counsel-M-x))
+ (or (not (bound-and-true-p read-extended-command-predicate))
+ (and (functionp read-extended-command-predicate)
+ (funcall read-extended-command-predicate sym buf)))))))
+
(defun counsel--M-x-prompt ()
"String for `M-x' plus the string representation of `current-prefix-arg'."
(concat (cond ((null current-prefix-arg)
@@ -872,7 +917,8 @@ packages are, in order of precedence, `amx' and `smex'."
(defun counsel-M-x-action (cmd)
"Execute CMD."
- (setq cmd (intern cmd))
+ (setq cmd (intern
+ (subst-char-in-string ?\s ?- (string-remove-prefix "^" cmd))))
(cond ((bound-and-true-p amx-initialized)
(amx-rank cmd))
((bound-and-true-p smex-initialized-p)
@@ -897,12 +943,8 @@ when available, in that order of precedence."
(let ((externs (counsel--M-x-externs)))
(ivy-read (counsel--M-x-prompt) (or externs obarray)
:predicate (if externs
- (lambda (x)
- (not (get (intern x) 'no-counsel-M-x)))
- (lambda (sym)
- (and (commandp sym)
- (not (get sym 'byte-obsolete-info))
- (not (get sym 'no-counsel-M-x)))))
+ #'counsel--M-x-externs-predicate
+ (counsel--M-x-make-predicate))
:require-match t
:history 'counsel-M-x-history
:action #'counsel-M-x-action
@@ -1079,17 +1121,17 @@ See `describe-buffer-bindings' for further information."
(describe-buffer-bindings buffer prefix))
(goto-char (point-min))
;; Skip the "Key translations" section
- (re-search-forward "")
- (forward-char 1)
+ (skip-chars-forward "^\C-l")
+ (forward-char 2)
(while (not (eobp))
(when (looking-at "^\\([^\t\n]+\\)[\t ]*\\(.*\\)$")
(let ((key (match-string 1))
(fun (match-string 2))
cmd)
(unless (or (member fun '("??" "self-insert-command"))
- (string-match re-exclude key)
+ (string-match-p re-exclude key)
(not (or (commandp (setq cmd (intern-soft fun)))
- (member fun '("Prefix Command")))))
+ (equal fun "Prefix Command"))))
(push
(cons (format
"%-15s %s"
@@ -1097,7 +1139,7 @@ See `describe-buffer-bindings' for further information."
fun)
(cons key cmd))
res))))
- (forward-line 1)))
+ (forward-line)))
(nreverse res)))
(defcustom counsel-descbinds-function #'describe-function
@@ -1173,6 +1215,15 @@ back to the face of the character after point, and
finally the
"Customize face with NAME in another window."
(customize-face-other-window (intern name)))
+(declare-function hi-lock-set-pattern "hi-lock")
+(defun counsel-highlight-with-face (face)
+ "Highlight thing-at-point with FACE."
+ (hi-lock-mode 1)
+ (let ((thing (ivy-thing-at-point)))
+ (when (use-region-p)
+ (deactivate-mark))
+ (hi-lock-set-pattern (regexp-quote thing) (intern face))))
+
(ivy-set-actions
'counsel-describe-face
'(("c" counsel-customize-face "customize")
@@ -1211,17 +1262,18 @@ selected face."
:caller 'counsel-faces)))
(ivy-configure 'counsel-faces
- :sort-fn #'ivy-string<
+ :parent 'counsel-describe-face
:format-fn #'counsel--faces-format-function)
(ivy-set-actions
'counsel-faces
'(("c" counsel-customize-face "customize")
- ("C" counsel-customize-face-other-window "customize other window")))
+ ("C" counsel-customize-face-other-window "customize other window")
+ ("h" counsel-highlight-with-face "highlight")))
;;* Git
;;** `counsel-git'
-(defvar counsel-git-cmd "git ls-files --full-name --"
+(defvar counsel-git-cmd "git ls-files -z --full-name --"
"Command for `counsel-git'.")
(ivy-set-actions
@@ -1241,11 +1293,11 @@ Like `locate-dominating-file', but DIR defaults to
(or (counsel--git-root)
(error "Not in a Git repository")))
-(defun counsel-git-cands ()
- (let ((default-directory (counsel-locate-git-root)))
+(defun counsel-git-cands (dir)
+ (let ((default-directory dir))
(split-string
(shell-command-to-string counsel-git-cmd)
- "\n"
+ "\0"
t)))
;;;###autoload
@@ -1255,7 +1307,7 @@ INITIAL-INPUT can be given as the initial minibuffer
input."
(interactive)
(counsel-require-program counsel-git-cmd)
(let ((default-directory (counsel-locate-git-root)))
- (ivy-read "Find file: " (counsel-git-cands)
+ (ivy-read "Find file: " (counsel-git-cands default-directory)
:initial-input initial-input
:action #'counsel-git-action
:caller 'counsel-git)))
@@ -1275,7 +1327,7 @@ INITIAL-INPUT can be given as the initial minibuffer
input."
(counsel-cmd-to-dired
(counsel--expand-ls
(format "%s | %s | xargs ls"
- counsel-git-cmd
+ (replace-regexp-in-string "\\(-0\\)\\|\\(-z\\)" "" counsel-git-cmd)
(counsel--file-name-filter)))))
(defvar counsel-dired-listing-switches "-alh"
@@ -1316,7 +1368,7 @@ INITIAL-INPUT can be given as the initial minibuffer
input."
(define-key map (kbd "C-x C-d") 'counsel-cd)
map))
-(defvar counsel-git-grep-cmd-default "git --no-pager grep --full-name -n
--no-color -i -I -e \"%s\""
+(defvar counsel-git-grep-cmd-default "git --no-pager grep -n --no-color -I -e
\"%s\""
"Initial command for `counsel-git-grep'.")
(defvar counsel-git-grep-cmd nil
@@ -1335,7 +1387,8 @@ Typical value: '(recenter)."
:type 'hook)
(defcustom counsel-git-grep-cmd-function
#'counsel-git-grep-cmd-function-default
- "How a git-grep shell call is built from the input."
+ "How a git-grep shell call is built from the input.
+This function should set `ivy--old-re'."
:type '(radio
(function-item counsel-git-grep-cmd-function-default)
(function-item counsel-git-grep-cmd-function-ignore-order)
@@ -1362,7 +1415,9 @@ Typical value: '(recenter)."
(ivy-more-chars)
(progn
(counsel--async-command
- (funcall counsel-git-grep-cmd-function string))
+ (concat
+ (funcall counsel-git-grep-cmd-function string)
+ (if (ivy--case-fold-p string) " -i" "")))
nil)))
(defun counsel-git-grep-action (x)
@@ -1385,14 +1440,12 @@ Typical value: '(recenter)."
(swiper--add-overlays (ivy--regex ivy-text))))))
(defun counsel-git-grep-transformer (str)
- "Higlight file and line number in STR."
+ "Highlight file and line number in STR."
(when (string-match "\\`\\([^:]+\\):\\([^:]+\\):" str)
- (ivy-add-face-text-property (match-beginning 1) (match-end 1)
- 'ivy-grep-info
- str)
- (ivy-add-face-text-property (match-beginning 2) (match-end 2)
- 'ivy-grep-line-number
- str))
+ (add-face-text-property (match-beginning 1) (match-end 1)
+ 'ivy-grep-info nil str)
+ (add-face-text-property (match-beginning 2) (match-end 2)
+ 'ivy-grep-line-number nil str))
str)
(defvar counsel-git-grep-projects-alist nil
@@ -1495,12 +1548,36 @@ When CMD is non-nil, prompt for a specific \"git grep\"
command."
:keymap counsel-git-grep-map
:action #'counsel-git-grep-action
:history 'counsel-git-grep-history
+ :require-match t
:caller 'counsel-git-grep))))
+(defun counsel--git-grep-index (_re-str cands)
+ (let (name ln)
+ (cond
+ (ivy--old-cands
+ (ivy-recompute-index-swiper-async nil cands))
+ ((unless (with-ivy-window
+ (when buffer-file-name
+ (setq ln (line-number-at-pos))
+ (setq name (file-name-nondirectory buffer-file-name))))
+ 0))
+ ;; Closest to current line going forwards.
+ ((let ((beg (1+ (length name))))
+ (cl-position-if (lambda (x)
+ (and (string-prefix-p name x)
+ (>= (string-to-number (substring x beg)) ln)))
+ cands)))
+ ;; Closest to current line going backwards.
+ ((cl-position-if (lambda (x)
+ (string-prefix-p name x))
+ cands
+ :from-end t))
+ (t 0))))
+
(ivy-configure 'counsel-git-grep
:occur #'counsel-git-grep-occur
:unwind-fn #'counsel--grep-unwind
- :index-fn #'ivy-recompute-index-swiper-async
+ :index-fn #'counsel--git-grep-index
:display-transformer-fn #'counsel-git-grep-transformer
:grep-p t
:exit-codes '(1 "No matches found"))
@@ -1511,7 +1588,10 @@ When CMD is non-nil, prompt for a specific \"git grep\"
command."
(ivy-more-chars)
(let ((regex (setq ivy--old-re
(ivy--regex str t))))
- (counsel--async-command (format counsel-git-grep-cmd regex))
+ (counsel--async-command
+ (concat
+ (format counsel-git-grep-cmd regex)
+ (if (ivy--case-fold-p str) " -i" "")))
nil)))
(defun counsel-git-grep-switch-cmd ()
@@ -1539,10 +1619,7 @@ When CMD is non-nil, prompt for a specific \"git grep\"
command."
str)
(defun counsel--git-grep-occur-cmd (input)
- (let* ((regex (funcall ivy--regex-function input))
- (regex (if (eq ivy--regex-function #'ivy--regex-fuzzy)
- (replace-regexp-in-string "\n" "" regex)
- regex))
+ (let* ((regex ivy--old-re)
(positive-pattern (replace-regexp-in-string
;; git-grep can't handle .*?
"\\.\\*\\?" ".*"
@@ -1554,7 +1631,10 @@ When CMD is non-nil, prompt for a specific \"git grep\"
command."
(format "| grep -v %s" (car x))))
regex
" "))))
- (concat (format counsel-git-grep-cmd positive-pattern) negative-patterns)))
+ (concat
+ (format counsel-git-grep-cmd positive-pattern)
+ negative-patterns
+ (if (ivy--case-fold-p input) " -i" ""))))
(defun counsel-git-grep-occur (&optional _cands)
"Generate a custom occur buffer for `counsel-git-grep'."
@@ -1607,16 +1687,16 @@ done") "\n" t)))
:caller 'counsel-git-stash)))
;;** `counsel-git-log'
-(defvar counsel-git-log-cmd "GIT_PAGER=cat git log --grep '%s'"
+(defvar counsel-git-log-cmd "GIT_PAGER=cat git log --no-color --grep '%s'"
"Command used for \"git log\".")
-(defun counsel-git-log-function (str)
- "Search for STR in git log."
+(defun counsel-git-log-function (_)
+ "Search for `ivy-regex' in git log."
(or
(ivy-more-chars)
(progn
;; `counsel--yank-pop-format-function' uses this
- (setq ivy--old-re (funcall ivy--regex-function str))
+ (setq ivy--old-re ivy-regex)
(counsel--async-command
;; "git log --grep" likes to have groups quoted e.g. \(foo\).
;; But it doesn't like the non-greedy ".*?".
@@ -1682,7 +1762,7 @@ TREE is the selected candidate."
(ivy-read "Select worktree: "
(or (cl-delete default-directory (counsel-git-worktree-list)
:key #'counsel-git-worktree-parse-root :test
#'string=)
- (error "No other worktrees!"))
+ (error "No other worktrees"))
:action (lambda (tree)
(counsel-git-change-worktree-action
(ivy-state-directory ivy-last) tree))
@@ -1748,9 +1828,17 @@ currently checked out."
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-DEL") 'counsel-up-directory)
(define-key map (kbd "C-<backspace>") 'counsel-up-directory)
- (define-key map (kbd "`") (ivy-make-magic-action 'counsel-find-file "b"))
+ (define-key map (kbd "`") #'counsel-file-jump-from-find)
+ (define-key map (kbd "C-`") (ivy-make-magic-action 'counsel-find-file "b"))
+ (define-key map [remap undo] 'counsel-find-file-undo)
map))
+(defun counsel-file-jump-from-find ()
+ "Switch to `counsel-file-jump' from `counsel-find-file'."
+ (interactive)
+ (ivy-quit-and-run
+ (counsel-file-jump ivy-text (ivy-state-directory ivy-last))))
+
(when (executable-find "git")
(add-to-list 'ivy-ffap-url-functions 'counsel-github-url-p)
(add-to-list 'ivy-ffap-url-functions 'counsel-emacs-url-p))
@@ -1848,6 +1936,7 @@ choose between `yes-or-no-p' and `y-or-n-p'; otherwise
default to
("x" counsel-find-file-extern "open externally")
("r" counsel-find-file-as-root "open as root")
("R" find-file-read-only "read only")
+ ("l" find-file-literally "open literally")
("k" counsel-find-file-delete "delete")
("c" counsel-find-file-copy "copy file")
("m" counsel-find-file-move "move or rename")
@@ -1897,7 +1986,7 @@ Skip some dotfiles unless `ivy-text' requires them."
(setq res (cl-remove-if-not counsel--find-file-predicate res))))
(if (or (null ivy-use-ignore)
(null counsel-find-file-ignore-regexp)
- (string-match-p "\\`\\." ivy-text))
+ (string-match-p counsel-find-file-ignore-regexp ivy-text))
res
(or (cl-remove-if
(lambda (x)
@@ -1918,15 +2007,14 @@ Skip some dotfiles unless `ivy-text' requires them."
(defun counsel-find-file-action (x)
"Find file X."
- (with-ivy-window
- (cond ((and counsel-find-file-speedup-remote
- (file-remote-p ivy--directory))
- (let ((find-file-hook nil))
- (find-file (expand-file-name x ivy--directory))))
- ((member (file-name-extension x) counsel-find-file-extern-extensions)
- (counsel-find-file-extern x))
- (t
- (find-file (expand-file-name x ivy--directory))))))
+ (cond ((and counsel-find-file-speedup-remote
+ (file-remote-p ivy--directory))
+ (let ((find-file-hook nil))
+ (find-file (expand-file-name x ivy--directory))))
+ ((member (file-name-extension x) counsel-find-file-extern-extensions)
+ (counsel-find-file-extern x))
+ (t
+ (find-file (expand-file-name x ivy--directory)))))
(defun counsel--preselect-file ()
"Return candidate to preselect during filename completion.
@@ -1937,7 +2025,8 @@ The preselect behavior can be customized via user options
(when counsel-find-file-at-point
(require 'ffap)
(let ((f (ffap-guesser)))
- (when f (expand-file-name f))))
+ (when (and f (not (ivy-ffap-url-p f)))
+ (expand-file-name f))))
(and counsel-preselect-current-file
buffer-file-name
(file-name-nondirectory buffer-file-name))))
@@ -1958,18 +2047,18 @@ The preselect behavior can be customized via user
options
:caller caller)))
;;;###autoload
-(defun counsel-find-file (&optional initial-input)
+(defun counsel-find-file (&optional initial-input initial-directory)
"Forward to `find-file'.
When INITIAL-INPUT is non-nil, use it in the minibuffer during completion."
(interactive)
- (counsel--find-file-1
- "Find file: " initial-input
- #'counsel-find-file-action
- 'counsel-find-file))
+ (let ((default-directory (or initial-directory default-directory)))
+ (counsel--find-file-1 "Find file: " initial-input
+ #'counsel-find-file-action
+ 'counsel-find-file)))
(ivy-configure 'counsel-find-file
- :occur #'counsel-find-file-occur
- :display-transformer-fn #'ivy-read-file-transformer)
+ :parent 'read-file-name-internal
+ :occur #'counsel-find-file-occur)
(defvar counsel-find-file-occur-cmd "ls -a | %s | xargs -d '\\n' ls -d
--group-directories-first"
"Format string for `counsel-find-file-occur'.")
@@ -1984,7 +2073,7 @@ When INITIAL-INPUT is non-nil, use it in the minibuffer
during completion."
(defvar counsel-file-name-filter-alist
'(("ag -i '%s'" . t)
("ack -i '%s'" . t)
- ("perl -ne '/(%s.*)/i && print \"$1\\n\";'" . t)
+ ("perl -ne '/(.*%s.*)/i && print \"$1\\n\";'" . t)
("grep -i -E '%s'"))
"Alist of file name filtering commands.
The car is a shell command and the cdr is t when the shell
@@ -2008,7 +2097,7 @@ If USE-IGNORE is non-nil, try to generate a command that
respects
(when (and use-ignore ivy-use-ignore
counsel-find-file-ignore-regexp
(cdr filter-cmd)
- (not (string-match-p "\\`\\." ivy-text))
+ (not (string-match-p counsel-find-file-ignore-regexp
ivy-text))
(not (string-match-p counsel-find-file-ignore-regexp
(or (car ivy--old-cands) ""))))
(let ((ignore-re (list (counsel--elisp-to-pcre
@@ -2084,7 +2173,7 @@ See variable `counsel-up-directory-level'."
(ivy-set-index 0)
(setq ivy--directory "")
(setq ivy--all-candidates nil)
- (setq ivy-text "")
+ (ivy-set-text "")
(delete-minibuffer-contents)
(insert up-dir))
(if (and counsel-up-directory-level (not (string= ivy-text "")))
@@ -2098,6 +2187,16 @@ See variable `counsel-up-directory-level'."
(interactive)
(ivy--directory-enter))
+(defun counsel-find-file-undo ()
+ (interactive)
+ (if (string= ivy-text "")
+ (let ((dir (progn
+ (pop ivy--directory-hist)
+ (pop ivy--directory-hist))))
+ (when dir
+ (ivy--cd dir)))
+ (undo)))
+
(defun counsel-at-git-issue-p ()
"When point is at an issue in a Git-versioned file, return the issue string."
(and (looking-at "#[0-9]+")
@@ -2196,29 +2295,111 @@ When INITIAL-INPUT is non-nil, use it in the
minibuffer during completion."
'counsel-dired)))
(ivy-configure 'counsel-dired
- :display-transformer-fn #'ivy-read-file-transformer)
+ :parent 'read-file-name-internal)
;;** `counsel-recentf'
(defvar recentf-list)
(declare-function recentf-mode "recentf")
+(defcustom counsel-recentf-include-xdg-list nil
+ "Include recently used files listed by XDG-compliant environments.
+Examples of such environments are GNOME and KDE. See the URL
+`https://www.freedesktop.org/wiki/Specifications/desktop-bookmark-spec'."
+ :type 'boolean
+ :link '(url-link "\
+https://www.freedesktop.org/wiki/Specifications/desktop-bookmark-spec"))
+
;;;###autoload
(defun counsel-recentf ()
"Find a file on `recentf-list'."
(interactive)
(require 'recentf)
(recentf-mode)
- (ivy-read "Recentf: " (mapcar #'substring-no-properties recentf-list)
+ (ivy-read "Recentf: " (counsel-recentf-candidates)
:action (lambda (f)
(with-ivy-window
(find-file f)))
:require-match t
:caller 'counsel-recentf))
+
(ivy-set-actions
'counsel-recentf
- '(("j" find-file-other-window "other window")
+ `(("j" find-file-other-window "other window")
("f" find-file-other-frame "other frame")
- ("x" counsel-find-file-extern "open externally")))
+ ("x" counsel-find-file-extern "open externally")
+ ("d" ,(lambda (file) (setq recentf-list (delete file recentf-list)))
+ "delete from recentf")))
+
+(defun counsel-recentf-candidates ()
+ "Return candidates for `counsel-recentf'.
+
+When `counsel-recentf-include-xdg-list' is non-nil, also include
+the files in said list, sorting the combined list by file access
+time."
+ (if (and counsel-recentf-include-xdg-list
+ (>= emacs-major-version 26))
+ (delete-dups
+ (sort (nconc (mapcar #'substring-no-properties recentf-list)
+ (counsel--recentf-get-xdg-recent-files))
+ (lambda (file1 file2)
+ (cond ((file-remote-p file1)
+ nil)
+ ((file-remote-p file2))
+ (t
+ ;; Added in Emacs 26.1.
+ (declare-function file-attribute-access-time "files"
+ (attributes))
+ (time-less-p (file-attribute-access-time
+ (file-attributes file2))
+ (file-attribute-access-time
+ (file-attributes file1))))))))
+ (mapcar #'substring-no-properties recentf-list)))
+
+(defalias 'counsel--xml-parse-region
+ (if (cond ((fboundp 'libxml-available-p)
+ ;; Added in Emacs 27.1.
+ (libxml-available-p))
+ ((fboundp 'libxml-parse-xml-region)
+ ;; Checking for `fboundp' is not enough on Windows, where it
+ ;; will return non-nil even if the library is not installed.
+ (with-temp-buffer
+ (insert "<xml/>")
+ (libxml-parse-xml-region (point-min) (point-max)))))
+ (lambda (&optional beg end)
+ (libxml-parse-xml-region (or beg (point-min)) (or end (point-max))))
+ #'xml-parse-region)
+ "Compatibility shim for `libxml-parse-xml-region'.
+For convenience, BEG and END default to `point-min' and
+`point-max', respectively.
+
+\(fn &optional BEG END)")
+
+(defun counsel--recentf-get-xdg-recent-files ()
+ "Return list of XDG recent files.
+
+This information is parsed from the file \"recently-used.xbel\",
+which lists both files and directories, under `xdg-data-home'.
+This function uses the `dom' library from Emacs 25.1 or later."
+ (unless (require 'dom nil t)
+ (user-error "This function requires Emacs 25.1 or later"))
+ (declare-function dom-attr "dom" (node attr))
+ (declare-function dom-by-tag "dom" (dom tag))
+ (let ((file-of-recent-files
+ (expand-file-name "recently-used.xbel" (counsel--xdg-data-home))))
+ (unless (file-readable-p file-of-recent-files)
+ (user-error "List of XDG recent files not found: %s"
+ file-of-recent-files))
+ (cl-mapcan (lambda (bookmark-node)
+ (let* ((file (dom-attr bookmark-node 'href))
+ (file (string-remove-prefix "file://" file))
+ (file (url-unhex-string file t))
+ (file (decode-coding-string file 'utf-8 t)))
+ (and (file-exists-p file)
+ (list file))))
+ (let ((dom (with-temp-buffer
+ (insert-file-contents file-of-recent-files)
+ (counsel--xml-parse-region))))
+ (nreverse (dom-by-tag dom 'bookmark))))))
(defun counsel-buffer-or-recentf-candidates ()
"Return candidates for `counsel-buffer-or-recentf'."
@@ -2233,7 +2414,7 @@ When INITIAL-INPUT is non-nil, use it in the minibuffer
during completion."
(append
buffers
(cl-remove-if (lambda (f) (member f buffers))
- (mapcar #'substring-no-properties recentf-list)))))
+ (counsel-recentf-candidates)))))
;;;###autoload
(defun counsel-buffer-or-recentf ()
@@ -2306,6 +2487,7 @@ By default `counsel-bookmark' opens a dired buffer for
directories."
'counsel-bookmark
`(("d" bookmark-delete "delete")
("e" bookmark-rename "edit")
+ ("s" bookmark-set "overwrite")
("x" ,(counsel--apply-bookmark-fn #'counsel-find-file-extern)
"open externally")
("r" ,(counsel--apply-bookmark-fn #'counsel-find-file-as-root)
@@ -2334,12 +2516,12 @@ current value of `default-directory'."
:action #'dired))
(ivy-set-actions 'counsel-bookmarked-directory
- '(("j" dired-other-window "other window")
+ `(("j" dired-other-window "other window")
("x" counsel-find-file-extern "open externally")
("r" counsel-find-file-as-root "open as root")
- ("f" (lambda (dir)
- (let ((default-directory dir))
- (call-interactively #'find-file)))
+ ("f" ,(lambda (dir)
+ (let ((default-directory dir))
+ (call-interactively #'find-file)))
"find-file")))
;;** `counsel-file-register'
@@ -2381,13 +2563,13 @@ can use `C-x r j i' to open that file."
;;** `counsel-locate'
(defcustom counsel-locate-cmd (cond ((memq system-type '(darwin berkeley-unix))
- 'counsel-locate-cmd-noregex)
+ #'counsel-locate-cmd-noregex)
((and (eq system-type 'windows-nt)
(executable-find "es.exe"))
- 'counsel-locate-cmd-es)
+ #'counsel-locate-cmd-es)
(t
- 'counsel-locate-cmd-default))
- "The function for producing a locate command string from the input.
+ #'counsel-locate-cmd-default))
+ "The function for producing a `locate' command string from the input.
The function takes a string - the current input, and returns a
string - the full shell command to run."
@@ -2395,7 +2577,8 @@ string - the full shell command to run."
(const :tag "Default" counsel-locate-cmd-default)
(const :tag "No regex" counsel-locate-cmd-noregex)
(const :tag "mdfind" counsel-locate-cmd-mdfind)
- (const :tag "everything" counsel-locate-cmd-es)))
+ (const :tag "everything" counsel-locate-cmd-es)
+ (function :tag "Custom")))
(ivy-set-actions
'counsel-locate
@@ -2430,33 +2613,33 @@ string - the full shell command to run."
(dired-jump nil x))
(defun counsel-locate-cmd-default (input)
- "Return a shell command based on INPUT."
+ "Return a `locate' shell command based on regexp INPUT."
(counsel-require-program "locate")
- (format "locate -i --regex '%s'"
- (counsel--elisp-to-pcre
- (ivy--regex input))))
+ (format "locate -i --regex %s"
+ (shell-quote-argument
+ (counsel--elisp-to-pcre
+ (ivy--regex input)))))
(defun counsel-locate-cmd-noregex (input)
- "Return a shell command based on INPUT."
+ "Return a `locate' shell command based on INPUT."
(counsel-require-program "locate")
- (format "locate -i '%s'" input))
+ (format "locate -i %s" (shell-quote-argument input)))
(defun counsel-locate-cmd-mdfind (input)
- "Return a shell command based on INPUT."
+ "Return a `mdfind' shell command based on INPUT."
(counsel-require-program "mdfind")
- (format "mdfind -name '%s'" input))
-
-(defvar w32-ansi-code-page)
+ (format "mdfind -name %s" (shell-quote-argument input)))
(defun counsel-locate-cmd-es (input)
- "Return a shell command based on INPUT."
+ "Return a `es' shell command based on INPUT."
+ (defvar w32-ansi-code-page)
(counsel-require-program "es.exe")
- (let ((raw-string (format "es.exe -i -r -p %s"
+ (let ((raw-string (format "es.exe -i -p -r %s"
(counsel--elisp-to-pcre
(ivy--regex input t)))))
- ;; W32 don't use Unicode by default, so we encode search command
- ;; to local codepage to support searching filename contains non-ASCII
- ;; characters.
+ ;; W32 doesn't use Unicode by default, so we encode search command
+ ;; to local codepage to support searching file names containing
+ ;; non-ASCII characters.
(if (and (eq system-type 'windows-nt)
(boundp 'w32-ansi-code-page))
(encode-coding-string raw-string
@@ -2464,7 +2647,7 @@ string - the full shell command to run."
raw-string)))
(defun counsel-locate-function (input)
- "Call the \"locate\" shell command with INPUT."
+ "Call a \"locate\" style shell command with INPUT."
(or
(ivy-more-chars)
(progn
@@ -2478,10 +2661,7 @@ string - the full shell command to run."
(defun counsel-file-stale-p (fname seconds)
"Return non-nil if FNAME was modified more than SECONDS ago."
- (> (time-to-seconds
- (time-subtract
- (current-time)
- (nth 5 (file-attributes fname))))
+ (> (float-time (time-subtract nil (nth 5 (file-attributes fname))))
seconds))
(defun counsel--locate-updatedb ()
@@ -2496,7 +2676,7 @@ string - the full shell command to run."
;;;###autoload
(defun counsel-locate (&optional initial-input)
- "Call the \"locate\" shell command.
+ "Call a \"locate\" style shell command.
INITIAL-INPUT can be given as the initial minibuffer input."
(interactive)
(counsel--locate-updatedb)
@@ -2515,6 +2695,35 @@ INITIAL-INPUT can be given as the initial minibuffer
input."
:unwind-fn #'counsel-delete-process
:exit-codes '(1 "Nothing found"))
+;;** `counsel-tracker'
+(defun counsel-tracker-function (input)
+ "Call the \"tracker\" shell command with INPUT."
+ (or
+ (ivy-more-chars)
+ (progn
+ (counsel--async-command
+ (format
+ "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"
+ (counsel--elisp-to-pcre (funcall ivy--regex-function input))))
+ '("" "working..."))))
+
+(defun counsel-tracker-transformer (str)
+ (if (string-match "file:///" str)
+ (decode-coding-string (url-unhex-string (substring str 9)) 'utf-8)
+ str))
+
+;;;###autoload
+(defun counsel-tracker ()
+ (interactive)
+ (ivy-read "Tracker: " 'counsel-tracker-function
+ :dynamic-collection t
+ :action (lambda (s) (find-file (counsel-tracker-transformer s)))
+ :caller 'counsel-tracker))
+
+(ivy-configure 'counsel-tracker
+ :display-transformer-fn #'counsel-tracker-transformer
+ :unwind-fn #'counsel-delete-process)
+
;;** `counsel-fzf'
(defvar counsel-fzf-cmd "fzf -f \"%s\""
"Command for `counsel-fzf'.")
@@ -2634,7 +2843,8 @@ FZF-PROMPT, if non-nil, is passed as `ivy-read' prompt
argument."
(defun counsel--find-return-list (args)
(unless (listp args)
- (user-error "`counsel-file-jump-args' is a list now, please customize
accordingly."))
+ (user-error
+ "`counsel-file-jump-args' is a list now; please customize accordingly"))
(counsel--call
(cons find-program args)
(lambda ()
@@ -2652,6 +2862,18 @@ FZF-PROMPT, if non-nil, is passed as `ivy-read' prompt
argument."
:type '(repeat string))
;;** `counsel-file-jump'
+(defvar counsel-file-jump-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "`") #'counsel-find-file-from-jump)
+ map)
+ "Key bindings to be used when in a file-jump minibuffer.")
+
+(defun counsel-find-file-from-jump ()
+ "Switch to `counsel-find-file' from `counsel-file-jump'."
+ (interactive)
+ (ivy-quit-and-run
+ (counsel-find-file ivy-text (ivy-state-directory ivy-last))))
+
;;;###autoload
(defun counsel-file-jump (&optional initial-input initial-directory)
"Jump to a file below the current directory.
@@ -2672,7 +2894,7 @@ INITIAL-DIRECTORY, if non-nil, is used as the root
directory for search."
:preselect (counsel--preselect-file)
:require-match 'confirm-after-completion
:history 'file-name-history
- :keymap counsel-find-file-map
+ :keymap counsel-file-jump-map
:caller 'counsel-file-jump)))
(ivy-set-actions
@@ -2709,26 +2931,6 @@ INITIAL-DIRECTORY, if non-nil, is used as the root
directory for search."
:caller 'counsel-dired-jump)))
;;* Grep
-(defun counsel--grep-mode-occur (git-grep-dir-is-file)
- "Generate a custom occur buffer for grep like commands.
-If GIT-GREP-DIR-IS-FILE is t, then `ivy-state-directory' is treated as a full
-path to a file rather than a directory (e.g. for `counsel-grep-occur').
-
-This function expects that the candidates have already been filtered.
-It applies no filtering to ivy--all-candidates."
- (unless (eq major-mode 'ivy-occur-grep-mode)
- (ivy-occur-grep-mode))
- (let ((directory
- (if git-grep-dir-is-file
- (file-name-directory (ivy-state-directory ivy-last))
- (ivy-state-directory ivy-last))))
- (setq default-directory directory)
- ;; Need precise number of header lines for `wgrep' to work.
- (insert (format "-*- mode:grep; default-directory: %S -*-\n\n\n"
default-directory))
- (insert (format "%d candidates:\n" (length ivy--all-candidates)))
- (ivy--occur-insert-lines
- (mapcar #'counsel--normalize-grep-match ivy--all-candidates))))
-
;;** `counsel-ag'
(defvar counsel-ag-map
(let ((map (make-sparse-keymap)))
@@ -2738,14 +2940,14 @@ It applies no filtering to ivy--all-candidates."
(define-key map (kbd "C-x C-d") 'counsel-cd)
map))
-(defcustom counsel-ag-base-command
- (if (memq system-type '(ms-dos windows-nt))
- "ag --vimgrep %s"
- "ag --nocolor --nogroup %s")
+(defcustom counsel-ag-base-command "ag --vimgrep %s"
"Format string to use in `counsel-ag-function' to construct the command.
The %s will be replaced by optional extra ag arguments followed by the
regex string."
- :type 'string)
+ :type '(radio
+ (const "ag --vimgrep %s")
+ (const "ag --nocolor --nogroup %s")
+ (string :tag "custom")))
(defvar counsel-ag-command nil)
@@ -2753,34 +2955,38 @@ regex string."
(defvar counsel--regex-look-around nil)
-(defconst counsel--command-args-separator "-- ")
+(defconst counsel--command-args-separator " -- ")
(defun counsel--split-command-args (arguments)
"Split ARGUMENTS into its switches and search-term parts.
Return pair of corresponding strings (SWITCHES . SEARCH-TERM)."
- (let ((switches "")
- (search-term arguments))
- (when (string-prefix-p "-" arguments)
- (let ((index (string-match counsel--command-args-separator arguments)))
- (when index
- (setq search-term
- (substring arguments (+ (length
counsel--command-args-separator) index)))
- (setq switches (substring arguments 0 index)))))
- (cons switches search-term)))
+ (if (string-match counsel--command-args-separator arguments)
+ (let ((args (substring arguments (match-end 0)))
+ (search-term (substring arguments 0 (match-beginning 0))))
+ (if (string-prefix-p "-" arguments)
+ (cons search-term args)
+ (cons args search-term)))
+ (cons "" arguments)))
(defun counsel--format-ag-command (extra-args needle)
"Construct a complete `counsel-ag-command' as a string.
EXTRA-ARGS is a string of the additional arguments.
NEEDLE is the search string."
- (format counsel-ag-command
- (if (string-match " \\(--\\) " extra-args)
- (replace-match needle t t extra-args 1)
- (concat extra-args " " needle))))
+ (counsel--format counsel-ag-command
+ (if (listp counsel-ag-command)
+ (if (string-match " \\(--\\) " extra-args)
+ (counsel--format
+ (split-string (replace-match "%s" t t extra-args
1))
+ needle)
+ (nconc (split-string extra-args) needle))
+ (if (string-match " \\(--\\) " extra-args)
+ (replace-match needle t t extra-args 1)
+ (concat extra-args " " needle)))))
(defun counsel--grep-regex (str)
(counsel--elisp-to-pcre
(setq ivy--old-re
- (funcall ivy--regex-function str))
+ (funcall (ivy-state-re-builder ivy-last) str))
counsel--regex-look-around))
(defun counsel--ag-extra-switches (regex)
@@ -2799,51 +3005,65 @@ NEEDLE is the search string."
(ivy-more-chars))
(let* ((default-directory (ivy-state-directory ivy-last))
(regex (counsel--grep-regex search-term))
- (switches (concat (car command-args)
+ (switches (concat (if (ivy--case-fold-p string)
+ " -i "
+ " -s ")
(counsel--ag-extra-switches regex)
- (and (ivy--case-fold-p string) " -i "))))
+ (car command-args))))
(counsel--async-command (counsel--format-ag-command
switches
- (shell-quote-argument regex)))
+ (funcall (if (listp counsel-ag-command)
#'identity
+ #'shell-quote-argument)
+ regex)))
nil))))
;;;###autoload
(cl-defun counsel-ag (&optional initial-input initial-directory extra-ag-args
ag-prompt
&key caller)
- "Grep for a string in the current directory using ag.
+ "Grep for a string in a root directory using ag.
+
+By default, the root directory is the first directory containing a .git
subdirectory.
+
INITIAL-INPUT can be given as the initial minibuffer input.
INITIAL-DIRECTORY, if non-nil, is used as the root directory for search.
-EXTRA-AG-ARGS string, if non-nil, is appended to `counsel-ag-base-command'.
+EXTRA-AG-ARGS, if non-nil, is appended to `counsel-ag-base-command'.
AG-PROMPT, if non-nil, is passed as `ivy-read' prompt argument.
-CALLER is passed to `ivy-read'."
+CALLER is passed to `ivy-read'.
+
+With a `\\[universal-argument]' prefix argument, prompt for INITIAL-DIRECTORY.
+With a `\\[universal-argument] \\[universal-argument]' prefix argument, \
+prompt additionally for EXTRA-AG-ARGS."
(interactive)
(setq counsel-ag-command counsel-ag-base-command)
(setq counsel--regex-look-around counsel--grep-tool-look-around)
(counsel-require-program counsel-ag-command)
- (when current-prefix-arg
- (setq initial-directory
- (or initial-directory
- (counsel-read-directory-name (concat
- (car (split-string
counsel-ag-command))
- " in directory: "))))
- (setq extra-ag-args
- (or extra-ag-args
- (read-from-minibuffer (format
- "%s args: "
- (car (split-string
counsel-ag-command)))))))
- (setq counsel-ag-command (counsel--format-ag-command (or extra-ag-args "")
"%s"))
- (let ((default-directory (or initial-directory
- (counsel--git-root)
- default-directory)))
- (ivy-read (or ag-prompt
- (concat (car (split-string counsel-ag-command)) ": "))
- #'counsel-ag-function
- :initial-input initial-input
- :dynamic-collection t
- :keymap counsel-ag-map
- :history 'counsel-git-grep-history
- :action #'counsel-git-grep-action
- :caller (or caller 'counsel-ag))))
+ (let ((prog-name (car (if (listp counsel-ag-command) counsel-ag-command
+ (split-string counsel-ag-command))))
+ (arg (prefix-numeric-value current-prefix-arg)))
+ (when (>= arg 4)
+ (setq initial-directory
+ (or initial-directory
+ (counsel-read-directory-name (concat
+ prog-name
+ " in directory: ")))))
+ (when (>= arg 16)
+ (setq extra-ag-args
+ (or extra-ag-args
+ (read-from-minibuffer (format "%s args: " prog-name)))))
+ (setq counsel-ag-command (counsel--format-ag-command (or extra-ag-args "")
"%s"))
+ (let ((default-directory (or initial-directory
+ (counsel--git-root)
+ default-directory)))
+ (ivy-read (or ag-prompt
+ (concat prog-name ": "))
+ #'counsel-ag-function
+ :initial-input initial-input
+ :dynamic-collection t
+ :keymap counsel-ag-map
+ :history 'counsel-git-grep-history
+ :action #'counsel-git-grep-action
+ :require-match t
+ :caller (or caller 'counsel-ag)))))
(ivy-configure 'counsel-ag
:occur #'counsel-ag-occur
@@ -2852,47 +3072,74 @@ CALLER is passed to `ivy-read'."
:grep-p t
:exit-codes '(1 "No matches found"))
-(defun counsel-read-directory-name (prompt)
+(defun counsel-read-directory-name (prompt &optional default)
"Read a directory name from user, a (partial) replacement of
`read-directory-name'."
(let ((counsel--find-file-predicate #'file-directory-p))
(ivy-read prompt
#'read-file-name-internal
:matcher #'counsel--find-file-matcher
+ :def default
:history 'file-name-history
:keymap counsel-find-file-map
:caller 'counsel-read-directory-name)))
(ivy-configure 'counsel-read-directory-name
- :display-transformer-fn #'ivy-read-file-transformer)
+ :parent 'read-file-name-internal)
(defun counsel-cd ()
"Change the directory for the currently running Ivy grep-like command.
Works for `counsel-git-grep', `counsel-ag', etc."
(interactive)
- (let ((input ivy-text)
- (new-dir (counsel-read-directory-name "cd: ")))
+ (counsel-delete-process)
+ (let* ((input ivy-text)
+ (enable-recursive-minibuffers t)
+ (def-dir (buffer-file-name (ivy-state-buffer ivy-last)))
+ (def-dir (and def-dir (file-name-directory def-dir)))
+ (new-dir (counsel-read-directory-name "cd: " def-dir)))
(ivy-quit-and-run
(funcall (ivy-state-caller ivy-last) input new-dir))))
+(defun counsel--grep-smart-case-flag ()
+ (if (ivy--case-fold-p ivy-text)
+ "-i"
+ (if (and (stringp counsel-ag-base-command)
+ (string-match-p "\\`pt" counsel-ag-base-command))
+ "-S"
+ "-s")))
+
(defun counsel-grep-like-occur (cmd-template)
(unless (eq major-mode 'ivy-occur-grep-mode)
(ivy-occur-grep-mode)
(setq default-directory (ivy-state-directory ivy-last)))
- (setq ivy-text
- (and (string-match "\"\\(.*\\)\"" (buffer-name))
- (match-string 1 (buffer-name))))
+ (ivy-set-text
+ (if (string-match "\"\\(.*\\)\"" (buffer-name))
+ (match-string 1 (buffer-name))
+ (ivy-state-text ivy-occur-last)))
(let* ((cmd
(if (functionp cmd-template)
(funcall cmd-template ivy-text)
(let* ((command-args (counsel--split-command-args ivy-text))
(regex (counsel--grep-regex (cdr command-args)))
- (switches (concat (car command-args)
- (counsel--ag-extra-switches regex))))
- (format cmd-template
- (concat
- switches
- (shell-quote-argument regex))))))
- (cands (counsel--split-string (shell-command-to-string cmd))))
+ (extra-switches (counsel--ag-extra-switches regex))
+ (all-args (append
+ (when (car command-args)
+ (split-string (car command-args)))
+ (when extra-switches
+ (split-string extra-switches))
+ (list
+ (counsel--grep-smart-case-flag)
+ regex))))
+ (if (stringp cmd-template)
+ (counsel--format
+ cmd-template
+ (mapconcat #'shell-quote-argument all-args " "))
+ (cl-mapcan
+ (lambda (x) (if (string= x "%s") (copy-sequence all-args)
(list x)))
+ cmd-template)))))
+ (cands (counsel--split-string
+ (if (stringp cmd)
+ (shell-command-to-string cmd)
+ (counsel--call cmd)))))
(swiper--occur-insert-lines (mapcar #'counsel--normalize-grep-match
cands))))
(defun counsel-ag-occur (&optional _cands)
@@ -2914,7 +3161,7 @@ This uses `counsel-ag' with `counsel-pt-base-command'
instead of
(interactive)
(let ((counsel-ag-base-command counsel-pt-base-command)
(counsel--grep-tool-look-around nil))
- (counsel-ag initial-input :caller 'counsel-pt)))
+ (counsel-ag initial-input nil nil nil :caller 'counsel-pt)))
(ivy-configure 'counsel-pt
:unwind-fn #'counsel--grep-unwind
@@ -2939,35 +3186,36 @@ This uses `counsel-ag' with `counsel-ack-base-command'
replacing
(interactive)
(let ((counsel-ag-base-command counsel-ack-base-command)
(counsel--grep-tool-look-around t))
- (counsel-ag initial-input :caller 'counsel-ack)))
+ (counsel-ag
+ initial-input nil nil nil
+ :caller 'counsel-ack)))
;;** `counsel-rg'
(defcustom counsel-rg-base-command
- (if (memq system-type '(ms-dos windows-nt))
- "rg --with-filename --no-heading --line-number --path-separator /
--color never %s ."
- "rg --with-filename --no-heading --line-number --color never %s")
+ (split-string
+ (if (memq system-type '(ms-dos windows-nt))
+ "rg -M 240 --with-filename --no-heading --line-number --color never %s
--path-separator / ."
+ "rg -M 240 --with-filename --no-heading --line-number --color never %s"))
"Alternative to `counsel-ag-base-command' using ripgrep.
Note: don't use single quotes for the regex."
- :type 'string)
+ :type '(choice
+ (repeat :tag "List to be used in `process-file'." string)
+ (string :tag "String to be used in `shell-command-to-string'.")))
(defun counsel--rg-targets ()
"Return a list of files to operate on, based on `dired-mode' marks."
- (if (eq major-mode 'dired-mode)
- (let ((files
- (dired-get-marked-files 'no-dir nil nil t)))
- (if (and (null (cdr files))
- (not (when (string-match-p "\\*ivy-occur" (buffer-name))
- (dired-toggle-marks)
- (setq files (dired-get-marked-files 'no-dir))
- (dired-toggle-marks)
- t)))
- ""
- (concat
- " "
- (mapconcat #'shell-quote-argument (delq t files) " "))))
- ""))
+ (when (eq major-mode 'dired-mode)
+ (let ((files
+ (dired-get-marked-files 'no-dir nil nil t)))
+ (when (or (cdr files)
+ (when (string-match-p "\\*ivy-occur" (buffer-name))
+ (dired-toggle-marks)
+ (setq files (dired-get-marked-files 'no-dir))
+ (dired-toggle-marks)
+ t))
+ (delq t files)))))
;;;###autoload
(defun counsel-rg (&optional initial-input initial-directory extra-rg-args
rg-prompt)
@@ -2978,14 +3226,18 @@ EXTRA-RG-ARGS string, if non-nil, is appended to
`counsel-rg-base-command'.
RG-PROMPT, if non-nil, is passed as `ivy-read' prompt argument.
Example input with inclusion and exclusion file patterns:
- -g*.py -g!*test* -- ..."
+ require i -- -g*.el"
(interactive)
(let ((counsel-ag-base-command
- (concat counsel-rg-base-command (counsel--rg-targets)))
+ (if (listp counsel-rg-base-command)
+ (append counsel-rg-base-command (counsel--rg-targets))
+ (concat counsel-rg-base-command " "
+ (mapconcat #'shell-quote-argument (counsel--rg-targets) "
"))))
(counsel--grep-tool-look-around
- (let ((rg (car (split-string counsel-rg-base-command)))
+ (let ((rg (car (if (listp counsel-rg-base-command)
counsel-rg-base-command
+ (split-string counsel-rg-base-command))))
(switch "--pcre2"))
- (and (eq 0 (call-process rg nil nil nil switch "--version"))
+ (and (eq 0 (call-process rg nil nil nil switch "--pcre2-version"))
switch))))
(counsel-ag initial-input initial-directory extra-rg-args rg-prompt
:caller 'counsel-rg)))
@@ -3018,11 +3270,18 @@ substituted by the search regexp and file,
respectively. Neither
"Grep in the current directory for STRING."
(or
(ivy-more-chars)
- (let ((regex (counsel--elisp-to-pcre
- (setq ivy--old-re
- (ivy--regex string)))))
+ (let* ((regex (counsel--grep-regex string))
+ (cmd (counsel--format
+ counsel-grep-command
+ (funcall (if (listp counsel-grep-command) #'identity
+ #'shell-quote-argument)
+ regex))))
(counsel--async-command
- (format counsel-grep-command (shell-quote-argument regex)))
+ (if (ivy--case-fold-p regex)
+ (if (listp cmd) (nconc (list (car cmd) "-i") (cdr cmd))
+ (string-match " " cmd)
+ (replace-match " -i " nil nil cmd))
+ cmd))
nil)))
(defvar counsel--grep-last-pos nil
@@ -3088,10 +3347,11 @@ When non-nil, INITIAL-INPUT is the initial search
pattern."
(user-error "Current buffer is not visiting a file"))
(counsel-require-program counsel-grep-base-command)
(setq counsel-grep-command
- (format counsel-grep-base-command
- "%s" (shell-quote-argument
- (file-name-nondirectory
- buffer-file-name))))
+ (counsel--format counsel-grep-base-command "%s"
+ (funcall (if (listp counsel-grep-base-command)
#'identity
+ #'shell-quote-argument)
+ (file-name-nondirectory
+ buffer-file-name))))
(let ((default-directory (file-name-directory buffer-file-name))
(init-point (point))
res)
@@ -3327,7 +3587,9 @@ otherwise continue prompting for tags."
(delete-dups
(append (counsel--org-get-tags) add-tags)))
(counsel-org--set-tags))))))
- (counsel-org--set-tags)))
+ (counsel-org--set-tags)
+ (unless (member x counsel-org-tags)
+ (message "Tag %S has been removed." x))))
((eq this-command 'ivy-call)
(with-selected-window (active-minibuffer-window)
(delete-minibuffer-contents)))))
@@ -3416,6 +3678,14 @@ otherwise continue prompting for tags."
"If non-nil, display priorities in matched `org-mode' headlines."
:type 'boolean)
+(defcustom counsel-org-headline-display-comment nil
+ "If non-nil, display COMMENT string in matched `org-mode' headlines."
+ :type 'boolean)
+
+(defcustom counsel-org-headline-display-statistics nil
+ "If non-nil, display statistics cookie in matched `org-mode' headlines."
+ :type 'boolean)
+
(declare-function org-get-heading "org")
(declare-function org-goto-marker-or-bmk "org")
(declare-function outline-next-heading "outline")
@@ -3535,11 +3805,13 @@ version. Argument values are based on the
`counsel-org-headline-display-*' user options."
(nbutlast (mapcar #'not (list counsel-org-headline-display-tags
counsel-org-headline-display-todo
- counsel-org-headline-display-priority))
+ counsel-org-headline-display-priority
+ counsel-org-headline-display-comment))
+ ;; Added in Emacs 26.1.
(if (if (fboundp 'func-arity)
(< (cdr (func-arity #'org-get-heading)) 3)
(version< org-version "9.1.1"))
- 1 0)))
+ 2 0)))
;;** `counsel-org-file'
(declare-function org-attach-dir "org-attach")
@@ -3556,7 +3828,7 @@ include attachments of other Org buffers."
(let (dirs)
(save-excursion
(goto-char (point-min))
- (while (re-search-forward "^:\\(ATTACH_DIR\\|ID\\):[\t ]+\\(.*\\)$" nil
t)
+ (while (re-search-forward ":\\(?:ATTACH_DIR\\|ID\\):[\t ]+.*$" nil t)
(let ((dir (org-attach-dir)))
(when dir
(push dir dirs)))))
@@ -3622,18 +3894,28 @@ include attachments of other Org buffers."
(interactive)
(require 'org-capture)
(ivy-read "Capture template: "
- (delq nil
- (mapcar
- (lambda (x)
- (when (> (length x) 2)
- (format "%-5s %s" (nth 0 x) (nth 1 x))))
- ;; We build the list of capture templates as in
- ;; `org-capture-select-template':
- (or (org-contextualize-keys
- (org-capture-upgrade-templates org-capture-templates)
- org-capture-templates-contexts)
- '(("t" "Task" entry (file+headline "" "Tasks")
- "* TODO %?\n %u\n %a")))))
+ ;; We build the list of capture templates as in
`org-capture-select-template':
+ (let (prefixes)
+ (cl-mapcan
+ (lambda (x)
+ (let ((x-keys (car x)))
+ ;; Remove prefixed keys until we get one that matches the
current item.
+ (while (and prefixes
+ (let ((p1-keys (caar prefixes)))
+ (or
+ (<= (length x-keys) (length p1-keys))
+ (not (string-prefix-p p1-keys x-keys)))))
+ (pop prefixes))
+ (if (> (length x) 2)
+ (let ((desc (mapconcat #'cadr (reverse (cons x
prefixes)) " | ")))
+ (list (format "%-5s %s" x-keys desc)))
+ (push x prefixes)
+ nil)))
+ (or (org-contextualize-keys
+ (org-capture-upgrade-templates org-capture-templates)
+ org-capture-templates-contexts)
+ '(("t" "Task" entry (file+headline "" "Tasks")
+ "* TODO %?\n %u\n %a")))))
:require-match t
:action (lambda (x)
(org-capture nil (car (split-string x))))
@@ -3757,10 +4039,31 @@ This variable has no effect unless
:history 'counsel-org-agenda-headlines-history
:caller 'counsel-org-agenda-headlines)))
-;;* Misc. Emacs
+;;** `counsel-org-link'
+(declare-function org-insert-link "ol")
+(declare-function org-id-get-create "org-id")
+
+(defun counsel-org-link-action (x)
+ "Insert a link to X."
+ (let ((id (save-excursion
+ (goto-char (cdr x))
+ (org-id-get-create))))
+ (org-insert-link nil (concat "id:" id) (car x))))
+
+;;;###autoload
+(defun counsel-org-link ()
+ "Insert a link to an headline with completion."
+ (interactive)
+ (ivy-read "Link: " (counsel-outline-candidates
+ '(:outline-title counsel-outline-title-org ))
+ :action #'counsel-org-link-action
+ :history 'counsel-org-link-history
+ :caller 'counsel-org-link))
+
+;; Misc. Emacs
;;** `counsel-mark-ring'
(defface counsel--mark-ring-highlight
- '((t (:inherit highlight)))
+ '((t :inherit highlight))
"Face for current `counsel-mark-ring' line."
:group 'ivy-faces)
@@ -3801,15 +4104,6 @@ This variable has no effect unless
Obeys `widen-automatically', which see."
(interactive)
(let* ((counsel--mark-ring-calling-point (point))
- (width (length (number-to-string (line-number-at-pos (point-max)))))
- (fmt (format "%%%dd %%s" width))
- (make-candidate
- (lambda (mark)
- (goto-char (marker-position mark))
- (let ((linum (line-number-at-pos))
- (line (buffer-substring
- (line-beginning-position) (line-end-position))))
- (propertize (format fmt linum line) 'point (point)))))
(marks (copy-sequence mark-ring))
(marks (delete-dups marks))
(marks
@@ -3817,33 +4111,125 @@ Obeys `widen-automatically', which see."
(if (equal (mark-marker) (make-marker))
marks
(cons (copy-marker (mark-marker)) marks)))
- (cands
- ;; Widen, both to save `line-number-at-pos' the trouble
- ;; and for `buffer-substring' to work.
- (save-excursion
- (save-restriction
- (widen)
- (mapcar make-candidate marks)))))
- (if cands
- (ivy-read "Mark: " cands
- :require-match t
- :action (lambda (cand)
- (let ((pos (get-text-property 0 'point cand)))
- (when pos
- (unless (<= (point-min) pos (point-max))
- (if widen-automatically
- (widen)
- (error "\
-Position of selected mark outside accessible part of buffer")))
- (goto-char pos))))
- :caller 'counsel-mark-ring)
+ (candidates (counsel-mark--get-candidates marks)))
+ (if candidates
+ (counsel-mark--ivy-read "Mark: " candidates 'counsel-mark-ring)
(message "Mark ring is empty"))))
+(defun counsel-mark--get-candidates (marks)
+ "Convert a list of MARKS into mark candidates.
+candidates are simply strings formatted to have the line number of the
+associated mark prepended to them and having an extra text property of
+point to indicarte where the candidate mark is."
+ (when marks
+ (save-excursion
+ (save-restriction
+ ;; Widen, both to save `line-number-at-pos' the trouble
+ ;; and for `buffer-substring' to work.
+ (widen)
+ (let* ((width (length (number-to-string (line-number-at-pos
(point-max)))))
+ (fmt (format "%%%dd %%s" width)))
+ (mapcar (lambda (mark)
+ (goto-char (marker-position mark))
+ (let ((linum (line-number-at-pos))
+ (line (buffer-substring
+ (line-beginning-position)
(line-end-position))))
+ (propertize (format fmt linum line) 'point (point))))
+ marks))))))
+
+(defun counsel-mark--ivy-read (prompt candidates caller)
+ "call `ivy-read' with sane defaults for traversing marks.
+CANDIDATES should be an alist with the `car' of the list being
+the string displayed by ivy and the `cdr' being the point that
+mark should take you to.
+
+NOTE This has been abstracted out into it's own method so it can
+be used by both `counsel-mark-ring' and `counsel-evil-marks'"
+ (ivy-read prompt candidates
+ :require-match t
+ :update-fn #'counsel--mark-ring-update-fn
+ :action (lambda (cand)
+ (let ((pos (get-text-property 0 'point cand)))
+ (when pos
+ (unless (<= (point-min) pos (point-max))
+ (if widen-automatically
+ (widen)
+ (error "\
+Position of selected mark outside accessible part of buffer")))
+ (goto-char pos))))
+ :unwind #'counsel--mark-ring-unwind
+ :caller caller))
+
(ivy-configure 'counsel-mark-ring
:update-fn #'counsel--mark-ring-update-fn
:unwind-fn #'counsel--mark-ring-unwind
:sort-fn #'ivy-string<)
+;;** `counsel-evil-marks'
+(defvar counsel-evil-marks-exclude-registers nil
+ "List of evil registers to not display in `counsel-evil-marks' by default.
+Each member of the list should be a character (stored as an integer).")
+
+(defvar evil-markers-alist)
+(declare-function evil-global-marker-p "ext:evil-common")
+
+(defun counsel-mark--get-evil-candidates (all-markers-p)
+ "Convert all evil MARKS in the current buffer to mark candidates.
+Works like `counsel-mark--get-candidates' but also prepends the
+register tied to a mark in the message string."
+ ;; evil doesn't provide a standalone method to access the list of
+ ;; marks in the current buffer, as it does with registers.
+ (let* ((all-markers
+ (append
+ (cl-remove-if (lambda (m)
+ (or (evil-global-marker-p (car m))
+ (not (markerp (cdr m)))))
+ evil-markers-alist)
+ (cl-remove-if (lambda (m)
+ (or (not (evil-global-marker-p (car m)))
+ (not (markerp (cdr m)))))
+ (default-value 'evil-markers-alist))))
+
+ (all-markers
+ ;; with prefix, ignore register exclusion list.
+ (if all-markers-p
+ all-markers
+ (cl-remove-if-not
+ (lambda (x) (not (member (car x)
counsel-evil-marks-exclude-registers)))
+ all-markers)))
+ ;; separate the markers from the evil registers
+ ;; for call to `counsel-mark--get-candidates'
+ (registers (mapcar #'car all-markers))
+ (markers (mapcar #'cdr all-markers))
+ (candidates (counsel-mark--get-candidates markers)))
+ (when candidates
+ (let (register candidate result)
+ (while (and (setq register (pop registers))
+ (setq candidate (pop candidates)))
+ (let ((point (get-text-property 0 'point candidate))
+ (evil-candidate
+ (format "[%s]: %s"
+ (propertize (char-to-string register)
+ 'face 'counsel-evil-register-face)
+ candidate)))
+ (push (propertize evil-candidate 'point point) result)))
+ result))))
+
+;;;###autoload
+(defun counsel-evil-marks (&optional arg)
+ "Ivy replacement for `evil-show-marks'.
+By default, this function respects `counsel-evil-marks-exclude-registers'.
+When ARG is non-nil, display all active evil registers."
+ (interactive "P")
+ (if (and (boundp 'evil-markers-alist)
+ (fboundp 'evil-global-marker-p))
+ (let* ((counsel--mark-ring-calling-point (point))
+ (candidates (counsel-mark--get-evil-candidates arg)))
+ (if candidates
+ (counsel-mark--ivy-read "Evil mark: " candidates
'counsel-evil-marks)
+ (message "No evil marks are active")))
+ (user-error "Required feature `evil' not installed or loaded")))
+
;;** `counsel-package'
(defvar package--initialized)
(defvar package-alist)
@@ -3901,7 +4287,8 @@ Additional actions:\\<ivy-minibuffer-map>
:history 'counsel-package-history
:caller 'counsel-package))
-(cl-pushnew '(counsel-package . "^+") ivy-initial-inputs-alist :key #'car)
+(ivy-configure 'counsel-package
+ :initial-input "^+")
(defun counsel-package-action (package)
"Delete or install PACKAGE."
@@ -4077,13 +4464,18 @@ Signal a `buffer-read-only' error if called from a
read-only
buffer position."
(with-ivy-window
(barf-if-buffer-read-only)
- (setq last-command 'yank)
(setq yank-window-start (window-start))
+ (unless (eq last-command 'yank)
+ ;; Avoid unexpected deletions with `yank-handler' properties.
+ (setq yank-undo-function nil))
(condition-case nil
- ;; Avoid unexpected additions to `kill-ring'
- (let (interprogram-paste-function)
+ (let (;; Deceive `yank-pop'.
+ (last-command 'yank)
+ ;; Avoid unexpected additions to `kill-ring'.
+ interprogram-paste-function)
(yank-pop (counsel--yank-pop-position s)))
(error
+ ;; Support strings not present in the kill ring.
(insert s)))
(when (funcall (if counsel-yank-pop-after-point #'> #'<)
(point) (mark t))
@@ -4130,6 +4522,7 @@ preselected. Otherwise, the prefix argument defaults to
0, which
results in the most recent kill being preselected."
:type 'boolean)
+;; Moved to subr.el in Emacs 27.1.
(autoload 'xor "array")
;;;###autoload
@@ -4173,14 +4566,14 @@ Note: Duplicate elements of `kill-ring' are always
deleted."
;;** `counsel-register'
(defvar counsel-register-actions
- '(("\\`buffer position" . jump-to-register)
+ '(("\\`buffer" . jump-to-register)
("\\`text" . insert-register)
("\\`rectangle" . insert-register)
- ("\\`window configuration" . jump-to-register)
- ("\\`frame configuration" . jump-to-register)
+ ("\\`window" . jump-to-register)
+ ("\\`frame" . jump-to-register)
("\\`[-+]?[0-9]+\\(?:\\.[0-9]\\)?\\'" . insert-register)
- ("\\`the file" . jump-to-register)
- ("\\`keyboard macro" . jump-to-register)
+ ("\\`\\(?:the \\)?file " . jump-to-register)
+ ("\\`keyboard" . jump-to-register)
("\\`file-query" . jump-to-register))
"Alist of (REGEXP . FUNCTION) pairs for `counsel-register'.
Selecting a register whose description matches REGEXP specifies
@@ -4226,6 +4619,11 @@ matching the register's value description against a
regexp in
:sort-fn #'ivy-string<)
;;** `counsel-evil-registers'
+(defface counsel-evil-register-face
+ '((t :inherit counsel-outline-1))
+ "Face for highlighting `evil' registers in ivy."
+ :group 'ivy-faces)
+
;;;###autoload
(defun counsel-evil-registers ()
"Ivy replacement for `evil-show-registers'."
@@ -4233,11 +4631,15 @@ matching the register's value description against a
regexp in
(if (fboundp 'evil-register-list)
(ivy-read "evil-registers: "
(cl-loop for (key . val) in (evil-register-list)
- collect (format "[%c]: %s" key (if (stringp val) val "")))
+ collect (format "[%s]: %s"
+ (propertize (char-to-string key)
+ 'face
'counsel-evil-register-face)
+ (if (stringp val) val "")))
:require-match t
:action #'counsel-evil-registers-action
:caller 'counsel-evil-registers)
- (user-error "Required feature `evil' not installed.")))
+ (user-error "Required feature `evil' not installed")))
+
(ivy-configure 'counsel-evil-registers
:height 5
:format-fn #'counsel--yank-pop-format-function)
@@ -4257,15 +4659,16 @@ S will be of the form \"[register]: content\"."
(declare-function imenu--make-index-alist "imenu")
(defun counsel--imenu-candidates ()
- (unless (featurep 'imenu)
- (require 'imenu nil t))
+ (require 'imenu)
(let* ((imenu-auto-rescan t)
(imenu-auto-rescan-maxout (if current-prefix-arg
(buffer-size)
imenu-auto-rescan-maxout))
(items (imenu--make-index-alist t))
(items (delete (assoc "*Rescan*" items) items))
- (items (counsel-imenu-categorize-functions items)))
+ (items (if (eq major-mode 'emacs-lisp-mode)
+ (counsel-imenu-categorize-functions items)
+ items)))
(counsel-imenu-get-candidates-from items)))
(defun counsel-imenu-get-candidates-from (alist &optional prefix)
@@ -4308,6 +4711,9 @@ PREFIX is used to create the key."
(with-ivy-window
(imenu (cdr x))))
+(defvar counsel-imenu-history nil
+ "History for `counsel-imenu'.")
+
;;;###autoload
(defun counsel-imenu ()
"Jump to a buffer position indexed by imenu."
@@ -4317,6 +4723,7 @@ PREFIX is used to create the key."
:require-match t
:action #'counsel-imenu-action
:keymap counsel-imenu-map
+ :history 'counsel-imenu-history
:caller 'counsel-imenu))
;;** `counsel-list-processes'
@@ -4389,36 +4796,92 @@ An extra action allows to switch to the process buffer."
(let ((enable-recursive-minibuffers t))
(ivy-read "History: " (ivy-history-contents minibuffer-history-variable)
:keymap ivy-reverse-i-search-map
- :action #'insert
+ :action (lambda (x)
+ (insert (substring-no-properties (car x))))
:caller 'counsel-minibuffer-history)))
;;** `counsel-esh-history'
-(defun counsel--browse-history (ring)
+(defvar comint-input-ring-index)
+(defvar eshell-history-index)
+(defvar slime-repl-input-history-position)
+
+(defvar counsel-esh--index-last nil
+ "Index corresponding to last selection with `counsel-esh-history'.")
+
+(defvar counsel-shell-history--index-last nil
+ "Index corresponding to last selection with `counsel-shell-history'.")
+
+(defun counsel--browse-history-action (pair)
+ (let ((snd (cdr pair)))
+ (cl-case (ivy-state-caller ivy-last)
+ (counsel-esh-history
+ (setq eshell-history-index snd
+ counsel-esh--index-last snd))
+ (counsel-shell-history
+ (setq comint-input-ring-index snd
+ counsel-shell-history--index-last snd))
+ ;; Leave this as a no-op. If someone decides to patch
+ ;; `slime-repl-previous-input' or one of its utility functions,
+ ;; or to add history-replay to Slime, then this section can be
+ ;; updated to add the relevant support for those commands.
+ (counsel-slime-repl-history
+ nil))
+ (ivy-completion-in-region-action (car pair))))
+
+(cl-defun counsel--browse-history (ring &key caller)
"Use Ivy to navigate through RING."
- (setq ivy-completion-beg (point))
- (setq ivy-completion-end (point))
- (ivy-read "History: " (ivy-history-contents ring)
- :keymap ivy-reverse-i-search-map
- :action #'ivy-completion-in-region-action
- :caller 'counsel-shell-history))
+ (let* ((proc (get-buffer-process (current-buffer)))
+ (end (point))
+ (beg (if proc
+ (min (process-mark proc) end)
+ end))
+ (input (when (< beg end)
+ (concat "^" (buffer-substring beg end)))))
+ (setq ivy-completion-beg beg)
+ (setq ivy-completion-end end)
+ (ivy-read "History: " (ivy-history-contents ring)
+ :keymap ivy-reverse-i-search-map
+ :initial-input input
+ :action #'counsel--browse-history-action
+ :caller caller)))
(defvar eshell-history-ring)
+(defvar eshell-matching-input-from-input-string)
;;;###autoload
(defun counsel-esh-history ()
"Browse Eshell history."
(interactive)
(require 'em-hist)
- (counsel--browse-history eshell-history-ring))
+ (counsel--browse-history eshell-history-ring
+ :caller #'counsel-esh-history))
+
+(defadvice eshell-previous-matching-input (before
+ counsel-set-eshell-history-index
+ activate)
+ "Reassign `eshell-history-index'."
+ (when (and (memq last-command '(ivy-alt-done ivy-done))
+ (equal (ivy-state-caller ivy-last) 'counsel-esh-history))
+ (setq eshell-history-index counsel-esh--index-last)))
(defvar comint-input-ring)
+(defvar comint-matching-input-from-input-string)
;;;###autoload
(defun counsel-shell-history ()
"Browse shell history."
(interactive)
(require 'comint)
- (counsel--browse-history comint-input-ring))
+ (counsel--browse-history comint-input-ring
+ :caller #'counsel-shell-history))
+
+(defadvice comint-previous-matching-input (before
+ counsel-set-comint-history-index
+ activate)
+ "Reassign `comint-input-ring-index'."
+ (when (and (memq last-command '(ivy-alt-done ivy-done))
+ (equal (ivy-state-caller ivy-last) 'counsel-shell-history))
+ (setq comint-input-ring-index counsel-shell-history--index-last)))
(defvar slime-repl-input-history)
@@ -4427,7 +4890,13 @@ An extra action allows to switch to the process buffer."
"Browse Slime REPL history."
(interactive)
(require 'slime-repl)
- (counsel--browse-history slime-repl-input-history))
+ (counsel--browse-history slime-repl-input-history
+ :caller #'counsel-slime-repl-history))
+
+;; TODO: add advice for slime-repl-input-previous/next to properly
+;; reassign the ring index and match string. This requires a case for
+;; `counsel-slime-repl-history' within
+;; `counsel--browse-history-action'.
;;** `counsel-hydra-heads'
(defvar hydra-curr-body-fn)
@@ -4532,6 +5001,8 @@ TREEP is used to expand internal nodes."
(counsel-imenu)))
;;** `counsel-outline'
+(declare-function org-trim "org-macs")
+
(defcustom counsel-outline-face-style nil
"Determines how to style outline headings during completion.
@@ -4591,7 +5062,12 @@ Intended as a value for the `:outline-title' setting in
"Return title of current outline heading.
Like `counsel-outline-title' (which see), but for `org-mode'
buffers."
- (apply #'org-get-heading (counsel--org-get-heading-args)))
+ (let ((statistics-re "\\[[0-9]*\\(?:%\\|/[0-9]*\\)]")
+ (heading (apply #'org-get-heading (counsel--org-get-heading-args))))
+ (cond (counsel-org-headline-display-statistics
+ heading)
+ (heading
+ (org-trim (replace-regexp-in-string statistics-re " " heading))))))
(defun counsel-outline-title-markdown ()
"Return title of current outline heading.
@@ -5046,11 +5522,257 @@ selected color."
You can insert or kill the name of the selected font."
(interactive)
- (ivy-read "Font: " (delete-dups (font-family-list))
+ (let ((current-font
+ (symbol-name (font-get (face-attribute 'default :font) :family))))
+ (ivy-read "Font: " (delete-dups (font-family-list))
+ :preselect current-font
+ :require-match t
+ :history 'counsel-fonts-history
+ :action #'insert
+ :caller 'counsel-fonts)))
+
+(ivy-configure 'counsel-fonts
+ :display-transformer-fn #'counsel--font-with-sample)
+
+(defun counsel--font-with-sample (font-name)
+ "Format function for `counsel-fonts'."
+ (format "%-75s%s" font-name
+ (propertize "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ 'face (list :family font-name))))
+
+;;** `counsel-kmacro'
+(defvar counsel-kmacro-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "C-k") #'counsel-kmacro-kill)
+ map))
+
+(defun counsel-kmacro-kill ()
+ "Kill the line, or delete the keyboard macro."
+ (interactive)
+ (if (not (eolp))
+ (ivy-kill-line)
+ (counsel-kmacro-action-delete-kmacro
+ (assoc
+ (ivy-state-current ivy-last)
+ (ivy-state-collection ivy-last)))
+ (ivy--kill-current-candidate)))
+
+;;;###autoload
+(defun counsel-kmacro ()
+ "Interactively choose and run a keyboard macro.
+
+With prefix argument, run macro that many times.
+
+Macros are run using the current value of `kmacro-counter-value'
+and their respective counter format. Displayed next to each macro is
+the counter's format and initial value.
+
+One can use actions to copy the counter format or initial counter
+value of a macro, using them for a new macro."
+ (interactive)
+ (if (or last-kbd-macro kmacro-ring)
+ (ivy-read
+ (concat "Execute macro (counter at "
+ (number-to-string (or kmacro-initial-counter-value
kmacro-counter))
+ "): ")
+ (counsel--kmacro-candidates)
+ :keymap counsel-kmacro-map
+ :require-match t
+ :action #'counsel-kmacro-action-run
+ :caller 'counsel-kmacro)
+ (user-error "No keyboard macros defined")))
+
+(ivy-configure 'counsel-kmacro
+ :format-fn #'counsel--kmacro-format-function)
+
+(defcustom counsel-kmacro-separator "\n------------------------\n"
+ "Separator displayed between keyboard macros in `counsel-kmacro'."
+ :type 'string)
+
+(defun counsel--kmacro-format-function (formatted-kmacro)
+ "Transform FORMATTED-KMACRO into a string for `counsel-kmacro'."
+ (ivy--format-function-generic
+ (lambda (str) (ivy--add-face str 'ivy-current-match))
+ (lambda (str) str)
+ formatted-kmacro
+ (propertize counsel-kmacro-separator 'face 'ivy-separator)))
+
+(defun counsel--kmacro-candidates ()
+ "Create the list of keyboard macros used by `counsel-kmacro'.
+This is a combination of `kmacro-ring' and, together in a list,
`last-kbd-macro',
+`kmacro-counter-format-start', and `kmacro-counter-value-start'."
+ (mapcar
+ (lambda (kmacro)
+ (cons
+ (concat "(" (nth 2 kmacro) "," (number-to-string (nth 1 kmacro)) "): "
+ (condition-case nil
+ (format-kbd-macro (if (listp kmacro) (car kmacro) kmacro) 1)
+ ;; Recover from error from `edmacro-fix-menu-commands'.
+ (error "Warning: Cannot display macros containing mouse
clicks")))
+ kmacro))
+ (cons
+ (if (listp last-kbd-macro)
+ last-kbd-macro
+ (list
+ last-kbd-macro
+ kmacro-counter-value-start
+ kmacro-counter-format-start))
+ kmacro-ring)))
+
+(defun counsel-kmacro-action-run (x)
+ "Run keyboard macro."
+ (let* ((actual-kmacro (cdr x))
+ (kmacro-keys (nth 0 actual-kmacro))
+ (kmacro-counter-format-start (nth 2 actual-kmacro)))
+ ;; With prefix argument, call the macro that many times.
+ (kmacro-call-macro (or current-prefix-arg 1) t nil kmacro-keys)))
+
+(defun counsel-kmacro-action-delete-kmacro (x)
+ "Delete a keyboard macro from within `counsel-kmacro'.
+
+Either delete a macro from `kmacro-ring', or set `last-kbd-macro'
+to the popped head of the ring."
+ (let ((actual-macro (cdr x)))
+ (if (eq (nth 0 actual-macro) last-kbd-macro)
+ (setq last-kbd-macro
+ (if (eq kmacro-ring nil)
+ nil
+ (let ((prev-macro (pop kmacro-ring)))
+ (if (listp prev-macro)
+ (nth 0 prev-macro)
+ prev-macro))))
+ (setq kmacro-ring (delq actual-macro kmacro-ring)))))
+
+(defun counsel-kmacro-action-copy-initial-counter-value (x)
+ "Pass an existing keyboard macro's original value to `kmacro-set-counter'.
+This value will be used by the next executed macro, or as an
+initial value by the next macro defined.
+
+Note that calling an existing macro that itself uses a counter
+effectively resets the initial counter value for the next defined macro
+to 0."
+ ;; NOTE:
+ ;; Calling `kmacro-start-macro' without an argument sets `kmacro-counter'
+ ;; to 0 if `kmacro-initial-counter'is nil, and sets `kmacro-initial-counter'
+ ;; to nil regardless.
+ ;; Using `kmacro-insert-counter' sets `kmacro-initial-counter' to nil.
+ (let* ((actual-kmacro (cdr x))
+ (number (nth 1 actual-kmacro)))
+ (kmacro-set-counter number)))
+
+(defun counsel-kmacro-action-copy-counter-format-for-new-macro (x)
+ "Set `kmacro-default-counter-format' to an existing keyboard macro's counter
format.
+This will apply to the next macro a user defines."
+ (let* ((actual-kmacro (cdr x))
+ (format (nth 2 actual-kmacro)))
+ (kmacro-set-format format)))
+
+(defun counsel-kmacro-action-cycle-ring-to-macro (x)
+ "Cycle `kmacro-ring' until `last-kbd-macro' is the selected macro.
+This is convenient when using \\[kmacro-end-or-call-macro] to call macros.
+Note that cycling the ring changes the starting value of the current macro
+to changes the current macro counter."
+ (let ((actual-kmacro (cdr x)))
+ (unless (equal last-kbd-macro
+ (if (listp last-kbd-macro)
+ last-kbd-macro
+ (car actual-kmacro)))
+ (while (not (equal actual-kmacro
+ (car kmacro-ring)))
+ (kmacro-cycle-ring-previous))
+ ;; Once selected macro is at the head of the ring,
+ ;; cycle one last time.
+ (kmacro-cycle-ring-previous))))
+
+(defun counsel-kmacro-action-set-saved-starting-counter (x)
+ "Set the starting counter value of the chosen macro.
+
+By default, sets to current value of the counter. It has no
+effect when selecting the current macro.
+
+Normally, when cycling keyboard macro ring with \\[kmacro-cycle-ring-previous]
+or \\[kmacro-cycle-ring-next], the current value of the macro counter is
+included with the current macro definition. Then, when cycling
+back, that counter value is restored. This function is meant to
+achieve something similar when cycling macros in the context of
+using `counsel-kmacro', which does not use different counter
+values when running different macros."
+ (let ((actual-kmacro (cdr x))
+ (default-kmacro-counter-string (number-to-string kmacro-counter)))
+ (setq kmacro-ring (mapcar (lambda (this-macro-in-ring)
+ (if (equal this-macro-in-ring actual-kmacro)
+ (list (car this-macro-in-ring)
+ (read-from-minibuffer (concat "Set
initial counter for macro (default: "
+
default-kmacro-counter-string
+ "): ")
+ nil nil t nil
+
default-kmacro-counter-string)
+ (cl-caddr this-macro-in-ring))
+ this-macro-in-ring))
+ kmacro-ring))))
+
+(defun counsel-kmacro-action-execute-after-prompt (x)
+ "Execute an existing keyboard macro, prompting for a starting counter value,
a
+counter format, and the number of times to execute the macro.
+
+If called with a prefix, will suggest that value for both the
+counter value and iteration amount."
+ (let* ((default-string (if current-prefix-arg
+ (number-to-string current-prefix-arg)
+ nil))
+ (actual-kmacro (cdr x))
+ (kmacro-keys (nth 0 actual-kmacro))
+ (kmacro-starting-counter (number-to-string (nth 1 actual-kmacro)))
+ (kmacro-starting-format (nth 2 actual-kmacro))
+ (number-of-iterations
+ (read-from-minibuffer
+ (concat "Enter number of iterations for macro (default: "
+ (or default-string (number-to-string 2))
+ "): ")
+ nil nil t nil
+ (or default-string (number-to-string 2))))
+ (kmacro-initial-counter-value
+ (read-from-minibuffer
+ (concat "Enter a starting counter for macro (default: "
+ (or default-string kmacro-starting-counter)
+ "): ")
+ nil nil t nil
+ (or default-string kmacro-starting-counter)))
+ (kmacro-counter-format-start
+ (symbol-name (read-from-minibuffer
+ (concat "Enter format for macro counter (default: "
+ kmacro-starting-format
+ "): ")
+ nil nil t nil
+ kmacro-starting-format))))
+ (kmacro-call-macro number-of-iterations t nil kmacro-keys)))
+
+(ivy-set-actions
+ 'counsel-kmacro
+ '(("c" counsel-kmacro-action-cycle-ring-to-macro "cycle to")
+ ("d" counsel-kmacro-action-delete-kmacro "delete")
+ ("e" counsel-kmacro-action-execute-after-prompt "execute after prompt")
+ ("f" counsel-kmacro-action-copy-counter-format-for-new-macro "copy counter
format for new macro")
+ ("s" counsel-kmacro-action-set-saved-starting-counter "set this counter
value")
+ ("v" counsel-kmacro-action-copy-initial-counter-value "copy initial counter
value")))
+
+;;** `counsel-geiser-doc-look-up-manual'
+(declare-function geiser-doc-manual-for-symbol "ext:geiser-doc")
+(defvar geiser-completion-symbol-list-func)
+
+(defvar counsel-geiser-doc-look-up-manual-history ()
+ "History for `counsel-geiser-doc-look-up-manual'.")
+
+;;;###autoload
+(defun counsel-geiser-doc-look-up-manual ()
+ "Search Scheme documentation."
+ (interactive)
+ (ivy-read "Symbol: " geiser-completion-symbol-list-func
:require-match t
- :history 'counsel-fonts-history
- :action #'insert
- :caller 'counsel-fonts))
+ :history 'counsel-geiser-doc-look-up-manual-history
+ :action (lambda (cand)
+ (geiser-doc-manual-for-symbol (intern cand)))
+ :caller 'counsel-geiser-doc-look-up-manual))
;;* Misc. OS
;;** `counsel-rhythmbox'
@@ -5093,6 +5815,15 @@ You can insert or kill the name of the selected font."
(dbus-call-method :session service path interface
"AddToQueue" (cdr song))))
+(defun counsel-rhythmbox-playpause-current-song ()
+ "Play/pause the current song."
+ (interactive)
+ (let ((service "org.gnome.Rhythmbox3")
+ (path "/org/mpris/MediaPlayer2")
+ (interface "org.mpris.MediaPlayer2.Player"))
+ (dbus-call-method :session service path interface
+ "PlayPause")))
+
(defun counsel-rhythmbox-toggle-shuffle (_song)
"Toggle Rhythmbox shuffle setting."
(let* ((old-order (counsel--command "dconf" "read"
"/org/gnome/rhythmbox/player/play-order"))
@@ -5164,6 +5895,8 @@ You can insert or kill the name of the selected font."
:caller 'counsel-rhythmbox))
;;** `counsel-linux-app'
+
+;; Added in Emacs 26.1.
(require 'xdg nil t)
(defalias 'counsel--xdg-data-home
@@ -5201,6 +5934,7 @@ as arguments."
(const :tag "Command : Name - Comment"
counsel-linux-app-format-function-default)
(const :tag "Name - Comment (Command)"
counsel-linux-app-format-function-name-first)
(const :tag "Name - Comment"
counsel-linux-app-format-function-name-only)
+ (const :tag "Name - Comment (Pretty)"
counsel-linux-app-format-function-name-pretty)
(const :tag "Command" counsel-linux-app-format-function-command-only)
(function :tag "Custom")))
@@ -5275,7 +6009,9 @@ NAME is the name of the application, COMMENT its comment
and EXEC
the command to launch it."
(format "% -45s: %s%s"
(propertize
- (ivy--truncate-string exec 45)
+ (ivy--truncate-string
+ (replace-regexp-in-string "env +[^ ]+ +" "" exec)
+ 45)
'face 'counsel-application-name)
name
(if comment
@@ -5304,6 +6040,16 @@ EXEC is the command to launch the application."
"Display only the command EXEC when formatting Linux application names."
exec)
+(defun counsel-linux-app-format-function-name-pretty (name comment _exec)
+ "Format Linux application names with the NAME (and COMMENT) only, but
pretty."
+ (format "% -45s%s"
+ (propertize
+ (ivy--truncate-string name 45)
+ 'face 'counsel-application-name)
+ (if comment
+ (concat ": " comment)
+ "")))
+
(defun counsel-linux-apps-list-desktop-files ()
"Return an alist of all Linux applications.
Each list entry is a pair of (desktop-name . desktop-file).
@@ -5313,6 +6059,7 @@ This function always returns its elements in a stable
order."
(dolist (dir counsel-linux-apps-directories)
(when (file-exists-p dir)
(let ((dir (file-name-as-directory dir)))
+ ;; Function `directory-files-recursively' added in Emacs 25.1.
(dolist (file (directory-files-recursively dir ".*\\.desktop$"))
(let ((id (subst-char-in-string ?/ ?- (file-relative-name file
dir))))
(when (and (not (gethash id hash)) (file-readable-p file))
@@ -5433,7 +6180,7 @@ Any desktop entries that fail to parse are recorded in
"Launch a Linux desktop application, similar to Alt-<F2>.
When ARG is non-nil, ignore NoDisplay property in *.desktop files."
(interactive "P")
- (ivy-read "Run a command: " (counsel-linux-apps-list)
+ (ivy-read "Run application: " (counsel-linux-apps-list)
:predicate (unless arg (lambda (x) (get-text-property 0 'visible
(car x))))
:action #'counsel-linux-app-action-default
:caller 'counsel-linux-app))
@@ -5481,15 +6228,22 @@ The buffers are those opened during a session of
`counsel-switch-buffer'."
(setq counsel--switch-buffer-temporary-buffers nil
counsel--switch-buffer-previous-buffers nil))
+(defcustom counsel-switch-buffer-preview-virtual-buffers t
+ "When non-nil, `counsel-switch-buffer' will preview virtual buffers."
+ :type 'boolean)
+
(defun counsel--switch-buffer-update-fn ()
(unless counsel--switch-buffer-previous-buffers
(setq counsel--switch-buffer-previous-buffers (buffer-list)))
- (let* ((current (ivy-state-current ivy-last))
- (virtual (assoc current ivy--virtual-buffers)))
+ (let* ((virtual (assoc (ivy-state-current ivy-last) ivy--virtual-buffers)))
+ (when (member (ivy-state-current ivy-last) ivy-marked-candidates)
+ (setf (ivy-state-current ivy-last)
+ (substring (ivy-state-current ivy-last) (length ivy-mark-prefix))))
(cond
- ((get-buffer current)
- (ivy-call))
- ((and virtual (file-exists-p (cdr virtual)))
+ ((get-buffer (ivy-state-current ivy-last))
+ (let ((ivy-marked-candidates nil))
+ (ivy-call)))
+ ((and counsel-switch-buffer-preview-virtual-buffers virtual
(file-exists-p (cdr virtual)))
(let ((buf (ignore-errors
;; may not open due to `large-file-warning-threshold' etc.
(find-file-noselect (cdr virtual)))))
@@ -5572,7 +6326,8 @@ This variable is suitable for addition to
`savehist-additional-variables'.")
(defvar counsel-compile-root-functions
- '(counsel--project-current
+ '(counsel--projectile-root
+ counsel--project-current
counsel--configure-root
counsel--git-root
counsel--dir-locals-root)
@@ -5587,6 +6342,12 @@ The root is determined by
`counsel-compile-root-functions'."
(or (run-hook-with-args-until-success 'counsel-compile-root-functions)
(error "Couldn't find project root")))
+(defun counsel--projectile-root ()
+ "Return root of current projectile project or nil on failure.
+Use `projectile-project-root' to determine the root."
+ (and (fboundp 'projectile-project-root)
+ (projectile-project-root)))
+
(defun counsel--project-current ()
"Return root of current project or nil on failure.
Use `project-current' to determine the root."
@@ -5611,7 +6372,8 @@ Use the presence of a `dir-locals-file' to determine the
root."
(defvar counsel-compile-local-builds
'(counsel-compile-get-filtered-history
counsel-compile-get-build-directories
- counsel-compile-get-make-invocation)
+ counsel-compile-get-make-invocation
+ counsel-compile-get-make-help-invocations)
"Additional compile invocations to feed into `counsel-compile'.
This can either be a list of compile invocation strings or
@@ -5651,26 +6413,30 @@ list is passed to `compilation-environment'."
(defvar counsel-compile-phony-pattern "^\\.PHONY:[\t ]+\\(.+\\)$"
"Regexp for extracting phony targets from Makefiles.")
-;; This is loosely based on the Bash Make completion code
+(defvar counsel-compile-help-pattern
+ "\\(?:^\\(\\*\\)?[[:space:]]+\\([^[:space:]]+\\)[[:space:]]+-\\)"
+ "Regexp for extracting help targets from a make help call.")
+
+;; This is loosely based on the Bash Make completion code which
+;; relies on GNUMake having the following return codes:
+;; 0 = no-rebuild, -q & 1 needs rebuild, 2 error
(defun counsel-compile--probe-make-targets (dir)
"Return a list of Make targets for DIR.
-Return an empty list is Make exits with an error. This might
-happen because some sort of configuration needs to be done first
-or the source tree is pristine and being used for multiple build
-trees."
- (let ((default-directory dir)
- (targets nil))
- (with-temp-buffer
- ;; 0 = no-rebuild, -q & 1 needs rebuild, 2 error (for GNUMake at
- ;; least)
- (when (< (call-process "make" nil t nil "-nqp") 2)
+Return a single blank target (so we invoke the default target)
+if Make exits with an error. This might happen because some sort
+of configuration needs to be done first or the source tree is
+pristine and being used for multiple build trees."
+ (with-temp-buffer
+ (let* ((default-directory dir)
+ (res (call-process "make" nil t nil "-nqp"))
+ targets)
+ (if (or (not (numberp res)) (> res 1))
+ (list "")
(goto-char (point-min))
(while (re-search-forward counsel-compile-phony-pattern nil t)
- (setq targets
- (nconc targets (split-string
- (match-string-no-properties 1)))))))
- (sort targets #'string-lessp)))
+ (push (split-string (match-string-no-properties 1)) targets))
+ (sort (apply #'nconc targets) #'string-lessp)))))
(defun counsel-compile--pretty-propertize (leader text face)
"Return a pretty string of the form \" LEADER TEXT\".
@@ -5681,12 +6447,13 @@ text with FACE."
'font-lock-warning-face)
(propertize text 'face face)))
-(defun counsel--compile-get-make-targets (srcdir &optional blddir)
- "Return a list of Make targets for a given SRCDIR/BLDDIR combination.
+(defun counsel--compile-get-make-targets (probe-fn srcdir &optional blddir)
+ "Return propertized make targets returned by PROBE-FN in SRCDIR.
-We search the Makefile for a list of phony targets which are
-generally the top level targets a Make system provides.
-The resulting strings are tagged with properties that
+The optional BLDDIR allows for handling build directories. We
+search the Makefile for a list of phony targets which are
+generally the top level targets a Make system provides. The
+resulting strings are tagged with properties that
`counsel-compile-history' can use for filtering results."
(let ((fmt (format (propertize "make %s %%s" 'cmd t)
counsel-compile-make-args))
@@ -5703,7 +6470,7 @@ The resulting strings are tagged with properties that
(setq target (concat (format fmt target) suffix build-env))
(add-text-properties 0 (length target) props target)
target)
- (counsel-compile--probe-make-targets (or blddir srcdir)))))
+ (funcall probe-fn (or blddir srcdir)))))
(defun counsel-compile-get-make-invocation (&optional blddir)
"Have a look in the root directory for any build control files.
@@ -5713,7 +6480,41 @@ sub-directories that builds may be invoked in."
(let ((srcdir (counsel--compile-root)))
(when (directory-files (or blddir srcdir) nil
counsel-compile-make-pattern t)
- (counsel--compile-get-make-targets srcdir blddir))))
+ (counsel--compile-get-make-targets
+ #'counsel-compile--probe-make-targets srcdir blddir))))
+
+(defun counsel-compile--probe-make-help (dir)
+ "Return a list of Make targets based on help for DIR.
+
+It is quite common for a 'make help' invocation to return a human
+readable list of targets. Often common targets are marked with a
+leading asterisk. The exact search pattern is controlled by
+`counsel-compile-help-pattern'."
+ (let ((default-directory dir)
+ primary-targets targets)
+ ;; Only proceed if the help target exists.
+ (when (eql 1 (apply #'call-process "make" nil nil nil "-q" "help"
+ counsel-compile-env))
+ (with-temp-buffer
+ (when (eql 0 (apply #'call-process "make" nil t nil "help"
+ counsel-compile-env))
+ (goto-char (point-min))
+ (while (re-search-forward counsel-compile-help-pattern nil t)
+ (push (match-string 2)
+ (if (match-beginning 1) primary-targets targets)))
+ (nconc (sort primary-targets #'string-lessp)
+ (sort targets #'string-lessp)))))))
+
+(defun counsel-compile-get-make-help-invocations (&optional blddir)
+ "Query the root directory for makefiles with help output.
+
+The optional BLDDIR is useful for other helpers that have found
+sub-directories that builds may be invoked in."
+ (let ((srcdir (counsel--compile-root)))
+ (when (directory-files (or blddir srcdir) nil
+ counsel-compile-make-pattern t)
+ (counsel--compile-get-make-targets
+ #'counsel-compile--probe-make-help srcdir blddir))))
(defun counsel--find-build-subdir (srcdir)
"Return builds subdirectory of SRCDIR, if one exists."
@@ -5827,9 +6628,36 @@ specified by the `blddir' property."
(compile cmd)
(remove-hook 'compilation-start-hook
#'counsel-compile--update-history))))))
+(defun counsel-compile-edit-command ()
+ "Insert current compile command into the minibuffer for editing.
+
+This mirrors the behavior of `ivy-insert-current' but with specific
+handling for the `counsel-compile' metadata."
+ (interactive)
+ (delete-minibuffer-contents)
+ (let* ((cmd (ivy-state-current ivy-last))
+ (blddir (get-text-property 0 'blddir cmd)))
+ (when blddir
+ (setq counsel-compile--current-build-dir blddir))
+ (insert (substring-no-properties
+ cmd 0 (and (get-text-property 0 'cmd cmd)
+ (next-single-property-change 0 'cmd cmd))))))
+
+;; Currently the only thing we do is override ivy's default insert
+;; operation which doesn't include the metadata we want.
+(defvar counsel-compile-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap ivy-insert-current] #'counsel-compile-edit-command)
+ map)
+ "Additional ivy keybindings during command selection.")
+
;;;###autoload
(defun counsel-compile (&optional dir)
- "Call `compile' completing with smart suggestions, optionally for DIR."
+ "Call `compile' completing with smart suggestions, optionally for DIR.
+
+Additional actions:
+
+\\{counsel-compile-map}"
(interactive)
(setq counsel-compile--current-build-dir (or dir
(counsel--compile-root)
@@ -5837,8 +6665,17 @@ specified by the `blddir' property."
(ivy-read "Compile command: "
(delete-dups (counsel--get-compile-candidates dir))
:action #'counsel-compile--action
+ :keymap counsel-compile-map
:caller 'counsel-compile))
+(ivy-add-actions
+ 'counsel-compile
+ '(("d" counsel-compile-forget-command "delete")))
+
+(defun counsel-compile-forget-command (cmd)
+ "Delete CMD from `counsel-compile-history'."
+ (setq counsel-compile-history
+ (delete cmd counsel-compile-history)))
(defun counsel-compile-env--format-hint (cands)
"Return a formatter for compile-env CANDS."
@@ -5893,7 +6730,7 @@ and minor mode symbol."
(mapcar
(lambda (mode)
(when (and (boundp mode) (commandp mode))
- (let ((lighter (alist-get mode minor-mode-alist)))
+ (let ((lighter (cdr (assq mode minor-mode-alist))))
(cons (concat
(if (symbol-value mode) "-" "+")
(symbol-name mode)
@@ -5951,19 +6788,42 @@ Additional actions:\\<ivy-minibuffer-map>
:action #'counsel-M-x-action
:caller 'counsel-major))
-;;* `counsel-google'
+;;** `counsel-search'
(declare-function request "ext:request")
-(defun counsel-google-function (input)
- "Create a request to Google with INPUT.
+
+(defcustom counsel-search-engine 'ddg
+ "The search engine choice in `counsel-search-engines-alist'."
+ :type '(choice
+ (const ddg)
+ (const google)))
+
+(defcustom counsel-search-engines-alist
+ '((google
+ "http://suggestqueries.google.com/complete/search"
+ "https://www.google.com/search?q="
+ counsel--search-request-data-google)
+ (ddg
+ "https://duckduckgo.com/ac/"
+ "https://duckduckgo.com/html/?q="
+ counsel--search-request-data-ddg))
+ "Search engine parameters for `counsel-search'."
+ :type '(list))
+
+(defun counsel--search-request-data-google (data)
+ (mapcar #'identity (aref data 1)))
+
+(defun counsel--search-request-data-ddg (data)
+ (mapcar #'cdar data))
+
+(defun counsel-search-function (input)
+ "Create a request to a search engine with INPUT.
Return 0 tells `ivy--exhibit' not to update the minibuffer.
We update it in the callback with `ivy-update-candidates'."
(or
(ivy-more-chars)
- (progn
- (require 'request)
- (require 'json)
+ (let ((engine (cdr (assoc counsel-search-engine
counsel-search-engines-alist))))
(request
- "http://suggestqueries.google.com/complete/search"
+ (nth 0 engine)
:type "GET"
:params (list
(cons "client" "firefox")
@@ -5972,17 +6832,119 @@ We update it in the callback with
`ivy-update-candidates'."
:success (cl-function
(lambda (&key data &allow-other-keys)
(ivy-update-candidates
- (mapcar #'identity (aref data 1))))))
+ (funcall (nth 2 engine) data)))))
0)))
-(defun counsel-google ()
- "Ivy interface for Google."
+(defun counsel-search-action (x)
+ "Search for X."
+ (browse-url
+ (concat
+ (nth 2 (assoc counsel-search-engine counsel-search-engines-alist))
+ (url-hexify-string x))))
+
+(defun counsel-search ()
+ "Ivy interface for dynamically querying a search engine."
(interactive)
- (ivy-read "search: " #'counsel-google-function
- :action (lambda (x)
- (browse-url (concat "https://www.google.com/search?q="
x)))
+ (require 'request)
+ (require 'json)
+ (ivy-read "search: " #'counsel-search-function
+ :action #'counsel-search-action
:dynamic-collection t
- :caller 'counsel-google))
+ :caller 'counsel-search))
+
+(define-obsolete-function-alias 'counsel-google
+ 'counsel-search "<2019-10-17 Thu>")
+
+;;** `counsel-compilation-errors'
+(defun counsel--compilation-errors-buffer (buf)
+ (with-current-buffer buf
+ (let ((res nil)
+ (pt (point-min)))
+ (save-excursion
+ (while (setq pt (compilation-next-single-property-change
+ pt 'compilation-message))
+ (let ((loc (get-text-property pt 'compilation-message)))
+ (when (and loc (setq loc (compilation--message->loc loc)))
+ (goto-char pt)
+ (push
+ (propertize
+ (buffer-substring-no-properties pt (line-end-position))
+ 'pt pt
+ 'buffer buf)
+ res)))))
+ (nreverse res))))
+
+(defun counsel-compilation-errors-cands ()
+ (cl-loop
+ for buf in (buffer-list)
+ when (compilation-buffer-p buf)
+ nconc (counsel--compilation-errors-buffer buf)))
+
+(defun counsel-compilation-errors-action (x)
+ (pop-to-buffer (get-text-property 0 'buffer x))
+ (goto-char (get-text-property 0 'pt x))
+ (compile-goto-error))
+
+;;;###autoload
+(defun counsel-compilation-errors ()
+ "Compilation errors."
+ (interactive)
+ (ivy-read "compilation errors: " (counsel-compilation-errors-cands)
+ :require-match t
+ :action #'counsel-compilation-errors-action
+ :history 'counsel-compilation-errors-history))
+
+;;** `counsel-flycheck'
+(defvar flycheck-current-errors)
+(declare-function flycheck-error-filename "ext:flycheck")
+(declare-function flycheck-error-line "ext:flycheck")
+(declare-function flycheck-error-message "ext:flycheck")
+(declare-function flycheck-jump-to-error "ext:flycheck")
+
+(defun counsel-flycheck-errors-cands ()
+ (mapcar
+ (lambda (err)
+ (propertize
+ (format "%s:%d:%s"
+ (file-name-base (flycheck-error-filename err))
+ (flycheck-error-line err)
+ (flycheck-error-message err)) 'error err))
+ flycheck-current-errors))
+
+(defun counsel-flycheck-occur (cands)
+ "Generate a custom occur buffer for `counsel-flycheck'."
+ (unless (eq major-mode 'ivy-occur-grep-mode)
+ (ivy-occur-grep-mode)
+ (setq default-directory (ivy-state-directory ivy-last)))
+ (swiper--occur-insert-lines
+ (mapcar
+ (lambda (cand)
+ (let ((err (get-text-property 0 'error cand)))
+ (propertize
+ (format
+ "%s:%d:%s"
+ (flycheck-error-filename err)
+ (flycheck-error-line err)
+ cand)
+ 'error err)))
+ cands)))
+
+(defun counsel-flycheck-errors-action (err)
+ (flycheck-jump-to-error (get-text-property 0 'error err)))
+
+(ivy-configure 'counsel-flycheck
+ :occur #'counsel-flycheck-occur)
+
+;;;###autoload
+(defun counsel-flycheck ()
+ "Flycheck errors."
+ (interactive)
+ (require 'flycheck)
+ (ivy-read "flycheck errors: " (counsel-flycheck-errors-cands)
+ :require-match t
+ :action #'counsel-flycheck-errors-action
+ :history 'counsel-flycheck-errors-history))
+
;;* `counsel-mode'
(defvar counsel-mode-map
@@ -5992,6 +6954,7 @@ We update it in the callback with
`ivy-update-candidates'."
(describe-bindings . counsel-descbinds)
(describe-function . counsel-describe-function)
(describe-variable . counsel-describe-variable)
+ (describe-symbol . counsel-describe-symbol)
(apropos-command . counsel-apropos)
(describe-face . counsel-describe-face)
(list-faces-display . counsel-faces)
@@ -6003,6 +6966,7 @@ We update it in the callback with
`ivy-update-candidates'."
(yank-pop . counsel-yank-pop)
(info-lookup-symbol . counsel-info-lookup-symbol)
(pop-to-mark-command . counsel-mark-ring)
+ (geiser-doc-look-up-manual . counsel-geiser-doc-look-up-manual)
(bookmark-jump . counsel-bookmark)))
(define-key map (vector 'remap (car binding)) (cdr binding)))
map)
@@ -6027,13 +6991,11 @@ Local bindings (`counsel-mode-map'):
:lighter " counsel"
(if counsel-mode
(progn
- (when (and (fboundp 'advice-add)
- counsel-mode-override-describe-bindings)
+ (when counsel-mode-override-describe-bindings
(advice-add #'describe-bindings :override #'counsel-descbinds))
(define-key minibuffer-local-map (kbd "C-r")
'counsel-minibuffer-history))
- (when (fboundp 'advice-remove)
- (advice-remove #'describe-bindings #'counsel-descbinds))))
+ (advice-remove #'describe-bindings #'counsel-descbinds)))
(provide 'counsel)