2018-01-08 19:03:38 -05:00
|
|
|
;;; completion/ivy/autoload/ivy.el -*- lexical-binding: t; -*-
|
|
|
|
|
2019-03-07 01:18:11 +10:00
|
|
|
(defun +ivy--is-workspace-buffer-p (buffer)
|
|
|
|
(let ((buffer (car buffer)))
|
|
|
|
(when (stringp buffer)
|
|
|
|
(setq buffer (get-buffer buffer)))
|
|
|
|
(+workspace-contains-buffer-p buffer)))
|
|
|
|
|
2019-03-07 11:07:45 +10:00
|
|
|
(defun +ivy--is-workspace-other-buffer-p (buffer)
|
2018-01-08 14:41:41 -05:00
|
|
|
(let ((buffer (car buffer)))
|
|
|
|
(when (stringp buffer)
|
|
|
|
(setq buffer (get-buffer buffer)))
|
|
|
|
(and (not (eq buffer (current-buffer)))
|
|
|
|
(+workspace-contains-buffer-p buffer))))
|
|
|
|
|
2018-10-17 14:34:43 -04:00
|
|
|
;;;###autoload
|
|
|
|
(defun +ivy-rich-buffer-name (candidate)
|
|
|
|
"Display the buffer name.
|
|
|
|
|
2019-04-07 15:10:22 -04:00
|
|
|
Buffers that are considered unreal (see `doom-real-buffer-p') are dimmed with
|
2019-04-07 15:54:03 -04:00
|
|
|
`+ivy-buffer-unreal-face'."
|
2019-04-10 19:22:29 -04:00
|
|
|
(let ((b (get-buffer candidate)))
|
2019-06-25 11:19:23 +02:00
|
|
|
(when-let* (((null uniquify-buffer-name-style))
|
|
|
|
(file-path (buffer-file-name b))
|
|
|
|
(uniquify-buffer-name-style 'forward))
|
|
|
|
(setq candidate
|
|
|
|
(uniquify-get-proposed-name
|
|
|
|
(replace-regexp-in-string "<[0-9]+>$" "" (buffer-name b))
|
|
|
|
(directory-file-name
|
|
|
|
(if file-path
|
|
|
|
(file-name-directory file-path)
|
|
|
|
default-directory))
|
|
|
|
1)))
|
2019-04-10 19:22:29 -04:00
|
|
|
(cond ((ignore-errors
|
|
|
|
(file-remote-p
|
|
|
|
(buffer-local-value 'default-directory b)))
|
|
|
|
(ivy-append-face candidate 'ivy-remote))
|
|
|
|
((doom-unreal-buffer-p b)
|
|
|
|
(ivy-append-face candidate +ivy-buffer-unreal-face))
|
|
|
|
((not (buffer-file-name b))
|
|
|
|
(ivy-append-face candidate 'ivy-subdir))
|
|
|
|
((buffer-modified-p b)
|
|
|
|
(ivy-append-face candidate 'ivy-modified-buffer))
|
|
|
|
(candidate))))
|
2019-04-06 01:31:59 -04:00
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(defun +ivy-rich-buffer-icon (candidate)
|
2019-04-26 23:48:49 +10:00
|
|
|
"Display the icon for CANDIDATE buffer."
|
|
|
|
;; NOTE This is inspired by `all-the-icons-ivy-buffer-transformer', minus the
|
|
|
|
;; buffer name and extra padding as those are handled by `ivy-rich'.
|
|
|
|
(propertize "\t" 'display
|
|
|
|
(if-let* ((buffer (get-buffer candidate))
|
|
|
|
(mode (buffer-local-value 'major-mode buffer)))
|
|
|
|
(or
|
|
|
|
(all-the-icons-ivy--icon-for-mode mode)
|
|
|
|
(all-the-icons-ivy--icon-for-mode (get mode 'derived-mode-parent))
|
|
|
|
(funcall
|
|
|
|
all-the-icons-ivy-family-fallback-for-buffer
|
|
|
|
all-the-icons-ivy-name-fallback-for-buffer))
|
|
|
|
(all-the-icons-icon-for-file candidate))))
|
2018-01-08 19:03:38 -05:00
|
|
|
|
2019-05-14 10:06:36 -04:00
|
|
|
;;;###autoload
|
|
|
|
(defun +ivy-rich-describe-variable-transformer (cand)
|
|
|
|
"Previews the value of the variable in the minibuffer"
|
|
|
|
(let* ((sym (intern cand))
|
|
|
|
(val (and (boundp sym) (symbol-value sym)))
|
|
|
|
(print-level 3))
|
|
|
|
(replace-regexp-in-string
|
|
|
|
"[\n\t\^[\^M\^@\^G]" " "
|
|
|
|
(cond ((booleanp val)
|
|
|
|
(propertize (format "%s" val) 'face
|
|
|
|
(if (null val)
|
|
|
|
'font-lock-comment-face
|
|
|
|
'success)))
|
|
|
|
((symbolp val)
|
|
|
|
(propertize (format "'%s" val)
|
|
|
|
'face 'highlight-quoted-symbol))
|
|
|
|
((keymapp val)
|
|
|
|
(propertize "<keymap>" 'face 'font-lock-constant-face))
|
|
|
|
((listp val)
|
|
|
|
(prin1-to-string val))
|
|
|
|
((stringp val)
|
|
|
|
(propertize (format "%S" val) 'face 'font-lock-string-face))
|
|
|
|
((numberp val)
|
|
|
|
(propertize (format "%s" val) 'face 'highlight-numbers-number))
|
|
|
|
((format "%s" val)))
|
|
|
|
t)))
|
|
|
|
|
2018-01-08 14:41:41 -05:00
|
|
|
|
|
|
|
;;
|
|
|
|
;; Library
|
2017-02-24 20:03:08 -05:00
|
|
|
|
2019-03-07 11:07:45 +10:00
|
|
|
(defun +ivy--switch-buffer-preview ()
|
2019-03-21 14:34:33 +10:00
|
|
|
(let (ivy-use-virtual-buffers ivy--virtual-buffers)
|
2019-03-08 16:08:36 +10:00
|
|
|
(counsel--switch-buffer-update-fn)))
|
|
|
|
|
|
|
|
(defalias '+ivy--switch-buffer-preview-all #'counsel--switch-buffer-update-fn)
|
|
|
|
(defalias '+ivy--switch-buffer-unwind #'counsel--switch-buffer-unwind)
|
2019-03-07 11:07:45 +10:00
|
|
|
|
|
|
|
(defun +ivy--switch-buffer (workspace other)
|
|
|
|
(let ((current (not other))
|
|
|
|
prompt action filter update unwind)
|
|
|
|
(cond ((and workspace current)
|
|
|
|
(setq prompt "Switch to workspace buffer: "
|
|
|
|
action #'ivy--switch-buffer-action
|
|
|
|
filter #'+ivy--is-workspace-other-buffer-p))
|
|
|
|
(workspace
|
|
|
|
(setq prompt "Switch to workspace buffer in other window: "
|
|
|
|
action #'ivy--switch-buffer-other-window-action
|
|
|
|
filter #'+ivy--is-workspace-buffer-p))
|
|
|
|
(current
|
|
|
|
(setq prompt "Switch to buffer: "
|
|
|
|
action #'ivy--switch-buffer-action))
|
2019-04-07 15:10:22 -04:00
|
|
|
((setq prompt "Switch to buffer in other window: "
|
2019-03-07 11:07:45 +10:00
|
|
|
action #'ivy--switch-buffer-other-window-action)))
|
|
|
|
(when +ivy-buffer-preview
|
|
|
|
(cond ((not (and ivy-use-virtual-buffers
|
|
|
|
(eq +ivy-buffer-preview 'everything)))
|
2019-03-08 16:08:36 +10:00
|
|
|
(setq update #'+ivy--switch-buffer-preview
|
|
|
|
unwind #'+ivy--switch-buffer-unwind))
|
2019-04-07 15:10:22 -04:00
|
|
|
((setq update #'+ivy--switch-buffer-preview-all
|
2019-03-08 16:08:36 +10:00
|
|
|
unwind #'+ivy--switch-buffer-unwind))))
|
2019-03-07 11:07:45 +10:00
|
|
|
(ivy-read prompt 'internal-complete-buffer
|
|
|
|
:action action
|
|
|
|
:predicate filter
|
|
|
|
:update-fn update
|
|
|
|
:unwind unwind
|
|
|
|
:preselect (buffer-name (other-buffer (current-buffer)))
|
|
|
|
:matcher #'ivy--switch-buffer-matcher
|
|
|
|
:keymap ivy-switch-buffer-map
|
2019-05-13 23:44:53 +10:00
|
|
|
;; NOTE A clever disguise, needed for virtual buffers.
|
|
|
|
:caller #'ivy-switch-buffer)))
|
2019-03-07 11:07:45 +10:00
|
|
|
|
2017-02-13 04:54:12 -05:00
|
|
|
;;;###autoload
|
2017-08-21 21:54:04 +02:00
|
|
|
(defun +ivy/switch-workspace-buffer (&optional arg)
|
|
|
|
"Switch to another buffer within the current workspace.
|
2017-07-08 13:54:44 +02:00
|
|
|
|
2017-08-21 21:54:04 +02:00
|
|
|
If ARG (universal argument), open selection in other-window."
|
2017-02-24 20:03:08 -05:00
|
|
|
(interactive "P")
|
2019-03-07 11:07:45 +10:00
|
|
|
(+ivy--switch-buffer t arg))
|
2017-02-13 04:54:12 -05:00
|
|
|
|
2019-02-25 00:22:36 +10:00
|
|
|
;;;###autoload
|
2019-03-07 01:18:11 +10:00
|
|
|
(defun +ivy/switch-workspace-buffer-other-window ()
|
2019-03-07 11:07:45 +10:00
|
|
|
"Switch another window to a buffer within the current workspace."
|
|
|
|
(interactive)
|
|
|
|
(+ivy--switch-buffer t t))
|
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(defun +ivy/switch-buffer ()
|
|
|
|
"Switch to another buffer."
|
|
|
|
(interactive)
|
|
|
|
(+ivy--switch-buffer nil nil))
|
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(defun +ivy/switch-buffer-other-window ()
|
|
|
|
"Switch to another buffer in another window."
|
2019-02-25 00:22:36 +10:00
|
|
|
(interactive)
|
2019-03-07 11:07:45 +10:00
|
|
|
(+ivy--switch-buffer nil t))
|
2019-02-25 00:22:36 +10:00
|
|
|
|
2017-05-14 13:49:11 +02:00
|
|
|
(defun +ivy--tasks-candidates (tasks)
|
2017-05-10 06:13:14 +02:00
|
|
|
"Generate a list of task tags (specified by `+ivy-task-tags') for
|
|
|
|
`+ivy/tasks'."
|
2017-06-08 11:47:56 +02:00
|
|
|
(let* ((max-type-width
|
|
|
|
(cl-loop for task in +ivy-task-tags maximize (length (car task))))
|
|
|
|
(max-desc-width
|
|
|
|
(cl-loop for task in tasks maximize (length (cl-cdadr task))))
|
2019-05-19 02:14:06 -04:00
|
|
|
(max-width (max (+ max-desc-width 3)
|
2017-06-08 11:47:56 +02:00
|
|
|
25)))
|
|
|
|
(cl-loop
|
2019-05-19 02:14:06 -04:00
|
|
|
with fmt = (format "%%-%ds %%-%ds%%s:%%s" max-type-width max-width)
|
2017-06-08 11:47:56 +02:00
|
|
|
for alist in tasks
|
|
|
|
collect
|
|
|
|
(let-alist alist
|
2019-05-19 02:14:06 -04:00
|
|
|
(list (format fmt
|
|
|
|
(propertize .type 'face (cdr (assoc .type +ivy-task-tags)))
|
|
|
|
(substring .desc 0 (min max-desc-width (length .desc)))
|
|
|
|
(propertize (abbreviate-file-name .file) 'face 'font-lock-keyword-face)
|
|
|
|
(propertize .line 'face 'font-lock-constant-face))
|
|
|
|
.type .file .line)))))
|
2017-05-14 13:49:11 +02:00
|
|
|
|
|
|
|
(defun +ivy--tasks (target)
|
2017-06-08 11:47:56 +02:00
|
|
|
(let* (case-fold-search
|
|
|
|
(task-tags (mapcar #'car +ivy-task-tags))
|
|
|
|
(cmd
|
|
|
|
(format "%s -H -S --no-heading -- %s %s"
|
2019-06-25 21:38:16 +02:00
|
|
|
(or (when-let (bin (executable-find "rg"))
|
2017-06-08 11:47:56 +02:00
|
|
|
(concat bin " --line-number"))
|
2019-06-25 21:38:16 +02:00
|
|
|
(when-let (bin (executable-find "ag"))
|
2017-06-08 11:47:56 +02:00
|
|
|
(concat bin " --numbers"))
|
|
|
|
(error "ripgrep & the_silver_searcher are unavailable"))
|
|
|
|
(shell-quote-argument
|
|
|
|
(concat "\\s("
|
|
|
|
(string-join task-tags "|")
|
|
|
|
")([\\s:]|\\([^)]+\\):?)"))
|
|
|
|
target)))
|
|
|
|
(save-match-data
|
|
|
|
(cl-loop with out = (shell-command-to-string cmd)
|
|
|
|
for x in (and out (split-string out "\n" t))
|
2017-08-14 23:37:17 -07:00
|
|
|
when (condition-case-unless-debug ex
|
|
|
|
(string-match
|
|
|
|
(concat "^\\([^:]+\\):\\([0-9]+\\):.+\\("
|
|
|
|
(string-join task-tags "\\|")
|
|
|
|
"\\):?\\s-*\\(.+\\)")
|
|
|
|
x)
|
|
|
|
(error
|
2018-09-07 21:56:07 -04:00
|
|
|
(print! (red "Error matching task in file: (%s) %s")
|
|
|
|
(error-message-string ex)
|
|
|
|
(car (split-string x ":")))
|
2017-08-14 23:37:17 -07:00
|
|
|
nil))
|
2017-06-08 11:47:56 +02:00
|
|
|
collect `((type . ,(match-string 3 x))
|
|
|
|
(desc . ,(match-string 4 x))
|
|
|
|
(file . ,(match-string 1 x))
|
|
|
|
(line . ,(match-string 2 x)))))))
|
2017-05-10 06:13:14 +02:00
|
|
|
|
|
|
|
(defun +ivy--tasks-open-action (x)
|
|
|
|
"Jump to the file and line of the current task."
|
2019-05-19 02:14:06 -04:00
|
|
|
(cl-destructuring-bind (label type file line) x
|
|
|
|
(with-ivy-window
|
|
|
|
(find-file (expand-file-name file (doom-project-root)))
|
|
|
|
(goto-char (point-min))
|
|
|
|
(forward-line (1- (string-to-number line)))
|
|
|
|
(when (search-forward type (line-end-position) t)
|
|
|
|
(backward-char (length type)))
|
|
|
|
(recenter))))
|
2017-05-10 06:13:14 +02:00
|
|
|
|
2017-02-13 04:54:12 -05:00
|
|
|
;;;###autoload
|
2017-05-10 06:13:14 +02:00
|
|
|
(defun +ivy/tasks (&optional arg)
|
|
|
|
"Search through all TODO/FIXME tags in the current project. If ARG, only
|
|
|
|
search current file. See `+ivy-task-tags' to customize what this searches for."
|
|
|
|
(interactive "P")
|
|
|
|
(ivy-read (format "Tasks (%s): "
|
|
|
|
(if arg
|
|
|
|
(concat "in: " (file-relative-name buffer-file-name))
|
|
|
|
"project"))
|
2018-07-29 02:55:45 +02:00
|
|
|
(let ((tasks (+ivy--tasks (if arg buffer-file-name (doom-project-root)))))
|
|
|
|
(unless tasks
|
|
|
|
(user-error "No tasks in your project! Good job!"))
|
|
|
|
(+ivy--tasks-candidates tasks))
|
2017-05-10 06:13:14 +02:00
|
|
|
:action #'+ivy--tasks-open-action
|
|
|
|
:caller '+ivy/tasks))
|
2017-02-13 04:54:12 -05:00
|
|
|
|
|
|
|
;;;###autoload
|
2019-05-20 21:06:06 -04:00
|
|
|
(defun +ivy/woccur ()
|
|
|
|
"Invoke a wgrep buffer on the current ivy results, if supported."
|
2017-02-13 04:54:12 -05:00
|
|
|
(interactive)
|
2017-06-08 11:47:56 +02:00
|
|
|
(unless (window-minibuffer-p)
|
|
|
|
(user-error "No completion session is active"))
|
|
|
|
(require 'wgrep)
|
2019-05-20 21:06:06 -04:00
|
|
|
(let ((caller (ivy-state-caller ivy-last)))
|
|
|
|
(if-let* ((occur-fn (plist-get +ivy-edit-functions caller)))
|
|
|
|
(ivy-exit-with-action
|
|
|
|
(lambda (_) (funcall occur-fn)))
|
|
|
|
(if-let* ((occur-fn (plist-get ivy--occurs-list caller)))
|
|
|
|
(let ((buffer (generate-new-buffer
|
|
|
|
(format "*ivy-occur%s \"%s\"*"
|
|
|
|
(if caller (concat " " (prin1-to-string caller)) "")
|
|
|
|
ivy-text))))
|
|
|
|
(with-current-buffer buffer
|
|
|
|
(let ((inhibit-read-only t))
|
|
|
|
(erase-buffer)
|
|
|
|
(funcall occur-fn))
|
|
|
|
(setf (ivy-state-text ivy-last) ivy-text)
|
|
|
|
(setq ivy-occur-last ivy-last)
|
|
|
|
(setq-local ivy--directory ivy--directory))
|
|
|
|
(ivy-exit-with-action
|
|
|
|
`(lambda (_)
|
|
|
|
(pop-to-buffer ,buffer)
|
|
|
|
(ivy-wgrep-change-to-wgrep-mode))))
|
|
|
|
(user-error "%S doesn't support wgrep" caller)))))
|
2017-02-13 04:54:12 -05:00
|
|
|
|
2017-02-13 21:11:54 -05:00
|
|
|
;;;###autoload
|
|
|
|
(defun +ivy-yas-prompt (prompt choices &optional display-fn)
|
|
|
|
(yas-completing-prompt prompt choices display-fn #'ivy-completing-read))
|
2017-05-10 05:20:54 +02:00
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(defun +ivy-git-grep-other-window-action (x)
|
|
|
|
"Opens the current candidate in another window."
|
2017-05-14 17:40:33 +02:00
|
|
|
(when (string-match "\\`\\(.*?\\):\\([0-9]+\\):\\(.*\\)\\'" x)
|
|
|
|
(select-window
|
|
|
|
(with-ivy-window
|
|
|
|
(let ((file-name (match-string-no-properties 1 x))
|
|
|
|
(line-number (match-string-no-properties 2 x)))
|
2018-01-04 15:49:18 +08:00
|
|
|
(find-file-other-window (expand-file-name file-name (ivy-state-directory ivy-last)))
|
2017-05-14 17:40:33 +02:00
|
|
|
(goto-char (point-min))
|
|
|
|
(forward-line (1- (string-to-number line-number)))
|
|
|
|
(re-search-forward (ivy--regex ivy-text t) (line-end-position) t)
|
|
|
|
(run-hooks 'counsel-grep-post-action-hook)
|
|
|
|
(selected-window))))))
|
2018-03-26 00:02:22 -04:00
|
|
|
|
2018-07-04 23:59:18 +08:00
|
|
|
;;;###autoload
|
2018-07-05 14:05:09 +02:00
|
|
|
(defun +ivy-confirm-delete-file (x)
|
|
|
|
(dired-delete-file x 'confirm-each-subdirectory))
|
2018-07-04 23:59:18 +08:00
|
|
|
|
|
|
|
|
2018-03-26 00:02:22 -04:00
|
|
|
;;
|
|
|
|
;; File searching
|
|
|
|
|
2018-08-03 16:10:20 +02:00
|
|
|
;;;###autoload
|
|
|
|
(defun +ivy/projectile-find-file ()
|
2018-08-04 02:28:45 +02:00
|
|
|
"A more sensible `counsel-projectile-find-file', which will revert to
|
|
|
|
`counsel-find-file' if invoked from $HOME, `counsel-file-jump' if invoked from a
|
2019-01-05 15:20:49 -05:00
|
|
|
non-project, `projectile-find-file' if in a big project (more than
|
2018-08-04 02:28:45 +02:00
|
|
|
`ivy-sort-max-size' files), or `counsel-projectile-find-file' otherwise.
|
2018-08-03 16:10:20 +02:00
|
|
|
|
2018-08-04 02:28:45 +02:00
|
|
|
The point of this is to avoid Emacs locking up indexing massive file trees."
|
2018-08-03 16:10:20 +02:00
|
|
|
(interactive)
|
|
|
|
(call-interactively
|
|
|
|
(cond ((or (file-equal-p default-directory "~")
|
2019-06-25 21:38:16 +02:00
|
|
|
(when-let (proot (doom-project-root))
|
2018-08-03 16:10:20 +02:00
|
|
|
(file-equal-p proot "~")))
|
|
|
|
#'counsel-find-file)
|
2018-08-04 02:28:45 +02:00
|
|
|
|
2018-09-28 13:54:20 -04:00
|
|
|
((doom-project-p)
|
2018-08-11 01:36:26 +02:00
|
|
|
(let ((files (projectile-current-project-files)))
|
|
|
|
(if (<= (length files) ivy-sort-max-size)
|
|
|
|
#'counsel-projectile-find-file
|
|
|
|
#'projectile-find-file)))
|
2018-08-04 02:28:45 +02:00
|
|
|
|
2018-08-03 16:10:20 +02:00
|
|
|
(#'counsel-file-jump))))
|
|
|
|
|
2019-06-17 15:01:00 +02:00
|
|
|
(defvar +ivy-file-search-shell
|
|
|
|
(or (executable-find "dash")
|
|
|
|
(executable-find "sh")
|
|
|
|
shell-file-name)
|
|
|
|
"The SHELL to invoke ag/rg/pt/git-grep/grep searchs from.
|
|
|
|
|
|
|
|
This only affects `+ivy/*' search commands (e.g. `+ivy/rg' and
|
|
|
|
`+ivy/project-search').
|
|
|
|
|
|
|
|
By default, this the most basic, uncustomized shell, to prevent interference
|
|
|
|
caused by slow shell configs at the cost of isolating these programs from
|
|
|
|
envvars that may have been set in the user's shell config to change their
|
|
|
|
behavior. If this bothers you, change this to `shell-file-name'.")
|
|
|
|
|
2018-06-20 15:37:31 +02:00
|
|
|
;;;###autoload
|
|
|
|
(cl-defun +ivy-file-search (engine &key query in all-files (recursive t))
|
|
|
|
"Conduct a file search using ENGINE, which can be any of: rg, ag, pt, and
|
|
|
|
grep. If omitted, ENGINE will default to the first one it detects, in that
|
|
|
|
order.
|
|
|
|
|
|
|
|
:query STRING
|
|
|
|
Determines the initial input to search for.
|
|
|
|
:in PATH
|
|
|
|
Sets what directory to base the search out of. Defaults to the current
|
|
|
|
project's root.
|
|
|
|
:recursive BOOL
|
|
|
|
Whether or not to search files recursively from the base directory."
|
|
|
|
(declare (indent defun))
|
2018-12-11 18:59:30 -05:00
|
|
|
(let* ((project-root (or (doom-project-root) default-directory))
|
2018-06-02 14:34:12 +02:00
|
|
|
(directory (or in project-root))
|
|
|
|
(default-directory directory)
|
2018-03-26 00:02:22 -04:00
|
|
|
(engine (or engine
|
2018-07-23 00:06:47 +02:00
|
|
|
(cl-loop for tool in +ivy-project-search-engines
|
|
|
|
if (executable-find (symbol-name tool))
|
|
|
|
return tool)
|
2018-06-02 14:34:12 +02:00
|
|
|
(and (or (executable-find "grep")
|
|
|
|
(executable-find "git"))
|
|
|
|
'grep)
|
|
|
|
(error "No search engine specified (is ag, rg, pt or git installed?)")))
|
2018-03-26 00:02:22 -04:00
|
|
|
(query
|
2019-06-12 20:08:16 +02:00
|
|
|
(or (if query query)
|
2018-03-26 00:02:22 -04:00
|
|
|
(when (use-region-p)
|
|
|
|
(let ((beg (or (bound-and-true-p evil-visual-beginning) (region-beginning)))
|
|
|
|
(end (or (bound-and-true-p evil-visual-end) (region-end))))
|
|
|
|
(when (> (abs (- end beg)) 1)
|
2019-06-12 20:08:16 +02:00
|
|
|
(let ((query (buffer-substring-no-properties beg end)))
|
2019-06-13 09:35:09 +02:00
|
|
|
;; Escape characters that are special to ivy searches
|
2019-06-16 23:04:39 +02:00
|
|
|
(replace-regexp-in-string "[! |]" (lambda (substr)
|
|
|
|
(cond ((and (featurep! +fuzzy)
|
|
|
|
(string= substr " "))
|
|
|
|
" ")
|
|
|
|
((and (string= substr "|")
|
|
|
|
(eq engine 'rg))
|
|
|
|
"\\\\\\\\|")
|
|
|
|
((concat "\\\\" substr))))
|
2019-06-13 09:35:09 +02:00
|
|
|
(regexp-quote query))))))))
|
2018-03-26 00:02:22 -04:00
|
|
|
(prompt
|
|
|
|
(format "%s%%s %s"
|
|
|
|
(symbol-name engine)
|
|
|
|
(cond ((equal directory default-directory)
|
|
|
|
"./")
|
|
|
|
((equal directory project-root)
|
|
|
|
(projectile-project-name))
|
2018-12-11 18:59:30 -05:00
|
|
|
((file-relative-name directory project-root))))))
|
2018-03-26 00:02:22 -04:00
|
|
|
(require 'counsel)
|
2019-04-05 23:52:29 -04:00
|
|
|
(let ((ivy-more-chars-alist
|
2019-06-17 15:01:00 +02:00
|
|
|
(if query '((t . 1)) ivy-more-chars-alist))
|
|
|
|
(shell-file-name +ivy-file-search-shell))
|
2018-03-26 00:02:22 -04:00
|
|
|
(pcase engine
|
2019-06-10 16:04:48 +02:00
|
|
|
(`grep
|
|
|
|
(let ((counsel-projectile-grep-initial-input query))
|
|
|
|
(cl-letf (((symbol-function #'counsel-locate-git-root)
|
|
|
|
(lambda () directory)))
|
|
|
|
(if all-files
|
|
|
|
(cl-letf (((symbol-function #'projectile-ignored-directories-rel)
|
|
|
|
(symbol-function #'ignore))
|
|
|
|
((symbol-function #'projectile-ignored-files-rel)
|
|
|
|
(symbol-function #'ignore)))
|
|
|
|
(counsel-projectile-grep))
|
|
|
|
(counsel-projectile-grep)))))
|
|
|
|
(`ag
|
2018-06-02 14:34:12 +02:00
|
|
|
(let ((args (concat (if all-files " -a")
|
|
|
|
(unless recursive " --depth 1"))))
|
2018-03-26 00:02:22 -04:00
|
|
|
(counsel-ag query directory args (format prompt args))))
|
2019-06-10 16:04:48 +02:00
|
|
|
(`rg
|
2018-06-02 14:34:12 +02:00
|
|
|
(let ((args (concat (if all-files " -uu")
|
|
|
|
(unless recursive " --maxdepth 1"))))
|
2018-03-26 00:02:22 -04:00
|
|
|
(counsel-rg query directory args (format prompt args))))
|
2019-06-10 16:04:48 +02:00
|
|
|
(`pt
|
2018-03-26 00:02:22 -04:00
|
|
|
(let ((counsel-pt-base-command
|
|
|
|
(concat counsel-pt-base-command
|
2018-06-02 14:34:12 +02:00
|
|
|
(if all-files " -U")
|
|
|
|
(unless recursive " --depth=1")))
|
2018-03-26 00:02:22 -04:00
|
|
|
(default-directory directory))
|
|
|
|
(counsel-pt query)))
|
|
|
|
(_ (error "No search engine specified"))))))
|
|
|
|
|
2018-08-13 19:14:25 +02:00
|
|
|
(defun +ivy--get-command (format)
|
|
|
|
(cl-loop for tool in (cl-remove-duplicates +ivy-project-search-engines :from-end t)
|
|
|
|
if (executable-find (symbol-name tool))
|
|
|
|
return (intern (format format tool))))
|
2018-03-26 00:02:22 -04:00
|
|
|
|
|
|
|
;;;###autoload
|
2019-04-14 13:36:56 -04:00
|
|
|
(defun +ivy/project-search (&optional arg initial-query directory)
|
2018-08-13 19:14:25 +02:00
|
|
|
"Performs a project search from the project root.
|
2018-03-26 00:02:22 -04:00
|
|
|
|
2018-08-13 19:14:25 +02:00
|
|
|
Uses the first available search backend from `+ivy-project-search-engines'. If
|
2019-04-14 13:36:56 -04:00
|
|
|
ARG (universal argument), include all files, even hidden or compressed ones, in
|
|
|
|
the search."
|
2018-03-28 12:34:04 -07:00
|
|
|
(interactive "P")
|
2018-09-09 13:44:12 -04:00
|
|
|
(funcall (or (+ivy--get-command "+ivy/%s")
|
2018-09-08 18:20:40 -04:00
|
|
|
#'+ivy/grep)
|
2019-04-14 13:36:56 -04:00
|
|
|
arg
|
|
|
|
initial-query
|
|
|
|
directory))
|
2018-03-26 00:02:22 -04:00
|
|
|
|
|
|
|
;;;###autoload
|
2019-04-16 23:31:23 +10:00
|
|
|
(defun +ivy/project-search-from-cwd (&optional arg initial-query)
|
2018-08-13 19:14:25 +02:00
|
|
|
"Performs a project search recursively from the current directory.
|
2018-03-26 00:02:22 -04:00
|
|
|
|
2018-08-13 19:14:25 +02:00
|
|
|
Uses the first available search backend from `+ivy-project-search-engines'. If
|
2019-04-14 13:36:56 -04:00
|
|
|
ARG (universal argument), include all files, even hidden or compressed ones."
|
2018-03-28 12:34:04 -07:00
|
|
|
(interactive "P")
|
2018-09-09 13:44:12 -04:00
|
|
|
(funcall (or (+ivy--get-command "+ivy/%s-from-cwd")
|
2018-09-08 18:20:40 -04:00
|
|
|
#'+ivy/grep-from-cwd)
|
2019-04-14 13:36:56 -04:00
|
|
|
arg
|
2019-04-16 23:31:23 +10:00
|
|
|
initial-query))
|
2018-08-13 19:14:25 +02:00
|
|
|
|
|
|
|
|
|
|
|
;;;###autoload (autoload '+ivy/rg "completion/ivy/autoload/ivy")
|
|
|
|
;;;###autoload (autoload '+ivy/rg-from-cwd "completion/ivy/autoload/ivy")
|
|
|
|
;;;###autoload (autoload '+ivy/ag "completion/ivy/autoload/ivy")
|
|
|
|
;;;###autoload (autoload '+ivy/ag-from-cwd "completion/ivy/autoload/ivy")
|
|
|
|
;;;###autoload (autoload '+ivy/pt "completion/ivy/autoload/ivy")
|
|
|
|
;;;###autoload (autoload '+ivy/pt-from-cwd "completion/ivy/autoload/ivy")
|
|
|
|
;;;###autoload (autoload '+ivy/grep "completion/ivy/autoload/ivy")
|
|
|
|
;;;###autoload (autoload '+ivy/grep-from-cwd "completion/ivy/autoload/ivy")
|
|
|
|
|
2018-10-13 13:26:59 -04:00
|
|
|
(dolist (engine `(,@(cl-remove-duplicates +ivy-project-search-engines :from-end t) grep))
|
2018-08-13 19:14:25 +02:00
|
|
|
(defalias (intern (format "+ivy/%s" engine))
|
|
|
|
(lambda (all-files-p &optional query directory)
|
|
|
|
(interactive "P")
|
|
|
|
(+ivy-file-search engine :query query :in directory :all-files all-files-p))
|
|
|
|
(format "Perform a project file search using %s.
|
|
|
|
|
|
|
|
QUERY is a regexp. If omitted, the current selection is used. If no selection is
|
2018-03-26 00:02:22 -04:00
|
|
|
active, the last known search is used.
|
|
|
|
|
2018-08-13 19:14:25 +02:00
|
|
|
If ALL-FILES-P, search compressed and hidden files as well."
|
|
|
|
engine))
|
2018-03-26 00:02:22 -04:00
|
|
|
|
2018-08-13 19:14:25 +02:00
|
|
|
(defalias (intern (format "+ivy/%s-from-cwd" engine))
|
2018-09-08 18:20:40 -04:00
|
|
|
(lambda (all-files-p &optional query)
|
2018-08-13 19:14:25 +02:00
|
|
|
(interactive "P")
|
|
|
|
(+ivy-file-search engine :query query :in default-directory :all-files all-files-p))
|
|
|
|
(format "Perform a project file search from the current directory using %s.
|
2018-03-26 00:02:22 -04:00
|
|
|
|
2018-08-13 19:14:25 +02:00
|
|
|
QUERY is a regexp. If omitted, the current selection is used. If no selection is
|
|
|
|
active, the last known search is used.
|
2018-03-26 00:02:22 -04:00
|
|
|
|
2018-08-13 19:14:25 +02:00
|
|
|
If ALL-FILES-P, search compressed and hidden files as well."
|
|
|
|
engine)))
|