summaryrefslogtreecommitdiff
path: root/emacs/evil-leader.el
diff options
context:
space:
mode:
Diffstat (limited to 'emacs/evil-leader.el')
-rw-r--r--emacs/evil-leader.el213
1 files changed, 213 insertions, 0 deletions
diff --git a/emacs/evil-leader.el b/emacs/evil-leader.el
new file mode 100644
index 0000000..84cdafb
--- /dev/null
+++ b/emacs/evil-leader.el
@@ -0,0 +1,213 @@
+;;; evil-leader.el --- let there be <leader>
+
+;; Copyright (C) 2011-2013 by Michael Markert
+;; Author: Michael Markert <markert.michael@googlemail.com>
+;; URL: http://github.com/cofi/evil-leader
+;; Git-Repository: git://github.com/cofi/evil-leader.git
+;; Created: 2011-09-13
+;; Version: 0.4.3
+;; Keywords: evil vim-emulation leader
+;; Package-Requires: ((evil "0"))
+
+;; 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:
+;;
+;; Known Bugs:
+;; See http://github.com/cofi/evil-leader/issues
+
+;; Install:
+;; (require 'evil-leader)
+
+;; Usage:
+;;
+;; (global-evil-leader-mode)
+;;
+;; to enable `evil-leader' in every buffer where `evil' is enabled.
+;;
+;; Note: You should enable `global-evil-leader-mode' before you enable
+;; `evil-mode', otherwise `evil-leader' won't be enabled in initial
+;; buffers (*scratch*, *Messages*, ...).
+;;
+;; Use `evil-leader/set-key' to bind keys in the leader map.
+;; For example:
+;;
+;; (evil-leader/set-key "e" 'find-file)
+;;
+;; You can also bind several keys at once:
+;;
+;; (evil-leader/set-key
+;; "e" 'find-file
+;; "b" 'switch-to-buffer
+;; "k" 'kill-buffer)
+;;
+;; The key map can of course be filled in several places.
+;;
+;; After you set up the key map you can access the bindings by pressing =<leader>=
+;; (default: \) and the key(s). E.g. \ e would call `find-file' to open a file.
+;;
+;; If you wish to change so you can customize =evil-leader/leader= or call
+;; `evil-leader/set-leader', e.g. (evil-leader/set-leader ",") to change it to
+;; ",".
+;; The leader has to be readable by `read-kbd-macro', so using Space as a
+;; prefix key would be (evil-leader/set-leader "<SPC>").
+;;
+;; Beginning with version 0.3 evil-leader has support for mode-local bindings:
+;;
+;; (evil-leader/set-key-for-mode 'emacs-lisp-mode "b" 'byte-compile-file)
+;;
+;; Again, you can bind several keys at once.
+;;
+;; A mode-local binding shadows a normal mode-independent binding.
+
+;;; Code:
+
+(require 'evil)
+
+(defvar evil-leader--default-map (make-sparse-keymap)
+ "Keymap used for mode-independent leader bindings.")
+
+(defvar evil-leader--mode-maps nil
+ "Alist of mode-local leader bindings, shadows mode-independent bindings.")
+
+;;; customization
+(defgroup evil-leader nil
+ "<leader> support for evil."
+ :group 'evil
+ :prefix 'evil-leader/)
+
+(defcustom evil-leader/leader "\\"
+ "The <leader> key, used to access keys defined by `evil-leader/set-key' in normal and visual state.
+Must be readable by `read-kbd-macro'. For example: \",\"."
+ :type 'string
+ :group 'evil-leader)
+
+(defcustom evil-leader/non-normal-prefix "C-"
+ "Prefix for leader-map in insert- and emacs-state.
+`evil-leader/in-all-states' has to be non-nil for this to be set.
+The combination has to be readable by `read-kbd-macro'."
+ :type 'string
+ :group 'evil-leader)
+
+(defcustom evil-leader/no-prefix-mode-rx nil
+ "List of regular expressions for mode names where `evil-leader/leader' is used regardless of the state.
+
+If the current major mode is matched by one of the regular expressions
+`evil-leader/leader' is installed in emacs/insert state without
+the prefix additionally to the prefixed key.
+
+`evil-leader/in-all-states' has to be non-nil for this setting to have any effect."
+ :type 'list
+ :group 'evil-leader)
+
+(defcustom evil-leader/in-all-states nil
+ "If is non-nil leader-map is accessible by <prefixed-leader> in emacs/insert state.
+
+<prefixed-leader> is `evil-leader/non-normal-prefix' + `evil-leader/leader'"
+ :type 'boolean
+ :group 'evil-leader)
+
+;;;###autoload
+(define-minor-mode global-evil-leader-mode
+ "Global minor mode for <leader> support."
+ nil nil nil
+ (if global-evil-leader-mode
+ (add-hook 'evil-local-mode-hook #'evil-leader-mode t)
+ (remove-hook 'evil-local-mode-hook #'evil-leader-mode t)))
+
+;;;###autoload
+(define-minor-mode evil-leader-mode
+ "Minor mode to enable <leader> support."
+ :init-value nil
+ :keymap nil
+ (let* ((prefixed (read-kbd-macro (concat evil-leader/non-normal-prefix evil-leader/leader)))
+ (no-prefix (read-kbd-macro evil-leader/leader))
+ (mode-map (cdr (assoc major-mode evil-leader--mode-maps)))
+ (map (or mode-map evil-leader--default-map))
+ (no-prefix-rx (if evil-leader/no-prefix-mode-rx
+ (mapconcat #'identity evil-leader/no-prefix-mode-rx "\\|")
+ nil)))
+ (if evil-leader-mode
+ (progn
+ (evil-normalize-keymaps)
+ (define-key evil-motion-state-local-map no-prefix map)
+ (define-key evil-normal-state-local-map no-prefix map)
+ (when evil-leader/in-all-states
+ (define-key evil-emacs-state-local-map prefixed map)
+ (define-key evil-insert-state-local-map prefixed map))
+ (when (and no-prefix-rx (string-match-p no-prefix-rx (symbol-name major-mode)))
+ (define-key evil-emacs-state-local-map no-prefix map)
+ (define-key evil-insert-state-local-map no-prefix map)))
+ (define-key evil-motion-state-local-map no-prefix nil)
+ (define-key evil-normal-state-local-map no-prefix nil)
+ (when evil-leader/in-all-states
+ (define-key evil-emacs-state-local-map prefixed nil)
+ (define-key evil-insert-state-local-map prefixed nil)
+ (when (and no-prefix-rx (string-match-p no-prefix-rx (symbol-name major-mode)))
+ (define-key evil-emacs-state-local-map no-prefix nil)
+ (define-key evil-insert-state-local-map no-prefix nil))))))
+
+(defun evil-leader/set-leader (key &optional prefix)
+ "Set leader key to `key' and non-normal-prefix to `prefix' and remove old bindings.
+
+Passing `nil' as `prefix' leaves prefix unchanged."
+ (let ((global-on global-evil-leader-mode)
+ (local-on evil-leader-mode))
+ (when local-on
+ (evil-leader-mode -1))
+ (when global-on
+ (global-evil-leader-mode -1))
+ (setq evil-leader/leader key)
+ (when prefix
+ (setq evil-leader/non-normal-prefix prefix))
+ (if global-on
+ (global-evil-leader-mode 1)
+ (when local-on
+ (evil-leader-mode 1)))))
+
+;;;###autoload
+(defun evil-leader/set-key (key def &rest bindings)
+ "Bind `key' to command `def' in `evil-leader/default-map'.
+
+Key has to be readable by `read-kbd-macro' and `def' a command.
+Accepts further `key' `def' pairs."
+ (interactive "kKey: \naCommand: ")
+ (evil-leader--def-keys evil-leader--default-map key def bindings))
+(put 'evil-leader/set-key 'lisp-indent-function 'defun)
+
+;;;###autoload
+(defun evil-leader/set-key-for-mode (mode key def &rest bindings)
+ "Create keybindings for major-mode `mode' with `key' bound to command `def'.
+
+See `evil-leader/set-key'."
+ (interactive "SMode: \nkKey: \naCommand: ")
+ (let ((mode-map (cdr (assoc mode evil-leader--mode-maps))))
+ (unless mode-map
+ (setq mode-map (make-sparse-keymap))
+ (set-keymap-parent mode-map evil-leader--default-map)
+ (push (cons mode mode-map) evil-leader--mode-maps))
+ (evil-leader--def-keys mode-map key def bindings)))
+(put 'evil-leader/set-key-for-mode 'lisp-indent-function 'defun)
+
+(defun evil-leader--def-keys (map key def bindings)
+ (while key
+ (define-key map (read-kbd-macro key) def)
+ (setq key (pop bindings)
+ def (pop bindings))))
+
+(provide 'evil-leader)
+;;; evil-leader.el ends here
+