general.el icon indicating copy to clipboard operation
general.el copied to clipboard

More convenient key definitions in emacs

#+TITLE: General User Manual #+AUTHOR: Fox Kiester #+LANGUAGE: en #+TEXINFO_DIR_CATEGORY: Emacs #+TEXINFO_DIR_TITLE: General: (general). #+TEXINFO_DIR_DESC: More convenient key definitions.

NOTE: If you are viewing this in org-mode, it is recommended that you install and enable [[https://github.com/snosov1/toc-org][toc-org]], so that all internal links open correctly

[[https://melpa.org/#/general][file:https://melpa.org/packages/general-badge.svg]] [[https://github.com/noctuid/general.el/actions?query=workflow%3Atest][https://github.com/noctuid/general.el/workflows/test/badge.svg]] [[https://codecov.io/gh/noctuid/general.el][https://codecov.io/gh/noctuid/general.el/branch/master/graph/badge.svg]]

[[https://github.com/noctuid/general.el][file:http://i.imgur.com/SXA66y7.png]] #+BEGIN_QUOTE A general is a leader. -- onioncheese #+END_QUOTE

  • Recent Breaking Changes :noexport: ** 2018-01-21 =general-default-...= variables are obsolete =general-default-prefix=, =general-default-non-normal-prefix=, =general-default-global-prefix=, =general-default-states=, and =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.

** 2018-01-20 ~general-create-vim-definer~ and ~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.

** 2018-01-20 =:states 'normal= is now the same as =:keymaps 'normal= =: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][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.

** 2018-01-20: ~general-simulate-keys~ is now obsolete Please switch to ~general-key~ or ~general-simulate-key~. Note that keyword arguments have replaced the positional arguments of ~general-simulate-keys~. ~general-simulate-keys~ will likely be removed sometime in the future.

  • Table of Contents :noexport:TOC:
  • [[#about][About]]
  • [[#dependency-versions][Dependency Versions]]
  • [[#key-features][Key Features]]
  • [[#reading-recommendations][Reading Recommendations]]
  • [[#usage-recommendations-and-documentation-clarifications][Usage Recommendations and Documentation Clarifications]]
  • [[#basic-examples][Basic Examples]]
    • [[#general-examples][General Examples]]
    • [[#evil-examples][Evil Examples]]
    • [[#switching-completely-to-general][Switching Completely to General]]
  • [[#general-define-key-details][~general-define-key~ Details]]
    • [[#definitions][Definitions]]
    • [[#keyword-arguments][Keyword Arguments]]
      • [[#predicates][Predicates]]
    • [[#keymapstate-aliases][Keymap/State Aliases]]
    • [[#general-define-key-wrappers][~general-define-key~ Wrappers]]
      • [[#positional-argument-wrappers][Positional Argument Wrappers]]
      • [[#mass-key-unbinding-wrapper][Mass Key Unbinding Wrapper]]
      • [[#creating-new-key-definers][Creating New Key Definers]]
      • [[#vim-like-definers][Vim-like Definers]]
    • [[#note-for-evil-users][Note for Evil Users]]
  • [[#override-keymaps-and-buffer-local-keybindings][Override Keymaps and Buffer Local Keybindings]]
  • [[#displaying-keybindings][Displaying Keybindings]]
  • [[#functionsmacros-to-aid-key-definition][Functions/Macros to Aid Key Definition]]
    • [[#disclaimer][Disclaimer]]
    • [[#simulating-keypresses][Simulating Keypresses]]
    • [[#mapping-under-non-prefix-keys][Mapping Under Non-prefix Keys]]
    • [[#choosing-definitions-based-on-predicates][Choosing Definitions Based on Predicates]]
    • [[#key-translation][Key "Translation"]]
    • [[#automatic-key-unbinding][Automatic Key Unbinding]]
  • [[#non-keybinding-related-configuration-helpers][Non-keybinding-related Configuration Helpers]]
    • [[#settings][Settings]]
    • [[#hooks-and-advice][Hooks and Advice]]
    • [[#miscellaneous][Miscellaneous]]
  • [[#integration-with-other-packages][Integration with Other Packages]]
    • [[#use-package-keywords][Use-package Keywords]]
      • [[#general-keyword][:general Keyword]]
      • [[#no-autoload-keyword][:no-autoload Keyword]]
      • [[#hook-keywords][Hook Keywords]]
        • [[#ghook-keyword][:ghook Keyword]]
        • [[#gfhook-keyword][:gfhook Keyword]]
    • [[#use-with-key-chord][Use with Key-chord]]
  • [[#extended-definition-syntax][Extended Definition Syntax]]
    • [[#autoloaded-keymaps]["Autoloaded" Keymaps]]
    • [[#which-key-integration][Which Key Integration]]
    • [[#evil-command-properties][Evil Command Properties]]
    • [[#user-defined-extended-definition-keywords][User-defined Extended Definition Keywords]]
  • [[#user-defined-key-definers][User-defined Key Definers]]
    • [[#wrapping-evil-define-minor-mode-key][Wrapping ~evil-define-minor-mode-key~]]
    • [[#lispy-integration-wrapping-lispy-define-key][Lispy Integration/ Wrapping ~lispy-define-key~]]
    • [[#worf-integration-wrapping-worf-define-key][Worf Integration/ Wrapping ~worf-define-key~]]
    • [[#other-provided-definers][Other Provided Definers]]
  • [[#faq][FAQ]]
    • [[#how-do-i-prevent-key-sequence-starts-with-non-prefix-key-errors][How do I prevent =Key sequence starts with non-prefix key= errors?]]
    • [[#why-dont-some-evil-keybindings-work-immediately][Why don't some evil keybindings work (immediately)?]]
  • About =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 ~general-describe-keybindings~.

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.

  • Dependency Versions 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.

  • Key Features

  • 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-key~ and other definers (e.g. ~evil-define-key(*)~ for evil users) before using this package
  • Uses a syntax similar to ~setq~ for key definitions (like ~evil-define-key~, ~bind-map~, =evil-leader.el=, etc.; unlike ~bind-key~)
  • Provides tight (and optional) integration with evil (unlike ~bind-key~)
  • ~general-def~ can act as a drop-in replacement for the following definers (see the documentation below for a minor caveat) (unique):
    • ~general-define-key~ and ~global-set-key~ (no positional keymap argument)
    • ~define-key~ and ~evil-global-set-key~ (positional argument for keymap)
    • ~evil-define-key~ (positional argument for state and keymap)
  • With the =:definer= keyword, ~general-define-key~ can be extended to use any key definition function (e.g. ~evil-define-minor-mode-key~, ~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 ~general-define-key~ (unique)
  • Allows binding keys in multiple keymaps/states at once (unlike ~bind-key~)
  • Automatically wraps string keys and definitions with ~kbd~ (this behavior can be turned off for compatibility with ~define-key~)
  • Allows using an arbitrary number of prefix keys or "leaders" of any length (but does not require prefix keys like) (unlike =evil-leader.el=)
  • Allows for automatically creating prefix commands (but does not require creating them like ~bind-key~ does)
  • Allows for buffer-local keybindings (unlike ~local-set-key~)
  • Allows deferring keybindings until the specified keymap exists (no need to use ~(with-)eval-after-load~) (like ~evil-define-key~)
  • Allows displaying defined keys (like =bind-key.el=)
  • Provides integration with other packages such as =key-chord.el= and =which-key.el= (unique)
  • Provides other helpers for keybindings (unique):
    • A method for creating "autoloaded" keymaps (like =bind-key.el=)
    • 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 =jk= in insert mode without losing =j=)
    • A helper to create a menu item to dispatch to different definitions based on predicates
  • Provides other helpers for configuration (e.g. more convenient functions for hooks and advice)
  • Is well tested (unlike =evil-leader.el=)
  • Reading Recommendations Before using =general.el=, you should first be familiar with ~define-key~, ~global-set-key~, and [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Key-Bindings.html][emacs' key binding system]]. I recommend reading [[https://www.masteringemacs.org/article/mastering-key-bindings-emacs][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-key~, ~evil-define-minor-mode-key~, etc. work. If you are a new evil user, I'd recommend looking at my [[https://github.com/noctuid/evil-guide][evil guide]]. The [[https://github.com/noctuid/evil-guide#keybindings-and-states][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 ~define-key~, ~evil-define-key~, etc. statement.

See also the [[#faq][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 =:states= and =:keymaps=. Since users will most often specify one or both of these keyword arguments, ~general-define-key~ is often less concise than ~define-key~ or ~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-define-key~. ~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, [[#positional-argument-wrappers][~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 ~general-define-key~, ~define-key~, and ~evil-define-key~). Note that ~general-create-definer~ and the =:general= keyword argument for ~use-package~ use ~general-def~. I personally only use ~general-def~.

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.

Although ~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.

  • Basic Examples ** General Examples #+begin_src emacs-lisp (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) #+end_src

** Evil Examples #+begin_src emacs-lisp (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) #+end_src

Vim-like definitions: #+begin_src emacs-lisp (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)

#+end_src

** 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 =:%s/(global-set-key|define-key|evil-global-set-key|evil-define-key)/general-def/g=.

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 (~general-define-key~, ~general-emacs-define-key~, or ~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.

  • ~general-define-key~ Details 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 ~general-define-key~.

** Definitions 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-definition-syntax]["extended definitions"]]. Here are a few examples of definitions that aren't standard ="string key" 'command= pairs: #+begin_src emacs-lisp ;; 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")) #+end_src

~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-define-key~ or ~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 ~general-key~, ~general-key-dispatch~, and ~general-translate-key~.

** Keyword Arguments =:prefix=, =:states=, and =: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 [[#keymapstate-aliases][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 [[#override-keymaps-and-buffer-local-keybindings][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][Note for Evil Users]] for more information).

=:states= and =: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 =:non-normal-prefix= or =: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 =evil-normal-state-map=. =: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: #+begin_src emacs-lisp (general-define-key :keymaps '(normal insert emacs) :prefix "SPC" :non-normal-prefix "M-SPC" "/" 'swiper) #+end_src

If you would like to create a named prefix keymap for your prefix keys, you can also specify =:prefix-command= and/or =: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-map= and =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-command= or =:prefix-map= will not clear the previously created keymap. #+begin_src emacs-lisp (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) #+end_src

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 [[#creating-new-key-definers][~general-create-definer~]] and write the definition like this: #+begin_src emacs-lisp (my-normal-and-insert-define-key "/" 'swiper) #+end_src

The =: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 =:prefix= and =:non-normal-prefix=: #+begin_src emacs-lisp (my-normal-and-insert-define-key :infix "g" <maps...>) #+end_src

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 =:keymaps= or =:prefix=: #+begin_src emacs-lisp ;; bind "/" directly in the newly created my-prefix-map (general-define-key :prefix-map 'my-prefix-map "/" 'swiper) #+end_src

There is also a =:predicate= keyword for giving a condition under which a map should be active.

*** Predicates The user can use the ~:predicate~ keyword to specify a condition under which the map(s) should be active. For example: #+begin_src emacs-lisp (general-define-key :keymaps 'local :predicate '(eobp) "" 'beginning-of-buffer) #+end_src

~~ 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-definitions-based-on-predicates][Choosing Definition Based on Predicates]].

See [[http://endlessparentheses.com/define-context-aware-keys-in-emacs.html][this post]] for more information about how this works.

** Keymap/State Aliases 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: #+begin_src emacs-lisp (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 ...) #+end_src

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 ~evil-global-set-key~ and ~evil-define-key~: #+begin_src emacs-lisp (general-define-key :keymaps 'motion ...) ;; or (general-define-key :keymaps 'm ...) #+end_src See =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 =-map= or =-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.

** ~general-define-key~ Wrappers *** 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 ~define-key~ and ~evil-define-key~ and another macro that can basically act is a drop-in replacement for both of those and more. They are ~general-emacs-define-key~, ~general-evil-define-key~, and ~general-def~ respectively. These are simply wrappers for ~general-define-key~ that pass the positional arguments to the corresponding keywords. However, for compatibility with ~define-key~ and ~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: #+begin_src emacs-lisp (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)) #+end_src

Similarly, the following are all equivalent: #+begin_src emacs-lisp (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) #+end_src

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, =:keymaps= and =:states= will not override the positional arguments): #+begin_src emacs-lisp ;; 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) #+end_src

As for ~global-set-key~ and ~evil-global-set-key~, wrappers are not needed. By default ~general-define-key~ acts like ~global-set-key~, and ~general-emacs-define-key~ can also act like ~global-evil-set-key~ using the symbols for evil's states (see [[#keymapstate-aliases][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-define-key~, ~general-emacs-define-key~, or ~general-evil-define-key~ depending on the number of positional arguments. #+begin_src emacs-lisp ;; 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) #+end_src

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 (~general-define-key~, ~general-emacs-define-key~, or ~evil-define-key~) or explicitly separate the positional arguments from the first key with a bogus keyword argument: #+begin_src emacs-lisp (general-def :start-maps t some-key 'some-command) #+end_src

*** 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: #+begin_src emacs-lisp (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) #+end_src

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 [[https://github.com/emacs-evil/evil-collection/blob/9fc1a19807dfcd0cc2b221832b6e6faad80a291d/evil-collection-util.el#L32][evil-collection]]): #+begin_src emacs-lisp (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) #+end_src

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 The ~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 ~evil-leader~ does): #+begin_src emacs-lisp ;; 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) #+end_src

It takes an optional =:wrapping= keyword argument that can be specified to use another definer instead of ~general-def~: #+begin_src emacs-lisp (general-create-definer my-prefix-def :wrapping general-emacs-define-key :prefix "M-,") #+end_src

*** Vim-like Definers ~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:

  • ~general-imap~
  • ~general-emap~
  • ~general-nmap~
  • ~general-vmap~
  • ~general-omap~
  • ~general-mmap~
  • ~general-rmap~
  • ~general-iemap~
  • ~general-nvmap~
  • ~general-otomap~
  • ~general-itomap~
  • ~general-tomap~

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. ~nmap~).

Here is an example using ~general-nmap~: #+begin_src emacs-lisp (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 ...) #+end_src

** Note for Evil Users When =:states= is specified, ~general-define-key~ will act as a wrapper around ~evil-define-key*~. ~evil-define-key*~ now directly supports the symbol =global= for the keymap argument, so the following are equivalent: #+begin_src emacs-lisp (general-define-key ;; (default) ;; :keymaps 'global :states '(normal visual) ...) (general-define-key :keymaps '(normal visual) ...) #+end_src

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-and-buffer-local-keybindings][Override Keymaps]]).

  • Override Keymaps and Buffer Local Keybindings General.el provides the equivalent of =bind-key='s =override-global-map= as =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 =:keymaps 'local=, ~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 [[https://github.com/noctuid/evil-guide#what-overrides-evil][here]] with explanations on how to deal with these cases. To understand which evil keybindings override others, review the [[https://github.com/noctuid/evil-guide#keymap-precedence][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: #+begin_src emacs-lisp ;; 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) #+end_src

Note that by default, evil keybindings made with =:keymaps 'override= will override even those made with =:keymaps 'local=.

  • Displaying Keybindings 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. =:keymaps 'local=)
  • Global keybindings (i.e. =:keymaps 'global=)
  • Global evil keybindings (e.g. =:keymaps 'evil-normal-state-map=)
  • 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 =general-describe-update-previous-definition= to =nil=.

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: #+begin_src emacs-lisp (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) #+end_src

For reference, keybindings are stored in an alist. Here is what is passed to each sorting function: #+begin_src emacs-lisp ;; 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) ...) #+end_src

To actually change how the keybinding table is printed, the user could override ~general--print-map~.

  • Functions/Macros to Aid Key Definition ** Disclaimer Key simulation (for ~general-simulate-key~ and ~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-simulate-key~ or ~general-key-dispatch~, please make an issue.

** Simulating Keypresses General provides two macros called ~general-key~ and ~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 [[https://www.emacswiki.org/emacs/Evil#toc14][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-key~ or ~general-simulate-key~: #+begin_src emacs-lisp (general-nmap "SPC" (general-simulate-key "C-c")) ;; or (general-nmap "SPC" (general-key "C-c")) #+end_src

Although both will work correctly, [[https://github.com/justbur/emacs-which-key][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 ~general-simulate-key~.

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 =post-command-hook= for ~general-simulate-key~ but not for ~general-key~).

~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: #+begin_src emacs-lisp (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") #+end_src

~general-simulate-key~ and ~general-key~ also support keyword arguments to control the context the keys are simulated in (both support =:state=; ~general-simulate-key~ supports =: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 =:keymap= to ~general-key~). For example: #+begin_src emacs-lisp (general-nmap "j" (general-simulate-key "C-n" :state 'emacs)) ;; general-key' supports :state only (general-nmap "j" (general-key "C-n" :state 'emacs)) #+end_src

~general-key~ also supports custom setup and teardown before key lookup. Here's a similar example to the previous one: #+begin_src emacs-lisp (general-nmap "j" (general-key "C-n" :setup (evil-local-mode -1) :teardown (evil-local-mode))) #+end_src

The advantage of ~general-simulate-key~ over ~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: #+begin_src emacs-lisp (general-nmap "s" (general-simulate-key ('evil-ex "s/"))) #+end_src 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: #+begin_src emacs-lisp (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")) #+end_src

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 =ctb= or =jk= in insert state). I've come up with a more general workaround called ~general-key-dispatch~. Consider the following example: #+begin_src emacs-lisp (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) #+end_src

~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 ~evil-change~.

Like with ~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 =w= to ~(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. =c2tb= and =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 =jk= to == keybinding: #+begin_src emacs-lisp (general-imap "j" (general-key-dispatch 'self-insert-command "k" 'evil-normal-state)) #+end_src

Commands created in this way support an optional timeout, meaning you could still insert =jk= (without =C-q= / ~quoted-insert~) like with [[https://www.emacswiki.org/emacs/key-chord.el][key-chord.el]]: #+begin_src emacs-lisp (general-imap "j" (general-key-dispatch 'self-insert-command :timeout 0.25 "k" 'evil-normal-state)) #+end_src

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: #+begin_src emacs-lisp (defun my-insert-j () (interactive) (insert "j"))

(general-imap "j" (general-key-dispatch 'my-insert-j :timeout 0.25 "k" 'evil-normal-state)) #+end_src

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: #+begin_src emacs-lisp (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)) #+end_src

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-key-dispatch~: #+begin_src emacs-lisp (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)) #+end_src 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~.

By default, ~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. =:name general-insert-prefix-dispatch=).

Like with ~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 (=3cc= vs =c3c=).

** 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)).

#+begin_src emacs-lisp (general-define-key "" (general-predicate-dispatch 'right-char ;; pred def ... (eolp) 'beginning-of-line)) #+end_src

The =:docstring= keyword can be specified to add a description to the extended menu item.

** Key "Translation" ~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 =states= and =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 =states= and =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. [[https://github.com/jojojames/evil-collection][evil-collection]]), it is easily possible to make these cycles in a single statement: #+begin_src emacs-lisp ;; 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")) #+end_src

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 ~map~, and =: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 ~evil-collection-translate-key~, so =:destructive t= may be useful for interactive experimentation.

Note that general state and keymap aliases (as well as =local= and =global=) and =general-implicit-kbd= are supported by ~general-translate-key~: #+begin_src emacs-lisp ;; normal -> evil-normal-state-keymap (general-translate-key nil 'normal ;; kbd not necessary by default "C-p" "C-n") #+end_src Keys are bound using ~general-define-key~, so they are viewable with ~general-describe-keybindings~.

~general-swap-key~ is provided as a wrapper around ~general-translate-key~ that allows swapping keys: #+begin_src emacs-lisp (general-swap-key nil 'normal ";" ":" "a" "A") ;; equivalent to (general-translate-key nil 'normal ";" ":" ":" ";" "a" "A" "A" "a") #+end_src

** 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 ~(general-auto-unbind-keys t)~.

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 =:definer=, ~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 = 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.

** Settings ~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 ~general-setq~ over ~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: #+begin_src emacs-lisp (general-setq auto-revert-interval 10 evil-want-Y-yank-to-eol t evil-search-module 'evil-search) #+end_src

Note that ~setq~ will work as expected as long it is used before the corresponding package is loaded, but with ~customize-set-variable~ or ~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 ~gsetq~.

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-default~ and ~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 ~set-default~). ~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-add-hook~, ~general-remove-hook~, ~general-advice-add~, and ~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-add-advice~ and ~general-remove-advice~ are also provided as aliases.

For example: #+begin_src emacs-lisp (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) #+end_src

~general-add-hook~ and ~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-gui~.

** Miscellaneous ~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-gui~ and ~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: #+begin_src emacs-lisp (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))) #+end_src

These both use ~general-add-hook~ to create "transient" hooks.

  • Integration with Other Packages ** Use-package Keywords *** :general Keyword 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, and the option ~general-use-package-emit-autoloads~ is non-nil, 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: #+begin_src emacs-lisp (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)) #+end_src

The =:general= keyword also supports using any other key definer/wrapper by manually specifying it: #+begin_src emacs-lisp (use-package org :general (general-nmap "SPC c" 'org-capture)) #+end_src

One annoyance you may encounter is that the default function for indentation will indent a list starting with a keyword like a function: #+begin_src emacs-lisp (:keymaps 'org-mode-map "TAB" 'org-cycle) #+end_src

This is an annoyance you may have using other emacs packages as well and can be fixed by modifying =lisp-indent-function= (see [[http://emacs.stackexchange.com/q/10230/5278][this emacs stackexchange question]] and Fuco1's modified ~lisp-indent-function~ in one of the answers there).

*** :no-autoload Keyword If generating autoloads for commands is not desirable, it can be disabled globally (with the =general-use-package-emit-autoloads= option), on a per-binding basis, or on a per-form basis. To skip generating autoloads for a command, use the extended command definition and set the =:no-autoload= option to non-nil. This can be particularly handy when binding to functions defined in the same use-package block, otherwise the byte-compiler complains about multiple definitions of the same function: #+begin_src emacs-lisp (use-package org :general (:states 'normal "SPC oa" '(my-org-agenda :no-autoload t)) :preface (defun my-org-agenda () (interactive) (let ((org-agenda-tag-filter-preset '("-drill"))) (call-interactively #'org-agenda)))) #+end_src

The keyword can also be used at the global level, instructing general to skip autoloads for all the keybindings in a form: #+begin_src emacs-lisp :general (:states 'normal :no-autoload t "SPC oa" #'my-org-agenda "SPC oc" #'my-org-capture) #+end_src

If you wish to disable emitting autoloads with the =general-use-package-emit-autoloads= variable in a byte-compiled configuration, make sure it is set during macro-expansion time before the =use-package= declarations, with something like ~(eval-and-compile (setq general-use-package-emit-autoloads nil))~.

*** Hook Keywords General provides two alternatives to =:hook= that use ~general-add-hook~ called =:ghook= and =: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 [[#hooks-and-advice][~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 =f=). Furthermore, =:ghook= usually implies =:defer t=, and =:gfhook= never implies =:defer t=. =: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 Keyword =: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 =:defer t=.

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: #+begin_src emacs-lisp (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)) #+end_src

If you are already familiar with =:hook=, you should note that there are quite a few syntactic differences between =:ghook= and =:hook=. Firstly, quoting the hooks and functions is required. Like =:general= uses the same syntax as ~general-def(ine-key)~ (unlike =:bind=), =: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-keyword][: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: #+begin_src emacs-lisp (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 ;; ... ))) #+end_src

Furthermore, =:ghook= will not automatically add =-hook= to specified hook symbols (i.e. you must specify =prog-mode-hook=; =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.

Lastly, =:hook= only takes one argument, whereas =:ghook= can take an arbitrary number of arguments (just like =:general=): #+begin_src emacs-lisp (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) #+end_src

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 ~general-add-hook~ arglist: #+begin_src emacs-lisp (use-package yasnippet :ghook ('(text-mode-hook prog-mode-hook) #'yas-minor-mode)) #+end_src

**** :gfhook Keyword =: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 =:ghook=. Unlike =:ghook=, =: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: #+begin_src emacs-lisp (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))) #+end_src

Like with =:ghook=, =:gfhook= still requires quoting, so you can use variables and function/macro calls to generate the function to add to the hook: #+begin_src emacs-lisp (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))) #+end_src

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 =:ghook=). =:gfhook= is more suited for setup functions. Expanding on the proced example: #+begin_src emacs-lisp (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) #+end_src

** 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:

#+begin_src emacs-lisp (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) #+end_src

Note that the order of the keys does matter unlike with the default ~key-chord-define~.

  • 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. =:prefix-command= and =:keymap=) and other keywords that will alter or ignore definitions (e.g. =:predicate= and =:ignore=).

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][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)

"Type" specifiers:

  • =:keymap= - For keymaps; if the keymap is not defined, will create an "autoloaded" keymap for =:package=
    • =:package= - The package to load (also global)
  • =:prefix-command= and/or =:prefix-map= - These are the same as =:def= and =:keymap= respectively 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=)
    • =:prefix-name= The 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: #+begin_src emacs-lisp ;; 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) #+end_src

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):

  • =:which-key= or =: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 =t= globally)
    • =: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:

  • =:predicate=

The default value for a keyword is =nil= unless otherwise specified.

** "Autoloaded" Keymaps 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: #+begin_src emacs-lisp (general-define-key "C-c p" '(:keymap projectile-command-map :package projectile)) #+end_src

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 [[https://github.com/justbur/emacs-which-key#automatic][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 =:non-normal-prefix= and/or =:global-prefix= are also specified).

The argument supplied to =:which-key= or =: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.

The =:which-key= keyword can be used with the =:major-modes= keyword (locally or globally) which can be compared to using ~which-key-add-major-mode-key-based-replacements~. =: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 =:keymaps=
    • the major mode name for that index
    • =nil= (or no item at the index) - don't match the major mode

=:wk-match-keys=, =:wk-match-binding=, and =: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: #+begin_src emacs-lisp (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) ...) #+end_src

** Evil Command Properties The =:properties=, =:repeat=, and =:jump= keywords can be used to add evil command properties: #+begin_src emacs-lisp (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)

#+end_src

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 [[https://github.com/noctuid/evil-guide#command-properties][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 ~general-extended-def-:~.

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. =state= and =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 ~general-define-key~.

Extended definition functions can optionally alter the definitions. Keywords that have this behavior must be added to either =general-rewrite-def-keywords= or =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 ~general-extended-def-:predicate~.

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-:~ 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.

Although ~general--get-keymap~ and ~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: #+begin_src emacs-lisp (general-define-key :predicate '(eobp) "" 'beginning-of-buffer) ;; call `general-extended-def-:predicate' with this as an edef argument: '(:def beginning-of-buffer)

(general-define-key "" '(beginning-of-buffer :predicate (eobp))) ;; call `general-extended-def-:predicate' with this as an edef argument: '(:def beginning-of-buffer :predicate (eobp)) #+end_src

For more information, see the docstring of =general-extended-def-keywords=.

  • 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. ~lispy-define-key~).

Alternate definers can be used by specifying the =:definer= keyword (globally or inside an extended definition): #+begin_src emacs-lisp (general-define-key :definer 'my "key" 'def "key2" '(def2 :definer 'my-other)) #+end_src

The user-created function should be named ~general--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= and =orig-def=. =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 ~kbd~ (since =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 =[remap kill-line]=).

See ~general-lispy-define-key~ for a basic example.

** Wrapping ~evil-define-minor-mode-key~ 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: #+begin_src emacs-lisp (general-define-key :definer 'minor-mode :states 'normal :keymaps 'org-src-mode "RET" 'org-edit-src-exit) #+end_src

If you are wondering why you might want to use ~evil-define-minor-mode-key~, see [[https://github.com/noctuid/evil-guide#why-dont-keys-defined-with-evil-define-key-work-immediately][here]].

** Lispy Integration/ Wrapping ~lispy-define-key~ To use ~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 ~lispy-define-key~.

** Worf Integration/ Wrapping ~worf-define-key~ To use ~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 ~worf-define-key~.

** Other Provided Definers To use ~lpy-define-key~ to make the definitions, =:definer 'lpy= can be specified.

  • FAQ ** 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 [[#mapping-under-non-prefix-keys][general-key-dispatch]].

Otherwise, you should unbind the non-prefix key. For example: #+begin_src emacs-lisp (general-define-key :keymaps 'normal :prefix "s" ;; prefix keys are prepended to other keys, so "" refers to the prefix itself "" nil "a" #'def ;; ... ) #+end_src

If you would rather force key definitions to always be made regardless of whether a subsequence of the key is already bound, [[#automatic-key-unbinding][general can automatically unbind keys when necessary to prevent this error]].

** Why don't some evil keybindings work (immediately)? This is a [[https://github.com/emacs-evil/evil/issues/301][known issue for evil]]. To work around this problem, you can use [[#wrapping-evil-define-minor-mode-key][:definer 'minor-mode]]. See [[https://github.com/noctuid/evil-guide#why-dont-keys-defined-with-evil-define-key-work-immediately][here]] for more information.

increase max depth

Local Variables:

toc-org-max-depth: 4

End: