From 4978af4f769b1d19ef39b58f04acebc257802a3a Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Mon, 13 Feb 2017 04:54:12 -0500 Subject: [PATCH] Add modules/completion/ivy --- modules/completion/ivy/autoload.el | 145 +++++++++++++++++++++++++++++ modules/completion/ivy/config.el | 80 ++++++++++++++++ modules/completion/ivy/packages.el | 6 ++ 3 files changed, 231 insertions(+) create mode 100644 modules/completion/ivy/autoload.el create mode 100644 modules/completion/ivy/config.el create mode 100644 modules/completion/ivy/packages.el diff --git a/modules/completion/ivy/autoload.el b/modules/completion/ivy/autoload.el new file mode 100644 index 000000000..170325c47 --- /dev/null +++ b/modules/completion/ivy/autoload.el @@ -0,0 +1,145 @@ +;;; completion/ivy/packages.el + +;; Show more information in ivy-switch-buffer; and only display +;; project/workgroup-relevant buffers. +(defun +ivy-get-buffers (&optional buffer-list) + (let ((min-name 5) + (min-mode 5) + (proot (doom-project-root))) + (mapcar + (lambda (b) (format (format "%%-%ds %%-%ds %%s" min-name min-mode) + (nth 0 b) + (nth 1 b) + (or (nth 2 b) ""))) + (mapcar (lambda (b) + (with-current-buffer b + (let ((buffer-name (buffer-name b)) + (mode-name (symbol-name major-mode))) + (when (> (length buffer-name) min-name) + (setq min-name (+ (length buffer-name) 15))) + (when (> (length mode-name) min-mode) + (setq min-mode (+ (length mode-name) 3))) + (list + (concat + (propertize buffer-name + 'face (cond ((string-match-p "^ ?\\*" buffer-name) + 'font-lock-comment-face) + ((not (string= proot (doom-project-root))) + 'font-lock-keyword-face) + (buffer-read-only + 'error))) + (when (and buffer-file-name (buffer-modified-p)) + (propertize "[+]" 'face 'doom-modeline-buffer-modified))) + (propertize mode-name 'face 'font-lock-constant-face) + (when buffer-file-name + (f-slash (abbreviate-file-name (f-dirname buffer-file-name)))))))) + (or buffer-list (doom/get-buffers t)))))) + +(defun +ivy--select-buffer-action (buffer) + (ivy--switch-buffer-action + (s-chop-suffix + "[+]" + (substring buffer 0 (s-index-of " " buffer))))) + +;;;###autoload +(defun +ivy/switch-project-buffer (&optional all-p) + "Displays open buffers in current project and workspace. If ALL-P, then show +all open buffers." + (interactive) + (ivy-read (format "%s buffers: " (if all-p "All" "Project")) + (+ivy-get-buffers (if all-p (buffer-list))) + :matcher #'ivy--switch-buffer-matcher + :action #'+ivy--select-buffer-action + :keymap ivy-switch-buffer-map + :caller '+ivy/switch-project-buffer)) + +;;;###autoload +(defun +ivy/switch-buffer () + "Displays all open buffers, across projects and workspaces." + (interactive) + (+ivy/switch-project-buffer t)) + +;;;###autoload +(defun +ivy/kill-ring () + (interactive) + (ivy-read "Kill ring:" (--filter (not (or (< (length it) 3) + (string-match-p "\\`[\n[:blank:]]+\\'" it))) + (cl-remove-duplicates kill-ring :test 'equal)))) + +;;;###autoload +(defun +ivy/recentf () + "Find a file on `recentf-list'." + (interactive) + (while (doom-popup-p) + (doom/popup-close)) + (call-interactively 'counsel-recentf)) + +;;;###autoload (autoload '+ivy:ag-search "completion/ivy/autoload" nil t) +;;;###autoload (autoload '+ivy:ag-search-cwd "completion/ivy/autoload" nil t) +;;;###autoload (autoload '+ivy:swiper "completion/ivy/autoload" nil t) +(@after evil + (defvar doom-ivy-ag-last-search nil) + + (evil-define-operator +ivy:ag-search (beg end search regex-p &optional dir) + "Preform a counsel search with SEARCH. If SEARCH is nil and in visual mode, +use the selection, otherwise activate live ag searching in helm. + +If REGEX-P is non-nil, SEARCH will be treated as a regular expression. +DIR specifies the default-directory from which ag is run." + :type inclusive :repeat nil + (interactive "") + (let ((search (or search + (and (evil-visual-state-p) + (and beg end (rxt-quote-pcre (buffer-substring-no-properties beg end)))) + doom-ivy-ag-last-search))) + (setq doom-ivy-ag-last-search search) + (counsel-ag search (or dir (f-slash (doom-project-root))) + (concat "--nocolor --nogroup" (if regex-p " -Q"))))) + + (evil-define-operator +ivy:ag-search-cwd (beg end search regex-p) + :type inclusive :repeat nil + (interactive "") + (+ivy:ag-search beg end search regex-p default-directory)) + + (evil-define-command +ivy:swiper (&optional search) + "Invoke `swiper' with SEARCH, otherwise with the symbol at point." + (interactive "") + (swiper (or search (thing-at-point 'symbol))))) + +;;;###autoload +(defun +ivy/tasks () + (interactive) + ;; TODO Something a little nicer + (counsel-ag " (TODO|FIXME|NOTE) " (doom-project-root))) + +;;;###autoload +(defun +ivy*counsel-ag-function (string base-cmd extra-ag-args) + "Advice to get rid of the character limit from `counsel-ag-function', which +interferes with my custom :ag ex command `+ivy:ag-search'." + (when (null extra-ag-args) + (setq extra-ag-args "")) + (if (< (length string) 1) + (counsel-more-chars 1) + (let ((default-directory counsel--git-grep-dir) + (regex (counsel-unquote-regex-parens + (setq ivy--old-re + (ivy--regex string))))) + (let ((ag-cmd (format base-cmd + (concat extra-ag-args + " -- " + (shell-quote-argument regex))))) + (if (file-remote-p default-directory) + (split-string (shell-command-to-string ag-cmd) "\n" t) + (counsel--async-command ag-cmd) + nil))))) + +;;;###autoload +(defun +ivy/counsel-ag-occur () + "Invoke the search+replace wgrep buffer on the current ag search results." + (interactive) + (require 'wgrep) + (call-interactively 'ivy-occur)) + +(provide 'completion/ivy/autoload) +;;; completion/ivy/autoload.el ends here + diff --git a/modules/completion/ivy/config.el b/modules/completion/ivy/config.el new file mode 100644 index 000000000..d9de22ad5 --- /dev/null +++ b/modules/completion/ivy/config.el @@ -0,0 +1,80 @@ +;;; completion/ivy/packages.el + +;; TODO Make this a setting +(defmacro @def-counsel-action (name &rest forms) + `(defun ,(intern (format "+ivy/counsel-%s" (symbol-name name))) () + (interactive) + (ivy-set-action ',@forms) + (setq ivy-exit 'done) + (exit-minibuffer))) + +(@def-package ivy :demand t + :init + (setq ivy-height 14 + ivy-do-completion-in-region nil + ivy-wrap t + ivy-fixed-height-minibuffer t + ivy-format-function 'ivy-format-function-line) ;; highlight til EOL + + :config + (@map :map ivy-mode-map + [remap ivy-switch-buffer] '+ivy/switch-buffer + [remap projectile-switch-to-buffer] '+ivy/switch-project-buffer + + :map ivy-minibuffer-map + [escape] 'keyboard-escape-quit + "C-r" 'evil-paste-from-register + "M-v" 'clipboard-yank + "C-w" 'backward-kill-word + "C-u" 'backward-kill-sentence + "C-b" 'backward-word + "C-f" 'forward-word) + + ;; Occasionally, when ivy closes, it causes display artifacting between + ;; horizontal splits. This fixes it, though may cause flickering on some OSes. + (defun doom|redisplay (&rest _) (redisplay)) + (advice-add 'ivy-read :after 'doom|redisplay) + + (@after magit (setq magit-completing-read-function 'ivy-completing-read)) + (@after smex (setq smex-completion-method 'ivy)) + (@after yasnippet (push 'doom-yas-ivy-prompt yas-prompt-functions)) + + (ivy-mode +1)) + + +(@def-package counsel + :after ivy + :init + (setq counsel-find-file-ignore-regexp "\\(?:^[#.]\\)\\|\\(?:[#~]$\\)\\|\\(?:^Icon?\\)") + + :config + (require 'counsel-projectile) + + (@def-counsel-action ag-open-in-other-window + (lambda (x) + (when (string-match "\\`\\(.*?\\):\\([0-9]+\\):\\(.*\\)\\'" x) + (let ((file-name (match-string-no-properties 1 x)) + (line-number (match-string-no-properties 2 x))) + (with-ivy-window + (find-file-other-window (expand-file-name file-name counsel--git-grep-dir)) + (forward-line (1- (string-to-number line-number))) + (re-search-forward (ivy--regex ivy-text t) (line-end-position) t) + (swiper--ensure-visible) + (run-hooks 'counsel-grep-post-action-hook) + (unless (eq ivy-exit 'done) + (swiper--cleanup) + (swiper--add-overlays (ivy--regex ivy-text)))))))) + + (@def-counsel-action open-in-other-window + (lambda (x) (with-ivy-window (find-file-other-window x)))) + + (@add-hook doom-popup-mode + (when (eq major-mode 'ivy-occur-grep-mode) + (ivy-wgrep-change-to-wgrep-mode))) + + (advice-add 'counsel-ag-function :override '+ivy*counsel-ag-function) + (@map :map counsel-ag-map + [backtab] '+ivy/counsel-ag-occur ; search/replace on results + "C-SPC" 'counsel-git-grep-recenter ; preview + "M-RET" '+ivy/counsel-ag-open-in-other-window)) + diff --git a/modules/completion/ivy/packages.el b/modules/completion/ivy/packages.el new file mode 100644 index 000000000..b9d6c7a72 --- /dev/null +++ b/modules/completion/ivy/packages.el @@ -0,0 +1,6 @@ +;; -*- no-byte-compile: t; -*- +;;; completion/ivy/packages.el + +(@package ivy) +(@package counsel) +(@package counsel-projectile)