Commit 7a4e5605fa50
Changed files (36)
.emacs.d
elpa
counsel-projectile-20170911.1304
epl-20150517.433
general-20170708.104
persp-projectile-20160709.2317
perspective-20160609.1444
pkg-info-20150517.443
projectile-20170917.410
.emacs.d/elpa/counsel-projectile-20170911.1304/counsel-projectile-autoloads.el
@@ -0,0 +1,74 @@
+;;; counsel-projectile-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
+
+;;;### (autoloads nil "counsel-projectile" "counsel-projectile.el"
+;;;;;; (22977 30126 563673 375000))
+;;; Generated autoloads from counsel-projectile.el
+
+(autoload 'counsel-projectile-find-file "counsel-projectile" "\
+Jump to a project's file using completion.
+
+Replacement for `projectile-find-file'. With a prefix ARG
+invalidates the cache first.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'counsel-projectile-find-dir "counsel-projectile" "\
+Jump to a project's directory using completion.
+
+With a prefix ARG invalidates the cache first.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'counsel-projectile-switch-to-buffer "counsel-projectile" "\
+Switch to a project buffer.
+
+\(fn)" t nil)
+
+(autoload 'counsel-projectile-ag "counsel-projectile" "\
+Run an ag search in the project.
+
+\(fn &optional OPTIONS)" t nil)
+
+(autoload 'counsel-projectile-rg "counsel-projectile" "\
+Run an rg search in the project.
+
+\(fn &optional OPTIONS)" t nil)
+
+(autoload 'counsel-projectile-switch-project "counsel-projectile" "\
+Switch to a project we have visited before.
+
+Invokes the command referenced by
+`projectile-switch-project-action' on switch.
+
+\(fn)" t nil)
+
+(autoload 'counsel-projectile "counsel-projectile" "\
+Use projectile with Ivy instead of ido.
+
+With a prefix ARG invalidates the cache first.
+
+\(fn &optional ARG)" t nil)
+
+(eval-after-load 'projectile '(progn (define-key projectile-command-map (kbd "SPC") #'counsel-projectile)))
+
+(autoload 'counsel-projectile-on "counsel-projectile" "\
+Turn on counsel-projectile key bindings.
+
+\(fn)" t nil)
+
+(autoload 'counsel-projectile-off "counsel-projectile" "\
+Turn off counsel-projectile key bindings.
+
+\(fn)" t nil)
+
+;;;***
+
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+;;; counsel-projectile-autoloads.el ends here
.emacs.d/elpa/counsel-projectile-20170911.1304/counsel-projectile-pkg.el
@@ -0,0 +1,2 @@
+;;; -*- no-byte-compile: t -*-
+(define-package "counsel-projectile" "20170911.1304" "Ivy integration for Projectile" '((counsel "0.8.0") (projectile "0.14.0")) :commit "20557b47a963cc5304ac2bc3ea4800c3a7da7feb" :url "https://github.com/ericdanan/counsel-projectile" :keywords '("project" "convenience"))
.emacs.d/elpa/counsel-projectile-20170911.1304/counsel-projectile.el
@@ -0,0 +1,582 @@
+;;; counsel-projectile.el --- Ivy integration for Projectile
+
+;; Copyright (C) 2016 Eric Danan
+
+;; Author: Eric Danan
+;; URL: https://github.com/ericdanan/counsel-projectile
+;; Package-Version: 20170911.1304
+;; Created: 2016-04-11
+;; Keywords: project, convenience
+;; Version: 0.1
+;; Package-Requires: ((counsel "0.8.0") (projectile "0.14.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 mechanism to select from a
+;; list of actions and/or apply an action without leaving the
+;; comlpetion session. It is inspired by helm-projectile. See the
+;; README for more details.
+;;
+;;; Code:
+
+(require 'counsel)
+(require 'projectile)
+
+;;; counsel-projectile-map
+
+(defun counsel-projectile-drop-to-switch-project ()
+ "For use in minibuffer maps. Quit and call
+`counsel-projectile-switch-project'."
+ (interactive)
+ (ivy-quit-and-run
+ (counsel-projectile-switch-project)))
+
+(defvar counsel-projectile-drop-to-switch-project-binding "M-SPC"
+ "Key binding for `counsel-projectile-drop-to-switch-project' in
+ `counsel-projectile-map'.")
+
+(defvar counsel-projectile-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map
+ (kbd counsel-projectile-drop-to-switch-project-binding)
+ 'counsel-projectile-drop-to-switch-project)
+ map)
+ "Keymap used in the minibuffer.")
+
+;;; counsel-projectile-find-file
+
+(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-transformer (name)
+ "Transform non-visited file names with `ivy-virtual' face."
+ (if (not (get-file-buffer (expand-file-name name (projectile-project-root))))
+ (propertize name 'face 'ivy-virtual)
+ name))
+
+;;;###autoload
+(defun counsel-projectile-find-file (&optional arg)
+ "Jump to a project's file using completion.
+
+Replacement for `projectile-find-file'. With a prefix ARG
+invalidates the cache first."
+ (interactive "P")
+ (projectile-maybe-invalidate-cache arg)
+ (ivy-read (projectile-prepend-project-name "Find file: ")
+ (projectile-current-project-files)
+ :matcher #'counsel--find-file-matcher
+ :require-match t
+ :keymap counsel-projectile-map
+ :action #'counsel-projectile-find-file-action
+ :caller 'counsel-projectile-find-file))
+
+(defvar counsel-projectile-find-file-actions
+ '(("j" counsel-projectile-find-file-action-other-window
+ "other window"))
+ "List of actions for `counsel-projecile-find-file'. If
+ you modify this variable after loading counsel-projectile, then
+ you should call `ivy-set-actions' afterwards to apply your
+ changes.")
+
+(ivy-set-actions
+ 'counsel-projectile-find-file
+ counsel-projectile-find-file-actions)
+
+(ivy-set-display-transformer
+ 'counsel-projectile-find-file
+ 'counsel-projectile-find-file-transformer)
+
+;;; counsel-projectile-find-dir
+
+(defun counsel-projectile--dir-list ()
+ "Return a list of files for the current project."
+ (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))
+
+;;;###autoload
+(defun counsel-projectile-find-dir (&optional arg)
+ "Jump to a project's directory using completion.
+
+With a prefix ARG invalidates the cache first."
+ (interactive "P")
+ (projectile-maybe-invalidate-cache arg)
+ (ivy-read (projectile-prepend-project-name "Find dir: ")
+ (counsel-projectile--dir-list)
+ :require-match t
+ :keymap counsel-projectile-map
+ :action #'counsel-projectile-find-dir-action
+ :caller 'counsel-projectile-find-dir))
+
+(defvar counsel-projectile-find-dir-actions
+ '(("j" counsel-projectile-find-dir-action-other-window
+ "other window"))
+ "List of actions for `counsel-projecile-find-dir'. If
+ you modify this variable after loading counsel-projectile, then
+ you should call `ivy-set-actions' afterwards to apply your
+ changes.")
+
+(ivy-set-actions
+ 'counsel-projectile-find-dir
+ counsel-projectile-find-dir-actions)
+
+;;; counsel-projectile-switch-to-buffer
+
+(defun counsel-projectile--buffer-list ()
+ "Get a list of project buffer names.
+
+Like `projectile-project-buffer-names', but propertize buffer
+names as in `ivy--buffer-list'."
+ (let ((buffer-names (projectile-project-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))
+
+;;;###autoload
+(defun counsel-projectile-switch-to-buffer ()
+ "Switch to a project buffer."
+ (interactive)
+ (ivy-read (projectile-prepend-project-name "Switch to buffer: ")
+ (counsel-projectile--buffer-list)
+ :matcher #'ivy--switch-buffer-matcher
+ :require-match t
+ :keymap counsel-projectile-map
+ :action #'counsel-projectile-switch-to-buffer-action
+ :caller 'counsel-projectile-switch-to-buffer))
+
+(defvar counsel-projectile-switch-to-buffer-actions
+ '(("j" switch-to-buffer-other-window
+ "other window"))
+ "List of actions for `counsel-projecile-switch-to-buffer'. If
+ you modify this variable after loading counsel-projectile, then
+ you should call `ivy-set-actions' afterwards to apply your
+ changes.")
+
+(ivy-set-actions
+ 'counsel-projectile-switch-to-buffer
+ counsel-projectile-switch-to-buffer-actions)
+
+(ivy-set-display-transformer
+ 'counsel-projectile-switch-to-buffer
+ 'ivy-switch-buffer-transformer)
+
+;;; counsel-projectile-ag
+
+(defvar counsel-projectile-ag-initial-input nil
+ "Initial minibuffer input for `counsel-projectile-ag'. If non-nil, it should be a form whose evaluation yields the initial input string, e.g.
+
+ (setq counsel-projectile-ag-initial-input
+ '(projectile-symbol-or-selection-at-point))
+
+or
+
+ (setq counsel-projectile-ag-initial-input
+ '(thing-at-point 'symbol t))
+
+Note that you can always insert the value of `(ivy-thing-at-point)' by
+hitting \"M-n\" in the minibuffer.")
+
+;;;###autoload
+(defun counsel-projectile-ag (&optional options)
+ "Run an ag search in the project."
+ (interactive)
+ (if (projectile-project-p)
+ (let* ((options
+ (if current-prefix-arg
+ (read-string "options: ")
+ options))
+ (ignored
+ (unless (eq (projectile-project-vcs) 'git)
+ ;; ag supports git ignore files
+ (append
+ (cl-union (projectile-ignored-files-rel) grep-find-ignored-files)
+ (cl-union (projectile-ignored-directories-rel) grep-find-ignored-directories))))
+ (options
+ (concat options " "
+ (mapconcat (lambda (i)
+ (concat "--ignore " (shell-quote-argument i)))
+ ignored
+ " "))))
+ (counsel-ag (eval counsel-projectile-ag-initial-input)
+ (projectile-project-root)
+ options
+ (projectile-prepend-project-name "ag")))
+ (user-error "You're not in a project")))
+
+;;; counsel-projectile-rg
+
+(defvar counsel-projectile-rg-initial-input nil
+ "Initial minibuffer input for `counsel-projectile-rg'. See `counsel-projectile-ag-initial-input' for details.")
+
+;;;###autoload
+(defun counsel-projectile-rg (&optional options)
+ "Run an rg search in the project."
+ (interactive)
+ (if (projectile-project-p)
+ (let* ((options
+ (if current-prefix-arg
+ (read-string "options: ")
+ options))
+ (ignored
+ (unless (eq (projectile-project-vcs) 'git)
+ ;; rg supports git ignore files
+ (append
+ (cl-union (projectile-ignored-files-rel) grep-find-ignored-files)
+ (cl-union (projectile-ignored-directories-rel) grep-find-ignored-directories))))
+ (options
+ (concat options " "
+ (mapconcat (lambda (i)
+ (concat "--glob " (shell-quote-argument (concat "!" i))))
+ ignored
+ " "))))
+ (counsel-rg (eval counsel-projectile-rg-initial-input)
+ (projectile-project-root)
+ options
+ (projectile-prepend-project-name "rg")))
+ (user-error "You're not in a project")))
+
+;;; counsel-projectile-switch-project
+
+(defun counsel-projectile-switch-project-action (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-find-file (project)
+ "Action for `counsel-projectile-switch-project' to find a
+PROJECT file."
+ (let ((projectile-switch-project-action
+ (lambda ()
+ (counsel-projectile-find-file ivy-current-prefix-arg))))
+ (counsel-projectile-switch-project-action project)))
+
+(defun counsel-projectile-switch-project-action-find-file-manually (project)
+ "Action for `counsel-projectile-switch-project' to find a
+PROJECT file manually."
+ (let ((projectile-switch-project-action
+ (lambda ()
+ (counsel-find-file project))))
+ (counsel-projectile-switch-project-action project)))
+
+(defun counsel-projectile-switch-project-action-find-dir (project)
+ "Action for `counsel-projectile-switch-project' to find a
+PROJECT directory."
+ (let ((projectile-switch-project-action
+ (lambda ()
+ (counsel-projectile-find-dir ivy-current-prefix-arg))))
+ (counsel-projectile-switch-project-action project)))
+
+(defun counsel-projectile-switch-project-action-switch-to-buffer (project)
+ "Action for `counsel-projectile-switch-project' to switch to a
+PROJECT buffer."
+ (let ((projectile-switch-project-action 'counsel-projectile-switch-to-buffer))
+ (counsel-projectile-switch-project-action project)))
+
+(defun counsel-projectile-switch-project-action-save-all-buffers (project)
+ "Action for `counsel-projectile-switch-project' to save all
+PROJECT buffers."
+ (let ((projectile-switch-project-action 'projectile-save-project-buffers))
+ (counsel-projectile-switch-project-action project)))
+
+(defun counsel-projectile-switch-project-action-kill-buffers (project)
+ "Action for `counsel-projectile-switch-project' to kill all
+PROJECT buffers."
+ (let ((projectile-switch-project-action 'projectile-kill-buffers))
+ (counsel-projectile-switch-project-action project)))
+
+(defun counsel-projectile-switch-project-action-remove-known-project (project)
+ "Action for `counsel-projectile-switch-project' to remove
+PROJECT from the list of known projects."
+ (projectile-remove-known-project project)
+ (setq ivy--all-candidates
+ (delete dir ivy--all-candidates))
+ (ivy--reset-state ivy-last))
+
+(defun counsel-projectile-switch-project-action-edit-dir-locals (project)
+ "Action for `counsel-projectile-switch-project' to edit
+PROJECT's dir-locals."
+ (let ((projectile-switch-project-action 'projectile-edit-dir-locals))
+ (counsel-projectile-switch-project-action project)))
+
+(defun counsel-projectile-switch-project-action-vc (project)
+ "Action for `counsel-projectile-switch-project' to open PROJECT
+in vc-dir / magit / monky."
+ (let ((projectile-switch-project-action 'projectile-vc))
+ (counsel-projectile-switch-project-action project)))
+
+(defun counsel-projectile-switch-project-action-run-eshell (project)
+ "Action for `counsel-projectile-switch-project' to start
+`eshell' from PROJECT's root."
+ (let ((projectile-switch-project-action 'projectile-run-eshell))
+ (counsel-projectile-switch-project-action project)))
+
+(defun counsel-projectile-switch-project-action-ag (project)
+ "Action for `counsel-projectile-switch-project' to search
+PROJECT with `ag'."
+ (let ((projectile-switch-project-action 'counsel-projectile-ag))
+ (counsel-projectile-switch-project-action project)))
+
+(defun counsel-projectile-switch-project-action-rg (project)
+ "Action for `counsel-projectile-switch-project' to search
+PROJECT with `rg'."
+ (let ((projectile-switch-project-action 'counsel-projectile-rg))
+ (counsel-projectile-switch-project-action project)))
+
+;;;###autoload
+(defun counsel-projectile-switch-project ()
+ "Switch to a project we have visited before.
+
+Invokes the command referenced by
+`projectile-switch-project-action' on switch."
+ (interactive)
+ (ivy-read (projectile-prepend-project-name "Switch to project: ")
+ projectile-known-projects
+ :preselect (and (projectile-project-p)
+ (abbreviate-file-name (projectile-project-root)))
+ :action #'counsel-projectile-switch-project-action
+ :require-match t
+ :caller 'counsel-projectile-switch-project))
+
+(defvar counsel-projectile-switch-project-actions
+ '(("f" counsel-projectile-switch-project-action-find-file
+ "find file")
+ ("F" counsel-projectile-switch-project-action-find-file-manually
+ "find file manually")
+ ("d" counsel-projectile-switch-project-action-find-dir
+ "find directory")
+ ("b" counsel-projectile-switch-project-action-switch-to-buffer
+ "switch to buffer")
+ ("s" counsel-projectile-switch-project-action-save-all-buffers
+ "save all buffers")
+ ("k" counsel-projectile-switch-project-action-kill-buffers
+ "kill all buffers")
+ ("r" counsel-projectile-switch-project-action-remove-known-project
+ "remove from known projects")
+ ("l" counsel-projectile-switch-project-action-edit-dir-locals
+ "edit dir-locals")
+ ("g" counsel-projectile-switch-project-action-vc
+ "open in vc-dir / magit / monky")
+ ("e" counsel-projectile-switch-project-action-run-eshell
+ "start eshell")
+ ("a" counsel-projectile-switch-project-action-ag
+ "search with ag")
+ ("R" counsel-projectile-switch-project-action-rg
+ "search with rg"))
+ "List of actions for `counsel-projecile-switch-project'. If
+ you modify this variable after loading counsel-projectile, then
+ you should call `ivy-set-actions' afterwards to apply your
+ changes.")
+
+(ivy-set-actions
+ 'counsel-projectile-switch-project
+ counsel-projectile-switch-project-actions)
+
+;;; counsel-projectile
+
+(defvar counsel-projectile--buffers nil
+ "Stores the list of project buffers.")
+
+(defvar counsel-projectile--non-visited-files nil
+ "Stores the list of project files that are not currently visited by a buffer.")
+
+(defun counsel-projectile--buffer-file-list ()
+ "Get a list of project buffers and files."
+ (append
+ (setq counsel-projectile--buffers
+ (counsel-projectile--buffer-list))
+ (setq counsel-projectile--non-visited-files
+ (let ((root (projectile-project-root))
+ (files (projectile-current-project-files))
+ file)
+ (dolist (buffer counsel-projectile--buffers files)
+ (when (setq file (buffer-file-name (get-buffer buffer)))
+ (delete (file-relative-name file root) files)))))))
+
+(defun counsel-projectile--matcher (regexp candidates)
+ "Return REGEXP-matching CANDIDATES.
+
+Relies on `ivy--switch-buffer-matcher' and
+`counsel--find-file-matcher'."
+ (append (ivy--switch-buffer-matcher regexp counsel-projectile--buffers)
+ (counsel--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-transformer (name)
+ "Fontifies modified, file-visiting buffers as well as non-visited files."
+ (if (member name counsel-projectile--buffers)
+ (ivy-switch-buffer-transformer name)
+ (propertize name 'face 'ivy-virtual)))
+
+;;;###autoload
+(defun counsel-projectile (&optional arg)
+ "Use projectile with Ivy instead of ido.
+
+With a prefix ARG invalidates the cache first."
+ (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: ")
+ (counsel-projectile--buffer-file-list)
+ :matcher #'counsel-projectile--matcher
+ :require-match t
+ :keymap counsel-projectile-map
+ :action #'counsel-projectile-action
+ :caller 'counsel-projectile)))
+
+(defvar counsel-projectile-actions
+ '(("j" counsel-projectile-action-other-window
+ "other window"))
+ "List of actions for `counsel-projecile'. If
+ you modify this variable after loading counsel-projectile, then
+ you should call `ivy-set-actions' afterwards to apply your
+ changes.")
+
+(ivy-set-actions
+ 'counsel-projectile
+ counsel-projectile-actions)
+
+(ivy-set-display-transformer
+ 'counsel-projectile
+ 'counsel-projectile-transformer)
+
+;;; key bindings
+
+;;;###autoload
+(eval-after-load 'projectile
+ '(progn
+ (define-key projectile-command-map (kbd "SPC") #'counsel-projectile)))
+
+(defun counsel-projectile-commander-bindings ()
+ (def-projectile-commander-method ?f
+ "Find file in project."
+ (counsel-projectile-find-file))
+ (def-projectile-commander-method ?d
+ "Find directory in project."
+ (counsel-projectile-find-dir))
+ (def-projectile-commander-method ?b
+ "Switch to project buffer."
+ (counsel-projectile-switch-to-buffer))
+ (def-projectile-commander-method ?A
+ "Search project files with ag."
+ (counsel-projectile-ag))
+ (def-projectile-commander-method ?s
+ "Switch project."
+ (counsel-projectile-switch-project)))
+
+(defun counsel-projectile-toggle (toggle)
+ "Toggle counsel-projectile keybindings."
+ (if (> toggle 0)
+ (progn
+ (when (eq projectile-switch-project-action #'projectile-find-file)
+ (setq projectile-switch-project-action #'counsel-projectile))
+ (define-key projectile-mode-map [remap projectile-find-file] #'counsel-projectile-find-file)
+ (define-key projectile-mode-map [remap projectile-find-dir] #'counsel-projectile-find-dir)
+ (define-key projectile-mode-map [remap projectile-switch-project] #'counsel-projectile-switch-project)
+ (define-key projectile-mode-map [remap projectile-ag] #'counsel-projectile-ag)
+ (define-key projectile-mode-map [remap projectile-switch-to-buffer] #'counsel-projectile-switch-to-buffer)
+ (counsel-projectile-commander-bindings))
+ (progn
+ (when (eq projectile-switch-project-action #'counsel-projectile)
+ (setq projectile-switch-project-action #'projectile-find-file))
+ (define-key projectile-mode-map [remap projectile-find-file] nil)
+ (define-key projectile-mode-map [remap projectile-find-dir] nil)
+ (define-key projectile-mode-map [remap projectile-switch-project] nil)
+ (define-key projectile-mode-map [remap projectile-ag] nil)
+ (define-key projectile-mode-map [remap projectile-switch-to-buffer] nil)
+ (projectile-commander-bindings))))
+
+;;;###autoload
+(defun counsel-projectile-on ()
+ "Turn on counsel-projectile key bindings."
+ (interactive)
+ (message "Turn on counsel-projectile key bindings")
+ (counsel-projectile-toggle 1))
+
+;;;###autoload
+(defun counsel-projectile-off ()
+ "Turn off counsel-projectile key bindings."
+ (interactive)
+ (message "Turn off counsel-projectile key bindings")
+ (counsel-projectile-toggle -1))
+
+
+(provide 'counsel-projectile)
+
+;;; counsel-projectile.el ends here
.emacs.d/elpa/counsel-projectile-20170911.1304/counsel-projectile.elc
Binary file
.emacs.d/elpa/epl-20150517.433/epl-autoloads.el
@@ -0,0 +1,15 @@
+;;; epl-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
+
+;;;### (autoloads nil nil ("epl.el") (22977 30123 194706 666000))
+
+;;;***
+
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+;;; epl-autoloads.el ends here
.emacs.d/elpa/epl-20150517.433/epl-pkg.el
@@ -0,0 +1,2 @@
+;;; -*- no-byte-compile: t -*-
+(define-package "epl" "20150517.433" "Emacs Package Library" '((cl-lib "0.3")) :commit "83797835f729f39b80acba4c7e83d73a2e410e26" :url "http://github.com/cask/epl" :keywords '("convenience"))
.emacs.d/elpa/epl-20150517.433/epl.el
@@ -0,0 +1,695 @@
+;;; epl.el --- Emacs Package Library -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2013-2015 Sebastian Wiesner
+;; Copyright (C) 1985-1986, 1992, 1994-1995, 1999-2015 Free Software
+
+;; Author: Sebastian Wiesner <swiesner@lunaryorn.com>
+;; Maintainer: Johan Andersson <johan.rejeep@gmail.com>
+;; Sebastian Wiesner <swiesner@lunaryorn.com>
+;; Version: 0.9-cvs
+;; Package-Version: 20150517.433
+;; Package-Requires: ((cl-lib "0.3"))
+;; Keywords: convenience
+;; URL: http://github.com/cask/epl
+
+;; This file is NOT part of GNU Emacs.
+
+;; 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 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; A package management library for Emacs, based on package.el.
+
+;; The purpose of this library is to wrap all the quirks and hassle of
+;; package.el into a sane API.
+
+;; The following functions comprise the public interface of this library:
+
+;;; Package directory selection
+
+;; `epl-package-dir' gets the directory of packages.
+
+;; `epl-default-package-dir' gets the default package directory.
+
+;; `epl-change-package-dir' changes the directory of packages.
+
+;;; Package system management
+
+;; `epl-initialize' initializes the package system and activates all
+;; packages.
+
+;; `epl-reset' resets the package system.
+
+;; `epl-refresh' refreshes all package archives.
+
+;; `epl-add-archive' adds a new package archive.
+
+;;; Package objects
+
+;; Struct `epl-requirement' describes a requirement of a package with `name' and
+;; `version' slots.
+
+;; `epl-requirement-version-string' gets a requirement version as string.
+
+;; Struct `epl-package' describes an installed or installable package with a
+;; `name' and some internal `description'.
+
+;; `epl-package-version' gets the version of a package.
+
+;; `epl-package-version-string' gets the version of a package as string.
+
+;; `epl-package-summary' gets the summary of a package.
+
+;; `epl-package-requirements' gets the requirements of a package.
+
+;; `epl-package-directory' gets the installation directory of a package.
+
+;; `epl-package-from-buffer' creates a package object for the package contained
+;; in the current buffer.
+
+;; `epl-package-from-file' creates a package object for a package file, either
+;; plain lisp or tarball.
+
+;; `epl-package-from-descriptor-file' creates a package object for a package
+;; description (i.e. *-pkg.el) file.
+
+;;; Package database access
+
+;; `epl-package-installed-p' determines whether a package is installed, either
+;; built-in or explicitly installed.
+
+;; `epl-package-outdated-p' determines whether a package is outdated, that is,
+;; whether a package with a higher version number is available.
+
+;; `epl-built-in-packages', `epl-installed-packages', `epl-outdated-packages'
+;; and `epl-available-packages' get all packages built-in, installed, outdated,
+;; or available for installation respectively.
+
+;; `epl-find-built-in-package', `epl-find-installed-packages' and
+;; `epl-find-available-packages' find built-in, installed and available packages
+;; by name.
+
+;; `epl-find-upgrades' finds all upgradable packages.
+
+;; `epl-built-in-p' return true if package is built-in to Emacs.
+
+;;; Package operations
+
+;; `epl-install-file' installs a package file.
+
+;; `epl-package-install' installs a package.
+
+;; `epl-package-delete' deletes a package.
+
+;; `epl-upgrade' upgrades packages.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'package)
+
+
+(unless (fboundp #'define-error)
+ ;; `define-error' for 24.3 and earlier, copied from subr.el
+ (defun define-error (name message &optional parent)
+ "Define NAME as a new error signal.
+MESSAGE is a string that will be output to the echo area if such an error
+is signaled without being caught by a `condition-case'.
+PARENT is either a signal or a list of signals from which it inherits.
+Defaults to `error'."
+ (unless parent (setq parent 'error))
+ (let ((conditions
+ (if (consp parent)
+ (apply #'append
+ (mapcar (lambda (parent)
+ (cons parent
+ (or (get parent 'error-conditions)
+ (error "Unknown signal `%s'" parent))))
+ parent))
+ (cons parent (get parent 'error-conditions)))))
+ (put name 'error-conditions
+ (delete-dups (copy-sequence (cons name conditions))))
+ (when message (put name 'error-message message)))))
+
+(defsubst epl--package-desc-p (package)
+ "Whether PACKAGE is a `package-desc' object.
+
+Like `package-desc-p', but return nil, if `package-desc-p' is not
+defined as function."
+ (and (fboundp 'package-desc-p) (package-desc-p package)))
+
+
+;;; EPL errors
+(define-error 'epl-error "EPL error")
+
+(define-error 'epl-invalid-package "Invalid EPL package" 'epl-error)
+
+(define-error 'epl-invalid-package-file "Invalid EPL package file"
+ 'epl-invalid-package)
+
+
+;;; Package directory
+(defun epl-package-dir ()
+ "Get the directory of packages."
+ package-user-dir)
+
+(defun epl-default-package-dir ()
+ "Get the default directory of packages."
+ (eval (car (get 'package-user-dir 'standard-value))))
+
+(defun epl-change-package-dir (directory)
+ "Change the directory of packages to DIRECTORY."
+ (setq package-user-dir directory)
+ (epl-initialize))
+
+
+;;; Package system management
+(defvar epl--load-path-before-initialize nil
+ "Remember the load path for `epl-reset'.")
+
+(defun epl-initialize (&optional no-activate)
+ "Load Emacs Lisp packages and activate them.
+
+With NO-ACTIVATE non-nil, do not activate packages."
+ (setq epl--load-path-before-initialize load-path)
+ (package-initialize no-activate))
+
+(defalias 'epl-refresh 'package-refresh-contents)
+
+(defun epl-add-archive (name url)
+ "Add a package archive with NAME and URL."
+ (add-to-list 'package-archives (cons name url)))
+
+(defun epl-reset ()
+ "Reset the package system.
+
+Clear the list of installed and available packages, the list of
+package archives and reset the package directory."
+ (setq package-alist nil
+ package-archives nil
+ package-archive-contents nil
+ load-path epl--load-path-before-initialize)
+ (when (boundp 'package-obsolete-alist) ; Legacy package.el
+ (setq package-obsolete-alist nil))
+ (epl-change-package-dir (epl-default-package-dir)))
+
+
+;;; Package structures
+(cl-defstruct (epl-requirement
+ (:constructor epl-requirement-create))
+ "Structure describing a requirement.
+
+Slots:
+
+`name' The name of the required package, as symbol.
+
+`version' The version of the required package, as version list."
+ name
+ version)
+
+(defun epl-requirement-version-string (requirement)
+ "The version of a REQUIREMENT, as string."
+ (package-version-join (epl-requirement-version requirement)))
+
+(cl-defstruct (epl-package (:constructor epl-package-create))
+ "Structure representing a package.
+
+Slots:
+
+`name' The package name, as symbol.
+
+`description' The package description.
+
+The format package description varies between package.el
+variants. For `package-desc' variants, it is simply the
+corresponding `package-desc' object. For legacy variants, it is
+a vector `[VERSION REQS DOCSTRING]'.
+
+Do not access `description' directly, but instead use the
+`epl-package' accessors."
+ name
+ description)
+
+(defmacro epl-package-as-description (var &rest body)
+ "Cast VAR to a package description in BODY.
+
+VAR is a symbol, bound to an `epl-package' object. This macro
+casts this object to the `description' object, and binds the
+description to VAR in BODY."
+ (declare (indent 1))
+ (unless (symbolp var)
+ (signal 'wrong-type-argument (list #'symbolp var)))
+ `(if (epl-package-p ,var)
+ (let ((,var (epl-package-description ,var)))
+ ,@body)
+ (signal 'wrong-type-argument (list #'epl-package-p ,var))))
+
+(defsubst epl-package--package-desc-p (package)
+ "Whether the description of PACKAGE is a `package-desc'."
+ (epl--package-desc-p (epl-package-description package)))
+
+(defun epl-package-version (package)
+ "Get the version of PACKAGE, as version list."
+ (epl-package-as-description package
+ (cond
+ ((fboundp 'package-desc-version) (package-desc-version package))
+ ;; Legacy
+ ((fboundp 'package-desc-vers)
+ (let ((version (package-desc-vers package)))
+ (if (listp version) version (version-to-list version))))
+ (:else (error "Cannot get version from %S" package)))))
+
+(defun epl-package-version-string (package)
+ "Get the version from a PACKAGE, as string."
+ (package-version-join (epl-package-version package)))
+
+(defun epl-package-summary (package)
+ "Get the summary of PACKAGE, as string."
+ (epl-package-as-description package
+ (cond
+ ((fboundp 'package-desc-summary) (package-desc-summary package))
+ ((fboundp 'package-desc-doc) (package-desc-doc package)) ; Legacy
+ (:else (error "Cannot get summary from %S" package)))))
+
+(defsubst epl-requirement--from-req (req)
+ "Create a `epl-requirement' from a `package-desc' REQ."
+ (let ((version (cadr req)))
+ (epl-requirement-create :name (car req)
+ :version (if (listp version) version
+ (version-to-list version)))))
+
+(defun epl-package-requirements (package)
+ "Get the requirements of PACKAGE.
+
+The requirements are a list of `epl-requirement' objects."
+ (epl-package-as-description package
+ (mapcar #'epl-requirement--from-req (package-desc-reqs package))))
+
+(defun epl-package-directory (package)
+ "Get the directory PACKAGE is installed to.
+
+Return the absolute path of the installation directory of
+PACKAGE, or nil, if PACKAGE is not installed."
+ (cond
+ ((fboundp 'package-desc-dir)
+ (package-desc-dir (epl-package-description package)))
+ ((fboundp 'package--dir)
+ (package--dir (symbol-name (epl-package-name package))
+ (epl-package-version-string package)))
+ (:else (error "Cannot get package directory from %S" package))))
+
+(defun epl-package-->= (pkg1 pkg2)
+ "Determine whether PKG1 is before PKG2 by version."
+ (not (version-list-< (epl-package-version pkg1)
+ (epl-package-version pkg2))))
+
+(defun epl-package--from-package-desc (package-desc)
+ "Create an `epl-package' from a PACKAGE-DESC.
+
+PACKAGE-DESC is a `package-desc' object, from recent package.el
+variants."
+ (if (and (fboundp 'package-desc-name)
+ (epl--package-desc-p package-desc))
+ (epl-package-create :name (package-desc-name package-desc)
+ :description package-desc)
+ (signal 'wrong-type-argument (list 'epl--package-desc-p package-desc))))
+
+(defun epl-package--parse-info (info)
+ "Parse a package.el INFO."
+ (if (epl--package-desc-p info)
+ (epl-package--from-package-desc info)
+ ;; For legacy package.el, info is a vector [NAME REQUIRES DESCRIPTION
+ ;; VERSION COMMENTARY]. We need to re-shape this vector into the
+ ;; `package-alist' format [VERSION REQUIRES DESCRIPTION] to attach it to the
+ ;; new `epl-package'.
+ (let ((name (intern (aref info 0)))
+ (info (vector (aref info 3) (aref info 1) (aref info 2))))
+ (epl-package-create :name name :description info))))
+
+(defun epl-package-from-buffer (&optional buffer)
+ "Create an `epl-package' object from BUFFER.
+
+BUFFER defaults to the current buffer.
+
+Signal `epl-invalid-package' if the buffer does not contain a
+valid package file."
+ (let ((info (with-current-buffer (or buffer (current-buffer))
+ (condition-case err
+ (package-buffer-info)
+ (error (signal 'epl-invalid-package (cdr err)))))))
+ (epl-package--parse-info info)))
+
+(defun epl-package-from-lisp-file (file-name)
+ "Parse the package headers the file at FILE-NAME.
+
+Return an `epl-package' object with the header metadata."
+ (with-temp-buffer
+ (insert-file-contents file-name)
+ (condition-case err
+ (epl-package-from-buffer (current-buffer))
+ ;; Attach file names to invalid package errors
+ (epl-invalid-package
+ (signal 'epl-invalid-package-file (cons file-name (cdr err))))
+ ;; Forward other errors
+ (error (signal (car err) (cdr err))))))
+
+(defun epl-package-from-tar-file (file-name)
+ "Parse the package tarball at FILE-NAME.
+
+Return a `epl-package' object with the meta data of the tarball
+package in FILE-NAME."
+ (condition-case nil
+ ;; In legacy package.el, `package-tar-file-info' takes the name of the tar
+ ;; file to parse as argument. In modern package.el, it has no arguments
+ ;; and works on the current buffer. Hence, we just try to call the legacy
+ ;; version, and if that fails because of a mismatch between formal and
+ ;; actual arguments, we use the modern approach. To avoid spurious
+ ;; signature warnings by the byte compiler, we suppress warnings when
+ ;; calling the function.
+ (epl-package--parse-info (with-no-warnings
+ (package-tar-file-info file-name)))
+ (wrong-number-of-arguments
+ (with-temp-buffer
+ (insert-file-contents-literally file-name)
+ ;; Switch to `tar-mode' to enable extraction of the file. Modern
+ ;; `package-tar-file-info' relies on `tar-mode', and signals an error if
+ ;; called in a buffer with a different mode.
+ (tar-mode)
+ (epl-package--parse-info (with-no-warnings
+ (package-tar-file-info)))))))
+
+(defun epl-package-from-file (file-name)
+ "Parse the package at FILE-NAME.
+
+Return an `epl-package' object with the meta data of the package
+at FILE-NAME."
+ (if (string-match-p (rx ".tar" string-end) file-name)
+ (epl-package-from-tar-file file-name)
+ (epl-package-from-lisp-file file-name)))
+
+(defun epl-package--parse-descriptor-requirement (requirement)
+ "Parse a REQUIREMENT in a package descriptor."
+ ;; This function is only called on legacy package.el. On package-desc
+ ;; package.el, we just let package.el do the work.
+ (cl-destructuring-bind (name version-string) requirement
+ (list name (version-to-list version-string))))
+
+(defun epl-package-from-descriptor-file (descriptor-file)
+ "Load a `epl-package' from a package DESCRIPTOR-FILE.
+
+A package descriptor is a file defining a new package. Its name
+typically ends with -pkg.el."
+ (with-temp-buffer
+ (insert-file-contents descriptor-file)
+ (goto-char (point-min))
+ (let ((sexp (read (current-buffer))))
+ (unless (eq (car sexp) 'define-package)
+ (error "%S is no valid package descriptor" descriptor-file))
+ (if (and (fboundp 'package-desc-from-define)
+ (fboundp 'package-desc-name))
+ ;; In Emacs snapshot, we can conveniently call a function to parse the
+ ;; descriptor
+ (let ((desc (apply #'package-desc-from-define (cdr sexp))))
+ (epl-package-create :name (package-desc-name desc)
+ :description desc))
+ ;; In legacy package.el, we must manually deconstruct the descriptor,
+ ;; because the load function has eval's the descriptor and has a lot of
+ ;; global side-effects.
+ (cl-destructuring-bind
+ (name version-string summary requirements) (cdr sexp)
+ (epl-package-create
+ :name (intern name)
+ :description
+ (vector (version-to-list version-string)
+ (mapcar #'epl-package--parse-descriptor-requirement
+ ;; Strip the leading `quote' from the package list
+ (cadr requirements))
+ summary)))))))
+
+
+;;; Package database access
+(defun epl-package-installed-p (package)
+ "Determine whether a PACKAGE is installed.
+
+PACKAGE is either a package name as symbol, or a package object."
+ (let ((name (if (epl-package-p package)
+ (epl-package-name package)
+ package))
+ (version (when (epl-package-p package)
+ (epl-package-version package))))
+ (package-installed-p name version)))
+
+(defun epl--parse-built-in-entry (entry)
+ "Parse an ENTRY from the list of built-in packages.
+
+Return the corresponding `epl-package' object."
+ (if (fboundp 'package--from-builtin)
+ ;; In package-desc package.el, convert the built-in package to a
+ ;; `package-desc' and convert that to an `epl-package'
+ (epl-package--from-package-desc (package--from-builtin entry))
+ (epl-package-create :name (car entry) :description (cdr entry))))
+
+(defun epl-built-in-packages ()
+ "Get all built-in packages.
+
+Return a list of `epl-package' objects."
+ ;; This looks mighty strange, but it's the only way to force package.el to
+ ;; build the list of built-in packages. Without this, `package--builtins'
+ ;; might be empty.
+ (package-built-in-p 'foo)
+ (mapcar #'epl--parse-built-in-entry package--builtins))
+
+(defun epl-find-built-in-package (name)
+ "Find a built-in package with NAME.
+
+NAME is a package name, as symbol.
+
+Return the built-in package as `epl-package' object, or nil if
+there is no built-in package with NAME."
+ (when (package-built-in-p name)
+ ;; We must call `package-built-in-p' *before* inspecting
+ ;; `package--builtins', because otherwise `package--builtins' might be
+ ;; empty.
+ (epl--parse-built-in-entry (assq name package--builtins))))
+
+(defun epl-package-outdated-p (package)
+ "Determine whether a PACKAGE is outdated.
+
+A package is outdated, if there is an available package with a
+higher version.
+
+PACKAGE is either a package name as symbol, or a package object.
+In the former case, test the installed or built-in package with
+the highest version number, in the later case, test the package
+object itself.
+
+Return t, if the package is outdated, or nil otherwise."
+ (let* ((package (if (epl-package-p package)
+ package
+ (or (car (epl-find-installed-packages package))
+ (epl-find-built-in-package package))))
+ (available (car (epl-find-available-packages
+ (epl-package-name package)))))
+ (and package available (version-list-< (epl-package-version package)
+ (epl-package-version available)))))
+
+(defun epl--parse-package-list-entry (entry)
+ "Parse a list of packages from ENTRY.
+
+ENTRY is a single entry in a package list, e.g. `package-alist',
+`package-archive-contents', etc. Typically it is a cons cell,
+but the exact format varies between package.el versions. This
+function tries to parse all known variants.
+
+Return a list of `epl-package' objects parsed from ENTRY."
+ (let ((descriptions (cdr entry)))
+ (cond
+ ((listp descriptions)
+ (sort (mapcar #'epl-package--from-package-desc descriptions)
+ #'epl-package-->=))
+ ;; Legacy package.el has just a single package in an entry, which is a
+ ;; standard description vector
+ ((vectorp descriptions)
+ (list (epl-package-create :name (car entry)
+ :description descriptions)))
+ (:else (error "Cannot parse entry %S" entry)))))
+
+(defun epl-installed-packages ()
+ "Get all installed packages.
+
+Return a list of package objects."
+ (apply #'append (mapcar #'epl--parse-package-list-entry package-alist)))
+
+(defsubst epl--filter-outdated-packages (packages)
+ "Filter outdated packages from PACKAGES."
+ (let (res)
+ (dolist (package packages)
+ (when (epl-package-outdated-p package)
+ (push package res)))
+ (nreverse res)))
+
+(defun epl-outdated-packages ()
+ "Get all outdated packages, as in `epl-package-outdated-p'.
+
+Return a list of package objects."
+ (epl--filter-outdated-packages (epl-installed-packages)))
+
+(defsubst epl--find-package-in-list (name list)
+ "Find a package by NAME in a package LIST.
+
+Return a list of corresponding `epl-package' objects."
+ (let ((entry (assq name list)))
+ (when entry
+ (epl--parse-package-list-entry entry))))
+
+(defun epl-find-installed-package (name)
+ "Find the latest installed package by NAME.
+
+NAME is a package name, as symbol.
+
+Return the installed package with the highest version number as
+`epl-package' object, or nil, if no package with NAME is
+installed."
+ (car (epl-find-installed-packages name)))
+(make-obsolete 'epl-find-installed-package 'epl-find-installed-packages "0.7")
+
+(defun epl-find-installed-packages (name)
+ "Find all installed packages by NAME.
+
+NAME is a package name, as symbol.
+
+Return a list of all installed packages with NAME, sorted by
+version number in descending order. Return nil, if there are no
+packages with NAME."
+ (epl--find-package-in-list name package-alist))
+
+(defun epl-available-packages ()
+ "Get all packages available for installation.
+
+Return a list of package objects."
+ (apply #'append (mapcar #'epl--parse-package-list-entry
+ package-archive-contents)))
+
+(defun epl-find-available-packages (name)
+ "Find available packages for NAME.
+
+NAME is a package name, as symbol.
+
+Return a list of available packages for NAME, sorted by version
+number in descending order. Return nil, if there are no packages
+for NAME."
+ (epl--find-package-in-list name package-archive-contents))
+
+(cl-defstruct (epl-upgrade
+ (:constructor epl-upgrade-create))
+ "Structure describing an upgradable package.
+Slots:
+
+`installed' The installed package
+
+`available' The package available for installation."
+ installed
+ available)
+
+(defun epl-find-upgrades (&optional packages)
+ "Find all upgradable PACKAGES.
+
+PACKAGES is a list of package objects to upgrade, defaulting to
+all installed packages.
+
+Return a list of `epl-upgrade' objects describing all upgradable
+packages."
+ (let ((packages (or packages (epl-installed-packages)))
+ upgrades)
+ (dolist (pkg packages)
+ (let* ((version (epl-package-version pkg))
+ (name (epl-package-name pkg))
+ ;; Find the latest available package for NAME
+ (available-pkg (car (epl-find-available-packages name)))
+ (available-version (when available-pkg
+ (epl-package-version available-pkg))))
+ (when (and available-version (version-list-< version available-version))
+ (push (epl-upgrade-create :installed pkg
+ :available available-pkg)
+ upgrades))))
+ (nreverse upgrades)))
+
+(defalias 'epl-built-in-p 'package-built-in-p)
+
+
+;;; Package operations
+
+(defalias 'epl-install-file 'package-install-file)
+
+(defun epl-package-install (package &optional force)
+ "Install a PACKAGE.
+
+PACKAGE is a `epl-package' object. If FORCE is given and
+non-nil, install PACKAGE, even if it is already installed."
+ (when (or force (not (epl-package-installed-p package)))
+ (if (epl-package--package-desc-p package)
+ (package-install (epl-package-description package))
+ ;; The legacy API installs by name. We have no control over versioning,
+ ;; etc.
+ (package-install (epl-package-name package)))))
+
+(defun epl-package-delete (package)
+ "Delete a PACKAGE.
+
+PACKAGE is a `epl-package' object to delete."
+ ;; package-delete allows for packages being trashed instead of fully deleted.
+ ;; Let's prevent his silly behavior
+ (let ((delete-by-moving-to-trash nil))
+ ;; The byte compiler will warn us that we are calling `package-delete' with
+ ;; the wrong number of arguments, since it can't infer that we guarantee to
+ ;; always call the correct version. Thus we suppress all warnings when
+ ;; calling `package-delete'. I wish there was a more granular way to
+ ;; disable just that specific warning, but it is what it is.
+ (if (epl-package--package-desc-p package)
+ (with-no-warnings
+ (package-delete (epl-package-description package)))
+ ;; The legacy API deletes by name (as string!) and version instead by
+ ;; descriptor. Hence `package-delete' takes two arguments. For some
+ ;; insane reason, the arguments are strings here!
+ (let ((name (symbol-name (epl-package-name package)))
+ (version (epl-package-version-string package)))
+ (with-no-warnings
+ (package-delete name version))
+ ;; Legacy package.el does not remove the deleted package
+ ;; from the `package-alist', so we do it manually here.
+ (let ((pkg (assq (epl-package-name package) package-alist)))
+ (when pkg
+ (setq package-alist (delq pkg package-alist))))))))
+
+(defun epl-upgrade (&optional packages preserve-obsolete)
+ "Upgrade PACKAGES.
+
+PACKAGES is a list of package objects to upgrade, defaulting to
+all installed packages.
+
+The old versions of the updated packages are deleted, unless
+PRESERVE-OBSOLETE is non-nil.
+
+Return a list of all performed upgrades, as a list of
+`epl-upgrade' objects."
+ (let ((upgrades (epl-find-upgrades packages)))
+ (dolist (upgrade upgrades)
+ (epl-package-install (epl-upgrade-available upgrade) 'force)
+ (unless preserve-obsolete
+ (epl-package-delete (epl-upgrade-installed upgrade))))
+ upgrades))
+
+(provide 'epl)
+
+;;; epl.el ends here
.emacs.d/elpa/epl-20150517.433/epl.elc
Binary file
.emacs.d/elpa/general-20170708.104/elpa.el
@@ -0,0 +1,4 @@
+(setq package-user-dir
+ (expand-file-name (format ".cask/%s/elpa" emacs-version)))
+(package-initialize)
+(add-to-list 'load-path default-directory)
.emacs.d/elpa/general-20170708.104/elpa.elc
Binary file
.emacs.d/elpa/general-20170708.104/general-autoloads.el
@@ -0,0 +1,171 @@
+;;; general-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
+
+;;;### (autoloads nil "general" "general.el" (22977 30634 481071
+;;;;;; 188000))
+;;; Generated autoloads from general.el
+
+(autoload 'general-define-key "general" "\
+The primary key definition function provided by general.
+
+PREFIX corresponds to a prefix key and defaults to none. STATES corresponds to
+the evil state(s) to bind the keys in. Non-evil users should not set STATES.
+When STATES is non-nil, `evil-define-key' will be used. Otherwise `define-key'
+will be used. Evil users may also want to leave STATES nil and set KEYMAPS to
+a keymap such as `evil-normal-state-map' for global mappings. KEYMAPS defaults
+to `global-map'. Note that STATES and KEYMAPS can either be a list or a single
+symbol. If any keymap does not exist, the keybindings will be deferred until
+the keymap does exist, so using `eval-after-load' is not necessary with this
+function.
+
+If NON-NORMAL-PREFIX is specified, this prefix will be used for emacs and insert
+state keybindings instead of PREFIX. This argument will only have an effect if
+'insert and/or 'emacs is one of the STATES or if 'evil-insert-state-map and/or
+'evil-emacs-state-map is one of the KEYMAPS. Alternatively, GLOBAL-PREFIX can be
+used with PREFIX and/or NON-NORMAL-PREFIX to bind keys in all states under a
+specified prefix. Like with NON-NORMAL-PREFIX, GLOBAL-PREFIX will prevent PREFIX
+from applying to insert and emacs states. Note that these keywords are only
+useful for evil users.
+
+INFIX can be used to append a string to all of the specified prefixes. This is
+potentially useful when you are using GLOBAL-PREFIX and/or NON-NORMAL-PREFIX so
+that you can sandwich keys in between all the prefixes and the specified keys in
+MAPS. This may be particularly useful if you are using default prefixes in a
+wrapper so that you can add to them without needing to re-specify all of them.
+If none of the other prefix arguments are specified, INFIX will have no effect.
+
+If PREFIX-COMMAND is specified, a prefix keymap/command will be created using
+`define-prefix-command' as long as the symbol specified is not already bound (to
+ensure that an existing prefix keymap is not overwritten if the
+`general-define-key' function is re-evaluated). All prefixes will then be bound
+to PREFIX-COMMAND. PREFIX-MAP and PREFIX-NAME can additionally be specified and
+are used as the last two arguments to `define-prefix-command'.
+
+Unlike with normal key definitions functions, the keymaps in KEYMAPS should be
+quoted (this makes it easy to check if there is only one keymap instead of a
+list of keymaps).
+
+MAPS will be recorded for later use with `general-describe-keybindings'.
+
+\(fn &rest MAPS &key (PREFIX general-default-prefix) (NON-NORMAL-PREFIX general-default-non-normal-prefix) (GLOBAL-PREFIX general-default-global-prefix) INFIX PREFIX-COMMAND PREFIX-MAP PREFIX-NAME (STATES general-default-states) (KEYMAPS general-default-keymaps) PREDICATE PACKAGE MAJOR-MODE &allow-other-keys)" nil nil)
+
+(autoload 'general-create-definer "general" "\
+A helper macro to create key definitions functions.
+This allows the creation of key definition functions that
+will use a certain keymap, evil state, and/or prefix key by default.
+NAME will be the function name and ARGS are the keyword arguments that
+are intended to be the defaults.
+
+\(fn NAME &rest ARGS)" nil t)
+
+(autoload 'general-emacs-define-key "general" "\
+A wrapper for `general-define-key' that is similar to `define-key'.
+It has a positional argument for KEYMAPS. It acts the same as
+`general-define-key', and ARGS can contain keyword arguments in addition to
+keybindings. This can basically act as a drop-in replacement for `define-key',
+and unlike with `general-define-key', if KEYMAPS is a single keymap, it does
+not need to be quoted.
+
+\(fn KEYMAPS &rest ARGS)" nil t)
+
+(function-put 'general-emacs-define-key 'lisp-indent-function '1)
+
+(autoload 'general-evil-define-key "general" "\
+A wrapper for `general-define-key' that is similar to `evil-define-key'.
+It has positional arguments for STATES and KEYMAPS. It acts the same as
+`general-define-key', and ARGS can contain keyword arguments in addition to
+keybindings. This can basically act as a drop-in replacement for
+`evil-define-key', and unlike with `general-define-key', if KEYMAPS is a single
+keymap, it does not need to be quoted.
+
+\(fn STATES KEYMAPS &rest ARGS)" nil t)
+
+(function-put 'general-evil-define-key 'lisp-indent-function '2)
+
+(autoload 'general-describe-keybindings "general" "\
+Show all keys that have been bound with general in an org buffer.
+Any local keybindings will be shown first followed by global keybindings.
+
+\(fn)" t nil)
+
+(autoload 'general-simulate-keys "general" "\
+Create a function to simulate KEYS.
+If EMACS-STATE is non-nil, execute the keys in emacs state. Otherwise simulate
+the keys in the current context (will work without evil). KEYS should be a
+string given in `kbd' notation. It an also be a list of a single command
+followed by a string of the keys to simulate after calling that command. If
+DOCSTRING is given, it will replace the automatically generated docstring. If
+NAME is given, it will replace the automatically generated function name. NAME
+should not be quoted.
+
+\(fn KEYS &optional EMACS-STATE DOCSTRING NAME)" nil t)
+
+(autoload 'general-key-dispatch "general" "\
+Create a function that will run FALLBACK-COMMAND or a command from MAPS.
+MAPS consists of <key> <command> pairs. If a key in MAPS is matched, the
+corresponding command will be run. Otherwise FALLBACK-COMMAND will be run with
+the unmatched keys. So, for example, if \"ab\" was pressed, and \"ab\" is not
+one of the key sequences from MAPS, the FALLBACK-COMMAND will be run followed by
+the simulated keypresses of \"ab\". Prefix arguments will still work regardless
+of which command is run. This is useful for binding under non-prefix keys. For
+example, this can be used to redefine a sequence like \"cw\" or \"cow\" in evil
+but still have \"c\" work as `evil-change'. If TIMEOUT is specified,
+FALLBACK-COMMAND will also be run in the case that the user does not press the
+next key within the TIMEOUT (e.g. 0.5).
+
+NAME and DOCSTRING are optional keyword arguments. They can be used to replace
+the automatically generated name and docstring for the created function and are
+potentially useful if you want to create multiple, different commands using the
+same FALLBACK-COMMAND (e.g. `self-insert-command').
+
+When INHERIT-KEYMAP is specified, all the keybindings from that keymap will be
+inherited in MAPS.
+
+WHICH-KEY can also be specified, in which case the description WHICH-KEY will
+replace the command name in the which-key popup. Note that this requires a
+version of which-key from after 2016-11-21.
+
+\(fn FALLBACK-COMMAND &rest MAPS &key TIMEOUT INHERIT-KEYMAP NAME DOCSTRING WHICH-KEY &allow-other-keys)" nil t)
+
+(function-put 'general-key-dispatch 'lisp-indent-function '1)
+
+(autoload 'general-create-vim-definer "general" "\
+A helper function to create vim-like wrappers over `general-define-key'.
+The function created will be called NAME and will have the keymaps default to
+KEYMAPS or the states default to STATES. If DEFAULT-TO-STATES is non-nil,
+:states STATES will be used. Otherwise :keymaps KEYMAPS will be used. This can
+be overriden later by setting the global `general-vim-definer-default'
+option.
+
+\(fn NAME KEYMAPS &optional STATES DEFAULT-TO-STATES)" nil t)
+
+(autoload 'general-create-dual-vim-definer "general" "\
+Like `general-create-vim-definer', create a \"vim definer\" called NAME.
+Only the short names in the STATES list need to be specified, but this will only
+work for valid evil states.
+
+\(fn NAME STATES &optional DEFAULT-TO-STATES)" nil t)
+
+(autoload 'general-evil-setup "general" "\
+Set up some basic equivalents for vim mapping functions.
+This creates global key definition functions for the evil states.
+Specifying SHORT-NAMES as non-nil will create non-prefixed function
+aliases such as `nmap' for `general-nmap'.
+
+\(fn &optional SHORT-NAMES DEFAULT-TO-STATES)" nil t)
+
+;;;***
+
+;;;### (autoloads nil nil ("elpa.el" "general-pkg.el") (22977 30634
+;;;;;; 483071 174000))
+
+;;;***
+
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+;;; general-autoloads.el ends here
.emacs.d/elpa/general-20170708.104/general-pkg.el
@@ -0,0 +1,7 @@
+(define-package "general" "20170708.104" "Convenience wrappers for keybindings."
+ '((cl-lib "0.5"))
+ :url "https://github.com/noctuid/general.el" :keywords
+ '("vim" "evil" "leader" "keybindings" "keys"))
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
.emacs.d/elpa/general-20170708.104/general.el
@@ -0,0 +1,1088 @@
+;;; general.el --- Convenience wrappers for keybindings.
+
+;; Author: Fox Kiester <noct@openmailbox.org>
+;; URL: https://github.com/noctuid/general.el
+;; Created: February 17, 2016
+;; Keywords: vim, evil, leader, keybindings, keys
+;; Package-Requires: ((cl-lib "0.5"))
+;; Version: 0.1
+
+;; This file is not part of GNU Emacs.
+
+;; 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 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;; This package provides convenient wrappers for more succinctly defining
+;; keybindings. It allows defining multiple keys at once, specifying an
+;; arbitrary number of named prefix keys to be used in key definitions,
+;; implicitly wrapping key strings with (kbd ...), and more. It provides a
+;; single function for standard emacs key definitions as well as evil key
+;; definitions for any evil state and any keymap. It also provides a setup
+;; function to generate "nmap", "vmap", etc. keybinding functions for evil.
+
+;; For more information see the README in the online repository.
+
+;;; Code:
+(require 'cl-lib)
+
+(defgroup general nil
+ "Gives convenient wrappers for key definitions."
+ :group 'convenience
+ :prefix 'general-)
+
+(defcustom general-implicit-kbd t
+ "Whether to implicitly wrap a (kbd) around keybindings.
+This applies to the prefix key as well."
+ :group 'general
+ :type 'boolean)
+
+(defcustom general-default-prefix nil
+ "The default prefix key sequence to use."
+ :group 'general
+ :type 'string)
+
+(defcustom general-default-non-normal-prefix nil
+ "The default prefix key sequence to use for the 'emacs and 'insert states.
+Note that this setting is only useful for evil-users and will only have an
+effect when binding keys in the 'emacs and/or 'insert states or in the
+'evil-insert-state-map and/or 'evil-emacs-state-map keymaps. When this is not
+specified, `general-default-prefix' will be the default prefix for any states
+and keymaps. If this is specified `general-default-prefix' or the arg to :prefix
+will not be used when binding keys in the insert and emacs states."
+ :group 'general
+ :type 'string)
+
+(defcustom general-default-global-prefix nil
+ "The default prefix key sequence to use for all evil states.
+This setting is only useful for evil users. Note that like with
+`general-default-non-normal-prefix', if this or :global-prefix is specified,
+`general-default-prefix' or the arg to :prefix will not be used for binding
+keys in the insert and emacs states. If you don't need a different or extra
+prefix for one or both state types (insert and emacs vs. the other states),
+just use `general-default-prefix'/:prefix by itself."
+ :group 'general
+ :type 'string)
+
+(define-widget 'general-state 'lazy
+ "General's evil state type."
+ :type '(choice
+ (const :tag "Normal state" normal)
+ (const :tag "Insert state" insert)
+ (const :tag "Visual state" visual)
+ (const :tag "Replace state" replace)
+ (const :tag "Operator state" operator)
+ (const :tag "Motion state" motion)
+ (const :tag "Emacs state" emacs)
+ (const :tag "Use define-key not evil-define-key" nil)))
+
+(defcustom general-default-states nil
+ "The default evil state(s) to make mappings in.
+Non-evil users should keep this nil."
+ :group 'general
+ :type '(choice general-state
+ (set general-state)))
+
+(define-widget 'general-keymap 'lazy
+ "General's keymap type."
+ :type '(choice
+ (const :tag "Global keymap" global)
+ (const :tag "Buffer local keymap" local)
+ symbol))
+
+(defcustom general-default-keymaps 'global
+ "The default keymap(s) to bind keys in."
+ :group 'general
+ :type '(choice general-keymap
+ (repeat general-keymap)))
+
+(defcustom general-vim-definer-default nil
+ "Whether set the states or keymaps in a `general-create-vim-definer' function.
+If nil, use the default from when the function was created. If 'keymaps, set the
+default keymaps. If 'states, set the default states."
+ :group 'general
+ :type '(choice
+ (const :tag "Default to setting :keymaps" keymaps)
+ (const :tag "Default to setting :states" states)
+ (const :tag "Use the initial default" nil)))
+
+(defvar general-keybindings nil
+ "Holds all the keybindings created with `general-define-key' (and wrappers).
+This is an alist of a keymap to an alist of a state to keybindings.")
+
+(defvar general-local-keybindings nil
+ "Holds all the local keybindings created with `general-define-key'.
+This is an alist of a state to keybindings.")
+(make-variable-buffer-local 'general-local-keybindings)
+
+;;; Helpers
+(defun general--concat (nokbd &rest keys)
+ "Concatenate the strings in KEYS.
+If `general-implicit-kbd' is non-nil, interleave the strings in KEYS with
+spaces; unless NOKBD is non-nil, apply (kbd ...) to the result. If
+`general-implicit-kbd' is nil, just concatenate the keys."
+ (setq keys (remove nil keys))
+ (if general-implicit-kbd
+ (let ((keys (mapconcat #'identity keys " ")))
+ (if nokbd
+ keys
+ (kbd keys)))
+ (apply #'concat keys)))
+
+(defun general--apply-prefix-and-kbd (prefix maps)
+ "Prepend the PREFIX sequence to all the keys that are strings in MAPS.
+Also apply (kbd ...) to key and definition strings if `general-implicit-kbd' is
+non-nil."
+ (setq prefix (or prefix ""))
+ (cl-loop for (key def) on maps by 'cddr
+ collect (if (stringp key)
+ (general--concat nil prefix key)
+ ;; don't touch vectors
+ key)
+ and collect def))
+
+;; http://endlessparentheses.com/define-context-aware-keys-in-emacs.html
+(defun general--maybe-apply-predicate (predicate def)
+ "Apply PREDICATE to DEF.
+If PREDICATE is nil just return DEF."
+ (if predicate
+ `(menu-item
+ "" nil
+ :filter (lambda (&optional _)
+ (when ,predicate
+ ',def)))
+ def))
+
+(defun general--remove-keys (maps keys)
+ "Return a list of MAPS with the mappings for KEYS removed."
+ (cl-loop for (key def) on maps by 'cddr
+ unless (member key keys)
+ collect key
+ and collect def))
+
+(defun general--record-keybindings (keymap state maps)
+ "For KEYMAP and STATE, add MAPS to `general-keybindings'.
+If KEYMAP is \"local\", add MAPS to `general-local-keybindings.' For non-evil
+keybindings, STATE will be nil. Duplicate keys will be replaced with the new
+ones."
+ (let ((keys (cl-loop for (key def) on maps by 'cddr
+ collect key)))
+ (cond ((eq keymap 'local)
+ (unless (assq state general-local-keybindings)
+ (add-to-list 'general-local-keybindings (list state)))
+ (let ((state-cons (assq state general-local-keybindings)))
+ (setcdr state-cons
+ (append
+ ;; remove old duplicate keys
+ (general--remove-keys (cdr state-cons) keys)
+ maps))))
+ (t
+ (unless (assq keymap general-keybindings)
+ (add-to-list 'general-keybindings (list keymap)))
+ (unless (assq state (assq keymap general-keybindings))
+ (setcdr (assq keymap general-keybindings)
+ (append (cdr (assq keymap general-keybindings))
+ (list (list state)))))
+ (let ((state-cons (assq state (assq keymap general-keybindings))))
+ (setcdr state-cons
+ (append (general--remove-keys (cdr state-cons) keys)
+ maps)))))))
+
+;; don't force non-evil user to require evil for one function (this is evil-delay)
+(defun general--delay (condition form hook &optional append local name)
+ "Execute FORM when CONDITION becomes true, checking with HOOK.
+NAME specifies the name of the entry added to HOOK. If APPEND is
+non-nil, the entry is appended to the hook. If LOCAL is non-nil,
+the buffer-local value of HOOK is modified."
+ (declare (indent 2))
+ (if (and (not (booleanp condition)) (eval condition))
+ (eval form)
+ (let* ((name (or name (format "general-delay-form-in-%s" hook)))
+ (fun (make-symbol name))
+ (condition (or condition t)))
+ (fset fun `(lambda (&rest args)
+ (when ,condition
+ (remove-hook ',hook #',fun ',local)
+ ,form)))
+ (put fun 'permanent-local-hook t)
+ (add-hook hook fun append local))))
+
+(defun general--evil-keymap-for-state (state &optional text-object)
+ "Return a symbol corresponding to the global evil keymap for STATE.
+If TEXT-OBJECT is non-nil, STATE should be 'inner or 'outer and a symbol for the
+corresponding global evil text object keymap will be returned."
+ (intern (concat "evil-" (symbol-name state)
+ (if text-object
+ "-text-objects-map"
+ "-state-map"))))
+
+;;; Extended Key Definition Language
+(defvar general-extended-def-keywords '(:which-key)
+ "Extra keywords that are valid in an extended definition.")
+
+(defun general-extended-def-:which-key (_state _keymap key def kargs)
+ "Add a which-key description for KEY.
+If :major-mode is specified in DEF, add the description for that major mode. KEY
+should not be in the kbd format (kbd should have already been run on it)."
+ (eval-after-load 'which-key
+ `(let ((doc (cl-getf ',def :which-key))
+ (major-mode (or (cl-getf ',def :major-mode)
+ (cl-getf ',kargs :major-mode)))
+ (key (key-description ',key)))
+ (if major-mode
+ (which-key-add-major-mode-key-based-replacements major-mode
+ key doc)
+ (which-key-add-key-based-replacements key doc)))))
+
+(defun general--maybe-autoload-keymap (state keymap def kargs)
+ "Return either a keymap or a function that serves as an \"autoloaded\" keymap.
+A created function will bind the keys it was invoked with in STATE and KEYMAP to
+the keymap specified in DEF with :keymap and then act as if it was originally
+bound to that keymap (subsequent keys will be looked up in the keymap). KARGS or
+DEF should contain the package in which the keymap is created (as specified
+with :package). If the keymap already exists, it will simply be returned."
+ (let ((bind-to-keymap (cl-getf def :keymap))
+ (package (or (cl-getf def :package)
+ (cl-getf kargs :package))))
+ (if (boundp bind-to-keymap)
+ (symbol-value bind-to-keymap)
+ (unless package
+ (error "In order to \"autoload\" a keymap, :package must be specified"))
+ `(lambda ()
+ (interactive)
+ (unless (or (featurep ',package)
+ (require ',package nil t))
+ (error (concat "Failed to load package: " (symbol-name ',package))))
+ (unless (and (boundp ',bind-to-keymap)
+ (keymapp (symbol-value ',bind-to-keymap)))
+ (error (format "A keymap called %s is not defined in the %s package"
+ ',bind-to-keymap ',package)))
+ (let ((keys (this-command-keys))
+ (general-implicit-kbd nil))
+ (general-define-key :states ',state
+ :keymaps ',keymap
+ keys ,bind-to-keymap)
+ (setq prefix-arg current-prefix-arg
+ unread-command-events
+ (mapcar (lambda (ev) (cons t ev))
+ (listify-key-sequence keys))))))))
+
+(defun general--parse-def (state keymap key def kargs)
+ "Rewrite DEF into a valid definition.
+This function will execute the actions specified in an extended definition and
+apply a predicate if there is one."
+ (cond ((and (listp def)
+ (not (keymapp def))
+ ;; lambda
+ (not (functionp def))
+ (not (eq (car def) 'menu-item)))
+ (unless (keywordp (car def))
+ (setq def (cons :command def)))
+ (dolist (keyword general-extended-def-keywords)
+ (when (cl-getf def keyword)
+ (funcall (intern (concat "general-extended-def-"
+ (symbol-name keyword)))
+ state keymap key def kargs)))
+ (cond ((cl-getf def :ignore)
+ ;; just for side effects (e.g. which-key description for prefix)
+ ;; return something that isn't a valid definition
+ :ignore)
+ ((cl-getf def :keymap)
+ ;; bind or autoload
+ (general--maybe-autoload-keymap state keymap def kargs))
+ (t
+ (general--maybe-apply-predicate (or (cl-getf def :predicate)
+ (cl-getf kargs :predicate))
+ (cl-getf def :command)))))
+ (t
+ ;; not and extended definition
+ (general--maybe-apply-predicate (cl-getf kargs :predicate) def))))
+
+(defun general--parse-maps (state keymap maps kargs)
+ "Rewrite MAPS so that the definitions are bindable.
+This includes possibly parsing extended definitions or applying a prefix."
+ (cl-loop for (key def) on maps by 'cddr
+ do (setq def (general--parse-def state keymap key def kargs))
+ unless (eq def :ignore)
+ collect key
+ and collect (if (and general-implicit-kbd
+ (stringp def))
+ (kbd def)
+ def)))
+
+;;; define-key and evil-define-key Wrappers
+;; TODO better way to do this?
+;; https://www.reddit.com/r/emacs/comments/1582uo/bufferlocalsetkey_set_a_key_in_one_buffer_only/
+(defvar general--blm nil)
+
+(defun general--generate-keymap-name (sym)
+ "Generate a map name from SYM."
+ (symbol-value (intern (concat (symbol-name sym) "-map"))))
+
+(defun general--emacs-local-set-key (key func)
+ "Bind KEY to FUNC for the current buffer only using a minor mode."
+ (if general--blm
+ (define-key (general--generate-keymap-name general--blm) key func)
+ (let* ((mode-name-loc (cl-gensym "general-blm")))
+ (eval `(define-minor-mode ,mode-name-loc nil nil nil (make-sparse-keymap)))
+ (setq-local general--blm mode-name-loc)
+ (funcall mode-name-loc 1)
+ (define-key (general--generate-keymap-name general--blm) key func))))
+
+;; this works but will make it so that keys defined for the major mode will no longer affect
+;; (use-local-map (copy-keymap (current-local-map)))
+;; (local-set-key (kbd "C-c y") 'helm-apropos)
+
+(defun general--emacs-define-key (keymap &rest maps)
+ "Wrapper for `define-key' and general's `general--emacs-local-set-key'.
+KEYMAP determines which keymap the MAPS will be defined in. When KEYMAP is
+is 'local, the MAPS will be bound only in the current buffer. MAPS is any
+number of paired keys and commands"
+ (declare (indent 1))
+ (while (not (cl-endp maps))
+ (if (eq keymap 'local)
+ (general--emacs-local-set-key (pop maps) (pop maps))
+ (define-key keymap (pop maps) (pop maps)))))
+
+(defun general--evil-define-key (state keymap &rest maps)
+ "A wrapper for `evil-define-key' and `evil-local-set-key'.
+STATE is the evil state to bind the keys in. `evil-local-set-key' is used when
+KEYMAP is 'local. MAPS is any number of keys and commands to bind."
+ (declare (indent defun))
+ (eval-after-load 'evil
+ `(let ((maps ',maps)
+ (keymap ',keymap)
+ (state ',state))
+ (while maps
+ (if (eq keymap 'local)
+ ;; has no &rest
+ (evil-local-set-key state (pop maps) (pop maps))
+ (evil-define-key* state keymap (pop maps) (pop maps)))))))
+
+(defun general--define-key
+ (states keymap maps non-normal-maps global-maps kargs)
+ "A helper function for `general-define-key'.
+Choose based on STATES and KEYMAP which of MAPS, NON-NORMAL-MAPS, and
+GLOBAL-MAPS to use for the keybindings. This function will rewrite extended
+definitions, add predicates when applicable, and then choose the base function
+to bind the keys with (depending on whether STATES is non-nil)."
+ (cl-macrolet ((defkeys (maps)
+ `(let ((maps (general--parse-maps state keymap ,maps kargs))
+ (keymap keymap))
+ (general--record-keybindings keymap state maps)
+ (setq keymap (cond ((eq keymap 'local)
+ 'local)
+ ((eq keymap 'global)
+ (current-global-map))
+ (t
+ (symbol-value keymap))))
+ (if state
+ (apply #'general--evil-define-key state keymap maps)
+ (apply #'general--emacs-define-key keymap maps))))
+ (def-pick-maps (non-normal-p)
+ `(progn
+ (cond ((and non-normal-maps ,non-normal-p)
+ (defkeys non-normal-maps))
+ ((and global-maps ,non-normal-p))
+ (t
+ (defkeys maps)))
+ (defkeys global-maps))))
+ (if states
+ (dolist (state states)
+ (def-pick-maps (memq state '(insert emacs))))
+ (let (state)
+ (def-pick-maps (memq keymap '(evil-insert-state-map
+ evil-emacs-state-map)))))))
+
+;;; Functions With Keyword Arguments
+;;;###autoload
+(cl-defun general-define-key
+ (&rest maps &key
+ (prefix general-default-prefix)
+ (non-normal-prefix general-default-non-normal-prefix)
+ (global-prefix general-default-global-prefix)
+ infix
+ prefix-command
+ prefix-map
+ prefix-name
+ (states general-default-states)
+ (keymaps general-default-keymaps)
+ predicate
+ ;; for extended definitions only
+ package
+ major-mode
+ &allow-other-keys)
+ "The primary key definition function provided by general.
+
+PREFIX corresponds to a prefix key and defaults to none. STATES corresponds to
+the evil state(s) to bind the keys in. Non-evil users should not set STATES.
+When STATES is non-nil, `evil-define-key' will be used. Otherwise `define-key'
+will be used. Evil users may also want to leave STATES nil and set KEYMAPS to
+a keymap such as `evil-normal-state-map' for global mappings. KEYMAPS defaults
+to `global-map'. Note that STATES and KEYMAPS can either be a list or a single
+symbol. If any keymap does not exist, the keybindings will be deferred until
+the keymap does exist, so using `eval-after-load' is not necessary with this
+function.
+
+If NON-NORMAL-PREFIX is specified, this prefix will be used for emacs and insert
+state keybindings instead of PREFIX. This argument will only have an effect if
+'insert and/or 'emacs is one of the STATES or if 'evil-insert-state-map and/or
+'evil-emacs-state-map is one of the KEYMAPS. Alternatively, GLOBAL-PREFIX can be
+used with PREFIX and/or NON-NORMAL-PREFIX to bind keys in all states under a
+specified prefix. Like with NON-NORMAL-PREFIX, GLOBAL-PREFIX will prevent PREFIX
+from applying to insert and emacs states. Note that these keywords are only
+useful for evil users.
+
+INFIX can be used to append a string to all of the specified prefixes. This is
+potentially useful when you are using GLOBAL-PREFIX and/or NON-NORMAL-PREFIX so
+that you can sandwich keys in between all the prefixes and the specified keys in
+MAPS. This may be particularly useful if you are using default prefixes in a
+wrapper so that you can add to them without needing to re-specify all of them.
+If none of the other prefix arguments are specified, INFIX will have no effect.
+
+If PREFIX-COMMAND is specified, a prefix keymap/command will be created using
+`define-prefix-command' as long as the symbol specified is not already bound (to
+ensure that an existing prefix keymap is not overwritten if the
+`general-define-key' function is re-evaluated). All prefixes will then be bound
+to PREFIX-COMMAND. PREFIX-MAP and PREFIX-NAME can additionally be specified and
+are used as the last two arguments to `define-prefix-command'.
+
+Unlike with normal key definitions functions, the keymaps in KEYMAPS should be
+quoted (this makes it easy to check if there is only one keymap instead of a
+list of keymaps).
+
+MAPS will be recorded for later use with `general-describe-keybindings'."
+ (let (non-normal-prefix-maps
+ global-prefix-maps
+ kargs)
+ ;; remove keyword arguments from rest var
+ (setq maps
+ (cl-loop for (key value) on maps by 'cddr
+ if (keywordp key)
+ do (progn (push key kargs)
+ (push value kargs))
+ else
+ collect key
+ and collect value))
+ ;; order matters for duplicates
+ (setq kargs (nreverse kargs))
+ ;; don't force the user to wrap a single state or keymap in a list
+ ;; luckily nil is a list
+ (unless (listp states)
+ (setq states (list states)))
+ (unless (listp keymaps)
+ (setq keymaps (list keymaps)))
+ (when (and prefix-command
+ (not (boundp prefix-command)))
+ (define-prefix-command prefix-command prefix-map prefix-name))
+ ;; TODO reduce code reduction here
+ (when non-normal-prefix
+ (setq non-normal-prefix-maps
+ (general--apply-prefix-and-kbd
+ (general--concat t non-normal-prefix infix) maps))
+ (when prefix-command
+ (push prefix-command non-normal-prefix-maps)
+ (push (if general-implicit-kbd
+ (kbd non-normal-prefix)
+ non-normal-prefix)
+ non-normal-prefix-maps)))
+ (when global-prefix
+ (setq global-prefix-maps
+ (general--apply-prefix-and-kbd
+ (general--concat t global-prefix infix) maps))
+ (when prefix-command
+ (push prefix-command global-prefix-maps)
+ (push (if general-implicit-kbd
+ (kbd global-prefix)
+ global-prefix)
+ global-prefix-maps)))
+ ;; last so not applying prefix twice
+ (setq maps (general--apply-prefix-and-kbd
+ (general--concat t prefix infix) maps))
+ (when prefix-command
+ (push prefix-command maps)
+ (push (if general-implicit-kbd
+ (kbd prefix)
+ prefix)
+ maps))
+ (dolist (keymap keymaps)
+ (when (memq keymap '(insert emacs normal visual operator motion replace))
+ (setq keymap (general--evil-keymap-for-state keymap)))
+ (when (memq keymap '(inner outer))
+ (setq keymap (general--evil-keymap-for-state keymap t)))
+ (general--delay `(or (memq ',keymap '(local global))
+ (and (boundp ',keymap)
+ (keymapp ,keymap)))
+ `(general--define-key ',states
+ ',keymap
+ ',maps
+ ',non-normal-prefix-maps
+ ',global-prefix-maps
+ ',kargs)
+ 'after-load-functions t nil
+ (format "general-define-key-in-%s" keymap)))))
+
+;;;###autoload
+(defmacro general-create-definer (name &rest args)
+ "A helper macro to create key definitions functions.
+This allows the creation of key definition functions that
+will use a certain keymap, evil state, and/or prefix key by default.
+NAME will be the function name and ARGS are the keyword arguments that
+are intended to be the defaults."
+ `(defun ,name (&rest args)
+ ;; can still override keywords afterwards
+ (apply #'general-define-key (append args (list ,@args)))))
+
+;;;###autoload
+(defmacro general-emacs-define-key (keymaps &rest args)
+ "A wrapper for `general-define-key' that is similar to `define-key'.
+It has a positional argument for KEYMAPS. It acts the same as
+`general-define-key', and ARGS can contain keyword arguments in addition to
+keybindings. This can basically act as a drop-in replacement for `define-key',
+and unlike with `general-define-key', if KEYMAPS is a single keymap, it does
+not need to be quoted."
+ (declare (indent 1))
+ `(general-define-key ,@args
+ :keymaps (if (symbolp ',keymaps)
+ ',keymaps
+ ,keymaps)))
+
+;;;###autoload
+(defmacro general-evil-define-key (states keymaps &rest args)
+ "A wrapper for `general-define-key' that is similar to `evil-define-key'.
+It has positional arguments for STATES and KEYMAPS. It acts the same as
+`general-define-key', and ARGS can contain keyword arguments in addition to
+keybindings. This can basically act as a drop-in replacement for
+`evil-define-key', and unlike with `general-define-key', if KEYMAPS is a single
+keymap, it does not need to be quoted."
+ (declare (indent 2))
+ `(general-define-key ,@args
+ :states ,states
+ :keymaps (if (symbolp ',keymaps)
+ ',keymaps
+ ,keymaps)))
+;;; Displaying Keybindings
+(defun general--print-keybind-table (maps)
+ "Print an org table for MAPS."
+ (princ "|key|command|\n|-+-|\n")
+ (cl-loop for (key command) on maps by 'cddr
+ do (princ (format "|=%s=|~%s~|\n" (key-description key) command)))
+ (princ "\n"))
+
+(defun general--print-state-heading (state-cons)
+ "Print a table and possibly a heading for STATE-CONS."
+ (let ((state (car state-cons))
+ (maps (cdr state-cons)))
+ (unless (null state)
+ (princ (capitalize (concat "** " (symbol-name state) " State\n"))))
+ (general--print-keybind-table maps)))
+
+(defun general--print-keymap-heading (keymap-cons)
+ "Print headings and tables for KEYMAP-CONS."
+ (let ((keymap (car keymap-cons))
+ (state-conses (cdr keymap-cons)))
+ (princ (capitalize (concat "* " (symbol-name keymap) " Keybindings\n")))
+ (let ((no-evil-state-cons (assq nil state-conses)))
+ ;; non-evil keybindings go first
+ (when no-evil-state-cons
+ (general--print-state-heading no-evil-state-cons)
+ (setq state-conses (assq-delete-all nil state-conses)))
+ (dolist (state-cons state-conses)
+ (general--print-state-heading state-cons)))))
+
+;;;###autoload
+(defun general-describe-keybindings ()
+ "Show all keys that have been bound with general in an org buffer.
+Any local keybindings will be shown first followed by global keybindings."
+ (interactive)
+ (with-output-to-temp-buffer "*General Keybindings*"
+ (let* ((keybindings (copy-alist general-keybindings))
+ (global-keybinds (assq 'global keybindings))
+ (global-evil-keymaps
+ '(evil-insert-state-map
+ evil-emacs-state-map
+ evil-normal-state-map
+ evil-visual-state-map
+ evil-motion-state-map
+ evil-operators-state-map
+ evil-outer-text-objects-map
+ evil-inner-text-objects-map
+ evil-replace-state-map
+ evil-ex-search-keymap
+ evil-ex-completion-map
+ evil-command-window-mode-map
+ evil-window-map))
+ (global-evil-keybinds
+ (cl-loop for keymap-cons in keybindings
+ when (memq (car keymap-cons) global-evil-keymaps)
+ append (list keymap-cons)))
+ (local-keybindings (copy-alist general-local-keybindings)))
+ (when local-keybindings
+ (general--print-keymap-heading (cons 'local local-keybindings)))
+ (when global-keybinds
+ (general--print-keymap-heading global-keybinds)
+ (setq keybindings (assq-delete-all 'global keybindings)))
+ (when global-evil-keybinds
+ (dolist (keymap-cons global-evil-keybinds)
+ (general--print-keymap-heading keymap-cons)
+ (setq keybindings (assq-delete-all (car keymap-cons) keybindings))))
+ (dolist (keymap-cons keybindings)
+ (general--print-keymap-heading keymap-cons))))
+ (with-current-buffer "*General Keybindings*"
+ (let ((org-startup-folded 'showall))
+ (org-mode))
+ (read-only-mode -1)
+ (while (progn
+ (while (progn
+ (forward-line)
+ (org-at-heading-p)))
+ (org-table-align)
+ (outline-next-heading)))
+ (goto-char (point-min))
+ (read-only-mode)))
+
+;;; Functions/Macros to Aid Key Definition
+;; https://emacs.stackexchange.com/questions/6037/emacs-bind-key-to-prefix/13432#13432
+;; altered to allow execution in a emacs state
+;; and to create a named function with a docstring
+;; also properly handles more edge cases like correctly adding evil repeat info
+
+(defvar general--last-simulate nil)
+
+;;;###autoload
+(defmacro general-simulate-keys (keys &optional emacs-state docstring name)
+ "Create a function to simulate KEYS.
+If EMACS-STATE is non-nil, execute the keys in emacs state. Otherwise simulate
+the keys in the current context (will work without evil). KEYS should be a
+string given in `kbd' notation. It an also be a list of a single command
+followed by a string of the keys to simulate after calling that command. If
+DOCSTRING is given, it will replace the automatically generated docstring. If
+NAME is given, it will replace the automatically generated function name. NAME
+should not be quoted."
+ (let* ((command (when (listp keys)
+ (car keys)))
+ (keys (if (listp keys)
+ (cadr keys)
+ keys))
+ (name (or name
+ (intern (concat
+ (format "general-simulate-%s"
+ (if command
+ (eval command)
+ ""))
+ (when command
+ "-")
+ (replace-regexp-in-string " " "_" keys)
+ (when emacs-state
+ "-in-emacs-state"))))))
+ `(progn
+ (eval-after-load 'evil
+ '(evil-set-command-property #',name :repeat 'general--simulate-repeat))
+ (defun ,name
+ ()
+ ,(or docstring
+ (concat "Simulate '" keys "' in " (if emacs-state
+ "emacs state."
+ "the current context.")))
+ (interactive)
+ (when ,emacs-state
+ ;; so don't have to redefine evil-stop-execute-in-emacs-state
+ (setq this-command #'evil-execute-in-emacs-state)
+ (let ((evil-no-display t))
+ (evil-execute-in-emacs-state)))
+ (let ((command ,command)
+ (invoked-keys (this-command-keys))
+ (keys (kbd ,keys)))
+ (setq prefix-arg current-prefix-arg)
+ (setq unread-command-events
+ (mapcar (lambda (ev) (cons t ev))
+ (listify-key-sequence keys)))
+ (when command
+ (let ((this-command command))
+ (call-interactively command)))
+ (setq general--last-simulate `(:command ,(or command ',name)
+ :invoked-keys ,invoked-keys
+ :keys ,keys)))))))
+
+(defun general--repeat-abort-p (repeat-prop)
+ "Return t if repeat recording should be aborted based on REPEAT-PROP."
+ (or (memq repeat-prop (list nil 'abort 'ignore))
+ (and (eq repeat-prop 'motion)
+ (not (memq evil-state '(insert replace))))))
+
+(defun general--simulate-repeat (flag)
+ "Modified version of `evil-repeat-keystrokes'.
+It ensures that no simulated keys are recorded. Only the keys used to invoke the
+general-simulate-... command are recorded. This function also ensures that the
+repeat is aborted when it should be."
+ (when (eq flag 'post)
+ ;; remove simulated keys
+ (setq evil-repeat-info (butlast evil-repeat-info))
+ (let* ((command (cl-getf general--last-simulate :command))
+ (repeat-prop (evil-get-command-property command :repeat t))
+ (record-keys (cl-getf general--last-simulate :invoked-keys)))
+ (if (and command
+ (general--repeat-abort-p repeat-prop))
+ (evil-repeat-abort)
+ (evil-repeat-record record-keys)
+ (evil-clear-command-keys)))))
+
+(defvar general--last-dispatch nil)
+
+;;;###autoload
+(cl-defmacro general-key-dispatch
+ (fallback-command &rest maps
+ &key timeout inherit-keymap name docstring
+ which-key
+ &allow-other-keys)
+ "Create a function that will run FALLBACK-COMMAND or a command from MAPS.
+MAPS consists of <key> <command> pairs. If a key in MAPS is matched, the
+corresponding command will be run. Otherwise FALLBACK-COMMAND will be run with
+the unmatched keys. So, for example, if \"ab\" was pressed, and \"ab\" is not
+one of the key sequences from MAPS, the FALLBACK-COMMAND will be run followed by
+the simulated keypresses of \"ab\". Prefix arguments will still work regardless
+of which command is run. This is useful for binding under non-prefix keys. For
+example, this can be used to redefine a sequence like \"cw\" or \"cow\" in evil
+but still have \"c\" work as `evil-change'. If TIMEOUT is specified,
+FALLBACK-COMMAND will also be run in the case that the user does not press the
+next key within the TIMEOUT (e.g. 0.5).
+
+NAME and DOCSTRING are optional keyword arguments. They can be used to replace
+the automatically generated name and docstring for the created function and are
+potentially useful if you want to create multiple, different commands using the
+same FALLBACK-COMMAND (e.g. `self-insert-command').
+
+When INHERIT-KEYMAP is specified, all the keybindings from that keymap will be
+inherited in MAPS.
+
+WHICH-KEY can also be specified, in which case the description WHICH-KEY will
+replace the command name in the which-key popup. Note that this requires a
+version of which-key from after 2016-11-21."
+ (declare (indent 1))
+ (let ((name (or name (intern (format "general-dispatch-%s"
+ (eval fallback-command)))))
+ ;; remove keyword arguments from maps
+ (maps (cl-loop for (key value) on maps by 'cddr
+ unless (keywordp key)
+ collect key
+ and collect value)))
+ `(progn
+ (eval-after-load 'evil
+ '(evil-set-command-property #',name :repeat 'general--dispatch-repeat))
+ (when ,which-key
+ (eval-after-load 'which-key
+ (lambda ()
+ (when (boundp 'which-key-replacement-alist)
+ (push '((nil . ,(symbol-name name))
+ nil . ,which-key)
+ which-key-replacement-alist)))))
+ ;; TODO list all of the bound keys in the docstring
+ (defun ,name ()
+ ,(or docstring (format (concat "Run %s or something else based"
+ "on the next keypresses.")
+ (eval fallback-command)))
+ (interactive)
+ (let ((map (make-sparse-keymap))
+ (invoked-keys (this-command-keys))
+ (timeout ,timeout)
+ (inherit-keymap ,inherit-keymap)
+ matched-command
+ fallback
+ char
+ timed-out-p)
+ (when inherit-keymap
+ (set-keymap-parent map inherit-keymap))
+ (if general-implicit-kbd
+ (general--emacs-define-key map
+ ,@(general--apply-prefix-and-kbd nil maps))
+ (general--emacs-define-key map ,@maps))
+ (while (progn
+ (if timeout
+ (with-timeout (timeout (setq timed-out-p t))
+ (setq char (concat char (char-to-string (read-char)))))
+ (setq char (concat char (char-to-string (read-char)))))
+ (and (not timed-out-p)
+ (keymapp (lookup-key map char)))))
+ (setq prefix-arg current-prefix-arg)
+ (cond
+ ((and (not timed-out-p)
+ (setq matched-command (lookup-key map char)))
+ ;; necessary for evil-this-operator checks because
+ ;; evil-define-operator sets evil-this-operator to this-command
+ (let ((this-command matched-command))
+ (call-interactively matched-command)))
+ (t
+ (setq fallback t
+ matched-command ,fallback-command)
+ ;; have to do this in "reverse" order (call command 2nd)
+ (setq unread-command-events (listify-key-sequence char))
+ (let ((this-command ,fallback-command))
+ (call-interactively ,fallback-command))))
+ (setq general--last-dispatch `(:command ,matched-command
+ :invoked-keys ,invoked-keys
+ :keys ,char
+ :fallback ,fallback)))))))
+
+(defvar general--repeat-info nil
+ "Used for debugging repeat behavior for `general-key-dispatch'.")
+
+(defun general--dispatch-repeat (flag)
+ "Modified version of `evil-repeat-keystrokes'.
+It will remove extra keys that would be added in a general-dispatch-... command
+with the default `evil-repeat-keystrokes' and ensures that the repeat is
+aborted when it should be."
+ (cond
+ ((eq flag 'pre)
+ (when evil-this-register
+ (evil-repeat-record
+ `(set evil-this-register ,evil-this-register))))
+ ((eq flag 'post)
+ (let* ((command (cl-getf general--last-dispatch :command))
+ (repeat-prop (evil-get-command-property command :repeat t))
+ (fallback (cl-getf general--last-dispatch :fallback))
+ (invoked-keys (cl-getf general--last-dispatch :invoked-keys))
+ (keys (cl-getf general--last-dispatch :keys))
+ (old-repeat-info (cl-copy-list evil-repeat-info))
+ (reversed-repeat-info (reverse evil-repeat-info))
+ count
+ next-repeat-item)
+ (while (and (stringp (setq next-repeat-item (car reversed-repeat-info)))
+ (string-match "^[0-9]+$" next-repeat-item))
+ ;; need to rely on evil-repeat-info to get counts
+ ;; evil counts will appear as last items, e.g. ("c3" "3" "3")
+ ;; this will work even if the user binds digits in the dispatch command
+ ;; as long as the key to invoke the dispatch command is not also a digit
+ ;; (the 3 in "c3" is the only duplicate)
+ (push (pop reversed-repeat-info) count))
+ (setq evil-repeat-info (if (= (length count) 0)
+ (butlast evil-repeat-info)
+ (nreverse (cdr reversed-repeat-info))))
+ ;; for debugging purposes only
+ (setq general--repeat-info
+ (list :invoked-keys invoked-keys :keys keys
+ :this-command-keys (this-command-keys)
+ :old-evil-repeat-info old-repeat-info
+ :evil-repeat-info (cl-copy-list evil-repeat-info)
+ :count count))
+ (if (general--repeat-abort-p repeat-prop)
+ (evil-repeat-abort)
+ (evil-repeat-record
+ (cond
+ (fallback
+ (concat invoked-keys (apply #'concat count) (this-command-keys)))
+ (t
+ (concat invoked-keys
+ keys
+ (unless (or (string= (concat invoked-keys keys)
+ (this-command-keys))
+ (eq (evil-get-command-property command :repeat)
+ 'general--simulate-repeat))
+ ;; (this-command-keys) will contain the text object if the
+ ;; matched command is an operator
+ (concat count (this-command-keys)))))))
+ (evil-clear-command-keys))))))
+
+(cl-defmacro general-predicate-dispatch
+ (fallback-def &rest defs
+ &key docstring
+ &allow-other-keys)
+ (declare (indent 1))
+ "Create a menu item that will run FALLBACK-DEF or a definition from DEFS.
+DEFS consists of <predicate> <definition> pairs. Binding this menu-item to a key
+will cause that key to act as the corresponding definition (a command, keymap,
+etc) for the first matched predicate. If no predicate is matched FALLBACK-DEF
+will be run. When FALLBACK-DEF is nil and no predicates are matched, the keymap
+with the next highest precedence for the pressed key will be checked. DOCSTRING
+can be specified as a description for the menu item."
+ ;; remove keyword arguments from defs
+ (let ((defs (cl-loop for (key value) on defs by 'cddr
+ unless (keywordp key)
+ collect (list key value))))
+ `'(menu-item
+ ,(or docstring "") nil
+ :filter (lambda (&optional _)
+ (cond ,@(mapcar (lambda (pred-def)
+ `(,(car pred-def) ,(cadr pred-def)))
+ defs)
+ (t ,fallback-def))))))
+
+;;; Optional Setup
+;;;###autoload
+(defmacro general-create-vim-definer
+ (name keymaps &optional states default-to-states)
+ "A helper function to create vim-like wrappers over `general-define-key'.
+The function created will be called NAME and will have the keymaps default to
+KEYMAPS or the states default to STATES. If DEFAULT-TO-STATES is non-nil,
+:states STATES will be used. Otherwise :keymaps KEYMAPS will be used. This can
+be overriden later by setting the global `general-vim-definer-default'
+option."
+ `(defun ,name (&rest args)
+ ,(format "A wrapper function over `general-define-key'.
+
+It has one the following defaults depending on `general-vim-definer-default':
+:keymaps
+%s
+
+:states
+%s
+
+When `general-vim-definer-default' is nil, default to setting %s.
+(If the default :states is nil, :keymaps will be used no matter what.)"
+ keymaps states
+ (if default-to-states
+ ":states"
+ ":keymaps"))
+ ;; can still override keywords afterwards
+ (let ((default-to-states
+ (cond ((eq general-vim-definer-default 'states)
+ t)
+ ((eq general-vim-definer-default 'keymaps)
+ nil)
+ (t
+ ,default-to-states))))
+ (apply #'general-define-key
+ (append args (if (and default-to-states ,states)
+ (list :states ,states)
+ (list :keymaps ,keymaps)))))))
+
+;;;###autoload
+(defmacro general-create-dual-vim-definer
+ (name states &optional default-to-states)
+ "Like `general-create-vim-definer', create a \"vim definer\" called NAME.
+Only the short names in the STATES list need to be specified, but this will only
+work for valid evil states."
+ `(general-create-vim-definer
+ ,name
+ ;; could alternatively just do ,states (difference is the docstring)
+ ',(let ((states (eval states)))
+ (if (listp states)
+ (mapcar #'general--evil-keymap-for-state states)
+ (general--evil-keymap-for-state states)))
+ ,states
+ ,default-to-states))
+
+;;;###autoload
+(defmacro general-evil-setup (&optional short-names default-to-states)
+ "Set up some basic equivalents for vim mapping functions.
+This creates global key definition functions for the evil states.
+Specifying SHORT-NAMES as non-nil will create non-prefixed function
+aliases such as `nmap' for `general-nmap'."
+ `(progn
+ (general-create-dual-vim-definer general-imap 'insert ,default-to-states)
+ (general-create-dual-vim-definer general-emap 'emacs ,default-to-states)
+ (general-create-dual-vim-definer general-nmap 'normal ,default-to-states)
+ (general-create-dual-vim-definer general-vmap 'visual ,default-to-states)
+ (general-create-dual-vim-definer general-omap 'operator ,default-to-states)
+ (general-create-dual-vim-definer general-mmap 'motion ,default-to-states)
+ (general-create-dual-vim-definer general-rmap 'replace ,default-to-states)
+ ;; these two don't have corresponding states
+ (general-create-vim-definer general-otomap 'evil-outer-text-objects-map)
+ (general-create-vim-definer general-itomap 'evil-inner-text-objects-map)
+ (general-create-dual-vim-definer general-iemap
+ '(insert emacs)
+ ,default-to-states)
+ (general-create-dual-vim-definer general-nvmap
+ '(normal visual)
+ ,default-to-states)
+ (general-create-vim-definer general-tomap
+ '(evil-outer-text-objects-map
+ evil-inner-text-objects-map))
+ (when ,short-names
+ (defalias 'imap #'general-imap)
+ (defalias 'emap #'general-emap)
+ (defalias 'nmap #'general-nmap)
+ (defalias 'vmap #'general-vmap)
+ (defalias 'omap #'general-omap)
+ (defalias 'mmap #'general-mmap)
+ (defalias 'rmap #'general-rmap)
+ (defalias 'otomap #'general-otomap)
+ (defalias 'itomap #'general-itomap)
+ (defalias 'iemap #'general-iemap)
+ (defalias 'nvmap #'general-nvmap)
+ (defalias 'tomap #'general-tomap))))
+
+;;; Use-package Integration
+(eval-after-load 'use-package
+ (lambda ()
+ (setq use-package-keywords
+ ;; should go in the same location as :bind
+ ;; adding to end may not cause problems, but see issue #22
+ (cl-loop for item in use-package-keywords
+ if (eq item :bind-keymap*)
+ collect :bind-keymap* and collect :general
+ else
+ ;; don't add duplicates
+ unless (eq item :general)
+ collect item))
+ (defun use-package-normalize/:general (_name _keyword args)
+ args)
+ (defun use-package-handler/:general (name _keyword arglists rest state)
+ (let* ((sanitized-arglist
+ ;; combine arglists into one without function names or
+ ;; positional arguments
+ (let (result
+ first)
+ (dolist (arglist arglists result)
+ (setq first (car arglist))
+ (cond ((eq first 'general-evil-define-key)
+ (setq arglist (cl-cdddr arglist)))
+ ((eq first 'general-emacs-define-key)
+ (setq arglist (cddr arglist)))
+ ((cl-oddp (length arglist))
+ ;; normal wrapper
+ (setq arglist (cdr arglist))))
+ (setq result (append result arglist)))))
+ (commands
+ (cl-loop for (key def) on sanitized-arglist by 'cddr
+ when (and (not (keywordp key))
+ (not (null def))
+ (ignore-errors
+ (setq def (eval def))
+ (or (symbolp def)
+ (when (and (symbolp (car def))
+ (not (keywordp (car def)))
+ (not (memq
+ (car def)
+ '(menu-item lambda)))
+ (not (keymapp def)))
+ (setq def (car def)))
+ (setq def (cl-getf def :command)))))
+ collect def)))
+ (use-package-concat
+ (use-package-process-keywords name
+ (use-package-sort-keywords
+ (use-package-plist-maybe-put rest :defer t))
+ (use-package-plist-append state :commands commands))
+ `((ignore ,@(mapcar (lambda (arglist)
+ (let ((first (car arglist)))
+ (if (or (eq first 'general-emacs-define-key)
+ (eq first 'general-evil-define-key)
+ (cl-oddp (length arglist)))
+ `(,@arglist :package ',name)
+ `(general-define-key ,@arglist
+ :package ',name))))
+ arglists))))))))
+
+;;; Key-chord "Integration"
+(defun general-chord (keys)
+ "Rewrite the string KEYS into a valid key-chord vector."
+ ;; taken straight from key-chord.el
+ (if (/= 2 (length keys))
+ (error "Key-chord keys must have two elements"))
+ ;; Exotic chars in a string are >255 but define-key wants 128..255 for those
+ (let ((key1 (logand 255 (aref keys 0)))
+ (key2 (logand 255 (aref keys 1))))
+ (vector 'key-chord key1 key2)))
+
+(provide 'general)
+;;; general.el ends here
.emacs.d/elpa/general-20170708.104/general.elc
Binary file
.emacs.d/elpa/persp-projectile-20160709.2317/persp-projectile-autoloads.el
@@ -0,0 +1,30 @@
+;;; persp-projectile-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
+
+;;;### (autoloads nil "persp-projectile" "persp-projectile.el" (22977
+;;;;;; 30128 60658 582000))
+;;; Generated autoloads from persp-projectile.el
+
+(autoload 'projectile-persp-switch-project "persp-projectile" "\
+Switch to a project or perspective we have visited before.
+If the perspective of corresponding project does not exist, this
+function will call `persp-switch' to create one and switch to
+that before `projectile-switch-project' invokes
+`projectile-switch-project-action'.
+
+Otherwise, this function calls `persp-switch' to switch to an
+existing perspective of the project unless we're already in that
+perspective.
+
+\(fn PROJECT-TO-SWITCH)" t nil)
+
+;;;***
+
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+;;; persp-projectile-autoloads.el ends here
.emacs.d/elpa/persp-projectile-20160709.2317/persp-projectile-pkg.el
@@ -0,0 +1,2 @@
+;;; -*- no-byte-compile: t -*-
+(define-package "persp-projectile" "20160709.2317" "Perspective integration with Projectile" '((perspective "1.9") (projectile "0.11.0") (cl-lib "0.3")) :commit "7686633acf44402fa90429759cca6a155e4df2b9" :keywords '("project" "convenience"))
.emacs.d/elpa/persp-projectile-20160709.2317/persp-projectile.el
@@ -0,0 +1,106 @@
+;;; persp-projectile.el --- Perspective integration with Projectile
+
+;; Copyright (C) 2014-2016 Daniel Wu, Bozhidar Batsov
+
+;; Author: Daniel Wu
+;; Created: 2014-04-14
+;; Keywords: project, convenience
+;; Package-Version: 20160709.2317
+;; Version: 0.2.0
+;; Package-Requires: ((perspective "1.9") (projectile "0.11.0") (cl-lib "0.3"))
+
+;; 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:
+;;
+;; This library bridges perspective mode to the awesome library
+;; Projectile. The idea is to create a separate perspective when
+;; switching project. A perspective is an independant workspace for
+;; Emacs, similar to multiple desktops in Gnome and MacOS. I often
+;; work on many projects at the same time, and using perspective and
+;; projectile together allows me to easily know which project I'm
+;; current in, and focus on files that only belong to current project
+;; when switching buffer.
+
+;; To use this library, put this file in your Emacs load path, and
+;; call (require 'persp-projectile)
+
+;; See perspective.el on github: https://github.com/nex3/perspective-el
+
+;;; Code:
+(require 'perspective)
+(require 'projectile)
+
+;; TODO this may be incompatible helm which let's you find stuff in new frame
+(defmacro projectile-persp-bridge (func-name)
+ "Create advice to create a perspective before invoking function FUNC-NAME.
+The advice provides bridge between perspective and projectile
+functions when switch between projects. After switching to a new
+project, this advice creates a new perspective for that project."
+ `(defadvice ,func-name (before projectile-create-perspective-after-switching-projects activate)
+ "Create a dedicated perspective for current project's window after switching projects."
+ (let ((project-name (projectile-project-name)))
+ (when (projectile-project-p)
+ (persp-switch project-name)))))
+
+(projectile-persp-bridge projectile-dired)
+(projectile-persp-bridge projectile-find-file)
+
+;;;###autoload
+(defun projectile-persp-switch-project (project-to-switch)
+ "Switch to a project or perspective we have visited before.
+If the perspective of corresponding project does not exist, this
+function will call `persp-switch' to create one and switch to
+that before `projectile-switch-project' invokes
+`projectile-switch-project-action'.
+
+Otherwise, this function calls `persp-switch' to switch to an
+existing perspective of the project unless we're already in that
+perspective."
+ (interactive (list (projectile-completing-read "Switch to project: "
+ (projectile-relevant-known-projects))))
+ (let* ((name (file-name-nondirectory (directory-file-name project-to-switch)))
+ (persp (gethash name perspectives-hash)))
+ (cond
+ ;; project-specific perspective already exists
+ ((and persp (not (equal persp persp-curr)))
+ (persp-switch name))
+ ;; project-specific perspective doesn't exist
+ ((not persp)
+ (let ((frame (selected-frame)))
+ (persp-switch name)
+ (projectile-switch-project-by-name project-to-switch)
+ ;; Clean up if we switched to a new frame. `helm' for one allows finding
+ ;; files in new frames so this is a real possibility.
+ (when (not (equal frame (selected-frame)))
+ (with-selected-frame frame
+ (persp-kill name))))))))
+
+(defadvice persp-init-frame (after projectile-persp-init-frame activate)
+ "Rename initial perspective to `projectile-project-name' when a
+new frame is created in a known project."
+ (with-selected-frame frame
+ (when (projectile-project-p)
+ (persp-rename (projectile-project-name)))))
+
+(define-key projectile-mode-map [remap projectile-switch-project] 'projectile-persp-switch-project)
+
+(provide 'persp-projectile)
+;;; persp-projectile.el ends here
.emacs.d/elpa/persp-projectile-20160709.2317/persp-projectile.elc
Binary file
.emacs.d/elpa/perspective-20160609.1444/perspective-autoloads.el
@@ -0,0 +1,34 @@
+;;; perspective-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
+
+;;;### (autoloads nil "perspective" "perspective.el" (22977 30127
+;;;;;; 560663 522000))
+;;; Generated autoloads from perspective.el
+
+(defvar persp-mode nil "\
+Non-nil if Persp mode is enabled.
+See the `persp-mode' command
+for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `persp-mode'.")
+
+(custom-autoload 'persp-mode "perspective" nil)
+
+(autoload 'persp-mode "perspective" "\
+Toggle perspective mode.
+When active, keeps track of multiple 'perspectives',
+named collections of buffers and window configurations.
+
+\(fn &optional ARG)" t nil)
+
+;;;***
+
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+;;; perspective-autoloads.el ends here
.emacs.d/elpa/perspective-20160609.1444/perspective-pkg.el
@@ -0,0 +1,2 @@
+;;; -*- no-byte-compile: t -*-
+(define-package "perspective" "20160609.1444" "switch between named \"perspectives\" of the editor" '((cl-lib "0.5")) :commit "89a8ef5e8297b113e4f732bb94336608b76e13fd" :url "http://github.com/nex3/perspective-el" :keywords '("workspace" "convenience" "frames"))
.emacs.d/elpa/perspective-20160609.1444/perspective.el
@@ -0,0 +1,926 @@
+;;; perspective.el --- switch between named "perspectives" of the editor
+
+;; Copyright (C) 2008-2015 Natalie Weizenbaum <nex342@gmail.com>
+;;
+;; Licensed under the same terms as Emacs and under the MIT license.
+
+;; Author: Natalie Weizenbaum <nex342@gmail.com>
+;; URL: http://github.com/nex3/perspective-el
+;; Package-Version: 20160609.1444
+;; Package-Requires: ((cl-lib "0.5"))
+;; Version: 1.12
+;; Created: 2008-03-05
+;; By: Natalie Weizenbaum <nex342@gmail.com>
+;; Keywords: workspace, convenience, frames
+
+;;; Commentary:
+
+;; This package provides tagged workspaces in Emacs, similar to
+;; workspaces in windows managers such as Awesome and XMonad (and
+;; somewhat similar to multiple desktops in Gnome or Spaces in OS X).
+
+;; perspective.el provides multiple workspaces (or "perspectives") for
+;; each Emacs frame. This makes it easy to work on many separate projects
+;; without getting lost in all the buffers.
+
+;; Each perspective is composed of a window configuration and a set of
+;; buffers. Switching to a perspective activates its window
+;; configuration, and when in a perspective only its buffers are
+;; available by default.
+
+(require 'cl-lib)
+
+;; 'cl' is still required because the use of 'lexical-let'. 'lexical-let' has
+;; been deprecated since emacs 24.1, and it should be replaced with true
+;; lexical bindings. For more information, please see
+;; https://www.gnu.org/software/emacs/manual/html_node/cl/
+;; Obsolete-Lexical-Binding.html
+(require 'cl)
+
+(defvar ido-temp-list)
+
+;;; Code:
+
+(defgroup perspective-mode 'nil
+ "Customization for Perspective mode"
+ :group 'frames)
+
+(defcustom persp-initial-frame-name "main"
+ "Name used for the initial perspective when enabling `persp-mode'."
+ :type 'string
+ :group 'perspective-mode)
+
+(defcustom persp-show-modestring t
+ "Determines if `persp-modestring' is shown in the modeline.
+If the value is 'header, `persp-modestring' is shown in the
+header line instead."
+ :group 'perspective-mode
+ :type '(choice (const :tag "Off" nil)
+ (const :tag "Modeline" t)
+ (const :tag "Header" 'header)))
+
+(defcustom persp-modestring-dividers '("[" "]" "|")
+ "Plist of strings used to created `persp-modestring'.
+First string is the start of the modestring, second is the
+closing of the mode string, and the last is the divider between
+perspectives."
+ :group 'perspective-mode
+ :type '(list (string :tag "Open")
+ (string :tag "Close")
+ (string :tag "Divider")))
+
+(defcustom persp-mode-prefix-key (kbd "C-x x")
+ "Prefix key to activate perspective-map"
+ :group 'perspective-mode
+ :set (lambda (sym value)
+ (when (and (bound-and-true-p persp-mode-map)
+ (bound-and-true-p perspective-map))
+ (persp-mode-set-prefix-key value))
+ (set-default sym value))
+ :type 'key-sequence)
+
+(defcustom persp-switch-wrap t
+ "Whether `persp-next' and `persp-prev' should wrap."
+ :group 'perspective-mode
+ :type 'boolean)
+
+;; This is only available in Emacs >23,
+;; so we redefine it here for compatibility.
+(unless (fboundp 'with-selected-frame)
+ (defmacro with-selected-frame (frame &rest body)
+ "Execute the forms in BODY with FRAME as the selected frame.
+The value returned is the value of the last form in BODY.
+See also `with-temp-buffer'."
+ (declare (indent 1) (debug t))
+ (let ((old-frame (make-symbol "old-frame"))
+ (old-buffer (make-symbol "old-buffer")))
+ `(let ((,old-frame (selected-frame))
+ (,old-buffer (current-buffer)))
+ (unwind-protect
+ (progn (select-frame ,frame)
+ ,@body)
+ (if (frame-live-p ,old-frame)
+ (select-frame ,old-frame))
+ (if (buffer-live-p ,old-buffer)
+ (set-buffer ,old-buffer)))))))
+
+(defmacro persp-frame-local-let (bindings &rest body)
+ "Like `let', but properly handles frame-local variables.
+Bind variables according to BINDINGS then eval BODY.
+
+In Emacs >= 23.2, frame-local variables are not reset after a
+`let' expression. This hacks around that by manually resetting
+them in Emacs >= 23.2. In older versions, this is identical to
+`let'."
+ (declare (indent 1))
+ (if (or (< emacs-major-version 23)
+ (and (= emacs-major-version 23) (< emacs-minor-version 2)))
+ `(let ,bindings ,@body)
+ (let ((binding-syms (mapcar (lambda (binding) (list (car binding) (cl-gensym))) bindings)))
+ ;; Each binding-sym is a pair (ORIGINAL-VALUE . WAS-BOUND).
+ `(let ,(mapcar (lambda (binding)
+ (list (cadr binding)
+ (let ((name (car binding)))
+ `(cons (when (boundp ',name) ,name)
+ (boundp ',name)))))
+ binding-syms)
+ (unwind-protect
+ (progn ,@(mapcar (lambda (binding) `(setq ,(car binding) ,(cadr binding))) bindings)
+ ,@body)
+ ;; After the body, reset the original value of each binding sym if
+ ;; there was one, unbind it if there wasn't.
+ ,@(mapcar (lambda (binding)
+ `(if (cdr ,(cadr binding))
+ (setq ,(car binding) (car ,(cadr binding)))
+ (makunbound ',(car binding)))) binding-syms))))))
+
+(cl-defstruct (perspective
+ (:conc-name persp-)
+ (:constructor make-persp-internal))
+ name buffers killed local-variables
+ (buffer-history buffer-name-history)
+ (window-configuration (current-window-configuration))
+ (point-marker (point-marker)))
+
+(defalias 'persp-killed-p 'persp-killed
+ "Return whether the perspective CL-X has been killed.")
+
+(defvar persp-interactive-completion-function
+ (if ido-mode 'ido-completing-read 'completing-read)
+ "The function which is used by perspective.el to interactivly complete user input")
+
+(defvar persp-before-switch-hook nil
+ "A hook that's run before `persp-switch'.
+Run with the previous perspective as `persp-curr'.")
+
+(defvar persp-switch-hook nil
+ "A hook that's run after `persp-switch'.
+Run with the newly created perspective as `persp-curr'.")
+
+(defvar persp-mode-hook nil
+ "A hook that's run after `persp-mode' has been activated.")
+
+(defvar persp-created-hook nil
+ "A hook that's run after a perspective has been created.
+Run with the newly created perspective as `persp-curr'.")
+
+(defvar persp-killed-hook nil
+ "A hook that's run just before a perspective is destroyed.
+Run with the perspective to be destroyed as `persp-curr'.")
+
+(defvar persp-activated-hook nil
+ "A hook that's run after a perspective has been activated.
+Run with the activated perspective active.")
+
+(defvar persp-mode-map (make-sparse-keymap)
+ "Keymap for perspective-mode.")
+
+(define-prefix-command 'perspective-map)
+(define-key persp-mode-map persp-mode-prefix-key 'perspective-map)
+
+(define-key perspective-map (kbd "s") 'persp-switch)
+(define-key perspective-map (kbd "k") 'persp-remove-buffer)
+(define-key perspective-map (kbd "c") 'persp-kill)
+(define-key perspective-map (kbd "r") 'persp-rename)
+(define-key perspective-map (kbd "a") 'persp-add-buffer)
+(define-key perspective-map (kbd "A") 'persp-set-buffer)
+(define-key perspective-map (kbd "b") 'persp-switch-to-buffer)
+(define-key perspective-map (kbd "i") 'persp-import)
+(define-key perspective-map (kbd "n") 'persp-next)
+(define-key perspective-map (kbd "<right>") 'persp-next)
+(define-key perspective-map (kbd "p") 'persp-prev)
+(define-key perspective-map (kbd "<left>") 'persp-prev)
+(define-key perspective-map persp-mode-prefix-key 'persp-switch-last)
+
+(defun persp-mode-set-prefix-key (newkey)
+ "Set the prefix key to activate persp-mode"
+ (substitute-key-definition 'perspective-map nil persp-mode-map)
+ (define-key persp-mode-map newkey 'perspective-map))
+
+;; make-variable-frame-local is obsolete according to the docs,
+;; but I don't want to have to manually munge frame-parameters
+;; all the time so I'm using it anyway.
+(make-variable-frame-local
+ (defvar perspectives-hash nil
+ "A hash containing all perspectives. The keys are the
+perspectives' names. The values are persp structs,
+with the fields NAME, WINDOW-CONFIGURATION, BUFFERS,
+BUFFER-HISTORY, KILLED, POINT-MARKER, and LOCAL-VARIABLES.
+
+NAME is the name of the perspective.
+
+WINDOW-CONFIGURATION is the configuration given by
+`current-window-configuration' last time the perspective was
+saved (if this isn't the current perspective, this is when the
+perspective was last active).
+
+BUFFERS is a list of buffer objects that are associated with this
+perspective.
+
+BUFFER-HISTORY is the list of buffer history values for this
+perspective.
+
+KILLED is non-nil if the perspective has been killed.
+
+POINT-MARKER is the point position in the active buffer.
+Otherwise, when multiple windows are visiting the same buffer,
+all but one of their points will be overwritten.
+
+LOCAL-VARIABLES is an alist from variable names to their
+perspective-local values."))
+
+(make-variable-frame-local
+ (defvar persp-curr nil
+ "The current perspective."))
+
+(make-variable-frame-local
+ (defvar persp-recursive nil
+ "The current perspective before beginning a recursive edit."))
+
+(make-variable-frame-local
+ (defvar persp-last nil
+ "The last perspective accessed before the current perspective."))
+
+(make-variable-frame-local
+ (defvar persp-modestring nil
+ "The string displayed in the modeline representing the perspectives."))
+(put 'persp-modestring 'risky-local-variable t)
+
+(defvar persp-protected nil
+ "Whether a perspective error should cause persp-mode to be disabled.
+Dynamically bound by `persp-protect'.")
+
+(defface persp-selected-face
+ '((t (:weight bold :foreground "Blue")))
+ "The face used to highlight the current perspective on the modeline.")
+
+(defmacro persp-protect (&rest body)
+ "Wrap BODY to disable persp-mode when it errors out.
+This prevents the persp-mode from completely breaking Emacs."
+ (declare (indent 0))
+ (let ((persp-protected t))
+ `(condition-case err
+ (progn ,@body)
+ (persp-error
+ (message "Fatal persp-mode error: %S" err)
+ (persp-mode -1)))))
+
+(defun persp-error (&rest args)
+ "Like `error', but marks it as a persp-specific error.
+Used along with `persp-protect' to ensure that persp-mode doesn't
+bring down Emacs."
+ (if persp-protected
+ (signal 'persp-error (list (apply 'format args)))
+ (apply 'error args)))
+
+(defun check-persp (persp)
+ "Raise an error if PERSP has been killed."
+ (cond
+ ((not persp)
+ (persp-error "Expected perspective, was nil"))
+ ((persp-killed-p persp)
+ (persp-error "Using killed perspective `%s'" (persp-name persp)))))
+
+(defmacro make-persp (&rest args)
+ "Create a new perspective struct and put it in `perspectives-hash'.
+
+ARGS is a list of keyword arguments followed by an optional BODY.
+The keyword arguments set the fields of the perspective struct.
+If BODY is given, it is executed to set the window configuration
+for the perspective."
+ (declare (indent defun))
+ (let ((keywords))
+ (while (keywordp (car args))
+ (dotimes (_ 2) (push (pop args) keywords)))
+ (setq keywords (reverse keywords))
+ `(let ((persp (make-persp-internal ,@keywords)))
+ (when persp-curr
+ (setf (persp-local-variables persp) (persp-local-variables persp-curr)))
+ (puthash (persp-name persp) persp perspectives-hash)
+ (with-perspective (persp-name persp)
+ ,(when args
+ ;; Body form given
+ `(save-excursion ,@args))
+ (run-hooks 'persp-created-hook))
+ persp)))
+
+(defun persp-save ()
+ "Save the current perspective state.
+Specifically, save the current window configuration and
+perspective-local variables to `persp-curr'"
+ (when persp-curr
+ (setf (persp-local-variables persp-curr)
+ (mapcar
+ (lambda (c)
+ (let ((name (car c)))
+ (list name (symbol-value name))))
+ (persp-local-variables persp-curr)))
+ (setf (persp-buffer-history persp-curr) buffer-name-history)
+ (setf (persp-window-configuration persp-curr) (current-window-configuration))
+ (setf (persp-point-marker persp-curr) (point-marker))))
+
+(defun persp-names ()
+ "Return a list of the names of all perspectives, sorted alphabetically."
+ (sort
+ (cl-loop for name being the hash-keys of perspectives-hash
+ collect name)
+ 'string<))
+
+(defun persp-all-names (&optional not-frame)
+ "Return a list of the perspective names for all frames.
+Excludes NOT-FRAME, if given."
+ (cl-reduce 'union
+ (mapcar
+ (lambda (frame)
+ (unless (equal frame not-frame)
+ (with-selected-frame frame (persp-names))))
+ (frame-list))))
+
+(defun persp-prompt (&optional default require-match)
+ "Prompt for the name of a perspective.
+
+DEFAULT is a default value for the prompt.
+
+REQUIRE-MATCH can take the same values as in `completing-read'."
+ (funcall persp-interactive-completion-function (concat "Perspective name"
+ (if default (concat " (default " default ")") "")
+ ": ")
+ (persp-names)
+ nil require-match nil nil default))
+
+(defmacro with-perspective (name &rest body)
+ "Switch to the perspective given by NAME while evaluating BODY."
+ (declare (indent 1))
+ (let ((old (cl-gensym)))
+ `(progn
+ (let ((,old (when persp-curr (persp-name persp-curr)))
+ (last-persp-cache persp-last))
+ (unwind-protect
+ (progn
+ (persp-switch ,name)
+ ,@body)
+ (when ,old (persp-switch ,old)))
+ (setq persp-last last-persp-cache)))))
+
+(defun persp-new (name)
+ "Return a new perspective with name NAME.
+The new perspective will start with only an `initial-major-mode'
+buffer called \"*scratch* (NAME)\"."
+ (make-persp :name name
+ (switch-to-buffer (concat "*scratch* (" name ")"))
+ (funcall initial-major-mode)
+ (delete-other-windows)))
+
+(defun persp-reactivate-buffers (buffers)
+ "Raise BUFFERS to the top of the most-recently-selected list.
+Returns BUFFERS with all non-living buffers removed.
+
+See also `other-buffer'."
+ (cl-loop for buf in (reverse buffers)
+ if (not (null (buffer-name buf)))
+ collect buf into living-buffers
+ and do (switch-to-buffer buf)
+ finally return (reverse living-buffers)))
+
+(defun persp-set-local-variables (vars)
+ "Set the local variables given in VARS.
+VARS should be an alist of variable names to values."
+ (dolist (var vars) (apply 'set var)))
+
+(defun persp-intersperse (list interspersed-val)
+ "Intersperse a value into a list.
+Return a new list made from taking LIST and inserting
+INTERSPERSED-VAL between every pair of items.
+
+For example, (persp-intersperse '(1 2 3) 'a) gives '(1 a 2 a 3)."
+ (reverse
+ (cl-reduce
+ (lambda (list el) (if list (cl-list* el interspersed-val list) (list el)))
+ list :initial-value nil)))
+
+(defconst persp-mode-line-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [mode-line down-mouse-1] 'persp-mode-line-click)
+ map))
+
+(defun persp-mode-line-click (event)
+ "Select the clicked perspective.
+EVENT is the click event triggering this function call."
+ (interactive "e")
+ (persp-switch (format "%s" (car (posn-string (event-start event))))))
+
+(defun persp-update-modestring ()
+ "Update `persp-modestring' to reflect the current perspectives.
+Has no effect when `persp-show-modestring' is nil."
+ (when persp-show-modestring
+ (let ((open (list (nth 0 persp-modestring-dividers)))
+ (close (list (nth 1 persp-modestring-dividers)))
+ (sep (nth 2 persp-modestring-dividers)))
+ (setq persp-modestring
+ (append open
+ (persp-intersperse (mapcar 'persp-format-name
+ (persp-names)) sep)
+ close)))))
+
+(defun persp-format-name (name)
+ "Format the perspective name given by NAME for display in `persp-modestring'."
+ (let ((string-name (format "%s" name)))
+ (if (equal name (persp-name persp-curr))
+ (propertize string-name 'face 'persp-selected-face)
+ (propertize string-name
+ 'local-map persp-mode-line-map
+ 'mouse-face 'mode-line-highlight))))
+
+(defun persp-get-quick (char &optional prev)
+ "Return the name of the first perspective that begins with CHAR.
+Perspectives are sorted alphabetically.
+
+PREV can be the name of a perspective. If it's passed,
+this will try to return the perspective alphabetically after PREV.
+This is used for cycling between perspectives."
+ (persp-get-quick-helper char prev (persp-names)))
+
+(defun persp-get-quick-helper (char prev names)
+ (if (null names) nil
+ (let ((name (car names)))
+ (cond
+ ((and (null prev) (eq (string-to-char name) char)) name)
+ ((equal name prev)
+ (if (and (not (null (cdr names))) (eq (string-to-char (cadr names)) char))
+ (cadr names)
+ (persp-get-quick char)))
+ (t (persp-get-quick-helper char prev (cdr names)))))))
+
+(defun persp-switch-last ()
+ "Switch to the perspective accessed before the current one."
+ (interactive)
+ (unless persp-last
+ (error "There is no last perspective"))
+ (persp-switch (persp-name persp-last)))
+
+(defun persp-switch (name)
+ "Switch to the perspective given by NAME.
+If it doesn't exist, create a new perspective and switch to that.
+
+Switching to a perspective means that all buffers associated with
+that perspective are reactivated (see `persp-reactivate-buffers'),
+the perspective's window configuration is restored, and the
+perspective's local variables are set."
+ (interactive "i")
+ (if (null name) (setq name (persp-prompt (and persp-last (persp-name persp-last)))))
+ (if (and persp-curr (equal name (persp-name persp-curr))) name
+ (let ((persp (gethash name perspectives-hash)))
+ (setq persp-last persp-curr)
+ (when (null persp)
+ (setq persp (persp-new name)))
+ (run-hooks 'persp-before-switch-hook)
+ (persp-activate persp)
+ name))
+ (run-hooks 'persp-switch-hook))
+
+(defun persp-activate (persp)
+ "Activate the perspective given by the persp struct PERSP."
+ (check-persp persp)
+ (persp-save)
+ (setq persp-curr persp)
+ (persp-set-local-variables (persp-local-variables persp))
+ (persp-reactivate-buffers (persp-buffers persp))
+ (setq buffer-name-history (persp-buffer-history persp))
+ (set-window-configuration (persp-window-configuration persp))
+ (goto-char (persp-point-marker persp))
+ (persp-update-modestring)
+ (run-hooks 'persp-activated-hook))
+
+(defun persp-switch-quick (char)
+ "Switch to the first perspective, alphabetically, that begins with CHAR.
+
+Sets `this-command' (and thus `last-command') to (persp-switch-quick . CHAR).
+
+See `persp-switch', `persp-get-quick'."
+ (interactive "c")
+ (let ((persp (if (and (consp last-command) (eq (car last-command) this-command))
+ (persp-get-quick char (cdr last-command))
+ (persp-get-quick char))))
+ (setq this-command (cons this-command persp))
+ (if persp (persp-switch persp)
+ (persp-error (concat "No perspective name begins with " (string char))))))
+
+(defun persp-next ()
+ "Switch to next perspective (to the right)."
+ (interactive)
+ (let* ((names (persp-names))
+ (pos (cl-position (persp-name persp-curr) names)))
+ (cond
+ ((null pos) (persp-find-some))
+ ((= pos (1- (length names)))
+ (if persp-switch-wrap (persp-switch (nth 0 names))))
+ (t (persp-switch (nth (1+ pos) names))))))
+
+(defun persp-prev ()
+ "Switch to previous perspective (to the left)."
+ (interactive)
+ (let* ((names (persp-names))
+ (pos (cl-position (persp-name persp-curr) names)))
+ (cond
+ ((null pos) (persp-find-some))
+ ((= pos 0)
+ (if persp-switch-wrap (persp-switch (nth (1- (length names)) names))))
+ (t (persp-switch (nth (1- pos) names))))))
+
+(defun persp-find-some ()
+ "Return the name of a valid perspective.
+
+This function tries to return the \"most appropriate\"
+perspective to switch to. It tries:
+
+ * The perspective given by `persp-last'.
+ * The main perspective.
+ * The first existing perspective, alphabetically.
+
+If none of these perspectives can be found, this function will
+create a new main perspective and return \"main\"."
+ (cond
+ (persp-last (persp-name persp-last))
+ ((gethash persp-initial-frame-name perspectives-hash) persp-initial-frame-name)
+ ((> (hash-table-count perspectives-hash) 0) (car (persp-names)))
+ (t (persp-activate
+ (make-persp :name persp-initial-frame-name :buffers (buffer-list)
+ :window-configuration (current-window-configuration)
+ :point-marker (point-marker)))
+ persp-initial-frame-name)))
+
+(defun persp-add-buffer (buffer)
+ "Associate BUFFER with the current perspective.
+
+See also `persp-switch' and `persp-remove-buffer'."
+ (interactive
+ (list
+ (let ((read-buffer-function nil))
+ (read-buffer "Add buffer to perspective: "))))
+ (let ((buffer (get-buffer buffer)))
+ (unless (memq buffer (persp-buffers persp-curr))
+ (push buffer (persp-buffers persp-curr)))))
+
+(defun persp-set-buffer (buffer-name)
+ "Associate BUFFER-NAME with the current perspective and remove it from any other."
+ (interactive
+ (list
+ (let ((read-buffer-function nil))
+ (read-buffer "Set buffer to perspective: "))))
+ (cond ((get-buffer buffer-name)
+ (persp-add-buffer buffer-name)
+ (cl-loop for other-persp = (persp-buffer-in-other-p (get-buffer buffer-name))
+ while other-persp
+ do (with-perspective (cdr other-persp)
+ (persp-remove-buffer buffer-name))))
+ (t (message "buffer %s doesn't exist" buffer-name))))
+
+(cl-defun persp-buffer-in-other-p (buffer)
+ "Returns nil if BUFFER is only in the current perspective.
+Otherwise, returns (FRAME . NAME), the frame and name of another
+perspective that has the buffer.
+
+Prefers perspectives in the selected frame."
+ (cl-loop for frame in (sort (frame-list) (lambda (frame1 frame2) (eq frame2 (selected-frame))))
+ do (cl-loop for persp being the hash-values of (with-selected-frame frame perspectives-hash)
+ if (and (not (and (equal frame (selected-frame))
+ (equal (persp-name persp) (persp-name persp-curr))))
+ (memq buffer (persp-buffers persp)))
+ do (cl-return-from persp-buffer-in-other-p
+ (cons frame (persp-name persp)))))
+ nil)
+
+(defun persp-switch-to-buffer (buffer-or-name)
+ "Like `switch-to-buffer', but switches to another perspective if necessary."
+ (interactive
+ (list
+ (let ((read-buffer-function nil))
+ (read-buffer-to-switch "Switch to buffer: "))))
+ (let ((buffer (window-normalize-buffer-to-switch-to buffer-or-name)))
+ (if (memq buffer (persp-buffers persp-curr))
+ (switch-to-buffer buffer)
+ (let ((other-persp (persp-buffer-in-other-p buffer)))
+ (when (eq (car-safe other-persp) (selected-frame))
+ (persp-switch (cdr other-persp)))
+ (switch-to-buffer buffer)))))
+
+(defun persp-remove-buffer (buffer)
+ "Disassociate BUFFER with the current perspective.
+
+See also `persp-switch' and `persp-add-buffer'."
+ (interactive "bRemove buffer from perspective: \n")
+ (setq buffer (get-buffer buffer))
+ (cond ((not (buffer-live-p buffer)))
+ ;; Only kill the buffer if no other perspectives are using it
+ ((not (persp-buffer-in-other-p buffer))
+ (kill-buffer buffer))
+ ;; Make the buffer go away if we can see it.
+ ;; TODO: Is it possible to tell if it's visible at all,
+ ;; rather than just the current buffer?
+ ((eq buffer (current-buffer)) (bury-buffer))
+ (t (bury-buffer buffer)))
+ (setf (persp-buffers persp-curr) (remq buffer (persp-buffers persp-curr))))
+
+(defun persp-kill (name)
+ "Kill the perspective given by NAME.
+
+Killing a perspective means that all buffers associated with that
+perspective and no others are killed."
+ (interactive "i")
+ (if (null name) (setq name (persp-prompt (persp-name persp-curr) t)))
+ (with-perspective name
+ (run-hooks 'persp-killed-hook)
+ (mapc 'persp-remove-buffer (persp-buffers persp-curr))
+ (setf (persp-killed persp-curr) t))
+ (remhash name perspectives-hash)
+ (persp-update-modestring)
+ (when (equal name (persp-name persp-last))
+ (setq persp-last nil))
+ (when (equal name (persp-name persp-curr))
+ ;; Don't let persp-last get set to the deleted persp.
+ (persp-frame-local-let ((persp-last persp-last)) (persp-switch (persp-find-some)))))
+
+(defun persp-rename (name)
+ "Rename the current perspective to NAME."
+ (interactive "sNew name: ")
+ (if (gethash name perspectives-hash)
+ (persp-error "Perspective `%s' already exists" name)
+ (remhash (persp-name persp-curr) perspectives-hash)
+ (puthash name persp-curr perspectives-hash)
+ (setf (persp-name persp-curr) name)
+ (persp-update-modestring)))
+
+(cl-defun persp-all-get (name not-frame)
+ "Returns the list of buffers for a perspective named NAME from any
+frame other than NOT-FRAME.
+
+This doesn't return the window configuration because those can't be
+copied across frames."
+ (dolist (frame (frame-list))
+ (unless (equal frame not-frame)
+ (with-selected-frame frame
+ (let ((persp (gethash name perspectives-hash)))
+ (if persp (cl-return-from persp-all-get (persp-buffers persp))))))))
+
+(defun persp-read-buffer (prompt &optional def require-match)
+ "A replacement for the built-in `read-buffer'.
+Meant to be used with `read-buffer-function'. Return the name of
+the buffer selected, only selecting from buffers within the
+current perspective.
+
+With a prefix arg, uses the old `read-buffer' instead."
+ (persp-protect
+ (let ((read-buffer-function nil))
+ (if current-prefix-arg
+ (read-buffer prompt def require-match)
+ ;; Most of this is taken from `minibuffer-with-setup-hook',
+ ;; slightly modified because it's not a macro.
+ ;; The only functional difference is that the append argument
+ ;; to add-hook is t, so that it'll be run after the hook added
+ ;; by `read-buffer-to-switch'.
+ (let ((rb-completion-table (persp-complete-buffer))
+ (persp-read-buffer-hook))
+ (setq persp-read-buffer-hook
+ (lambda ()
+ (remove-hook 'minibuffer-setup-hook persp-read-buffer-hook)
+ (setq minibuffer-completion-table rb-completion-table)))
+ (unwind-protect
+ (progn
+ (add-hook 'minibuffer-setup-hook persp-read-buffer-hook t)
+ (read-buffer prompt def require-match))
+ (remove-hook 'minibuffer-setup-hook persp-read-buffer-hook)))))))
+
+(defun persp-complete-buffer ()
+ "Perform completion on all buffers within the current perspective."
+ (lexical-let ((persp-names (mapcar 'buffer-name (persp-buffers persp-curr))))
+ (apply-partially 'completion-table-with-predicate
+ (or minibuffer-completion-table 'internal-complete-buffer)
+ (lambda (name)
+ (member (if (consp name) (car name) name) persp-names))
+ nil)))
+
+(cl-defun persp-import (name &optional dont-switch)
+ "Import a perspective named NAME from another frame. If DONT-SWITCH
+is non-nil or with prefix arg, don't switch to the new perspective."
+ ;; TODO: Have some way of selecting which frame the perspective is imported from.
+ (interactive "i\nP")
+ (unless name
+ (setq name (funcall persp-interactive-completion-function
+ "Import perspective: " (persp-all-names (selected-frame)) nil t)))
+ (if (and (gethash name perspectives-hash)
+ (not (yes-or-no-p (concat "Perspective `" name "' already exits. Continue? "))))
+ (cl-return-from persp-import))
+ (let ((buffers (persp-all-get name (selected-frame)))
+ persp)
+ (if (null buffers)
+ (persp-error "Perspective `%s' doesn't exist in another frame" name))
+ (setq persp (make-persp :name name :buffers buffers
+ (switch-to-buffer (cl-loop for buffer in buffers
+ if (buffer-live-p buffer)
+ return buffer))
+ (delete-other-windows)))
+ (if dont-switch
+ (persp-update-modestring)
+ (persp-activate persp))))
+
+(defadvice switch-to-buffer (after persp-add-buffer-adv)
+ "Add BUFFER to the current perspective.
+
+See also `persp-add-buffer'."
+ (persp-protect
+ (let ((buf (ad-get-arg 0)))
+ (when buf
+ (persp-add-buffer buf)))))
+
+(defadvice display-buffer (after persp-add-buffer-adv)
+ "Add BUFFER to the perspective for the frame on which it's displayed.
+
+See also `persp-add-buffer'."
+ (persp-protect
+ (when ad-return-value
+ (let ((buf (ad-get-arg 0))
+ (frame (window-frame ad-return-value)))
+ (when (and buf frame)
+ (with-selected-frame frame
+ (persp-add-buffer buf)))))))
+
+(defadvice set-window-buffer (after persp-add-buffer-adv)
+ "Add BUFFER to the perspective for window's frame.
+
+See also `persp-add-buffer'."
+ (persp-protect
+ (let ((buf (ad-get-arg 1))
+ (frame (window-frame (ad-get-arg 0))))
+ (when (and buf frame)
+ (with-selected-frame frame
+ (persp-add-buffer buf))))))
+
+(defadvice switch-to-prev-buffer (around persp-ensure-buffer-in-persp)
+ "Ensure that the selected buffer is in WINDOW's perspective."
+ (let* ((window (window-normalize-window window t))
+ (frame (window-frame window))
+ (old-buffer (window-buffer window)))
+ ad-do-it
+
+ (let ((buffer (window-buffer window)))
+ (with-selected-frame frame
+ (unless (memq buffer (persp-buffers persp-curr))
+ ;; If a buffer from outside this perspective was selected, it's because
+ ;; this perspective is out of buffers. For lack of any better option, we
+ ;; recreate the scratch buffer.
+ ;;
+ ;; If we were just in a scratch buffer, change the name slightly.
+ ;; Otherwise our new buffer will get deleted too.
+ (let ((name (concat "*scratch* (" (persp-name persp-curr) ")")))
+ (when (and bury-or-kill (equal name (buffer-name old-buffer)))
+ (setq name (concat "*scratch* (" (persp-name persp-curr) ")")))
+ (with-selected-window window
+ (switch-to-buffer name)
+ (funcall initial-major-mode))))))))
+
+(defadvice recursive-edit (around persp-preserve-for-recursive-edit)
+ "Preserve the current perspective when entering a recursive edit."
+ (persp-protect
+ (persp-save)
+ (persp-frame-local-let ((persp-recursive persp-curr))
+ (let ((old-hash (copy-hash-table perspectives-hash)))
+ ad-do-it
+ ;; We want the buffer lists that were created in the recursive edit,
+ ;; but not the window configurations
+ (maphash (lambda (key new-persp)
+ (let ((persp (gethash key old-hash)))
+ (when persp
+ (setf (persp-buffers persp) (persp-buffers new-persp)))))
+ perspectives-hash)
+ (setq perspectives-hash old-hash)))))
+
+(defadvice exit-recursive-edit (before persp-restore-after-recursive-edit)
+ "Restore the old perspective when exiting a recursive edit."
+ (persp-protect
+ (if persp-recursive (persp-switch (persp-name persp-recursive)))))
+
+;;;###autoload
+(define-minor-mode persp-mode
+ "Toggle perspective mode.
+When active, keeps track of multiple 'perspectives',
+named collections of buffers and window configurations."
+ :global t
+ :keymap persp-mode-map
+ (if persp-mode
+ (persp-protect
+ (ad-activate 'switch-to-buffer)
+ (ad-activate 'display-buffer)
+ (ad-activate 'set-window-buffer)
+ (ad-activate 'switch-to-prev-buffer)
+ (ad-activate 'recursive-edit)
+ (ad-activate 'exit-recursive-edit)
+ (add-hook 'after-make-frame-functions 'persp-init-frame)
+ (add-hook 'ido-make-buffer-list-hook 'persp-set-ido-buffers)
+ (setq read-buffer-function 'persp-read-buffer)
+ (mapc 'persp-init-frame (frame-list))
+ (setf (persp-buffers persp-curr) (buffer-list))
+
+ (run-hooks 'persp-mode-hook))
+ (ad-deactivate-regexp "^persp-.*")
+ (remove-hook 'after-make-frame-functions 'persp-init-frame)
+ (remove-hook 'ido-make-buffer-list-hook 'persp-set-ido-buffers)
+ (setq read-buffer-function nil)
+ (setq perspectives-hash nil)
+ (setq global-mode-string (delq 'persp-modestring global-mode-string))))
+
+(defun persp-init-frame (frame)
+ "Initialize the perspectives system in FRAME.
+By default, this uses the current frame."
+ (with-selected-frame frame
+ (modify-frame-parameters
+ frame
+ '((perspectives-hash) (persp-curr) (persp-last) (persp-recursive) (persp-modestring)))
+
+ ;; Don't set these variables in modify-frame-parameters
+ ;; because that won't do anything if they've already been accessed
+ (setq perspectives-hash (make-hash-table :test 'equal :size 10))
+
+ (when persp-show-modestring
+ (if (eq persp-show-modestring 'header)
+ (let ((val (or (default-value 'header-line-format) '(""))))
+ (unless (memq 'persp-modestring val)
+ (set-default 'header-line-format (append val '(persp-modestring)))))
+ (setq global-mode-string (or global-mode-string '("")))
+ (unless (memq 'persp-modestring global-mode-string)
+ (setq global-mode-string (append global-mode-string '(persp-modestring)))))
+ (persp-update-modestring))
+
+ (persp-activate
+ (make-persp :name persp-initial-frame-name :buffers (list (current-buffer))
+ :window-configuration (current-window-configuration)
+ :point-marker (point-marker)))))
+
+(defun persp-make-variable-persp-local (variable)
+ "Make VARIABLE become perspective-local.
+This means that whenever a new perspective is switched into, the
+variable will take on its local value for that perspective. When
+a new perspective is created, the variable will inherit its value
+from the current perspective at time of creation."
+ (unless (assq variable (persp-local-variables persp-curr))
+ (let ((entry (list variable (symbol-value variable))))
+ (dolist (frame (frame-list))
+ (cl-loop for persp being the hash-values of (with-selected-frame frame perspectives-hash)
+ do (push entry (persp-local-variables persp)))))))
+
+(defmacro persp-setup-for (name &rest body)
+ "Add code that should be run to set up the perspective named NAME.
+Whenever a new perspective named NAME is created, runs BODY in
+it. In addition, if one exists already, runs BODY in it immediately."
+ (declare (indent 1))
+ `(progn
+ (add-hook 'persp-created-hook
+ (lambda ()
+ (when (string= (persp-name persp-curr) ,name)
+ ,@body))
+ 'append)
+ (when (gethash ,name perspectives-hash)
+ (with-perspective ,name ,@body))))
+
+(defun persp-set-ido-buffers ()
+ "Restrict the ido buffer to the current perspective."
+ (let ((persp-names
+ (remq nil (mapcar 'buffer-name (persp-buffers persp-curr))))
+ (indices (make-hash-table :test 'equal)))
+ (cl-loop for elt in ido-temp-list
+ for i upfrom 0
+ do (puthash elt i indices))
+ (setq ido-temp-list
+ (sort (intersection persp-names ido-temp-list)
+ (lambda (a b)
+ (< (gethash a indices)
+ (gethash b indices)))))))
+
+(defun quick-perspective-keys ()
+ "Bind quick key commands to switch to perspectives.
+All C-S-letter key combinations are bound to switch to the first
+perspective beginning with the given letter."
+ (cl-loop for c from ?a to ?z
+ do (define-key persp-mode-map
+ (read-kbd-macro (concat "C-S-" (string c)))
+ `(lambda ()
+ (interactive)
+ (persp-switch-quick ,c)))))
+
+(defun persp-turn-off-modestring ()
+ "Deactivate the perspective modestring."
+ (interactive)
+ (setq persp-modestring nil)
+ (setq persp-show-modestring nil))
+
+(defun persp-turn-on-modestring ()
+ "Activate the perspective modestring."
+ (interactive)
+ (setq persp-show-modestring t)
+ (persp-update-modestring))
+
+(provide 'perspective)
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; perspective.el ends here
.emacs.d/elpa/perspective-20160609.1444/perspective.elc
Binary file
.emacs.d/elpa/pkg-info-20150517.443/pkg-info-autoloads.el
@@ -0,0 +1,122 @@
+;;; pkg-info-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
+
+;;;### (autoloads nil "pkg-info" "pkg-info.el" (22977 30123 659702
+;;;;;; 70000))
+;;; Generated autoloads from pkg-info.el
+
+(autoload 'pkg-info-library-original-version "pkg-info" "\
+Get the original version in the header of LIBRARY.
+
+The original version is stored in the X-Original-Version header.
+This header is added by the MELPA package archive to preserve
+upstream version numbers.
+
+LIBRARY is either a symbol denoting a named feature, or a library
+name as string.
+
+If SHOW is non-nil, show the version in the minibuffer.
+
+Return the version from the header of LIBRARY as list. Signal an
+error if the LIBRARY was not found or had no X-Original-Version
+header.
+
+See Info node `(elisp)Library Headers' for more information
+about library headers.
+
+\(fn LIBRARY &optional SHOW)" t nil)
+
+(autoload 'pkg-info-library-version "pkg-info" "\
+Get the version in the header of LIBRARY.
+
+LIBRARY is either a symbol denoting a named feature, or a library
+name as string.
+
+If SHOW is non-nil, show the version in the minibuffer.
+
+Return the version from the header of LIBRARY as list. Signal an
+error if the LIBRARY was not found or had no proper header.
+
+See Info node `(elisp)Library Headers' for more information
+about library headers.
+
+\(fn LIBRARY &optional SHOW)" t nil)
+
+(autoload 'pkg-info-defining-library-original-version "pkg-info" "\
+Get the original version of the library defining FUNCTION.
+
+The original version is stored in the X-Original-Version header.
+This header is added by the MELPA package archive to preserve
+upstream version numbers.
+
+If SHOW is non-nil, show the version in mini-buffer.
+
+This function is mainly intended to find the version of a major
+or minor mode, i.e.
+
+ (pkg-info-defining-library-version 'flycheck-mode)
+
+Return the version of the library defining FUNCTION. Signal an
+error if FUNCTION is not a valid function, if its defining
+library was not found, or if the library had no proper version
+header.
+
+\(fn FUNCTION &optional SHOW)" t nil)
+
+(autoload 'pkg-info-defining-library-version "pkg-info" "\
+Get the version of the library defining FUNCTION.
+
+If SHOW is non-nil, show the version in mini-buffer.
+
+This function is mainly intended to find the version of a major
+or minor mode, i.e.
+
+ (pkg-info-defining-library-version 'flycheck-mode)
+
+Return the version of the library defining FUNCTION. Signal an
+error if FUNCTION is not a valid function, if its defining
+library was not found, or if the library had no proper version
+header.
+
+\(fn FUNCTION &optional SHOW)" t nil)
+
+(autoload 'pkg-info-package-version "pkg-info" "\
+Get the version of an installed PACKAGE.
+
+If SHOW is non-nil, show the version in the minibuffer.
+
+Return the version as list, or nil if PACKAGE is not installed.
+
+\(fn PACKAGE &optional SHOW)" t nil)
+
+(autoload 'pkg-info-version-info "pkg-info" "\
+Obtain complete version info for LIBRARY and PACKAGE.
+
+LIBRARY is a symbol denoting a named feature, or a library name
+as string. PACKAGE is a symbol denoting an ELPA package. If
+omitted or nil, default to LIBRARY.
+
+If SHOW is non-nil, show the version in the minibuffer.
+
+When called interactively, prompt for LIBRARY. When called
+interactively with prefix argument, prompt for PACKAGE as well.
+
+Return a string with complete version information for LIBRARY.
+This version information contains the version from the headers of
+LIBRARY, and the version of the installed PACKAGE, the LIBRARY is
+part of. If PACKAGE is not installed, or if the PACKAGE version
+is the same as the LIBRARY version, do not include a package
+version.
+
+\(fn LIBRARY &optional PACKAGE SHOW)" t nil)
+
+;;;***
+
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+;;; pkg-info-autoloads.el ends here
.emacs.d/elpa/pkg-info-20150517.443/pkg-info-pkg.el
@@ -0,0 +1,2 @@
+;;; -*- no-byte-compile: t -*-
+(define-package "pkg-info" "20150517.443" "Information about packages" '((epl "0.8")) :commit "76ba7415480687d05a4353b27fea2ae02b8d9d61" :url "https://github.com/lunaryorn/pkg-info.el" :keywords '("convenience"))
.emacs.d/elpa/pkg-info-20150517.443/pkg-info.el
@@ -0,0 +1,331 @@
+;;; pkg-info.el --- Information about packages -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2013-2015 Sebastian Wiesner <swiesner@lunaryorn.com>
+
+;; Author: Sebastian Wiesner <swiesner@lunaryorn.com>
+;; URL: https://github.com/lunaryorn/pkg-info.el
+;; Package-Version: 20150517.443
+;; Keywords: convenience
+;; Version: 0.7-cvs
+;; Package-Requires: ((epl "0.8"))
+
+;; This file is not part of GNU Emacs.
+
+;; 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 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library extracts information from installed packages.
+
+;;;; Functions:
+
+;; `pkg-info-library-version' extracts the version from the header of a library.
+;;
+;; `pkg-info-defining-library-version' extracts the version from the header of a
+;; library defining a function.
+;;
+;; `pkg-info-package-version' gets the version of an installed package.
+;;
+;; `pkg-info-format-version' formats a version list as human readable string.
+;;
+;; `pkg-info-version-info' returns complete version information for a specific
+;; package.
+;;
+;; `pkg-info-get-melpa-recipe' gets the MELPA recipe for a package.
+;;
+;; `pkg-info-get-melpa-fetcher' gets the fetcher used to build a package on
+;; MELPA.
+;;
+;; `pkg-info-wiki-package-p' determines whether a package was build from
+;; EmacsWiki on MELPA.
+
+;;; Code:
+
+(require 'epl)
+
+(require 'lisp-mnt)
+(require 'find-func)
+(require 'json) ; `json-read'
+(require 'url-http) ; `url-http-parse-response'
+
+(defvar url-http-end-of-headers)
+
+
+;;; Version information
+(defun pkg-info-format-version (version)
+ "Format VERSION as human-readable string.
+
+Return a human-readable string representing VERSION."
+ ;; XXX: Find a better, more flexible way of formatting?
+ (package-version-join version))
+
+(defsubst pkg-info--show-version-and-return (version show)
+ "Show and return VERSION.
+
+When SHOW is non-nil, show VERSION in minibuffer.
+
+Return VERSION."
+ (when show
+ (message (if (listp version) (pkg-info-format-version version) version)))
+ version)
+
+(defun pkg-info--read-library ()
+ "Read a library from minibuffer."
+ (completing-read "Load library: "
+ (apply-partially 'locate-file-completion-table
+ load-path
+ (get-load-suffixes))))
+
+(defun pkg-info--read-function ()
+ "Read a function name from minibuffer."
+ (let ((input (completing-read "Function: " obarray #'boundp :require-match)))
+ (if (string= input "") nil (intern input))))
+
+(defun pkg-info--read-package ()
+ "Read a package name from minibuffer."
+ (let* ((installed (epl-installed-packages))
+ (names (sort (mapcar (lambda (pkg)
+ (symbol-name (epl-package-name pkg)))
+ installed)
+ #'string<))
+ (default (car names)))
+ (completing-read "Installed package: " names nil 'require-match
+ nil nil default)))
+
+(defun pkg-info-library-source (library)
+ "Get the source file of LIBRARY.
+
+LIBRARY is either a symbol denoting a named feature, or a library
+name as string.
+
+Return the source file of LIBRARY as string."
+ (find-library-name (if (symbolp library) (symbol-name library) library)))
+
+(defun pkg-info-defining-library (function)
+ "Get the source file of the library defining FUNCTION.
+
+FUNCTION is a function symbol.
+
+Return the file name of the library as string. Signal an error
+if the library does not exist, or if the definition of FUNCTION
+was not found."
+ (unless (functionp function)
+ (signal 'wrong-type-argument (list 'functionp function)))
+ (let ((library (symbol-file function 'defun)))
+ (unless library
+ (error "Can't find definition of %s" function))
+ library))
+
+(defun pkg-info-x-original-version (file)
+ "Read the X-Original-Version header from FILE.
+
+Return the value as version list, or return nil if FILE lacks
+this header. Signal an error, if the value of the header is not
+a valid version."
+ (let ((version-str (with-temp-buffer
+ (insert-file-contents file)
+ (lm-header "X-Original-Version"))))
+ (when version-str
+ (version-to-list version-str))))
+
+;;;###autoload
+(defun pkg-info-library-original-version (library &optional show)
+ "Get the original version in the header of LIBRARY.
+
+The original version is stored in the X-Original-Version header.
+This header is added by the MELPA package archive to preserve
+upstream version numbers.
+
+LIBRARY is either a symbol denoting a named feature, or a library
+name as string.
+
+If SHOW is non-nil, show the version in the minibuffer.
+
+Return the version from the header of LIBRARY as list. Signal an
+error if the LIBRARY was not found or had no X-Original-Version
+header.
+
+See Info node `(elisp)Library Headers' for more information
+about library headers."
+ (interactive (list (pkg-info--read-library) t))
+ (let ((version (pkg-info-x-original-version
+ (pkg-info-library-source library))))
+ (if version
+ (pkg-info--show-version-and-return version show)
+ (error "Library %s has no original version" library))))
+
+;;;###autoload
+(defun pkg-info-library-version (library &optional show)
+ "Get the version in the header of LIBRARY.
+
+LIBRARY is either a symbol denoting a named feature, or a library
+name as string.
+
+If SHOW is non-nil, show the version in the minibuffer.
+
+Return the version from the header of LIBRARY as list. Signal an
+error if the LIBRARY was not found or had no proper header.
+
+See Info node `(elisp)Library Headers' for more information
+about library headers."
+ (interactive (list (pkg-info--read-library) t))
+ (let* ((source (pkg-info-library-source library))
+ (version (epl-package-version (epl-package-from-file source))))
+ (pkg-info--show-version-and-return version show)))
+
+;;;###autoload
+(defun pkg-info-defining-library-original-version (function &optional show)
+ "Get the original version of the library defining FUNCTION.
+
+The original version is stored in the X-Original-Version header.
+This header is added by the MELPA package archive to preserve
+upstream version numbers.
+
+If SHOW is non-nil, show the version in mini-buffer.
+
+This function is mainly intended to find the version of a major
+or minor mode, i.e.
+
+ (pkg-info-defining-library-version 'flycheck-mode)
+
+Return the version of the library defining FUNCTION. Signal an
+error if FUNCTION is not a valid function, if its defining
+library was not found, or if the library had no proper version
+header."
+ (interactive (list (pkg-info--read-function) t))
+ (pkg-info-library-original-version (pkg-info-defining-library function) show))
+
+;;;###autoload
+(defun pkg-info-defining-library-version (function &optional show)
+ "Get the version of the library defining FUNCTION.
+
+If SHOW is non-nil, show the version in mini-buffer.
+
+This function is mainly intended to find the version of a major
+or minor mode, i.e.
+
+ (pkg-info-defining-library-version 'flycheck-mode)
+
+Return the version of the library defining FUNCTION. Signal an
+error if FUNCTION is not a valid function, if its defining
+library was not found, or if the library had no proper version
+header."
+ (interactive (list (pkg-info--read-function) t))
+ (pkg-info-library-version (pkg-info-defining-library function) show))
+
+;;;###autoload
+(defun pkg-info-package-version (package &optional show)
+ "Get the version of an installed PACKAGE.
+
+If SHOW is non-nil, show the version in the minibuffer.
+
+Return the version as list, or nil if PACKAGE is not installed."
+ (interactive (list (pkg-info--read-package) t))
+ (let* ((name (if (stringp package) (intern package) package))
+ (package (car (epl-find-installed-packages name))))
+ (unless package
+ (error "Can't find installed package %s" name))
+ (pkg-info--show-version-and-return (epl-package-version package) show)))
+
+;;;###autoload
+(defun pkg-info-version-info (library &optional package show)
+ "Obtain complete version info for LIBRARY and PACKAGE.
+
+LIBRARY is a symbol denoting a named feature, or a library name
+as string. PACKAGE is a symbol denoting an ELPA package. If
+omitted or nil, default to LIBRARY.
+
+If SHOW is non-nil, show the version in the minibuffer.
+
+When called interactively, prompt for LIBRARY. When called
+interactively with prefix argument, prompt for PACKAGE as well.
+
+Return a string with complete version information for LIBRARY.
+This version information contains the version from the headers of
+LIBRARY, and the version of the installed PACKAGE, the LIBRARY is
+part of. If PACKAGE is not installed, or if the PACKAGE version
+is the same as the LIBRARY version, do not include a package
+version."
+ (interactive (list (pkg-info--read-library)
+ (when current-prefix-arg
+ (pkg-info--read-package))
+ t))
+ (let* ((package (or package (if (stringp library) (intern library) library)))
+ (orig-version (condition-case nil
+ (pkg-info-library-original-version library)
+ (error nil)))
+ ;; If we have X-Original-Version, we assume that MELPA replaced the
+ ;; library version with its generated version, so we use the
+ ;; X-Original-Version header instead, and ignore the library version
+ ;; header
+ (lib-version (or orig-version (pkg-info-library-version library)))
+ (pkg-version (condition-case nil
+ (pkg-info-package-version package)
+ (error nil)))
+ (version (if (and pkg-version
+ (not (version-list-= lib-version pkg-version)))
+ (format "%s (package: %s)"
+ (pkg-info-format-version lib-version)
+ (pkg-info-format-version pkg-version))
+ (pkg-info-format-version lib-version))))
+ (pkg-info--show-version-and-return version show)))
+
+(defconst pkg-info-melpa-recipe-url "http://melpa.org/recipes.json"
+ "The URL from which to fetch MELPA recipes.")
+
+(defvar pkg-info-melpa-recipes nil
+ "An alist of MELPA recipes.")
+
+(defun pkg-info-retrieve-melpa-recipes ()
+ "Retrieve MELPA recipes from MELPA archive."
+ (let ((buffer (url-retrieve-synchronously pkg-info-melpa-recipe-url)))
+ (with-current-buffer buffer
+ (unwind-protect
+ (let ((response-code (url-http-parse-response)))
+ (unless (equal response-code 200)
+ (error "Failed to retrieve MELPA recipes from %s (code %s)"
+ pkg-info-melpa-recipe-url response-code))
+ (goto-char url-http-end-of-headers)
+ (json-read))
+ (when (and buffer (buffer-live-p buffer))
+ (kill-buffer buffer))))))
+
+(defun pkg-info-get-melpa-recipes ()
+ "Get MELPA recipes."
+ (setq pkg-info-melpa-recipes
+ (or pkg-info-melpa-recipes
+ (pkg-info-retrieve-melpa-recipes))))
+
+(defun pkg-info-get-melpa-recipe (package)
+ "Get the MELPA recipe for PACKAGE.
+
+Return nil if PACKAGE is not on MELPA."
+ (cdr (assq package (pkg-info-get-melpa-recipes))))
+
+(defun pkg-info-get-melpa-fetcher (package)
+ "Get the MELPA fetcher for PACKAGE."
+ (cdr (assq 'fetcher (pkg-info-get-melpa-recipe package))))
+
+(defun pkg-info-wiki-package-p (package)
+ "Determine whether PACKAGE is build from the EmacsWiki."
+ (equal (pkg-info-get-melpa-fetcher package) "wiki"))
+
+(provide 'pkg-info)
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; coding: utf-8
+;; End:
+
+;;; pkg-info.el ends here
.emacs.d/elpa/pkg-info-20150517.443/pkg-info.elc
Binary file
.emacs.d/elpa/projectile-20170917.410/projectile-autoloads.el
@@ -0,0 +1,514 @@
+;;; projectile-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
+
+;;;### (autoloads nil "projectile" "projectile.el" (22977 30125 558683
+;;;;;; 305000))
+;;; Generated autoloads from projectile.el
+
+(autoload 'projectile-version "projectile" "\
+Get the Projectile version as string.
+
+If called interactively or if SHOW-VERSION is non-nil, show the
+version in the echo area and the messages buffer.
+
+The returned string includes both, the version from package.el
+and the library version, if both a present and different.
+
+If the version number could not be determined, signal an error,
+if called interactively, or if SHOW-VERSION is non-nil, otherwise
+just return nil.
+
+\(fn &optional SHOW-VERSION)" t nil)
+
+(autoload 'projectile-invalidate-cache "projectile" "\
+Remove the current project's files from `projectile-projects-cache'.
+
+With a prefix argument ARG prompts for the name of the project whose cache
+to invalidate.
+
+\(fn ARG)" t nil)
+
+(autoload 'projectile-purge-file-from-cache "projectile" "\
+Purge FILE from the cache of the current project.
+
+\(fn FILE)" t nil)
+
+(autoload 'projectile-purge-dir-from-cache "projectile" "\
+Purge DIR from the cache of the current project.
+
+\(fn DIR)" t nil)
+
+(autoload 'projectile-cache-current-file "projectile" "\
+Add the currently visited file to the cache.
+
+\(fn)" t nil)
+
+(autoload 'projectile-discover-projects-in-directory "projectile" "\
+Discover any projects in DIRECTORY and add them to the projectile cache.
+This function is not recursive and only adds projects with roots
+at the top level of DIRECTORY.
+
+\(fn DIRECTORY)" t nil)
+
+(autoload 'projectile-switch-to-buffer "projectile" "\
+Switch to a project buffer.
+
+\(fn)" t nil)
+
+(autoload 'projectile-switch-to-buffer-other-window "projectile" "\
+Switch to a project buffer and show it in another window.
+
+\(fn)" t nil)
+
+(autoload 'projectile-switch-to-buffer-other-frame "projectile" "\
+Switch to a project buffer and show it in another window.
+
+\(fn)" t nil)
+
+(autoload 'projectile-display-buffer "projectile" "\
+Display a project buffer in another window without selecting it.
+
+\(fn)" t nil)
+
+(autoload 'projectile-project-buffers-other-buffer "projectile" "\
+Switch to the most recently selected buffer project buffer.
+Only buffers not visible in windows are returned.
+
+\(fn)" t nil)
+
+(autoload 'projectile-multi-occur "projectile" "\
+Do a `multi-occur' in the project's buffers.
+With a prefix argument, show NLINES of context.
+
+\(fn &optional NLINES)" t nil)
+
+(autoload 'projectile-find-other-file "projectile" "\
+Switch between files with the same name but different extensions.
+With FLEX-MATCHING, match any file that contains the base name of current file.
+Other file extensions can be customized with the variable `projectile-other-file-alist'.
+
+\(fn &optional FLEX-MATCHING)" t nil)
+
+(autoload 'projectile-find-other-file-other-window "projectile" "\
+Switch between files with the same name but different extensions in other window.
+With FLEX-MATCHING, match any file that contains the base name of current file.
+Other file extensions can be customized with the variable `projectile-other-file-alist'.
+
+\(fn &optional FLEX-MATCHING)" t nil)
+
+(autoload 'projectile-find-other-file-other-frame "projectile" "\
+Switch between files with the same name but different extensions in other window.
+With FLEX-MATCHING, match any file that contains the base name of current file.
+Other file extensions can be customized with the variable `projectile-other-file-alist'.
+
+\(fn &optional FLEX-MATCHING)" t nil)
+
+(autoload 'projectile-find-file-dwim "projectile" "\
+Jump to a project's files using completion based on context.
+
+With a prefix ARG invalidates the cache first.
+
+If point is on a filename, Projectile first tries to search for that
+file in project:
+
+- If it finds just a file, it switches to that file instantly. This works even
+if the filename is incomplete, but there's only a single file in the current project
+that matches the filename at point. For example, if there's only a single file named
+\"projectile/projectile.el\" but the current filename is \"projectile/proj\" (incomplete),
+`projectile-find-file-dwim' still switches to \"projectile/projectile.el\" immediately
+ because this is the only filename that matches.
+
+- If it finds a list of files, the list is displayed for selecting. A list of
+files is displayed when a filename appears more than one in the project or the
+filename at point is a prefix of more than two files in a project. For example,
+if `projectile-find-file-dwim' is executed on a filepath like \"projectile/\", it lists
+the content of that directory. If it is executed on a partial filename like
+ \"projectile/a\", a list of files with character 'a' in that directory is presented.
+
+- If it finds nothing, display a list of all files in project for selecting.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'projectile-find-file-dwim-other-window "projectile" "\
+Jump to a project's files using completion based on context in other window.
+
+With a prefix ARG invalidates the cache first.
+
+If point is on a filename, Projectile first tries to search for that
+file in project:
+
+- If it finds just a file, it switches to that file instantly. This works even
+if the filename is incomplete, but there's only a single file in the current project
+that matches the filename at point. For example, if there's only a single file named
+\"projectile/projectile.el\" but the current filename is \"projectile/proj\" (incomplete),
+`projectile-find-file-dwim-other-window' still switches to \"projectile/projectile.el\"
+immediately because this is the only filename that matches.
+
+- If it finds a list of files, the list is displayed for selecting. A list of
+files is displayed when a filename appears more than one in the project or the
+filename at point is a prefix of more than two files in a project. For example,
+if `projectile-find-file-dwim-other-window' is executed on a filepath like \"projectile/\", it lists
+the content of that directory. If it is executed on a partial filename
+like \"projectile/a\", a list of files with character 'a' in that directory
+is presented.
+
+- If it finds nothing, display a list of all files in project for selecting.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'projectile-find-file-dwim-other-frame "projectile" "\
+Jump to a project's files using completion based on context in other frame.
+
+With a prefix ARG invalidates the cache first.
+
+If point is on a filename, Projectile first tries to search for that
+file in project:
+
+- If it finds just a file, it switches to that file instantly. This works even
+if the filename is incomplete, but there's only a single file in the current project
+that matches the filename at point. For example, if there's only a single file named
+\"projectile/projectile.el\" but the current filename is \"projectile/proj\" (incomplete),
+`projectile-find-file-dwim-other-frame' still switches to \"projectile/projectile.el\"
+immediately because this is the only filename that matches.
+
+- If it finds a list of files, the list is displayed for selecting. A list of
+files is displayed when a filename appears more than one in the project or the
+filename at point is a prefix of more than two files in a project. For example,
+if `projectile-find-file-dwim-other-frame' is executed on a filepath like \"projectile/\", it lists
+the content of that directory. If it is executed on a partial filename
+like \"projectile/a\", a list of files with character 'a' in that directory
+is presented.
+
+- If it finds nothing, display a list of all files in project for selecting.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'projectile-find-file "projectile" "\
+Jump to a project's file using completion.
+With a prefix ARG invalidates the cache first.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'projectile-find-file-other-window "projectile" "\
+Jump to a project's file using completion and show it in another window.
+
+With a prefix ARG invalidates the cache first.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'projectile-find-file-other-frame "projectile" "\
+Jump to a project's file using completion and show it in another frame.
+
+With a prefix ARG invalidates the cache first.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'projectile-find-dir "projectile" "\
+Jump to a project's directory using completion.
+
+With a prefix ARG invalidates the cache first.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'projectile-find-dir-other-window "projectile" "\
+Jump to a project's directory in other window using completion.
+
+With a prefix ARG invalidates the cache first.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'projectile-find-dir-other-frame "projectile" "\
+Jump to a project's directory in other window using completion.
+
+With a prefix ARG invalidates the cache first.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'projectile-find-test-file "projectile" "\
+Jump to a project's test file using completion.
+
+With a prefix ARG invalidates the cache first.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'projectile-project-info "projectile" "\
+Display info for current project.
+
+\(fn)" t nil)
+
+(autoload 'projectile-find-implementation-or-test-other-window "projectile" "\
+Open matching implementation or test file in other window.
+
+\(fn)" t nil)
+
+(autoload 'projectile-find-implementation-or-test-other-frame "projectile" "\
+Open matching implementation or test file in other frame.
+
+\(fn)" t nil)
+
+(autoload 'projectile-toggle-between-implementation-and-test "projectile" "\
+Toggle between an implementation file and its test file.
+
+\(fn)" t nil)
+
+(autoload 'projectile-grep "projectile" "\
+Perform rgrep in the project.
+
+With a prefix ARG asks for files (globbing-aware) which to grep in.
+With prefix ARG of `-' (such as `M--'), default the files (without prompt),
+to `projectile-grep-default-files'.
+
+With REGEXP given, don't query the user for a regexp.
+
+\(fn &optional REGEXP ARG)" t nil)
+
+(autoload 'projectile-ag "projectile" "\
+Run an ag search with SEARCH-TERM in the project.
+
+With an optional prefix argument ARG SEARCH-TERM is interpreted as a
+regular expression.
+
+\(fn SEARCH-TERM &optional ARG)" t nil)
+
+(autoload 'projectile-regenerate-tags "projectile" "\
+Regenerate the project's [e|g]tags.
+
+\(fn)" t nil)
+
+(autoload 'projectile-find-tag "projectile" "\
+Find tag in project.
+
+\(fn)" t nil)
+
+(autoload 'projectile-run-command-in-root "projectile" "\
+Invoke `execute-extended-command' in the project's root.
+
+\(fn)" t nil)
+
+(autoload 'projectile-run-shell-command-in-root "projectile" "\
+Invoke `shell-command' in the project's root.
+
+\(fn)" t nil)
+
+(autoload 'projectile-run-async-shell-command-in-root "projectile" "\
+Invoke `async-shell-command' in the project's root.
+
+\(fn)" t nil)
+
+(autoload 'projectile-run-shell "projectile" "\
+Invoke `shell' in the project's root.
+
+\(fn)" t nil)
+
+(autoload 'projectile-run-eshell "projectile" "\
+Invoke `eshell' in the project's root.
+
+\(fn)" t nil)
+
+(autoload 'projectile-run-term "projectile" "\
+Invoke `term' in the project's root.
+
+\(fn PROGRAM)" t nil)
+
+(autoload 'projectile-replace "projectile" "\
+Replace literal string in project using non-regexp `tags-query-replace'.
+
+With a prefix argument ARG prompts you for a directory on which
+to run the replacement.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'projectile-replace-regexp "projectile" "\
+Replace a regexp in the project using `tags-query-replace'.
+
+With a prefix argument ARG prompts you for a directory on which
+to run the replacement.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'projectile-kill-buffers "projectile" "\
+Kill all project buffers.
+
+\(fn)" t nil)
+
+(autoload 'projectile-save-project-buffers "projectile" "\
+Save all project buffers.
+
+\(fn)" t nil)
+
+(autoload 'projectile-dired "projectile" "\
+Open `dired' at the root of the project.
+
+\(fn)" t nil)
+
+(autoload 'projectile-dired-other-window "projectile" "\
+Open `dired' at the root of the project in another window.
+
+\(fn)" t nil)
+
+(autoload 'projectile-dired-other-frame "projectile" "\
+Open `dired' at the root of the project in another frame.
+
+\(fn)" t nil)
+
+(autoload 'projectile-vc "projectile" "\
+Open `vc-dir' at the root of the project.
+
+For git projects `magit-status-internal' is used if available.
+For hg projects `monky-status' is used if available.
+
+\(fn &optional PROJECT-ROOT)" t nil)
+
+(autoload 'projectile-recentf "projectile" "\
+Show a list of recently visited files in a project.
+
+\(fn)" t nil)
+
+(autoload 'projectile-compile-project "projectile" "\
+Run project compilation command.
+
+Normally you'll be prompted for a compilation command, unless
+variable `compilation-read-command'. You can force the prompt
+with a prefix ARG.
+
+\(fn ARG &optional DIR)" t nil)
+
+(autoload 'projectile-test-project "projectile" "\
+Run project test command.
+
+Normally you'll be prompted for a compilation command, unless
+variable `compilation-read-command'. You can force the prompt
+with a prefix ARG.
+
+\(fn ARG)" t nil)
+
+(autoload 'projectile-run-project "projectile" "\
+Run project run command.
+
+Normally you'll be prompted for a compilation command, unless
+variable `compilation-read-command'. You can force the prompt
+with a prefix ARG.
+
+\(fn ARG)" t nil)
+
+(autoload 'projectile-switch-project "projectile" "\
+Switch to a project we have visited before.
+Invokes the command referenced by `projectile-switch-project-action' on switch.
+With a prefix ARG invokes `projectile-commander' instead of
+`projectile-switch-project-action.'
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'projectile-switch-open-project "projectile" "\
+Switch to a project we have currently opened.
+Invokes the command referenced by `projectile-switch-project-action' on switch.
+With a prefix ARG invokes `projectile-commander' instead of
+`projectile-switch-project-action.'
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'projectile-find-file-in-directory "projectile" "\
+Jump to a file in a (maybe regular) DIRECTORY.
+
+This command will first prompt for the directory the file is in.
+
+\(fn &optional DIRECTORY)" t nil)
+
+(autoload 'projectile-find-file-in-known-projects "projectile" "\
+Jump to a file in any of the known projects.
+
+\(fn)" t nil)
+
+(autoload 'projectile-cleanup-known-projects "projectile" "\
+Remove known projects that don't exist anymore.
+
+\(fn)" t nil)
+
+(autoload 'projectile-clear-known-projects "projectile" "\
+Clear both `projectile-known-projects' and `projectile-known-projects-file'.
+
+\(fn)" t nil)
+
+(autoload 'projectile-remove-known-project "projectile" "\
+Remove PROJECT from the list of known projects.
+
+\(fn &optional PROJECT)" t nil)
+
+(autoload 'projectile-remove-current-project-from-known-projects "projectile" "\
+Remove the current project from the list of known projects.
+
+\(fn)" t nil)
+
+(autoload 'projectile-ibuffer "projectile" "\
+Open an IBuffer window showing all buffers in the current project.
+
+Let user choose another project when PREFIX is supplied.
+
+\(fn PREFIX)" t nil)
+
+(autoload 'projectile-commander "projectile" "\
+Execute a Projectile command with a single letter.
+The user is prompted for a single character indicating the action to invoke.
+The `?' character describes then
+available actions.
+
+See `def-projectile-commander-method' for defining new methods.
+
+\(fn)" t nil)
+
+(autoload 'projectile-edit-dir-locals "projectile" "\
+Edit or create a .dir-locals.el file of the project.
+
+\(fn)" t nil)
+
+(defvar projectile-mode-line '(:eval (format " Projectile[%s]" (projectile-project-name))) "\
+Mode line lighter for Projectile.
+
+The value of this variable is a mode line template as in
+`mode-line-format'. See Info Node `(elisp)Mode Line Format' for
+details about mode line templates.
+
+Customize this variable to change how Projectile displays its
+status in the mode line. The default value displays the project
+name. Set this variable to nil to disable the mode line
+entirely.")
+
+(custom-autoload 'projectile-mode-line "projectile" t)
+
+(defvar projectile-mode nil "\
+Non-nil if Projectile mode is enabled.
+See the `projectile-mode' command
+for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `projectile-mode'.")
+
+(custom-autoload 'projectile-mode "projectile" nil)
+
+(autoload 'projectile-mode "projectile" "\
+Minor mode to assist project management and navigation.
+
+When called interactively, toggle `projectile-mode'. With prefix
+ARG, enable `projectile-mode' if ARG is positive, otherwise disable
+it.
+
+When called from Lisp, enable `projectile-mode' if ARG is omitted,
+nil or positive. If ARG is `toggle', toggle `projectile-mode'.
+Otherwise behave as if called interactively.
+
+\\{projectile-mode-map}
+
+\(fn &optional ARG)" t nil)
+
+(define-obsolete-function-alias 'projectile-global-mode 'projectile-mode)
+
+;;;***
+
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+;;; projectile-autoloads.el ends here
.emacs.d/elpa/projectile-20170917.410/projectile-pkg.el
@@ -0,0 +1,2 @@
+;;; -*- no-byte-compile: t -*-
+(define-package "projectile" "20170917.410" "Manage and navigate projects in Emacs easily" '((emacs "24.1") (pkg-info "0.4")) :commit "e4bbeef993a1642c6ef197e0f76f11faced5f133" :url "https://github.com/bbatsov/projectile" :keywords '("project" "convenience"))
.emacs.d/elpa/projectile-20170917.410/projectile.el
@@ -0,0 +1,3860 @@
+;;; projectile.el --- Manage and navigate projects in Emacs easily -*- lexical-binding: t -*-
+
+;; Copyright ยฉ 2011-2017 Bozhidar Batsov <bozhidar@batsov.com>
+
+;; Author: Bozhidar Batsov <bozhidar@batsov.com>
+;; URL: https://github.com/bbatsov/projectile
+;; Package-Version: 20170917.410
+;; Keywords: project, convenience
+;; Version: 0.15.0-cvs
+;; Package-Requires: ((emacs "24.1") (pkg-info "0.4"))
+
+;; This file is NOT part of GNU Emacs.
+
+;; 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:
+;;
+;; This library provides easy project management and navigation. The
+;; concept of a project is pretty basic - just a folder containing
+;; special file. Currently git, mercurial and bazaar repos are
+;; considered projects by default. If you want to mark a folder
+;; manually as a project just create an empty .projectile file in
+;; it. See the README for more details.
+;;
+;;; Code:
+
+(require 'cl-lib)
+(require 'thingatpt)
+(require 'ibuffer)
+(require 'ibuf-ext)
+(require 'compile)
+(require 'grep)
+
+(eval-when-compile
+ (defvar ag-ignore-list)
+ (defvar ggtags-completion-table)
+ (defvar tags-completion-table)
+ (defvar tags-loop-scan)
+ (defvar tags-loop-operate)
+ (defvar eshell-buffer-name)
+ (defvar explicit-shell-file-name))
+
+(declare-function ggtags-ensure-project "ggtags")
+(declare-function ggtags-update-tags "ggtags")
+(declare-function pkg-info-version-info "pkg-info")
+(declare-function tags-completion-table "etags")
+(declare-function make-term "term")
+(declare-function term-mode "term")
+(declare-function term-char-mode "term")
+
+(defvar grep-files-aliases)
+(defvar grep-find-ignored-directories)
+(defvar grep-find-ignored-files)
+
+;;;; Compatibility
+(eval-and-compile
+ ;; Added in Emacs 24.3.
+ (unless (fboundp 'defvar-local)
+ (defmacro defvar-local (var val &optional docstring)
+ "Define VAR as a buffer-local variable with default value VAL.
+Like `defvar' but additionally marks the variable as being automatically
+buffer-local wherever it is set."
+ (declare (debug defvar) (doc-string 3))
+ `(progn
+ (defvar ,var ,val ,docstring)
+ (make-variable-buffer-local ',var))))
+
+ ;; Added in Emacs 24.4
+ (unless (fboundp 'string-suffix-p)
+ (defun string-suffix-p (suffix string &optional ignore-case)
+ "Return non-nil if SUFFIX is a suffix of STRING.
+If IGNORE-CASE is non-nil, the comparison is done without paying
+attention to case differences."
+ (let ((start-pos (- (length string) (length suffix))))
+ (and (>= start-pos 0)
+ (eq t (compare-strings suffix nil nil
+ string start-pos nil ignore-case))))))
+
+ ;; Improved (no more stack overflows) in Emacs 24.5
+ (eval-after-load 'etags
+ '(when (< emacs-major-version 25)
+ (defvar etags--table-line-limit 500)
+ (defun etags-tags-completion-table ()
+ (let ((table (make-vector 511 0))
+ (progress-reporter
+ (make-progress-reporter
+ (format "Making tags completion table for %s..." buffer-file-name)
+ (point-min) (point-max))))
+ (save-excursion
+ (goto-char (point-min))
+ (while (not (eobp))
+ (if (not (re-search-forward
+ "[\f\t\n\r()=,; ]?\177\\\(?:\\([^\n\001]+\\)\001\\)?"
+ (+ (point) etags--table-line-limit) t))
+ (forward-line 1)
+ (intern (prog1 (if (match-beginning 1)
+ (buffer-substring (match-beginning 1) (match-end 1))
+ (goto-char (match-beginning 0))
+ (skip-chars-backward "^\f\t\n\r()=,; ")
+ (prog1
+ (buffer-substring (point) (match-beginning 0))
+ (goto-char (match-end 0))))
+ (progress-reporter-update progress-reporter (point)))
+ table))))
+ table)))))
+
+(defun projectile-trim-string (string)
+ "Remove whitespace at the beginning and end of STRING."
+ (replace-regexp-in-string
+ "[ \n\r]+\\'"
+ ""
+ (replace-regexp-in-string
+ "\\`[ \n\r]+"
+ ""
+ string)))
+
+
+;;; Customization
+(defgroup projectile nil
+ "Manage and navigate projects easily."
+ :group 'tools
+ :group 'convenience
+ :link '(url-link :tag "Github" "https://github.com/bbatsov/projectile")
+ :link '(url-link :tag "Online Manual" "https://projectile.readthedocs.org")
+ :link '(emacs-commentary-link :tag "Commentary" "projectile"))
+
+(defcustom projectile-indexing-method (if (eq system-type 'windows-nt) 'native 'alien)
+ "Specifies the indexing method used by Projectile.
+
+There are two indexing methods - native and alien.
+
+The native method is implemented in Emacs Lisp (therefore it is
+native to Emacs). Its advantage is that it is portable and will
+work everywhere that Emacs does. Its disadvantage is that it is a
+bit slow (especially for large projects). Generally it's a good
+idea to pair the native indexing method with caching.
+
+The alien indexing method uses external tools (e.g. git, find,
+etc) to speed up the indexing process. The disadvantage of this
+method is that it's not well supported on Windows systems.
+
+By default alien indexing is the default on all operating
+systems, except Windows."
+ :group 'projectile
+ :type '(radio
+ (const :tag "Native" native)
+ (const :tag "Alien" alien)))
+
+(defcustom projectile-enable-caching (eq projectile-indexing-method 'native)
+ "When t enables project files caching.
+
+Project caching is automatically enabled by default if you're
+using the native indexing method."
+ :group 'projectile
+ :type 'boolean)
+
+(defcustom projectile-file-exists-local-cache-expire nil
+ "Number of seconds before file existence cache expires for a
+file on a local file system.
+
+ A value of nil disables this cache."
+
+ :group 'projectile
+ :type '(choice (const :tag "Disabled" nil)
+ (integer :tag "Seconds")))
+
+(defcustom projectile-file-exists-remote-cache-expire (* 5 60)
+ "Number of seconds before file existence cache expires for a
+file on a remote file system such as tramp.
+
+ A value of nil disables this cache."
+ :group 'projectile
+ :type '(choice (const :tag "Disabled" nil)
+ (integer :tag "Seconds")))
+
+(defcustom projectile-require-project-root t
+ "Require the presence of a project root to operate when true.
+Otherwise consider the current directory the project root."
+ :group 'projectile
+ :type 'boolean)
+
+(defcustom projectile-completion-system 'ido
+ "The completion system to be used by Projectile."
+ :group 'projectile
+ :type '(radio
+ (const :tag "Ido" ido)
+ (const :tag "Grizzl" grizzl)
+ (const :tag "Helm" helm)
+ (const :tag "Ivy" ivy)
+ (const :tag "Default" default)
+ (function :tag "Custom function")))
+
+(defcustom projectile-keymap-prefix (kbd "C-c p")
+ "Projectile keymap prefix."
+ :group 'projectile
+ :type 'string)
+
+(defcustom projectile-cache-file
+ (expand-file-name "projectile.cache" user-emacs-directory)
+ "The name of Projectile's cache file."
+ :group 'projectile
+ :type 'string)
+
+(defcustom projectile-build-dir "build"
+ "The directory Projectile will use for build systems that build out of tree."
+ :group 'projectile
+ :type 'string)
+
+(defcustom projectile-tags-file-name "TAGS"
+ "The tags filename Projectile's going to use."
+ :group 'projectile
+ :type 'string)
+
+(defcustom projectile-tags-command "ctags -Re -f \"%s\" %s"
+ "The command Projectile's going to use to generate a TAGS file."
+ :group 'projectile
+ :type 'string)
+
+(defcustom projectile-tags-backend 'auto
+ "The tag backend that Projectile should use.
+
+If set to 'auto', `projectile-find-tag' will automatically choose
+which backend to use. Preference order is ggtags -> xref
+-> etags-select -> `find-tag'. Variable can also be set to specify which
+backend to use. If selected backend is unavailable, fall back to
+`find-tag'.
+
+If this variable is set to 'auto' and ggtags is available, or if
+set to 'ggtags', then ggtags will be used for
+`projectile-regenerate-tags'. For all other settings
+`projectile-tags-command' will be used."
+ :group 'projectile
+ :type '(radio
+ (const :tag "auto" auto)
+ (const :tag "xref" xref)
+ (const :tag "ggtags" ggtags)
+ (const :tag "etags" etags-select)
+ (const :tag "standard" find-tag))
+ :package-version '(projectile . "0.14.0"))
+
+(defcustom projectile-sort-order 'default
+ "The sort order used for a project's files."
+ :group 'projectile
+ :type '(radio
+ (const :tag "default" default)
+ (const :tag "recentf" recentf)
+ (const :tag "recently active" recently-active)
+ (const :tag "access time" access-time)
+ (const :tag "modification time" modification-time)))
+
+(defcustom projectile-verbose t
+ "Echo messages that are not errors."
+ :group 'projectile
+ :type 'boolean)
+
+(defcustom projectile-buffers-filter-function nil
+ "A function used to filter the buffers in `projectile-project-buffers'.
+
+The function should accept and return a list of Emacs buffers.
+Two example filter functions are shipped by default -
+`projectile-buffers-with-file' and
+`projectile-buffers-with-file-or-process'."
+ :group 'projectile
+ :type 'function)
+
+(defcustom projectile-project-name nil
+ "If this value is non-nil, it will be used as project name.
+
+It has precedence over function `projectile-project-name-function'."
+ :group 'projectile
+ :type 'string
+ :package-version '(projectile . "0.14.0"))
+
+(defcustom projectile-project-name-function 'projectile-default-project-name
+ "A function that receives the project-root and returns the project name.
+
+If variable `projectile-project-name' is non-nil, this function will not be used."
+ :group 'projectile
+ :type 'function
+ :package-version '(projectile . "0.14.0"))
+
+(defcustom projectile-project-root-files
+ '("rebar.config" ; Rebar project file
+ "project.clj" ; Leiningen project file
+ "build.boot" ; Boot-clj project file
+ "SConstruct" ; Scons project file
+ "pom.xml" ; Maven project file
+ "build.sbt" ; SBT project file
+ "gradlew" ; Gradle wrapper script
+ "build.gradle" ; Gradle project file
+ ".ensime" ; Ensime configuration file
+ "Gemfile" ; Bundler file
+ "requirements.txt" ; Pip file
+ "setup.py" ; Setuptools file
+ "tox.ini" ; Tox file
+ "composer.json" ; Composer project file
+ "Cargo.toml" ; Cargo project file
+ "mix.exs" ; Elixir mix project file
+ "stack.yaml" ; Haskell's stack tool based project
+ "info.rkt" ; Racket package description file
+ "DESCRIPTION" ; R package description file
+ "TAGS" ; etags/ctags are usually in the root of project
+ "GTAGS" ; GNU Global tags
+ )
+ "A list of files considered to mark the root of a project.
+The topmost match has precedence."
+ :group 'projectile
+ :type '(repeat string))
+
+(defcustom projectile-project-root-files-bottom-up
+ '(".projectile" ; projectile project marker
+ ".git" ; Git VCS root dir
+ ".hg" ; Mercurial VCS root dir
+ ".fslckout" ; Fossil VCS root dir
+ "_FOSSIL_" ; Fossil VCS root DB on Windows
+ ".bzr" ; Bazaar VCS root dir
+ "_darcs" ; Darcs VCS root dir
+ )
+ "A list of files considered to mark the root of a project.
+The bottommost (parentmost) match has precedence."
+ :group 'projectile
+ :type '(repeat string))
+
+(defcustom projectile-project-root-files-top-down-recurring
+ '(".svn" ; Svn VCS root dir
+ "CVS" ; Csv VCS root dir
+ "Makefile")
+ "A list of files considered to mark the root of a project.
+The search starts at the top and descends down till a directory
+that contains a match file but its parent does not. Thus, it's a
+bottommost match in the topmost sequence of directories
+containing a root file."
+ :group 'projectile
+ :type '(repeat string))
+
+(defcustom projectile-project-root-files-functions
+ '(projectile-root-local
+ projectile-root-bottom-up
+ projectile-root-top-down
+ projectile-root-top-down-recurring)
+ "A list of functions for finding project roots."
+ :group 'projectile
+ :type '(repeat function))
+
+(defcustom projectile-globally-ignored-files
+ (list projectile-tags-file-name)
+ "A list of files globally ignored by projectile."
+ :group 'projectile
+ :type '(repeat string))
+
+(defcustom projectile-globally-unignored-files nil
+ "A list of files globally unignored by projectile."
+ :group 'projectile
+ :type '(repeat string)
+ :package-version '(projectile . "0.14.0"))
+
+(defcustom projectile-globally-ignored-file-suffixes
+ nil
+ "A list of file suffixes globally ignored by projectile."
+ :group 'projectile
+ :type '(repeat string))
+
+(defcustom projectile-globally-ignored-directories
+ '(".idea"
+ ".ensime_cache"
+ ".eunit"
+ ".git"
+ ".hg"
+ ".fslckout"
+ "_FOSSIL_"
+ ".bzr"
+ "_darcs"
+ ".tox"
+ ".svn"
+ ".stack-work")
+ "A list of directories globally ignored by projectile."
+ :safe (lambda (x) (not (remq t (mapcar #'stringp x))))
+ :group 'projectile
+ :type '(repeat string))
+
+(defcustom projectile-globally-unignored-directories nil
+ "A list of directories globally unignored by projectile."
+ :group 'projectile
+ :type '(repeat string)
+ :package-version '(projectile . "0.14.0"))
+
+(defcustom projectile-globally-ignored-modes
+ '("erc-mode"
+ "help-mode"
+ "completion-list-mode"
+ "Buffer-menu-mode"
+ "gnus-.*-mode"
+ "occur-mode")
+ "A list of regular expressions for major modes ignored by projectile.
+
+If a buffer is using a given major mode, projectile will ignore
+it for functions working with buffers."
+ :group 'projectile
+ :type '(repeat string))
+
+(defcustom projectile-globally-ignored-buffers nil
+ "A list of buffer-names ignored by projectile.
+
+If a buffer is in the list projectile will ignore
+it for functions working with buffers."
+ :group 'projectile
+ :type '(repeat string)
+ :package-version '(projectile . "0.12.0"))
+
+(defcustom projectile-find-file-hook nil
+ "Hooks run when a file is opened with `projectile-find-file'."
+ :group 'projectile
+ :type 'hook)
+
+(defcustom projectile-find-dir-hook nil
+ "Hooks run when a directory is opened with `projectile-find-dir'."
+ :group 'projectile
+ :type 'hook)
+
+(defcustom projectile-switch-project-action 'projectile-find-file
+ "Action invoked after switching projects with `projectile-switch-project'.
+
+Any function that does not take arguments will do."
+ :group 'projectile
+ :type 'function)
+
+(defcustom projectile-find-dir-includes-top-level nil
+ "If true, add top-level dir to options offered by `projectile-find-dir'."
+ :group 'projectile
+ :type 'boolean)
+
+(defcustom projectile-use-git-grep nil
+ "If true, use `vc-git-grep' in git projects."
+ :group 'projectile
+ :type 'boolean)
+
+(defcustom projectile-grep-finished-hook nil
+ "Hooks run when `projectile-grep' finishes."
+ :group 'projectile
+ :type 'hook
+ :package-version '(projectile . "0.14.0"))
+
+(defcustom projectile-test-prefix-function 'projectile-test-prefix
+ "Function to find test files prefix based on PROJECT-TYPE."
+ :group 'projectile
+ :type 'function)
+
+(defcustom projectile-test-suffix-function 'projectile-test-suffix
+ "Function to find test files suffix based on PROJECT-TYPE."
+ :group 'projectile
+ :type 'function)
+
+
+;;; Idle Timer
+(defvar projectile-idle-timer nil
+ "The timer object created when `projectile-enable-idle-timer' is non-nil.")
+
+(defcustom projectile-idle-timer-seconds 30
+ "The idle period to use when `projectile-enable-idle-timer' is non-nil."
+ :group 'projectile
+ :type 'number)
+
+(defcustom projectile-idle-timer-hook '(projectile-regenerate-tags)
+ "The hook run when `projectile-enable-idle-timer' is non-nil."
+ :group 'projectile
+ :type '(repeat symbol))
+
+(defcustom projectile-enable-idle-timer nil
+ "Enables idle timer hook `projectile-idle-timer-functions'.
+
+When `projectile-enable-idle-timer' is non-nil, the hook
+`projectile-idle-timer-hook' is run each time Emacs has been idle
+for `projectile-idle-timer-seconds' seconds and we're in a
+project."
+ :group 'projectile
+ :set (lambda (symbol value)
+ (set symbol value)
+ (when projectile-idle-timer
+ (cancel-timer projectile-idle-timer))
+ (setq projectile-idle-timer nil)
+ (when projectile-enable-idle-timer
+ (setq projectile-idle-timer (run-with-idle-timer
+ projectile-idle-timer-seconds t
+ (lambda ()
+ (when (projectile-project-p)
+ (run-hooks 'projectile-idle-timer-hook)))))))
+ :type 'boolean)
+
+;;; Serialization
+(defun projectile-serialize (data filename)
+ "Serialize DATA to FILENAME.
+
+The saved data can be restored with `projectile-unserialize'."
+ (when (file-writable-p filename)
+ (with-temp-file filename
+ (insert (let (print-length) (prin1-to-string data))))))
+
+(defun projectile-unserialize (filename)
+ "Read data serialized by `projectile-serialize' from FILENAME."
+ (with-demoted-errors
+ "Error during file deserialization: %S"
+ (when (file-exists-p filename)
+ (with-temp-buffer
+ (insert-file-contents filename)
+ ;; this will blow up if the contents of the file aren't
+ ;; lisp data structures
+ (read (buffer-string))))))
+
+(defvar projectile-projects-cache nil
+ "A hashmap used to cache project file names to speed up related operations.")
+
+(defvar projectile-project-root-cache (make-hash-table :test 'equal)
+ "Cached value of function `projectile-project-root`.")
+
+(defvar projectile-project-type-cache (make-hash-table :test 'equal)
+ "A hashmap used to cache project type to speed up related operations.")
+
+(defvar projectile-known-projects nil
+ "List of locations where we have previously seen projects.
+The list of projects is ordered by the time they have been accessed.
+
+See also `projectile-remove-known-project',
+`projectile-cleanup-known-projects' and `projectile-clear-known-projects'.")
+
+(defvar projectile-known-projects-on-file nil
+ "List of known projects reference point.
+
+Contains a copy of `projectile-known-projects' when it was last
+synchronized with `projectile-known-projects-file'.")
+
+(defcustom projectile-known-projects-file
+ (expand-file-name "projectile-bookmarks.eld"
+ user-emacs-directory)
+ "Name and location of the Projectile's known projects file."
+ :group 'projectile
+ :type 'string)
+
+(defcustom projectile-ignored-projects nil
+ "A list of projects not to be added to `projectile-known-projects'."
+ :group 'projectile
+ :type '(repeat :tag "Project list" directory)
+ :package-version '(projectile . "0.11.0"))
+
+(defcustom projectile-ignored-project-function nil
+ "Function to decide if a project is added to `projectile-known-projects'.
+
+Can be either nil, or a function that takes the truename of the
+project root as argument and returns non-nil if the project is to
+be ignored or nil otherwise.
+
+This function is only called if the project is not listed in
+`projectile-ignored-projects'.
+
+A suitable candidate would be `file-remote-p' to ignore remote
+projects."
+ :group 'projectile
+ :type '(choice
+ (const :tag "Nothing" nil)
+ (const :tag "Remote files" file-remote-p)
+ function)
+ :package-version '(projectile . "0.13.0"))
+
+(defcustom projectile-track-known-projects-automatically t
+ "Controls whether Projectile will automatically register known projects.
+
+When set to nil you'll have always add projects explicitly with
+`projectile-add-known-project'."
+ :group 'projectile
+ :type 'boolean
+ :package-version '(projectile . "0.15.0"))
+
+
+;;; Version information
+
+;;;###autoload
+(defun projectile-version (&optional show-version)
+ "Get the Projectile version as string.
+
+If called interactively or if SHOW-VERSION is non-nil, show the
+version in the echo area and the messages buffer.
+
+The returned string includes both, the version from package.el
+and the library version, if both a present and different.
+
+If the version number could not be determined, signal an error,
+if called interactively, or if SHOW-VERSION is non-nil, otherwise
+just return nil."
+ (interactive (list t))
+ (if (require 'pkg-info nil t)
+ (let ((version (pkg-info-version-info 'projectile)))
+ (when show-version
+ (message "Projectile %s" version))
+ version)
+ (error "Cannot determine version without package pkg-info")))
+
+
+;;; Caching
+(defvar projectile-file-exists-cache
+ (make-hash-table :test 'equal)
+ "Cached `projectile-file-exists-p' results.")
+
+(defvar projectile-file-exists-cache-timer nil
+ "Timer for scheduling`projectile-file-exists-cache-cleanup'.")
+
+(defun projectile-file-exists-cache-cleanup ()
+ "Removed timed out cache entries and reschedules or remove the
+timer if no more items are in the cache."
+ (let ((now (current-time)))
+ (maphash (lambda (key value)
+ (if (time-less-p (cdr value) now)
+ (remhash key projectile-file-exists-cache)))
+ projectile-file-exists-cache)
+ (setq projectile-file-exists-cache-timer
+ (if (> (hash-table-count projectile-file-exists-cache) 0)
+ (run-with-timer 10 nil 'projectile-file-exists-cache-cleanup)))))
+
+(defun projectile-file-exists-p (filename)
+ "Return t if file FILENAME exist.
+A wrapper around `file-exists-p' with additional caching support."
+ (let* ((file-remote (file-remote-p filename))
+ (expire-seconds
+ (if file-remote
+ (and projectile-file-exists-remote-cache-expire
+ (> projectile-file-exists-remote-cache-expire 0)
+ projectile-file-exists-remote-cache-expire)
+ (and projectile-file-exists-local-cache-expire
+ (> projectile-file-exists-local-cache-expire 0)
+ projectile-file-exists-local-cache-expire)))
+ (remote-file-name-inhibit-cache (if expire-seconds
+ expire-seconds
+ remote-file-name-inhibit-cache)))
+ (if (not expire-seconds)
+ (file-exists-p filename)
+ (let* ((current-time (current-time))
+ (cached (gethash filename projectile-file-exists-cache))
+ (cached-value (if cached (car cached)))
+ (cached-expire (if cached (cdr cached)))
+ (cached-expired (if cached (time-less-p cached-expire current-time) t))
+ (value (or (and (not cached-expired) cached-value)
+ (if (file-exists-p filename) 'found 'notfound))))
+ (when (or (not cached) cached-expired)
+ (puthash filename
+ (cons value (time-add current-time (seconds-to-time expire-seconds)))
+ projectile-file-exists-cache))
+ (unless projectile-file-exists-cache-timer
+ (setq projectile-file-exists-cache-timer
+ (run-with-timer 10 nil 'projectile-file-exists-cache-cleanup)))
+ (equal value 'found)))))
+
+;;;###autoload
+(defun projectile-invalidate-cache (arg)
+ "Remove the current project's files from `projectile-projects-cache'.
+
+With a prefix argument ARG prompts for the name of the project whose cache
+to invalidate."
+ (interactive "P")
+ (let ((project-root
+ (if arg
+ (completing-read "Remove cache for: "
+ (projectile-hash-keys projectile-projects-cache))
+ (projectile-project-root))))
+ (setq projectile-project-root-cache (make-hash-table :test 'equal))
+ (remhash project-root projectile-project-type-cache)
+ (remhash project-root projectile-projects-cache)
+ (projectile-serialize-cache)
+ (when projectile-verbose
+ (message "Invalidated Projectile cache for %s."
+ (propertize project-root 'face 'font-lock-keyword-face))))
+ (when (fboundp 'recentf-cleanup)
+ (recentf-cleanup)))
+
+(defun projectile-cache-project (project files)
+ "Cache PROJECTs FILES.
+The cache is created both in memory and on the hard drive."
+ (when projectile-enable-caching
+ (puthash project files projectile-projects-cache)
+ (projectile-serialize-cache)))
+
+;;;###autoload
+(defun projectile-purge-file-from-cache (file)
+ "Purge FILE from the cache of the current project."
+ (interactive
+ (list (projectile-completing-read
+ "Remove file from cache: "
+ (projectile-current-project-files))))
+ (let* ((project-root (projectile-project-root))
+ (project-cache (gethash project-root projectile-projects-cache)))
+ (if (projectile-file-cached-p file project-root)
+ (progn
+ (puthash project-root (remove file project-cache) projectile-projects-cache)
+ (projectile-serialize-cache)
+ (when projectile-verbose
+ (message "%s removed from cache" file)))
+ (error "%s is not in the cache" file))))
+
+;;;###autoload
+(defun projectile-purge-dir-from-cache (dir)
+ "Purge DIR from the cache of the current project."
+ (interactive
+ (list (projectile-completing-read
+ "Remove directory from cache: "
+ (projectile-current-project-dirs))))
+ (let* ((project-root (projectile-project-root))
+ (project-cache (gethash project-root projectile-projects-cache)))
+ (puthash project-root
+ (cl-remove-if (lambda (str) (string-prefix-p dir str)) project-cache)
+ projectile-projects-cache)))
+
+(defun projectile-file-cached-p (file project)
+ "Check if FILE is already in PROJECT cache."
+ (member file (gethash project projectile-projects-cache)))
+
+;;;###autoload
+(defun projectile-cache-current-file ()
+ "Add the currently visited file to the cache."
+ (interactive)
+ (let ((current-project (projectile-project-root)))
+ (when (and (buffer-file-name) (gethash (projectile-project-root) projectile-projects-cache))
+ (let* ((abs-current-file (file-truename (buffer-file-name)))
+ (current-file (file-relative-name abs-current-file current-project)))
+ (unless (or (projectile-file-cached-p current-file current-project)
+ (projectile-ignored-directory-p (file-name-directory abs-current-file))
+ (projectile-ignored-file-p abs-current-file))
+ (puthash current-project
+ (cons current-file (gethash current-project projectile-projects-cache))
+ projectile-projects-cache)
+ (projectile-serialize-cache)
+ (message "File %s added to project %s cache."
+ (propertize current-file 'face 'font-lock-keyword-face)
+ (propertize current-project 'face 'font-lock-keyword-face)))))))
+
+;; cache opened files automatically to reduce the need for cache invalidation
+(defun projectile-cache-files-find-file-hook ()
+ "Function for caching files with `find-file-hook'."
+ (let ((project-root (projectile-project-p)))
+ (when (and projectile-enable-caching
+ project-root
+ (not (projectile-ignored-project-p project-root)))
+ (projectile-cache-current-file))))
+
+(defun projectile-track-known-projects-find-file-hook ()
+ "Function for caching projects with `find-file-hook'."
+ (when (and projectile-track-known-projects-automatically (projectile-project-p))
+ (let ((known-projects (and (sequencep projectile-known-projects)
+ (copy-sequence projectile-known-projects))))
+ (projectile-add-known-project (projectile-project-root))
+ (unless (equal known-projects projectile-known-projects)
+ (projectile-merge-known-projects)))))
+
+
+(defun projectile-maybe-invalidate-cache (force)
+ "Invalidate if FORCE or project's dirconfig newer than cache."
+ (when (or force (file-newer-than-file-p (projectile-dirconfig-file)
+ projectile-cache-file))
+ (projectile-invalidate-cache nil)))
+
+;;;###autoload
+(defun projectile-discover-projects-in-directory (directory)
+ "Discover any projects in DIRECTORY and add them to the projectile cache.
+This function is not recursive and only adds projects with roots
+at the top level of DIRECTORY."
+ (interactive
+ (list (read-directory-name "Starting directory: ")))
+ (let ((subdirs (directory-files directory t)))
+ (mapcar
+ (lambda (dir)
+ (when (and (file-directory-p dir)
+ (not (member (file-name-nondirectory dir) '(".." "."))))
+ (let ((default-directory dir))
+ (when (projectile-project-p)
+ (projectile-add-known-project (projectile-project-root))))))
+ subdirs)))
+
+
+(defadvice delete-file (before purge-from-projectile-cache (filename &optional trash))
+ (if (and projectile-enable-caching (projectile-project-p))
+ (let* ((project-root (projectile-project-root))
+ (true-filename (file-truename filename))
+ (relative-filename (file-relative-name true-filename project-root)))
+ (if (projectile-file-cached-p relative-filename project-root)
+ (projectile-purge-file-from-cache relative-filename)))))
+
+
+;;; Project root related utilities
+(defun projectile-parent (path)
+ "Return the parent directory of PATH.
+PATH may be a file or directory and directory paths may end with a slash."
+ (directory-file-name (file-name-directory (directory-file-name (expand-file-name path)))))
+
+(defun projectile-locate-dominating-file (file name)
+ "Look up the directory hierarchy from FILE for a directory containing NAME.
+Stop at the first parent directory containing a file NAME,
+and return the directory. Return nil if not found.
+Instead of a string, NAME can also be a predicate taking one argument
+\(a directory) and returning a non-nil value if that directory is the one for
+which we're looking."
+ ;; copied from files.el (stripped comments) emacs-24 bzr branch 2014-03-28 10:20
+ (setq file (abbreviate-file-name file))
+ (let ((root nil)
+ try)
+ (while (not (or root
+ (null file)
+ (string-match locate-dominating-stop-dir-regexp file)))
+ (setq try (if (stringp name)
+ (projectile-file-exists-p (expand-file-name name file))
+ (funcall name file)))
+ (cond (try (setq root file))
+ ((equal file (setq file (file-name-directory
+ (directory-file-name file))))
+ (setq file nil))))
+ (and root (expand-file-name (file-name-as-directory root)))))
+
+(defvar-local projectile-project-root nil
+ "Defines a custom Projectile project root.
+This is intended to be used as a file local variable.")
+
+(defun projectile-root-local (_dir)
+ "A simple wrapper around `projectile-project-root'."
+ projectile-project-root)
+
+(defun projectile-root-top-down (dir &optional list)
+ "Identify a project root in DIR by top-down search for files in LIST.
+If LIST is nil, use `projectile-project-root-files' instead.
+Return the first (topmost) matched directory or nil if not found."
+ (projectile-locate-dominating-file
+ dir
+ (lambda (dir)
+ (cl-find-if (lambda (f) (projectile-file-exists-p (expand-file-name f dir)))
+ (or list projectile-project-root-files)))))
+
+(defun projectile-root-bottom-up (dir &optional list)
+ "Identify a project root in DIR by bottom-up search for files in LIST.
+If LIST is nil, use `projectile-project-root-files-bottom-up' instead.
+Return the first (bottommost) matched directory or nil if not found."
+ (cl-some (lambda (name) (projectile-locate-dominating-file dir name))
+ (or list projectile-project-root-files-bottom-up)))
+
+(defun projectile-root-top-down-recurring (dir &optional list)
+ "Identify a project root in DIR by recurring top-down search for files in LIST.
+If LIST is nil, use `projectile-project-root-files-top-down-recurring'
+instead. Return the last (bottommost) matched directory in the
+topmost sequence of matched directories. Nil otherwise."
+ (cl-some
+ (lambda (f)
+ (projectile-locate-dominating-file
+ dir
+ (lambda (dir)
+ (and (projectile-file-exists-p (expand-file-name f dir))
+ (or (string-match locate-dominating-stop-dir-regexp (projectile-parent dir))
+ (not (projectile-file-exists-p (expand-file-name f (projectile-parent dir)))))))))
+ (or list projectile-project-root-files-top-down-recurring)))
+
+(defvar-local projectile-cached-project-root nil
+ "Cached root of the current Projectile project. If non-nil, it
+is used as the return value of `projectile-project-root' for
+performance (unless the variable `projectile-project-root' is
+also set). If nil, it is recalculated the next time
+`projectile-project-root' is called.
+
+This variable is reset automatically when Projectile detects that
+the `buffer-file-name' has changed. It can also be reset manually
+by calling `projectile-reset-cached-project-root'.")
+
+(defvar-local projectile-cached-buffer-file-name nil
+ "The last known value of `buffer-file-name' for the current
+buffer. This is used to detect a change in `buffer-file-name',
+which triggers a reset of `projectile-cached-project-root' and
+`projectile-cached-project-name'.")
+
+(defun projectile-project-root ()
+ "Retrieves the root directory of a project if available.
+The current directory is assumed to be the project's root otherwise."
+ ;; the cached value will be 'none in the case of no project root (this is to
+ ;; ensure it is not reevaluated each time when not inside a project) so use
+ ;; cl-subst to replace this 'none value with nil so a nil value is used
+ ;; instead
+ (or (cl-subst nil 'none
+ (or (and (equal projectile-cached-buffer-file-name buffer-file-name)
+ projectile-cached-project-root)
+ (progn
+ (setq projectile-cached-buffer-file-name buffer-file-name)
+ (setq projectile-cached-project-root
+ ;; The `is-local' and `is-connected' variables are
+ ;; used to fix the behavior where Emacs hangs
+ ;; because of Projectile when you open a file over
+ ;; TRAMP. It basically prevents Projectile from
+ ;; trying to find information about files for which
+ ;; it's not possible to get that information right
+ ;; now.
+ (or (let* ((dir default-directory)
+ (is-local (not (file-remote-p dir))) ;; `true' if the file is local
+ (is-connected (file-remote-p dir nil t))) ;; `true' if the file is remote AND we are connected to the remote
+ (when (or is-local is-connected)
+ (cl-some
+ (lambda (func)
+ (let* ((cache-key (format "%s-%s" func dir))
+ (cache-value (gethash cache-key projectile-project-root-cache)))
+ (if (and cache-value (file-exists-p cache-value))
+ cache-value
+ (let ((value (funcall func (file-truename dir))))
+ (puthash cache-key value projectile-project-root-cache)
+ value))))
+ projectile-project-root-files-functions)))
+ ;; set cached to none so is non-nil so we don't try
+ ;; and look it up again
+ 'none)))))
+ (if projectile-require-project-root
+ (error "You're not in a project")
+ default-directory)))
+
+(defun projectile-file-truename (file-name)
+ "Return the truename of FILE-NAME.
+A thin wrapper around `file-truename' that handles nil."
+ (when file-name
+ (file-truename file-name)))
+
+(defun projectile-project-p ()
+ "Check if we're in a project."
+ (condition-case nil
+ (projectile-project-root)
+ (error nil)))
+
+(defun projectile-default-project-name (project-root)
+ "Default function used create project name to be displayed based on the value of PROJECT-ROOT."
+ (file-name-nondirectory (directory-file-name project-root)))
+
+(defvar-local projectile-cached-project-name nil
+ "Cached name of the current Projectile project. If non-nil, it
+is used as the return value of `projectile-project-name' for
+performance (unless the variable `projectile-project-name' is
+also set). If nil, it is recalculated the next time
+`projectile-project-name' is called.
+
+This variable is reset automatically when Projectile detects that
+the `buffer-file-name' has changed. It can also be reset manually
+by calling `projectile-reset-cached-project-name'.")
+
+(defun projectile-reset-cached-project-root ()
+ "Reset the value of `projectile-cached-project-root' to nil.
+
+This means that it is automatically recalculated the next time
+function `projectile-project-root' is called."
+ (interactive)
+ (setq projectile-cached-project-root nil))
+
+(defun projectile-reset-cached-project-name ()
+ "Reset the value of `projectile-cached-project-name' to nil.
+
+This means that it is automatically recalculated the next time
+function `projectile-project-name' is called."
+ (interactive)
+ (setq projectile-cached-project-name nil))
+
+(defun projectile-project-name ()
+ "Return project name."
+ (or projectile-project-name
+ (and (equal projectile-cached-buffer-file-name buffer-file-name)
+ projectile-cached-project-name)
+ (progn
+ (setq projectile-cached-buffer-file-name buffer-file-name)
+ (setq projectile-cached-project-name
+ (let ((project-root
+ (condition-case nil
+ (projectile-project-root)
+ (error nil))))
+ (if project-root
+ (funcall projectile-project-name-function project-root)
+ "-"))))))
+
+
+;;; Project indexing
+(defun projectile-get-project-directories ()
+ "Get the list of project directories that are of interest to the user."
+ (mapcar (lambda (subdir) (concat (projectile-project-root) subdir))
+ (or (nth 0 (projectile-parse-dirconfig-file)) '(""))))
+
+(defun projectile-dir-files (directory)
+ "List the files in DIRECTORY and in its sub-directories.
+Files are returned as relative paths to the project root."
+ ;; check for a cache hit first if caching is enabled
+ (let ((files-list (and projectile-enable-caching
+ (gethash directory projectile-projects-cache)))
+ (root (projectile-project-root)))
+ ;; cache disabled or cache miss
+ (or files-list
+ (if (eq projectile-indexing-method 'native)
+ (projectile-dir-files-native root directory)
+ ;; use external tools to get the project files
+ (projectile-adjust-files (projectile-dir-files-external root directory))))))
+
+(defun projectile-dir-files-native (root directory)
+ "Get the files for ROOT under DIRECTORY using just Emacs Lisp."
+ (let ((progress-reporter
+ (make-progress-reporter
+ (format "Projectile is indexing %s"
+ (propertize directory 'face 'font-lock-keyword-face)))))
+ ;; we need the files with paths relative to the project root
+ (mapcar (lambda (file) (file-relative-name file root))
+ (projectile-index-directory directory (projectile-filtering-patterns)
+ progress-reporter))))
+
+(defun projectile-dir-files-external (root directory)
+ "Get the files for ROOT under DIRECTORY using external tools."
+ (let ((default-directory directory))
+ (mapcar (lambda (file)
+ (file-relative-name (expand-file-name file directory) root))
+ (projectile-get-repo-files))))
+
+(defcustom projectile-git-command "git ls-files -zco --exclude-standard"
+ "Command used by projectile to get the files in a git project."
+ :group 'projectile
+ :type 'string)
+
+(defcustom projectile-git-submodule-command "git submodule --quiet foreach 'echo $path' | tr '\\n' '\\0'"
+ "Command used by projectile to get the files in git submodules."
+ :group 'projectile
+ :type 'string)
+
+(defcustom projectile-git-ignored-command "git ls-files -zcoi --exclude-standard"
+ "Command used by projectile to get the ignored files in a git project."
+ :group 'projectile
+ :type 'string
+ :package-version '(projectile . "0.14.0"))
+
+(defcustom projectile-hg-command "hg locate -f -0 -I ."
+ "Command used by projectile to get the files in a hg project."
+ :group 'projectile
+ :type 'string)
+
+(defcustom projectile-fossil-command (concat "fossil ls | "
+ (when (string-equal system-type
+ "windows-nt")
+ "dos2unix | ")
+ "tr '\\n' '\\0'")
+ "Command used by projectile to get the files in a fossil project."
+ :group 'projectile
+ :type 'string)
+
+(defcustom projectile-bzr-command "bzr ls -R --versioned -0"
+ "Command used by projectile to get the files in a bazaar project."
+ :group 'projectile
+ :type 'string)
+
+(defcustom projectile-darcs-command "darcs show files -0 . "
+ "Command used by projectile to get the files in a darcs project."
+ :group 'projectile
+ :type 'string)
+
+(defcustom projectile-svn-command "svn list -R . | grep -v '$/' | tr '\\n' '\\0'"
+ "Command used by projectile to get the files in a svn project."
+ :group 'projectile
+ :type 'string)
+
+(defcustom projectile-generic-command "find . -type f -print0"
+ "Command used by projectile to get the files in a generic project."
+ :group 'projectile
+ :type 'string)
+
+(defcustom projectile-vcs-dirty-state '("edited" "unregistered" "needs-update" "needs-merge" "unlocked-changes" "conflict")
+ "List of states checked by `projectile-browse-dirty-projects'.
+Possible checked states are:
+\"edited\", \"unregistered\", \"needs-update\", \"needs-merge\", unlocked-changes\" and \"conflict\",
+as defined in `vc.el'."
+ :group 'projectile
+ :type '(repeat (string))
+ :package-version '(projectile . "0.15.0"))
+
+(defun projectile-get-ext-command ()
+ "Determine which external command to invoke based on the project's VCS."
+ (let ((vcs (projectile-project-vcs)))
+ (cond
+ ((eq vcs 'git) projectile-git-command)
+ ((eq vcs 'hg) projectile-hg-command)
+ ((eq vcs 'fossil) projectile-fossil-command)
+ ((eq vcs 'bzr) projectile-bzr-command)
+ ((eq vcs 'darcs) projectile-darcs-command)
+ ((eq vcs 'svn) projectile-svn-command)
+ (t projectile-generic-command))))
+
+(defun projectile-get-sub-projects-command ()
+ (let ((vcs (projectile-project-vcs)))
+ (cond
+ ((eq vcs 'git) projectile-git-submodule-command)
+ (t ""))))
+
+(defun projectile-get-ext-ignored-command ()
+ "Determine which external command to invoke based on the project's VCS."
+ (let ((vcs (projectile-project-vcs)))
+ (cond
+ ((eq vcs 'git) projectile-git-ignored-command)
+ ;; TODO: Add support for other VCS
+ (t nil))))
+
+(defun projectile-flatten (lst)
+ "Take a nested list LST and return its contents as a single, flat list."
+ (if (and (listp lst) (listp (cdr lst)))
+ (cl-mapcan 'projectile-flatten lst)
+ (list lst)))
+
+(defun projectile-get-all-sub-projects (project)
+ "Get all sub-projects for a given project.
+
+PROJECT is base directory to start search recursively."
+ (let ((submodules (projectile-get-immediate-sub-projects project)))
+ (cond
+ ((null submodules)
+ nil)
+ (t
+ (nconc submodules (projectile-flatten
+ ;; recursively get sub-projects of each sub-project
+ (mapcar (lambda (s)
+ (projectile-get-all-sub-projects s)) submodules)))))))
+
+(defun projectile-get-immediate-sub-projects (path)
+ "Get immediate sub-projects for a given project without recursing.
+
+PATH is the vcs root or project root from which to start
+searching, and should end with an appropriate path delimiter, such as
+'/' or a '\\'.
+
+If the vcs get-sub-projects query returns results outside of path,
+they are excluded from the results of this function."
+ (let* ((default-directory path)
+ ;; search for sub-projects under current project `project'
+ (submodules (mapcar
+ (lambda (s)
+ (file-name-as-directory (expand-file-name s default-directory)))
+ (projectile-files-via-ext-command (projectile-get-sub-projects-command))))
+ (project-child-folder-regex
+ (concat "\\`"
+ (regexp-quote path))))
+
+ ;; If project root is inside of an VCS folder, but not actually an
+ ;; VCS root itself, submodules external to the project will be
+ ;; included in the VCS get sub-projects result. Let's remove them.
+ (cl-remove-if-not
+ (lambda (submodule)
+ (string-match-p project-child-folder-regex
+ submodule))
+ submodules)))
+
+(defun projectile-get-sub-projects-files ()
+ "Get files from sub-projects recursively."
+ (projectile-flatten
+ (mapcar (lambda (s)
+ (let ((default-directory s))
+ (mapcar (lambda (f)
+ (concat s f))
+ (projectile-files-via-ext-command projectile-git-command))))
+ (condition-case nil
+ (projectile-get-all-sub-projects (projectile-project-root))
+ (error nil)))))
+
+(defun projectile-get-repo-files ()
+ "Get a list of the files in the project, including sub-projects."
+ (cond
+ ((eq (projectile-project-vcs) 'git)
+ (nconc (projectile-files-via-ext-command (projectile-get-ext-command))
+ (projectile-get-sub-projects-files)))
+ (t (projectile-files-via-ext-command (projectile-get-ext-command)))))
+
+(defun projectile-get-repo-ignored-files ()
+ "Get a list of the files ignored in the project."
+ (let ((cmd (projectile-get-ext-ignored-command)))
+ (when cmd
+ (projectile-files-via-ext-command cmd))))
+
+(defun projectile-get-repo-ignored-directory (dir)
+ "Get a list of the files ignored in the project in the directory DIR."
+ (let ((cmd (projectile-get-ext-ignored-command)))
+ (when cmd
+ (projectile-files-via-ext-command (concat cmd " " dir)))))
+
+(defun projectile-call-process-to-string (program &rest args)
+ "Invoke the executable PROGRAM with ARGS and return the output as a string."
+ (with-temp-buffer
+ (apply 'call-process program nil (current-buffer) nil args)
+ (buffer-string)))
+
+(defun projectile-shell-command-to-string (command)
+ "Try to run COMMAND without actually using a shell and return the output.
+
+The function `eshell-search-path' will be used to search the PATH
+environment variable for an appropriate executable using the text
+occuring before the first space. If no executable is found,
+fallback to `shell-command-to-string'."
+ (cl-destructuring-bind
+ (the-command . args) (split-string command " ")
+ (let ((binary-path (eshell-search-path the-command)))
+ (if binary-path
+ (apply 'projectile-call-process-to-string binary-path args)
+ (shell-command-to-string command)))))
+
+(defun projectile-check-vcs-status (&optional PROJECT-PATH)
+ "Check the status of the current project.
+If PROJECT-PATH is a project, check this one instead."
+ (let* ((PROJECT-PATH (or PROJECT-PATH (projectile-project-root)))
+ (project-status nil))
+ (save-excursion
+ (vc-dir PROJECT-PATH)
+ ;; wait until vc-dir is done
+ (while (vc-dir-busy) (sleep-for 0 100))
+ ;; check for status
+ (save-excursion
+ (save-match-data
+ (dolist (check projectile-vcs-dirty-state)
+ (goto-char (point-min))
+ (when (search-forward check nil t)
+ (setq project-status (cons check project-status))))))
+ (kill-buffer)
+ project-status)))
+
+(defun projectile-check-vcs-status-of-known-projects ()
+ "Return the list of dirty projects.
+The list is composed of sublists~: (project-path, project-status).
+Raise an error if their is no dirty project."
+ (let ((projects projectile-known-projects)
+ (status ()))
+ (dolist (project projects)
+ (when (and (projectile-keep-project-p project) (not (string= 'none (projectile-project-vcs project))))
+ (let ((tmp-status (projectile-check-vcs-status project)))
+ (when tmp-status
+ (setq status (cons (list project tmp-status) status))))))
+ (when (= (length status) 0)
+ (message "No dirty projects have been found"))
+ status))
+
+(defun projectile-browse-dirty-projects ()
+ "Browse dirty version controlled projects."
+ (interactive)
+ (let ((status nil)
+ (mod-proj nil))
+ (message "Checking for modifications in known projects...")
+ (setq status (projectile-check-vcs-status-of-known-projects))
+ (while (not (= (length status) 0))
+ (setq mod-proj (cons (car (pop status)) mod-proj)))
+ (projectile-vc
+ (projectile-completing-read "Select project: " mod-proj))))
+
+(defun projectile-files-via-ext-command (command)
+ "Get a list of relative file names in the project root by executing COMMAND."
+ (split-string (shell-command-to-string command) "\0" t))
+
+(defun projectile-index-directory (directory patterns progress-reporter)
+ "Index DIRECTORY taking into account PATTERNS.
+The function calls itself recursively until all sub-directories
+have been indexed. The PROGRESS-REPORTER is updated while the
+function is executing."
+ (apply 'append
+ (mapcar
+ (lambda (f)
+ (unless (or (and patterns (projectile-ignored-rel-p f directory patterns))
+ (member (file-name-nondirectory (directory-file-name f))
+ '("." ".." ".svn" ".cvs")))
+ (progress-reporter-update progress-reporter)
+ (if (file-directory-p f)
+ (unless (projectile-ignored-directory-p
+ (file-name-as-directory f))
+ (projectile-index-directory f patterns progress-reporter))
+ (unless (projectile-ignored-file-p f)
+ (list f)))))
+ (directory-files directory t))))
+
+(defun projectile-adjust-files (files)
+ "First remove ignored files from FILES, then add back unignored files."
+ (projectile-add-unignored (projectile-remove-ignored files)))
+
+(defun projectile--stringi= (string1 string2)
+ "Match STRING1 and STRING2 case insensitively."
+ (equal (compare-strings string1 nil nil string2 nil nil t) t))
+
+(defun projectile-remove-ignored (files)
+ "Remove ignored files and folders from FILES.
+
+If ignored directory prefixed with '*', then ignore all
+directories/subdirectories with matching filename,
+otherwise operates relative to project root."
+ (let ((ignored-files (projectile-ignored-files-rel))
+ (ignored-dirs (projectile-ignored-directories-rel)))
+ (cl-remove-if
+ (lambda (file)
+ (or (cl-some
+ (lambda (f)
+ (string= f (file-name-nondirectory file)))
+ ignored-files)
+ (cl-some
+ (lambda (dir)
+ ;; if the directory is prefixed with '*' then ignore all directories matching that name
+ (if (string-prefix-p "*" dir)
+ ;; remove '*' and trailing slash from ignored directory name
+ (let ((d (substring dir 1 (if (equal (substring dir -1) "/") -1 nil))))
+ (cl-some
+ (lambda (p)
+ (string= d p))
+ ;; split path by '/', remove empty strings, and check if any subdirs match name 'd'
+ (delete "" (split-string (or (file-name-directory file) "") "/"))))
+ (string-prefix-p dir file)))
+ ignored-dirs)
+ (cl-some
+ (lambda (suf)
+ (projectile--stringi= suf (file-name-extension file t)))
+ projectile-globally-ignored-file-suffixes)))
+ files)))
+
+(defun projectile-keep-ignored-files (files)
+ "Filter FILES to retain only those that are ignored."
+ (when files
+ (cl-remove-if-not
+ (lambda (file)
+ (cl-some (lambda (f) (string-prefix-p f file)) files))
+ (projectile-get-repo-ignored-files))))
+
+(defun projectile-keep-ignored-directories (directories)
+ "Get ignored files within each of DIRECTORIES."
+ (when directories
+ (let (result)
+ (dolist (dir directories result)
+ (setq result (append result
+ (projectile-get-repo-ignored-directory dir))))
+ result)))
+
+(defun projectile-add-unignored (files)
+ "This adds unignored files to FILES.
+
+Useful because the VCS may not return ignored files at all. In
+this case unignored files will be absent from FILES."
+ (let ((unignored-files (projectile-keep-ignored-files
+ (projectile-unignored-files-rel)))
+ (unignored-paths (projectile-remove-ignored
+ (projectile-keep-ignored-directories
+ (projectile-unignored-directories-rel)))))
+ (append files unignored-files unignored-paths)))
+
+(defun projectile-buffers-with-file (buffers)
+ "Return only those BUFFERS backed by files."
+ (cl-remove-if-not (lambda (b) (buffer-file-name b)) buffers))
+
+(defun projectile-buffers-with-file-or-process (buffers)
+ "Return only those BUFFERS backed by files or processes."
+ (cl-remove-if-not (lambda (b) (or (buffer-file-name b)
+ (get-buffer-process b))) buffers))
+
+(defun projectile-project-buffers ()
+ "Get a list of project buffers."
+ (let* ((project-root (projectile-project-root))
+ (all-buffers (cl-remove-if-not
+ (lambda (buffer)
+ (projectile-project-buffer-p buffer project-root))
+ (buffer-list))))
+ (if projectile-buffers-filter-function
+ (funcall projectile-buffers-filter-function all-buffers)
+ all-buffers)))
+
+(defun projectile-process-current-project-buffers (action)
+ "Process the current project's buffers using ACTION."
+ (let ((project-buffers (projectile-project-buffers)))
+ (dolist (buffer project-buffers)
+ (funcall action buffer))))
+
+(defun projectile-project-buffer-files ()
+ "Get a list of project buffer files."
+ (let ((project-root (projectile-project-root)))
+ (mapcar
+ (lambda (buffer)
+ (file-relative-name
+ (buffer-file-name buffer)
+ project-root))
+ (projectile-buffers-with-file
+ (projectile-project-buffers)))))
+
+(defun projectile-project-buffer-p (buffer project-root)
+ "Check if BUFFER is under PROJECT-ROOT."
+ (with-current-buffer buffer
+ (and (not (string-prefix-p " " (buffer-name buffer)))
+ (not (projectile-ignored-buffer-p buffer))
+ (string-equal (file-remote-p default-directory)
+ (file-remote-p project-root))
+ (not (string-match-p "^http\\(s\\)?://" default-directory))
+ (string-prefix-p project-root (file-truename default-directory) (eq system-type 'windows-nt)))))
+
+(defun projectile-ignored-buffer-p (buffer)
+ "Check if BUFFER should be ignored."
+ (or
+ (member (buffer-name buffer) projectile-globally-ignored-buffers)
+ (with-current-buffer buffer
+ (cl-some
+ (lambda (mode)
+ (string-match-p (concat "^" mode "$")
+ (symbol-name major-mode)))
+ projectile-globally-ignored-modes))))
+
+(defun projectile-difference (list1 list2)
+ (cl-remove-if
+ (lambda (x) (member x list2))
+ list1))
+
+(defun projectile-recently-active-files ()
+ "Get list of recently active files.
+
+Files are ordered by recently active buffers, and then recently
+opened through use of recentf."
+ (let ((project-buffer-files (projectile-project-buffer-files)))
+ (append project-buffer-files
+ (projectile-difference
+ (projectile-recentf-files)
+ project-buffer-files))))
+
+(defun projectile-project-buffer-names ()
+ "Get a list of project buffer names."
+ (mapcar #'buffer-name (projectile-project-buffers)))
+
+(defun projectile-prepend-project-name (string)
+ "Prepend the current project's name to STRING."
+ (format "[%s] %s" (projectile-project-name) string))
+
+(defun projectile-read-buffer-to-switch (prompt)
+ "Read the name of a buffer to switch to, prompting with PROMPT.
+
+This function excludes the current buffer from the offered
+choices."
+ (projectile-completing-read
+ prompt
+ (delete (buffer-name (current-buffer))
+ (projectile-project-buffer-names))))
+
+;;;###autoload
+(defun projectile-switch-to-buffer ()
+ "Switch to a project buffer."
+ (interactive)
+ (switch-to-buffer
+ (projectile-read-buffer-to-switch "Switch to buffer: ")))
+
+;;;###autoload
+(defun projectile-switch-to-buffer-other-window ()
+ "Switch to a project buffer and show it in another window."
+ (interactive)
+ (switch-to-buffer-other-window
+ (projectile-read-buffer-to-switch "Switch to buffer: ")))
+
+;;;###autoload
+(defun projectile-switch-to-buffer-other-frame ()
+ "Switch to a project buffer and show it in another window."
+ (interactive)
+ (switch-to-buffer-other-frame
+ (projectile-read-buffer-to-switch "Switch to buffer: ")))
+
+;;;###autoload
+(defun projectile-display-buffer ()
+ "Display a project buffer in another window without selecting it."
+ (interactive)
+ (display-buffer
+ (projectile-completing-read
+ "Display buffer: "
+ (projectile-project-buffer-names))))
+
+;;;###autoload
+(defun projectile-project-buffers-other-buffer ()
+ "Switch to the most recently selected buffer project buffer.
+Only buffers not visible in windows are returned."
+ (interactive)
+ (switch-to-buffer (car (projectile-project-buffers-non-visible))) nil t)
+
+(defun projectile-project-buffers-non-visible ()
+ "Get a list of non visible project buffers."
+ (cl-remove-if-not
+ (lambda (buffer)
+ (not (get-buffer-window buffer 'visible)))
+ (projectile-project-buffers)))
+
+;;;###autoload
+(defun projectile-multi-occur (&optional nlines)
+ "Do a `multi-occur' in the project's buffers.
+With a prefix argument, show NLINES of context."
+ (interactive "P")
+ (multi-occur (projectile-project-buffers)
+ (car (occur-read-primary-args))
+ nlines))
+
+(defun projectile-normalise-paths (patterns)
+ "Remove leading `/' from the elements of PATTERNS."
+ (delq nil (mapcar (lambda (pat) (and (string-prefix-p "/" pat)
+ ;; remove the leading /
+ (substring pat 1)))
+ patterns)))
+
+(defun projectile-expand-paths (paths)
+ "Expand the elements of PATHS.
+
+Elements containing wildcards are expanded and spliced into the
+resulting paths. The returned PATHS are absolute, based on the
+projectile project root."
+ (let ((default-directory (projectile-project-root)))
+ (projectile-flatten (mapcar
+ (lambda (pattern)
+ (or (file-expand-wildcards pattern t)
+ (projectile-expand-root pattern)))
+ paths))))
+
+(defun projectile-normalise-patterns (patterns)
+ "Remove paths from PATTERNS."
+ (cl-remove-if (lambda (pat) (string-prefix-p "/" pat)) patterns))
+
+(defun projectile-make-relative-to-root (files)
+ "Make FILES relative to the project root."
+ (let ((project-root (projectile-project-root)))
+ (mapcar (lambda (f) (file-relative-name f project-root)) files)))
+
+(defun projectile-ignored-directory-p (directory)
+ "Check if DIRECTORY should be ignored."
+ (member directory (projectile-ignored-directories)))
+
+(defun projectile-ignored-file-p (file)
+ "Check if FILE should be ignored."
+ (member file (projectile-ignored-files)))
+
+(defun projectile-check-pattern-p (file pattern)
+ "Check if FILE meets PATTERN."
+ (or (string-suffix-p (directory-file-name pattern)
+ (directory-file-name file))
+ (member file (file-expand-wildcards pattern t))))
+
+(defun projectile-ignored-rel-p (file directory patterns)
+ "Check if FILE should be ignored relative to DIRECTORY
+according to PATTERNS: (ignored . unignored)"
+ (let ((default-directory directory))
+ (and (cl-some
+ (lambda (pat) (projectile-check-pattern-p file pat))
+ (car patterns))
+ (cl-notany
+ (lambda (pat) (projectile-check-pattern-p file pat))
+ (cdr patterns)))))
+
+(defun projectile-ignored-files ()
+ "Return list of ignored files."
+ (projectile-difference
+ (mapcar
+ #'projectile-expand-root
+ (append
+ projectile-globally-ignored-files
+ (projectile-project-ignored-files)))
+ (projectile-unignored-files)))
+
+(defun projectile-ignored-directories ()
+ "Return list of ignored directories."
+ (projectile-difference
+ (mapcar
+ #'file-name-as-directory
+ (mapcar
+ #'projectile-expand-root
+ (append
+ projectile-globally-ignored-directories
+ (projectile-project-ignored-directories))))
+ (projectile-unignored-directories)))
+
+(defun projectile-ignored-directories-rel ()
+ "Return list of ignored directories, relative to the root."
+ (projectile-make-relative-to-root (projectile-ignored-directories)))
+
+(defun projectile-ignored-files-rel ()
+ "Return list of ignored files, relative to the root."
+ (projectile-make-relative-to-root (projectile-ignored-files)))
+
+(defun projectile-project-ignored-files ()
+ "Return list of project ignored files.
+Unignored files are not included."
+ (cl-remove-if 'file-directory-p (projectile-project-ignored)))
+
+(defun projectile-project-ignored-directories ()
+ "Return list of project ignored directories.
+Unignored directories are not included."
+ (cl-remove-if-not 'file-directory-p (projectile-project-ignored)))
+
+(defun projectile-paths-to-ignore ()
+ "Return a list of ignored project paths."
+ (projectile-normalise-paths (nth 1 (projectile-parse-dirconfig-file))))
+
+(defun projectile-patterns-to-ignore ()
+ "Return a list of relative file patterns."
+ (projectile-normalise-patterns (nth 1 (projectile-parse-dirconfig-file))))
+
+(defun projectile-project-ignored ()
+ "Return list of project ignored files/directories.
+Unignored files/directories are not included."
+ (let ((paths (projectile-paths-to-ignore)))
+ (projectile-expand-paths paths)))
+
+(defun projectile-unignored-files ()
+ "Return list of unignored files."
+ (mapcar
+ #'projectile-expand-root
+ (append
+ projectile-globally-unignored-files
+ (projectile-project-unignored-files))))
+
+(defun projectile-unignored-directories ()
+ "Return list of unignored directories."
+ (mapcar
+ #'file-name-as-directory
+ (mapcar
+ #'projectile-expand-root
+ (append
+ projectile-globally-unignored-directories
+ (projectile-project-unignored-directories)))))
+
+(defun projectile-unignored-directories-rel ()
+ "Return list of unignored directories, relative to the root."
+ (projectile-make-relative-to-root (projectile-unignored-directories)))
+
+(defun projectile-unignored-files-rel ()
+ "Return list of unignored files, relative to the root."
+ (projectile-make-relative-to-root (projectile-unignored-files)))
+
+(defun projectile-project-unignored-files ()
+ "Return list of project unignored files."
+ (cl-remove-if 'file-directory-p (projectile-project-unignored)))
+
+(defun projectile-project-unignored-directories ()
+ "Return list of project unignored directories."
+ (cl-remove-if-not 'file-directory-p (projectile-project-unignored)))
+
+(defun projectile-paths-to-ensure ()
+ "Return a list of unignored project paths."
+ (projectile-normalise-paths (nth 2 (projectile-parse-dirconfig-file))))
+
+(defun projectile-files-to-ensure ()
+ (projectile-flatten (mapcar (lambda (pat) (file-expand-wildcards pat t))
+ (projectile-patterns-to-ensure))))
+
+(defun projectile-patterns-to-ensure ()
+ "Return a list of relative file patterns."
+ (projectile-normalise-patterns (nth 2 (projectile-parse-dirconfig-file))))
+
+(defun projectile-filtering-patterns ()
+ (cons (projectile-patterns-to-ignore)
+ (projectile-patterns-to-ensure)))
+
+(defun projectile-project-unignored ()
+ "Return list of project ignored files/directories."
+ (delete-dups (append (projectile-expand-paths (projectile-paths-to-ensure))
+ (projectile-expand-paths (projectile-files-to-ensure)))))
+
+
+(defun projectile-dirconfig-file ()
+ "Return the absolute path to the project's dirconfig file."
+ (expand-file-name ".projectile" (projectile-project-root)))
+
+(defun projectile-parse-dirconfig-file ()
+ "Parse project ignore file and return directories to ignore and keep.
+
+The return value will be a list of three elements, the car being
+the list of directories to keep, the cadr being the list of files
+or directories to ignore, and the caddr being the list of files
+or directories to ensure.
+
+Strings starting with + will be added to the list of directories
+to keep, and strings starting with - will be added to the list of
+directories to ignore. For backward compatibility, without a
+prefix the string will be assumed to be an ignore string."
+ (let (keep ignore ensure (dirconfig (projectile-dirconfig-file)))
+ (when (projectile-file-exists-p dirconfig)
+ (with-temp-buffer
+ (insert-file-contents dirconfig)
+ (while (not (eobp))
+ (pcase (char-after)
+ (?+ (push (buffer-substring (1+ (point)) (line-end-position)) keep))
+ (?- (push (buffer-substring (1+ (point)) (line-end-position)) ignore))
+ (?! (push (buffer-substring (1+ (point)) (line-end-position)) ensure))
+ (_ (push (buffer-substring (point) (line-end-position)) ignore)))
+ (forward-line)))
+ (list (mapcar (lambda (f) (file-name-as-directory (projectile-trim-string f)))
+ (delete "" (reverse keep)))
+ (mapcar #'projectile-trim-string
+ (delete "" (reverse ignore)))
+ (mapcar #'projectile-trim-string
+ (delete "" (reverse ensure)))))))
+
+(defun projectile-expand-root (name)
+ "Expand NAME to project root.
+
+Never use on many files since it's going to recalculate the
+project-root for every file."
+ (expand-file-name name (projectile-project-root)))
+
+(cl-defun projectile-completing-read (prompt choices &key initial-input action)
+ "Present a project tailored PROMPT with CHOICES."
+ (let ((prompt (projectile-prepend-project-name prompt))
+ res)
+ (setq res
+ (cond
+ ((eq projectile-completion-system 'ido)
+ (ido-completing-read prompt choices nil nil initial-input))
+ ((eq projectile-completion-system 'default)
+ (completing-read prompt choices nil nil initial-input))
+ ((eq projectile-completion-system 'helm)
+ (if (and (fboundp 'helm)
+ (fboundp 'helm-make-source))
+ (helm :sources
+ (helm-make-source "Projectile" 'helm-source-sync
+ :candidates choices
+ :action (if action
+ (prog1 action
+ (setq action nil))
+ #'identity))
+ :prompt prompt
+ :input initial-input
+ :buffer "*helm-projectile*")
+ (user-error "Please install helm from \
+https://github.com/emacs-helm/helm")))
+ ((eq projectile-completion-system 'grizzl)
+ (if (and (fboundp 'grizzl-completing-read)
+ (fboundp 'grizzl-make-index))
+ (grizzl-completing-read prompt (grizzl-make-index choices))
+ (user-error "Please install grizzl from \
+https://github.com/d11wtq/grizzl")))
+ ((eq projectile-completion-system 'ivy)
+ (if (fboundp 'ivy-read)
+ (ivy-read prompt choices
+ :initial-input initial-input
+ :action (prog1 action
+ (setq action nil))
+ :caller 'projectile-completing-read)
+ (user-error "Please install ivy from \
+https://github.com/abo-abo/swiper")))
+ (t (funcall projectile-completion-system prompt choices))))
+ (if action
+ (funcall action res)
+ res)))
+
+(defun projectile-current-project-files ()
+ "Return a list of files for the current project."
+ (let ((files (and projectile-enable-caching
+ (gethash (projectile-project-root) projectile-projects-cache))))
+ ;; nothing is cached
+ (unless files
+ (when projectile-enable-caching
+ (message "Empty cache. Projectile is initializing cache..."))
+ (setq files (cl-mapcan
+ #'projectile-dir-files
+ (projectile-get-project-directories)))
+ ;; cache the resulting list of files
+ (when projectile-enable-caching
+ (projectile-cache-project (projectile-project-root) files)))
+ (projectile-sort-files files)))
+
+(defun projectile-process-current-project-files (action)
+ "Process the current project's files using ACTION."
+ (let ((project-files (projectile-current-project-files))
+ (default-directory (projectile-project-root)))
+ (dolist (filename project-files)
+ (funcall action filename))))
+
+(defun projectile-current-project-dirs ()
+ "Return a list of dirs for the current project."
+ (delete-dups
+ (delq nil
+ (mapcar #'file-name-directory
+ (projectile-current-project-files)))))
+
+(defun projectile-hash-keys (hash)
+ "Return a list of all HASH keys."
+ (let (allkeys)
+ (maphash (lambda (k _v) (setq allkeys (cons k allkeys))) hash)
+ allkeys))
+
+
+;;; Interactive commands
+(defcustom projectile-other-file-alist
+ '( ;; handle C/C++ extensions
+ ("cpp" . ("h" "hpp" "ipp"))
+ ("ipp" . ("h" "hpp" "cpp"))
+ ("hpp" . ("h" "ipp" "cpp" "cc"))
+ ("cxx" . ("h" "hxx" "ixx"))
+ ("ixx" . ("h" "hxx" "cxx"))
+ ("hxx" . ("h" "ixx" "cxx"))
+ ("c" . ("h"))
+ ("m" . ("h"))
+ ("mm" . ("h"))
+ ("h" . ("c" "cc" "cpp" "ipp" "hpp" "cxx" "ixx" "hxx" "m" "mm"))
+ ("cc" . ("h" "hh" "hpp"))
+ ("hh" . ("cc"))
+
+ ;; vertex shader and fragment shader extensions in glsl
+ ("vert" . ("frag"))
+ ("frag" . ("vert"))
+
+ ;; handle files with no extension
+ (nil . ("lock" "gpg"))
+ ("lock" . (""))
+ ("gpg" . (""))
+ )
+ "Alist of extensions for switching to file with the same name,
+ using other extensions based on the extension of current
+ file."
+ :type 'alist)
+
+(defun projectile--find-other-file (&optional flex-matching ff-variant)
+ "Switch between files with the same name but different extensions.
+With FLEX-MATCHING, match any file that contains the base name of current file.
+Other file extensions can be customized with the variable
+`projectile-other-file-alist'. With FF-VARIANT set to a defun, use that
+instead of `find-file'. A typical example of such a defun would be
+`find-file-other-window' or `find-file-other-frame'"
+ (let ((ff (or ff-variant #'find-file))
+ (other-files (projectile-get-other-files
+ (buffer-file-name)
+ (projectile-current-project-files)
+ flex-matching)))
+ (if other-files
+ (let ((file-name (if (= (length other-files) 1)
+ (car other-files)
+ (projectile-completing-read "Switch to: "
+ other-files))))
+ (funcall ff (expand-file-name file-name
+ (projectile-project-root))))
+ (error "No other file found"))))
+
+;;;###autoload
+(defun projectile-find-other-file (&optional flex-matching)
+ "Switch between files with the same name but different extensions.
+With FLEX-MATCHING, match any file that contains the base name of current file.
+Other file extensions can be customized with the variable `projectile-other-file-alist'."
+ (interactive "P")
+ (projectile--find-other-file flex-matching))
+
+;;;###autoload
+(defun projectile-find-other-file-other-window (&optional flex-matching)
+ "Switch between files with the same name but different extensions in other window.
+With FLEX-MATCHING, match any file that contains the base name of current file.
+Other file extensions can be customized with the variable `projectile-other-file-alist'."
+ (interactive "P")
+ (projectile--find-other-file flex-matching
+ #'find-file-other-window))
+
+;;;###autoload
+(defun projectile-find-other-file-other-frame (&optional flex-matching)
+ "Switch between files with the same name but different extensions in other window.
+With FLEX-MATCHING, match any file that contains the base name of current file.
+Other file extensions can be customized with the variable `projectile-other-file-alist'."
+ (interactive "P")
+ (projectile--find-other-file flex-matching
+ #'find-file-other-frame))
+
+(defun projectile--file-name-sans-extensions (file-name)
+ "Return FILE-NAME sans any extensions.
+The extensions, in a filename, are what follows the first '.', with the exception of a leading '.'"
+ (setq file-name (file-name-nondirectory file-name))
+ (substring file-name 0 (string-match "\\..*" file-name 1)))
+
+(defun projectile--file-name-extensions (file-name)
+ "Return FILE-NAME's extensions.
+The extensions, in a filename, are what follows the first '.', with the exception of a leading '.'"
+ ;;would it make sense to return nil instead of an empty string if no extensions are found?
+ (setq file-name (file-name-nondirectory file-name))
+ (let (extensions-start)
+ (substring file-name
+ (if (setq extensions-start (string-match "\\..*" file-name 1))
+ (1+ extensions-start)
+ (length file-name)))))
+
+(defun projectile-associated-file-name-extensions (file-name)
+ "Return projectile-other-file-extensions associated to FILE-NAME's extensions.
+If no associated other-file-extensions for the complete (nested) extension are found, remove subextensions from FILENAME's extensions until a match is found."
+ (let ((current-extensions (projectile--file-name-extensions (file-name-nondirectory file-name)))
+ associated-extensions)
+ (catch 'break
+ (while (not (string= "" current-extensions))
+ (if (setq associated-extensions (cdr (assoc current-extensions projectile-other-file-alist)))
+ (throw 'break associated-extensions))
+ (setq current-extensions (projectile--file-name-extensions current-extensions))))))
+
+(defun projectile-get-other-files (current-file project-file-list &optional flex-matching)
+ "Narrow to files with the same names but different extensions.
+Returns a list of possible files for users to choose.
+
+With FLEX-MATCHING, match any file that contains the base name of current file"
+ (let* ((file-ext-list (projectile-associated-file-name-extensions current-file))
+ (fulldirname (if (file-name-directory current-file)
+ (file-name-directory current-file) "./"))
+ (dirname (file-name-nondirectory (directory-file-name fulldirname)))
+ (filename (projectile--file-name-sans-extensions current-file))
+ (file-list (mapcar (lambda (ext)
+ (if flex-matching
+ (concat ".*" filename ".*" "\." ext "\\'")
+ (concat "^" filename
+ (unless (equal ext "")
+ (concat "\." ext))
+ "\\'")))
+ file-ext-list))
+ (candidates (cl-remove-if-not
+ (lambda (project-file)
+ (string-match filename project-file))
+ project-file-list))
+ (candidates
+ (projectile-flatten (mapcar
+ (lambda (file)
+ (cl-remove-if-not
+ (lambda (project-file)
+ (string-match file
+ (concat (file-name-base project-file)
+ (unless (equal (file-name-extension project-file) nil)
+ (concat "\." (file-name-extension project-file))))))
+ candidates))
+ file-list)))
+ (candidates
+ (cl-remove-if-not (lambda (file) (not (backup-file-name-p file))) candidates))
+ (candidates
+ (cl-sort (copy-sequence candidates)
+ (lambda (file _)
+ (let ((candidate-dirname (file-name-nondirectory (directory-file-name (file-name-directory file)))))
+ (unless (equal fulldirname (file-name-directory file))
+ (equal dirname candidate-dirname)))))))
+ candidates))
+
+(defun projectile-select-files (project-files &optional arg)
+ "Select a list of files based on filename at point.
+
+With a prefix ARG invalidates the cache first."
+ (projectile-maybe-invalidate-cache arg)
+ (let* ((file (if (region-active-p)
+ (buffer-substring (region-beginning) (region-end))
+ (or (thing-at-point 'filename) "")))
+ (file (if (string-match "\\.?\\./" file)
+ (file-relative-name (file-truename file) (projectile-project-root))
+ file))
+ (files (if file
+ (cl-remove-if-not
+ (lambda (project-file)
+ (string-match file project-file))
+ project-files)
+ nil)))
+ files))
+
+(defun projectile--find-file-dwim (invalidate-cache &optional ff-variant)
+ "Jump to a project's files using completion based on context.
+
+With a INVALIDATE-CACHE invalidates the cache first.
+
+With FF-VARIANT set to a defun, use that instead of `find-file'.
+A typical example of such a defun would be `find-file-other-window' or
+`find-file-other-frame'
+
+Subroutine for `projectile-find-file-dwim' and
+`projectile-find-file-dwim-other-window'"
+ (let* ((project-files (projectile-current-project-files))
+ (files (projectile-select-files project-files invalidate-cache))
+ (file (cond ((= (length files) 1)
+ (car files))
+ ((> (length files) 1)
+ (projectile-completing-read "Switch to: " files))
+ (t
+ (projectile-completing-read "Switch to: " project-files))))
+ (ff (or ff-variant #'find-file)))
+ (funcall ff (expand-file-name file (projectile-project-root)))
+ (run-hooks 'projectile-find-file-hook)))
+
+;;;###autoload
+(defun projectile-find-file-dwim (&optional arg)
+ "Jump to a project's files using completion based on context.
+
+With a prefix ARG invalidates the cache first.
+
+If point is on a filename, Projectile first tries to search for that
+file in project:
+
+- If it finds just a file, it switches to that file instantly. This works even
+if the filename is incomplete, but there's only a single file in the current project
+that matches the filename at point. For example, if there's only a single file named
+\"projectile/projectile.el\" but the current filename is \"projectile/proj\" (incomplete),
+`projectile-find-file-dwim' still switches to \"projectile/projectile.el\" immediately
+ because this is the only filename that matches.
+
+- If it finds a list of files, the list is displayed for selecting. A list of
+files is displayed when a filename appears more than one in the project or the
+filename at point is a prefix of more than two files in a project. For example,
+if `projectile-find-file-dwim' is executed on a filepath like \"projectile/\", it lists
+the content of that directory. If it is executed on a partial filename like
+ \"projectile/a\", a list of files with character 'a' in that directory is presented.
+
+- If it finds nothing, display a list of all files in project for selecting."
+ (interactive "P")
+ (projectile--find-file-dwim arg))
+
+;;;###autoload
+(defun projectile-find-file-dwim-other-window (&optional arg)
+ "Jump to a project's files using completion based on context in other window.
+
+With a prefix ARG invalidates the cache first.
+
+If point is on a filename, Projectile first tries to search for that
+file in project:
+
+- If it finds just a file, it switches to that file instantly. This works even
+if the filename is incomplete, but there's only a single file in the current project
+that matches the filename at point. For example, if there's only a single file named
+\"projectile/projectile.el\" but the current filename is \"projectile/proj\" (incomplete),
+`projectile-find-file-dwim-other-window' still switches to \"projectile/projectile.el\"
+immediately because this is the only filename that matches.
+
+- If it finds a list of files, the list is displayed for selecting. A list of
+files is displayed when a filename appears more than one in the project or the
+filename at point is a prefix of more than two files in a project. For example,
+if `projectile-find-file-dwim-other-window' is executed on a filepath like \"projectile/\", it lists
+the content of that directory. If it is executed on a partial filename
+like \"projectile/a\", a list of files with character 'a' in that directory
+is presented.
+
+- If it finds nothing, display a list of all files in project for selecting."
+ (interactive "P")
+ (projectile--find-file-dwim arg #'find-file-other-window))
+
+;;;###autoload
+(defun projectile-find-file-dwim-other-frame (&optional arg)
+ "Jump to a project's files using completion based on context in other frame.
+
+With a prefix ARG invalidates the cache first.
+
+If point is on a filename, Projectile first tries to search for that
+file in project:
+
+- If it finds just a file, it switches to that file instantly. This works even
+if the filename is incomplete, but there's only a single file in the current project
+that matches the filename at point. For example, if there's only a single file named
+\"projectile/projectile.el\" but the current filename is \"projectile/proj\" (incomplete),
+`projectile-find-file-dwim-other-frame' still switches to \"projectile/projectile.el\"
+immediately because this is the only filename that matches.
+
+- If it finds a list of files, the list is displayed for selecting. A list of
+files is displayed when a filename appears more than one in the project or the
+filename at point is a prefix of more than two files in a project. For example,
+if `projectile-find-file-dwim-other-frame' is executed on a filepath like \"projectile/\", it lists
+the content of that directory. If it is executed on a partial filename
+like \"projectile/a\", a list of files with character 'a' in that directory
+is presented.
+
+- If it finds nothing, display a list of all files in project for selecting."
+ (interactive "P")
+ (projectile--find-file-dwim arg #'find-file-other-frame))
+
+(defun projectile--find-file (invalidate-cache &optional ff-variant)
+ "Jump to a project's file using completion.
+With INVALIDATE-CACHE invalidates the cache first. With FF-VARIANT set to a
+defun, use that instead of `find-file'. A typical example of such a defun
+would be `find-file-other-window' or `find-file-other-frame'"
+ (interactive "P")
+ (projectile-maybe-invalidate-cache invalidate-cache)
+ (let ((file (projectile-completing-read "Find file: "
+ (projectile-current-project-files)))
+ (ff (or ff-variant #'find-file)))
+ (funcall ff (expand-file-name file (projectile-project-root)))
+ (run-hooks 'projectile-find-file-hook)))
+
+;;;###autoload
+(defun projectile-find-file (&optional arg)
+ "Jump to a project's file using completion.
+With a prefix ARG invalidates the cache first."
+ (interactive "P")
+ (projectile--find-file arg))
+
+;;;###autoload
+(defun projectile-find-file-other-window (&optional arg)
+ "Jump to a project's file using completion and show it in another window.
+
+With a prefix ARG invalidates the cache first."
+ (interactive "P")
+ (projectile--find-file arg #'find-file-other-window))
+
+;;;###autoload
+(defun projectile-find-file-other-frame (&optional arg)
+ "Jump to a project's file using completion and show it in another frame.
+
+With a prefix ARG invalidates the cache first."
+ (interactive "P")
+ (projectile--find-file arg #'find-file-other-frame))
+
+(defun projectile-sort-files (files)
+ "Sort FILES according to `projectile-sort-order'."
+ (cl-case projectile-sort-order
+ (default files)
+ (recentf (projectile-sort-by-recentf-first files))
+ (recently-active (projectile-sort-by-recently-active-first files))
+ (modification-time (projectile-sort-by-modification-time files))
+ (access-time (projectile-sort-by-access-time files))))
+
+(defun projectile-sort-by-recentf-first (files)
+ "Sort FILES by a recent first scheme."
+ (let ((project-recentf-files (projectile-recentf-files)))
+ (append project-recentf-files
+ (projectile-difference files project-recentf-files))))
+
+(defun projectile-sort-by-recently-active-first (files)
+ "Sort FILES by most recently active buffers or opened files."
+ (let ((project-recently-active-files (projectile-recently-active-files)))
+ (append project-recently-active-files
+ (projectile-difference files project-recently-active-files))))
+
+(defun projectile-sort-by-modification-time (files)
+ "Sort FILES by modification time."
+ (let ((default-directory (projectile-project-root)))
+ (cl-sort
+ (copy-sequence files)
+ (lambda (file1 file2)
+ (let ((file1-mtime (nth 5 (file-attributes file1)))
+ (file2-mtime (nth 5 (file-attributes file2))))
+ (not (time-less-p file1-mtime file2-mtime)))))))
+
+(defun projectile-sort-by-access-time (files)
+ "Sort FILES by access time."
+ (let ((default-directory (projectile-project-root)))
+ (cl-sort
+ (copy-sequence files)
+ (lambda (file1 file2)
+ (let ((file1-atime (nth 4 (file-attributes file1)))
+ (file2-atime (nth 4 (file-attributes file2))))
+ (not (time-less-p file1-atime file2-atime)))))))
+
+(defun projectile--find-dir (invalidate-cache &optional dired-variant)
+ "Jump to a project's directory using completion.
+
+With INVALIDATE-CACHE invalidates the cache first. With DIRED-VARIANT set to a
+defun, use that instead of `dired'. A typical example of such a defun would be
+`dired-other-window' or `dired-other-frame'"
+ (projectile-maybe-invalidate-cache invalidate-cache)
+ (let ((dir (projectile-complete-dir))
+ (dired-v (or dired-variant #'dired)))
+ (funcall dired-v (expand-file-name dir (projectile-project-root)))
+ (run-hooks 'projectile-find-dir-hook)))
+
+;;;###autoload
+(defun projectile-find-dir (&optional arg)
+ "Jump to a project's directory using completion.
+
+With a prefix ARG invalidates the cache first."
+ (interactive "P")
+ (projectile--find-dir arg))
+
+;;;###autoload
+(defun projectile-find-dir-other-window (&optional arg)
+ "Jump to a project's directory in other window using completion.
+
+With a prefix ARG invalidates the cache first."
+ (interactive "P")
+ (projectile--find-dir arg #'dired-other-window))
+
+;;;###autoload
+(defun projectile-find-dir-other-frame (&optional arg)
+ "Jump to a project's directory in other window using completion.
+
+With a prefix ARG invalidates the cache first."
+ (interactive "P")
+ (projectile--find-dir arg #'dired-other-frame))
+
+(defun projectile-complete-dir ()
+ (projectile-completing-read
+ "Find dir: "
+ (if projectile-find-dir-includes-top-level
+ (append '("./") (projectile-current-project-dirs))
+ (projectile-current-project-dirs))))
+
+;;;###autoload
+(defun projectile-find-test-file (&optional arg)
+ "Jump to a project's test file using completion.
+
+With a prefix ARG invalidates the cache first."
+ (interactive "P")
+ (projectile-maybe-invalidate-cache arg)
+ (let ((file (projectile-completing-read "Find test file: "
+ (projectile-current-project-test-files))))
+ (find-file (expand-file-name file (projectile-project-root)))))
+
+(defun projectile-test-files (files)
+ "Return only the test FILES."
+ (cl-remove-if-not 'projectile-test-file-p files))
+
+(defun projectile-test-file-p (file)
+ "Check if FILE is a test file."
+ (or (cl-some (lambda (pat) (string-prefix-p pat (file-name-nondirectory file)))
+ (delq nil (list (funcall projectile-test-prefix-function (projectile-project-type)))))
+ (cl-some (lambda (pat) (string-suffix-p pat (file-name-sans-extension (file-name-nondirectory file))))
+ (delq nil (list (funcall projectile-test-suffix-function (projectile-project-type)))))))
+
+(defun projectile-current-project-test-files ()
+ "Return a list of test files for the current project."
+ (projectile-test-files (projectile-current-project-files)))
+
+(defvar projectile-project-types (make-hash-table)
+ "A hash table holding all project types that are known to Projectile.")
+
+(cl-defun projectile-register-project-type
+ (project-type marker-files &key compile test run test-suffix test-prefix)
+ "Register a project type with projectile.
+
+A project type is defined by PROJECT-TYPE, a set of MARKER-FILES, and optional keyword arguments
+COMPILE which specifies a command that builds the project,
+TEST which specified a command that tests the project,
+RUN which specifies a command that runs the project,
+TEST-SUFFIX which specifies test file suffix, and
+TEST-PREFIX which specifies test file prefix."
+ (let ((project-plist (list 'marker-files marker-files
+ 'compile-command compile
+ 'test-command test
+ 'run-command run)))
+ ;; There is no way for the function to distinguish between an explicit argument of nil and an omitted argument. However, the body of the function is free to consider nil an abbreviation for some other meaningful value
+ (when test-suffix
+ (plist-put project-plist 'test-suffix test-suffix))
+ (when test-prefix
+ (plist-put project-plist 'test-prefix test-prefix))
+ (puthash project-type project-plist
+ projectile-project-types)))
+
+(defun projectile-cmake-run-target (target)
+ "Run CMake TARGET, generating build dir if needed."
+ (interactive "sTarget: ")
+ (let ((configure-cmd (format "cmake -E chdir %s cmake .."
+ projectile-build-dir))
+ (build-cmd (format "cmake --build %s --target %s"
+ projectile-build-dir
+ target)))
+ (compile (if (file-accessible-directory-p projectile-build-dir)
+ build-cmd
+ (mkdir projectile-build-dir)
+ (format "%s && %s" configure-cmd build-cmd)))))
+
+(defun projectile-cmake-compile ()
+ "Compile the current cmake project."
+ (interactive)
+ (projectile-cmake-run-target ""))
+
+(defun projectile-cmake-test ()
+ "Run the current cmake projects test suite."
+ (interactive)
+ (projectile-cmake-run-target "test"))
+
+(defun projectile-meson-run-target (target)
+ "Run meson TARGET, generating build dir if needed."
+ (interactive "sTarget: ")
+ (let* ((configure-cmd (format "meson %s" projectile-build-dir))
+ (build-cmd (format "ninja -C %s %s" projectile-build-dir target)))
+ (compile (if (file-accessible-directory-p projectile-build-dir)
+ build-cmd
+ (format "%s && %s" configure-cmd build-cmd)))))
+
+(defun projectile-meson-compile ()
+ "Compile the current meson project."
+ (interactive)
+ (projectile-meson-run-target ""))
+
+(defun projectile-meson-test ()
+ "Run the current meson projects test suite."
+ (interactive)
+ (projectile-meson-run-target "test"))
+
+(defun projectile-cabal ()
+ "Check if a project contains *.cabal files but no stack.yaml file."
+ (and (projectile-verify-file "*.cabal")
+ (not (projectile-verify-file "stack.yaml"))))
+
+(defun projectile-go ()
+ "Check if a project contains Go source files."
+ (cl-some
+ (lambda (file)
+ (string= (file-name-extension file) "go"))
+ (projectile-current-project-files)))
+
+(defcustom projectile-go-function 'projectile-go
+ "Function to determine if project's type is go."
+ :group 'projectile
+ :type 'function)
+
+(projectile-register-project-type 'emacs-cask '("Cask")
+ :compile "cask install")
+(projectile-register-project-type 'rails-rspec '("Gemfile" "app" "lib" "db" "config" "spec")
+ :compile "bundle exec rails server"
+ :test "bundle exec rspec")
+(projectile-register-project-type 'rails-test '("Gemfile" "app" "lib" "db" "config" "test")
+ :compile "bundle exec rails server"
+ :test "bundle exec rake test")
+(projectile-register-project-type 'symfony '("composer.json" "app" "src" "vendor")
+ :compile "app/console server:run"
+ :test "phpunit -c app ")
+(projectile-register-project-type 'ruby-rspec '("Gemfile" "lib" "spec")
+ :compile "bundle exec rake"
+ :test "bundle exec rspec")
+(projectile-register-project-type 'ruby-test '("Gemfile" "lib" "test")
+ :compile"bundle exec rake"
+ :test "bundle exec rake test")
+(projectile-register-project-type 'django '("manage.py")
+ :compile "python manage.py runserver"
+ :test "python manage.py test")
+(projectile-register-project-type 'python-pip '("requirements.txt")
+ :compile "python setup.by build"
+ :test "python -m unittest discover")
+(projectile-register-project-type 'python-pkg '("setup.py")
+ :compile "python setup.py build"
+ :test "python -m unittest discover")
+(projectile-register-project-type 'python-tox '("tox.ini")
+ :compile "tox -r --notest"
+ :test "tox")
+(projectile-register-project-type 'scons '("SConstruct")
+ :compile "scons"
+ :test "scons test")
+(projectile-register-project-type 'maven '("pom.xml")
+ :compile "mvn clean install"
+ :test "mvn test")
+(projectile-register-project-type 'gradle '("build.gradle")
+ :compile "gradle build"
+ :test "gradle test")
+(projectile-register-project-type 'gradlew '("gradlew")
+ :compile "./gradlew build"
+ :test "./gradlew test")
+(projectile-register-project-type 'grails '("application.properties" "grails-app")
+ :compile "grails package"
+ :test "grails test-app")
+(projectile-register-project-type 'lein-test '("project.clj")
+ :compile "lein compile"
+ :test "lein test")
+(projectile-register-project-type 'lein-midje '("project.clj" ".midje.clj")
+ :compile "lein compile"
+ :test "lein midje")
+(projectile-register-project-type 'boot-clj '("build.boot")
+ :compile "boot aot"
+ :test "boot test")
+(projectile-register-project-type 'rebar '("rebar.config")
+ :compile "rebar"
+ :test "rebar eunit")
+(projectile-register-project-type 'sbt '("build.sbt")
+ :compile "sbt compile"
+ :test "sbt test")
+(projectile-register-project-type 'make '("Makefile")
+ :compile "make"
+ :test "make test")
+(projectile-register-project-type 'grunt '("Gruntfile.js")
+ :compile "grunt"
+ :test "grunt test")
+(projectile-register-project-type 'gulp '("gulpfile.js")
+ :compile "gulp"
+ :test "gulp test")
+(projectile-register-project-type 'haskell-stack '("stack.yaml")
+ :compile "stack build"
+ :test "stack build --test")
+(projectile-register-project-type 'haskell-cabal #'projectile-cabal
+ :compile "cabal build"
+ :test "cabal test")
+(projectile-register-project-type 'rust-cargo '("Cargo.toml")
+ :compile "cargo build"
+ :test "cargo test")
+(projectile-register-project-type 'r '("DESCRIPTION")
+ :compile "R CMD INSTALL --with-keep.source ."
+ :test (concat "R CMD check -o " temporary-file-directory " ."))
+(projectile-register-project-type 'go projectile-go-function
+ :compile "go build ./..."
+ :test "go test ./...")
+(projectile-register-project-type 'racket '("info.rkt")
+ :test "raco test .")
+(projectile-register-project-type 'elixir '("mix.exs")
+ :compile "mix compile"
+ :test "mix test")
+(projectile-register-project-type 'npm '("package.json")
+ :compile "npm install"
+ :test "npm test")
+(projectile-register-project-type 'meson '("meson.build")
+ :compile #'projectile-meson-compile
+ :test #'projectile-meson-test)
+(projectile-register-project-type 'cmake '("CMakeLists.txt")
+ :compile #'projectile-cmake-compile
+ :test #'projectile-cmake-test)
+(projectile-register-project-type 'nix '("default.nix")
+ :compile "nix-build"
+ :test "nix-build")
+
+(defvar-local projectile-project-type nil
+ "Buffer local var for overriding the auto-detected project type.
+Normally you'd set this from .dir-locals.el.")
+(put 'projectile-project-type 'safe-local-variable #'symbolp)
+
+(defun projectile-detect-project-type ()
+ "Detect the type of the current project."
+ (let ((project-type (cl-find-if
+ (lambda (project-type)
+ (let ((marker (plist-get (gethash project-type projectile-project-types) 'marker-files)))
+ (if (listp marker)
+ (and (projectile-verify-files marker) project-type)
+ (and (funcall marker) project-type))))
+ (projectile-hash-keys projectile-project-types))))
+ (when project-type
+ (puthash (projectile-project-root) project-type projectile-project-type-cache))
+ project-type))
+
+(defun projectile-project-type ()
+ "Determine the project's type based on its structure."
+ (if projectile-project-type
+ projectile-project-type
+ (or (gethash (projectile-project-root) projectile-project-type-cache)
+ (projectile-detect-project-type)
+ 'generic)))
+
+;;;###autoload
+(defun projectile-project-info ()
+ "Display info for current project."
+ (interactive)
+ (message "Project dir: %s ## Project VCS: %s ## Project type: %s"
+ (projectile-project-root)
+ (projectile-project-vcs)
+ (projectile-project-type)))
+
+(defun projectile-verify-files (files)
+ "Check whether all FILES exist in the current project."
+ (cl-every 'projectile-verify-file files))
+
+(defun projectile-verify-file (file)
+ "Check whether FILE exists in the current project.
+Expands wildcards using `file-expand-wildcards' before checking."
+ (file-expand-wildcards (projectile-expand-root file)))
+
+(defun projectile-project-vcs (&optional project-root)
+ "Determine the VCS used by the project if any.
+PROJECT-ROOT is the targeted directory. If nil, use
+`projectile-project-root'."
+ (or project-root (setq project-root (projectile-project-root)))
+ (cond
+ ((projectile-file-exists-p (expand-file-name ".git" project-root)) 'git)
+ ((projectile-file-exists-p (expand-file-name ".hg" project-root)) 'hg)
+ ((projectile-file-exists-p (expand-file-name ".fslckout" project-root)) 'fossil)
+ ((projectile-file-exists-p (expand-file-name "_FOSSIL_" project-root)) 'fossil)
+ ((projectile-file-exists-p (expand-file-name ".bzr" project-root)) 'bzr)
+ ((projectile-file-exists-p (expand-file-name "_darcs" project-root)) 'darcs)
+ ((projectile-file-exists-p (expand-file-name ".svn" project-root)) 'svn)
+ ((projectile-locate-dominating-file project-root ".git") 'git)
+ ((projectile-locate-dominating-file project-root ".hg") 'hg)
+ ((projectile-locate-dominating-file project-root ".fslckout") 'fossil)
+ ((projectile-locate-dominating-file project-root "_FOSSIL_") 'fossil)
+ ((projectile-locate-dominating-file project-root ".bzr") 'bzr)
+ ((projectile-locate-dominating-file project-root "_darcs") 'darcs)
+ ((projectile-locate-dominating-file project-root ".svn") 'svn)
+ (t 'none)))
+
+(defun projectile--test-name-for-impl-name (impl-file-path)
+ (let* ((project-type (projectile-project-type))
+ (impl-file-name (file-name-sans-extension (file-name-nondirectory impl-file-path)))
+ (impl-file-ext (file-name-extension impl-file-path))
+ (test-prefix (funcall projectile-test-prefix-function project-type))
+ (test-suffix (funcall projectile-test-suffix-function project-type)))
+ (cond
+ (test-prefix (concat test-prefix impl-file-name "." impl-file-ext))
+ (test-suffix (concat impl-file-name test-suffix "." impl-file-ext))
+ (t (error "Project type not supported!")))))
+
+(defun projectile-create-test-file-for (impl-file-path)
+ (let* ((test-file (projectile--test-name-for-impl-name impl-file-path))
+ (project-root (projectile-project-root))
+ (relative-dir (file-name-directory (file-relative-name impl-file-path project-root)))
+ (test-dir (expand-file-name (replace-regexp-in-string "src/" "test/" relative-dir) project-root))
+ (test-path (expand-file-name test-file test-dir)))
+ (unless (file-exists-p test-path)
+ (progn (unless (file-exists-p test-dir)
+ (make-directory test-dir :create-parents))
+ test-path))))
+
+(defcustom projectile-create-missing-test-files nil
+ "During toggling, if non-nil enables creating test files if not found.
+
+When not-nil, every call to projectile-find-implementation-or-test-*
+creates test files if not found on the file system. Defaults to nil.
+It assumes the test/ folder is at the same level as src/."
+ :group 'projectile
+ :type 'boolean)
+
+(defun projectile-find-implementation-or-test (file-name)
+ "Given a FILE-NAME return the matching implementation or test filename."
+ (unless file-name (error "The current buffer is not visiting a file"))
+ (if (projectile-test-file-p file-name)
+ ;; find the matching impl file
+ (let ((impl-file (projectile-find-matching-file file-name)))
+ (if impl-file
+ (projectile-expand-root impl-file)
+ (error "No matching source file found")))
+ ;; find the matching test file
+ (let ((test-file (projectile-find-matching-test file-name)))
+ (if test-file
+ (projectile-expand-root test-file)
+ (if projectile-create-missing-test-files
+ (projectile-create-test-file-for file-name)
+ (error "No matching test file found"))))))
+
+;;;###autoload
+(defun projectile-find-implementation-or-test-other-window ()
+ "Open matching implementation or test file in other window."
+ (interactive)
+ (find-file-other-window
+ (projectile-find-implementation-or-test (buffer-file-name))))
+
+;;;###autoload
+(defun projectile-find-implementation-or-test-other-frame ()
+ "Open matching implementation or test file in other frame."
+ (interactive)
+ (find-file-other-frame
+ (projectile-find-implementation-or-test (buffer-file-name))))
+
+;;;###autoload
+(defun projectile-toggle-between-implementation-and-test ()
+ "Toggle between an implementation file and its test file."
+ (interactive)
+ (find-file
+ (projectile-find-implementation-or-test (buffer-file-name))))
+
+
+(defun projectile--registration-value-or-default (project-type key &optional default-value)
+ "Returs project registration value for a KEY for a project PROJECT-TYPE or if nothing DEFAULT-VALUE"
+ (let ((project (gethash project-type projectile-project-types)))
+ (if (and project (plist-member project key))
+ (plist-get project key)
+ default-value)))
+
+(defun projectile-test-prefix (project-type)
+ "Find default test files prefix based on PROJECT-TYPE."
+ (cl-flet ((prefix (&optional pfx)
+ (projectile--registration-value-or-default project-type 'test-prefix pfx)))
+ (cond
+ ((member project-type '(django python-pip python-pkg python-tox)) (prefix "test_"))
+ ((member project-type '(emacs-cask)) (prefix "test-"))
+ ((member project-type '(lein-midje)) (prefix "t_"))
+ (t (prefix)))))
+
+(defun projectile-test-suffix (project-type)
+ "Find default test files suffix based on PROJECT-TYPE."
+ (cl-flet ((suffix (&optional sfx)
+ (projectile--registration-value-or-default project-type 'test-suffix sfx)))
+ (cond
+ ((member project-type '(rebar)) (suffix "_SUITE"))
+ ((member project-type '(emacs-cask)) (suffix "-test"))
+ ((member project-type '(rails-rspec ruby-rspec)) (suffix "_spec"))
+ ((member project-type '(rails-test ruby-test lein-test boot-clj go elixir)) (suffix "_test"))
+ ((member project-type '(scons)) (suffix "test"))
+ ((member project-type '(maven symfony)) (suffix "Test"))
+ ((member project-type '(gradle gradlew grails)) (suffix "Spec"))
+ ((member project-type '(sbt)) (suffix "Spec"))
+ (t (suffix)))))
+
+(defun projectile-dirname-matching-count (a b)
+ "Count matching dirnames ascending file paths."
+ (setq a (reverse (split-string (or (file-name-directory a) "") "/" t))
+ b (reverse (split-string (or (file-name-directory b) "") "/" t)))
+ (let ((common 0))
+ (while (and a b (string-equal (pop a) (pop b)))
+ (setq common (1+ common)))
+ common))
+
+(defun projectile-group-file-candidates (file candidates)
+ "Group file candidates by dirname matching count."
+ (cl-sort (copy-sequence
+ (let (value result)
+ (while (setq value (pop candidates))
+ (let* ((key (projectile-dirname-matching-count file value))
+ (kv (assoc key result)))
+ (if kv
+ (setcdr kv (cons value (cdr kv)))
+ (push (list key value) result))))
+ (mapcar (lambda (x)
+ (cons (car x) (nreverse (cdr x))))
+ (nreverse result))))
+ (lambda (a b) (> (car a) (car b)))))
+
+(defun projectile-find-matching-test (file)
+ "Compute the name of the test matching FILE."
+ (let* ((basename (file-name-nondirectory (file-name-sans-extension file)))
+ (test-prefix (funcall projectile-test-prefix-function (projectile-project-type)))
+ (test-suffix (funcall projectile-test-suffix-function (projectile-project-type)))
+ (candidates
+ (cl-remove-if-not
+ (lambda (current-file)
+ (let ((name (file-name-nondirectory
+ (file-name-sans-extension current-file))))
+ (or (when test-prefix
+ (string-equal name (concat test-prefix basename)))
+ (when test-suffix
+ (string-equal name (concat basename test-suffix))))))
+ (projectile-current-project-files))))
+ (cond
+ ((null candidates) nil)
+ ((= (length candidates) 1) (car candidates))
+ (t (let ((grouped-candidates (projectile-group-file-candidates file candidates)))
+ (if (= (length (car grouped-candidates)) 2)
+ (car (last (car grouped-candidates)))
+ (projectile-completing-read
+ "Switch to: "
+ (apply 'append (mapcar 'cdr grouped-candidates)))))))))
+
+(defun projectile-find-matching-file (test-file)
+ "Compute the name of a file matching TEST-FILE."
+ (let* ((basename (file-name-nondirectory (file-name-sans-extension test-file)))
+ (test-prefix (funcall projectile-test-prefix-function (projectile-project-type)))
+ (test-suffix (funcall projectile-test-suffix-function (projectile-project-type)))
+ (candidates
+ (cl-remove-if-not
+ (lambda (current-file)
+ (let ((name (file-name-nondirectory
+ (file-name-sans-extension current-file))))
+ (or (when test-prefix
+ (string-equal (concat test-prefix name) basename))
+ (when test-suffix
+ (string-equal (concat name test-suffix) basename)))))
+ (projectile-current-project-files))))
+ (cond
+ ((null candidates) nil)
+ ((= (length candidates) 1) (car candidates))
+ (t (let ((grouped-candidates (projectile-group-file-candidates test-file candidates)))
+ (if (= (length (car grouped-candidates)) 2)
+ (car (last (car grouped-candidates)))
+ (projectile-completing-read
+ "Switch to: "
+ (apply 'append (mapcar 'cdr grouped-candidates)))))))))
+
+(defun projectile-grep-default-files ()
+ "Try to find a default pattern for `projectile-grep'.
+This is a subset of `grep-read-files', where either a matching entry from
+`grep-files-aliases' or file name extension pattern is returned."
+ (when buffer-file-name
+ (let* ((fn (file-name-nondirectory buffer-file-name))
+ (default-alias
+ (let ((aliases (remove (assoc "all" grep-files-aliases)
+ grep-files-aliases))
+ alias)
+ (while aliases
+ (setq alias (car aliases)
+ aliases (cdr aliases))
+ (if (string-match (mapconcat
+ #'wildcard-to-regexp
+ (split-string (cdr alias) nil t)
+ "\\|")
+ fn)
+ (setq aliases nil)
+ (setq alias nil)))
+ (cdr alias)))
+ (default-extension
+ (let ((ext (file-name-extension fn)))
+ (and ext (concat "*." ext)))))
+ (or default-alias default-extension))))
+
+(defun projectile--globally-ignored-file-suffixes-glob ()
+ "Return ignored file suffixes as a list of glob patterns."
+ (mapcar (lambda (pat) (concat "*" pat)) projectile-globally-ignored-file-suffixes))
+
+(defun projectile--read-search-string-with-default (prefix-label)
+ (let* ((prefix-label (projectile-prepend-project-name prefix-label))
+ (default-value (projectile-symbol-or-selection-at-point))
+ (default-label (if (or (not default-value)
+ (string= default-value ""))
+ ""
+ (format " (default %s)" default-value))))
+ (read-string (format "%s%s: " prefix-label default-label) nil nil default-value)))
+
+;;;###autoload
+(defun projectile-grep (&optional regexp arg)
+ "Perform rgrep in the project.
+
+With a prefix ARG asks for files (globbing-aware) which to grep in.
+With prefix ARG of `-' (such as `M--'), default the files (without prompt),
+to `projectile-grep-default-files'.
+
+With REGEXP given, don't query the user for a regexp."
+ (interactive "i\nP")
+ (require 'grep) ;; for `rgrep'
+ (let* ((roots (projectile-get-project-directories))
+ (search-regexp (or regexp
+ (projectile--read-search-string-with-default "Grep for")))
+ (files (and arg (or (and (equal current-prefix-arg '-)
+ (projectile-grep-default-files))
+ (read-string (projectile-prepend-project-name "Grep in: ")
+ (projectile-grep-default-files))))))
+ (dolist (root-dir roots)
+ (require 'vc-git) ;; for `vc-git-grep'
+ ;; in git projects users have the option to use `vc-git-grep' instead of `rgrep'
+ (if (and (eq (projectile-project-vcs) 'git)
+ projectile-use-git-grep
+ (fboundp 'vc-git-grep))
+ (vc-git-grep search-regexp (or files "") root-dir)
+ ;; paths for find-grep should relative and without trailing /
+ (let ((grep-find-ignored-directories
+ (cl-union (mapcar (lambda (f) (directory-file-name (file-relative-name f root-dir)))
+ (projectile-ignored-directories))
+ grep-find-ignored-directories))
+ (grep-find-ignored-files
+ (cl-union (append (mapcar (lambda (file)
+ (file-relative-name file root-dir))
+ (projectile-ignored-files))
+ (projectile--globally-ignored-file-suffixes-glob))
+ grep-find-ignored-files)))
+ (grep-compute-defaults)
+ (rgrep search-regexp (or files "* .*") root-dir))))
+ (run-hooks 'projectile-grep-finished-hook)))
+
+;;;###autoload
+(defun projectile-ag (search-term &optional arg)
+ "Run an ag search with SEARCH-TERM in the project.
+
+With an optional prefix argument ARG SEARCH-TERM is interpreted as a
+regular expression."
+ (interactive
+ (list (projectile--read-search-string-with-default
+ (format "Ag %ssearch for" (if current-prefix-arg "regexp " "")))
+ current-prefix-arg))
+ (if (require 'ag nil 'noerror)
+ (let ((ag-command (if arg 'ag-regexp 'ag))
+ (ag-ignore-list (delq nil
+ (delete-dups
+ (append
+ ag-ignore-list
+ (projectile--globally-ignored-file-suffixes-glob)
+ ;; ag supports git ignore files directly
+ (unless (eq (projectile-project-vcs) 'git)
+ (append (projectile-ignored-files-rel)
+ (projectile-ignored-directories-rel)
+ grep-find-ignored-files
+ grep-find-ignored-directories))))))
+ ;; reset the prefix arg, otherwise it will affect the ag-command
+ (current-prefix-arg nil))
+ (funcall ag-command search-term (projectile-project-root)))
+ (error "Package 'ag' is not available")))
+
+(defun projectile-tags-exclude-patterns ()
+ "Return a string with exclude patterns for ctags."
+ (mapconcat (lambda (pattern) (format "--exclude=\"%s\""
+ (directory-file-name pattern)))
+ (projectile-ignored-directories-rel) " "))
+
+;;;###autoload
+(defun projectile-regenerate-tags ()
+ "Regenerate the project's [e|g]tags."
+ (interactive)
+ (if (and (boundp 'ggtags-mode)
+ (memq projectile-tags-backend '(auto ggtags)))
+ (progn
+ (let* ((ggtags-project-root (projectile-project-root))
+ (default-directory ggtags-project-root))
+ (ggtags-ensure-project)
+ (ggtags-update-tags t)))
+ (let* ((project-root (projectile-project-root))
+ (tags-exclude (projectile-tags-exclude-patterns))
+ (default-directory project-root)
+ (tags-file (expand-file-name projectile-tags-file-name))
+ (command (format projectile-tags-command tags-file tags-exclude))
+ shell-output exit-code)
+ (with-temp-buffer
+ (setq exit-code
+ (call-process-shell-command command nil (current-buffer))
+ shell-output (projectile-trim-string
+ (buffer-substring (point-min) (point-max)))))
+ (unless (zerop exit-code)
+ (error shell-output))
+ (visit-tags-table tags-file)
+ (message "Regenerated %s" tags-file))))
+
+(defun projectile-visit-project-tags-table ()
+ "Visit the current project's tags table."
+ (when (projectile-project-p)
+ (let ((tags-file (projectile-expand-root projectile-tags-file-name)))
+ (when (file-exists-p tags-file)
+ (with-demoted-errors "Error loading tags-file: %s"
+ (visit-tags-table tags-file t))))))
+
+(defun projectile-determine-find-tag-fn ()
+ "Determine which function to use for a call to `projectile-find-tag'."
+ (or
+ (cond
+ ((eq projectile-tags-backend 'auto)
+ (cond
+ ((fboundp 'ggtags-find-tag-dwim)
+ 'ggtags-find-tag-dwim)
+ ((fboundp 'xref-find-definitions)
+ 'xref-find-definitions)
+ ((fboundp 'etags-select-find-tag)
+ 'etags-select-find-tag)))
+ ((eq projectile-tags-backend 'xref)
+ (when (fboundp 'xref-find-definitions)
+ 'xref-find-definitions))
+ ((eq projectile-tags-backend 'ggtags)
+ (when (fboundp 'ggtags-find-tag-dwim)
+ 'ggtags-find-tag-dwim))
+ ((eq projectile-tags-backend 'etags-select)
+ (when (fboundp 'etags-select-find-tag)
+ 'etags-select-find-tag)))
+ 'find-tag))
+
+;;;###autoload
+(defun projectile-find-tag ()
+ "Find tag in project."
+ (interactive)
+ (projectile-visit-project-tags-table)
+ ;; Auto-discover the user's preference for tags
+ (let ((find-tag-fn (projectile-determine-find-tag-fn)))
+ (call-interactively find-tag-fn)))
+
+(defmacro projectile-with-default-dir (dir &rest body)
+ "Invoke in DIR the BODY."
+ (declare (debug t) (indent 1))
+ `(let ((default-directory ,dir))
+ ,@body))
+
+;;;###autoload
+(defun projectile-run-command-in-root ()
+ "Invoke `execute-extended-command' in the project's root."
+ (interactive)
+ (projectile-with-default-dir (projectile-project-root)
+ (call-interactively 'execute-extended-command)))
+
+;;;###autoload
+(defun projectile-run-shell-command-in-root ()
+ "Invoke `shell-command' in the project's root."
+ (interactive)
+ (projectile-with-default-dir (projectile-project-root)
+ (call-interactively 'shell-command)))
+
+;;;###autoload
+(defun projectile-run-async-shell-command-in-root ()
+ "Invoke `async-shell-command' in the project's root."
+ (interactive)
+ (projectile-with-default-dir (projectile-project-root)
+ (call-interactively 'async-shell-command)))
+
+;;;###autoload
+(defun projectile-run-shell ()
+ "Invoke `shell' in the project's root."
+ (interactive)
+ (projectile-with-default-dir (projectile-project-root)
+ (shell (concat "*shell " (projectile-project-name) "*"))))
+
+;;;###autoload
+(defun projectile-run-eshell ()
+ "Invoke `eshell' in the project's root."
+ (interactive)
+ (let ((eshell-buffer-name (concat "*eshell " (projectile-project-name) "*")))
+ (projectile-with-default-dir (projectile-project-root)
+ (eshell))))
+
+;;;###autoload
+(defun projectile-run-term (program)
+ "Invoke `term' in the project's root."
+ (interactive (list nil))
+ (let* ((term (concat "term " (projectile-project-name)))
+ (buffer (concat "*" term "*")))
+ (unless (get-buffer buffer)
+ (require 'term)
+ (let ((program (or program
+ (read-from-minibuffer "Run program: "
+ (or explicit-shell-file-name
+ (getenv "ESHELL")
+ (getenv "SHELL")
+ "/bin/sh")))))
+ (projectile-with-default-dir (projectile-project-root)
+ (set-buffer (make-term term program))
+ (term-mode)
+ (term-char-mode))))
+ (switch-to-buffer buffer)))
+
+(defun projectile-files-in-project-directory (directory)
+ "Return a list of files in DIRECTORY."
+ (let ((dir (file-relative-name (expand-file-name directory)
+ (projectile-project-root))))
+ (cl-remove-if-not
+ (lambda (f) (string-prefix-p dir f))
+ (projectile-current-project-files))))
+
+(defun projectile-unixy-system-p ()
+ "Check to see if unixy text utilities are installed."
+ (cl-every
+ (lambda (x) (executable-find x))
+ '("grep" "cut" "uniq")))
+
+(defun projectile-files-from-cmd (cmd directory)
+ "Use a grep-like CMD to search for files within DIRECTORY.
+
+CMD should include the necessary search params and should output
+equivalently to grep -HlI (only unique matching filenames).
+Returns a list of expanded filenames."
+ (let ((default-directory directory))
+ (mapcar (lambda (str)
+ (concat directory
+ (if (string-prefix-p "./" str)
+ (substring str 2)
+ str)))
+ (split-string
+ (projectile-trim-string
+ (shell-command-to-string cmd))
+ "\n+"
+ t))))
+
+(defun projectile-files-with-string (string directory)
+ "Return a list of all files containing STRING in DIRECTORY.
+
+Tries to use ag, ack, git-grep, and grep in that order. If those
+are impossible (for instance on Windows), returns a list of all
+files in the project."
+ (if (projectile-unixy-system-p)
+ (let* ((search-term (shell-quote-argument string))
+ (cmd (cond ((executable-find "ag")
+ (concat "ag --literal --nocolor --noheading -l -- "
+ search-term))
+ ((executable-find "ack")
+ (concat "ack --literal --noheading --nocolor -l -- "
+ search-term))
+ ((and (executable-find "git")
+ (eq (projectile-project-vcs) 'git))
+ (concat "git grep -HlI " search-term))
+ (t
+ ;; -r: recursive
+ ;; -H: show filename for each match
+ ;; -l: show only file names with matches
+ ;; -I: no binary files
+ (format "grep -rHlI %s ." search-term)))))
+ (projectile-files-from-cmd cmd directory))
+ ;; we have to reject directories as a workaround to work with git submodules
+ (cl-remove-if
+ #'file-directory-p
+ (mapcar #'projectile-expand-root (projectile-dir-files directory)))))
+
+;;;###autoload
+(defun projectile-replace (&optional arg)
+ "Replace literal string in project using non-regexp `tags-query-replace'.
+
+With a prefix argument ARG prompts you for a directory on which
+to run the replacement."
+ (interactive "P")
+ (let* ((old-text (read-string
+ (projectile-prepend-project-name "Replace: ")
+ (projectile-symbol-or-selection-at-point)))
+ (new-text (read-string
+ (projectile-prepend-project-name
+ (format "Replace %s with: " old-text))))
+ (directory (if arg
+ (file-name-as-directory
+ (read-directory-name "Replace in directory: "))
+ (projectile-project-root)))
+ (files (projectile-files-with-string old-text directory)))
+ ;; Adapted from `tags-query-replace' for literal strings (not regexp)
+ (setq tags-loop-scan `(let ,(unless (equal old-text (downcase old-text))
+ '((case-fold-search nil)))
+ (if (search-forward ',old-text nil t)
+ ;; When we find a match, move back to
+ ;; the beginning of it so
+ ;; perform-replace will see it.
+ (goto-char (match-beginning 0))))
+ tags-loop-operate `(perform-replace ',old-text ',new-text t nil nil
+ nil multi-query-replace-map))
+ (tags-loop-continue (or (cons 'list files) t))))
+
+;;;###autoload
+(defun projectile-replace-regexp (&optional arg)
+ "Replace a regexp in the project using `tags-query-replace'.
+
+With a prefix argument ARG prompts you for a directory on which
+to run the replacement."
+ (interactive "P")
+ (let* ((old-text (read-string
+ (projectile-prepend-project-name "Replace regexp: ")
+ (projectile-symbol-or-selection-at-point)))
+ (new-text (read-string
+ (projectile-prepend-project-name
+ (format "Replace regexp %s with: " old-text))))
+ (directory (if arg
+ (file-name-as-directory
+ (read-directory-name "Replace regexp in directory: "))
+ (projectile-project-root)))
+ (files
+ ;; We have to reject directories as a workaround to work with git submodules.
+ ;;
+ ;; We can't narrow the list of files with
+ ;; `projectile-files-with-string' because those regexp tools
+ ;; don't support Emacs regular expressions.
+ (cl-remove-if
+ #'file-directory-p
+ (mapcar #'projectile-expand-root (projectile-dir-files directory)))))
+ (tags-query-replace old-text new-text nil (cons 'list files))))
+
+(defun projectile-symbol-or-selection-at-point ()
+ "Get the symbol or selected text at point."
+ (if (use-region-p)
+ (buffer-substring-no-properties (region-beginning) (region-end))
+ (projectile-symbol-at-point)))
+
+(defun projectile-symbol-at-point ()
+ "Get the symbol at point and strip its properties."
+ (substring-no-properties (or (thing-at-point 'symbol) "")))
+
+;;;###autoload
+(defun projectile-kill-buffers ()
+ "Kill all project buffers."
+ (interactive)
+ (let ((name (projectile-project-name))
+ (buffers (projectile-project-buffers)))
+ (if (yes-or-no-p
+ (format "Are you sure you want to kill %d buffer(s) for '%s'? "
+ (length buffers) name))
+ ;; we take care not to kill indirect buffers directly
+ ;; as we might encounter them after their base buffers are killed
+ (mapc #'kill-buffer (cl-remove-if 'buffer-base-buffer buffers)))))
+
+;;;###autoload
+(defun projectile-save-project-buffers ()
+ "Save all project buffers."
+ (interactive)
+ (dolist (buf (projectile-project-buffers))
+ (with-current-buffer buf
+ (when buffer-file-name
+ (save-buffer)))))
+
+;;;###autoload
+(defun projectile-dired ()
+ "Open `dired' at the root of the project."
+ (interactive)
+ (dired (projectile-project-root)))
+
+;;;###autoload
+(defun projectile-dired-other-window ()
+ "Open `dired' at the root of the project in another window."
+ (interactive)
+ (dired-other-window (projectile-project-root)))
+
+;;;###autoload
+(defun projectile-dired-other-frame ()
+ "Open `dired' at the root of the project in another frame."
+ (interactive)
+ (dired-other-frame (projectile-project-root)))
+
+;;;###autoload
+(defun projectile-vc (&optional project-root)
+ "Open `vc-dir' at the root of the project.
+
+For git projects `magit-status-internal' is used if available.
+For hg projects `monky-status' is used if available."
+ (interactive)
+ (or project-root (setq project-root (projectile-project-root)))
+ (let ((vcs (projectile-project-vcs project-root)))
+ (cl-case vcs
+ (git
+ (cond ((fboundp 'magit-status-internal)
+ (magit-status-internal project-root))
+ ((fboundp 'magit-status)
+ (with-no-warnings (magit-status project-root)))
+ (t
+ (vc-dir project-root))))
+ (hg
+ (if (fboundp 'monky-status)
+ (monky-status project-root)
+ (vc-dir project-root)))
+ (t (vc-dir project-root)))))
+
+;;;###autoload
+(defun projectile-recentf ()
+ "Show a list of recently visited files in a project."
+ (interactive)
+ (if (boundp 'recentf-list)
+ (find-file (projectile-expand-root
+ (projectile-completing-read
+ "Recently visited files: "
+ (projectile-recentf-files))))
+ (message "recentf is not enabled")))
+
+(defun projectile-recentf-files ()
+ "Return a list of recently visited files in a project."
+ (and (boundp 'recentf-list)
+ (let ((project-root (projectile-project-root)))
+ (mapcar
+ (lambda (f) (file-relative-name f project-root))
+ (cl-remove-if-not
+ (lambda (f) (string-prefix-p project-root f))
+ recentf-list)))))
+
+(defun projectile-serialize-cache ()
+ "Serializes the memory cache to the hard drive."
+ (projectile-serialize projectile-projects-cache projectile-cache-file))
+
+(defvar projectile-compilation-cmd-map
+ (make-hash-table :test 'equal)
+ "A mapping between projects and the last compilation command used on them.")
+
+(defvar projectile-test-cmd-map
+ (make-hash-table :test 'equal)
+ "A mapping between projects and the last test command used on them.")
+
+(defvar projectile-run-cmd-map
+ (make-hash-table :test 'equal)
+ "A mapping between projects and the last run command used on them.")
+
+(defvar projectile-project-compilation-cmd nil
+ "The command to use with `projectile-compile-project'.
+It takes precedence over the default command for the project type when set.
+Should be set via .dir-locals.el.")
+
+(defvar projectile-project-compilation-dir nil
+ "The directory to use with `projectile-compile-project'.
+The directory path is relative to the project root.
+Should be set via .dir-locals.el.")
+
+(defvar projectile-project-test-cmd nil
+ "The command to use with `projectile-test-project'.
+It takes precedence over the default command for the project type when set.
+Should be set via .dir-locals.el.")
+
+(defvar projectile-project-run-cmd nil
+ "The command to use with `projectile-run-project'.
+It takes precedence over the default command for the project type when set.
+Should be set via .dir-locals.el.")
+
+(defun projectile-default-compilation-command (project-type)
+ "Retrieve default compilation command for PROJECT-TYPE."
+ (plist-get (gethash project-type projectile-project-types) 'compile-command))
+
+(defun projectile-default-test-command (project-type)
+ "Retrieve default test command for PROJECT-TYPE."
+ (plist-get (gethash project-type projectile-project-types) 'test-command))
+
+(defun projectile-default-run-command (project-type)
+ "Retrieve default run command for PROJECT-TYPE."
+ (plist-get (gethash project-type projectile-project-types) 'run-command))
+
+(defun projectile-compilation-command (compile-dir)
+ "Retrieve the compilation command for COMPILE-DIR."
+ (or (gethash compile-dir projectile-compilation-cmd-map)
+ projectile-project-compilation-cmd
+ (projectile-default-compilation-command (projectile-project-type))))
+
+(defun projectile-test-command (project)
+ "Retrieve the test command for PROJECT."
+ (or (gethash project projectile-test-cmd-map)
+ projectile-project-test-cmd
+ (projectile-default-test-command (projectile-project-type))))
+
+(defun projectile-run-command (project)
+ "Retrieve the run command for PROJECT."
+ (or (gethash project projectile-run-cmd-map)
+ projectile-project-run-cmd
+ (projectile-default-run-command (projectile-project-type))))
+
+(defun projectile-read-command (prompt command)
+ "Adapted from `compilation-read-command'."
+ (read-shell-command prompt command
+ (if (equal (car compile-history) command)
+ '(compile-history . 1)
+ 'compile-history)))
+
+(defun projectile-compilation-dir ()
+ "Choose the directory to use for project compilation."
+ (if projectile-project-compilation-dir
+ (file-truename
+ (concat (file-name-as-directory (projectile-project-root))
+ (file-name-as-directory projectile-project-compilation-dir)))
+ (projectile-project-root)))
+
+(defun projectile-maybe-read-command (arg default-cmd prompt)
+ "Prompt user for command unless DEFAULT-CMD is an Elisp function."
+ (if (and (or (stringp default-cmd) (null default-cmd))
+ (or compilation-read-command arg))
+ (projectile-read-command prompt default-cmd)
+ default-cmd))
+
+(defun projectile-run-compilation (cmd)
+ "Run external or Elisp compilation command CMD."
+ (if (functionp cmd)
+ (funcall cmd)
+ (compile cmd)))
+
+;;;###autoload
+(defun projectile-compile-project (arg &optional dir)
+ "Run project compilation command.
+
+Normally you'll be prompted for a compilation command, unless
+variable `compilation-read-command'. You can force the prompt
+with a prefix ARG."
+ (interactive "P")
+ (let* ((project-root (projectile-project-root))
+ (default-directory (or dir (projectile-compilation-dir)))
+ (default-cmd (projectile-compilation-command default-directory))
+ (compilation-cmd (projectile-maybe-read-command arg default-cmd "Compile command: ")))
+ (puthash default-directory compilation-cmd projectile-compilation-cmd-map)
+ (save-some-buffers (not compilation-ask-about-save)
+ (lambda ()
+ (projectile-project-buffer-p (current-buffer)
+ project-root)))
+ (projectile-run-compilation compilation-cmd)))
+
+(defadvice compilation-find-file (around projectile-compilation-find-file)
+ "Try to find a buffer for FILENAME, if we cannot find it,
+fallback to the original function."
+ (let ((filename (ad-get-arg 1))
+ full-filename)
+ (ad-set-arg 1
+ (or
+ (if (file-exists-p (expand-file-name filename))
+ filename)
+ ;; Try to find the filename using projectile
+ (and (projectile-project-p)
+ (let ((root (projectile-project-root))
+ (dirs (cons "" (projectile-current-project-dirs))))
+ (when (setq full-filename
+ (car (cl-remove-if-not
+ #'file-exists-p
+ (mapcar
+ (lambda (f)
+ (expand-file-name
+ filename
+ (expand-file-name f root)))
+ dirs))))
+ full-filename)))
+ ;; Fall back to the old argument
+ filename))
+ ad-do-it))
+
+;; TODO - factor this duplication out
+;;;###autoload
+(defun projectile-test-project (arg)
+ "Run project test command.
+
+Normally you'll be prompted for a compilation command, unless
+variable `compilation-read-command'. You can force the prompt
+with a prefix ARG."
+ (interactive "P")
+ (let* ((project-root (projectile-project-root))
+ (default-cmd (projectile-test-command project-root))
+ (test-cmd (projectile-maybe-read-command arg default-cmd "Test command: "))
+ (default-directory project-root))
+ (puthash project-root test-cmd projectile-test-cmd-map)
+ (save-some-buffers (not compilation-ask-about-save)
+ (lambda ()
+ (projectile-project-buffer-p (current-buffer)
+ project-root)))
+ (projectile-run-compilation test-cmd)))
+
+;;;###autoload
+(defun projectile-run-project (arg)
+ "Run project run command.
+
+Normally you'll be prompted for a compilation command, unless
+variable `compilation-read-command'. You can force the prompt
+with a prefix ARG."
+ (interactive "P")
+ (let* ((project-root (projectile-project-root))
+ (default-cmd (projectile-run-command project-root))
+ (run-cmd (projectile-maybe-read-command arg default-cmd "Run command: "))
+ (default-directory project-root))
+ (puthash project-root run-cmd projectile-run-cmd-map)
+ (projectile-run-compilation run-cmd)))
+
+(defun projectile-open-projects ()
+ "Return a list of all open projects.
+An open project is a project with any open buffers."
+ (delete-dups
+ (delq nil
+ (mapcar (lambda (buffer)
+ (with-current-buffer buffer
+ (when (projectile-project-p)
+ (abbreviate-file-name (projectile-project-root)))))
+ (buffer-list)))))
+
+(defun projectile--remove-current-project (projects)
+ "Remove the current project (if any) from the list of PROJECTS."
+ (if (projectile-project-p)
+ (projectile-difference projects
+ (list (abbreviate-file-name (projectile-project-root))))
+ projects))
+
+(defun projectile-relevant-known-projects ()
+ "Return a list of known projects except the current one (if present)."
+ (projectile--remove-current-project projectile-known-projects))
+
+(defun projectile-relevant-open-projects ()
+ "Return a list of open projects except the current one (if present)."
+ (projectile--remove-current-project (projectile-open-projects)))
+
+;;;###autoload
+(defun projectile-switch-project (&optional arg)
+ "Switch to a project we have visited before.
+Invokes the command referenced by `projectile-switch-project-action' on switch.
+With a prefix ARG invokes `projectile-commander' instead of
+`projectile-switch-project-action.'"
+ (interactive "P")
+ (let ((projects (projectile-relevant-known-projects)))
+ (if projects
+ (projectile-completing-read
+ "Switch to project: " projects
+ :action (lambda (project)
+ (projectile-switch-project-by-name project arg)))
+ (user-error "There are no known projects"))))
+
+;;;###autoload
+(defun projectile-switch-open-project (&optional arg)
+ "Switch to a project we have currently opened.
+Invokes the command referenced by `projectile-switch-project-action' on switch.
+With a prefix ARG invokes `projectile-commander' instead of
+`projectile-switch-project-action.'"
+ (interactive "P")
+ (let ((projects (projectile-relevant-open-projects)))
+ (if projects
+ (projectile-switch-project-by-name
+ (projectile-completing-read "Switch to open project: " projects)
+ arg)
+ (user-error "There are no open projects"))))
+
+(defun projectile-switch-project-by-name (project-to-switch &optional arg)
+ "Switch to project by project name PROJECT-TO-SWITCH.
+Invokes the command referenced by `projectile-switch-project-action' on switch.
+With a prefix ARG invokes `projectile-commander' instead of
+`projectile-switch-project-action.'"
+ (let ((switch-project-action (if arg
+ 'projectile-commander
+ projectile-switch-project-action)))
+ (run-hooks 'projectile-before-switch-project-hook)
+ (let ((default-directory project-to-switch))
+ ;; use a temporary buffer to load PROJECT-TO-SWITCH's dir-locals before calling SWITCH-PROJECT-ACTION
+ (with-temp-buffer
+ (hack-dir-local-variables-non-file-buffer))
+ ;; Normally the project name is determined from the current
+ ;; buffer. However, when we're switching projects, we want to
+ ;; show the name of the project being switched to, rather than
+ ;; the current project, in the minibuffer. This is a simple hack
+ ;; to tell the `projectile-project-name' function to ignore the
+ ;; current buffer and the caching mechanism, and just return the
+ ;; value of the `projectile-project-name' variable. We also
+ ;; need to ignore the cached project-root value otherwise we end
+ ;; up still showing files from the current project rather than
+ ;; the new project
+ (let ((projectile-cached-project-root nil)
+ (projectile-project-name (funcall projectile-project-name-function
+ project-to-switch)))
+ (funcall switch-project-action)))
+ (run-hooks 'projectile-after-switch-project-hook)))
+
+;;;###autoload
+(defun projectile-find-file-in-directory (&optional directory)
+ "Jump to a file in a (maybe regular) DIRECTORY.
+
+This command will first prompt for the directory the file is in."
+ (interactive "DFind file in directory: ")
+ (let ((default-directory directory)
+ (projectile-require-project-root nil))
+ (if (projectile-project-p)
+ ;; target directory is in a project
+ (let ((file (projectile-completing-read "Find file: "
+ (projectile-dir-files directory))))
+ (find-file (expand-file-name file (projectile-project-root)))
+ (run-hooks 'projectile-find-file-hook))
+ ;; target directory is not in a project
+ (projectile-find-file))))
+
+(defun projectile-all-project-files ()
+ "Get a list of all files in all projects."
+ (cl-mapcan
+ (lambda (project)
+ (when (file-exists-p project)
+ (let ((default-directory project)
+ (projectile-cached-project-root nil))
+ (mapcar (lambda (file)
+ (expand-file-name file project))
+ (projectile-current-project-files)))))
+ projectile-known-projects))
+
+;;;###autoload
+(defun projectile-find-file-in-known-projects ()
+ "Jump to a file in any of the known projects."
+ (interactive)
+ (let ((projectile-require-project-root nil))
+ (find-file (projectile-completing-read "Find file in projects: " (projectile-all-project-files)))))
+
+(defcustom projectile-after-switch-project-hook nil
+ "Hooks run right after project is switched."
+ :group 'projectile
+ :type 'hook)
+
+(defcustom projectile-before-switch-project-hook nil
+ "Hooks run when right before project is switched."
+ :group 'projectile
+ :type 'hook)
+
+(defun projectile-keep-project-p (project)
+ "Determine whether we should cleanup (remove) PROJECT or not.
+
+It handles the case of remote projects as well.
+See `projectile-cleanup-known-projects'."
+ ;; Taken from from `recentf-keep-default-predicate'
+ (cond
+ ((file-remote-p project nil t) (file-readable-p project))
+ ((file-remote-p project))
+ ((file-readable-p project))))
+
+;;;###autoload
+(defun projectile-cleanup-known-projects ()
+ "Remove known projects that don't exist anymore."
+ (interactive)
+ (projectile-merge-known-projects)
+ (let ((projects-kept (cl-remove-if-not #'projectile-keep-project-p projectile-known-projects))
+ (projects-removed (cl-remove-if #'projectile-keep-project-p projectile-known-projects)))
+ (setq projectile-known-projects projects-kept)
+ (projectile-merge-known-projects)
+ (if projects-removed
+ (message "Projects removed: %s"
+ (mapconcat #'identity projects-removed ", "))
+ (message "No projects needed to be removed."))))
+
+;;;###autoload
+(defun projectile-clear-known-projects ()
+ "Clear both `projectile-known-projects' and `projectile-known-projects-file'."
+ (interactive)
+ (setq projectile-known-projects nil)
+ (projectile-save-known-projects))
+
+;;;###autoload
+(defun projectile-remove-known-project (&optional project)
+ "Remove PROJECT from the list of known projects."
+ (interactive (list (projectile-completing-read
+ "Remove from known projects: " projectile-known-projects
+ :action 'projectile-remove-known-project)))
+ (unless (called-interactively-p 'any)
+ (setq projectile-known-projects
+ (cl-remove-if
+ (lambda (proj) (string= project proj))
+ projectile-known-projects))
+ (projectile-merge-known-projects)
+ (when projectile-verbose
+ (message "Project %s removed from the list of known projects." project))))
+
+;;;###autoload
+(defun projectile-remove-current-project-from-known-projects ()
+ "Remove the current project from the list of known projects."
+ (interactive)
+ (projectile-remove-known-project (abbreviate-file-name (projectile-project-root))))
+
+(defun projectile-ignored-projects ()
+ "A list of projects that should not be save in `projectile-known-projects'."
+ (mapcar #'file-truename projectile-ignored-projects))
+
+(defun projectile-ignored-project-p (project-root)
+ "Return t if PROJECT-ROOT should not be added to `projectile-known-projects'."
+ (or (member project-root (projectile-ignored-projects))
+ (and (functionp projectile-ignored-project-function)
+ (funcall projectile-ignored-project-function project-root))))
+
+(defun projectile-add-known-project (project-root)
+ "Add PROJECT-ROOT to the list of known projects."
+ (interactive (list (read-directory-name "Add to known projects: ")))
+ (unless (projectile-ignored-project-p project-root)
+ (setq projectile-known-projects
+ (delete-dups
+ (cons (abbreviate-file-name project-root)
+ projectile-known-projects)))))
+
+(defun projectile-load-known-projects ()
+ "Load saved projects from `projectile-known-projects-file'.
+Also set `projectile-known-projects'."
+ (setq projectile-known-projects
+ (projectile-unserialize projectile-known-projects-file))
+ (setq projectile-known-projects-on-file
+ (and (sequencep projectile-known-projects)
+ (copy-sequence projectile-known-projects))))
+
+;; load the known projects
+(projectile-load-known-projects)
+
+(defun projectile-save-known-projects ()
+ "Save PROJECTILE-KNOWN-PROJECTS to PROJECTILE-KNOWN-PROJECTS-FILE."
+ (projectile-serialize projectile-known-projects
+ projectile-known-projects-file)
+ (setq projectile-known-projects-on-file
+ (and (sequencep projectile-known-projects)
+ (copy-sequence projectile-known-projects))))
+
+(defun projectile-merge-known-projects ()
+ "Merge any change from `projectile-known-projects-file' and save to disk.
+
+This enables multiple Emacs processes to make changes without
+overwriting each other's changes."
+ (let* ((known-now projectile-known-projects)
+ (known-on-last-sync projectile-known-projects-on-file)
+ (known-on-file
+ (projectile-unserialize projectile-known-projects-file))
+ (removed-after-sync (projectile-difference known-on-last-sync known-now))
+ (removed-in-other-process
+ (projectile-difference known-on-last-sync known-on-file))
+ (result (delete-dups
+ (projectile-difference
+ (append known-now known-on-file)
+ (append removed-after-sync removed-in-other-process)))))
+ (setq projectile-known-projects result)
+ (projectile-save-known-projects)))
+
+(define-ibuffer-filter projectile-files
+ "Show Ibuffer with all buffers in the current project."
+ (:reader (read-directory-name "Project root: " (ignore-errors (projectile-project-root)))
+ :description nil)
+ (with-current-buffer buf
+ (equal (file-name-as-directory (expand-file-name qualifier))
+ (ignore-errors (projectile-project-root)))))
+
+(defun projectile-ibuffer-by-project (project-root)
+ "Open an IBuffer window showing all buffers in PROJECT-ROOT."
+ (let ((project-name (funcall projectile-project-name-function project-root)))
+ (ibuffer nil (format "*%s Buffers*" project-name)
+ (list (cons 'projectile-files project-root)))))
+
+;;;###autoload
+(defun projectile-ibuffer (prefix)
+ "Open an IBuffer window showing all buffers in the current project.
+
+Let user choose another project when PREFIX is supplied."
+ (interactive "p")
+ (let ((project-root (if (= prefix 4)
+ (projectile-completing-read
+ "Project name: "
+ (projectile-relevant-known-projects))
+ (projectile-project-root))))
+
+ (projectile-ibuffer-by-project project-root)))
+
+;;;; projectile-commander
+
+(defconst projectile-commander-help-buffer "*Commander Help*")
+
+(defvar projectile-commander-methods nil
+ "List of file-selection methods for the `projectile-commander' command.
+Each element is a list (KEY DESCRIPTION FUNCTION).
+DESCRIPTION is a one-line description of what the key selects.")
+
+;;;###autoload
+(defun projectile-commander ()
+ "Execute a Projectile command with a single letter.
+The user is prompted for a single character indicating the action to invoke.
+The `?' character describes then
+available actions.
+
+See `def-projectile-commander-method' for defining new methods."
+ (interactive)
+ (let* ((choices (mapcar #'car projectile-commander-methods))
+ (prompt (concat "Commander [" choices "]: "))
+ (ch (read-char-choice prompt choices))
+ (fn (nth 2 (assq ch projectile-commander-methods))))
+ (funcall fn)))
+
+(defmacro def-projectile-commander-method (key description &rest body)
+ "Define a new `projectile-commander' method.
+
+KEY is the key the user will enter to choose this method.
+
+DESCRIPTION is a one-line sentence describing how the method.
+
+BODY is a series of forms which are evaluated when the find
+is chosen."
+ (let ((method `(lambda ()
+ ,@body)))
+ `(setq projectile-commander-methods
+ (cl-sort (copy-sequence
+ (cons (list ,key ,description ,method)
+ (assq-delete-all ,key projectile-commander-methods)))
+ (lambda (a b) (< (car a) (car b)))))))
+
+(def-projectile-commander-method ?? "Commander help buffer."
+ (ignore-errors (kill-buffer projectile-commander-help-buffer))
+ (with-current-buffer (get-buffer-create projectile-commander-help-buffer)
+ (insert "Projectile Commander Methods:\n\n")
+ (dolist (met projectile-commander-methods)
+ (insert (format "%c:\t%s\n" (car met) (cadr met))))
+ (goto-char (point-min))
+ (help-mode)
+ (display-buffer (current-buffer) t))
+ (projectile-commander))
+
+(defun projectile-commander-bindings ()
+ (def-projectile-commander-method ?A
+ "Find ag on project."
+ (call-interactively 'projectile-ag))
+
+ (def-projectile-commander-method ?f
+ "Find file in project."
+ (projectile-find-file))
+
+ (def-projectile-commander-method ?T
+ "Find test file in project."
+ (projectile-find-test-file))
+
+ (def-projectile-commander-method ?b
+ "Switch to project buffer."
+ (projectile-switch-to-buffer))
+
+ (def-projectile-commander-method ?d
+ "Find directory in project."
+ (projectile-find-dir))
+
+ (def-projectile-commander-method ?D
+ "Open project root in dired."
+ (projectile-dired))
+
+ (def-projectile-commander-method ?v
+ "Open project root in vc-dir or magit."
+ (projectile-vc))
+
+ (def-projectile-commander-method ?V
+ "Browse dirty projects"
+ (projectile-browse-dirty-projects))
+
+ (def-projectile-commander-method ?r
+ "Replace a string in the project."
+ (projectile-replace))
+
+ (def-projectile-commander-method ?R
+ "Regenerate the project's [e|g]tags."
+ (projectile-regenerate-tags))
+
+ (def-projectile-commander-method ?g
+ "Run grep on project."
+ (projectile-grep))
+
+ (def-projectile-commander-method ?s
+ "Switch project."
+ (projectile-switch-project))
+
+ (def-projectile-commander-method ?o
+ "Run multi-occur on project buffers."
+ (projectile-multi-occur))
+
+ (def-projectile-commander-method ?j
+ "Find tag in project."
+ (projectile-find-tag))
+
+ (def-projectile-commander-method ?k
+ "Kill all project buffers."
+ (projectile-kill-buffers))
+
+ (def-projectile-commander-method ?e
+ "Find recently visited file in project."
+ (projectile-recentf)))
+
+(projectile-commander-bindings)
+
+(defun projectile-read-variable ()
+ "Prompt for a variable and return its name."
+ (completing-read "Variable: "
+ obarray
+ '(lambda (v)
+ (and (boundp v) (not (keywordp v))))
+ t))
+
+(define-skeleton projectile-skel-variable-cons
+ "Insert a variable-name and a value in a cons-cell."
+ "Value: "
+ "("
+ (projectile-read-variable)
+ " . "
+ str
+ ")")
+
+(define-skeleton projectile-skel-dir-locals
+ "Insert a .dir-locals.el template."
+ nil
+ "((nil . ("
+ ("" '(projectile-skel-variable-cons) \n)
+ resume:
+ ")))")
+
+;;;###autoload
+(defun projectile-edit-dir-locals ()
+ "Edit or create a .dir-locals.el file of the project."
+ (interactive)
+ (let ((file (expand-file-name ".dir-locals.el" (projectile-project-root))))
+ (find-file file)
+ (when (not (file-exists-p file))
+ (unwind-protect
+ (projectile-skel-dir-locals)
+ (save-buffer)))))
+
+;;; Minor mode
+(defvar projectile-command-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "4 a") #'projectile-find-other-file-other-window)
+ (define-key map (kbd "4 b") #'projectile-switch-to-buffer-other-window)
+ (define-key map (kbd "4 C-o") #'projectile-display-buffer)
+ (define-key map (kbd "4 d") #'projectile-find-dir-other-window)
+ (define-key map (kbd "4 D") #'projectile-dired-other-window)
+ (define-key map (kbd "4 f") #'projectile-find-file-other-window)
+ (define-key map (kbd "4 g") #'projectile-find-file-dwim-other-window)
+ (define-key map (kbd "4 t") #'projectile-find-implementation-or-test-other-window)
+ (define-key map (kbd "5 a") #'projectile-find-other-file-other-frame)
+ (define-key map (kbd "5 b") #'projectile-switch-to-buffer-other-frame)
+ (define-key map (kbd "5 d") #'projectile-find-dir-other-frame)
+ (define-key map (kbd "5 D") #'projectile-dired-other-frame)
+ (define-key map (kbd "5 f") #'projectile-find-file-other-frame)
+ (define-key map (kbd "5 g") #'projectile-find-file-dwim-other-frame)
+ (define-key map (kbd "5 t") #'projectile-find-implementation-or-test-other-frame)
+ (define-key map (kbd "!") #'projectile-run-shell-command-in-root)
+ (define-key map (kbd "&") #'projectile-run-async-shell-command-in-root)
+ (define-key map (kbd "a") #'projectile-find-other-file)
+ (define-key map (kbd "b") #'projectile-switch-to-buffer)
+ (define-key map (kbd "c") #'projectile-compile-project)
+ (define-key map (kbd "d") #'projectile-find-dir)
+ (define-key map (kbd "D") #'projectile-dired)
+ (define-key map (kbd "e") #'projectile-recentf)
+ (define-key map (kbd "E") #'projectile-edit-dir-locals)
+ (define-key map (kbd "f") #'projectile-find-file)
+ (define-key map (kbd "g") #'projectile-find-file-dwim)
+ (define-key map (kbd "F") #'projectile-find-file-in-known-projects)
+ (define-key map (kbd "i") #'projectile-invalidate-cache)
+ (define-key map (kbd "I") #'projectile-ibuffer)
+ (define-key map (kbd "j") #'projectile-find-tag)
+ (define-key map (kbd "k") #'projectile-kill-buffers)
+ (define-key map (kbd "l") #'projectile-find-file-in-directory)
+ (define-key map (kbd "m") #'projectile-commander)
+ (define-key map (kbd "o") #'projectile-multi-occur)
+ (define-key map (kbd "p") #'projectile-switch-project)
+ (define-key map (kbd "q") #'projectile-switch-open-project)
+ (define-key map (kbd "P") #'projectile-test-project)
+ (define-key map (kbd "r") #'projectile-replace)
+ (define-key map (kbd "R") #'projectile-regenerate-tags)
+ (define-key map (kbd "s g") #'projectile-grep)
+ (define-key map (kbd "s s") #'projectile-ag)
+ (define-key map (kbd "S") #'projectile-save-project-buffers)
+ (define-key map (kbd "t") #'projectile-toggle-between-implementation-and-test)
+ (define-key map (kbd "T") #'projectile-find-test-file)
+ (define-key map (kbd "u") #'projectile-run-project)
+ (define-key map (kbd "v") #'projectile-vc)
+ (define-key map (kbd "V") #'projectile-browse-dirty-projects)
+ (define-key map (kbd "x e") #'projectile-run-eshell)
+ (define-key map (kbd "x t") #'projectile-run-term)
+ (define-key map (kbd "x s") #'projectile-run-shell)
+ (define-key map (kbd "z") #'projectile-cache-current-file)
+ (define-key map (kbd "ESC") #'projectile-project-buffers-other-buffer)
+ map)
+ "Keymap for Projectile commands after `projectile-keymap-prefix'.")
+(fset 'projectile-command-map projectile-command-map)
+
+(defvar projectile-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map projectile-keymap-prefix 'projectile-command-map)
+ map)
+ "Keymap for Projectile mode.")
+
+(easy-menu-change
+ '("Tools") "Projectile"
+ '(["Find file" projectile-find-file]
+ ["Find file in known projects" projectile-find-file-in-known-projects]
+ ["Find test file" projectile-find-test-file]
+ ["Find directory" projectile-find-dir]
+ ["Find file in directory" projectile-find-file-in-directory]
+ ["Find other file" projectile-find-other-file]
+ ["Switch to buffer" projectile-switch-to-buffer]
+ ["Jump between implementation file and test file" projectile-toggle-between-implementation-and-test]
+ ["Kill project buffers" projectile-kill-buffers]
+ ["Recent files" projectile-recentf]
+ ["Edit .dir-locals.el" projectile-edit-dir-locals]
+ "--"
+ ["Open project in dired" projectile-dired]
+ ["Switch to project" projectile-switch-project]
+ ["Switch to open project" projectile-switch-open-project]
+ ["Discover projects in directory" projectile-discover-projects-in-directory]
+ ["Search in project (grep)" projectile-grep]
+ ["Search in project (ag)" projectile-ag]
+ ["Replace in project" projectile-replace]
+ ["Multi-occur in project" projectile-multi-occur]
+ ["Browse dirty projects" projectile-browse-dirty-projects]
+ "--"
+ ["Run shell" projectile-run-shell]
+ ["Run eshell" projectile-run-eshell]
+ ["Run term" projectile-run-term]
+ "--"
+ ["Cache current file" projectile-cache-current-file]
+ ["Invalidate cache" projectile-invalidate-cache]
+ ["Regenerate [e|g]tags" projectile-regenerate-tags]
+ "--"
+ ["Compile project" projectile-compile-project]
+ ["Test project" projectile-test-project]
+ ["Run project" projectile-run-project]
+ "--"
+ ["Project info" projectile-project-info]
+ ["About" projectile-version])
+ "Search Files (Grep)...")
+
+(easy-menu-change '("Tools") "--" nil "Search Files (Grep)...")
+
+;;;###autoload
+(defcustom projectile-mode-line
+ '(:eval (format " Projectile[%s]" (projectile-project-name)))
+ "Mode line lighter for Projectile.
+
+The value of this variable is a mode line template as in
+`mode-line-format'. See Info Node `(elisp)Mode Line Format' for
+details about mode line templates.
+
+Customize this variable to change how Projectile displays its
+status in the mode line. The default value displays the project
+name. Set this variable to nil to disable the mode line
+entirely."
+ :group 'projectile
+ :type 'sexp
+ :risky t
+ :package-version '(projectile . "0.12.0"))
+
+(defun projectile-find-file-hook-function ()
+ "Called by `find-file-hook' when `projectile-mode' is on.
+
+The function does pretty much nothing when triggered on remote files
+as all the operations it normally performs are extremely slow over
+tramp."
+ (unless (file-remote-p default-directory)
+ (projectile-cache-files-find-file-hook)
+ (projectile-track-known-projects-find-file-hook)
+ (projectile-visit-project-tags-table)))
+
+;;;###autoload
+(define-minor-mode projectile-mode
+ "Minor mode to assist project management and navigation.
+
+When called interactively, toggle `projectile-mode'. With prefix
+ARG, enable `projectile-mode' if ARG is positive, otherwise disable
+it.
+
+When called from Lisp, enable `projectile-mode' if ARG is omitted,
+nil or positive. If ARG is `toggle', toggle `projectile-mode'.
+Otherwise behave as if called interactively.
+
+\\{projectile-mode-map}"
+ :lighter projectile-mode-line
+ :keymap projectile-mode-map
+ :group 'projectile
+ :require 'projectile
+ :global t
+ (cond
+ (projectile-mode
+ ;; initialize the projects cache if needed
+ (unless projectile-projects-cache
+ (setq projectile-projects-cache
+ (or (projectile-unserialize projectile-cache-file)
+ (make-hash-table :test 'equal))))
+ (add-hook 'find-file-hook 'projectile-find-file-hook-function)
+ (add-hook 'projectile-find-dir-hook #'projectile-track-known-projects-find-file-hook t)
+ (add-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook t t)
+ (ad-activate 'compilation-find-file)
+ (ad-activate 'delete-file))
+ (t
+ (remove-hook 'find-file-hook #'projectile-find-file-hook-function)
+ (remove-hook 'dired-before-readin-hook #'projectile-track-known-projects-find-file-hook t)
+ (ad-deactivate 'compilation-find-file)
+ (ad-deactivate 'delete-file))))
+
+;;;###autoload
+(define-obsolete-function-alias 'projectile-global-mode 'projectile-mode)
+
+(provide 'projectile)
+
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+
+;;; projectile.el ends here
.emacs.d/elpa/projectile-20170917.410/projectile.elc
Binary file
.emacs.d/emacs.org
@@ -300,4 +300,3 @@
(use-package go-config)
(use-package navigation-config)
#+END_SRC
-
.emacs.d/init.el
@@ -126,7 +126,7 @@
;; If there is more than one, they won't work right.
'(package-selected-packages
(quote
- (counsel ivy-hydra go-mode direnv nixos-sandbox nix-mode s evil-indent-textobject evil-surround evil-jumper evil which-key delight diminish solaire-mode htmlize exec-path-from-shell doom-themes dashboard auto-compile))))
+ (general persp-projectile counsel-projectile projectile counsel ivy-hydra go-mode direnv nixos-sandbox nix-mode s evil-indent-textobject evil-surround evil-jumper evil which-key delight diminish solaire-mode htmlize exec-path-from-shell doom-themes dashboard auto-compile))))
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
.emacs.d/init.elc
Binary file