about summary refs log tree commit diff
path: root/configs/shared/emacs/.emacs.d/elpa/counsel-projectile-20180906.739/counsel-projectile.el
diff options
context:
space:
mode:
Diffstat (limited to 'configs/shared/emacs/.emacs.d/elpa/counsel-projectile-20180906.739/counsel-projectile.el')
-rw-r--r--configs/shared/emacs/.emacs.d/elpa/counsel-projectile-20180906.739/counsel-projectile.el1474
1 files changed, 1474 insertions, 0 deletions
diff --git a/configs/shared/emacs/.emacs.d/elpa/counsel-projectile-20180906.739/counsel-projectile.el b/configs/shared/emacs/.emacs.d/elpa/counsel-projectile-20180906.739/counsel-projectile.el
new file mode 100644
index 000000000000..4a6e33c03820
--- /dev/null
+++ b/configs/shared/emacs/.emacs.d/elpa/counsel-projectile-20180906.739/counsel-projectile.el
@@ -0,0 +1,1474 @@
+;;; counsel-projectile.el --- Ivy integration for Projectile -*- lexical-binding: t -*-
+
+;; Copyright (C) 2016-2018 Eric Danan
+
+;; Author: Eric Danan
+;; URL: https://github.com/ericdanan/counsel-projectile
+;; Package-Version: 20180906.739
+;; Keywords: project, convenience
+;; Version: 0.3.0-snapshot
+;; Package-Requires: ((counsel "0.10.0") (projectile "1.0.0"))
+
+;; This file is NOT part of GNU Emacs.
+
+;;; License:
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 3, or (at
+;; your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;;; Commentary:
+;;
+;; Projectile has native support for using ivy as its completion
+;; system. Counsel-projectile provides further ivy integration into
+;; projectile by taking advantage of ivy's support for selecting from
+;; a list of actions and applying an action without leaving the
+;; completion session. Concretely, counsel-projectile defines
+;; replacements for existing projectile commands as well as new
+;; commands that have no projectile counterparts. A minor mode is also
+;; provided that adds key bindings for all these commands on top of
+;; the projectile key bindings.
+;;
+;;; Code:
+
+;;* require
+
+(require 'counsel)
+(require 'projectile)
+
+;;* global
+
+(defgroup counsel-projectile nil
+  "Ivy integration for Projectile."
+  :group 'ivy
+  :group 'projectile)
+
+(defun counsel-projectile--defcustom-action (command action group)
+  "Create a custom variable named \"COMMAND-action\" in GROUP,
+with default value ACTION, to be used as `:action' parameter for
+COMMAND's `ivy-read' call.
+
+This variable holds either a single action function, or an action
+list whose first element is the index of the default action in
+the list and the remaining elements are the actions (a key, a
+function, and a name for each action)."
+  (eval
+   `(defcustom ,(intern (format "%s-action" command))
+      ',action
+      ,(format "Action(s) for `%s'.
+
+This variable holds either a single action function (function of
+one variable, the selected candidate) or an action list
+consisting of:
+
+- the index of the default action in the list (1 for the first
+  action, etc),
+- the available actions, each of which consists of:
+  - a key (string) to call the action,
+  - an action function of one variable,
+  - a name (string) for the action.
+
+In both cases, extra actions can be added with `ivy-set-actions'.
+An action is triggered for the selected candidate with `M-o
+<key>' or `C-M-o <key>'.  The default action can also be
+triggered with `M-RET' or `C-M-RET'. If this variable holds a
+single action function, this action becomes the default action
+and is assigned the key \"o\".  For an action list, it is also
+usual to assign the key \"o\" to the default action." command)
+      :type '(choice
+              (function :tag "Single action function")
+              (cons :tag "Action list"
+                    (integer :tag "Index of default action" :value 1)
+                    (repeat :tag "Actions"
+                            (list :tag "Action"
+                                  (string   :tag "     key")
+                                  (function :tag "function")
+                                  (string   :tag "    name")))))
+      :group ',group)))
+
+(defun counsel-projectile--action-index (action-item action-list)
+  "Return the index in ACTION-LIST of the action whose key,
+function, name, or index in the list (1 for the first action,
+etc) is ACTION-ITEM.  If there is no such action, throw an error.
+
+ACTION-LIST is an action list whose first element is the index of
+the default action in the list and the remaining elements are the
+actions (a key, a function, and a name for each action)."
+  (let (index)
+    (if (integerp action-item)
+        (when (< 0 action-item (length action-list))
+          (setq index action-item))
+      (setq index (cl-position-if
+                   (cond
+                    ((functionp action-item)
+                     (lambda (action)
+                       (equal action-item
+                              (cadr action))))
+                    ((stringp action-item)
+                     (lambda (action)
+                       (member action-item
+                               (list (car action) (cl-caddr action))))))
+                   (cdr action-list)))
+      (when index
+        (setq index (1+ index))))
+    (or index
+        (error "Action not found: %s" action-item))))
+
+(defun counsel-projectile-modify-action (action-var modifications)
+  "Make MODIFICATIONS to ACTION-VAR.
+
+ACTION-VAR is a variable holding an action list whose first
+element is the index of the default action in the list and the
+remaining elements are the actions (a key, a function, and a name
+for each action).
+
+MODIFICATIONS is a list of modifications to be applied
+sequentially to ACTION-LIST. Each modification has one of the
+following formats:
+
+    (remove ACTION-ITEM)
+        Remove the action whose key, function, name, or index in
+        the list (1 for the first action, etc) is ACTION-ITEM
+        from the list.
+
+    (add ACTION TARGET-ITEM)
+        Add ACTION (a list containing a key, a function, and a
+        name) to the list, just before the action whose key,
+        function, name, or index in the list (1 for the first
+        action, etc) is TARGET-ITEM.  If TARGET-ITEM is omitted,
+        add the action at the end of the list.
+
+    (move ACTION-ITEM TARGET-ITEM)
+        Move the action whose key, function, name, or index in
+        the list (1 for the first action, etc) is ACTION-ITEM
+        just before the action whose key, function, name, or
+        index in the list (1 for the first action, etc) is
+        TARGET-ITEM.  If TARGET-ITEM is omitted, move the action
+        to the end of the list.
+
+    (setkey ACTION-ITEM KEY)
+        Set the key of the action whose key, function, name, or
+        index in the list (1 for the first action, etc) is
+        ACTION-ITEM to KEY.
+
+    (setfun ACTION-ITEM FUNCTION)
+        Set the function of the action whose key, function, name,
+        or index in the list (1 for the first action, etc) is
+        ACTION-ITEM to FUNCTION.
+
+    (setname ACTION-ITEM NAME)
+        Set the name of the action whose key, function, name, or
+        index in the list (1 for the first action, etc) is
+        ACTION-ITEM to NAME.
+
+    (default ACTION-ITEM)
+        Set the index of the default action in the list to that
+        of the action whose key, function, name, or index in the
+        list (1 for the first action, etc) is ACTION-ITEM.
+
+If anything goes wrong, throw an error and do not modify ACTION-VAR."
+  (let ((action-list (symbol-value action-var))
+        mod)
+    ;; Make sure ACTION-VAR actually holds a list and not a single
+    ;; action function
+    (unless (listp action-list)
+      (error "%s's value is not a list" action-var))
+    (while (setq mod (pop modifications))
+      (pcase mod
+        (`(remove ,action-item)
+         (setq action-list
+               (remove (nth (counsel-projectile--action-index action-item action-list)
+                            action-list)
+                       action-list)))
+        (`(add ,action ,target-item)
+         (let ((index (counsel-projectile--action-index target-item action-list)))
+           ;; copied from `helm-append-at-nth'
+           (setq action-list (cl-loop for a in action-list
+                                      for count from 1
+                                      collect a
+                                      when (= count index)
+                                      collect action))))
+        (`(add ,action)
+         (setq action-list (append action-list (list action))))
+        (`(move ,action-item ,target-item)
+         (push `(add ,(nth (counsel-projectile--action-index action-item action-list)
+                           action-list)
+                     ,target-item)
+               modifications)
+         (push `(remove ,action-item)
+               modifications))
+        (`(move ,action-item)
+         (push `(add ,(nth (counsel-projectile--action-index action-item action-list)
+                           action-list))
+               modifications)
+         (push `(remove ,action-item)
+               modifications))
+        (`(setkey ,action-item ,key)
+         (let ((index (counsel-projectile--action-index action-item action-list)))
+           (setq action-list (cl-loop for a in action-list
+                                      for count from 0
+                                      if (= count index)
+                                      collect (cons key (cdr a))
+                                      else
+                                      collect a))))
+        (`(setfun ,action-item ,fun)
+         (let ((index (counsel-projectile--action-index action-item action-list)))
+           (setq action-list (cl-loop for a in action-list
+                                      for count from 0
+                                      if (= count index)
+                                      collect (list (car a) fun (cl-caddr a))
+                                      else
+                                      collect a))))
+        (`(setname ,action-item ,name)
+         (let ((index (counsel-projectile--action-index action-item action-list)))
+           (setq action-list (cl-loop for a in action-list
+                                      for count from 0
+                                      if (= count index)
+                                      collect (list (car a) (cadr a) name)
+                                      else
+                                      collect a))))
+        (`(default ,action-item)
+         (setq action-list
+               (cons (counsel-projectile--action-index action-item action-list)
+                     (cdr action-list))))))
+    (set action-var action-list)))
+
+;;* counsel-projectile-find-file
+
+(defcustom counsel-projectile-sort-files nil
+  "Non-nil if files should be sorted in
+`counsel-projectile-find-file' and `counsel-projectile'.
+
+The sorting function can be modified by adding an entry for
+`counsel-projectile-find-file' in `ivy-sort-functions-alist'."
+  :type 'boolean
+  :group 'counsel-projectile)
+
+(defcustom counsel-projectile-find-file-matcher 'counsel--find-file-matcher
+  "Function returning candidates matching minibuffer input in
+`counsel-projectile-find-file', also used to match files in
+`counsel-projectile'.
+
+Several choices are proposed:
+
+- Ivy generic matcher (`ivy--re-filter'). This is the matcher
+  used by default in all ivy commands.
+
+- Counsel matcher (`counsel--find-file-matcher').  This is the
+  matcher used in `counsel-find-file', allowing to ignore some
+  files based on `counsel-find-file-ignore-regexp'.
+
+- Counsel-projectile basename
+  matcher (`counsel-projectile-basename-matcher').  This one only
+  displays files whose basename matches minibuffer input, or if
+  there is none all files whose name (relative to the project
+  root) matches. It also uses the counsel matcher to ignore some
+  files.
+
+It is also possible to use a custom matcher.  It must be a function taking two argument, the regexp and the candidates (see e.g. `counsel--find-file-matcher')."
+  :type '(choice
+          (const :tag "Ivy generic matcher" ivy--re-filter)
+          (const :tag "Counsel matcher" counsel--find-file-matcher)
+          (const :tag "Counsel-projectile basename matcher" counsel-projectile-find-file-matcher-basename)
+          (function :tag "Custom function"))
+  :group 'counsel-projectile)
+
+(counsel-projectile--defcustom-action
+ 'counsel-projectile-find-file
+ '(1
+   ("o" counsel-projectile-find-file-action
+    "current window")
+   ("j" counsel-projectile-find-file-action-other-window
+    "other window")
+   ("x" counsel-projectile-find-file-action-extern
+    "open externally")
+   ("r" counsel-projectile-find-file-action-root
+    "open as root")
+   ("m" counsel-projectile-find-file-action-find-file-manually
+    "find file manually")
+   ("k" counsel-projectile-find-file-action-delete
+    "delete")
+   ("p" (lambda (_) (counsel-projectile-switch-project))
+    "switch project"))
+ 'counsel-projectile)
+
+(defun counsel-projectile-find-file-matcher-basename (regexp candidates)
+  "Return the list of CANDIDATES whose basename matches REGEXP,
+or if there is none the list of all CANDIDATES matching REGEXP.
+Also uses `counsel--find-file-matcher' to ignore candidates based
+on `counsel-find-file-ignore-regexp'."
+  (let ((cands (ivy--re-filter regexp candidates)))
+    (or (and (not (string= ivy-text ""))
+             ;; We first filter `cands' to retain only matches in file
+             ;; basename. This is almost copied from `ivy--re-filter'
+             ;; because we can't quite use it directly.
+             (let ((re-list (if (stringp regexp)
+                                (list (cons regexp t))
+                              regexp))
+                   (res cands))
+               (dolist (re re-list)
+                 (setq res
+                       (ignore-errors
+                         (funcall
+                          (if (cdr re)
+                              #'cl-remove-if-not
+                            #'cl-remove-if)
+                          (let ((re-str (car re)))
+                            (lambda (x)
+                              (string-match re-str
+                                            (file-name-nondirectory x))))
+                          res))))
+               ;; We then apply `counsel--find-file-matcher' to `res'
+               ;; so we can honor `ivy-use-ignore', but we don't need
+               ;; to filter again.
+               (counsel--find-file-matcher nil res)))
+        ;; We apply `counsel--find-file-matcher' to `cands' so we can
+        ;; honor `ivy-use-ignore', but we don't need to filter
+        ;; again.
+        (counsel--find-file-matcher nil cands))))     
+
+(defun counsel-projectile-find-file-action (file)
+  "Find FILE and run `projectile-find-file-hook'."
+  (find-file (projectile-expand-root file))
+  (run-hooks 'projectile-find-file-hook))
+
+(defun counsel-projectile-find-file-action-other-window (file)
+  "Find FILE in another window and run
+`projectile-find-file-hook'."
+  (find-file-other-window (projectile-expand-root file))
+  (run-hooks 'projectile-find-file-hook))
+
+(defun counsel-projectile-find-file-action-find-file-manually (file)
+  "Call `counsel-find-file' from FILE's directory."
+  (let* ((f (projectile-expand-root file))
+         (default-directory (file-name-directory f)))
+    (counsel-find-file)))
+
+(defun counsel-projectile-find-file-action-extern (file)
+  "Find FILE externally and run `projectile-find-file-hook'."
+  (counsel-find-file-extern (projectile-expand-root file))
+  (run-hooks 'projectile-find-file-hook))
+
+(defun counsel-projectile-find-file-action-root (file)
+  "Find FILE as root and run `projectile-find-file-hook'."
+  (counsel-find-file-as-root (projectile-expand-root file))
+  (run-hooks 'projectile-find-file-hook))
+
+(defun counsel-projectile-find-file-action-delete (file)
+  "Delete FILE."
+  (counsel-find-file-delete (projectile-expand-root file)))
+
+(defun counsel-projectile-find-file-transformer (str)
+  "Transform non-visited file names with `ivy-virtual' face."
+  (if (not (get-file-buffer (projectile-expand-root str)))
+      (propertize str 'face 'ivy-virtual)
+    str))
+
+;;;###autoload
+(defun counsel-projectile-find-file (&optional arg dwim)
+  "Jump to a file in the current project.
+
+With a prefix ARG, invalidate the cache first.  If DWIM is
+non-nil, use completion based on context."
+  (interactive "P")
+  (projectile-maybe-invalidate-cache arg)
+  (let* ((project-files (projectile-current-project-files))
+         (files (and dwim (projectile-select-files project-files))))
+    (ivy-read (projectile-prepend-project-name "Find file: ")
+              (or files project-files)
+              :matcher counsel-projectile-find-file-matcher
+              :require-match t
+              :sort counsel-projectile-sort-files
+              :action counsel-projectile-find-file-action
+              :caller 'counsel-projectile-find-file)))
+
+(ivy-set-display-transformer
+ 'counsel-projectile-find-file
+ 'counsel-projectile-find-file-transformer)
+
+;;;###autoload
+(defun counsel-projectile-find-file-dwim (&optional arg)
+  "Jump to a file in the current project using completion based on context.
+
+With a prefix ARG, invalidate the cache first."
+  (interactive "P")
+  (counsel-projectile-find-file arg t))
+
+;;* counsel-projectile-find-dir
+
+(defcustom counsel-projectile-sort-directories nil
+  "Non-nil if directories should be sorted in
+`counsel-projectile-find-dir'.
+
+The sorting function can be modified by adding an entry for
+`counsel-projectile-find-dir' in `ivy-sort-functions-alist'."
+  :type 'boolean
+  :group 'counsel-projectile)
+
+(counsel-projectile--defcustom-action
+ 'counsel-projectile-find-dir
+ '(1
+   ("o" counsel-projectile-find-dir-action
+    "current window")
+   ("j" counsel-projectile-find-dir-action-other-window
+    "other window")
+   ("x" counsel-projectile-find-dir-action-extern
+    "open externally")
+   ("r" counsel-projectile-find-dir-action-root
+    "open as root")
+   ("m" counsel-projectile-find-file-action-find-file-manually
+    "find file manually")
+   ("p" (lambda (_) (counsel-projectile-switch-project))
+    "switch project"))
+ 'counsel-projectile)
+ 
+(defun counsel-projectile--project-directories ()
+  "Return a list of current project's directories."
+  (if projectile-find-dir-includes-top-level
+      (append '("./") (projectile-current-project-dirs))
+    (projectile-current-project-dirs)))
+
+(defun counsel-projectile-find-dir-action (dir)
+  "Visit DIR with dired and run `projectile-find-dir-hook'."
+  (dired (projectile-expand-root dir))
+  (run-hooks 'projectile-find-dir-hook))
+
+(defun counsel-projectile-find-dir-action-other-window (dir)
+  "Visit DIR with dired in another window and run
+`projectile-find-dir-hook'."
+  (dired-other-window (projectile-expand-root dir))
+  (run-hooks 'projectile-find-dir-hook))
+
+(defun counsel-projectile-find-dir-action-extern (dir)
+  "Visit DIR externally and run `projectile-find-dir-hook'."
+  (counsel-find-file-extern (projectile-expand-root dir))
+  (run-hooks 'projectile-find-dir-hook))
+
+(defun counsel-projectile-find-dir-action-root (dir)
+  "Visit DIR as root and run `projectile-find-dir-hook'."
+  (counsel-find-file-as-root (projectile-expand-root dir))
+  (run-hooks 'projectile-find-dir-hook))
+
+(defun counsel-projectile-find-dir-transformer (str)
+  "Transform candidates with `ivy-subdir' face."
+  (propertize str 'face 'ivy-subdir))
+
+;;;###autoload
+(defun counsel-projectile-find-dir (&optional arg)
+  "Jump to a directory in the current project.
+
+With a prefix ARG, invalidate the cache first."
+  (interactive "P")
+  (projectile-maybe-invalidate-cache arg)
+  (ivy-read (projectile-prepend-project-name "Find dir: ")
+            (counsel-projectile--project-directories)
+            :require-match t
+            :sort counsel-projectile-sort-directories
+            :action counsel-projectile-find-dir-action
+            :caller 'counsel-projectile-find-dir))
+
+(ivy-set-display-transformer
+ 'counsel-projectile-find-dir
+ 'counsel-projectile-find-dir-transformer)
+
+;;* counsel-projectile-switch-to-buffer
+
+(defcustom counsel-projectile-sort-buffers nil
+  "Non-nil if buffers should be sorted in
+`counsel-projectile-switch-to-buffer' and `counsel-projectile'.
+
+The sorting function can be modified by adding an entry for
+`counsel-projectile-switch-to-buffer' in
+`ivy-sort-functions-alist'."
+  :type 'boolean
+  :group 'counsel-projectile)
+
+(defcustom counsel-projectile-remove-current-buffer nil
+  "Non-nil if current buffer should be removed from the
+candidates list of `counsel-projectile-switch-to-buffer' and
+`counsel-projectile'."
+  :type 'boolean
+  :group 'counsel-projectile)
+
+(counsel-projectile--defcustom-action
+ 'counsel-projectile-switch-to-buffer
+ '(1
+   ("o" counsel-projectile-switch-to-buffer-action
+    "current window")
+   ("j" switch-to-buffer-other-window
+    "other window")
+   ("k" ivy--kill-buffer-action
+    "kill")
+   ("m" counsel-projectile-switch-to-buffer-action-find-file-manually
+    "find file manually")
+   ("p" (lambda (_) (counsel-projectile-switch-project))
+    "switch project"))
+ 'counsel-projectile)
+
+(defvar counsel-projectile-switch-to-buffer-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map (kbd "C-c C-k") (lambda ()
+                                      (interactive)
+                                      (ivy--kill-buffer-action (ivy-state-current ivy-last))))
+    map)
+  "Keymap for `counsel-projectile-switch-to-buffer'.")
+
+(defun counsel-projectile--project-buffers (&rest _)
+  ;; The ignored arguments are so that the function can be used as
+  ;; collection function in `counsel-projectile-switch-to-buffer'.
+  "Return a list of buffers in the current project.
+
+Like `projectile-project-buffer-names', but propertize buffer
+names as in `ivy--buffer-list', and remove current buffer if
+`counsel-projectile-remove-currennt-buffer' is non-nil."
+  (let ((buffer-names (projectile-project-buffer-names)))
+    (when counsel-projectile-remove-current-buffer
+      (setq buffer-names (delete (buffer-name (current-buffer)) buffer-names)))
+    (ivy--buffer-list "" nil
+                      (lambda (x)
+                        (member (car x) buffer-names)))))
+
+(defun counsel-projectile-switch-to-buffer-action (buffer)
+  "Switch to BUFFER."
+  (switch-to-buffer buffer nil 'force-same-window))
+
+(defun counsel-projectile-switch-to-buffer-action-find-file-manually (buffer)
+  "Call `counsel-find-file' from BUFFER's default directory."
+  (let* ((b (get-buffer buffer))
+         (default-directory
+           (or (and b (buffer-local-value 'default-directory b))
+               (projectile-project-root))))
+    (counsel-find-file)))
+
+(defun counsel-projectile-switch-to-buffer-transformer (str)
+  "Transform candidate STR when switching project buffers.
+
+This simply applies the same transformer as in `ivy-switch-buffer', which is `ivy-switch-buffer-transformer' by default but could have been modified e.g. by the ivy-rich package."
+  (funcall (plist-get ivy--display-transformers-list 'ivy-switch-buffer)
+           str))
+
+;;;###autoload
+(defun counsel-projectile-switch-to-buffer ()
+  "Jump to a buffer in the current project."
+  (interactive)
+  (ivy-read (projectile-prepend-project-name "Switch to buffer: ")
+            ;; We use a collection function so that it is called each
+            ;; time the `ivy-state' is reset. This is needed for the
+            ;; "kill buffer" action.
+            #'counsel-projectile--project-buffers
+            :matcher #'ivy--switch-buffer-matcher
+            :require-match t
+            :sort counsel-projectile-sort-buffers
+            :action counsel-projectile-switch-to-buffer-action
+            :keymap counsel-projectile-switch-to-buffer-map
+            :caller 'counsel-projectile-switch-to-buffer))
+
+(ivy-set-display-transformer
+ 'counsel-projectile-switch-to-buffer
+ 'counsel-projectile-switch-to-buffer-transformer)
+
+;;* counsel-projectile-grep
+
+(defcustom counsel-projectile-grep-initial-input nil
+  "Initial minibuffer input for `counsel-projectile-grep'.  If
+non-nil, it should be a Lisp expression whose evaluation yields
+the initial input string.
+
+Note that you can always insert the value
+of `(ivy-thing-at-point)' by hitting \"M-n\" in the minibuffer."
+  :type '(choice
+          (const :tag "None" nil)
+          (const :tag "Symbol at point (generic)" '(thing-at-point 'symbol t))
+          (const :tag "Symbol or selection at point (projectile)" '(projectile-symbol-or-selection-at-point))
+          (const :tag "Thing at point (ivy)" '(ivy-thing-at-point))
+          (sexp  :tag "Custom expression"))
+  :group 'counsel-projectile)
+
+(defvar counsel-projectile-grep-base-command "grep -rnEI %s -- %%s %s"
+  "Format string to use in `cousel-projectile-grep' to
+construct the command.")
+
+(defvar counsel-projectile-grep-command nil)
+
+(defun counsel-projectile-grep-function (string)
+  "Grep for STRING in the current project."
+  (or (counsel-more-chars)
+      (let ((default-directory (ivy-state-directory ivy-last))
+            (regex (counsel-unquote-regex-parens
+                    (setq ivy--old-re
+                          (ivy--regex string)))))
+        (counsel--async-command (format counsel-projectile-grep-command
+                                        (shell-quote-argument regex)))
+        nil)))
+
+(defun counsel-projectile-grep-transformer (str)
+  "Higlight file and line number in STR, first removing the
+\"./\" prefix from the filename."
+  ;; This makes the display consistent with `counsel-git-grep' and
+  ;; `counsel-ag'-like commands.
+  (counsel-git-grep-transformer (string-remove-prefix "./" str)))
+
+(defun counsel-projectile-grep-occur ()
+  "Generate a custom occur buffer for `counsel-projectile-grep'."
+  ;; Copied from `counsel-grep-like-occur', except that we don't
+  ;; prepend "./" to the candidates since grep already does so.
+  (unless (eq major-mode 'ivy-occur-grep-mode)
+    (ivy-occur-grep-mode)
+    (setq default-directory (ivy-state-directory ivy-last)))
+  (setq ivy-text
+        (and (string-match "\"\\(.*\\)\"" (buffer-name))
+             (match-string 1 (buffer-name))))
+  (let* ((cmd (format counsel-projectile-grep-command
+                      (shell-quote-argument
+                       (counsel-unquote-regex-parens
+                        (ivy--regex ivy-text)))))
+         (cands (split-string (shell-command-to-string cmd) "\n" t)))
+    ;; 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 cands)))
+
+;;;###autoload
+(defun counsel-projectile-grep (&optional options-or-cmd)
+  "Search the current project with grep.
+
+If inside a git project and `projectile-use-git-grep' is non-nil,
+use git grep. Otherwise use grep recursively.
+
+OPTIONS-OR-CMD, if non-nil, is a string containing either
+additional options to be passed to grep, or an alternative git
+grep command. It is read from the minibuffer if the function is
+called with a prefix argument."
+  (interactive)
+  (if (and (eq (projectile-project-vcs) 'git)
+             projectile-use-git-grep)
+      (counsel-projectile-git-grep options-or-cmd)
+    (let* ((path
+            (mapconcat 'shell-quote-argument
+                       (projectile-normalise-paths
+                        (car (projectile-parse-dirconfig-file)))
+                       " "))
+           (ignored-files
+            (mapconcat (lambda (i)
+                         (concat "--exclude=" (shell-quote-argument i)))
+                       (append
+                        (projectile--globally-ignored-file-suffixes-glob)
+                        (projectile-ignored-files-rel))
+                       " "))
+           (ignored-dirs
+            (mapconcat (lambda (i)
+                         (concat "--exclude-dir=" (shell-quote-argument i)))
+                       (projectile-ignored-directories-rel)
+                       " "))
+           (ignored (concat ignored-files " " ignored-dirs))
+           (default-directory (projectile-project-root)))
+      (counsel-require-program
+       (car (split-string counsel-projectile-grep-base-command)))
+      (setq counsel-projectile-grep-command
+            (format counsel-projectile-grep-base-command ignored path))
+      (ivy-read (projectile-prepend-project-name "grep")
+                #'counsel-projectile-grep-function
+                :initial-input counsel-projectile-grep-initial-input
+                :dynamic-collection t
+                :keymap counsel-ag-map
+                :history 'counsel-git-grep-history
+                :action #'counsel-git-grep-action
+                :unwind (lambda ()
+                          (counsel-delete-process)
+                          (swiper--cleanup))
+                :caller 'counsel-projectile-grep))))
+
+(counsel-set-async-exit-code 'counsel-projectile-grep 1 "No matches found")
+(ivy-set-occur 'counsel-projectile-grep 'counsel-projectile-grep-occur)
+(ivy-set-display-transformer 'counsel-projectile-grep  'counsel-projectile-grep-transformer)
+
+;;;###autoload
+(defun counsel-projectile-git-grep (&optional cmd)
+  "Search the current project with git grep.
+
+CMD, if non-nil, is a string containing an alternative git grep
+command. It is read from the minibuffer if the function is called
+with a prefix argument."
+  (interactive)
+  (let* ((path
+          (mapconcat 'shell-quote-argument
+                     (projectile-normalise-paths
+                      (car (projectile-parse-dirconfig-file)))
+                     " "))
+         (counsel-git-grep-cmd-default
+          (concat (string-trim-right counsel-git-grep-cmd-default " \\.")
+                  " " path)))
+    (counsel-git-grep (or current-prefix-arg cmd)
+                      counsel-projectile-grep-initial-input)))
+
+;;* counsel-projectile-ag
+
+(defcustom counsel-projectile-ag-initial-input nil
+  "Initial minibuffer input for `counsel-projectile-ag'.  If
+non-nil, it should be a Lisp expression whose evaluation yields
+the initial input string.
+
+Note that you can always insert the value
+of `(ivy-thing-at-point)' by hitting \"M-n\" in the minibuffer."
+  :type '(choice
+          (const :tag "None" nil)
+          (const :tag "Symbol at point (generic)" '(thing-at-point 'symbol t))
+          (const :tag "Symbol or selection at point (projectile)" '(projectile-symbol-or-selection-at-point))
+          (const :tag "Thing at point (ivy)" '(ivy-thing-at-point))
+          (sexp  :tag "Custom expression"))
+  :group 'counsel-projectile)
+
+;;;###autoload
+(defun counsel-projectile-ag (&optional options)
+  "Search the current project with ag.
+
+OPTIONS, if non-nil, is a string containing additional options to
+be passed to ag. It is read from the minibuffer if the function
+is called with a prefix argument."
+  (interactive)
+  (let* ((path (mapconcat 'shell-quote-argument
+                          (projectile-normalise-paths
+                           (car (projectile-parse-dirconfig-file)))
+                          " "))
+         (ignored
+          (mapconcat (lambda (i)
+                       (concat "--ignore " (shell-quote-argument i)))
+                     (append
+                      (projectile--globally-ignored-file-suffixes-glob)
+                      (projectile-ignored-files-rel)
+                      (projectile-ignored-directories-rel))
+                     " "))
+         (counsel-ag-base-command
+          (format (string-trim-right counsel-ag-base-command " \\.")
+                  (concat ignored " %s " path))))
+    (counsel-ag (eval counsel-projectile-ag-initial-input)
+                (projectile-project-root)
+                options
+                (projectile-prepend-project-name
+                 (car (split-string counsel-ag-base-command))))))
+
+;;* counsel-projectile-rg
+
+(defcustom counsel-projectile-rg-initial-input nil
+  "Initial minibuffer input for `counsel-projectile-rg'.  If
+non-nil, it should be a Lisp expression whose evaluation yields
+the initial input string.
+
+Note that you can always insert the value
+of `(ivy-thing-at-point)' by hitting \"M-n\" in the minibuffer."
+  :type '(choice
+          (const :tag "None" nil)
+          (const :tag "Symbol at point (generic)" '(thing-at-point 'symbol t))
+          (const :tag "Symbol or selection at point (projectile)" '(projectile-symbol-or-selection-at-point))
+          (const :tag "Thing at point (ivy)" '(ivy-thing-at-point))
+          (sexp  :tag "Custom expression"))
+  :group 'counsel-projectile)
+
+;;;###autoload
+(defun counsel-projectile-rg (&optional options)
+  "Search the current project with rg.
+
+OPTIONS, if non-nil, is a string containing additional options to
+be passed to rg. It is read from the minibuffer if the function
+is called with a prefix argument."
+  (interactive)
+  (let* ((path
+          (mapconcat 'shell-quote-argument
+                     (or (projectile-normalise-paths
+                          (car (projectile-parse-dirconfig-file)))
+                         '("."))
+                     " "))
+         (ignored
+          (mapconcat (lambda (i)
+                       (concat "--glob !" (shell-quote-argument i)))
+                     (append
+                      (projectile--globally-ignored-file-suffixes-glob)
+                      (projectile-ignored-files-rel)
+                      (projectile-ignored-directories-rel))
+                     " "))
+         (counsel-rg-base-command
+          (format (string-trim-right counsel-rg-base-command " \\.")
+                  (concat ignored " %s " path))))
+    (counsel-rg (eval counsel-projectile-rg-initial-input)
+                (projectile-project-root)
+                options
+                (projectile-prepend-project-name
+                 (car (split-string counsel-rg-base-command))))))
+
+;;* counsel-projectile-org-capture
+
+(defvar org-capture-templates)
+(defvar org-capture-templates-contexts)
+
+(defcustom counsel-projectile-org-capture-templates
+  '(("t" "[${name}] Task" entry (file+headline "${root}/notes.org" "Tasks")
+     "* TODO %?\n  %u\n  %a"))
+  "Project-specific templates for the creation of new entries
+with `counsel-projectile-org-capture'.
+
+The format is the same as in `org-capture-templates', except that
+in a template's name or target, the placeholders \"${root}\" and
+\"${name}\" can be used to stand for the current project root and
+name, respectively.
+
+The default value contains a single template, whose name is
+\"[${name}] Task\" and whose target is:
+
+    \(file+headline \"${root}/notes.org}\" \"Tasks\"\)
+
+This points to headline \"Tasks\" in file \"notes.org\" in the
+project root directory (one file per project).
+
+Two other examples of valid targets are:
+
+    \(file+headline \"${root}/${name}.org}\" \"Tasks\"\)
+    \(file+olp \"~/notes.org\" \"${root}\" \"Tasks\"\)
+
+The first one is similar to the default value's target, except
+that the file is named after the project name (this can be handy
+if you use org-mode's agenda since the project name is then
+displayed as category). The second one points to outline path
+\"<project-root>/Tasks\" in file \"~/notes.org\" (same file for
+all projects)."
+  :type ;; copied from `org-capture-templates'
+  (let ((file-variants '(choice :tag "Filename       "
+                                (file :tag "Literal")
+                                (function :tag "Function")
+                                (variable :tag "Variable")
+                                (sexp :tag "Form"))))
+    `(repeat
+      (choice :value ("" "" entry (file "~/org/notes.org") "")
+              (list :tag "Multikey description"
+                    (string :tag "Keys       ")
+                    (string :tag "Description"))
+              (list :tag "Template entry"
+                    (string :tag "Keys           ")
+                    (string :tag "Description    ")
+                    (choice :tag "Capture Type   " :value entry
+                            (const :tag "Org entry" entry)
+                            (const :tag "Plain list item" item)
+                            (const :tag "Checkbox item" checkitem)
+                            (const :tag "Plain text" plain)
+                            (const :tag "Table line" table-line))
+                    (choice :tag "Target location"
+                            (list :tag "File"
+                                  (const :format "" file)
+                                  ,file-variants)
+                            (list :tag "ID"
+                                  (const :format "" id)
+                                  (string :tag "  ID"))
+                            (list :tag "File & Headline"
+                                  (const :format "" file+headline)
+                                  ,file-variants
+                                  (string :tag "  Headline"))
+                            (list :tag "File & Outline path"
+                                  (const :format "" file+olp)
+                                  ,file-variants
+                                  (repeat :tag "Outline path" :inline t
+                                          (string :tag "Headline")))
+                            (list :tag "File & Regexp"
+                                  (const :format "" file+regexp)
+                                  ,file-variants
+                                  (regexp :tag "  Regexp"))
+                            (list :tag "File [ & Outline path ] & Date tree"
+                                  (const :format "" file+olp+datetree)
+                                  ,file-variants
+                                  (option (repeat :tag "Outline path" :inline t
+                                                  (string :tag "Headline"))))
+                            (list :tag "File & function"
+                                  (const :format "" file+function)
+                                  ,file-variants
+                                  (sexp :tag "  Function"))
+                            (list :tag "Current clocking task"
+                                  (const :format "" clock))
+                            (list :tag "Function"
+                                  (const :format "" function)
+                                  (sexp :tag "  Function")))
+                    (choice :tag "Template       "
+                            (string)
+                            (list :tag "File"
+                                  (const :format "" file)
+                                  (file :tag "Template file"))
+                            (list :tag "Function"
+                                  (const :format "" function)
+                                  (function :tag "Template function")))
+                    (plist :inline t
+                           ;; Give the most common options as checkboxes
+                           :options (((const :format "%v " :prepend) (const t))
+                                     ((const :format "%v " :immediate-finish) (const t))
+                                     ((const :format "%v " :jump-to-captured) (const t))
+                                     ((const :format "%v " :empty-lines) (const 1))
+                                     ((const :format "%v " :empty-lines-before) (const 1))
+                                     ((const :format "%v " :empty-lines-after) (const 1))
+                                     ((const :format "%v " :clock-in) (const t))
+                                     ((const :format "%v " :clock-keep) (const t))
+                                     ((const :format "%v " :clock-resume) (const t))
+                                     ((const :format "%v " :time-prompt) (const t))
+                                     ((const :format "%v " :tree-type) (const week))
+                                     ((const :format "%v " :unnarrowed) (const t))
+                                     ((const :format "%v " :table-line-pos) (string))
+                                     ((const :format "%v " :kill-buffer) (const t))))))))
+  :group 'counsel-projectile)
+
+(defcustom counsel-projectile-org-capture-templates-contexts nil
+  "Alist of capture templates and valid contexts for `counsel-projectile-org-capture'.
+
+The format is the same as in `org-capture-templates-contexts'."
+  :type ;; copied from `org-capture-target-templates'
+  '(repeat (list :tag "Rule"
+                 (string :tag "        Capture key")
+                 (string :tag "Replace by template")
+                 (repeat :tag "Available when"
+                         (choice
+                          (cons :tag "Condition"
+                                (choice
+                                 (const :tag "In file" in-file)
+                                 (const :tag "Not in file" not-in-file)
+                                 (const :tag "In buffer" in-buffer)
+                                 (const :tag "Not in buffer" not-in-buffer)
+                                 (const :tag "In mode" in-mode)
+                                 (const :tag "Not in mode" not-in-mode))
+                                (regexp))
+                          (function :tag "Custom function")))))
+  :group 'counsel-projectile)
+
+;;;###autoload
+(defun counsel-projectile-org-capture (&optional from-buffer)
+  "Capture into the current project.
+
+This command is a replacement for `org-capture' (or
+`counsel-org-capture') offering project-specific capture
+templates, in addition to the regular templates available from
+`org-capture'. These project templates, which are \"expanded\"
+relatively to the current project, are determined by the
+variables `counsel-projectile-org-capture-templates' and
+`counsel-projectile-org-capture-templates-contexts'. See the
+former variable in particular for details.
+
+Optional argument FROM-BUFFER specifies the buffer from which to
+capture."
+  (interactive)
+  (require 'org-capture)
+  (let* ((root (ignore-errors (projectile-project-root)))
+         (name (projectile-project-name))
+         (org-capture-templates-contexts
+          (append (when root
+                    counsel-projectile-org-capture-templates-contexts)
+                  org-capture-templates-contexts))
+         (org-capture-templates
+          (append
+           (when root
+             (cl-loop
+              with replace-fun = `(lambda (string)
+                                    (replace-regexp-in-string
+                                     "\\${[^}]+}"
+                                     (lambda (s)
+                                       (pcase s
+                                         ("${root}" ,root)
+                                         ("${name}" ,name)))
+                                     string))
+              for template in counsel-projectile-org-capture-templates
+              collect (cl-loop
+                       for item in template
+                       if (= (cl-position item template) 1) ;; template's name
+                       collect (funcall replace-fun item)
+                       else if (= (cl-position item template) 3) ;; template's target
+                       collect (cl-loop
+                                for x in item
+                                if (stringp x)
+                                collect (funcall replace-fun x)
+                                else
+                                collect x)
+                       else
+                       collect item)))
+           org-capture-templates)))
+    (with-current-buffer (or from-buffer (current-buffer))
+      (counsel-org-capture))))
+
+;;* counsel-projectile-org-agenda
+
+(declare-function org-agenda-files "org")
+(defvar org-agenda-files)
+
+;;;###autoload
+(defun counsel-projectile-org-agenda (&optional arg keys restriction)
+  "Open project agenda.
+
+This command simply calls `org-agenda' after filtering out all
+agenda files that do not belong to the current project.
+
+Optional arguments ARG, KEYS, and RESTRICTION are as in
+`org-agenda'."
+  (interactive "P")
+  (require 'org-agenda)
+  (let* ((root (projectile-project-root))
+         (org-agenda-files
+          (cl-remove-if-not (lambda (file)
+                              (string-prefix-p root file))
+                            (org-agenda-files t 'ifmode))))
+    (org-agenda arg keys restriction)))
+
+;;* counsel-projectile-switch-project
+
+(defcustom counsel-projectile-sort-projects nil
+  "Non-nil if projects should be sorted in
+`counsel-projectile-switch-project'.
+
+The sorting function can be modified by adding an entry for
+`counsel-projectile-switch-project' in
+`ivy-sort-functions-alist'."
+  :type 'boolean
+  :group 'counsel-projectile)
+
+(defcustom counsel-projectile-remove-current-project nil
+  "Non-nil if current project should be removed from the
+candidates list of `counsel-projectile-switch-project'."
+  :type 'boolean
+  :group 'counsel-projectile)
+
+(counsel-projectile--defcustom-action
+ 'counsel-projectile-switch-project
+ '(1
+   ("o" counsel-projectile-switch-project-action
+    "jump to a project buffer or file")
+   ("f" counsel-projectile-switch-project-action-find-file
+    "jump to a project file")
+   ("d" counsel-projectile-switch-project-action-find-dir
+    "jump to a project directory")
+   ("D" counsel-projectile-switch-project-action-dired
+    "open project in dired")
+   ("b" counsel-projectile-switch-project-action-switch-to-buffer
+    "jump to a project buffer")
+   ("m" counsel-projectile-switch-project-action-find-file-manually
+    "find file manually from project root")
+   ("S" counsel-projectile-switch-project-action-save-all-buffers
+    "save all project buffers")
+   ("k" counsel-projectile-switch-project-action-kill-buffers
+    "kill all project buffers")
+   ("K" counsel-projectile-switch-project-action-remove-known-project
+    "remove project from known projects")
+   ("c" counsel-projectile-switch-project-action-compile
+    "run project compilation command")
+   ("C" counsel-projectile-switch-project-action-configure
+    "run project configure command")
+   ("E" counsel-projectile-switch-project-action-edit-dir-locals
+    "edit project dir-locals")
+   ("v" counsel-projectile-switch-project-action-vc
+    "open project in vc-dir / magit / monky")
+   ("sg" counsel-projectile-switch-project-action-grep
+    "search project with grep")
+   ("si" counsel-projectile-switch-project-action-git-grep
+    "search project with git grep")
+   ("ss" counsel-projectile-switch-project-action-ag
+    "search project with ag")
+   ("sr" counsel-projectile-switch-project-action-rg
+    "search project with rg")
+   ("xs" counsel-projectile-switch-project-action-run-shell
+    "invoke shell from project root")
+   ("xe" counsel-projectile-switch-project-action-run-eshell
+    "invoke eshell from project root")
+   ("xt" counsel-projectile-switch-project-action-run-term
+    "invoke term from project root")
+   ("Oc" counsel-projectile-switch-project-action-org-capture
+    "capture into project")
+   ("Oa" counsel-projectile-switch-project-action-org-agenda
+    "open project agenda"))
+ 'counsel-projectile)
+
+(defun counsel-projectile-switch-project-by-name (project)
+  "Switch to PROJECT.
+Invokes the command referenced by
+`projectile-switch-project-action' on switch.
+
+This is a replacement for `projectile-switch-project-by-name'
+with a different switching mechanism: the switch-project action
+is called from a dedicated buffer rather than the initial buffer.
+Also, PROJECT's dir-local variables are loaded before calling the
+action."
+  (run-hooks 'projectile-before-switch-project-hook)
+  ;; Kill and recreate the switch buffer to get rid of any local
+  ;; variable
+  (ignore-errors (kill-buffer " *counsel-projectile*"))
+  (set-buffer (get-buffer-create " *counsel-projectile*"))
+  (setq default-directory project)
+  ;; Load the project dir-local variables into the switch buffer, so
+  ;; the action can make use of them
+  (hack-dir-local-variables-non-file-buffer)
+  (funcall projectile-switch-project-action)
+  ;; If the action relies on `ivy-read' then, after one of its
+  ;; `ivy-read' actions is executed, the current buffer will be set
+  ;; back to the initial buffer. Hence we make sure tu evaluate
+  ;; `projectile-after-switch-project-hook' from the switch buffer.
+  (with-current-buffer " *counsel-projectile*"
+    (run-hooks 'projectile-after-switch-project-hook)))
+
+(defun counsel-projectile-switch-project-action (project)
+  "Jump to a file or buffer in PROJECT."
+  (let ((projectile-switch-project-action
+         (lambda ()
+           (counsel-projectile ivy-current-prefix-arg))))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-find-file (project)
+  "Jump to a file in PROJECT."
+  (let ((projectile-switch-project-action
+         (lambda ()
+           (counsel-projectile-find-file ivy-current-prefix-arg))))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-find-file-manually (project)
+  "Call `find-file' from PROJECT's root."
+  (let ((projectile-switch-project-action
+         (lambda ()
+           (counsel-find-file project))))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-find-dir (project)
+  "Jump to a directory in PROJECT."
+  (let ((projectile-switch-project-action
+         (lambda ()
+           (counsel-projectile-find-dir ivy-current-prefix-arg))))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-dired (project)
+  "Open `dired' at PROJECT root."
+  (let ((projectile-switch-project-action 'projectile-dired))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-switch-to-buffer (project)
+  "Jump to a buffer in PROJECT."
+  (let ((projectile-switch-project-action 'counsel-projectile-switch-to-buffer))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-save-all-buffers (project)
+  "Save all buffers in PROJECT."
+  (let ((projectile-switch-project-action 'projectile-save-project-buffers))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-kill-buffers (project)
+  "Kill all buffers in PROJECT."
+  (let ((projectile-switch-project-action 'projectile-kill-buffers))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-remove-known-project (project)
+  "Remove PROJECT from the list of known projects."
+  (projectile-remove-known-project project)
+  (setq ivy--all-candidates
+        (delete project ivy--all-candidates))
+  (ivy--reset-state ivy-last))
+
+(defun counsel-projectile-switch-project-action-compile (project)
+  "Run PROJECT compliation command."
+  (let ((projectile-switch-project-action
+         (lambda ()
+           (projectile-compile-project ivy-current-prefix-arg))))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-configure (project)
+  "Run PROJECT configure command."
+  (let ((projectile-switch-project-action
+         (lambda ()
+           (projectile-configure-project ivy-current-prefix-arg))))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-edit-dir-locals (project)
+  "Edit PROJECT's dir-locals."
+  (let ((projectile-switch-project-action 'projectile-edit-dir-locals))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-vc (project)
+  "Open PROJECT in vc-dir / magit / monky."
+  (let ((projectile-switch-project-action 'projectile-vc))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-run-shell (project)
+  "Invoke `shell' from PROJECT's root."
+  (let ((projectile-switch-project-action 'projectile-run-shell))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-run-eshell (project)
+  "Invoke `eshell' from PROJECT's root."
+  (let ((projectile-switch-project-action 'projectile-run-eshell))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-run-term (project)
+  "Invoke `term' from PROJECT's root."
+  (let ((projectile-switch-project-action
+         (lambda ()
+           (projectile-run-term nil))))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-grep (project)
+  "Search PROJECT with grep."
+  (let ((projectile-switch-project-action 'counsel-projectile-grep))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-git-grep (project)
+  "Search PROJECT with git grep."
+  (let ((projectile-switch-project-action 'counsel-projectile-git-grep))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-ag (project)
+  "Search PROJECT with ag."
+  (let ((projectile-switch-project-action 'counsel-projectile-ag))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-rg (project)
+  "Search PROJECT with rg."
+  (let ((projectile-switch-project-action 'counsel-projectile-rg))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-org-capture (project)
+  "Capture into PROJECT."
+  (let* ((from-buffer (ivy-state-buffer ivy-last))
+         (projectile-switch-project-action `(lambda ()
+                                              (counsel-projectile-org-capture ,from-buffer))))
+    (counsel-projectile-switch-project-by-name project)))
+
+(defun counsel-projectile-switch-project-action-org-agenda (project)
+  "Open PROJECT agenda."
+  (let ((projectile-switch-project-action 'counsel-projectile-org-agenda))
+    (counsel-projectile-switch-project-by-name project)))
+
+;;;###autoload
+(defun counsel-projectile-switch-project ()
+  "Switch project."
+  (interactive)
+  (ivy-read (projectile-prepend-project-name "Switch to project: ")
+            (if counsel-projectile-remove-current-project
+                (projectile-relevant-known-projects)
+              projectile-known-projects)
+            :preselect (and (projectile-project-p)
+                            (abbreviate-file-name (projectile-project-root)))
+            :action counsel-projectile-switch-project-action
+            :require-match t
+            :sort counsel-projectile-sort-projects
+            :caller 'counsel-projectile-switch-project))
+
+;;* counsel-projectile
+
+(counsel-projectile--defcustom-action
+ 'counsel-projectile
+ '(1
+   ("o" counsel-projectile-action
+    "current window")
+   ("j" counsel-projectile-action-other-window
+    "other window")
+   ("k" counsel-projectile-action-kill-delete
+    "kill buffer / delete-file")
+   ("x" counsel-projectile-action-file-extern
+    "open file externally")
+   ("r" counsel-projectile-action-file-root
+    "open file as root")
+   ("m" counsel-projectile-action-find-file-manually
+    "find file manually")
+   ("p" (lambda (_) (counsel-projectile-switch-project))
+    "switch project"))
+ 'counsel-projectile)
+
+(defvar counsel-projectile-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map (kbd "C-c C-k") (lambda ()
+                                      (interactive)
+                                      (counsel-projectile-action-kill-delete (ivy-state-current ivy-last))))
+    map)
+  "Keymap for `counsel-projectile'.")
+
+(defvar counsel-projectile--buffers nil
+  "Stores a list of project buffers.")
+
+(defvar counsel-projectile--non-visited-files nil
+  "Stores a list of project files that are not currently
+  visited by a buffer.")
+
+(defun counsel-projectile--project-buffers-and-files (&rest _)
+  ;; The ignored arguments are so that the function can be used as
+  ;; collection function in `counsel-projectile'.
+  "Return a list of buffers and non-visited files in the current
+  project.  Buffers and files are separately sorted depending on
+  `counsel-projectile-sort-buffers' and
+  `counsel-projectile-sort-files', respectively."
+  (let ((buffers (counsel-projectile--project-buffers))
+        (files (projectile-current-project-files))
+        (root (projectile-project-root))
+        file sort-fn)
+    ;; Remove files that are visited by a buffer:
+    (dolist (buffer buffers files)
+      (when (setq file (buffer-file-name (get-buffer buffer)))
+        (setq files (remove (file-relative-name file root) files))))
+    ;; Sort buffers and files depending on
+    ;; `counsel-projectile-sort-buffers' and
+    ;; `counsel-projectile-sort-files', respectively.
+    ;; We need to do this here because matching will be done against
+    ;; the variables `counsel-projectile--buffers' and
+    ;; `counsel-projectile--non-visited-files', not against the
+    ;; returned collection, so ivy's native sorting mechanism won't
+    ;; work.
+    (when (and counsel-projectile-sort-buffers
+               (<= (length buffers) ivy-sort-max-size)
+               (setq sort-fn (ivy--sort-function 'counsel-projectile-switch-to-buffer)))
+      (setq buffers (sort (copy-sequence buffers) sort-fn)))
+    (when (and counsel-projectile-sort-files
+               (<= (length files) ivy-sort-max-size)
+               (setq sort-fn (ivy--sort-function 'counsel-projectile-find-file)))
+      (setq files (sort (copy-sequence files) sort-fn)))
+    ;; Finally, bind `counsel-projectile--buffers' and
+    ;; `counsel-projectile--non-visited-files' and return the whole
+    ;; collection.
+    (append (setq counsel-projectile--buffers buffers)
+            (setq counsel-projectile--non-visited-files files))))
+
+(defun counsel-projectile--matcher (regexp _candidates)
+  "Return REGEXP-matching CANDIDATES for `counsel-projectile'.
+
+Relies on `ivy--switch-buffer-matcher' for buffers and the
+matcher specified in `counsel-projectile-find-file-matcher' for
+files."
+  (append (ivy--switch-buffer-matcher regexp counsel-projectile--buffers)
+          (funcall counsel-projectile-find-file-matcher regexp counsel-projectile--non-visited-files)))
+
+(defun counsel-projectile-action (name)
+  "Switch to buffer or find file named NAME."
+  (if (member name counsel-projectile--buffers)
+      (counsel-projectile-switch-to-buffer-action name)
+    (counsel-projectile-find-file-action name)))
+
+(defun counsel-projectile-action-other-window (name)
+  "Switch to buffer or find file named NAME in another window."
+  (if (member name counsel-projectile--buffers)
+      (switch-to-buffer-other-window name)
+    (counsel-projectile-find-file-action-other-window name)))
+
+(defun counsel-projectile-action-kill-delete (name)
+  "Kill buffer or delete-file named NAME."
+  (if (member name counsel-projectile--buffers)
+      (ivy--kill-buffer-action name)
+    (counsel-projectile-find-file-action-delete name)))
+  
+(defun counsel-projectile-action-find-file-manually (name)
+  "Call `counsel-find-file' from default directory of buffer
+directory of file named NAME."
+  (if (member name counsel-projectile--buffers)
+      (counsel-projectile-switch-to-buffer-action-find-file-manually name)
+    (counsel-projectile-find-file-action-find-file-manually name)))
+
+(defun counsel-projectile-action-file-extern (name)
+  "Find file named NAME externally."
+  (if (member name counsel-projectile--buffers)
+      (message "This action does not apply to buffers.")
+    (counsel-projectile-find-file-action-extern name)))
+
+(defun counsel-projectile-action-file-root (name)
+  "Find file named NAME as root."
+  (if (member name counsel-projectile--buffers)
+      (message "This action does not apply to buffers.")
+    (counsel-projectile-find-file-action-root name)))
+
+(defun counsel-projectile-transformer (str)
+  "Fontifies modified, file-visiting buffers as well as non-visited files."
+  (if (member str counsel-projectile--buffers)
+      (counsel-projectile-switch-to-buffer-transformer str)
+    (propertize str 'face 'ivy-virtual)))
+
+;;;###autoload
+(defun counsel-projectile (&optional arg)
+  "Jump to a buffer or file in the current project.
+
+With a prefix ARG, invalidate the cache first.
+
+If not inside a project, call `counsel-projectile-switch-project'."
+  (interactive "P")
+  (if (not (projectile-project-p))
+      (counsel-projectile-switch-project)
+    (projectile-maybe-invalidate-cache arg)
+    (ivy-read (projectile-prepend-project-name "Load buffer or file: ")
+              ;; We use a collection function so that it is called each
+              ;; time the `ivy-state' is reset. This is needed for the
+              ;; "kill buffer" action.
+              #'counsel-projectile--project-buffers-and-files
+              :matcher #'counsel-projectile--matcher
+              :require-match t
+              :action counsel-projectile-action
+              :keymap counsel-projectile-map
+              :caller 'counsel-projectile)))
+
+(ivy-set-display-transformer
+ 'counsel-projectile
+ 'counsel-projectile-transformer)
+
+;;* counsel-projectile-mode
+
+(defcustom counsel-projectile-key-bindings
+  '((projectile-find-file        . counsel-projectile-find-file)
+    (projectile-find-file-dwim   . counsel-projectile-find-file-dwim)
+    (projectile-find-dir         . counsel-projectile-find-dir)
+    (projectile-switch-to-buffer . counsel-projectile-switch-to-buffer)
+    (projectile-grep             . counsel-projectile-grep)
+    (projectile-ag               . counsel-projectile-ag)
+    (projectile-ripgrep          . counsel-projectile-rg)
+    (projectile-switch-project   . counsel-projectile-switch-project)
+    (" "                         . counsel-projectile)
+    ("si"                        . counsel-projectile-git-grep)
+    ("Oc"                        . counsel-projectile-org-capture)
+    ("Oa"                        . counsel-projectile-org-agenda))
+  "Alist of counsel-projectile key bindings.
+
+Each element is of the form \(KEY . DEF\) where KEY is either a
+key sequence to bind in `projectile-command-map' or a projectile
+command to remap in `projectile-mode-map', and DEF is the
+counsel-projectile command to which KEY is remapped or bound."
+  :type '(alist :key-type (choice (function :tag "Projectile command")
+                                  key-sequence)
+                :value-type (function :tag "Counsel-projectile command"))
+  :group 'counsel-projectile)
+
+;;;###autoload
+(define-minor-mode counsel-projectile-mode
+  "Toggle Counsel-Projectile mode on or off.
+
+With a prefix argument ARG, enable the mode if ARG is positive,
+and disable it otherwise.  If called from Lisp, enable the mode
+if ARG is omitted or nil, and toggle it if ARG is `toggle'.
+
+Counsel-Projectile mode turns on Projectile mode, thus enabling
+all projectile key bindings, and adds the counsel-projectile key
+bindings on top of them.
+
+The counsel-projectile key bindings either remap existing
+projectile commands to their counsel-projectile replacements or
+bind keys to counsel-projectile commands that have no projectile
+counterparts."
+  :group 'counsel-projectile
+  :require 'counsel-projectile
+  :global t
+  (cond
+   (counsel-projectile-mode
+    (projectile-mode)
+    (dolist (binding counsel-projectile-key-bindings)
+      (if (functionp (car binding))
+          (define-key projectile-mode-map `[remap ,(car binding)] (cdr binding))
+        (define-key projectile-command-map (car binding) (cdr binding)))))
+   (t
+    (dolist (binding counsel-projectile-key-bindings)
+      (if (functionp (car binding))
+          (define-key projectile-mode-map `[remap ,(car binding)] nil)
+        (define-key projectile-command-map (car binding) nil)))
+    (projectile-mode -1))))
+
+;;* provide
+
+(provide 'counsel-projectile)
+
+;;; counsel-projectile.el ends here