Merge branch 'develop'

* develop: (64 commits)
  Prepare for v2.0.5
  Temporarily disable doom-themes-visual-bell-config
  Fix neotree always changing root
  Update changelog
  Fix wrong-type-argument error from +org/insert-item
  Make +ivy-buffer-transformer autoloadable
  General refactor & cleanup
  Correct troubleshooting link in README
  org: set org-ellipsis to downward chevron
  Add elfeed-(show|search)-mode to evil-snipe-disabled-modes
  Autoload json library
  Rethink smartparens config #181
  README: expand troubleshooting
  Fix wiki links in README (again)
  Correct intro in README
  Fix wiki links in README
  Prevent private commands from affecting projectile cache
  Remove recentf-filename-handlers fix for projectile-recentf-files
  lang/sh: remove unused setup.sh
  Convert +ivy/switch-buffer to transformers + add mode icons #169
  ...
This commit is contained in:
Henrik Lissner 2017-09-03 23:32:23 +02:00
commit d2d71795e5
75 changed files with 1165 additions and 954 deletions

View file

@ -1,93 +1,96 @@
* :completion ivy
#+TITLE: :completion ivy
This module adds the Ivy completion backend.
This module adds Ivy, a completion backend.
I prefer ivy over ido and helm, for its speed and simplicity. With ivy's help and some hackery, I get the following features:
#+begin_quote
I prefer ivy over ido for its flexibility. I prefer ivy over helm because it's lighter.
#+end_quote
+ Project-wide search & replace powered by ~rg~ and ~ag~
+ Project-wide search & replace powered by ~rg~ or ~ag~
+ Project jump-to navigation ala Command-T, Sublime Text's Jump-to-anywhere or Vim's CtrlP plugin.
+ Ivy integration for ~M-x~, ~imenu~, ~recentf~ and others.
+ A powerful, interactive in-buffer search using ~swiper~.
+ Ivy-powered TODO/FIXME navigation
** Install
* Table of Contents :TOC:
- [[#install][Install]]
- [[#macos][MacOS]]
- [[#arch-linux][Arch Linux]]
- [[#usage][Usage]]
- [[#project-search--replace][Project search & replace]]
- [[#jump-to-file-project-navigation][Jump-to-file project navigation]]
- [[#in-buffer-searching][In-buffer searching]]
- [[#task-lookup][Task lookup]]
- [[#appendix][Appendix]]
- [[#commands][Commands]]
- [[#hacks][Hacks]]
* Install
This module optionally depends on [[https://github.com/BurntSushi/ripgrep][ripgrep]] and [[https://github.com/ggreer/the_silver_searcher][the_silver_searcher]].
~rg~ is faster, but its results aren't deterministic and it doesn't support multiline search or full PCRE, that's where ~ag~ is useful.
~rg~ is faster, but its results aren't deterministic, neither does it support multiline search or full PCRE, that's where ~ag~ is useful.
*** MacOS
** MacOS
#+BEGIN_SRC sh :tangle (if (doom-system-os 'macos) "yes")
brew install ripgrep the_silver_searcher
#+END_SRC
*** Arch Linux
** Arch Linux
#+BEGIN_SRC sh :dir /sudo:: :tangle (if (doom-system-os 'arch) "yes")
sudo pacman --needed --noconfirm -S ripgrep the_silver_searcher
#+END_SRC
** Usage
*** Search & Replace
A project-wide search can be performed with Ag (the silver searcher) or Rg
(ripgrep) via their ex commands: ~:ag[!]~ and ~:rg[!]~ (or their
current-directory counterparts ~:agcwd[!]~ and ~:rgcwd[!]~)
* Usage
Here is some insight into how I use this module. Keep in mind that the referenced commands and keybindings are defined [[/modules/private/hlissner][in my private module]].
** Project search & replace
Ex interfaces to Ag (the silver searcher) and Rg (ripgrep) are available: ~:ag[!]~ and ~:rg[!]~, or their current-directory counterparts ~:agcwd[!]~ and ~:rgcwd[!]~.
[[/../screenshots/modules/completion/ivy/ivy-search.gif]]
From this session, you can press =Shift + Tab= to create an writeable occur
buffer in wgrep mode.
From this session, you can press =S+Tab= to create a writeable occur-buffer in wgrep mode.
[[/../screenshots/modules/completion/ivy/ivy-search-replace.gif]]
Make your modifications and press =C-c C-c= to commit them, or =C-c C-k= to
abort.
Make your modifications and press =C-c C-c= to commit them, or =C-c C-k= to abort.
*** Jump-to-file project navigation
Inspired by Sublime Text's jump-to-anywhere, Vim's CtrlP or Unite plugins, and
Textmate's Command-T, a marriage of ~projectile~ and ~ivy~ makes this available
to you in Emacs. Invoke it with =<leader> /= or ~counsel-projectile-find-file~.
** Jump-to-file project navigation
Inspired by Sublime Text's jump-to-anywhere, Vim's CtrlP or Unite plugins, and Textmate's Command-T, a marriage of ~projectile~ and ~ivy~ makes this available to you in Emacs. Invoke it with =SPC f /=, =SPC SPC= or ~counsel-projectile-find-file~.
[[/../screenshots/modules/completion/ivy/ivy-projectile.gif]]
*** In-buffer searching
I prefer to use ~evil-search~ (invoked by pressing =/= in normal mode) when
jumping small/moderate (or predictable) distances. On occasion I need more
feedback, so I turn to ~swiper~ (available directly with =M-x swiper RET=, or
via ~:sw[iper]~).
** In-buffer searching
I use ~evil-search~ (invoked by pressing =/= in normal mode) when jumping small/moderate (or predictable) distances. However, there are occasions where I need more feedback, so I turn to ~swiper~ (available directly with =M-x swiper RET=, or via ~:sw[iper]~).
[[/../screenshots/modules/completion/ivy/ivy-swiper.gif]]
*** TODO-Task lookup
I sprinkle my projects with TODO's & FIXME's. Using ivy and ripgrep, I wrote
~+ivy/tasks~ to help me navigate to them. It can be invoked via ~:todo[!]~ as
well.
** Task lookup
I sprinkle my projects with TODO's & FIXME's. You can navigate to and peruse them via ~M-x +ivy/tasks~ or ~:todo[!]~ (ex command).
[[/../screenshots/modules/completion/ivy/ivy-todo.gif]]
** Appendix
*** Commands & Keybindings
Here is a list of my commonly used commands, their default keybinds (defined in
[[../../private/hlissner/+bindings.el][private/hlissner/+bindings.el]]), and their corresponding ex command (defined in
[[../../private/hlissner/+commands.el][private/hlissner/+commands.el]]).
* Appendix
** Commands
Here is a list of my commonly used commands, their default keybinds (defined in [[../../private/hlissner/+bindings.el][private/hlissner/+bindings.el]]), and their corresponding ex command (defined in [[../../private/hlissner/+commands.el][private/hlissner/+commands.el]]).
| command | key / ex command | description |
|-------------------------------------+---------------------+------------------------------------------------------------------|
| ~counsel-M-x~ | =M-x= | Smarter, smex-powered M-x |
| ~counsel-bookmark~ | =<leader> b= | Find bookmark |
| ~counsel-find-file~ | =<leader> .= | Browse from current directory |
| ~counsel-projectile-find-file~ | =<leader> /= | Find file in project |
| ~counsel-projectile-switch-project~ | =<leader> p= | Open another project |
| ~counsel-recentf~ | =<leader> r= | Find recently opened file |
| ~+ivy/switch-buffer~ | =<leader> ,= | Jump to buffer in current workspace |
| ~+ivy/switch-workspace-buffer~ | =<leader> <= | Jump to buffer across workspaces |
| ~+ivy:ag~ | ~:ag[!] [QUERY]~ | Search project (BANG = ignore gitignore) |
| ~+ivy:ag-cwd~ | ~:agcwd[!] [QUERY]~ | Search this directory (BANG = don't recurse into subdirectories) |
| ~+ivy:rg~ | ~:rg[!] [QUERY]~ | Search project (if BANG, ignore gitignore) |
| ~+ivy:rg-cwd~ | ~:rgcwd[!] [QUERY]~ | Search this directory (BANG = don't recurse into subdirectories) |
| ~+ivy:swiper~ | ~:sw[iper] [QUERY]~ | Search current buffer |
| ~+ivy:todo~ | ~:todo[!]~ | List all TODO/FIXMEs in project (or current file if BANG) |
| command | key / ex command | description |
|-------------------------------------+------------------------+------------------------------------------------------------------|
| ~counsel-M-x~ | =M-x= | Smarter, smex-powered M-x |
| ~counsel-bookmark~ | =SPC RET= | Find bookmark |
| ~counsel-find-file~ | =SPC f .= or =SPC .= | Browse from current directory |
| ~counsel-projectile-find-file~ | =SPC f /= or =SPC SPC= | Find file in project |
| ~counsel-projectile-switch-project~ | =SPC p p= | Open another project |
| ~counsel-recentf~ | =SPC f r= | Find recently opened file |
| ~ivy-switch-buffer~ | =SPC b b= | Jump to buffer in current workspace |
| ~+ivy/switch-workspace-buffer~ | =SPC b B= | Jump to buffer across workspaces |
| ~+ivy:ag~ | ~:ag[!] [QUERY]~ | Search project (BANG = ignore gitignore) |
| ~+ivy:ag-cwd~ | ~:agcwd[!] [QUERY]~ | Search this directory (BANG = don't recurse into subdirectories) |
| ~+ivy:rg~ | ~:rg[!] [QUERY]~ | Search project (if BANG, ignore gitignore) |
| ~+ivy:rg-cwd~ | ~:rgcwd[!] [QUERY]~ | Search this directory (BANG = don't recurse into subdirectories) |
| ~+ivy:swiper~ | ~:sw[iper] [QUERY]~ | Search current buffer |
| ~+ivy:todo~ | ~:todo[!]~ | List all TODO/FIXMEs in project (or current file if BANG) |
While in a search (e.g. invoked from ~+ivy:ag~ or ~+ivy:rg~), these new
keybindings are available to you:
While in a search (e.g. invoked from ~+ivy:ag~ or ~+ivy:rg~), these new keybindings are available to you:
| key | description |
|-------------+--------------------------------------------------------------------------------|
@ -95,10 +98,8 @@ keybindings are available to you:
| =C-SPC= | Preview the current candidate |
| =M-RET= | Open the selected candidate in other-window |
*** Hacks
+ Where possible, functions with ivy/counsel equivalents have been remapped
(like ~find-file~ => ~counsel-find-file~). So a keybinding to ~find-file~ will
invoke ~counsel-find-file~ instead.
** Hacks
+ Functions with ivy/counsel equivalents have been globally remapped (like ~find-file~ => ~counsel-find-file~). So a keybinding to ~find-file~ will invoke ~counsel-find-file~ instead.
+ ~counsel-[arp]g~'s 3-character limit was reduced to 1 (mainly for the ex command)
+ ~counsel-[arp]g~'s parentheses quoting behavior was reversed. Now, if you
want literal parentheses, you must escape them: e.g. ~\(match\)~ is literal,

View file

@ -1,72 +1,48 @@
;;; completion/ivy/autoload/ivy.el -*- lexical-binding: t; -*-
;; Show more information in ivy-switch-buffer; and only display
;; workgroup-relevant buffers.
(defun +ivy--get-buffers (&optional buffer-list)
(when-let (buffer-list (delq (current-buffer) (or buffer-list (doom-buffer-list))))
(let* ((min-name
(+ 5 (cl-loop for buf in buffer-list
maximize (length (buffer-name buf)))))
(min-mode
(+ 5 (cl-loop for buf in buffer-list
maximize (length (symbol-name (buffer-local-value 'major-mode buf)))))))
(cl-loop
with project-root = (doom-project-root)
for buf in buffer-list
collect
(cl-destructuring-bind (type mode path)
(with-current-buffer buf
(list (concat
(let ((buffer-name (buffer-name buf)))
(propertize
buffer-name
'face (cond ((string-match-p "^ ?\\*" buffer-name)
'font-lock-comment-face)
((not (string= project-root (doom-project-root)))
'warning)
(buffer-read-only
'error))))
(when (and buffer-file-name (buffer-modified-p))
(propertize "[+]" 'face 'doom-modeline-buffer-modified)))
(propertize (symbol-name major-mode) 'face 'font-lock-constant-face)
(when buffer-file-name
(abbreviate-file-name
(file-name-directory buffer-file-name)))))
(format (format "%%-%ds %%-%ds %%s" min-name min-mode)
type mode (or path "")))))))
(defun +ivy--select-buffer-action (buffer)
(ivy--switch-buffer-action
(string-remove-suffix
"[+]"
(substring buffer 0 (string-match-p (regexp-quote " ") buffer)))))
(defun +ivy--select-buffer-other-window-action (buffer)
(ivy--switch-buffer-other-window-action
(string-remove-suffix
"[+]"
(substring buffer 0 (string-match-p (regexp-quote " ") buffer)))))
(defsubst +ivy--icon-for-mode (mode)
"Apply `all-the-icons-for-mode' on MODE but either return an icon or nil."
(let ((icon (all-the-icons-icon-for-mode mode)))
(unless (symbolp icon) icon)))
;;;###autoload
(defun +ivy/switch-workspace-buffer (&optional other-window-p)
"Switch to an open buffer in the current workspace.
If OTHER-WINDOW-P (universal arg), then open target in other window."
(interactive "P")
(+ivy/switch-buffer other-window-p t))
(defun +ivy-buffer-transformer (str)
(let* ((buf (get-buffer str))
(path (buffer-file-name buf))
(mode (buffer-local-value 'major-mode buf))
(faces
(with-current-buffer buf
(cond ((string-match-p "^ ?\\*" (buffer-name buf))
'font-lock-comment-face)
((buffer-modified-p buf)
'doom-modeline-buffer-modified)
(buffer-read-only
'error)))))
(propertize
(format "%-40s %s%-20s %s"
str
(if +ivy-buffer-icons
(concat (propertize " " 'display
(or (+ivy--icon-for-mode mode)
(+ivy--icon-for-mode (get mode 'derived-mode-parent))))
"\t")
"")
mode
(or (and path (abbreviate-file-name (file-name-directory (file-truename path))))
""))
'face faces)))
;;;###autoload
(defun +ivy/switch-buffer (&optional other-window-p workspace-only-p)
"Switch to an open buffer in the global buffer list.
(defun +ivy/switch-workspace-buffer (&optional arg)
"Switch to another buffer within the current workspace.
If OTHER-WINDOW-P (universal arg), then open target in other window.
If WORKSPACE-ONLY-P (universal arg), limit to buffers in the current workspace."
If ARG (universal argument), open selection in other-window."
(interactive "P")
(ivy-read (format "%s buffers: " (if workspace-only-p "Workspace" "Global"))
(+ivy--get-buffers (unless workspace-only-p (buffer-list)))
:action (if other-window-p
#'+ivy--select-buffer-other-window-action
#'+ivy--select-buffer-action)
(ivy-read "Switch to workspace buffer: "
(mapcar #'buffer-name (delq (current-buffer) (doom-buffer-list)))
:action (if arg
#'ivy--switch-buffer-other-window-action
#'ivy--switch-buffer-action)
:matcher #'ivy--switch-buffer-matcher
:keymap ivy-switch-buffer-map
:caller #'+ivy/switch-workspace-buffer))

View file

@ -1,5 +1,8 @@
;;; completion/ivy/config.el -*- lexical-binding: t; -*-
(defvar +ivy-buffer-icons nil
"If non-nil, show buffer mode icons in `ivy-switch-buffer' and the like.")
(defvar +ivy-task-tags
'(("TODO" . warning)
("FIXME" . error))
@ -22,7 +25,8 @@ session)."
;;
(def-package! ivy
:demand t
:commands ivy-mode
:init (add-hook 'doom-init-hook #'ivy-mode)
:config
(setq ivy-height 12
ivy-do-completion-in-region nil
@ -40,13 +44,11 @@ session)."
(after! magit (setq magit-completing-read-function #'ivy-completing-read))
(after! yasnippet (push #'+ivy-yas-prompt yas-prompt-functions))
(add-hook 'doom-init-hook #'ivy-mode)
(map! :map ivy-mode-map
[remap apropos] #'counsel-apropos
[remap describe-face] #'counsel-describe-face
[remap find-file] #'counsel-find-file
[remap switch-to-buffer] #'+ivy/switch-buffer
[remap switch-to-buffer] #'ivy-switch-buffer
[remap persp-switch-to-buffer] #'+ivy/switch-workspace-buffer
[remap recentf] #'counsel-recentf
[remap imenu] #'counsel-imenu
@ -59,6 +61,12 @@ session)."
[remap describe-variable] #'counsel-describe-variable
[remap describe-face] #'counsel-describe-face)
;; Show more buffer information in switch-buffer commands
(ivy-set-display-transformer 'ivy-switch-buffer #'+ivy-buffer-transformer)
(ivy-set-display-transformer 'ivy-switch-buffer-other-window #'+ivy-buffer-transformer)
(ivy-set-display-transformer '+ivy/switch-workspace-buffer #'+ivy-buffer-transformer)
(ivy-set-display-transformer 'counsel-recentf #'abbreviate-file-name)
(when (featurep! :feature workspaces)
(nconc ivy-sort-functions-alist
'((persp-kill-buffer . nil)