doomemacs/modules/completion/ivy/autoload/ivy.el

366 lines
14 KiB
EmacsLisp
Raw Normal View History

;;; completion/ivy/autoload/ivy.el -*- lexical-binding: t; -*-
(defun +ivy--is-workspace-buffer-p (buffer)
(let ((buffer (car buffer)))
(when (stringp buffer)
(setq buffer (get-buffer buffer)))
(+workspace-contains-buffer-p buffer)))
(defun +ivy--is-workspace-other-buffer-p (buffer)
(let ((buffer (car buffer)))
(when (stringp buffer)
(setq buffer (get-buffer buffer)))
(and (not (eq buffer (current-buffer)))
(+workspace-contains-buffer-p buffer))))
;;;###autoload
(defun +ivy-standard-search (str)
"TODO"
(funcall +ivy-standard-search-fn str))
;;;###autoload
(defun +ivy-alternative-search (str)
"TODO"
(funcall +ivy-alternative-search-fn str))
;;;###autoload
(defun +ivy-rich-buffer-name (candidate)
"Display the buffer name.
Buffers that are considered unreal (see `doom-real-buffer-p') are dimmed with
`+ivy-buffer-unreal-face'."
(let ((b (get-buffer candidate)))
(when (null uniquify-buffer-name-style)
(setq candidate (replace-regexp-in-string "<[0-9]+>$" "" candidate)))
(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))))
;;;###autoload
(defun +ivy-rich-buffer-icon (candidate)
"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))))
;;;###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)))
;;
;; Library
(defun +ivy--switch-buffer-preview ()
(let (ivy-use-virtual-buffers ivy--virtual-buffers)
(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)
(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))
((setq prompt "Switch to buffer in other window: "
action #'ivy--switch-buffer-other-window-action)))
(when +ivy-buffer-preview
(cond ((not (and ivy-use-virtual-buffers
(eq +ivy-buffer-preview 'everything)))
(setq update #'+ivy--switch-buffer-preview
unwind #'+ivy--switch-buffer-unwind))
((setq update #'+ivy--switch-buffer-preview-all
unwind #'+ivy--switch-buffer-unwind))))
(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
;; NOTE A clever disguise, needed for virtual buffers.
:caller #'ivy-switch-buffer)))
2017-02-13 04:54:12 -05:00
;;;###autoload
(defun +ivy/switch-workspace-buffer (&optional arg)
"Switch to another buffer within the current workspace.
If ARG (universal argument), open selection in other-window."
(interactive "P")
(+ivy--switch-buffer t arg))
2017-02-13 04:54:12 -05:00
;;;###autoload
(defun +ivy/switch-workspace-buffer-other-window ()
"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."
(interactive)
(+ivy--switch-buffer nil t))
2017-02-13 04:54:12 -05:00
;;;###autoload
(defun +ivy/woccur ()
"Invoke a wgrep buffer on the current ivy results, if supported."
2017-02-13 04:54:12 -05:00
(interactive)
(unless (window-minibuffer-p)
(user-error "No completion session is active"))
(require 'wgrep)
(let ((caller (ivy-state-caller ivy-last)))
2019-12-14 20:36:14 -05:00
(if-let (occur-fn (plist-get +ivy-edit-functions caller))
(ivy-exit-with-action
(lambda (_) (funcall occur-fn)))
2019-12-14 20:36:14 -05:00
(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
;;;###autoload
(defun +ivy-yas-prompt (prompt choices &optional display-fn)
(yas-completing-prompt prompt choices display-fn #'ivy-completing-read))
;;;###autoload
(defun +ivy-git-grep-other-window-action (x)
"Opens the current candidate in another window."
(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)))
(find-file-other-window (expand-file-name file-name (ivy-state-directory ivy-last)))
(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-07-04 23:59:18 +08:00
;;;###autoload
(defun +ivy-confirm-delete-file (x)
(dired-delete-file x 'confirm-each-subdirectory))
2018-07-04 23:59:18 +08:00
;;
;;; File searching
;;;###autoload
(defun +ivy/projectile-find-file ()
"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
non-project, `projectile-find-file' if in a big project (more than
`ivy-sort-max-size' files), or `counsel-projectile-find-file' otherwise.
The point of this is to avoid Emacs locking up indexing massive file trees."
(interactive)
(call-interactively
(cond ((or (file-equal-p default-directory "~")
(when-let (proot (doom-project-root))
(file-equal-p proot "~")))
#'counsel-find-file)
((doom-project-p)
(let ((files (projectile-current-project-files)))
(if (<= (length files) ivy-sort-max-size)
#'counsel-projectile-find-file
#'projectile-find-file)))
(#'counsel-file-jump))))
;;;###autoload
(cl-defun +ivy-file-search (&key query in all-files (recursive t))
"Conduct a file search using ripgrep.
: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))
(unless (executable-find "rg")
(user-error "Couldn't find ripgrep in your PATH"))
(require 'counsel)
(let* ((ivy-more-chars-alist '((t . 1)))
(project-root (or (doom-project-root) default-directory))
(directory (or in project-root))
(args (concat (if all-files " -uu")
(unless recursive " --maxdepth 1"))))
(counsel-rg
(or (if query query)
(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)
(let ((query (buffer-substring-no-properties beg end)))
;; Escape characters that are special to ivy searches
(replace-regexp-in-string "[! |]" (lambda (substr)
(cond ((and (string= substr " ")
(not (featurep! +fuzzy)))
" ")
((string= substr "|")
"\\\\\\\\|")
((concat "\\\\" substr))))
(rxt-quote-pcre query)))))))
directory args
(format "rg%s [%s]: "
args
(cond ((equal directory default-directory)
"./")
((equal directory project-root)
(projectile-project-name))
((file-relative-name directory project-root)))))))
;;;###autoload
(defun +ivy/project-search (&optional arg initial-query directory)
"Performs a live project search from the project root using ripgrep.
If ARG (universal argument), include all files, even hidden or compressed ones,
in the search."
(interactive "P")
(+ivy-file-search :query initial-query :in directory :all-files arg))
;;;###autoload
(defun +ivy/project-search-from-cwd (&optional arg initial-query)
"Performs a project search recursively from the current directory.
If ARG (universal argument), include all files, even hidden or compressed ones."
(interactive "P")
(+ivy/project-search arg initial-query default-directory))
;;
;;; Wrappers around `counsel-compile'
;;;###autoload
(defun +ivy/compile ()
"Execute a compile command from the current buffer's directory."
(interactive)
(counsel-compile default-directory))
;;;###autoload
(defun +ivy/project-compile ()
"Execute a compile command from the current project's root."
(interactive)
(counsel-compile (projectile-project-root)))
;;;###autoload
(defun +ivy/jump-list ()
"Go to an entry in evil's (or better-jumper's) jumplist."
(interactive)
;; REVIEW Refactor me
(let (buffers)
(unwind-protect
(ivy-read "jumplist: "
(nreverse
(delete-dups
(delq
nil
(mapcar (lambda (mark)
(when mark
(cl-destructuring-bind (path pt _id) mark
(let ((buf (get-file-buffer path)))
(unless buf
(push (setq buf (find-file-noselect path t))
buffers))
(with-current-buffer buf
(goto-char pt)
(font-lock-fontify-region (line-beginning-position) (line-end-position))
(cons (format "%s:%d: %s"
(buffer-name)
(line-number-at-pos)
(string-trim-right (or (thing-at-point 'line) "")))
(point-marker)))))))
(cddr (better-jumper-jump-list-struct-ring
(better-jumper-get-jumps (better-jumper--get-current-context))))))))
:sort nil
:require-match t
:action (lambda (cand)
(let ((mark (cdr cand)))
(delq! (marker-buffer mark) buffers)
(mapc #'kill-buffer buffers)
(setq buffers nil)
(with-current-buffer (switch-to-buffer (marker-buffer mark))
(goto-char (marker-position mark)))))
:caller '+ivy/jump-list)
(mapc #'kill-buffer buffers))))
2019-10-25 20:24:36 -04:00
;;;###autoload
(defun +ivy/git-grep-other-window-action ()
"Open the current counsel-{ag,rg,git-grep} candidate in other-window."
(interactive)
(ivy-set-action #'+ivy-git-grep-other-window-action)
(setq ivy-exit 'done)
(exit-minibuffer))