(format "%d chars more" (- n (length ivy-text)))))
(defun counsel-unquote-regex-parens (str)
- (replace-regexp-in-string
- "\\\\)" ")"
- (replace-regexp-in-string
- "\\\\(" "("
- str)))
+ (let ((start 0)
+ ms)
+ (while (setq start (string-match "\\\\)\\|\\\\(\\|[()]" str start))
+ (setq ms (match-string-no-properties 0 str))
+ (cond ((equal ms "\\(")
+ (setq str (replace-match "(" nil t str))
+ (setq start (+ start 1)))
+ ((equal ms "\\)")
+ (setq str (replace-match ")" nil t str))
+ (setq start (+ start 1)))
+ ((equal ms "(")
+ (setq str (replace-match "\\(" nil t str))
+ (setq start (+ start 2)))
+ ((equal ms ")")
+ (setq str (replace-match "\\)" nil t str))
+ (setq start (+ start 2)))
+ (t
+ (error "unexpected"))))
+ str))
(defun counsel-directory-parent (dir)
"Return the directory parent of directory DIR."
"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.")
+
+(defvar counsel--async-duration nil
+ "Store the time in seconds between starting a process and
+ receiving all candidates.")
+
(defvar counsel--async-exit-code-plist nil
"Associates exit codes with reasons.")
counsel--process
counsel--process
cmd))
- (setq counsel--async-time (current-time))
+ (setq counsel--async-start
+ (setq counsel--async-time (current-time)))
(set-process-sentinel proc (or process-sentinel #'counsel--async-sentinel))
(set-process-filter proc (or process-filter #'counsel--async-filter))))
(ivy--set-candidates
(ivy--sort-maybe
cands))
- (if (null ivy--old-cands)
- (setq ivy--index
- (or (ivy--preselect-index
- (ivy-state-preselect ivy-last)
- ivy--all-candidates)
- 0))
- (let ((re (funcall ivy--regex-function ivy-text)))
- (unless (stringp re)
- (setq re (caar re)))
+ (setq counsel--async-duration
+ (time-to-seconds (time-since counsel--async-start)))
+ (let ((re (funcall ivy--regex-function ivy-text)))
+ (unless (stringp re)
+ (setq re (caar re)))
+ (if (null ivy--old-cands)
+ (unless (setq ivy--index (ivy--preselect-index
+ (ivy-state-preselect ivy-last)
+ ivy--all-candidates))
+ (ivy--recompute-index
+ ivy-text re ivy--all-candidates))
(ivy--recompute-index
ivy-text re ivy--all-candidates)))
(setq ivy--old-cands ivy--all-candidates)
;;** `counsel-M-x'
(ivy-set-actions
'counsel-M-x
- '(("d" counsel--find-symbol "definition")))
+ '(("d" counsel--find-symbol "definition")
+ ("h" (lambda (x) (describe-function (intern x))) "help")))
(ivy-set-display-transformer
'counsel-M-x
(defvar counsel--git-dir nil
"Store the base git directory.")
+(ivy-set-actions
+ 'counsel-git
+ '(("j"
+ find-file-other-window
+ "other")))
+
;;;###autoload
(defun counsel-git ()
"Find file in the current Git repository."
(ivy--exhibit)))))))))
(defun counsel-git-grep-occur ()
- "Generate a custom occur buffer for `counsel-git-grep'."
- (ivy-occur-grep-mode)
- (setq default-directory counsel--git-grep-dir)
+ "Generate a custom occur buffer for `counsel-git-grep'.
+When REVERT is non-nil, regenerate the current *ivy-occur* buffer."
+ (unless (eq major-mode 'ivy-occur-grep-mode)
+ (ivy-occur-grep-mode)
+ (setq default-directory counsel--git-grep-dir))
(let ((cands (split-string
(shell-command-to-string
(format counsel-git-grep-cmd
(when f (expand-file-name f))))
:require-match 'confirm-after-completion
:history 'file-name-history
- :keymap counsel-find-file-map))
+ :keymap counsel-find-file-map
+ :caller 'counsel-find-file))
(defun counsel-up-directory ()
"Go to the parent directory preselecting the current one."
;;* Grep
;;** `counsel-ag'
+(defvar counsel-ag-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "C-l") 'counsel-git-grep-recenter)
+ (define-key map (kbd "M-q") 'counsel-git-grep-query-replace)
+ map))
+
(defcustom counsel-ag-base-command "ag --nocolor --nogroup %s -- ."
"Format string to use in `cousel-ag-function' to construct the
command. %S will be replaced by the regex string. The default is
'counsel-ag-function
:initial-input initial-input
:dynamic-collection t
+ :keymap counsel-ag-map
:history 'counsel-git-grep-history
:action #'counsel-git-grep-action
:unwind (lambda ()
(defun counsel-ag-occur ()
"Generate a custom occur buffer for `counsel-ag'."
- (ivy-occur-grep-mode)
+ (unless (eq major-mode 'ivy-occur-grep-mode)
+ (ivy-occur-grep-mode))
(setq default-directory counsel--git-grep-dir)
(let* ((regex (counsel-unquote-regex-parens
(setq ivy--old-re
- (ivy--regex ivy-text))))
+ (ivy--regex
+ (progn (string-match "\"\\(.*\\)\"" (buffer-name))
+ (match-string 1 (buffer-name)))))))
(cands (split-string
(shell-command-to-string
(format counsel-ag-base-command (shell-quote-argument regex)))
(call-interactively 'counsel-ag)))
;;** `counsel-grep'
+(defcustom counsel-grep-base-command "grep -nE \"%s\" %s"
+ "Format string to use in `cousel-grep-function' to construct
+the command."
+ :type 'string
+ :group 'ivy)
+
(defun counsel-grep-function (string)
"Grep in the current directory for STRING."
- (if (< (length string) 3)
- (counsel-more-chars 3)
+ (if (< (length string) 2)
+ (counsel-more-chars 2)
(let ((regex (counsel-unquote-regex-parens
(setq ivy--old-re
(ivy--regex string)))))
(counsel--async-command
- (format "grep -nP --ignore-case '%s' %s" regex counsel--git-grep-dir))
+ (format counsel-grep-base-command regex counsel--git-grep-dir))
nil)))
(defun counsel-grep-action (x)
- (when (string-match "\\`\\([0-9]+\\):\\(.*\\)\\'" x)
- (with-ivy-window
- (let ((file-name counsel--git-grep-dir)
- (line-number (match-string-no-properties 1 x)))
+ (with-ivy-window
+ (swiper--cleanup)
+ (let ((default-directory (file-name-directory counsel--git-grep-dir))
+ file-name line-number)
+ (when (cond ((string-match "\\`\\([0-9]+\\):\\(.*\\)\\'" x)
+ (setq file-name counsel--git-grep-dir)
+ (setq line-number (match-string-no-properties 1 x)))
+ ((string-match "\\`\\([^:]+\\):\\([0-9]+\\):\\(.*\\)\\'" x)
+ (setq file-name (match-string-no-properties 1 x))
+ (setq line-number (match-string-no-properties 2 x)))
+ (t nil))
(find-file file-name)
(goto-char (point-min))
(forward-line (1- (string-to-number line-number)))
(re-search-forward (ivy--regex ivy-text t) (line-end-position) t)
- (unless (eq ivy-exit 'done)
- (swiper--cleanup)
+ (if (eq ivy-exit 'done)
+ (swiper--ensure-visible)
(isearch-range-invisible (line-beginning-position)
(line-end-position))
(swiper--add-overlays (ivy--regex ivy-text)))))))
+(defun counsel-grep-occur ()
+ "Generate a custom occur buffer for `counsel-grep'."
+ (unless (eq major-mode 'ivy-occur-grep-mode)
+ (ivy-occur-grep-mode))
+ (let ((cands
+ (split-string
+ (shell-command-to-string
+ (format counsel-grep-base-command
+ (counsel-unquote-regex-parens
+ (setq ivy--old-re
+ (ivy--regex
+ (progn (string-match "\"\\(.*\\)\"" (buffer-name))
+ (match-string 1 (buffer-name))) t)))
+ counsel--git-grep-dir))
+ "\n" t))
+ (file (file-name-nondirectory counsel--git-grep-dir)))
+ ;; 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 cands)))
+ (ivy--occur-insert-lines
+ (mapcar
+ (lambda (cand) (concat "./" file ":" cand))
+ cands))))
+
+(ivy-set-occur 'counsel-grep 'counsel-grep-occur)
+(counsel-set-async-exit-code 'counsel-grep 1 "")
+
;;;###autoload
(defun counsel-grep ()
"Grep for a string in the current file."
("s" counsel-list-processes-action-switch "switch"))
:caller 'counsel-list-processes))
+;;** `counsel-ace-link'
+(defun counsel-ace-link ()
+ "Use Ivy completion for `ace-link'."
+ (interactive)
+ (let (collection action)
+ (cond ((eq major-mode 'Info-mode)
+ (setq collection 'ace-link--info-collect)
+ (setq action 'ace-link--info-action))
+ ((eq major-mode 'help-mode)
+ (setq collection 'ace-link--help-collect)
+ (setq action 'ace-link--help-action))
+ ((eq major-mode 'woman-mode)
+ (setq collection 'ace-link--woman-collect)
+ (setq action 'ace-link--woman-action))
+ ((eq major-mode 'eww-mode)
+ (setq collection 'ace-link--eww-collect)
+ (setq action 'ace-link--eww-action))
+ ((eq major-mode 'compilation-mode)
+ (setq collection 'ace-link--eww-collect)
+ (setq action 'ace-link--compilation-action))
+ ((eq major-mode 'org-mode)
+ (setq collection 'ace-link--org-collect)
+ (setq action 'ace-link--org-action)))
+ (if (null collection)
+ (error "%S is not supported" major-mode)
+ (ivy-read "Ace-Link: " (funcall collection)
+ :action action
+ :require-match t
+ :caller 'counsel-ace-link))))
+;;** `counsel-expression-history'
+;;;###autoload
+(defun counsel-expression-history ()
+ "Select an element of `read-expression-history'.
+And insert it into the minibuffer. Useful during
+`eval-expression'"
+ (interactive)
+ (let ((enable-recursive-minibuffers t))
+ (ivy-read "Expr: " (delete-dups read-expression-history)
+ :action #'insert)))
+
+;;** `counsel-esh-history'
+(defun counsel--browse-history (elements)
+ "Use Ivy to navigate through ELEMENTS."
+ (setq ivy-completion-beg (point))
+ (setq ivy-completion-end (point))
+ (ivy-read "Symbol name: "
+ (delete-dups
+ (ring-elements elements))
+ :action #'ivy-completion-in-region-action))
+
+(defvar eshell-history-ring)
+
+;;;###autoload
+(defun counsel-esh-history ()
+ "Browse Eshell history."
+ (interactive)
+ (require 'em-hist)
+ (counsel--browse-history eshell-history-ring))
+
+(defvar comint-input-ring)
+
+;;;###autoload
+(defun counsel-shell-history ()
+ "Browse shell history."
+ (interactive)
+ (require 'comint)
+ (counsel--browse-history comint-input-ring))
+
;;* Misc OS
;;** `counsel-rhythmbox'
(defvar helm-rhythmbox-library)