General User Manual
A general is a leader. – onioncheese
Recent Breaking Changes
general-default-... variables are obsolete
general-default-keymaps still work. However, they will eventually be removed, so please switch to using
general-create-definer if you want to use a definer with different defaults.
general-create-dual-vim-definer have been removed
general-create-definer should now be used instead as it is now capable of the same functionality (
general-evil-setup now uses it). Additionally,
general-vim-definer-default is obsolete and will be removed eventually. The second argument to
general-evil-setup is no longer used and will also be removed eventually. The vim definers will now always set the default
:states (and never the default
:keymaps) because of the change below.
:states 'normal is now the same as
:keymaps 'global :states 'normal will now bind in
evil-normal-state-keymap as opposed to the normal state auxiliary keymap of
(current-global-map) (see Note for Evil Users). It is not recommended to bind in a state and
(current-global-map). If you want to prevent certain keys from being overridden, please use evil intercept keymaps instead.
If you update general, please make sure that you are also using a recent version of evil.
general-simulate-keys is now obsolete
Please switch to
general-simulate-key. Note that keyword arguments have replaced the positional arguments of
general-simulate-keys will likely be removed sometime in the future.
Table of Contents
- Dependency Versions
- Key Features
- Reading Recommendations
- Usage Recommendations and Documentation Clarifications
- Basic Examples
- ~general-define-key~ Details
- Override Keymaps and Buffer Local Keybindings
- Displaying Keybindings
- Functions/Macros to Aid Key Definition
- Non-keybinding-related Configuration Helpers
- Integration with Other Packages
- Extended Definition Syntax
- User-defined Key Definers
general.el provides a more convenient method for binding keys in emacs (for both evil and non-evil users). Like
use-package, which provides a convenient, unified interface for managing packages,
general.el is intended to provide a convenient, unified interface for key definitions. While this package does implement some completely new functionality (such as the ability to make vim-style keybindings under non-prefix keys with an optional timeout), its primary purpose is to build on existing functionality to make key definition more clear and concise.
general-define-key is user-extensible and supports defining multiple keys in multiple keymaps at once, implicitly wrapping key strings with
(kbd ...), using named prefix key sequences (like the leader key in vim), and much more.
One advantage of using
general-define-key (or a wrapper for it) even in cases where its extra functionality isn’t necessary and doesn’t significantly improve brevity is that all keybindings are recorded and can be displayed later with
This manual explains the most relevant parts of every
general.el feature. All user-facing functions, macros, and variables also have docstrings (e.g. accessible with
C-h f or
C-h v), so please consult these for further details.
Please use MELPA and not MELPA stable for installing optional dependencies (e.g. evil and use-package). General may rely on functionality not in released versions for these packages, so if you are having trouble, please try updating them.
- Provides a single function,
general-define-key, that is usable for all key definition; wrappers are provided as well
- Does not hide important details of key definition (unlike
evil-leader.el); users should be familiar with
define-keyand other definers (e.g.
evil-define-key(*)for evil users) before using this package
- Uses a syntax similar to
setqfor key definitions (like
evil-leader.el, etc.; unlike
- Provides tight (and optional) integration with evil (unlike
general-defcan act as a drop-in replacement for the following definers (see the documentation below for a minor caveat) (unique):
global-set-key(no positional keymap argument)
evil-global-set-key(positional argument for keymap)
evil-define-key(positional argument for state and keymap)
- With the
general-define-keycan be extended to use any key definition function (e.g.
lispy-define-key, etc.) (unique)
- With “extended” definitions, user-created keywords can be added globally (in
general-define-key) and locally (in an “extended” definition plist) to extend the behavior of
- Allows binding keys in multiple keymaps/states at once (unlike
- Automatically wraps string keys and definitions with
kbd(this behavior can be turned off for compatibility with
- Allows using an arbitrary number of prefix keys or “leaders” of any length (but does not require prefix keys like) (unlike
- Allows for automatically creating prefix commands (but does not require creating them like
- Allows for buffer-local keybindings (unlike
- Allows deferring keybindings until the specified keymap exists (no need to use
- Allows displaying defined keys (like
- Provides integration with other packages such as
- Provides other helpers for keybindings (unique):
- A method for creating “autoloaded” keymaps (like
- A potentially better way to simulate keypresses (works with prefix args and for incomplete key sequences, i.e. a key bound to a keymap)
- A method for binding under non-prefix keys with an optional timeout (like in vim; e.g. bind
jkin insert mode without losing
- A helper to create a menu item to dispatch to different definitions based on predicates
- A method for creating “autoloaded” keymaps (like
- Provides other helpers for configuration (e.g. more convenient functions for hooks and advice)
- Is well tested (unlike
general.el, you should first be familiar with
global-set-key, and emacs’ key binding system. I recommend reading Mastering Key Bindings in Emacs if you are new to emacs. Also see
define-key’s help text for information on valid keys and definitions.
If you are also using evil, you should first be familiar with how
evil-define-minor-mode-key, etc. work. If you are a new evil user, I’d recommend looking at my evil guide. The Keybindings and States section in particular may be useful
A large number of issues opened on this repository are not specifically related to
general.el (e.g. user usage or syntax errors that would also occur without
general-define-key). While I don’t mind generic questions about keybinding issues, you may save yourself some time if you first determine whether or not an issue is related to
general-define-key by, if possible, testing with an equivalent
evil-define-key, etc. statement.
See also the FAQ for commonly asked questions.
Usage Recommendations and Documentation Clarifications
To facilitate extensibility and easy creation of wrappers,
general-define-key uses keyword arguments to specify everything besides the key definitions, including for the
:keymaps. Since users will most often specify one or both of these keyword arguments,
general-define-key is often less concise than
evil-define-key. It is for this reason that it is recommended that
general-define-key not be used directly.
general.el provides wrappers around
general-define-key that take positional arguments, and it is recommended that you use these instead of
general-create-definer can also be used to create a new definer with certain default settings (e.g. prefix settings). For clarity and consistency, examples in the documentation usually use
general-define-key unless the example is explicitly for a wrapper. However, ~general-def~ is recommended over
general-define-key as it is more flexible and concise. Positional arguments are optional but not required, so
general-def can basically act as a drop-in replacement for many key definers (including
evil-define-key). Note that
general-create-definer and the
:general keyword argument for
general-def. I personally only use
Since it is more common for commands to not be sharp quoted in key definitions, this package’s examples use single quotes for commands. I personally prefer to always properly sharp quote functions, so commands in the actual non-example code are always sharp quoted.
general-define-key will automatically defer keybindings until the specified keymaps exist, you can still use it with
with-eval-after-load or use-package’s
:config keyword whenever it makes sense to. If you have a lot of keybindings, this could potentially shave some fraction of a second off of your startup time.
(require 'general) ;; * Global Keybindings ;; `general-define-key' acts like `global-set-key' when :keymaps is not ;; specified (because ":keymaps 'global" is the default) ;; kbd is not necessary and arbitrary amount of key def pairs are allowed (general-define-key "M-x" 'amx ; or 'smex "C-s" 'counsel-grep-or-swiper) ;; * Mode Keybindings ;; `general-define-key' is comparable to `define-key' when :keymaps is specified (general-define-key ;; NOTE: keymaps specified with :keymaps must be quoted :keymaps 'org-mode-map "C-c C-q" 'counsel-org-tag ;; ... ) ;; `general-def' can be used instead for `define-key'-like syntax (general-def org-mode-map "C-c C-q" 'counsel-org-tag ;; ... ) ;; * Prefix Keybindings ;; :prefix can be used to prevent redundant specification of prefix keys (general-define-key :prefix "C-c" ;; bind "C-c a" to 'org-agenda "a" 'org-agenda "b" 'counsel-bookmark "c" 'org-capture) ;; for frequently used prefix keys, the user can create a custom definer with a ;; default :prefix ;; using a variable is not necessary, but it may be useful if you want to ;; experiment with different prefix keys and aren't using `general-create-definer' (defconst my-leader "C-c") (general-create-definer my-leader-def ;; :prefix my-leader ;; or without a variable :prefix "C-c") ;; ** Global Keybindings (my-leader-def "a" 'org-agenda "b" 'counsel-bookmark "c" 'org-capture) ;; ** Mode Keybindings (my-leader-def :keymaps 'clojure-mode-map ;; bind "C-c C-l" "C-l" 'cider-load-file "C-z" 'cider-switch-to-repl-buffer) ;; `general-create-definer' creates wrappers around `general-def', so ;; `define-key'-like syntax is also supported (my-leader-def clojure-mode-map "C-l" 'cider-load-file "C-z" 'cider-switch-to-repl-buffer) ;; * Settings ;; change `auto-revert-interval' after autorevert has been loaded (`setq' will ;; not work) (general-setq auto-revert-interval 10)
(require 'general) ;; * Global Keybindings ;; `general-define-key' acts like `evil-define-key' when :states is specified (general-define-key :states 'motion ;; swap ; and : ";" 'evil-ex ":" 'evil-repeat-find-char) ;; same as (general-define-key :states 'motion ";" 'evil-ex ":" 'evil-repeat-find-char) ;; `general-def' can be used instead for `evil-global-set-key'-like syntax (general-def 'motion ";" 'evil-ex ":" 'evil-repeat-find-char) ;; alternative using `general-translate-key' ;; swap ; and : in `evil-motion-state-map' (general-swap-key nil 'motion ";" ":") ;; * Mode Keybindings (general-define-key :states 'normal :keymaps 'emacs-lisp-mode-map ;; or xref equivalent "K" 'elisp-slime-nav-describe-elisp-thing-at-point) ;; `general-def' can be used instead for `evil-define-key'-like syntax (general-def 'normal emacs-lisp-mode-map "K" 'elisp-slime-nav-describe-elisp-thing-at-point) ;; * Prefix Keybindings ;; :prefix can be used to prevent redundant specification of prefix keys ;; again, variables are not necessary and likely not useful if you are only ;; using a definer created with `general-create-definer' for the prefixes ;; (defconst my-leader "SPC") ;; (defconst my-local-leader "SPC m") (general-create-definer my-leader-def ;; :prefix my-leader :prefix "SPC") (general-create-definer my-local-leader-def ;; :prefix my-local-leader :prefix "SPC m") ;; ** Global Keybindings (my-leader-def :keymaps 'normal ;; bind "SPC a" "a" 'org-agenda "b" 'counsel-bookmark "c" 'org-capture) ;; `general-create-definer' creates wrappers around `general-def', so ;; `evil-global-set-key'-like syntax is also supported (my-leader-def 'normal "a" 'org-agenda "b" 'counsel-bookmark "c" 'org-capture) ;; to prevent your leader keybindings from ever being overridden (e.g. an evil ;; package may bind "SPC"), use :keymaps 'override (my-leader-def :states 'normal :keymaps 'override "a" 'org-agenda) ;; or (my-leader-def 'normal 'override "a" 'org-agenda) ;; ** Mode Keybindings (my-local-leader-def :states 'normal :keymaps 'org-mode-map "y" 'org-store-link "p" 'org-insert-link ;; ... ) ;; `general-create-definer' creates wrappers around `general-def', so ;; `evil-define-key'-like syntax is also supported (my-local-leader-def 'normal org-mode-map "y" 'org-store-link "p" 'org-insert-link ;; ... ) ;; * Settings ;; change evil's search module after evil has been loaded (`setq' will not work) (general-setq evil-search-module 'evil-search)
(general-evil-setup) ;; * Global Keybindings ;; all keywords arguments are still supported ;; these are just wrappers around `general-def' that set a default :states (general-nmap :prefix "SPC" "p" 'helm-mini) ;; bind in motion state (inherited by the normal, visual, and operator states) (general-mmap ";" 'evil-ex ":" 'evil-repeat-find-char) ;; alternatively, for shorter names (general-evil-setup t) (mmap ";" 'evil-ex ":" 'evil-repeat-find-char) ;; * Mode Keybindings (general-nmap :keymaps 'emacs-lisp-mode-map "K" 'elisp-slime-nav-describe-elisp-thing-at-point) ;; same as (general-nmap emacs-lisp-mode-map "K" 'elisp-slime-nav-describe-elisp-thing-at-point)
Switching Completely to General
It is possible to gradually switch to using general by using it only for new configuration and slowly converting old configuration if desired. If you would like to quickly convert all keybindings in your init file to use general so that they show up with
general-describe-keybindings, you can potentially use regexp replace. For example, you could use
M-< C-M-% \(global-set-key\|define-key\|evil-global-set-key\|evil-define-key\) RET general-def RET !. The evil equivalent would be
There are two caveats. The old key definers all require using
kbd. This means that you will either have to remove every
kbd in these key definers (e.g.
:%s/(kbd ?\(.*?\))/\1/gc; you should likely confirm whether each
kbd should be removed) or set
general-implicit-kbd to nil for the old configuration. Furthermore,
general-def can only correctly replace definer statements where the first specified key is a string or vector. It will not work correctly to replace a definer that uses a variable or function for the first key (e.g.
(global-set-key my-key 'command) cannot be replaced directly with
general-def). To use general for definitions like this, you must either use the actual equivalent definer that
general-def ends up using (
evil-define-key) or explicitly separate the positional arguments from the first key with a bogus keyword argument (e.g.
(general-def :start-maps my-key 'command)).
If you decide to do this, please make sure that your configuration is backed up, and test this out to make sure that there are no errors before permanently changing your configuration.
This package provides one main function,
general-define-key, for key definitions for both evil and non-evil users. It is recommended you use the provided wrappers around it or create your own with
general-create-definer, but first you should understand the keyword arguments provided by
The only positional arguments for
general-define-key are any number of key/definition pairs. General supports all key and definition types supported by
define-key (see its help text) as well as its own “extended definitions”. Here are a few examples of definitions that aren’t standard =”string key” ‘command= pairs:
;; vector keys, including [t] and [remap] are supported (general-define-key :keymaps 'org-capture-mode-map [remap evil-save-and-close] 'org-capture-finalize [remap evil-save-modified-and-close] 'org-capture-finalize [remap evil-quit] 'org-capture-kill) (general-define-key :states 'normal :keymaps 'org-capture-mode-map ;; keyboard macro definition "RET" "C-c C-c" ;; general.el extended definition "SPC k" '(org-capture-kill :which-key "abort capture"))
kbd will automatically be called on every string key.
general-implicit-kbd can be set to nil if you want to manually use
(kbd "key"). This option is mainly provided to make it easy to transition to
general-def from other key definers with search and replace and therefore only applies to
general-define-key (and wrappers).
kbd will always be called on string keys for other helpers such as
:keymaps are the most basic keyword arguments. By default, there is no prefix or state (each is nil), and the keymap is =’global=. Each keymap can either be a quoted keymap, quoted keymap alias, =’global=, or =’local=. This is the biggest contrast between
general-define-key and other definers such as
define-key, where the keymap is passed in directly. Note that the provided wrappers such as
general-def do not require quoting keymaps. When the keymap is =’local=, the key will be bound only in the current buffer (see here for more details). When the keymap is =’global=, the key will be bound in
(current-global-map) (or the corresponding evil global map if
:states is specified; see Note for Evil Users for more information).
:keymaps can be lists or a single element, allowing the user to define keys for multiple evil states or keymaps simultaneously. This can be useful in certain situations to prevent redundancy.
Using a different prefix for the insert and emacs states (or any state in
general-non-normal-states) can be done with
:global-prefix. By default,
:prefix will apply to all keys, but if one (or both) of the other prefix keywords is specified,
:prefix will only apply to evil states not listed in
general-non-normal-states. This is also the case for the global evil keymaps such as
:non-normal-prefix will always only apply to the non-normal states.
:global-prefix will always apply to all keys. For example, this command will bind
SPC / to swiper in normal state and
M-SPC / to swiper in emacs and insert state:
(general-define-key :keymaps '(normal insert emacs) :prefix "SPC" :non-normal-prefix "M-SPC" "/" 'swiper)
If you would like to create a named prefix keymap for your prefix keys, you can also specify
:prefix-map. All prefix keys will then be bound to the prefix command or prefix keymap in the correct keymaps. If
:prefix-command is specified,
define-prefix-command will be used with
prefix-name passed in as additional arguments to
define-prefix-command. If only
:prefix-map is specified, a prefix keymap alone will be created with a menu item/prompt corresponding to
:prefix-name. Note that existing prefix commands/keymaps will not be redefined, so reevaluating a general.el form that uses
:prefix-map will not clear the previously created keymap.
(general-define-key :keymaps '(normal insert emacs) :prefix "SPC" :non-normal-prefix "M-SPC" :prefix-command 'my-prefix-command :prefix-map 'my-prefix-map "/" 'swiper)
General is flexible in allowing you to choose how you write things, so if the above would be something you’d use often, you could create a function with the above keyword arguments as defaults using ~general-create-definer~ and write the definition like this:
(my-normal-and-insert-define-key "/" 'swiper)
:infix keyword can be used to sandwich keys in between all of the specified prefix keys and the keys in each mapping. This is mainly useful when using multiple prefix keywords and especially when using wrappers. For example, if you wanted to define several keys that were prefixed with
SPC g in normal state and
M-SPC g in insert state, you could use the previous wrapper with
:infix instead of re-specifying both
(my-normal-and-insert-define-key :infix "g" <maps...>)
If you just want to create the prefix keymap and bind keys directly in it without immediately binding a prefix key to the prefix keymap, simply don’t specify
;; bind "/" directly in the newly created my-prefix-map (general-define-key :prefix-map 'my-prefix-map "/" 'swiper)
There is also a
:predicate keyword for giving a condition under which a map should be active.
The user can use the
:predicate keyword to specify a condition under which the map(s) should be active. For example:
(general-define-key :keymaps 'local :predicate '(eobp) "<right>" 'beginning-of-buffer)
<right> will now behave normally except at the end of the buffer where it will jump to the beginning of the buffer. Note that with
:predicate, you can still only have a key bound once in a single keymap. In other words,
:predicate is only useful if a fallback keybinding already exists in a different, lower precedence keymap. If you want to have a key take different actions depending on conditions in a single keymap, see Choosing Definition Based on Predicates.
See this post for more information about how this works.
To prevent the need to type out long keymap names like
evil-inner-text-objects-map, general allows the user to specify shorthand names for keymaps by altering
general-keymap-aliases (and for states by altering
general-state-aliases). These are alists of either an alias or a list of aliases to the full keymap name:
(push '(help . help-map) general-keymap-aliases) ;; or (push '((h help) . help-map) general-keymap-aliases) ;; or (emacs 25+) (setf (alist-get 'help general-keymap-aliases) 'help-map) ;; or (emacs 25+) (setf (alist-get '(h help) general-keymap-aliases) 'help-map) ;; now (general-define-key :keymaps 'help ...) ;; is the same as (general-define-key :keymaps 'help-map ...)
Note that earlier entries in the alist take precedence.
By default, the global evil state and text object keymaps have aliases. This allows for using the same syntax as
(general-define-key :keymaps 'motion ...) ;; or (general-define-key :keymaps 'm ...)
general-keymap-aliases for all default aliases.
All keymap symbols are immediately processed by
general--unalias. By overriding this function, it would be possible to, for example, automatically append
-mode-map to keymap names that don’t end in
-map or do something more complicated to create a generic shorthand without having manually specify all aliases. This is not recommended as it could potentially become confusing (and would currently break
:definer 'minor-mode), but if anyone would find this useful, feel free to make an issue, and I’ll consider adding it as an option.
Positional Argument Wrappers
When defining keys in specific keymaps and states, using positional arguments can be shorter. General has two macros that can basically act as drop-in replacements for
evil-define-key and another macro that can basically act is a drop-in replacement for both of those and more. They are
general-def respectively. These are simply wrappers for
general-define-key that pass the positional arguments to the corresponding keywords. However, for compatibility with
evil-define-key, it is not necessary to quote keymaps. Both keymaps and states can be left quoted or unquoted (regardless of whether they are lists).
For example, the following are all equivalent:
(general-define-key :keymaps 'org-mode-map "M-n" 'org-next-visible-heading "M-p" 'org-previous-visible-heading) (general-emacs-define-key org-mode-map "M-n" 'org-next-visible-heading "M-p" 'org-previous-visible-heading) ;; rough equivalent with define-key (with-eval-after-load 'org-mode (define-key org-mode-map (kbd "M-n") 'org-next-visible-heading) (define-key org-mode-map (kbd "M-p") 'org-previous-visible-heading))
Similarly, the following are all equivalent:
(general-define-key :states '(normal visual) :keymaps 'org-mode-map "gj" 'org-next-visible-heading "gk" 'org-previous-visible-heading) (general-evil-define-key '(normal visual) org-mode-map "gj" 'org-next-visible-heading "gk" 'org-previous-visible-heading) ;; equivalent with evil-define-key (evil-define-key '(normal visual) org-mode-map "gj" 'org-next-visible-heading "gk" 'org-previous-visible-heading)
The actual behavior of these two macros is the same as
general-define-key. You can still use
general-define-key’s keyword arguments after the positional arguments (however,
:states will not override the positional arguments):
;; these are both valid (general-emacs-define-key 'global :prefix "C-c" "/" 'swiper) (general-evil-define-key 'normal org-mode-map :prefix "SPC" "g" 'worf-goto)
evil-global-set-key, wrappers are not needed. By default
general-define-key acts like
general-emacs-define-key can also act like
global-evil-set-key using the symbols for evil’s states (see keymap aliases).
The third macro,
general-def, is provided for those who would prefer to use a single, succinctly named definer for all of the previous cases. It will act the same as
general-evil-define-key depending on the number of positional arguments.
;; use `general-define-key' when no "positional" arguments (general-def "key" 'def ...) ;; example equivalents (general-define-key "key" 'def) (global-set-key (kbd "key") 'def) ;; use `general-emacs-define-key' when one "positional" argument (general-def org-mode-map "key" 'def ...) ;; example equivalent (define-key org-mode-map (kbd "key") 'def) ;; act like `evil-global-set-key' (general-def 'normal "key" 'def ...) ;; example equivalents (evil-global-set-key 'normal (kbd "key") 'def) (evil-define-key 'normal 'global (kbd "key") 'def) ;; use `general-evil-define-key' when two "positional" arguments (general-def 'normal org-mode-map "key" 'def ...) ;; example equivalent (evil-define-key 'normal org-mode-map (kbd "key") 'def)
Note that all leading quoted and unquoted symbols and lists are considered to be positional arguments. This means that if you want to use a variable or function for a key that could be a positional argument, you should either use the definer
general-def would end up using (
evil-define-key) or explicitly separate the positional arguments from the first key with a bogus keyword argument:
(general-def :start-maps t some-key 'some-command)
Mass Key Unbinding Wrapper
general-unbind acts as
general-def, but the positional arguments should all be keys (instead of pairs of keys and definitions) that should be unbound:
(general-unbind 'insert "C-v" "C-k" "C-y" "C-e") ;; equivalent to (general-def 'insert "C-v" nil "C-k" nil "C-y" nil "C-e" nil)
This wrapper can also be used, for example, if you want to disable certain commands or keys from working in certain modes by using with
:with keyword argument (example use case taken from evil-collection):
(general-unbind 'normal Info-mode-map :with 'ignore [remap evil-append] [remap evil-append-line] [remap evil-insert] [remap evil-insert-line]) ;; equivalent to (general-def 'normal Info-mode-map [remap evil-append] 'ignore [remap evil-append-line] 'ignore [remap evil-insert] 'ignore [remap evil-insert-line] 'ignore)
The reason that this functionality is implemented as a wrapper and not as a keyword argument for
general-define-key is that
cl-defun cannot correctly parse keyword arguments when the keyword is in an odd position (e.g.
("a" :keyword 'arg) instead of
(:keyword 'arg "a")). For example, if this functionality was implemented with an
:unbind keyword, the
:general use-package keyword and any definer created with
general-create-definer would not work if the user specified an odd number of keys to unbind (because the default keyword arguments would be at the end of the arglist, in the wrong positions). As I’d rather not re-implement keyword argument parsing just for this use case, this functionality is provided as a macro. This macro will correctly handle any positioning for keyword arguments.
Creating New Key Definers
general-create-definer macro can create definers that wrap
general-def but with certain default settings. For example, it can be used to create a definer that will default to a certain prefix (like
;; basic example (general-create-definer my-leader-def :prefix "C-c") ;; bind "C-c o" to `other-window' (my-leader-def "o" 'other-window) ;; more complex example (general-create-definer tyrant-def :states '(normal insert emacs) :prefix "SPC" :non-normal-prefix "M-SPC" :prefix-command 'tyrant-prefix-command :prefix-map 'tyrant-prefix-map) ;; globally bind "SPC /" in normal state and "M-SPC /" in the insert/emacs ;; states to `swiper' (tyrant-def "/" 'swiper) ;; for org-mode, bind "SPC o" in normal state and "M-SPC /" in the insert/emacs ;; states to `counsel-org-goto' (tyrant-def org-mode-map "o" 'counsel-org-goto) ;; same as (tyrant-def :keymaps 'org-mode-map "o" 'counsel-org-goto)
It takes an optional
:wrapping keyword argument that can be specified to use another definer instead of
(general-create-definer my-prefix-def :wrapping general-emacs-define-key :prefix "M-,")
general-evil-setup can be used to generate key definition functions that are named similarly to vim’s. Currently, the following functions will be created:
These are wrappers around
general-def created with
general-create-definer that set the default
:states. You can see the help text for each for a more specific description.
general-evil-setup can be called with a non-nil argument (i.e.
(general-evil-setup t)) to create non-prefixed aliases for these definers (e.g.
Here is an example using
(general-evil-setup) ;; define in evil-normal-state-map (general-nmap "key" 'def ...) ;; define in the normal state auxiliary map for org-mode-map (general-nmap org-mode-map "key" 'def ...) ;; same as (general-nmap :keymaps 'org-mode-map "key" 'def ...)
Note for Evil Users
:states is specified,
general-define-key will act as a wrapper around
evil-define-key* now directly supports the symbol
global for the keymap argument, so the following are equivalent:
(general-define-key ;; (default) ;; :keymaps 'global :states '(normal visual) ...) (general-define-key :keymaps '(normal visual) ...)
Note that this previously was not the case and
(general-define-key :states 'normal ...) would bind in the normal state auxiliary map for
(current-global-map). Since auxiliary maps have a higher precedence than evil global and override keymaps, this was previously mentioned as one possible way of preventing certain keybindings from being overridden. However, this is not a reliable method. Keys bound in auxiliary maps can override keys bound in other auxiliary maps, for example, and keys bound in evil local or minor-mode keymaps will always override keys bound in regular auxiliary maps. If you need this functionality, please use evil intercept keymaps instead (see Override Keymaps).
Override Keymaps and Buffer Local Keybindings
General.el provides the equivalent of
general-override-mode-map (keymap alias is =’override=). When
general-override-mode is enabled, keys bound in
general-override-mode-map will take precedence over keys bound in any other minor mode keymaps. By default, general.el will automatically enable
general-override-mode when binding a key in
general-override-mode-map. If you would prefer to enable it manually (e.g. you wish to toggle it at some point), you can set
general-override-auto-enable to nil.
General also provides a local equivalent called
general-override-local-mode which is used to add support for buffer-local keybindings (with higher precedence than mode keybindings) by specifying
:keymaps 'local. Unlike with the global override mode,
:keymaps 'local should always be used instead of the actual keymap name since
:keymaps 'local will cause general.el to automatically turn on the corresponding minor mode and perform some necessary extra setup. Note that this is not the same as using
local-set-key (which will bind the key for the current buffer’s major mode, affecting other buffers). When
:states is specified with
evil-local-set-key will be used instead.
Note that binding directly in
general-override-mode-map (i.e. no
:states specified) is only useful for non-evil keybindings. Evil keybindings already override almost all normal emacs keybindings using the same method used here (i.e. evil keymaps are in
emulation-mode-map-alists). The main exceptions where evil keybindings will be overridden by non-evil keybindings are noted here with explanations on how to deal with these cases. To understand which evil keybindings override others, review the precedence for evil keymaps. If you want a global evil keybinding to not be overridden by any other evil keymaps (e.g. overriding keymaps created in
evil-integration.el or auxiliary keymaps created by some evil package), you can use intercept keymaps. You can make any keymap an intercept keymap, but it may be convenient to just use
general-override-mode-map for this purpose since the necessary setup (
evil-make-intercept-map) has already been performed:
;; keybindings that should not be overriden (general-define-key :states 'normal :keymaps 'override :prefix "SPC" "f" 'find-file) ;; the above has precedence over the following (excerpt from evil-collection) ;; "SPC f" will still work as `find-file' (evil-define-key 'normal transmission-mode-map (kbd "SPC") 'scroll-up-command)
Note that by default, evil keybindings made with
:keymaps 'override will override even those made with
General keeps track of all your keybindings and allows presenting them as tables in an org buffer using
general-describe-keybindings. By default, they will be displayed in this order:
- Buffer local keybindings (i.e.
- Global keybindings (i.e.
- Global evil keybindings (e.g.
- Other keybindings
Within these categories keymaps, states, and keybindings will be presented in the order they were created in. For each keybinding created, this command will display the key, the definition, and the previous definition. The previous definition will only be updated when the definition changes by default. To have it only be updated when the key was previously unbound, the user can set
The order in which keybindings are displayed is customizable. All keymaps listed in
general-describe-priority-keymaps will be displayed first. The rest can optionally be sorted by setting
general-describe-keymap-sort-function (nil by default). The order evil states are displayed in can be altered either by changing
general-describe-state-sort-function or changing the order of states in
general-describe-evil-states. Keybindings can also be sorted if the user sets
general-describe-keybinding-sort-function. Here is an example that will sort everything alphabetically:
(setq general-describe-priority-keymaps nil general-describe-keymap-sort-function #'general-sort-by-car general-describe-state-sort-function #'general-sort-by-car) ;; sort keybindings alphabetically by key (setq general-describe-keybinding-sort-function #'general-sort-by-car) ;; sort keybindings alphabetically by definition (setq general-describe-keybinding-sort-function #'general-sort-by-cadr)
For reference, keybindings are stored in an alist. Here is what is passed to each sorting function:
;; `general-keybindings' - an alist of keymap to state alist ;; passed to `general-describe-keymap-sort-function' ((keymap-name . state-alist) ...) ;; a state alist (state name is nil if there is no state) ;; passed to `general-describe-state-sort-function' ((state-name . keybindings) ...) ;; the list of keybindings is passed to `general-describe-keybinding-sort-function' (("key after kbd applied" 'def 'previous-def) ...)
To actually change how the keybinding table is printed, the user could override
Functions/Macros to Aid Key Definition
Key simulation (for
general-key-dispatch but not for
general-key) can result in duplicate keys being recorded for keyboard macros and evil repeating. To work around this issue,
general.el will discard these duplicate keys during macro playback (i.e.
executing-kbd-macro is non-nil). So far, this seems to be a reliable method for getting macros and repeating to work correctly with key simulation. However, it is hard (and maybe impossible) to test some of these cases automatically since it involves simulating keys that in turn simulate keys, and, for example, I haven’t found a way to correctly simulate recording a macro in these cases. Therefore, if you find any issues with macro playback or evil repeating when using
general-key-dispatch, please make an issue.
General provides two macros called
general-simulate-key that can be used to simulate key sequences. In some cases, they can be used similarly to keyboard macros, but they have some advantages. Unlike with a keyboard macro, prefix arguments will work for the command that ends up running. Also, the key simulated does not have to correspond to the full key sequence for a command. See here for information on an alternative method of doing some of the things these key simulation helpers can do using
key-translation-map. I personally prefer general’s helpers as they are simple and more powerful.
Note that when a named prefix keymap/command exists (e.g.
help-command), you should generally prefer to bind directly to that. However, this is not possible for a key like
C-c whose definition varies depending on the buffer. Therefore, you need to use either
(general-nmap "SPC" (general-simulate-key "C-c")) ;; or (general-nmap "SPC" (general-key "C-c"))
Although both will work correctly, which-key does not currently show all available keys when
general-key is used, so I would currently recommend using
general-simulate-key instead for an example like this.
On the other hand,
general-key should be preferred for simulating a key that corresponds to a single command. Unlike
general-simulate-key, which creates/returns a function,
general-key expands to an extended menu item like
general-predicate-dispatch. Using an extended menu item is a simpler and more direct approach as emacs will dynamically look up and act as the specified key. This has the advantage of showing the docstring for the exact command with
C-h k. If the key to act as is unbound, key lookup can continue (like if
:predicate returns nil), so having a fallback keybinding is possible with
general-key but not with
Another downside of
general-simulate-key is that any commands/functions called just afterwards will actually be run before the keys are simulated. This won’t affect the most common use cases, but it makes setting up and tearing down a context more difficult (e.g. simulating a key in a specific evil state requires using
general-simulate-key but not for
general-key may be useful when you want to have a key act as another without having to bind it to the exact command in every relevant keymap:
(general-nmap "RET" (general-key "C-c C-c")) ;; a keyboard macro works, but C-h k will not show the command docstring (general-nmap "RET" "C-c C-c")
general-key also support keyword arguments to control the context the keys are simulated in (both support
:keymap for now but I don’t know how useful it is; please make an issue if you think it would be useful to add
general-key). For example:
(general-nmap "j" (general-simulate-key "C-n" :state 'emacs)) ;; `general-key' supports :state only` (general-nmap "j" (general-key "C-n" :state 'emacs))
general-key also supports custom setup and teardown before key lookup. Here’s a similar example to the previous one:
(general-nmap "j" (general-key "C-n" :setup (evil-local-mode -1) :teardown (evil-local-mode)))
The advantage of
general-key is that it can be used to simulate a key sequence corresponding to multiple commands or a command followed by a key sequence. The key argument can be replaced by a list of a command and keys (e.g.
(general-simulate-key ('evil-delete "iw"))). For example, the following is possible with
general-simulate-key but not with
general-key or a keyboard macro:
(general-nmap "s" (general-simulate-key ('evil-ex "s/")))
See the next section for another reasonable use case for this feature.
When a command is specified for
general-simulate-key, general will used the remapped version of it if it exists (e.g. if
[remap evil-delete] 'lispyville-delete is in an active keymap,
lispyville-delete will be used instead of
evil-delete). To use the exact command instead,
:remap nil can be specified
general-simulate-key creates a named function with a docstring, so which-key and
describe-key will work properly for keys bound to a command created with it. The automatically generated function name, docstring, and which-key description can be replaced with keyword arguments:
(general-nmap "SPC" (general-simulate-key "C-c" :state 'emacs :name general-SPC-simulates-C-c :docstring "Simulate C-c in emacs state with SPC." :which-key "Simulate C-c"))
Make sure that you don’t bind a key to simulate itself (e.g.
(general-emap "C-n" (general-simulate-key "C-n" :state 'emacs))) as this will cause an infinite loop.
Mapping Under Non-prefix Keys
This functionality is mainly targeted at evil users, but it could potentially be useful for non-evil users as well. In vim you can bind something like
cow without a problem. With evil,
c is bound to
evil-change, so you can’t bind directly to
cow. A workaround for this case is to bind a key in
evil-operator-state-map, but this won’t work when operator state is not used (e.g. you want to bind something like
jk in insert state). I’ve come up with a more general workaround called
general-key-dispatch. Consider the following example:
(general-nmap "c" (general-key-dispatch 'evil-change "ow" 'toggle-word-wrap "tb" 'some-command "c" 'evil-change-whole-line ;; alternatively if there was no linewise version: "c" (general-simulate-key ('evil-change "c")))) ;; `evil-change' is not bound in `evil-visual-state-map' by default but ;; inherited from `evil-normal-state-map' ;; if you don't want "c" to be affected in visual state, you should add this (general-vmap "c" 'evil-change)
general-key-dispatch is a function-creating macro. In this example, the command created will wait for user input and try to match one of the specified key sequences (e.g.
ow). If a key sequence is matched, the corresponding command will be executed. Otherwise it will fall back to simulating the fallback command followed by the unmatched keys (using the same mechanism as
general-simulate-key). For example,
ow is bound, so
cow would run
toggle-word-wrap. On the other hand,
b is not mapped, so
cb would act the same as
cb would by default. Counts and repeating should still work for both the mapped keys and fallback command. Because evil handles
cc differently (since
c is not a motion),
c must be explicitly bound to
evil-change-whole-line (or to simulate
('evil-change "c")) to keep its behavior.
c is not actually bound in visual state by default, so to keep
c working the same in visual state, you should explicitly bind it to
general-simulate-key, general will first check to see if the command to be executed has been remapped (e.g. if
[remap evil-delete] 'lispyville-delete is in an active keymap,
lispyville-delete will be used instead of
evil-delete). To use the exact command instead,
:remap nil can be specified.
Another thing to note is that you can’t bind a key in the
general-key-dispatch section to simulate the base key (i.e. the key you bind to the resulting command, in this case
c). For this example, you couldn’t bind
(general-simulate-key "ciw"). While this wouldn’t cause an infinite loop, it wouldn’t work either, so you would have to use the command name instead (e.g
(general-simulate-key ('evil-change "iw"))).
Also, if you use a count in the middle (e.g.
2 is not explicitly bound), the fallback command will be run immediately. If anyone cares about this, feel free to make an issue. I could potentially add an option to allow changing the count in the middle without immediately falling back to the default command.
Another possible use case of
general-key-dispatch is to emulate vim’s
imap. For example, you can recreate the common
(general-imap "j" (general-key-dispatch 'self-insert-command "k" 'evil-normal-state))
Commands created in this way support an optional timeout, meaning you could still insert
quoted-insert) like with key-chord.el:
(general-imap "j" (general-key-dispatch 'self-insert-command :timeout 0.25 "k" 'evil-normal-state))
If there is input lag, a timeout will not work well (this is also true for packages like key-chord.el). One example is vterm (even though there is not normally visible input lag). In vterm, the real amount of time you would have to wait after pressing “j” before pressing “k” is longer than 0.25 seconds. It is also likely that the next character you type will be input instead (e.g. “jo” would result in “oo”). There’s not much that can be done about the first problem. You can try lowering the timeout in a problematic mode. However, if the input lag is inconsistently present (e.g. caused by some minor mode) and/or severe, this probably won’t help much. You can at least address the second problem by explicitly specifying the character you want to insert:
(defun my-insert-j () (interactive) (insert "j")) (general-imap "j" (general-key-dispatch 'my-insert-j :timeout 0.25 "k" 'evil-normal-state))
If input lag is an issue,
:timeout can still be used as a visual enhancement. For example, you can bind
SPC SPC to end a sentence if you don’t normally need to type two spaces anywhere else. This works without
:timeout but is visually confusing since spaces are never be inserted until the next keypress.
:timeout can be used to enhance such a keybinding:
(defun my-insert-space () (interactive) (insert " ")) (defun my-sentence-end () (interactive) (insert ". ")) (general-def 'insert text-mode-map "SPC" (general-key-dispatch 'my-insert-space :timeout 0.1 "SPC" 'my-sentence-end))
If you are using
general-key-dispatch with a timeout to mirror some prefix keymap in insert state, it may also convenient to use the
:inherit-keymap keyword. This allows using prefix keybindings without the need to re-specify them in the
(general-nmap :prefix "," :prefix-command 'my-prefix-map "g" 'magit-status) (general-imap "," (general-key-dispatch 'self-insert-command :timeout 0.25 :inherit-keymap my-prefix-map))
If you bind more keys under your prefix later on in normal state, they will still be available when pressing the prefix in insert state without the need to re-evaluate the
general-key-dispatch will prevent name clashes by appending a unique number to name of the created command (e.g.
general-dispatch-self-insert-command-G402). If you would like to reference the created command by name, you can name it yourself using the
:name keyword argument (e.g.
general-simulate-key used with a command name, the behavior of
evil-repeat will depend on the command that ends up running. Having repeating work correctly requires handling a lot of edge cases, so please make an issue if you find any problems. Note that evil does not support repeating a count that comes before an operator currently, but repeating should work when the count follows the operator key (
Choosing Definitions Based on Predicates
general-predicate-dispatch can be used to generate a
menu-item that will behave differently based on the provided predicates. It takes a fallback definition as the first argument and then a list of predicates and alternate definitions (which can be commands, keymaps, etc.). Predicates are checked in order. If no predicate is matched and the fallback command is nil, then the mapping will be ignored (the keymap with the next highest precedence, if one exists, will be checked for the pressed key(s)).
(general-define-key "<right>" (general-predicate-dispatch 'right-char ;; pred def ... (eolp) 'beginning-of-line))
:docstring keyword can be specified to add a description to the extended menu item.
general-translate-key allows binding a key to the definition of another key in the same keymap (comparable to how vim’s keybindings work). Its arguments are the
states (which can be nil for non-evil keymaps) and
keymaps (both symbols or lists of symbols like for
general-define-key) to bind/look up the key(s) in followed optionally by keyword arguments (currently only
:destructive) and key/replacement pairs.
evil-collection-translate-key allows binding a key to the definition of another key in the same keymap (comparable to how vim’s keybindings work). Its arguments are the
keymaps to bind/look up the key(s) in followed optionally by keyword arguments (currently only
:destructive) and key/replacement pairs.
states can be nil for non-evil keymaps, and both
keymaps can be a single symbol or a list of symbols.
This can be particularly useful, for example, when you want make key swaps/cycles en masse. This use case is similar to one for
general-simulate-key (i.e. make a key act as another key that has a consistent meaning but different commands for different modes without having to individually bind the key to the exact definition in each mode’s keymap). However,
general-simulate-key is not always suitable for this purpose. It can be used to, for example, make
j in normal state act as
C-n in emacs state (to use the default “down” navigation key for all modes without needing to individually make keybindings for every mode), but it cannot be used to swap/cycle keys within a single keymap, as this would cause an infinite loop of simulating the other key(s).
An example use case of
general-translate-key is for non-QWERTY users who want to retain the hjkl keyboard positions for movement in dired, mu4e, etc. When using a package that already creates hjkl keybindings for the desired mode(s) (e.g. evil-collection), it is easily possible to make these cycles in a single statement:
;; single invocation example (general-translate-key nil 'evil-normal-state-keymap "n" "j" "e" "k" ...) ;; cycling keys en masse (dolist (keymap keymaps-with-hjkl-keybindings) (general-translate-key 'normal keymap ;; colemak hnei is qwerty hjkl "n" "j" "e" "k" "i" "l" ;; add back nei "j" "e" "k" "n" "l" "i"))
By default, the first invocation of
general-translate-key will make a backup of the keymap. Each subsequent invocation will look up keys in the backup instead of the original. This means that a call to
general-translate-key will always have the same behavior even if evaluated multiple times. When
:destructive t is specified, keys are looked up in the keymap as it is currently. This means that a call to
general-translate-key that swapped two keys would continue to swap/unswap them with each call. Therefore when
:destructive t is used, all cycles/swaps must be done within a single call to
general-translate-key. To make a comparison to vim keybindings,
:destructive t is comparable to vim’s
:destructive nil is comparable to vim’s
noremap (where the “original” keybindings are those that existed in the keymap when
general-translate-key was first used).
You’ll almost always want to use the default behavior (especially in your init file). The limitation of
:destructive nil is that you can’t translate a key to another key that was defined after the first
:destructive t may be useful for interactive experimentation.
Note that general state and keymap aliases (as well as
general-implicit-kbd are supported by
;; normal -> evil-normal-state-keymap (general-translate-key nil 'normal ;; kbd not necessary by default "C-p" "C-n")
Keys are bound using
general-define-key, so they are viewable with
general-swap-key is provided as a wrapper around
general-translate-key that allows swapping keys:
(general-swap-key nil 'normal ";" ":" "a" "A") ;; equivalent to (general-translate-key nil 'normal ";" ":" ":" ";" "a" "A" "A" "a")
Automatic Key Unbinding
To automatically prevent
Key sequence starts with a non-prefix key errors without the need to explicitly unbind non-prefix keys, you can add
(general-auto-unbind-keys) to your configuration file. This will advise
define-key to unbind any bound subsequence of the
KEY. Currently, this will only have an effect for
general.el key definers. The advice can later be removed with
The reason that advice is used is because
general-define-key does not always define keys in the same manner. Because customer definers are supported with
general-define-key does not have the necessary information to handle every case itself.
As a final note, if you, for example, bind
s to a command using
general-define-key and then later bind
s <key> to something,
s will still show up in
general-describe-keybindings even though it’s no longer bound. Since this is preventable by simply removing the initial unused keybinding, I likely will not try to add a workaround to fix this.
Non-keybinding-related Configuration Helpers
General.el also provides a few helper functions/macros for other configuration purposes. They are intended to be slightly more convenient versions of functions/macros provided by default.
general-setq is a stripped-down
customize-set-variable that can act as a drop-in replacement for
setq. The reason you might want to use it instead of
setq is that
setq cannot correctly set all variables. Some variables defined with
defcustom specify a custom setter with
:set that must be used for changes to take effect (e.g.
auto-revert-interval). If the corresponding package has already been loaded, using
setq will generally not work to set these variables. On the other hand,
general-setq will correctly use the custom setter when necessary. One benefit of
customize-set-variable is that it can be used to set multiple variables at once. It does not do everything
customize-set-variable does (e.g. it cannot be used interactively, does not attempt to load variable dependencies, and does not allow the user to specify comments). From some basic testing, it is 10x to 100x faster because of this, but the speed difference should not really be noticeable if you aren’t setting thousands of variables during emacs initialization.
Here’s an example using variables that have a custom setter:
(general-setq auto-revert-interval 10 evil-want-Y-yank-to-eol t evil-search-module 'evil-search)
setq will work as expected as long it is used before the corresponding package is loaded, but with
general-setq, you do not need to worry about whether or not the package has been loaded. If you decide to use
general-setq, I’d recommend aliasing it to something shorter like
One major difference from
customize-set-variable that you should be aware of is that
general-setq falls back to using
set instead of
set-default. This means that, like
setq, it will alter the local value of buffer-local variables instead of the default value.
general-setq-local also exist but do not attempt to call custom setters. The reason for this is that I have never seen any custom setters for variables that make sense to set both globally and locally (custom setters I’ve seen just use
setq-default is useful when you want to globally change the default for a buffer-local variable.
setq-local is useful when you want to make a non-buffer-local variable buffer-local and then change its local value (
setq already preferentially alters the buffer-local value of a variable if there is one). For now, the general.el equivalents are just aliases, but in the future, they will likely record user settings to be displayed in a table later.
Hooks and Advice
general-advice-remove all act as drop-in replacements for their corresponding functions but allow lists for some of the arguments. The hook functions allow specifying lists for the hooks and functions, and the advice functions allow specifying lists for the symbols and functions. Because I don’t like the difference in naming for the default advice functions,
general-remove-advice are also provided as aliases.
(general-add-hook my-lisp-mode-hooks (list #'lispy-mode #'rainbow-delimiters-mode)) ;; note that setting the :jump command property is recommended instead of this (general-add-advice (list 'git-gutter:next-hunk 'git-gutter:previous-hunk) :before #'evil-set-jump)
general-add-advice can add “transient” functions to hooks or as advice. These transient functions will remove themselves from the hook or as advice after they run once (inspired by Doom Emacs). Additionally, they can remove themselves after the first time they return non-nil or after any arbitrary condition is met. For an example of this, see the implementation of
general-after-init can be used to run code after initialization (e.g.
(general-after-init (do-something) (do-something-else))). It just adds to
after-init-hook or runs the code immediately if initialization has happened already.
general-after-tty can be used to run some code once after the first graphical or terminal frame is created. Here is an example use case:
(use-package clipetty :ensure t :init ;; only need to load if create a terminal frame ;; `global-clipetty-mode' will not cause issues if enabled for a server with ;; both graphical and terminal frames (general-after-tty (global-clipetty-mode)))
These both use
general-add-hook to create “transient” hooks.
Integration with Other Packages
General also optionally provides a use-package keyword.
:general is similar to
:bind in that it implies
:defer t whenever there are bound commands that can be autoloaded (e.g. it will not imply
:defer t if the only bound command is to a lambda, for example). Whenever autoloadable commands are bound, use-package will create autoloads for them (though this is usually not necessary). The keyword is followed by one or more lists containing arguments for
general-def; there is no difference in syntax:
(use-package org :general ("C-c c" 'org-capture) (:keymaps 'org-mode-map "TAB" 'org-cycle) ;; uses `general-def' not `general-define-key', so this is fine (org-mode-map "TAB" 'org-cycle))
:general keyword also supports using any other key definer/wrapper by manually specifying it:
(use-package org :general (general-nmap "SPC c" 'org-capture))
One annoyance you may encounter is that the default function for indentation will indent a list starting with a keyword like a function:
(:keymaps 'org-mode-map "TAB" 'org-cycle)
This is an annoyance you may have using other emacs packages as well and can be fixed by modifying
lisp-indent-function (see this emacs stackexchange question and Fuco1’s modified
lisp-indent-function in one of the answers there).
General provides two alternatives to
:hook that use
:gfhook. Both take any number of arguments of symbols or lists. List arguments work the same for both; they correspond to a list of arguments for ~general-add-hook~. The primary difference between the two is that symbol arguments to
:ghook are hooks, but they are functions for
:gfhook (hence the
:ghook usually implies
:defer t, and
:gfhook never implies
:ghook should be used when the
general-add-hook is meant to trigger the loading of the package.
:gfhook should be used when the
general-add-hook is meant to trigger some function in response to the package’s mode being enabled (or toggled in the case of a minor mode). More simply put,
:ghook is suited towards enabling minor modes, and
:gfhook is suited towards performing setup once some mode has loaded. The use case for each is further explained below.
:ghook is intended to be used to add a package’s minor mode enabling function to a user-specified hook, so that when hook is run, the package will be loaded and the mode enabled. This means that
:ghook will usually imply
:defer t. While it does not always imply
:defer t, it will add any non-lambda functions to
:commands (this is the same behavior as
:hook). Though this is usually unnecessary (the commands probably already have autoloads), it will in turn imply
Symbols specified with
:ghook correspond to hooks, and the function to add to each hook is inferred from the package’s name (i.e.
-mode is automatically added to the package name unless the package’s name already ends in
-mode). For example, these are all the same:
(use-package rainbow-delimiters :ghook 'prog-mode-hook) (use-package rainbow-delimiters ;; `general-add-hook' arglist: HOOKS FUNCTIONS &optional APPEND LOCAL ;; a missing FUNCTIONS argument will be replaced with inferred minor mode :ghook ('prog-mode-hook)) (use-package rainbow-delimiters ;; a null or non-symbol placeholder for FUNCTIONS will be replaced with ;; inferred minor mode command; this may be useful if you want to keep the ;; inferred command but also want to set the APPEND and/or LOCAL arguments ;; afterwards, e.g. ('prog-mode-hook nil t) :ghook ('prog-mode-hook nil)) (use-package rainbow-delimiters ;; the full arglist for `general-add-hook' can be specified ;; this is necessary if inference is not possible (see below for an example) :ghook ('prog-mode-hook #'rainbow-delimiters-mode)) (use-package ;; :commands implies :defer t :commands rainbow-delimiters-mode :init (general-add-hook 'prog-mode-hook #'rainbow-delimiters-mode))
If you are already familiar with
:hook, you should note that there are quite a few syntactic differences between
:hook. Firstly, quoting the hooks and functions is required. Like
:general uses the same syntax as
:ghook uses the same syntax as
(general-)add-hook for both clarity and convenience. For example, the user may want to use a helper function/macro to generate the function(s) to add to the hook (see the :gfhook section for a specific example). The user may also want to specify a variable containing a list of hooks instead of an actual hook name:
(defconst my-lisp-mode-hooks '(lisp-mode-hook emacs-lisp-mode-hook clojure-mode-hook scheme-mode-hook ;; ... )) (use-package lispy :ghook my-lisp-mode-hooks) ;; same as (use-package lispy :ghook (my-lisp-mode-hooks)) ;; same as (use-package lispy ;; `general-add-hook' can take a list of hooks for the HOOK argument :ghook ('(lisp-mode-hook emacs-lisp-mode-hook clojure-mode-hook scheme-mode-hook ;; ... )))
:ghook will not automatically add
-hook to specified hook symbols (i.e. you must specify
prog-mode is not sufficient). This design decision is intended to help prevent confusion since
:gfhook also exists, and its symbols correspond to functions (not hooks) that could also end in
-mode (and could potentially not be sharp quoted). I don’t think the loss in conciseness is major, and hopefully this will help always make it immediately clear whether symbols correspond to functions or hooks.
:hook only takes one argument, whereas
:ghook can take an arbitrary number of arguments (just like
(use-package lispy ;; any number of symbols (or lists) is allowed :ghook 'lisp-mode-hook 'emacs-lisp-mode-hook 'clojure-mode-hook 'scheme-mode-hook)
Note that if the function name cannot be inferred from the package name (i.e. the package name or the package name with
-mode appended is not correct), you need to specify a full
(use-package yasnippet :ghook ('(text-mode-hook prog-mode-hook) #'yas-minor-mode))
:gfhook is intended to be used to specify functions to add to the package’s mode hook. The hook is inferred from the package’s name (by appending either
-mode-hook or just
-hook if the package’s name ends in
-mode). If the hook cannot be inferred from the package name, then the full arglist must be specified just as with
:gfhook never adds functions to
:commands and therefore never implies
:defer t. This is because the functions specified are ones that should be run when turning on (or toggling) the mode(s) the package provides. The specified functions are external to the package, could be called elsewhere, and therefore should not trigger the package to load. The following all have the same effect:
(use-package org ;; for a major-mode package, you might use :mode to imply :defer t (or just ;; use :defer t; or just `use-package-always-defer' which I personally prefer) :gfhook #'visual-line-mode #'my-org-setup ;; ... ) (use-package org :init (general-add-hook 'org-mode-hook #'visual-line-mode) (general-add-hook 'org-mode-hook #'my-org-setup)) ;; this is also valid but less concise (use-package org ;; specify null or non-symbol placeholder for HOOKS to use inferred hook :gfhook (nil (list #'visual-line-mode #'my-org-setup))) (use-package org :init (general-add-hook 'org-mode-hook (list #'visual-line-mode #'my-org-setup)))
:gfhook still requires quoting, so you can use variables and function/macro calls to generate the function to add to the hook:
(defmacro disable (mode) `(lambda () (,mode -1))) (use-package proced ;; must be in a `general-add-hook' argument list, so that it itself is not ;; considered one :gfhook (nil (disable visual-line-mode)))
Although you could use
:gfhook to enable minor modes for some major mode (e.g. enable flyspell inside
(use-package org)), it is probably more logical/organized to group these hooks along with their minor modes’ use-package declarations (e.g. using
:gfhook is more suited for setup functions. Expanding on the proced example:
(defun my-proced-setup () (visual-line-mode -1) ;; not global; has to be run in buffer (proced-toggle-auto-update t)) (use-package proced :gfhook #'my-proced-setup)
Use with Key-chord
General provides a simple function that will rewrite a string into a key-chord vector. This allows you to easily use general to create definitions for
key-chord.el. The following are equivalent:
(key-chord-define evil-insert-state-map "jk" 'evil-normal-state) (general-define-key :keymaps 'evil-insert-state-map (general-chord "jk") 'evil-normal-state (general-chord "kj") 'evil-normal-state)
Note that the order of the keys does matter unlike with the default
Extended Definition Syntax
General.el supports some extra per-definition keywords. It has “type” keywords that give general.el some extra information to use to create definitions (e.g.
:keymap) and other keywords that will alter or ignore definitions (e.g.
The system that allows for the default keywords can also be extended by the user to support more keywords that can either directly alter the definition or just be used for side effects (like
:which-key). An extended definition keyword can have any number of helper keywords (and can also be used as a helper keyword itself, e.g.
:keymap). See User-defined Extended Definition Keywords for more information on creating new keywords.
Here are the keywords available by default (helper keywords are subitems; specific examples are given later):
:def- Implicit; this is paired with the actual definition (helper keyword; does not trigger any special behavior by itself)
:keymap- For keymaps; if the keymap is not defined, will create an “autoloaded” keymap for
:package- The package to load (also global)
:prefix-map- These are the same as
:keymaprespectively but will create a prefix command and/or keymap (these behave the same as the global keyword arguments except for any key as opposed to just
:prefix-nameThe keymap menu name/prompt (global value never considered)
:ignore- Do not create a keybinding for the key def pair
Note that every bindable definition must have
:def, but general allows for shorthand where
:def can be omitted or a “type” specifier can be used instead:
;; shorthand '(swiper :wk "swipe") ;; rewritten to '(:def swiper :wk "swipe") ;; shorthand '(:keymap some-keymap) ;; rewritten to '(:def some-keymap :keymap some-keymap) ;; same as '(:def some-keymap :keymap t) ;; shorthand '(:prefix-command my-prefix-cmd :prefix-map my-prefix-map) ;; rewritten to '(:def my-prefix-cmd :prefix-command my-prefix-cmd :prefix-map my-prefix-map)
After the shorthand expansion, the type keywords are handled exactly the same as any other extended definition keyword.
Which-key functionality (see below for more details):
:wk- The replacement text (or cons or function)
:major-modes- Major modes to match (optional; also global)
:wk-match-keys- Whether to include the keys in the match cons (defaults to
:wk-match-binding- Whether to include the binding in the match cons (defaults to
t; also global)
:wk-full-keys- Whether the bound keys correspond to the full sequence to match (defaults to
t; also global)
:keymap- When non-nil, general will not try to match a keymap symbol as if it was a command
Evil command properties (see below for more details):
:properties- The list of properties to add to the command (also global)
:repeat- The repeat property to set for the command (also global)
:jump- The jump property to set for the command (also global)
Global keywords that can be overridden locally:
The default value for a keyword is
nil unless otherwise specified.
As the first example, an extended definition can be used to create an “autoload” for a keymap like use-package’s
:bind-keymap keyword does:
(general-define-key "C-c p" '(:keymap projectile-command-map :package projectile))
Using this feature, a key can be bound to a keymap that does not exist yet and still work as expected. Projectile will be loaded when
C-c p is used for the first time. This is done by using an intermediate function to load the package and rebind the keys.
:keymap is the primary keyword that triggers this check. It can also be used as a helper keyword (e.g. for
which-key). If the keymap already exists, general will not try to create an autoloaded keymap, and
:package is not required.
:package is a helper keyword that can be specified locally within the extended definition or globally. When using the use-package
:general keyword, it will automatically be specified.
Which Key Integration
If you are not already familiar with which-key’s replacement system, please see the docstring for
which-key-replacement-alist if you don’t understand any of the examples or information here.
There are several benefits to using general.el to add which-key replacements. The main benefit is that because the keys and definition are already specified, general.el can automatically assemble the match cons. This reuse of information saves a little space since it is not necessary to make an additional call to
which-key-add-key-based-replacements with the key information. It is also useful since which-key does not currently provide any convenience function for creating a replacement that matches a binding (you have to manually add to
which-key-replacement-alist). However, see which-key’s which-key-enable-extended-define-key which provides another method for automatically creating replacements and binding keys simultaneously.
Another related benefit of using
:which-key instead of
which-key-add-key-based-replacements directly even for keys that won’t be bound is that replacements will be added for all prefix combinations (i.e. when
:global-prefix are also specified).
The argument supplied to
:wk is equivalent to the REPLACEMENT argument in
which-key-add-key-based-replacements. It can be a full replacement cons of
(KEY . BINDING) or just a string (which will be used as the BINDING and serve as the new description). Additionally it can be a function that will return a replacement cons (see the docstring for
which-key-replacements-alist or the which-key README). Finally, which-key allows for a special replacement of
t to prevent a key from being shown in the which-key popup at all.
:which-key keyword can be used with the
:major-modes keyword (locally or globally) which can be compared to using
:major-modes can have the following values (see the examples below):
t- the major mode will be obtained from all keymaps by removing “-map”
- the major mode name (when only one keymap is specified)
- a list of the following values:
t- same behavior as above but only for corresponding index in
- the major mode name for that index
nil(or no item at the index) - don’t match the major mode
:wk-full-keys can be used to customize the match cons. Generally these will not need to be adjusted. The binding is only included in the match cons if one is available, and
:wk-full-keys only needs to be specified as
nil if you are binding keys in a prefix map.
Here are some examples:
(general-define-key :prefix "SPC" :keymaps 'normal ;; unbind SPC and give it a title for which-key (see echo area) "" '(nil :which-key "my lieutenant general prefix") ;; bind nothing but give SPC f a description for which-key "f" '(:ignore t :which-key "file prefix") ;; use a cons as a replacement "g" '(:ignore t :wk ("g-key" . "git prefix")) ;; toggle lispy; use a function as a replacement to show if currently on "l" '(lispy-mode :wk my-lispy-which-key-display) ;; for a keymap, only the keys will be matched; ;; :no-match-binding is not necessary "p" '(:keymap projectile-command-map :wk "projectile prefix") ;; don't display this keybinding at all "z" '(hidden-command :wk t) ...) (general-define-key :keymaps 'help-map ;; allow keys before bound keys in match ;; since binding in a prefix map :wk-full-keys nil ;; make a prefix-command and add description "A" '(:prefix-command apropos-prefix-map :which-key "apropos")) ;; an equivalent of the above (general-define-key :keymaps 'help-map :wk-full-keys nil :prefix "A" :prefix-command 'apropos-prefix-map ;; make a prefix-command and add description "" '(:ignore t :which-key "apropos")) ;; :major-modes (general-define-key :keymaps 'emacs-lisp-mode-map :major-modes t ...) (general-define-key :keymaps '(no-follow-convention-mode-keymap1 org-mode-map) :major-modes '(no-follow-convention-mode t) ...)
Evil Command Properties
:jump keywords can be used to add evil command properties:
(general-define-key :keymaps 'normal :prefix "SPC" "gj" '(git-gutter:next-hunk :properties (:repeat t :jump t)) "gk" '(git-gutter:previous-hunk :repeat t :jump t)) ;; they also work globally (general-define-key :keymaps 'normal :prefix "SPC" :properties '(:repeat t :jump t) ;; or :repeat t :jump t "gj" 'git-gutter:next-hunk "gk" 'git-gutter:previous-hunk)
Note that the default for commands without a repeat property are treated the same as commands with
:repeat t, so the above repeat configuration isn’t explicitly necessary in this case.
If you would like for more keywords to be added that correspond to specific properties (like
:repeat), feel free to make an issue or pull request. For more information on command properties see evil’s documentation and here.
User-defined Extended Definition Keywords
New keywords and functionality can be added by the user by adding a keyword to
general-extended-def-keywords and creating a corresponding function named
Whenever this keyword is specified, general calls the corresponding function with the arguments
state keymap key edef kargs. Generally, you can ignore at least some of these arguments.
keymap are the evil state (nil if none) and keymap that the
key (internal representation;
kbd already used if necessary) is being bound in. Note that
keymap will be the symbol for the keymap in case it is needed. To get the actual keymap, using
general--get-keymap is recommended.
edef is the extended definition itself, and
kargs is the plist of all the keyword arguments given to the original
Extended definition functions can optionally alter the definitions. Keywords that have this behavior must be added to either
general-rewrite-def-after-keywords instead of to
general-extended-def-keywords. The difference between the two is that the former will alter the definition before the functions for the keywords in
general-extended-def-keywords are called. Functions that alter the definition should return a new extended definition plist with the
:def entry updated. For a simple example of a function that does not alter the definition, see
general-extended-def-:properties. For a simple example of a function that does alter the definition, see
Extended definition keywords may use any number of helper keywords. These do not need to be added to any variables but should be distinct from any other keywords.
Note that the keywords in
general-extended-def-keywords and their helper keywords can all be specified both globally and locally. Since globally specifying keywords may not always make sense, it is up to the
general-extended-def-:<keyword> function to decide how to handle things. When a keyword can be specified both globally and locally,
general--getf may be useful to get the local value or the global value if there is no local one (e.g.
(general--getf edef kargs :predicate)). If it does not make sense for your keyword to be specified globally, you can add it to
general-extended-def-global-ignore-keywords. This will prevent your function from being called unless the keyword is specified locally.
general--getf are marked internal, they will continue to exist and keep their current functionality; they are intended to be used as helpers for extended definitions.
You can rely on
edef being a valid extended definition plist with a
:def keyword. Even if the user only specifies a keyword globally and does not explicitly write definitions as plists or explicitly specify
:def, general will automatically rewrite definitions to be valid plists. Consider the following example:
(general-define-key :predicate '(eobp) "<right>" 'beginning-of-buffer) ;; call `general-extended-def-:predicate' with this as an edef argument: '(:def beginning-of-buffer) (general-define-key "<right>" '(beginning-of-buffer :predicate (eobp))) ;; call `general-extended-def-:predicate' with this as an edef argument: '(:def beginning-of-buffer :predicate (eobp))
For more information, see the docstring of
User-defined Key Definers
In addition to being able to add new keywords for extended definitions, the user can also create their own key definers. These are generally useful when you want to use some package-specific key definer that has some additional functionality (e.g.
Alternate definers can be used by specifying the
:definer keyword (globally or inside an extended definition):
(general-define-key :definer 'my "key" 'def "key2" '(def2 :definer 'my-other))
The user-created function should be named
general-<definer>-define-key. It will be passed
state keymap key def orig-def kargs. These arguments are the same as for extended definition functions except for
def is the transformed definition in its final form (though the definer may also alter it before binding it). On the other hand,
orig-def is the original definition but always as an extended definition plist (e.g. =’(:def command)= if the user only specified =’command=).
Like extended definitions, custom definers can have any number of helper keyword arguments specified locally in an extended definition or globally in the arguments to
general-define-key. In cases where a keyword can be both global and local,
general--getf is a useful helper function. Since the keymap passed in is a symbol,
general--get-keymap may be useful as well for transforming it to the keymap value.
key-description will also be useful if the underlying definition function uses
key is the internal representation ready to be passed directly to
define-key; note that
key-description will work with both strings and vectors, including something like
general-lispy-define-key for a basic example.
If you want to use
evil-define-minor-mode-key instead of
evil-define-key*, you can use
:definer 'minor-mode. This will repurpose
:keymaps to specify minor mode names instead of keymap names:
(general-define-key :definer 'minor-mode :states 'normal :keymaps 'org-src-mode "RET" 'org-edit-src-exit)
If you are wondering why you might want to use
evil-define-minor-mode-key, see here.
Lispy Integration/ Wrapping
lispy-define-key to make the definitions,
:definer 'lispy can be specified.
:lispy-plist can be specified globally or in an extended definition to set the last argument to
Worf Integration/ Wrapping
worf-define-key to make the definitions,
:definer 'worf can be specified.
:worf-plist can be specified globally or in an extended definition to set the last argument to
Other Provided Definers
lpy-define-key to make the definitions,
:definer 'lpy can be specified.
How do I prevent
Key sequence starts with non-prefix key errors?
By default, emacs does not support binding a key sequence where a subsequence of the key is already bound in the same keymap (e.g. you cannot bind
C-a a to a command in a keymap where
C-a is already bound to a command).
If you want to be able to bind both key sequences and fall back to the shorter key’s command after a timeout or unmatched keypress, see general-key-dispatch.
Otherwise, you should unbind the non-prefix key. For example:
(general-define-key :keymaps 'normal :prefix "s" ;; prefix keys are prepended to other keys, so "" refers to the prefix itself "" nil "a" #'def ;; ... )
If you would rather force key definitions to always be made regardless of whether a subsequence of the key is already bound, general can automatically unbind keys when necessary to prevent this error.