spacemacs/core/core-keybindings.el

197 lines
8.7 KiB
EmacsLisp

;;; core-keybindings.el --- Spacemacs Core File -*- lexical-binding: t -*-
;;
;; Copyright (c) 2012-2022 Sylvain Benner & Contributors
;;
;; Author: Sylvain Benner <sylvain.benner@gmail.com>
;; URL: https://github.com/syl20bnr/spacemacs
;;
;; This file is not part of GNU Emacs.
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
(require 'core-funcs)
(defvar spacemacs/prefix-titles nil
"alist for mapping command prefixes to long names.")
(defvar spacemacs-default-map (make-sparse-keymap)
"Base keymap for all spacemacs leader key commands.")
(defun spacemacs/translate-C-i (_)
"If `dotspacemacs-distinguish-gui-tab' is non nil, the raw key
sequence does not include <tab> or <kp-tab>, and we are in the
gui, translate to [C-i]. Otherwise, [9] (TAB)."
(interactive)
(if (and (not (cl-position 'tab (this-single-command-raw-keys)))
(not (cl-position 'kp-tab (this-single-command-raw-keys)))
dotspacemacs-distinguish-gui-tab
(display-graphic-p))
[C-i] [?\C-i]))
(define-key key-translation-map [?\C-i] 'spacemacs/translate-C-i)
;; (defun spacemacs/translate-C-m (_)
;; "If `dotspacemacs-distinguish-gui-ret' is non nil, the raw key
;; sequence does not include <ret>, and we are in the gui, translate
;; to [C-m]. Otherwise, [9] (TAB)."
;; (interactive)
;; (if (and
;; (not (cl-position 'return (this-single-command-raw-keys)))
;; (not (cl-position 'kp-enter (this-single-command-raw-keys)))
;; dotspacemacs-distinguish-gui-ret
;; (display-graphic-p))
;; [C-m] [?\C-m]))
;; (define-key key-translation-map [?\C-m] 'spacemacs/translate-C-m)
(defun spacemacs/declare-prefix (prefix name &rest more)
"Declare a prefix PREFIX. PREFIX is a string describing a key
sequence. NAME is a string used as the prefix command."
(declare (indent defun))
(apply #'which-key-add-keymap-based-replacements spacemacs-default-map
prefix name more))
(defun spacemacs/declare-prefix-for-mode (mode prefix name &optional _)
"Declare a prefix PREFIX. MODE is the mode in which this prefix command should
be added. PREFIX is a string describing a key sequence. NAME is a symbol name
used as the prefix command."
(let* ((is-major-mode-prefix (string-prefix-p "m" prefix))
(is-minor-mode-prefix (not is-major-mode-prefix))
(smap (intern (format "spacemacs-%s-map" mode))))
(when (spacemacs//init-leader-mode-map mode smap is-minor-mode-prefix)
(which-key-add-keymap-based-replacements (symbol-value smap)
(if is-major-mode-prefix (substring prefix 1) prefix) name))))
(put 'spacemacs/declare-prefix-for-mode 'lisp-indent-function 'defun)
(defun spacemacs/set-leader-keys (key def &rest bindings)
"Add KEY and DEF as key bindings under
`dotspacemacs-leader-key' and `dotspacemacs-emacs-leader-key'.
KEY should be a string suitable for passing to `kbd', and it
should not include the leaders. DEF is most likely a quoted
command. See `define-key' for more information about the possible
choices for DEF. This function simply uses `define-key' to add
the bindings.
For convenience, this function will accept additional KEY DEF
pairs. For example,
\(spacemacs/set-leader-keys
\"a\" 'command1
\"C-c\" 'command2
\"bb\" 'command3\)"
(while key
(define-key spacemacs-default-map (kbd key) def)
(setq key (pop bindings) def (pop bindings))))
(put 'spacemacs/set-leader-keys 'lisp-indent-function 'defun)
(defalias 'evil-leader/set-key 'spacemacs/set-leader-keys)
(defun spacemacs//acceptable-leader-p (key)
"Return t if key is a string and non-empty."
(and (stringp key) (not (string= key ""))))
(defun spacemacs//init-leader-mode-map (mode map &optional minor)
"Check for MAP-prefix. If it doesn't exist yet, use `bind-map'
to create it and bind it to `dotspacemacs-major-mode-leader-key'
and `dotspacemacs-major-mode-emacs-leader-key'. If MODE is a
minor-mode, the third argument should be non nil."
(let* ((prefix (intern (format "%s-prefix" map)))
(leader1 (when (spacemacs//acceptable-leader-p
dotspacemacs-major-mode-leader-key)
dotspacemacs-major-mode-leader-key))
(leader2 (when (spacemacs//acceptable-leader-p
dotspacemacs-leader-key)
(concat dotspacemacs-leader-key " m")))
(emacs-leader1 (when (spacemacs//acceptable-leader-p
dotspacemacs-major-mode-emacs-leader-key)
dotspacemacs-major-mode-emacs-leader-key))
(emacs-leader2 (when (spacemacs//acceptable-leader-p
dotspacemacs-emacs-leader-key)
(concat dotspacemacs-emacs-leader-key " m")))
(leaders (delq nil (list leader1 leader2)))
(emacs-leaders (delq nil (list emacs-leader1 emacs-leader2))))
(or (boundp prefix)
(progn
(eval
`(bind-map ,map
:prefix-cmd ,prefix
,(if minor :minor-modes :major-modes) (,mode)
:keys ,emacs-leaders
:evil-keys ,leaders
:evil-states (normal motion visual evilified)))
(boundp prefix)))))
(defun spacemacs/inherit-leader-keys-from-parent-mode (mode &optional parent-mode)
"Make derived mode MODE inherit leader key bindings from PARENT-MODE.
If omitted, PARENT-MODE defaults to the parent mode of MODE.
Signal an error if MODE is not a derived mode (for example if the
package defining the mode has not yet been loaded)."
(unless parent-mode
(setq parent-mode (or (get mode 'derived-mode-parent)
(error "Mode %s has no parent" mode))))
(let ((map (intern (format "spacemacs-%s-map" mode)))
(parent-map (intern (format "spacemacs-%s-map" parent-mode))))
(when (and (spacemacs//init-leader-mode-map mode map)
(spacemacs//init-leader-mode-map parent-mode parent-map))
(set-keymap-parent (symbol-value map) (symbol-value parent-map)))))
(defun spacemacs/set-leader-keys-for-major-mode (mode key def &rest bindings)
"Add KEY and DEF as key bindings under
`dotspacemacs-major-mode-leader-key' and
`dotspacemacs-major-mode-emacs-leader-key' for the major-mode
MODE. MODE should be a quoted symbol corresponding to a valid
major mode. The rest of the arguments are treated exactly like
they are in `spacemacs/set-leader-keys'."
(let* ((map (intern (format "spacemacs-%s-map" mode))))
(when (spacemacs//init-leader-mode-map mode map)
(while key
(define-key (symbol-value map) (kbd key) def)
(setq key (pop bindings) def (pop bindings))))))
(put 'spacemacs/set-leader-keys-for-major-mode 'lisp-indent-function 'defun)
(defalias
'evil-leader/set-key-for-mode
'spacemacs/set-leader-keys-for-major-mode)
(defun spacemacs/set-leader-keys-for-minor-mode (mode key def &rest bindings)
"Add KEY and DEF as key bindings under
`dotspacemacs-major-mode-leader-key' and
`dotspacemacs-major-mode-emacs-leader-key' for the minor-mode
MODE. MODE should be a quoted symbol corresponding to a valid
minor mode. The rest of the arguments are treated exactly like
they are in `spacemacs/set-leader-keys'. If DEF is string, then
it is treated as a prefix not a command."
(let* ((map (intern (format "spacemacs-%s-map" mode))))
(when (spacemacs//init-leader-mode-map mode map t)
(let ((map-value (symbol-value map)))
(while key
(if (stringp def)
(which-key-add-keymap-based-replacements map-value key def)
(define-key map-value (kbd key) def))
(setq key (pop bindings) def (pop bindings)))))))
(put 'spacemacs/set-leader-keys-for-minor-mode 'lisp-indent-function 'defun)
(defun spacemacs/declare-prefix-for-minor-mode (mode prefix name)
"Declare a prefix PREFIX. MODE is the mode in which this prefix command should
be added. PREFIX is a string describing a key sequence. NAME is a symbol name
used as the prefix command.
Example:
\(spacemacs/declare-prefix-for-minor-mode 'tide-mode \"E\" \"errors\"\)"
(let* ((map (intern (format "spacemacs-%s-map" mode))))
(when (spacemacs//init-leader-mode-map mode map t)
(which-key-add-keymap-based-replacements (symbol-value map) prefix name))))
(provide 'core-keybindings)