Introduce general.el & rewrite map!

+ Now uses an overriding keymap for leader keys, so that it is always
  available, even outside of normal/visual states. In insert/emacs
  states, or in sessions where evil is absent, an alternative prefix is
  used for leader/localleader keys. See these variables:
  + doom-leader-prefix
  + doom-leader-alt-prefix
  + doom-localleader-prefix
  + doom-localleader-alt-prefix
+ Keybinds now support alternative prefixes through the new :alt-prefix
  property. This is useful for non-evil users and non-normal evil
  states. By default, this is M-SPC (leader) and M-SPC m (localleader).
+ Removed +evil-commands flag from config/default (moved to
  feature/evil/+commands.el).
+ config/default/+bindings.el has been split into
  config/default/+{evil,emacs}-bindings.el, which one is loaded depends
  on whether evil is present or not. The latter is blank, but will soon
  be populated with a keybinding scheme for non-evil users (perhaps
  inspired by #641).
+ The define-key! macro has been replaced; it is now an alias for
  general-def.
+ Added unmap! as an alias for general-unbind.
+ The following modifier key conventions are now enforced for
  consistency, across all OSes:
    alt/option      = meta
    windows/command = super
  It used to be
    alt/option      = alt
    windows/command = meta
  Many of the default keybinds have been updated to reflect this switch,
  but it is likely to affect personal meta/super keybinds!

The map! macro has also been rewritten to use general-define-key. Here
is what has been changed:

+ map! no longer works with characters, e.g. (map! ?x #'do-something) is
  no longer supported. Keys must be kbd-able strings like "C-c x" or
  vectors like [?C-c ?x].
+ The :map and :map* properties are now the same thing. If specified
  keymaps aren't defined when binding keys, it is automatically
  deferred.
+ The way you bind local keybinds has changed:

    ;; Don't do this
    (map! :l "a" #'func-a
          :l "b" #'func-b)
    ;; Do this
    (map! :map 'local "a" #'func-a
                      "b" #'func-b)

+ map! now supports the following new blocks:
  + (:if COND THEN-FORM ELSE-FORM...)
  + (:alt-prefix PREFIX KEYS...) -- this prefix will be used for
    non-normal evil states. Equivalent to :non-normal-prefix in general.
+ The way you declare a which-key label for a prefix key has changed:

    ;; before
    (map! :desc "label" :prefix "a" ...)
    ;; now
    (map! :prefix ("a" . "label") ...)

+ It used to be that map! supported binding a key to a key sequence,
  like so:

    (map! "a" [?x])  ; pressing a is like pressing x

  This functionality was removed *temporarily* while I figure out the
  implementation.

Addresses: #448, #814, #860
Mentioned in: #940
This commit is contained in:
Henrik Lissner 2018-12-22 03:30:04 -05:00
parent ce38a80cf8
commit 4daa9271a0
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
26 changed files with 1616 additions and 1501 deletions

View file

@ -289,11 +289,11 @@ savehist file."
;; `helpful' --- a better *help* buffer
(define-key! 'global
[remap describe-function] #'helpful-callable
[remap describe-command] #'helpful-command
[remap describe-variable] #'helpful-variable
[remap describe-key] #'helpful-key)
(let ((map (current-global-map)))
(define-key map [remap describe-function] #'helpful-callable)
(define-key map [remap describe-command] #'helpful-command)
(define-key map [remap describe-variable] #'helpful-variable)
(define-key map [remap describe-key] #'helpful-key))
(def-package! ws-butler

View file

@ -5,21 +5,21 @@
;; never loaded, then evil bindings set with `map!' will be ignored.
(defvar doom-leader-key "SPC"
"The leader prefix key, for global commands.")
"The leader prefix key for Evil users.")
(defvar doom-leader-alt-key "M-SPC"
"An alternative leader prefix key, used for Insert and Emacs states, and for
non-evil users.")
(defvar doom-localleader-key "SPC m"
"The localleader prefix key, for major-mode specific commands.")
(defvar doom-evil-state-alist
'((?n . normal)
(?v . visual)
(?i . insert)
(?e . emacs)
(?o . operator)
(?m . motion)
(?r . replace)
(?g . global))
"A list of cons cells that map a letter to a evil state symbol.")
(defvar doom-localleader-alt-key "M-SPC m"
"The localleader prefix key, for major-mode specific commands.")
(defvar doom-leader-map (make-sparse-keymap)
"An overriding keymap for <leader> keys.")
;;
(defvar doom-escape-hook nil
@ -45,6 +45,50 @@ If any hook returns non-nil, all hooks after it are ignored.")
;;
;; General
(require 'general)
;; Convenience aliases
(defalias 'define-key! #'general-def)
(defalias 'unmap! #'general-unbind)
;; <leader>
(define-prefix-command 'doom-leader 'doom-leader-map)
(define-key doom-leader-map [override-state] 'all)
(general-define-key :states '(normal visual motion replace) doom-leader-key 'doom-leader)
(general-define-key :states '(emacs insert) doom-leader-alt-key 'doom-leader)
(defun general-leader-define-key (_state _keymap key def orig-def _kargs)
(let (general-implicit-kbd)
(general-define-key
:keymaps 'doom-leader-map
:wk-full-keys nil
key orig-def)))
;; <localleader>
(defun general-localleader-define-key (state keymap key _def orig-def kargs)
(unless keymap
(signal 'wrong-type-argument (list 'keymapp keymap)))
(let (general-implicit-kbd)
(apply #'general-define-key
:major-modes t
:keymaps keymap
(append
;; :non-normal-prefix isn't respected when evil is absent, so this
;; is necessary:
(if (featurep 'evil)
(list :states '(normal visual motion)
:prefix doom-localleader-key
:non-normal-prefix doom-localleader-alt-key)
(list :prefix doom-localleader-alt-key))
(list key orig-def)
nil))))
;;
;; Packages
(def-package! which-key
:defer 1
:after-call pre-command-hook
@ -68,18 +112,16 @@ If any hook returns non-nil, all hooks after it are ignored.")
;;
(defun doom--keybind-register (key desc &optional modes)
"Register a description for KEY with `which-key' in MODES.
KEYS should be a string in kbd format.
DESC should be a string describing what KEY does.
MODES should be a list of major mode symbols."
(after! which-key
(if modes
(dolist (mode modes)
(which-key-add-major-mode-key-based-replacements mode key desc))
(which-key-add-key-based-replacements key desc))))
(defvar doom-evil-state-alist
'((?n . normal)
(?v . visual)
(?i . insert)
(?e . emacs)
(?o . operator)
(?m . motion)
(?r . replace)
(?g . global))
"A list of cons cells that map a letter to a evil state symbol.")
(defun doom--keyword-to-states (keyword)
"Convert a KEYWORD into a list of evil state symbols.
@ -95,29 +137,153 @@ For example, :nvi will map to (list 'normal 'visual 'insert). See
(put :after 'lisp-indent-function 'defun)
(put :desc 'lisp-indent-function 'defun)
(put :leader 'lisp-indent-function 'defun)
(put :local 'lisp-indent-function 'defun)
(put :localleader 'lisp-indent-function 'defun)
(put :map 'lisp-indent-function 'defun)
(put :map* 'lisp-indent-function 'defun)
(put :keymap 'lisp-indent-function 'defun)
(put :mode 'lisp-indent-function 'defun)
(put :prefix 'lisp-indent-function 'defun)
(put :textobj 'lisp-indent-function 'defun)
(put :alt-prefix 'lisp-indent-function 'defun)
(put :unless 'lisp-indent-function 'defun)
(put :if 'lisp-indent-function 'defun)
(put :when 'lisp-indent-function 'defun)
;; specials
(defvar doom--keymaps nil)
(defvar doom--prefix nil)
(defvar doom--defer nil)
(defvar doom--local nil)
(defvar doom--map-forms nil)
(defvar doom--map-batch-forms nil)
(defvar doom--map-state '(:dummy t))
(defvar doom--map-parent-state nil)
(defvar doom--map-evil-p nil)
(after! evil (setq doom--map-evil-p t))
(defun doom--map-process (rest)
(let (doom--map-state
doom--map-forms
desc)
(while rest
(let ((key (pop rest)))
(cond ((listp key)
(doom--map-nested nil key))
((keywordp key)
(pcase key
(:leader
(doom--map-set :definer '(quote leader)))
(:localleader
(doom--map-set :definer '(quote localleader)))
(:after
(doom--map-nested (list 'after! (pop rest)) rest)
(setq rest nil))
(:desc
(setq desc (pop rest)))
((or :map :map* :keymap)
(doom--map-set :keymaps `(quote ,(doom-enlist (pop rest)))))
(:mode
(push (cl-loop for m in (doom-enlist (pop rest))
collect (intern (concat (symbol-name m) "-map")))
rest)
(push :map rest))
((or :if :when :unless)
(doom--map-nested (list (intern (doom-keyword-name key)) (pop rest)) rest)
(setq rest nil))
(:prefix
(cl-destructuring-bind (prefix . desc) (doom-enlist (pop rest))
(doom--map-set :prefix prefix)
(when (stringp desc)
(setq rest (append (list :desc desc "" nil) rest)))))
(:alt-prefix
(cl-destructuring-bind (prefix . desc) (doom-enlist (pop rest))
(doom--map-set :non-normal-prefix prefix)
(when (stringp desc)
(setq rest (append (list :desc desc "" nil) rest)))))
(:textobj
(let* ((key (pop rest))
(inner (pop rest))
(outer (pop rest)))
(push `(map! (:map evil-inner-text-objects-map ,key ,inner)
(:map evil-outer-text-objects-map ,key ,outer))
doom--map-forms)))
(_
(condition-case e
(doom--map-def (pop rest) (pop rest) (doom--keyword-to-states key) desc)
(error
(error "Not a valid `map!' property: %s" key))))))
((doom--map-def key (pop rest) nil desc)))))
(doom--map-commit)
(macroexp-progn (nreverse (delq nil doom--map-forms)))))
(defun doom--map-append-keys (prop)
(let ((a (plist-get doom--map-parent-state prop))
(b (plist-get doom--map-state prop)))
(if (and a b)
`(general--concat t ,a ,b)
(or a b))))
(defun doom--map-nested (wrapper rest)
(doom--map-commit)
(let ((doom--map-parent-state (copy-seq (append doom--map-state doom--map-parent-state nil))))
(push (if wrapper
(append wrapper (list (doom--map-process rest)))
(doom--map-process rest))
doom--map-forms)))
(defun doom--map-set (prop &optional value inhibit-commit)
(unless (or inhibit-commit
(equal (plist-get doom--map-state prop) value))
(doom--map-commit))
(setq doom--map-state (plist-put doom--map-state prop value)))
(defun doom--map-def (key def &optional states desc)
(when (or (memq 'global states) (null states))
(setq states (delq 'global states))
(push 'nil states))
(dolist (state states)
(when desc
(setq def
(if (and (equal key "")
(null def))
`(quote (nil :which-key ,desc))
`(list ,@(plist-put (general--normalize-extended-def def)
:which-key desc)))))
(push key (alist-get state doom--map-batch-forms))
(push def (alist-get state doom--map-batch-forms))))
(defun doom--map-commit ()
(when doom--map-batch-forms
(cl-loop with attrs = (doom--map-state)
for (state . defs) in doom--map-batch-forms
if (or doom--map-evil-p (not state))
collect `(general-define-key ,@(if state `(:states ',state)) ,@attrs ,@(nreverse defs))
into forms
finally do (push (macroexp-progn forms) doom--map-forms))
(setq doom--map-batch-forms nil)))
(defun doom--map-state ()
(let ((plist
(append (list :prefix (doom--map-append-keys :prefix)
:non-normal-prefix (doom--map-append-keys :non-normal-prefix)
:definer (plist-get doom--map-parent-state :definer)
:keymaps
(append (plist-get doom--map-parent-state :keymaps)
(plist-get doom--map-state :keymaps)
nil))
doom--map-state
nil))
newplist)
(while plist
(let ((key (pop plist))
(val (pop plist)))
(when (and val (not (plist-member newplist key)))
(push val newplist)
(push key newplist))))
newplist))
;;
(defmacro map! (&rest rest)
"A nightmare of a key-binding macro that will use `evil-define-key*',
`define-key', `local-set-key' and `global-set-key' depending on context and
plist key flags (and whether evil is loaded or not). It was designed to make
binding multiple keys more concise, like in vim.
"A convenience macro for defining keybinds, powered by `general'.
If evil isn't loaded, it will ignore evil-specific bindings.
If evil isn't loaded, evil-specific bindings are ignored.
States
:n normal
@ -127,170 +293,41 @@ States
:o operator
:m motion
:r replace
:g global (will work without evil)
These can be combined (order doesn't matter), e.g. :nvi will apply to
normal, visual and insert mode. The state resets after the following
key=>def pair.
These can be combined in any order, e.g. :nvi will apply to normal, visual and
insert mode. The state resets after the following key=>def pair. If states are
omitted the keybind will be global (no emacs state; this is different from
evil's Emacs state and will work in the absence of `evil-mode').
If states are omitted the keybind will be global.
Properties
:leader [...] an alias for (:prefix doom-leader-key ...)
:localleader [...] bind to localleader; requires a keymap
:mode [MODE(s)] [...] inner keybinds are applied to major MODE(s)
:map [KEYMAP(s)] [...] inner keybinds are applied to KEYMAP(S)
:keymap [KEYMAP(s)] [...] same as :map
:prefix [PREFIX] [...] set keybind prefix for following keys
:alt-prefix [PREFIX] [...] use non-normal-prefix for following keys
:after [FEATURE] [...] apply keybinds when [FEATURE] loads
:textobj KEY INNER-FN OUTER-FN define a text object keybind pair
:if [CONDITION] [...]
:when [CONDITION] [...]
:unless [CONDITION] [...]
This can be customized with `doom-evil-state-alist'.
:textobj is a special state that takes a key and two commands, one for the
inner binding, another for the outer.
Flags
(:leader [...]) an alias for (:prefix doom-leader-key ...)
(:localleader [...]) an alias for (:prefix doom-localleader-key ...)
(:mode [MODE(s)] [...]) inner keybinds are applied to major MODE(s)
(:map [KEYMAP(s)] [...]) inner keybinds are applied to KEYMAP(S)
(:map* [KEYMAP(s)] [...]) same as :map, but deferred
(:prefix [PREFIX] [...]) assign prefix to all inner keybindings
(:after [FEATURE] [...]) apply keybinds when [FEATURE] loads
(:local [...]) make bindings buffer local; incompatible with keymaps!
Conditional keybinds
(:when [CONDITION] [...])
(:unless [CONDITION] [...])
Any of the above properties may be nested, so that they only apply to a
certain group of keybinds.
Example
(map! :map magit-mode-map
:m \"C-r\" 'do-something ; assign C-r in motion state
:nv \"q\" 'magit-mode-quit-window ; assign to 'q' in normal and visual states
:m \"C-r\" 'do-something ; C-r in motion state
:nv \"q\" 'magit-mode-quit-window ; q in normal+visual states
\"C-x C-r\" 'a-global-keybind
:g \"C-x C-r\" 'another-global-keybind ; same as above
(:when IS-MAC
:n \"M-s\" 'some-fn
:i \"M-o\" (lambda (interactive) (message \"Hi\"))))"
(let ((doom--keymaps doom--keymaps)
(doom--prefix doom--prefix)
(doom--defer doom--defer)
(doom--local doom--local)
key def states forms desc modes)
(while rest
(setq key (pop rest))
(cond
;; it's a sub expr
((listp key)
(push (macroexpand `(map! ,@key)) forms))
;; it's a flag
((keywordp key)
(cond ((eq key :leader)
(push 'doom-leader-key rest)
(setq key :prefix
desc "<leader>"))
((eq key :localleader)
(push 'doom-localleader-key rest)
(setq key :prefix
desc "<localleader>")))
(pcase key
(:when (push `(if ,(pop rest) ,(macroexpand `(map! ,@rest))) forms) (setq rest '()))
(:unless (push `(if (not ,(pop rest)) ,(macroexpand `(map! ,@rest))) forms) (setq rest '()))
(:after (push `(after! ,(pop rest) ,(macroexpand `(map! ,@rest))) forms) (setq rest '()))
(:desc (setq desc (pop rest)))
((or :map :map*)
(setq doom--keymaps (doom-enlist (pop rest))
doom--defer (eq key :map*)))
(:mode
(setq modes (doom-enlist (pop rest)))
(unless doom--keymaps
(setq doom--keymaps
(cl-loop for m in modes
collect (intern (format "%s-map" (symbol-name m)))))))
(:textobj
(let* ((key (pop rest))
(inner (pop rest))
(outer (pop rest)))
(push (macroexpand `(map! (:map evil-inner-text-objects-map ,key ,inner)
(:map evil-outer-text-objects-map ,key ,outer)))
forms)))
(:prefix
(let ((def (pop rest)))
(setq doom--prefix
`(vconcat ,doom--prefix
,(if (or (stringp def)
(and (symbolp def)
(stringp (symbol-value def))))
`(kbd ,def)
def)))
(when desc
(push `(doom--keybind-register ,(key-description (eval doom--prefix))
,desc ',modes)
forms)
(setq desc nil))))
(:local
(setq doom--local t))
(_ ; might be a state doom--prefix
(setq states (doom--keyword-to-states key)))))
;; It's a key-def pair
((or (stringp key)
(characterp key)
(vectorp key)
(symbolp key))
(unwind-protect
(catch 'skip
(when (symbolp key)
(setq key `(kbd ,key)))
(when (stringp key)
(setq key (kbd key)))
(when doom--prefix
(setq key (append doom--prefix (list key))))
(unless (> (length rest) 0)
(user-error "map! has no definition for %s key" key))
(setq def (pop rest))
(when (or (vectorp def)
(stringp def))
(setq def
`(lambda () (interactive)
(setq unread-command-events
(nconc (mapcar (lambda (ev) (cons t ev))
(listify-key-sequence
,(cond ((vectorp def) def)
((stringp def) (kbd def)))))
unread-command-events)))))
(when desc
(push `(doom--keybind-register ,(key-description (eval key))
,desc ',modes)
forms))
(cond ((and doom--local doom--keymaps)
(push `(lwarn 'doom-map :warning
"Can't local bind '%s' key to a keymap; skipped"
,key)
forms)
(throw 'skip 'local))
((and doom--keymaps states)
(dolist (keymap doom--keymaps)
(when (memq 'global states)
(push `(define-key ,keymap ,key ,def) forms))
(when (featurep 'evil)
(when-let* ((states (delq 'global states)))
(push `(,(if doom--defer #'evil-define-key #'evil-define-key*)
',states ,keymap ,key ,def)
forms)))))
(states
(dolist (state states)
(if (eq state 'global)
(push `(global-set-key ,key ,def) forms)
(when (featurep 'evil)
(push (if doom--local
`(evil-local-set-key ',state ,key ,def)
`(evil-define-key* ',state 'global ,key ,def))
forms)))))
(doom--keymaps
(dolist (keymap doom--keymaps)
(push `(define-key ,keymap ,key ,def) forms)))
(t
(push `(,(if doom--local #'local-set-key #'global-set-key)
,key ,def)
forms))))
(setq states '()
doom--local nil
desc nil)))
(t (user-error "Invalid key %s" key))))
`(progn ,@(nreverse forms))))
(doom--map-process rest))
(provide 'core-keybinds)
;;; core-keybinds.el ends here

View file

@ -369,34 +369,6 @@ For example:
,(doom--resolve-path-forms spec '--directory--))
(doom--resolve-path-forms spec)))
(defmacro define-key! (keymaps key def &rest rest)
"Like `define-key', but accepts a variable number of KEYMAPS and/or KEY+DEFs.
KEYMAPS can also be (or contain) 'global or 'local, to make this equivalent to
using `global-set-key' and `local-set-key'.
KEY is a key string or vector. It is *not* piped through `kbd'."
(declare (indent defun))
(or (cl-evenp (length rest))
(signal 'wrong-number-of-arguments (list 'evenp (length rest))))
(if (and (listp keymaps)
(not (eq (car-safe keymaps) 'quote)))
`(dolist (map (list ,@keymaps))
,(macroexpand `(define-key! map ,key ,def ,@rest)))
(when (eq (car-safe keymaps) 'quote)
(pcase (cadr keymaps)
(`global (setq keymaps '(current-global-map)))
(`local (setq keymaps '(current-local-map)))
(x (error "%s is not a valid keymap" x))))
`(let ((map ,keymaps))
(define-key map ,key ,def)
,@(let (forms)
(while rest
(let ((key (pop rest))
(def (pop rest)))
(push `(define-key map ,key ,def) forms)))
(nreverse forms)))))
(defmacro load! (filename &optional path noerror)
"Load a file relative to the current executing file (`load-file-name').

View file

@ -20,9 +20,13 @@
(when (featurep 'exec-path-from-shell)
`(exec-path-from-shell-copy-envs ,@vars)))
;; key conventions:
;; alt/option = meta
;; windows/command = super
(cond (IS-MAC
(setq mac-command-modifier 'meta
mac-option-modifier 'alt
(setq mac-command-modifier 'super
mac-option-modifier 'meta
;; sane trackpad/mouse scroll settings
mac-redisplay-dont-reset-vscroll t
mac-mouse-wheel-smooth-scroll nil
@ -60,11 +64,16 @@
(IS-LINUX
(setq x-gtk-use-system-tooltips nil ; native tooltips are ugly!
x-underline-at-descent-line t)) ; draw underline lower
x-underline-at-descent-line t ; draw underline lower
x-alt-keysym 'meta))
(IS-WINDOWS
(setq w32-get-true-file-attributes nil) ; fix file io slowdowns
))
(setq w32-get-true-file-attributes nil ; fix file io slowdowns
;; map window keys to super
w32-pass-lwindow-to-system nil
w32-lwindow-modifier 'super
w32-pass-rwindow-to-system nil
w32-rwindow-modifier 'super)))
(provide 'core-os)
;;; core-os.el ends here

View file

@ -41,6 +41,7 @@
(package! projectile)
;; core-keybinds.el
(package! general)
(package! which-key)
(package! hydra)

View file

@ -0,0 +1,266 @@
;; -*- no-byte-compile: t; -*-
;;; core/test/test-core-keybinds.el
(describe "core/keybinds"
(describe "map!"
:var (doom--map-evil-p doom-map-states)
(before-each
(setq doom--map-evil-p t
doom-map-states '((:n . normal)
(:v . visual)
(:i . insert)
(:e . emacs)
(:o . operator)
(:m . motion)
(:r . replace))))
(describe "Single keybinds"
(it "binds a global key"
(expect (macroexpand '(map! "C-." #'a))
:to-equal '(general-define-key "C-." #'a)))
(it "binds a key in one evil state"
(dolist (state doom-map-states)
(expect (macroexpand `(map! ,(car state) "C-." #'a))
:to-equal `(general-define-key :states ',(cdr state) "C-." #'a))))
(it "binds a key in multiple evil states"
(expect (cdr (macroexpand `(map! :nvi "C-." #'a)))
:to-have-same-items-as
'((general-define-key :states 'normal "C-." #'a)
(general-define-key :states 'visual "C-." #'a)
(general-define-key :states 'insert "C-." #'a))))
(it "binds evil keybinds together with global keybinds"
(expect (macroexpand '(map! :ng "C-." #'a))
:to-equal
'(progn
(general-define-key :states 'normal "C-." #'a)
(general-define-key "C-." #'a)))))
(describe "Multiple keybinds"
(it "binds global keys and preserves order"
(expect (macroexpand '(map! "C-." #'a
"C-," #'b
"C-/" #'c))
:to-equal '(general-define-key "C-." #'a
"C-," #'b
"C-/" #'c)))
(it "binds multiple keybinds in an evil state and preserve order"
(dolist (state doom-map-states)
(expect (macroexpand `(map! ,(car state) "a" #'a
,(car state) "b" #'b
,(car state) "c" #'c))
:to-equal
`(general-define-key :states ',(cdr state)
"a" #'a
"b" #'b
"c" #'c))))
(it "binds multiple keybinds in different evil states"
(expect (cdr (macroexpand `(map! :n "a" #'a
:n "b" #'b
:n "e" #'e
:v "c" #'c
:i "d" #'d)))
:to-have-same-items-as
`((general-define-key :states 'insert "d" #'d)
(general-define-key :states 'visual "c" #'c)
(general-define-key :states 'normal "a" #'a "b" #'b "e" #'e))))
(it "groups multi-state keybinds while preserving same-group key order"
(expect (cdr (macroexpand `(map! :n "a" #'a
:v "c" #'c
:n "b" #'b
:i "d" #'d
:n "e" #'e)))
:to-have-same-items-as
`((general-define-key :states 'insert "d" #'d)
(general-define-key :states 'visual "c" #'c)
(general-define-key :states 'normal "a" #'a "b" #'b "e" #'e))))
(it "binds multiple keybinds in multiple evil states"
(expect (cdr (macroexpand `(map! :nvi "a" #'a
:nvi "b" #'b
:nvi "c" #'c)))
:to-have-same-items-as
'((general-define-key :states 'normal "a" #'a "b" #'b "c" #'c)
(general-define-key :states 'visual "a" #'a "b" #'b "c" #'c)
(general-define-key :states 'insert "a" #'a "b" #'b "c" #'c)))))
(describe "Nested keybinds"
(it "binds global keys"
(expect (macroexpand '(map! "C-." #'a
("C-a" #'b)
("C-x" #'c)))
:to-equal '(progn
(general-define-key "C-." #'a)
(general-define-key "C-a" #'b)
(general-define-key "C-x" #'c))))
(it "binds nested evil keybinds"
(expect (macroexpand '(map! :n "C-." #'a
(:n "C-a" #'b)
(:n "C-x" #'c)))
:to-equal
'(progn
(general-define-key :states 'normal "C-." #'a)
(general-define-key :states 'normal "C-a" #'b)
(general-define-key :states 'normal "C-x" #'c))))
(it "binds global keybinds in between evil keybinds"
(expect (cdr (macroexpand-1 '(map! :n "a" #'a
"b" #'b
:i "c" #'c)))
:to-have-same-items-as
'((general-define-key :states 'insert "c" #'c)
(general-define-key "b" #'b)
(general-define-key :states 'normal "a" #'a)))))
;;
(describe "Properties"
(describe ":after"
(it "wraps `general-define-key' in a `after!' block"
(dolist (form '((map! :after helm "a" #'a "b" #'b)
(map! (:after helm "a" #'a "b" #'b))))
(expect (macroexpand-1 form)
:to-equal
'(after! helm (general-define-key "a" #'a "b" #'b))))
(expect (macroexpand-1 '(map! "a" #'a (:after helm "b" #'b "c" #'c)))
:to-equal
'(progn
(general-define-key "a" #'a)
(after! helm
(general-define-key "b" #'b "c" #'c))))
(expect (macroexpand-1 '(map! (:after helm "b" #'b "c" #'c) "a" #'a))
:to-equal
'(progn
(after! helm
(general-define-key "b" #'b "c" #'c))
(general-define-key "a" #'a))))
(it "nests `after!' blocks"
(expect (macroexpand-1 '(map! :after x "a" #'a
(:after y "b" #'b
(:after z "c" #'c))))
:to-equal
'(after! x (progn (general-define-key "a" #'a)
(after! y (progn (general-define-key "b" #'b)
(after! z (general-define-key "c" #'c))))))))
(it "nests `after!' blocks in other nested blocks"
(expect (macroexpand-1 '(map! :after x "a" #'a
(:when t "b" #'b
(:after z "c" #'c))))
:to-equal
'(after! x
(progn
(general-define-key "a" #'a)
(when t
(progn
(general-define-key "b" #'b)
(after! z (general-define-key "c" #'c)))))))))
(describe ":desc"
(it "add a :which-key property to a keybind's DEF"
(expect (macroexpand-1 '(map! :desc "A" "a" #'a))
:to-equal `(general-define-key "a" (list :def #'a :which-key "A")))))
(describe ":if/:when/:unless"
(it "wraps keys in a conditional block"
(dolist (prop '(:if :when :unless))
(let ((prop-fn (intern (doom-keyword-name prop))))
(expect (macroexpand-1 `(map! ,prop t "a" #'a "b" #'b))
:to-equal `(,prop-fn t (general-define-key "a" #'a "b" #'b)))
(expect (macroexpand-1 `(map! (,prop t "a" #'a "b" #'b)))
:to-equal `(,prop-fn t (general-define-key "a" #'a "b" #'b))))))
(it "nests conditional blocks"
(expect (macroexpand-1 '(map! (:when t "a" #'a (:when t "b" #'b))))
:to-equal '(when t
(progn (general-define-key "a" #'a)
(when t (general-define-key "b" #'b)))))))
(describe ":leader"
(it "uses leader definer"
(expect (macroexpand-1 '(map! :leader "a" #'a "b" #'b))
:to-equal '(general-define-key :definer 'leader "a" #'a "b" #'b)))
(it "it persists for nested keys"
(expect (cdr (macroexpand-1 '(map! :leader "a" #'a ("b" #'b))))
:to-equal '((general-define-key :definer 'leader "a" #'a)
(general-define-key :definer 'leader "b" #'b)))))
(describe ":localleader"
(it "uses localleader definer"
(expect (macroexpand-1 '(map! :localleader "a" #'a "b" #'b))
:to-equal '(general-define-key :definer 'localleader "a" #'a "b" #'b)))
(it "it persists for nested keys"
(expect (cdr (macroexpand-1 '(map! :localleader "a" #'a ("b" #'b))))
:to-equal '((general-define-key :definer 'localleader "a" #'a)
(general-define-key :definer 'localleader "b" #'b)))))
(describe ":map/:keymap"
(it "specifies a single keymap for keys"
(expect (macroexpand-1 '(map! :map emacs-lisp-mode-map "a" #'a))
:to-equal
'(general-define-key :keymaps '(emacs-lisp-mode-map) "a" #'a)))
(it "specifies multiple keymap for keys"
(expect (macroexpand-1 '(map! :map (lisp-mode-map emacs-lisp-mode-map) "a" #'a))
:to-equal
'(general-define-key :keymaps '(lisp-mode-map emacs-lisp-mode-map) "a" #'a))))
(describe ":mode"
(it "appends -map to MODE"
(expect (macroexpand-1 '(map! :mode emacs-lisp-mode "a" #'a))
:to-equal
'(general-define-key :keymaps '(emacs-lisp-mode-map) "a" #'a))))
(describe ":prefix"
(it "specifies a prefix for all keys"
(expect (macroexpand-1 '(map! :prefix "a" "x" #'x "y" #'y "z" #'z))
:to-equal
'(general-define-key :prefix "a" "x" #'x "y" #'y "z" #'z)))
(it "overwrites previous inline :prefix properties"
(expect (cdr (macroexpand-1 '(map! :prefix "a" "x" #'x "y" #'y :prefix "b" "z" #'z)))
:to-equal
'((general-define-key :prefix "a" "x" #'x "y" #'y)
(general-define-key :prefix "b" "z" #'z))))
(it "accumulates keys when nested"
(expect (cdr (macroexpand-1 '(map! (:prefix "a" "x" #'x (:prefix "b" "x" #'x)))))
:to-equal
`((general-define-key :prefix "a" "x" #'x)
(general-define-key :prefix (general--concat t "a" "b")
"x" #'x)))))
(describe ":alt-prefix"
(it "specifies a prefix for all keys"
(expect (macroexpand-1 '(map! :alt-prefix "a" "x" #'x "y" #'y "z" #'z))
:to-equal
'(general-define-key :non-normal-prefix "a" "x" #'x "y" #'y "z" #'z)))
(it "overwrites previous inline :alt-prefix properties"
(expect (cdr (macroexpand-1 '(map! :alt-prefix "a" "x" #'x "y" #'y :alt-prefix "b" "z" #'z)))
:to-equal
'((general-define-key :non-normal-prefix "a" "x" #'x "y" #'y)
(general-define-key :non-normal-prefix "b" "z" #'z))))
(it "accumulates keys when nested"
(expect (cdr (macroexpand-1 '(map! (:alt-prefix "a" "x" #'x (:alt-prefix "b" "x" #'x)))))
:to-equal
`((general-define-key :non-normal-prefix "a" "x" #'x)
(general-define-key :non-normal-prefix (general--concat t "a" "b")
"x" #'x)))))
(describe ":textobj"
(it "defines keys in evil-{inner,outer}-text-objects-map"
(expect (macroexpand-1 '(map! :textobj "a" #'inner #'outer))
:to-equal
'(map! (:map evil-inner-text-objects-map "a" #'inner)
(:map evil-outer-text-objects-map "a" #'outer))))))))

View file

@ -156,4 +156,4 @@
;; provides a Spacemacs-inspired keybinding scheme, a custom yasnippet
;; library, and additional ex commands for evil-mode. Use it as a
;; reference for your own modules.
(default +bindings +evil-commands))
(default +bindings))

View file

@ -122,19 +122,15 @@ playback.")
(add-hook 'circe-chat-mode-hook #'solaire-mode))
(map! :localleader
(:map circe-mode-map
:n "a" #'tracking-next-buffer
:n "j" #'circe-command-JOIN
:n "m" #'+irc/send-message
:n "p" #'circe-command-PART
:n "Q" #'+irc/quit
:n "R" #'circe-reconnect
(:when (featurep! :completion ivy)
:n "c" #'+irc/ivy-jump-to-channel))
(:map circe-channel-mode-map
:n "n" #'circe-command-NAMES)))
:map circe-mode-map
"a" #'tracking-next-buffer
"j" #'circe-command-JOIN
"m" #'+irc/send-message
"p" #'circe-command-PART
"Q" #'+irc/quit
"R" #'circe-reconnect
:when (featurep! :completion ivy)
"c" #'+irc/ivy-jump-to-channel))
(def-package! circe-color-nicks

View file

@ -34,11 +34,10 @@ be negative.")
;; Packages
(def-package! helm-mode
:defer 1
:defer t
:after-call pre-command-hook
:init
(define-key! 'global
[remap apropos] #'helm-apropos
(map! [remap apropos] #'helm-apropos
[remap find-library] #'helm-locate-library
[remap bookmark-jump] #'helm-bookmarks
[remap execute-extended-command] #'helm-M-x
@ -52,7 +51,8 @@ be negative.")
[remap projectile-recentf] #'helm-projectile-recentf
[remap projectile-switch-project] #'helm-projectile-switch-project
[remap projectile-switch-to-buffer] #'helm-projectile-switch-to-buffer
[remap recentf-open-files] #'helm-recentf)
[remap recentf-open-files] #'helm-recentf
[remap yank-pop] #'helm-show-kill-ring)
:config
(helm-mode +1)
;; helm is too heavy for `find-file-at-point'
@ -179,4 +179,5 @@ be negative.")
(after! swiper-helm
(setq swiper-helm-display-function
(lambda (buf &optional _resume) (pop-to-buffer buf)))
(global-set-key [remap swiper] #'swiper-helm)
(add-to-list 'swiper-font-lock-exclude #'+doom-dashboard-mode nil #'eq))

View file

@ -58,8 +58,7 @@ immediately runs it on the current candidate (ending the ivy session)."
(after! yasnippet
(add-to-list 'yas-prompt-functions #'+ivy-yas-prompt nil #'eq))
(define-key! 'global
[remap switch-to-buffer] #'ivy-switch-buffer
(map! [remap switch-to-buffer] #'ivy-switch-buffer
[remap persp-switch-to-buffer] #'+ivy/switch-workspace-buffer
[remap imenu-anywhere] #'ivy-imenu-anywhere)
@ -91,8 +90,7 @@ immediately runs it on the current candidate (ending the ivy session)."
(def-package! counsel
:commands counsel-describe-face
:init
(define-key! 'global
[remap apropos] #'counsel-apropos
(map! [remap apropos] #'counsel-apropos
[remap bookmark-jump] #'counsel-bookmark
[remap describe-face] #'counsel-faces
[remap describe-function] #'counsel-describe-function
@ -104,8 +102,9 @@ immediately runs it on the current candidate (ending the ivy session)."
[remap imenu] #'counsel-imenu
[remap recentf-open-files] #'counsel-recentf
[remap org-capture] #'counsel-org-capture
[remap swiper] #'counsel-grep-or-swiper)
[remap swiper] #'counsel-grep-or-swiper
[remap evil-ex-registers] #'counsel-evil-registers
[remap yank-pop] #'counsel-yank-pop)
:config
(set-popup-rule! "^\\*ivy-occur" :size 0.35 :ttl 0 :quit nil)
@ -160,8 +159,7 @@ immediately runs it on the current candidate (ending the ivy session)."
:commands (counsel-projectile-find-file counsel-projectile-find-dir counsel-projectile-switch-to-buffer
counsel-projectile-grep counsel-projectile-ag counsel-projectile-switch-project)
:init
(define-key! 'global
[remap projectile-find-file] #'+ivy/projectile-find-file
(map! [remap projectile-find-file] #'+ivy/projectile-find-file
[remap projectile-find-dir] #'counsel-projectile-find-dir
[remap projectile-switch-to-buffer] #'counsel-projectile-switch-to-buffer
[remap projectile-grep] #'counsel-projectile-grep
@ -232,22 +230,22 @@ immediately runs it on the current candidate (ending the ivy session)."
(map! :when (featurep! :feature evil +everywhere)
:after ivy
:map ivy-occur-mode-map
:n [mouse-1] #'ivy-occur-click
:n "<return>" #'ivy-occur-press-and-switch
:map (ivy-occur-mode-map ivy-occur-grep-mode-map)
:m "j" #'ivy-occur-next-line
:m "k" #'ivy-occur-previous-line
:m "h" #'evil-backward-char
:m "l" #'evil-forward-char
:m "g" nil
:m "gg" #'evil-goto-first-line
:map ivy-occur-mode-map
:n [mouse-1] #'ivy-occur-click
:n [return] #'ivy-occur-press-and-switch
:n "gf" #'ivy-occur-press
:n "ga" #'ivy-occur-read-action
:n "go" #'ivy-occur-dispatch
:n "gc" #'ivy-occur-toggle-calling
:n "gr" #'ivy-occur-revert-buffer
:n "q" #'quit-window
:map ivy-occur-grep-mode-map
:v "j" #'evil-next-line
:v "k" #'evil-previous-line
@ -258,17 +256,10 @@ immediately runs it on the current candidate (ending the ivy session)."
:n "i" #'ivy-wgrep-change-to-wgrep-mode
:n "gd" #'ivy-occur-delete-candidate
:n [mouse-1] #'ivy-occur-click
:n "<return>" #'ivy-occur-press-and-switch
:m "j" #'ivy-occur-next-line
:m "k" #'ivy-occur-previous-line
:m "h" #'evil-backward-char
:m "l" #'evil-forward-char
:m "g" nil
:m "gg" #'evil-goto-first-line
:n [return] #'ivy-occur-press-and-switch
:n "gf" #'ivy-occur-press
:n "gr" #'ivy-occur-revert-buffer
:n "ga" #'ivy-occur-read-action
:n "go" #'ivy-occur-dispatch
:n "gc" #'ivy-occur-toggle-calling
;; quit
:n "q" #'quit-window)

View file

@ -1,879 +0,0 @@
;;; config/default/+bindings.el -*- lexical-binding: t; -*-
;; This file defines a Spacemacs-esque keybinding scheme
;; expand-region's prompt can't tell what key contract-region is bound to, so we
;; tell it explicitly.
(setq expand-region-contract-fast-key "V")
;;
(map! [remap evil-jump-to-tag] #'projectile-find-tag
[remap find-tag] #'projectile-find-tag
;; Ensure there are no conflicts
:nmvo doom-leader-key nil
:nmvo doom-localleader-key nil
;; Swap RET/C-j in insert mode
:i [remap newline] #'newline-and-indent
:i "C-j" #'+default/newline
;; --- Global keybindings ---------------------------
;; Make M-x available everywhere
:gnvime "M-x" #'execute-extended-command
:gnvime "A-x" #'execute-extended-command
;; A little sandbox to run code in
:gnvime "M-;" #'eval-expression
;; Text-scaling
:n "M-+" (λ! (text-scale-set 0))
:n "M-=" #'text-scale-increase
:n "M--" #'text-scale-decrease
;; Simple window/frame navigation/manipulation
:n "C-`" #'+popup/toggle
:n "C-~" #'+popup/raise
:n "M-t" #'+workspace/new
:n "M-T" #'+workspace/display
:n "M-w" #'delete-window
:n "M-W" #'delete-frame
:n "C-M-f" #'toggle-frame-fullscreen
:n "M-n" #'evil-buffer-new
:n "M-N" #'make-frame
:n "M-1" (λ! (+workspace/switch-to 0))
:n "M-2" (λ! (+workspace/switch-to 1))
:n "M-3" (λ! (+workspace/switch-to 2))
:n "M-4" (λ! (+workspace/switch-to 3))
:n "M-5" (λ! (+workspace/switch-to 4))
:n "M-6" (λ! (+workspace/switch-to 5))
:n "M-7" (λ! (+workspace/switch-to 6))
:n "M-8" (λ! (+workspace/switch-to 7))
:n "M-9" (λ! (+workspace/switch-to 8))
:n "M-0" #'+workspace/switch-to-last
;; Other sensible, textmate-esque global bindings
:n "M-r" #'+eval/buffer
:n "M-R" #'+eval/region-and-replace
:n "M-b" #'+default/compile
:n "M-a" #'mark-whole-buffer
:n "M-c" #'evil-yank
:n "M-q" (if (daemonp) #'delete-frame #'evil-quit-all)
(:when (featurep! :completion helm)
:n "M-f" #'swiper-helm)
(:when (featurep! :completion ivy)
:n "M-f" #'swiper)
:n "M-s" #'save-buffer
:m "A-j" #'+default:multi-next-line
:m "A-k" #'+default:multi-previous-line
:nv "C-SPC" #'+evil/fold-toggle
:gnvimr "M-v" #'clipboard-yank
"C-x p" #'+popup/other
(:when IS-MAC
"M-`" #'other-frame)
;; --- Personal vim-esque bindings ------------------
:nv "K" #'+lookup/documentation
:n "zx" #'kill-this-buffer
:n "ZX" #'bury-buffer
:m "]a" #'evil-forward-arg
:m "[a" #'evil-backward-arg
:n "]b" #'next-buffer
:n "[b" #'previous-buffer
:m "]o" #'outline-next-visible-heading
:m "[o" #'outline-previous-visible-heading
:n "]w" #'+workspace/switch-right
:n "[w" #'+workspace/switch-left
:m "gt" #'+workspace/switch-right
:m "gT" #'+workspace/switch-left
:m "gd" #'+lookup/definition
:m "gD" #'+lookup/references
:n "gf" #'+lookup/file
:n "gQ" #'+format:region
:n "gp" #'+evil/reselect-paste
:v "gp" #'+evil/paste-preserve-register
:n "gr" #'+eval:region
:n "gR" #'+eval/buffer
:v "gR" #'+eval:replace-region
:nv "g-" #'+evil:narrow-buffer
:n "g=" #'widen
:v "@" #'+evil:apply-macro
:n "g@" #'+evil:apply-macro
;; repeat in visual mode (FIXME buggy)
:v "." #'evil-repeat
;; don't leave visual mode after shifting
:v "<" #'+evil/visual-dedent ; vnoremap < <gv
:v ">" #'+evil/visual-indent ; vnoremap > >gv
:nv "C-a" #'evil-numbers/inc-at-pt
:nv "C-S-a" #'evil-numbers/dec-at-pt
;; --- Plugin bindings ------------------------------
;; auto-yasnippet
:i [C-tab] #'aya-expand
:nv [C-tab] #'aya-create
;; company-mode (vim-like omnicompletion)
:i "C-@" #'+company/complete
:i "C-SPC" #'+company/complete
(:prefix "C-x"
:i "C-l" #'+company/whole-lines
:i "C-k" #'+company/dict-or-keywords
:i "C-f" #'company-files
:i "C-]" #'company-etags
:i "s" #'company-ispell
:i "C-s" #'company-yasnippet
:i "C-o" #'company-capf
:i "C-n" #'+company/dabbrev
:i "C-p" #'+company/dabbrev-code-previous)
(:after company
(:map company-active-map
;; Don't interfere with `evil-delete-backward-word' in insert mode
"C-w" nil
"C-n" #'company-select-next
"C-p" #'company-select-previous
"C-j" #'company-select-next
"C-k" #'company-select-previous
"C-h" #'company-show-doc-buffer
"C-u" #'company-previous-page
"C-d" #'company-next-page
"C-s" #'company-filter-candidates
(:when (featurep! :completion helm)
"C-S-s" #'helm-company)
(:when (featurep! :completion ivy)
"C-S-s" #'counsel-company)
"C-SPC" #'company-complete-common
[tab] #'company-complete-common-or-cycle
[backtab] #'company-select-previous)
;; Automatically applies to `company-filter-map'
(:map company-search-map
"C-n" #'company-select-next-or-abort
"C-p" #'company-select-previous-or-abort
"C-j" #'company-select-next-or-abort
"C-k" #'company-select-previous-or-abort
"C-s" (λ! (company-search-abort) (company-filter-candidates))
[escape] #'company-search-abort))
;; counsel
(:when (featurep! :completion ivy)
(:after counsel
(:map counsel-ag-map
[backtab] #'+ivy/wgrep-occur ; search/replace on results
"C-SPC" #'ivy-call-and-recenter ; preview
"M-RET" (+ivy-do-action! #'+ivy-git-grep-other-window-action))))
;; easymotion
:m "gs" #'+evil/easymotion ; lazy-load `evil-easymotion'
(:after evil-easymotion
:map evilem-map
"a" (evilem-create #'evil-forward-arg)
"A" (evilem-create #'evil-backward-arg)
"s" (evilem-create #'evil-snipe-repeat
:name 'evil-easymotion-snipe-forward
:pre-hook (save-excursion (call-interactively #'evil-snipe-s))
:bind ((evil-snipe-scope 'buffer)
(evil-snipe-enable-highlight)
(evil-snipe-enable-incremental-highlight)))
"S" (evilem-create #'evil-snipe-repeat
:name 'evil-easymotion-snipe-backward
:pre-hook (save-excursion (call-interactively #'evil-snipe-S))
:bind ((evil-snipe-scope 'buffer)
(evil-snipe-enable-highlight)
(evil-snipe-enable-incremental-highlight)))
"SPC" #'avy-goto-char-timer
"/" (evilem-create #'evil-ex-search-next
:pre-hook (save-excursion (call-interactively #'evil-ex-search-forward))
:bind ((evil-search-wrap)))
"?" (evilem-create #'evil-ex-search-previous
:pre-hook (save-excursion (call-interactively #'evil-ex-search-backward))
:bind ((evil-search-wrap))))
;; evil
(:after evil
:textobj "x" #'evil-inner-xml-attr #'evil-outer-xml-attr
:textobj "a" #'evil-inner-arg #'evil-outer-arg
:textobj "B" #'evil-textobj-anyblock-inner-block #'evil-textobj-anyblock-a-block
:textobj "i" #'evil-indent-plus-i-indent #'evil-indent-plus-a-indent
:textobj "k" #'evil-indent-plus-i-indent-up #'evil-indent-plus-a-indent-up
:textobj "j" #'evil-indent-plus-i-indent-up-down #'evil-indent-plus-a-indent-up-down
(:map evil-window-map ; prefix "C-w"
;; Navigation
"C-h" #'evil-window-left
"C-j" #'evil-window-down
"C-k" #'evil-window-up
"C-l" #'evil-window-right
"C-w" #'other-window
;; Swapping windows
"H" #'+evil/window-move-left
"J" #'+evil/window-move-down
"K" #'+evil/window-move-up
"L" #'+evil/window-move-right
"C-S-w" #'ace-swap-window
;; Window undo/redo
"u" #'winner-undo
"C-u" #'winner-undo
"C-r" #'winner-redo
"o" #'doom/window-enlargen
"O" #'doom/window-zoom
;; Delete window
"c" #'+workspace/close-window-or-workspace
"C-C" #'ace-delete-window))
;; evil-commentary
:n "gc" #'evil-commentary
;; evil-exchange
:n "gx" #'evil-exchange
;; evil-matchit
:nv [tab] #'+evil/matchit-or-toggle-fold
;; evil-magit
(:after evil-magit
:map (magit-status-mode-map magit-revision-mode-map)
:n "C-j" nil
:n "C-k" nil)
;; evil-mc
(:prefix "gz"
:nv "m" #'evil-mc-make-all-cursors
:nv "u" #'evil-mc-undo-all-cursors
:nv "z" #'+evil/mc-make-cursor-here
:nv "t" #'+evil/mc-toggle-cursors
:nv "n" #'evil-mc-make-and-goto-next-cursor
:nv "p" #'evil-mc-make-and-goto-prev-cursor
:nv "N" #'evil-mc-make-and-goto-last-cursor
:nv "P" #'evil-mc-make-and-goto-first-cursor
:nv "d" #'evil-mc-make-and-goto-next-match
:nv "D" #'evil-mc-make-and-goto-prev-match
:nv "j" #'evil-mc-make-cursor-move-next-line
:nv "k" #'evil-mc-make-cursor-move-prev-line)
(:after evil-mc
:map evil-mc-key-map
:nv "C-n" #'evil-mc-make-and-goto-next-cursor
:nv "C-N" #'evil-mc-make-and-goto-last-cursor
:nv "C-p" #'evil-mc-make-and-goto-prev-cursor
:nv "C-P" #'evil-mc-make-and-goto-first-cursor)
;; evil-multiedit
:v "R" #'evil-multiedit-match-all
:n "M-d" #'evil-multiedit-match-symbol-and-next
:n "M-D" #'evil-multiedit-match-symbol-and-prev
:v "M-d" #'evil-multiedit-match-and-next
:v "M-D" #'evil-multiedit-match-and-prev
:nv "C-M-d" #'evil-multiedit-restore
(:after evil-multiedit
(:map evil-multiedit-state-map
"M-d" #'evil-multiedit-match-and-next
"M-D" #'evil-multiedit-match-and-prev
"RET" #'evil-multiedit-toggle-or-restrict-region)
(:map (evil-multiedit-state-map evil-multiedit-insert-state-map)
"C-n" #'evil-multiedit-next
"C-p" #'evil-multiedit-prev))
;; evil-snipe
(:after evil-snipe
:map evil-snipe-parent-transient-map
;; switch to evil-easymotion/avy after a snipe
"C-;" (λ! (require 'evil-easymotion)
(call-interactively
(evilem-create #'evil-snipe-repeat
:bind ((evil-snipe-scope 'whole-buffer)
(evil-snipe-enable-highlight)
(evil-snipe-enable-incremental-highlight))))))
;; evil-surround
:v "S" #'evil-surround-region
:o "s" #'evil-surround-edit
:o "S" #'evil-Surround-edit
;; expand-region
:v "v" #'er/expand-region
:v "V" #'er/contract-region
;; flycheck
:m "]e" #'next-error
:m "[e" #'previous-error
(:after flycheck
:map flycheck-error-list-mode-map
:n "C-n" #'flycheck-error-list-next-error
:n "C-p" #'flycheck-error-list-previous-error
:n "j" #'flycheck-error-list-next-error
:n "k" #'flycheck-error-list-previous-error
:n "RET" #'flycheck-error-list-goto-error)
;; flyspell
:m "]S" #'flyspell-correct-word-generic
:m "[S" #'flyspell-correct-previous-word-generic
(:after flyspell
;; Press RET on misspelled words to correct them
(:map flyspell-mouse-map
"RET" #'flyspell-correct-word-generic
"<mouse-1>" #'flyspell-correct-word-generic))
;; git-gutter
:m "]d" #'git-gutter:next-hunk
:m "[d" #'git-gutter:previous-hunk
;; git-timemachine
(:after git-timemachine
(:map git-timemachine-mode-map
:n "C-p" #'git-timemachine-show-previous-revision
:n "C-n" #'git-timemachine-show-next-revision
:n "[[" #'git-timemachine-show-previous-revision
:n "]]" #'git-timemachine-show-next-revision
:n "q" #'git-timemachine-quit
:n "gb" #'git-timemachine-blame))
;; gist
(:after gist
:map gist-list-menu-mode-map
:n "RET" #'+gist/open-current
:n "b" #'gist-browse-current-url
:n "c" #'gist-add-buffer
:n "d" #'gist-kill-current
:n "f" #'gist-fork
:n "q" #'quit-window
:n "r" #'gist-list-reload
:n "s" #'gist-star
:n "S" #'gist-unstar
:n "y" #'gist-print-current-url)
;; helm
(:after helm
(:map helm-map
[left] #'left-char
[right] #'right-char
"C-S-n" #'helm-next-source
"C-S-p" #'helm-previous-source
"C-j" #'helm-next-line
"C-k" #'helm-previous-line
"C-S-j" #'helm-next-source
"C-S-k" #'helm-previous-source
"C-f" #'helm-next-page
"C-S-f" #'helm-previous-page
"C-u" #'helm-delete-minibuffer-contents
"C-w" #'backward-kill-word
"C-r" #'evil-paste-from-register ; Evil registers in helm! Glorious!
"C-s" #'helm-minibuffer-history
"C-b" #'backward-word
;; Swap TAB and C-z
[tab] #'helm-execute-persistent-action
"C-z" #'helm-select-action)
(:after helm-files
:map (helm-find-files-map helm-read-file-map)
[M-return] #'helm-ff-run-switch-other-window
"C-w" #'helm-find-files-up-one-level)
(:after helm-ag
:map helm-ag-map
[backtab] #'helm-ag-edit
[left] nil
[right] nil)
(:after helm-locate
:map helm-generic-files-map
[M-return] #'helm-ff-run-switch-other-window)
(:after helm-buffers
:map helm-buffer-map
[M-return] #'helm-buffer-switch-other-window)
(:after helm-regexp
:map helm-moccur-map
[M-return] #'helm-moccur-run-goto-line-ow)
(:after helm-grep
:map helm-grep-map
[M-return] #'helm-grep-run-other-window-action))
;; hl-todo
:m "]t" #'hl-todo-next
:m "[t" #'hl-todo-previous
;; ivy
(:after ivy
:map ivy-minibuffer-map
"C-SPC" #'ivy-call-and-recenter ; preview file
"C-l" #'ivy-alt-done
"M-z" #'undo
"M-v" #'yank
"C-v" #'yank)
;; neotree
(:after neotree
:map neotree-mode-map
:n "g" nil
:n [tab] #'neotree-quick-look
:n "RET" #'neotree-enter
:n [backspace] #'evil-window-prev
:n "c" #'neotree-create-node
:n "r" #'neotree-rename-node
:n "d" #'neotree-delete-node
:n "j" #'neotree-next-line
:n "k" #'neotree-previous-line
:n "n" #'neotree-next-line
:n "p" #'neotree-previous-line
:n "h" #'+neotree/collapse-or-up
:n "l" #'+neotree/expand-or-open
:n "J" #'neotree-select-next-sibling-node
:n "K" #'neotree-select-previous-sibling-node
:n "H" #'neotree-select-up-node
:n "L" #'neotree-select-down-node
:n "G" #'evil-goto-line
:n "gg" #'evil-goto-first-line
:n "v" #'neotree-enter-vertical-split
:n "s" #'neotree-enter-horizontal-split
:n "q" #'neotree-hide
:n "R" #'neotree-refresh)
;; realgud
(:after realgud
:map realgud:shortkey-mode-map
:n "j" #'evil-next-line
:n "k" #'evil-previous-line
:n "h" #'evil-backward-char
:n "l" #'evil-forward-char
:m "n" #'realgud:cmd-next
:m "b" #'realgud:cmd-break
:m "B" #'realgud:cmd-clear
:n "c" #'realgud:cmd-continue)
;; rotate-text
:n "!" #'rotate-text
;; swiper
(:after swiper
(:map swiper-map
[backtab] #'+ivy/wgrep-occur))
;; yasnippet
(:after yasnippet
(:map yas-keymap
"C-e" #'+snippets/goto-end-of-field
"C-a" #'+snippets/goto-start-of-field
"<M-right>" #'+snippets/goto-end-of-field
"<M-left>" #'+snippets/goto-start-of-field
"<M-backspace>" #'+snippets/delete-to-start-of-field
[backspace] #'+snippets/delete-backward-char
[delete] #'+snippets/delete-forward-char-or-field)
(:map yas-minor-mode-map
:ig [tab] yas-maybe-expand
:v [tab] #'yas-insert-snippet))
;; --- Major mode bindings --------------------------
(:after markdown-mode
(:map markdown-mode-map
;; fix conflicts with private bindings
"<backspace>" nil
"<M-left>" nil
"<M-right>" nil))
;; --- Built-in plugins -----------------------------
(:when (featurep! :completion company)
(:after comint
;; TAB auto-completion in term buffers
:map comint-mode-map [tab] #'company-complete))
(:map* (help-mode-map helpful-mode-map)
:n "Q" #'ivy-resume)
(:after vc-annotate
:map vc-annotate-mode-map
[remap quit-window] #'kill-this-buffer))
;; <leader>
;;
(map! :leader
:desc "Ex command" :nv ";" #'evil-ex
:desc "M-x" :nv ":" #'execute-extended-command
:desc "Pop up scratch buffer" :nv "x" #'doom/open-scratch-buffer
:desc "Org Capture" :nv "X" #'org-capture
;; Most commonly used
:desc "Find file in project" :n "SPC" #'projectile-find-file
:desc "Browse files" :n "." #'find-file
:desc "Toggle last popup" :n "~" #'+popup/toggle
(:when (featurep! :completion ivy)
:desc "Resume last search" :n "'" #'ivy-resume)
(:when (featurep! :completion helm)
:desc "Resume last search" :n "'" #'helm-resume)
:desc "Blink cursor line" :n "DEL" #'+nav-flash/blink-cursor
:desc "Jump to bookmark" :n "RET" #'bookmark-jump
(:when (featurep! :feature workspaces)
:desc "Switch workspace buffer" :n "," #'persp-switch-to-buffer
:desc "Switch buffer" :n "<" #'switch-to-buffer)
(:unless (featurep! :feature workspaces)
:desc "Switch buffer" :n "," #'switch-to-buffer)
;; C-u is used by evil
:desc "Universal argument" :n "u" #'universal-argument
:desc "window" :nm "w" evil-window-map
(:desc "previous..." :prefix "["
:desc "Text size" :nv "[" #'text-scale-decrease
:desc "Buffer" :nv "b" #'previous-buffer
:desc "Diff Hunk" :nv "d" #'git-gutter:previous-hunk
:desc "Todo" :nv "t" #'hl-todo-previous
:desc "Error" :nv "e" #'previous-error
:desc "Workspace" :nv "w" #'+workspace/switch-left
:desc "Spelling error" :nv "s" #'evil-prev-flyspell-error
:desc "Spelling correction" :n "S" #'flyspell-correct-previous-word-generic)
(:desc "next..." :prefix "]"
:desc "Text size" :nv "]" #'text-scale-increase
:desc "Buffer" :nv "b" #'next-buffer
:desc "Diff Hunk" :nv "d" #'git-gutter:next-hunk
:desc "Todo" :nv "t" #'hl-todo-next
:desc "Error" :nv "e" #'next-error
:desc "Workspace" :nv "w" #'+workspace/switch-right
:desc "Spelling error" :nv "s" #'evil-next-flyspell-error
:desc "Spelling correction" :n "S" #'flyspell-correct-word-generic)
(:desc "search" :prefix "/"
(:when (featurep! :completion ivy)
:desc "Buffer" :nv "b" #'swiper
:desc "Project" :nv "p" #'+ivy/project-search
:desc "Directory" :nv "d" #'+ivy/project-search-from-cwd)
(:when (featurep! :completion helm)
:desc "Buffer" :nv "b" #'swiper-helm
:desc "Project" :nv "p" #'+helm/project-search
:desc "Directory" :nv "d" #'+helm/project-search-from-cwd)
:desc "Symbols" :nv "i" #'imenu
:desc "Symbols across buffers" :nv "I" #'imenu-anywhere
:desc "Online providers" :nv "o" #'+lookup/online-select)
(:desc "workspace" :prefix [tab]
:desc "Display tab bar" :n [tab] #'+workspace/display
:desc "New workspace" :n "n" #'+workspace/new
:desc "Load workspace from file" :n "l" #'+workspace/load
:desc "Load a past session" :n "L" #'+workspace/load-session
:desc "Save workspace to file" :n "s" #'+workspace/save
:desc "Autosave current session" :n "S" #'+workspace/save-session
:desc "Switch workspace" :n "." #'+workspace/switch-to
:desc "Kill all buffers" :n "x" #'doom/kill-all-buffers
:desc "Delete session" :n "X" #'+workspace/kill-session
:desc "Delete this workspace" :n "d" #'+workspace/delete
:desc "Rename workspace" :n "r" #'+workspace/rename
:desc "Restore last session" :n "R" #'+workspace/load-last-session
:desc "Next workspace" :n "]" #'+workspace/switch-right
:desc "Previous workspace" :n "[" #'+workspace/switch-left
:desc "Switch to 1st workspace" :n "1" (λ! (+workspace/switch-to 0))
:desc "Switch to 2nd workspace" :n "2" (λ! (+workspace/switch-to 1))
:desc "Switch to 3rd workspace" :n "3" (λ! (+workspace/switch-to 2))
:desc "Switch to 4th workspace" :n "4" (λ! (+workspace/switch-to 3))
:desc "Switch to 5th workspace" :n "5" (λ! (+workspace/switch-to 4))
:desc "Switch to 6th workspace" :n "6" (λ! (+workspace/switch-to 5))
:desc "Switch to 7th workspace" :n "7" (λ! (+workspace/switch-to 6))
:desc "Switch to 8th workspace" :n "8" (λ! (+workspace/switch-to 7))
:desc "Switch to 9th workspace" :n "9" (λ! (+workspace/switch-to 8))
:desc "Switch to last workspace" :n "0" #'+workspace/switch-to-last)
(:desc "buffer" :prefix "b"
:desc "New empty buffer" :n "n" #'evil-buffer-new
(:when (featurep! :feature workspaces)
:desc "Switch workspace buffer" :n "b" #'persp-switch-to-buffer
:desc "Switch buffer" :n "B" #'switch-to-buffer)
(:unless (featurep! :feature workspaces)
:desc "Switch buffer" :n "b" #'switch-to-buffer)
:desc "Kill buffer" :n "k" #'kill-this-buffer
:desc "Kill other buffers" :n "o" #'doom/kill-other-buffers
:desc "Toggle narrowing" :nv "-" #'doom/clone-and-narrow-buffer
:desc "Next buffer" :n "n" #'next-buffer
:desc "Previous buffer" :n "p" #'previous-buffer
:desc "Next buffer" :n "]" #'next-buffer
:desc "Previous buffer" :n "[" #'previous-buffer
:desc "Save buffer" :n "s" #'save-buffer
:desc "Pop scratch buffer" :n "x" #'doom/open-scratch-buffer
:desc "Bury buffer" :n "z" #'bury-buffer
:desc "Sudo edit this file" :n "S" #'doom/sudo-this-file)
(:desc "code" :prefix "c"
:desc "List errors" :n "x" #'flycheck-list-errors
:desc "Evaluate buffer/region" :n "e" #'+eval/buffer
:v "e" #'+eval/region
:desc "Evaluate & replace region" :nv "E" #'+eval:replace-region
:desc "Format buffer/region" :n "f" #'+format/buffer
:v "f" #'+format/region
:desc "Build tasks" :nv "b" #'+eval/build
:desc "Jump to definition" :n "d" #'+lookup/definition
:desc "Jump to references" :n "D" #'+lookup/references
:desc "Open REPL" :n "r" #'+eval/open-repl
:v "r" #'+eval:repl)
(:desc "file" :prefix "f"
:desc "Find file" :n "." #'find-file
:desc "Sudo find file" :n ">" #'doom/sudo-find-file
:desc "Find file in project" :n "/" #'projectile-find-file
:desc "Find file from here" :n "?" #'counsel-file-jump
:desc "Find other file" :n "a" #'projectile-find-other-file
:desc "Open project editorconfig" :n "c" #'editorconfig-find-current-editorconfig
:desc "Find directory" :n "d" #'dired
:desc "Find file in emacs.d" :n "e" #'+default/find-in-emacsd
:desc "Browse emacs.d" :n "E" #'+default/browse-emacsd
:desc "Recent files" :n "r" #'recentf-open-files
:desc "Recent project files" :n "R" #'projectile-recentf
:desc "Yank filename" :n "y" #'+default/yank-buffer-filename
:desc "Find file in private config" :n "p" #'+default/find-in-config
:desc "Browse private config" :n "P" #'+default/browse-config
:desc "Delete this file" :n "X" #'doom/delete-this-file)
(:desc "git" :prefix "g"
:desc "Magit blame" :n "b" #'magit-blame-addition
:desc "Magit commit" :n "c" #'magit-commit
:desc "Magit clone" :n "C" #'+magit/clone
:desc "Magit dispatch" :n "d" #'magit-dispatch-popup
:desc "Magit find-file" :n "f" #'magit-find-file
:desc "Magit status" :n "g" #'magit-status
:desc "Magit file delete" :n "x" #'magit-file-delete
:desc "List gists" :n "G" #'+gist:list
:desc "MagitHub dispatch" :n "h" #'magithub-dispatch-popup
:desc "Initialize repo" :n "i" #'magit-init
:desc "Browse issues tracker" :n "I" #'+vc/git-browse-issues
:desc "Magit buffer log" :n "l" #'magit-log-buffer-file
:desc "List repositories" :n "L" #'magit-list-repositories
:desc "Browse remote" :n "o" #'+vc/git-browse
:desc "Magit push popup" :n "p" #'magit-push-popup
:desc "Magit pull popup" :n "P" #'magit-pull-popup
:desc "Git revert hunk" :n "r" #'git-gutter:revert-hunk
:desc "Git revert file" :n "R" #'vc-revert
:desc "Git stage hunk" :n "s" #'git-gutter:stage-hunk
:desc "Git stage file" :n "S" #'magit-stage-file
:desc "Git time machine" :n "t" #'git-timemachine-toggle
:desc "Git unstage file" :n "U" #'magit-unstage-file
:desc "Next hunk" :nv "]" #'git-gutter:next-hunk
:desc "Previous hunk" :nv "[" #'git-gutter:previous-hunk)
(:desc "help" :prefix "h"
:n "h" help-map
:desc "Apropos" :n "a" #'apropos
:desc "Open Bug Report" :n "b" #'doom/open-bug-report
:desc "Describe char" :n "c" #'describe-char
:desc "Describe DOOM module" :n "d" #'doom/describe-module
:desc "Open Doom manual" :n "D" #'doom/open-manual
:desc "Open vanilla sandbox" :n "E" #'doom/open-vanilla-sandbox
:desc "Describe function" :n "f" #'describe-function
:desc "Describe face" :n "F" #'describe-face
:desc "Info" :n "i" #'info-lookup-symbol
:desc "Describe key" :n "k" #'describe-key
:desc "Find documentation" :n "K" #'+lookup/documentation
:desc "Find library" :n "l" #'find-library
:desc "Command log" :n "L" #'global-command-log-mode
:desc "View *Messages*" :n "m" #'view-echo-area-messages
:desc "Describe mode" :n "M" #'describe-mode
:desc "Toggle profiler" :n "p" #'doom/toggle-profiler
:desc "Reload theme" :n "r" #'doom/reload-theme
:desc "Reload private config" :n "R" #'doom/reload
:desc "Describe DOOM setting" :n "s" #'doom/describe-setters
:desc "Describe variable" :n "v" #'describe-variable
:desc "Print Doom version" :n "V" #'doom/version
:desc "Man pages" :n "w" #'+default/man-or-woman
:desc "Describe at point" :n "." #'helpful-at-point
:desc "What face" :n "'" #'doom/what-face
:desc "What minor modes" :n ";" #'doom/describe-active-minor-mode)
(:desc "insert" :prefix "i"
(:when (featurep! :completion helm)
:desc "From kill-ring" :nv "y" #'helm-show-kill-ring)
(:when (featurep! :completion ivy)
:desc "From kill-ring" :nv "y" #'counsel-yank-pop
:desc "From evil registers" :nv "r" #'counsel-evil-registers)
:desc "From snippet" :nv "s" #'yas-insert-snippet)
(:desc "notes" :prefix "n"
(:when (featurep! :ui deft)
:desc "Deft" :n "d" #'deft)
:desc "Find file in notes" :n "n" #'+default/find-in-notes
:desc "Browse notes" :n "N" #'+default/browse-notes
:desc "Org capture" :n "x" #'org-capture)
(:desc "open" :prefix "o"
:desc "Org agenda" :n "a" #'org-agenda
:desc "Default browser" :n "b" #'browse-url-of-file
:desc "Debugger" :n "d" #'+debug/open
:desc "REPL" :n "r" #'+eval/open-repl
:v "r" #'+eval:repl
:desc "Dired" :n "-" #'dired-jump
(:when (featurep! :emacs dired +ranger)
:desc "Deer" :nm "j" #'deer
:desc "Ranger" :nm "J" #'ranger)
(:when (featurep! :ui neotree)
:desc "Project sidebar" :n "p" #'+neotree/open
:desc "Find file in project sidebar" :n "P" #'+neotree/find-this-file)
(:when (featurep! :ui treemacs)
:desc "Project sidebar" :n "p" #'+treemacs/toggle
:desc "Find file in project sidebar" :n "P" #'+treemacs/find-file)
:desc "Imenu sidebar" :nv "i" #'imenu-list-smart-toggle
:desc "Terminal" :n "t" #'+term/open
:desc "Terminal in popup" :n "T" #'+term/open-popup-in-project
:desc "Eshell" :n "e" #'+eshell/open
:desc "Eshell in popup" :n "E" #'+eshell/open-popup
(:when (featurep! :collab floobits)
:desc "floobits" :prefix "f"
:n "c" #'floobits-clear-highlights
:n "f" #'floobits-follow-user
:n "j" #'floobits-join-workspace
:n "l" #'floobits-leave-workspace
:n "R" #'floobits-share-dir-private
:n "s" #'floobits-summon
:n "t" #'floobits-follow-mode-toggle
:n "U" #'floobits-share-dir-public)
(:when (featurep! :tools macos)
:desc "Reveal in Finder" :n "o" #'+macos/reveal-in-finder
:desc "Reveal project in Finder" :n "O" #'+macos/reveal-project-in-finder
:desc "Send to Transmit" :n "u" #'+macos/send-to-transmit
:desc "Send project to Transmit" :n "U" #'+macos/send-project-to-transmit
:desc "Send to Launchbar" :n "l" #'+macos/send-to-launchbar
:desc "Send project to Launchbar" :n "L" #'+macos/send-project-to-launchbar)
(:when (featurep! :tools docker)
:desc "Docker" :n "D" #'docker))
(:desc "project" :prefix "p"
:desc "Browse project" :n "." #'+default/browse-project
:desc "Find file in project" :n "/" #'projectile-find-file
:desc "Run cmd in project root" :nv "!" #'projectile-run-shell-command-in-root
:desc "Compile project" :n "c" #'projectile-compile-project
:desc "Find other file" :n "o" #'projectile-find-other-file
:desc "Switch project" :n "p" #'projectile-switch-project
:desc "Recent project files" :n "r" #'projectile-recentf
:desc "List project tasks" :n "t" #'+ivy/tasks
:desc "Invalidate cache" :n "x" #'projectile-invalidate-cache)
(:desc "quit" :prefix "q"
:desc "Quit Emacs" :n "q" #'evil-quit-all
:desc "Save and quit" :n "Q" #'evil-save-and-quit
:desc "Quit (forget session)" :n "X" #'+workspace/kill-session-and-quit
:desc "Restart & restore Doom" :n "r" #'+workspace/restart-emacs-then-restore
:desc "Restart Doom" :n "R" #'restart-emacs)
(:when (featurep! :tools upload)
(:desc "remote" :prefix "r"
:desc "Upload local" :n "u" #'ssh-deploy-upload-handler
:desc "Upload local (force)" :n "U" #'ssh-deploy-upload-handler-forced
:desc "Download remote" :n "d" #'ssh-deploy-download-handler
:desc "Diff local & remote" :n "D" #'ssh-deploy-diff-handler
:desc "Browse remote files" :n "." #'ssh-deploy-browse-remote-handler
:desc "Detect remote changes" :n ">" #'ssh-deploy-remote-changes-handler))
(:when (featurep! :feature snippets)
(:desc "snippets" :prefix "s"
:desc "New snippet" :n "n" #'yas-new-snippet
:desc "Insert snippet" :nv "i" #'yas-insert-snippet
:desc "Jump to mode snippet" :n "/" #'yas-visit-snippet-file
:desc "Jump to snippet" :n "s" #'+snippets/find-file
:desc "Browse snippets" :n "S" #'+snippets/browse
:desc "Reload snippets" :n "r" #'yas-reload-all))
(:desc "toggle" :prefix "t"
:desc "Flyspell" :n "s" #'flyspell-mode
:desc "Flycheck" :n "f" #'flycheck-mode
:desc "Line numbers" :n "l" #'doom/toggle-line-numbers
:desc "Frame fullscreen" :n "F" #'toggle-frame-fullscreen
:desc "Indent guides" :n "i" #'highlight-indentation-mode
:desc "Indent guides (column)" :n "I" #'highlight-indentation-current-column-mode
:desc "Impatient mode" :n "h" #'+impatient-mode/toggle
:desc "Big mode" :n "b" #'doom-big-font-mode
:desc "Evil goggles" :n "g" #'evil-goggles-mode
:desc "org-tree-slide mode" :n "p" #'+org-present/start))
;;
;; Keybinding fixes
;; This section is dedicated to "fixing" certain keys so that they behave
;; sensibly (and consistently with similar contexts).
;; Make SPC u SPC u possible (#747)
(define-key universal-argument-map
(kbd (concat doom-leader-key " u")) #'universal-argument-more)
;; Fix MacOS shift+tab
(when IS-MAC
(define-key input-decode-map [S-iso-lefttab] [backtab]))
(defun +default|setup-input-decode-map ()
(define-key input-decode-map (kbd "TAB") [tab]))
(add-hook 'tty-setup-hook #'+default|setup-input-decode-map)
(after! tabulated-list
(define-key tabulated-list-mode-map "q" #'quit-window))
(when (featurep! :feature evil +everywhere)
(evil-define-key* 'insert 'global
;; I want C-a and C-e to be a little smarter. C-a will jump to indentation.
;; Pressing it again will send you to the true bol. Same goes for C-e,
;; except it will ignore comments and trailing whitespace before jumping to
;; eol.
"\C-a" #'doom/backward-to-bol-or-indent
"\C-e" #'doom/forward-to-last-non-comment-or-eol
"\C-u" #'doom/backward-kill-to-bol-and-indent
;; textmate-esque newline insertion
[M-return] #'evil-open-below
[S-M-return] #'evil-open-above
;; Emacsien motions for insert mode
"\C-b" #'backward-word
"\C-f" #'forward-word
;; textmate-esque deletion
[M-backspace] #'doom/backward-kill-to-bol-and-indent)
(define-key! evil-ex-completion-map
"\C-s" (if (featurep! :completion ivy)
#'counsel-minibuffer-history
#'helm-minibuffer-history)
"\C-a" #'move-beginning-of-line
"\C-b" #'backward-word
"\C-f" #'forward-word)
(after! man
(evil-define-key* 'normal Man-mode-map "q" #'kill-this-buffer))
(after! view
(define-key view-mode-map [escape] #'View-quit-all)))
;; Restore common editing keys (and ESC) in minibuffer
(defun +default|fix-minibuffer-in-map (map)
(define-key! map
"\C-s" (if (featurep! :completion ivy)
#'counsel-minibuffer-history
#'helm-minibuffer-history)
"\C-a" #'move-beginning-of-line
"\C-w" #'backward-kill-word
"\C-u" #'backward-kill-sentence
"\C-b" #'backward-word
"\C-f" #'forward-word
"\C-z" (λ! (ignore-errors (call-interactively #'undo))))
(when (featurep! :feature evil +everywhere)
(define-key! map
[escape] #'abort-recursive-edit
"\C-r" #'evil-paste-from-register
"\C-j" #'next-line
"\C-k" #'previous-line
(kbd "C-S-j") #'scroll-up-command
(kbd "C-S-k") #'scroll-down-command)))
(mapc #'+default|fix-minibuffer-in-map
(list minibuffer-local-map
minibuffer-local-ns-map
minibuffer-local-completion-map
minibuffer-local-must-match-map
minibuffer-local-isearch-map
read-expression-map))
(after! ivy (+default|fix-minibuffer-in-map ivy-minibuffer-map))
(after! man
(evil-define-key* 'normal Man-mode-map "q" #'kill-this-buffer))
;; Evil-collection fixes
(setq evil-collection-key-blacklist
(list "C-j" "C-k" "gd" "gf" "K" "[" "]" "gz"
doom-leader-key doom-localleader-key))

View file

@ -0,0 +1,3 @@
;;; config/default/+emacs-bindings.el -*- lexical-binding: t; -*-
;; TODO

View file

@ -0,0 +1,890 @@
;;; config/default/+bindings.el -*- lexical-binding: t; -*-
;; This file defines a Spacemacs-esque keybinding scheme
;; expand-region's prompt can't tell what key contract-region is bound to, so we
;; tell it explicitly.
(setq expand-region-contract-fast-key "V")
;;
;; Global keybindings
(map! (:map 'override
;; Make M-x more accessible
"s-x" 'execute-extended-command
"M-x" 'execute-extended-command
;; A little sandbox to run code in
"s-;" 'eval-expression)
[remap evil-jump-to-tag] #'projectile-find-tag
[remap find-tag] #'projectile-find-tag
:i [remap newline] #'newline-and-indent
:i "C-j" #'+default/newline
:n "s-+" (λ! (text-scale-set 0))
:n "s-=" #'text-scale-increase
:n "s--" #'text-scale-decrease
;; Simple window/frame navigation/manipulation
:n "s-w" #'delete-window
:n "s-W" #'delete-frame
:n "C-S-f" #'toggle-frame-fullscreen
:n "s-n" #'+default/new-buffer
:n "s-N" #'make-frame
;; Textmate-esque bindings
:n "s-R" #'+eval/region-and-replace
:n "s-a" #'mark-whole-buffer
:n "s-b" #'+default/compile
:n "s-c" #'evil-yank
:n "s-f" #'swiper
:n "s-q" (if (daemonp) #'delete-frame #'evil-quit-all)
;; expand-region
:v "v" #'er/expand-region
:v "C-v" #'er/contract-region
;; Restore OS undo, save, copy, & paste keys (without cua-mode, because it
;; imposes some other functionality and overhead we don't need)
:g "s-z" #'undo
:g "s-s" #'save-buffer
:g "s-c" #'yank
:g "s-v" #'copy-region-as-kill
:v "s-v" (if (featurep 'evil) #'evil-yank #'yank)
:nv "C-SPC" #'+evil/fold-toggle)
;;
;; Built-in plugins
(map! :after vc-annotate
:map vc-annotate-mode-map
[remap quit-window #'kill-this-buffer])
;;
;; Module keybinds
;;; :feature
(map! (:when (featurep! :feature debugger)
:after realgud
:map realgud:shortkey-mode-map
:n "j" #'evil-next-line
:n "k" #'evil-previous-line
:n "h" #'evil-backward-char
:n "l" #'evil-forward-char
:n "c" #'realgud:cmd-continue
:m "n" #'realgud:cmd-next
:m "b" #'realgud:cmd-break
:m "B" #'realgud:cmd-clear)
(:when (featurep! :feature eval)
:g "s-r" #'+eval/buffer
:nv "gr" #'+eval:region
:n "gR" #'+eval/buffer
:v "gR" #'+eval:replace-region)
(:when (featurep! :feature evil)
:m "]a" #'evil-forward-arg
:m "[a" #'evil-backward-arg
:m "]o" #'outline-next-visible-heading
:m "[o" #'outline-previous-visible-heading
:n "]b" #'next-buffer
:n "[b" #'previous-buffer
:n "zx" #'kill-this-buffer
:n "ZX" #'bury-buffer
:n "gp" #'+evil/reselect-paste
:nv "g=" #'widen
:nv "g-" #'+evil:narrow-buffer
:nv "g@" #'+evil:apply-macro
:nv "gc" #'evil-commentary
:nv "gx" #'evil-exchange
:nv "C-a" #'evil-numbers/inc-at-pt
:nv "C-S-a" #'evil-numbers/dec-at-pt
:nv [tab] #'+evil/matchit-or-toggle-fold
:v "gp" #'+evil/paste-preserve-register
:v "@" #'+evil:apply-macro
;; repeat in visual mode (FIXME buggy)
:v "." #'+evil:apply-macro
;; don't leave visual mode after shifting
:v "<" #'+evil/visual-dedent ; vnoremap < <gv
:v ">" #'+evil/visual-indent ; vnoremap > >gv
;; window management (prefix "C-w")
(:map evil-window-map
;; Navigation
"C-h" #'evil-window-left
"C-j" #'evil-window-down
"C-k" #'evil-window-up
"C-l" #'evil-window-right
"C-w" #'other-window
;; Swapping windows
"H" #'+evil/window-move-left
"J" #'+evil/window-move-down
"K" #'+evil/window-move-up
"L" #'+evil/window-move-right
"C-S-w" #'ace-swap-window
;; Window undo/redo
"u" #'winner-undo
"C-u" #'winner-undo
"C-r" #'winner-redo
"o" #'doom/window-enlargen
"O" #'doom/window-zoom
;; Delete window
"c" #'+workspace/close-window-or-workspace
"C-C" #'ace-delete-window)
;; Plugins
;; evil-easymotion
:m "gs" #'+evil/easymotion ; lazy-load `evil-easymotion'
(:after evil-easymotion
:map evilem-map
"a" (evilem-create #'evil-forward-arg)
"A" (evilem-create #'evil-backward-arg)
"s" (evilem-create #'evil-snipe-repeat
:name 'evil-easymotion-snipe-forward
:pre-hook (save-excursion (call-interactively #'evil-snipe-s))
:bind ((evil-snipe-scope 'buffer)
(evil-snipe-enable-highlight)
(evil-snipe-enable-incremental-highlight)))
"S" (evilem-create #'evil-snipe-repeat
:name 'evil-easymotion-snipe-backward
:pre-hook (save-excursion (call-interactively #'evil-snipe-S))
:bind ((evil-snipe-scope 'buffer)
(evil-snipe-enable-highlight)
(evil-snipe-enable-incremental-highlight)))
"SPC" #'avy-goto-char-timer
"/" (evilem-create #'evil-ex-search-next
:pre-hook (save-excursion (call-interactively #'evil-ex-search-forward))
:bind ((evil-search-wrap)))
"?" (evilem-create #'evil-ex-search-previous
:pre-hook (save-excursion (call-interactively #'evil-ex-search-backward))
:bind ((evil-search-wrap))))
;; text object plugins
:textobj "x" #'evil-inner-xml-attr #'evil-outer-xml-attr
:textobj "a" #'evil-inner-arg #'evil-outer-arg
:textobj "B" #'evil-textobj-anyblock-inner-block #'evil-textobj-anyblock-a-block
:textobj "i" #'evil-indent-plus-i-indent #'evil-indent-plus-a-indent
:textobj "k" #'evil-indent-plus-i-indent-up #'evil-indent-plus-a-indent-up
:textobj "j" #'evil-indent-plus-i-indent-up-down #'evil-indent-plus-a-indent-up-down
;; evil-snipe
(:after evil-snipe
:map evil-snipe-parent-transient-map
"C-;" (λ! (require 'evil-easymotion)
(call-interactively
(evilem-create #'evil-snipe-repeat
:bind ((evil-snipe-scope 'whole-buffer)
(evil-snipe-enable-highlight)
(evil-snipe-enable-incremental-highlight))))))
;; evil-surround
:v "S" #'evil-surround-region
:o "s" #'evil-surround-edit
:g "S" #'evil-Surround-edit)
(:when (featurep! :feature lookup)
:nv "K" #'+lookup/documentation
:nv "gd" #'+lookup/definition
:nv "gD" #'+lookup/references
:nv "gf" #'+lookup/file)
(:when (featurep! :feature snippets)
;; auto-yasnippet
:i [C-tab] #'aya-expand
:nv [C-tab] #'aya-create
;; yasnippet
(:after yasnippet
(:map yas-keymap
"C-e" #'+snippets/goto-end-of-field
"C-a" #'+snippets/goto-start-of-field
"<s-right>" #'+snippets/goto-end-of-field
"<s-left>" #'+snippets/goto-start-of-field
"<s-backspace>" #'+snippets/delete-to-start-of-field
[backspace] #'+snippets/delete-backward-char
[delete] #'+snippets/delete-forward-char-or-field)
:ie yas-minor-mode-map [tab] yas-maybe-expand
:v yas-minor-mode-map [tab] #'yas-insert-snippet))
(:when (featurep! :feature spellcheck)
:m "]S" #'flyspell-correct-word-generic
:m "[S" #'flyspell-correct-previous-word-generic
(:map flyspell-mouse-map
"RET" #'flyspell-correct-word-generic
[mouse-1] #'flyspell-correct-word-generic))
(:when (featurep! :completion syntax-checker)
:m "]e" #'next-error
:m "[e" #'previous-error
(:after flycheck
:map flycheck-error-list-mode-map
:n "C-n" #'flycheck-error-list-next-error
:n "C-p" #'flycheck-error-list-previous-error
:n "j" #'flycheck-error-list-next-error
:n "k" #'flycheck-error-list-previous-error
:n "RET" #'flycheck-error-list-goto-error))
(:when (featurep! :feature workspaces)
:n "s-t" #'+workspace/new
:n "s-T" #'+workspace/display
:n "s-1" (λ! (+workspace/switch-to 0))
:n "s-2" (λ! (+workspace/switch-to 1))
:n "s-3" (λ! (+workspace/switch-to 2))
:n "s-4" (λ! (+workspace/switch-to 3))
:n "s-5" (λ! (+workspace/switch-to 4))
:n "s-6" (λ! (+workspace/switch-to 5))
:n "s-7" (λ! (+workspace/switch-to 6))
:n "s-8" (λ! (+workspace/switch-to 7))
:n "s-9" (λ! (+workspace/switch-to 8))
:n "s-0" #'+workspace/switch-to-last
:n "gt" #'+workspace/switch-right
:n "gT" #'+workspace/switch-left
:n "]w" #'+workspace/switch-right
:n "[w" #'+workspace/switch-left))
;;; :completion
(map! (:when (featurep! :completion company)
:i "C-@" #'+company/complete
:i "C-SPC" #'+company/complete
(:prefix "C-x"
:i "C-l" #'+company/whole-lines
:i "C-k" #'+company/dict-or-keywords
:i "C-f" #'company-files
:i "C-]" #'company-etags
:i "s" #'company-ispell
:i "C-s" #'company-yasnippet
:i "C-o" #'company-capf
:i "C-n" #'+company/dabbrev
:i "C-p" #'+company/dabbrev-code-previous)
(:after company
(:map company-active-map
"C-w" nil ; don't interfere with `evil-delete-backward-word'
"C-n" #'company-select-next
"C-p" #'company-select-previous
"C-j" #'company-select-next
"C-k" #'company-select-previous
"C-h" #'company-show-doc-buffer
"C-u" #'company-previous-page
"C-d" #'company-next-page
"C-s" #'company-filter-candidates
"C-S-s" `(,(cond ((featurep! :completion helm) #'helm-company)
((featurep! :completion ivy) #'counsel-company)))
"C-SPC" #'company-complete-common
[tab] #'company-complete-common-or-cycle
[backtab] #'company-select-previous)
(:map company-search-map ; applies to `company-filter-map' too
"C-n" #'company-select-next-or-abort
"C-p" #'company-select-previous-or-abort
"C-j" #'company-select-next-or-abort
"C-k" #'company-select-previous-or-abort
"C-s" (λ! (company-search-abort) (company-filter-candidates))
[escape] #'company-search-abort)
;; TAB auto-completion in term buffers
:map comint-mode-map [tab] #'company-complete))
(:when (featurep! :completion ivy)
(:map (help-mode-map helpful-mode-map)
:n "Q" #'ivy-resume)
(:after ivy
:map ivy-minibuffer-map
"C-SPC" #'ivy-call-and-recenter ; preview file
"C-l" #'ivy-alt-done
"s-z" #'undo
"s-v" #'yank
"C-v" #'yank)
(:after counsel
:map counsel-ag-map
[backtab] #'+ivy/wgrep-occur ; search/replace on results
"C-SPC" #'ivy-call-and-recenter ; preview
"s-RET" (+ivy-do-action! #'+ivy-git-grep-other-window-action))
(:after swiper
:map swiper-map
[backtab] #'+ivy/wgrep-occur))
(:when (featurep! :completion helm)
(:after helm
(:map helm-map
[left] #'left-char
[right] #'right-char
"C-S-n" #'helm-next-source
"C-S-p" #'helm-previous-source
"C-j" #'helm-next-line
"C-k" #'helm-previous-line
"C-S-j" #'helm-next-source
"C-S-k" #'helm-previous-source
"C-f" #'helm-next-page
"C-S-f" #'helm-previous-page
"C-u" #'helm-delete-minibuffer-contents
"C-w" #'backward-kill-word
"C-r" #'evil-paste-from-register ; Evil registers in helm! Glorious!
"C-s" #'helm-minibuffer-history
"C-b" #'backward-word
;; Swap TAB and C-z
[tab] #'helm-execute-persistent-action
"C-z" #'helm-select-action)
(:after swiper-helm
:map swiper-helm-keymap [backtab] #'helm-ag-edit)
(:after helm-ag
:map helm-ag-map
"C--" #'+helm-do-ag-decrease-context
"C-=" #'+helm-do-ag-increase-context
[backtab] #'helm-ag-edit
[left] nil
[right] nil)
(:after helm-files
:map (helm-find-files-map helm-read-file-map)
[M-return] #'helm-ff-run-switch-other-window
"C-w" #'helm-find-files-up-one-level)
(:after helm-locate
:map helm-generic-files-map [M-return] #'helm-ff-run-switch-other-window)
(:after helm-buffers
:map helm-buffer-map [M-return] #'helm-buffer-switch-other-window)
(:after helm-regexp
:map helm-moccur-map [M-return] #'helm-moccur-run-goto-line-ow)
(:after helm-grep
:map helm-grep-map [M-return] #'helm-grep-run-other-window-action))))
;;; :ui
(map! (:when (featurep! :ui hl-todo)
:m "]t" #'hl-todo-next
:m "[t" #'hl-todo-previous)
(:when (featurep! :ui neotree)
:after neotree
:map neotree-mode-map
:n "g" nil
:n [tab] #'neotree-quick-look
:n "RET" #'neotree-enter
:n [backspace] #'evil-window-prev
:n "c" #'neotree-create-node
:n "r" #'neotree-rename-node
:n "d" #'neotree-delete-node
:n "j" #'neotree-next-line
:n "k" #'neotree-previous-line
:n "n" #'neotree-next-line
:n "p" #'neotree-previous-line
:n "h" #'+neotree/collapse-or-up
:n "l" #'+neotree/expand-or-open
:n "J" #'neotree-select-next-sibling-node
:n "K" #'neotree-select-previous-sibling-node
:n "H" #'neotree-select-up-node
:n "L" #'neotree-select-down-node
:n "G" #'evil-goto-line
:n "gg" #'evil-goto-first-line
:n "v" #'neotree-enter-vertical-split
:n "s" #'neotree-enter-horizontal-split
:n "q" #'neotree-hide
:n "R" #'neotree-refresh)
(:when (featurep! :ui popup)
:n "C-`" #'+popup/toggle
:n "C-~" #'+popup/raise
:g "C-x p" #'+popup/other)
(:when (featurep! :ui vc-gutter)
:m "]d" #'git-gutter:next-hunk
:m "[d" #'git-gutter:previous-hunk))
;;; :editor
(map! (:when (featurep! :editor format)
:n "gQ" #'+format:region)
(:when (featurep! :editor multiple-cursors)
;; evil-mc
(:prefix "gz"
:nv "d" #'evil-mc-make-and-goto-next-match
:nv "D" #'evil-mc-make-and-goto-prev-match
:nv "j" #'evil-mc-make-cursor-move-next-line
:nv "k" #'evil-mc-make-cursor-move-prev-line
:nv "m" #'evil-mc-make-all-cursors
:nv "n" #'evil-mc-make-and-goto-next-cursor
:nv "N" #'evil-mc-make-and-goto-last-cursor
:nv "p" #'evil-mc-make-and-goto-prev-cursor
:nv "P" #'evil-mc-make-and-goto-first-cursor
:nv "t" #'+evil/mc-toggle-cursors
:nv "u" #'evil-mc-undo-all-cursors
:nv "z" #'+evil/mc-make-cursor-here)
(:after evil-mc
:map evil-mc-key-map
:nv "C-n" #'evil-mc-make-and-goto-next-cursor
:nv "C-N" #'evil-mc-make-and-goto-last-cursor
:nv "C-p" #'evil-mc-make-and-goto-prev-cursor
:nv "C-P" #'evil-mc-make-and-goto-first-cursor)
;; evil-multiedit
:v "R" #'evil-multiedit-match-all
:n "M-d" #'evil-multiedit-match-symbol-and-next
:n "M-D" #'evil-multiedit-match-symbol-and-prev
:v "M-d" #'evil-multiedit-match-and-next
:v "M-D" #'evil-multiedit-match-and-prev
:nv "C-M-d" #'evil-multiedit-restore
(:after evil-multiedit
(:map evil-multiedit-state-map
"M-d" #'evil-multiedit-match-and-next
"M-D" #'evil-multiedit-match-and-prev
"RET" #'evil-multiedit-toggle-or-restrict-region)
(:map (evil-multiedit-state-map evil-multiedit-insert-state-map)
"C-n" #'evil-multiedit-next
"C-p" #'evil-multiedit-prev)))
(:when (featurep! :editor rotate-text)
:n "!" #'rotate-text))
;;; :emacs
(map! (:when (featurep! :emacs vc)
:after git-timemachine
:map git-timemachine-mode-map
:n "C-p" #'git-timemachine-show-previous-revision
:n "C-n" #'git-timemachine-show-next-revision
:n "[[" #'git-timemachine-show-previous-revision
:n "]]" #'git-timemachine-show-next-revision
:n "q" #'git-timemachine-quit
:n "gb" #'git-timemachine-blame))
;;; :tools
(map! (:when (featurep! :tools magit)
:after evil-magit
;; fix conflicts with private bindings
:map (magit-status-mode-map magit-revision-mode-map)
"C-j" nil
"C-k" nil)
(:when (featurep! :tools gist)
:after gist
:map gist-list-menu-mode-map
:n "RET" #'+gist/open-current
:n "b" #'gist-browse-current-url
:n "c" #'gist-add-buffer
:n "d" #'gist-kill-current
:n "f" #'gist-fork
:n "q" #'quit-window
:n "r" #'gist-list-reload
:n "s" #'gist-star
:n "S" #'gist-unstar
:n "y" #'gist-print-current-url))
;;; :lang
(map! (:when (featurep! :lang markdown)
:after markdown-mode
:map markdown-mode-map
;; fix conflicts with private bindings
"<backspace>" nil
"<s-left>" nil
"<s-right>" nil))
;;
;; <leader>
(map! :leader
:desc "Ex Command" ";" #'evil-ex
:desc "M-x" ":" #'execute-extended-command
:desc "Pop up scratch buffer" "x" #'doom/open-scratch-buffer
:desc "Org Capture" "X" #'org-capture
;; C-u is used by evil
:desc "Universal argument" "u" #'universal-argument
:desc "Window management" "w" #'evil-window-map
:desc "Toggle last popup" "~" #'+popup/toggle
:desc "Find file" "." #'find-file
:desc "Switch to buffer" "," #'switch-to-buffer
:desc "Resume last search" "'"
(cond ((featurep! :completion ivy) #'ivy-resume)
((featurep! :completion helm) #'helm-resume))
:desc "Find file in project" "SPC" #'projectile-find-file
:desc "Blink cursor line" "DEL" #'+nav-flash/blink-cursor
:desc "Jump to bookmark" "RET" #'bookmark-jump
;; Prefixed key groups
(:prefix ("/" . "search")
:desc "Jump to symbol across buffers" "I" #'imenu-anywhere
:desc "Search buffer" "b" #'swiper
:desc "Search current directory" "d" #'+ivy/project-search-from-cwd
:desc "Jump to symbol" "i" #'imenu
:desc "Jump to link" "l" #'ace-link
:desc "Look up online" "o" #'+lookup/online-select
:desc "Search project" "p" #'+ivy/project-search)
(:prefix ("]" . "next")
:desc "Increase text size" "[" #'text-scale-decrease
:desc "Next buffer" "b" #'previous-buffer
:desc "Next diff Hunk" "d" #'git-gutter:previous-hunk
:desc "Next todo" "t" #'hl-todo-previous
:desc "Next error" "e" #'previous-error
:desc "Next workspace" "w" #'+workspace/switch-left
:desc "Next spelling error" "s" #'evil-prev-flyspell-error
:desc "Next spelling correction" "S" #'flyspell-correct-previous-word-generic)
(:prefix ("[" . "previous")
:desc "Text size" "]" #'text-scale-increase
:desc "Buffer" "b" #'next-buffer
:desc "Diff Hunk" "d" #'git-gutter:next-hunk
:desc "Todo" "t" #'hl-todo-next
:desc "Error" "e" #'next-error
:desc "Workspace" "w" #'+workspace/switch-right
:desc "Spelling error" "s" #'evil-next-flyspell-error
:desc "Spelling correction" "S" #'flyspell-correct-word-generic)
(:when (featurep! :feature workspaces)
(:prefix ("TAB" . "workspace")
:desc "Display tab bar" "TAB" #'+workspace/display
:desc "New workspace" "n" #'+workspace/new
:desc "Load workspace from file" "l" #'+workspace/load
:desc "Load a past session" "L" #'+workspace/load-session
:desc "Save workspace to file" "s" #'+workspace/save
:desc "Autosave current session" "S" #'+workspace/save-session
:desc "Switch workspace" "." #'+workspace/switch-to
:desc "Delete session" "x" #'+workspace/kill-session
:desc "Delete this workspace" "d" #'+workspace/delete
:desc "Rename workspace" "r" #'+workspace/rename
:desc "Restore last session" "R" #'+workspace/load-last-session
:desc "Next workspace" "]" #'+workspace/switch-right
:desc "Previous workspace" "[" #'+workspace/switch-left
:desc "Switch to 1st workspace" "1" (λ! (+workspace/switch-to 0))
:desc "Switch to 2nd workspace" "2" (λ! (+workspace/switch-to 1))
:desc "Switch to 3rd workspace" "3" (λ! (+workspace/switch-to 2))
:desc "Switch to 4th workspace" "4" (λ! (+workspace/switch-to 3))
:desc "Switch to 5th workspace" "5" (λ! (+workspace/switch-to 4))
:desc "Switch to 6th workspace" "6" (λ! (+workspace/switch-to 5))
:desc "Switch to 7th workspace" "7" (λ! (+workspace/switch-to 6))
:desc "Switch to 8th workspace" "8" (λ! (+workspace/switch-to 7))
:desc "Switch to 9th workspace" "9" (λ! (+workspace/switch-to 8))
:desc "Switch to last workspace" "0" #'+workspace/switch-to-last))
(:prefix ("b" . "buffer")
:desc "Toggle narrowing" "-" #'doom/clone-and-narrow-buffer
:desc "New empty buffer" "N" #'evil-buffer-new
:desc "Sudo edit this file" "S" #'doom/sudo-this-file
:desc "Previous buffer" "[" #'previous-buffer
:desc "Next buffer" "]" #'next-buffer
:desc "Switch buffer" "b" #'switch-to-buffer
:desc "Kill buffer" "k" #'kill-this-buffer
:desc "Next buffer" "n" #'next-buffer
:desc "Kill other buffers" "o" #'doom/kill-other-buffers
:desc "Previous buffer" "p" #'previous-buffer
:desc "Save buffer" "s" #'save-buffer
:desc "Pop scratch buffer" "x" #'doom/open-scratch-buffer
:desc "Bury buffer" "z" #'bury-buffer)
(:prefix ("c" . "code")
:desc "Jump to references" "D" #'+lookup/references
:desc "Evaluate & replace region" "E" #'+eval:replace-region
:desc "Delete trailing newlines" "W" #'doom/delete-trailing-newlines
:desc "Build tasks" "b" #'+eval/build
:desc "Jump to definition" "d" #'+lookup/definition
:desc "Evaluate buffer/region" "e" #'+eval/buffer-or-region
:desc "Format buffer/region" "f" #'+format/region-or-buffer
:desc "Open REPL" "r" #'+eval/open-repl
:desc "Delete trailing whitespace" "w" #'delete-trailing-whitespace
:desc "List errors" "x" #'flycheck-list-errors)
(:prefix ("f" . "file")
:desc "Find file" "." #'find-file
:desc "Find file in project" "/" #'projectile-find-file
:desc "Sudo find file" ">" #'doom/sudo-find-file
:desc "Find file from here" "?" #'counsel-file-jump
:desc "Browse emacs.d" "E" #'+default/browse-emacsd
:desc "Browse private config" "P" #'+default/browse-config
:desc "Recent project files" "R" #'projectile-recentf
:desc "Delete this file" "X" #'doom/delete-this-file
:desc "Find other file" "a" #'projectile-find-other-file
:desc "Open project editorconfig" "c" #'editorconfig-find-current-editorconfig
:desc "Find directory" "d" #'dired
:desc "Find file in emacs.d" "e" #'+default/find-in-emacsd
:desc "Find file in private config" "p" #'+default/find-in-config
:desc "Recent files" "r" #'recentf-open-files
:desc "Save file" "s" #'save-buffer
:desc "Yank filename" "y" #'+default/yank-buffer-filename)
(:prefix ("g" . "git")
(:when (featurep! :ui vc-gutter)
:desc "Git revert hunk" "r" #'git-gutter:revert-hunk
:desc "Git stage hunk" "s" #'git-gutter:stage-hunk
:desc "Git time machine" "t" #'git-timemachine-toggle
:desc "Next hunk" "]" #'git-gutter:next-hunk
:desc "Previous hunk" "[" #'git-gutter:previous-hunk)
(:when (featurep! :emacs vc)
:desc "Browse issues tracker" "I" #'+vc/git-browse-issues
:desc "Browse remote" "o" #'+vc/git-browse
:desc "Git revert file" "R" #'vc-revert)
(:when (featurep! :tools magit)
:desc "Magit blame" "b" #'magit-blame-addition
:desc "Magit commit" "c" #'magit-commit
:desc "Magit clone" "C" #'+magit/clone
:desc "Magit dispatch" "d" #'magit-dispatch-popup
:desc "Magit find-file" "f" #'magit-find-file
:desc "Magit status" "g" #'magit-status
:desc "Magit file delete" "x" #'magit-file-delete
:desc "MagitHub dispatch" "h" #'magithub-dispatch-popup
:desc "Initialize repo" "i" #'magit-init
:desc "Magit buffer log" "l" #'magit-log-buffer-file
:desc "List repositories" "L" #'magit-list-repositories
:desc "Git stage file" "S" #'magit-stage-file
:desc "Git unstage file" "U" #'magit-unstage-file
:desc "Magit push popup" "p" #'magit-push-popup
:desc "Magit pull popup" "P" #'magit-pull-popup)
(:when (featurep! :tools gist)
:desc "List gists" "G" #'+gist:list))
(:prefix ("h" . "help")
:desc "What face" "'" #'doom/what-face
:desc "Describe at point" "." #'helpful-at-point
:desc "Describe active minor modes" ";" #'doom/describe-active-minor-mode
:desc "Open Doom manual" "D" #'doom/open-manual
:desc "Open vanilla sandbox" "E" #'doom/open-vanilla-sandbox
:desc "Describe face" "F" #'describe-face
:desc "Find documentation" "K" #'+lookup/documentation
:desc "Command log" "L" #'global-command-log-mode
:desc "Describe mode" "M" #'describe-mode
:desc "Reload private config" "R" #'doom/reload
:desc "Print Doom version" "V" #'doom/version
:desc "Apropos" "a" #'apropos
:desc "Open Bug Report" "b" #'doom/open-bug-report
:desc "Describe char" "c" #'describe-char
:desc "Describe DOOM module" "d" #'doom/describe-module
:desc "Describe function" "f" #'describe-function
:desc "Emacs help map" "h" help-map
:desc "Info" "i" #'info-lookup-symbol
:desc "Describe key" "k" #'describe-key
:desc "Find library" "l" #'find-library
:desc "View *Messages*" "m" #'view-echo-area-messages
:desc "Toggle profiler" "p" #'doom/toggle-profiler
:desc "Reload theme" "r" #'doom/reload-theme
:desc "Describe DOOM setting" "s" #'doom/describe-setters
:desc "Describe variable" "v" #'describe-variable
:desc "Man pages" "w" #'+default/man-or-woman)
(:prefix ("i" . "insert")
:desc "Insert from clipboard" "y" #'yank-pop
:desc "Insert from evil register" "r" #'evil-ex-registers
:desc "Insert snippet" "s" #'yas-insert-snippet)
(:prefix ("n" . "notes")
"d" (if (featurep! :ui deft) #'deft)
"n" '(+default/find-in-notes :wk "Find file in notes")
"N" '(+default/browse-notes :wk "Browse notes")
"x" '(org-capture :wk "Org capture"))
(:prefix ("o" . "open")
:desc "Org agenda" "a" #'org-agenda
:desc "Default browser" "b" #'browse-url-of-file
:desc "Debugger" "d" #'+debug/open
:desc "REPL" "r" #'+eval/open-repl
:desc "Dired" "-" #'dired-jump
(:when (featurep! :ui neotree)
:desc "Project sidebar" "p" #'+neotree/open
:desc "Find file in project sidebar" "P" #'+neotree/find-this-file)
(:when (featurep! :ui treemacs)
:desc "Project sidebar" "p" #'+treemacs/toggle
:desc "Find file in project sidebar" "P" #'+treemacs/find-file)
(:when (featurep! :emacs imenu)
:desc "Imenu sidebar" "i" #'imenu-list-smart-toggle)
(:when (featurep! :emacs term)
:desc "Terminal" "t" #'+term/open
:desc "Terminal in popup" "T" #'+term/open-popup-in-project)
(:when (featurep! :emacs eshell)
:desc "Eshell" "e" #'+eshell/open
:desc "Eshell in popup" "E" #'+eshell/open-popup)
(:when (featurep! :collab floobits)
(:prefix ("f" . "floobits")
"c" #'floobits-clear-highlights
"f" #'floobits-follow-user
"j" #'floobits-join-workspace
"l" #'floobits-leave-workspace
"R" #'floobits-share-dir-private
"s" #'floobits-summon
"t" #'floobits-follow-mode-toggle
"U" #'floobits-share-dir-public))
(:when (featurep! :tools macos)
:desc "Reveal in Finder" "o" #'+macos/reveal-in-finder
:desc "Reveal project in Finder" "O" #'+macos/reveal-project-in-finder
:desc "Send to Transmit" "u" #'+macos/send-to-transmit
:desc "Send project to Transmit" "U" #'+macos/send-project-to-transmit
:desc "Send to Launchbar" "l" #'+macos/send-to-launchbar
:desc "Send project to Launchbar" "L" #'+macos/send-project-to-launchbar)
(:when (featurep! :tools docker)
:desc "Docker" "D" #'docker))
;; (:prefix ("p" . "project")
;; "." '(+default/browse-project :wk "Browse project")
;; "/" '(projectile-find-file :wk "Find file in project")
;; "!" '(projectile-run-shell-command-in-root :wk "Run cmd in project root")
;; "c" '(projectile-compile-project :wk "Compile project")
;; "o" '(projectile-find-other-file :wk "Find other file")
;; "p" '(projectile-switch-project :wk "Switch project")
;; "r" '(projectile-recentf :wk "Recent project files")
;; "t" '(+ivy/tasks :wk "List project tasks")
;; "x" '(projectile-invalidate-cache :wk "Invalidate cache"))
;; (:prefix ("q" . "quit/restart")
;; "q" '(evil-quit-all :wk "Quit Emacs")
;; "Q" '(evil-save-and-quit :wk "Save and quit Emacs")
;; "X" '(+workspace/kill-session-and-quit :wk "Quit Emacs & forget session")
;; "r" '(+workspace/restart-emacs-then-restore :wk "Restart & restore Emacs")
;; "R" '(restart-emacs :wk "Restart Emacs"))
;; (:when (featurep! :tools upload)
;; (:prefix ("r" . "remote")
;; "u" '(ssh-deploy-upload-handler :wk "Upload local")
;; "U" '(ssh-deploy-upload-handler-forced :wk "Upload local (force)")
;; "d" '(ssh-deploy-download-handler :wk "Download remote")
;; "D" '(ssh-deploy-diff-handler :wk "Diff local & remote")
;; "." '(ssh-deploy-browse-remote-handler :wk "Browse remote files")
;; ">" '(ssh-deploy-remote-changes-handler :wk "Detect remote changes")))
;; (:when (featurep! :feature snippets)
;; (:prefix ("s" . "snippets")
;; "n" '(yas-new-snippet :wk "New snippet")
;; "i" '(yas-insert-snippet :wk "Insert snippet")
;; "/" '(yas-visit-snippet-file :wk "Jump to mode snippet")
;; "s" '(+snippets/find-file :wk "Jump to snippet")
;; "S" '(+snippets/browse :wk "Browse snippets")
;; "r" '(yas-reload-all :wk "Reload snippets")))
;; (:prefix ("t" . "toggle")
;; "s" '(flyspell-mode :wk "Flyspell")
;; "f" '(flycheck-mode :wk "Flycheck")
;; "l" '(doom/toggle-line-numbers :wk "Line numbers")
;; "F" '(toggle-frame-fullscreen :wk "Frame fullscreen")
;; "i" '(highlight-indentation-mode :wk "Indent guides")
;; "I" '(highlight-indentation-current-column-mode :wk "Indent guides (column)")
;; "h" '(+impatient-mode/toggle :wk "Impatient mode")
;; "b" '(doom-big-font-mode :wk "Big mode")
;; "g" '(evil-goggles-mode :wk "Evil goggles")
;; "p" '(+org-present/start :wk "org-tree-slide mode"))
)
;;
;; Keybinding fixes
;; This section is dedicated to "fixing" certain keys so that they behave
;; sensibly (and consistently with similar contexts).
;; Make SPC u SPC u [...] possible (#747)
(define-key universal-argument-map
(kbd (concat doom-leader-key " u")) #'universal-argument-more)
(when IS-MAC
;; Fix MacOS shift+tab
(define-key input-decode-map [S-iso-lefttab] [backtab])
;; Fix frame-switching on MacOS
(global-set-key "M-`" #'other-frame))
(defun +default|setup-input-decode-map ()
(define-key input-decode-map (kbd "TAB") [tab]))
(add-hook 'tty-setup-hook #'+default|setup-input-decode-map)
(after! tabulated-list
(define-key tabulated-list-mode-map "q" #'quit-window))
(when (featurep! :feature evil +everywhere)
;; Evil-collection fixes
(setq evil-collection-key-blacklist
(list "C-j" "C-k" "gd" "gf" "K" "[" "]" "gz"
doom-leader-key doom-localleader-key))
(define-key! 'insert
;; I want C-a and C-e to be a little smarter. C-a will jump to indentation.
;; Pressing it again will send you to the true bol. Same goes for C-e,
;; except it will ignore comments and trailing whitespace before jumping to
;; eol.
"C-a" #'doom/backward-to-bol-or-indent
"C-e" #'doom/forward-to-last-non-comment-or-eol
"C-u" #'doom/backward-kill-to-bol-and-indent
;; textmate-esque newline insertion
[s-return] #'evil-open-below
[S-s-return] #'evil-open-above
;; Emacsien motions for insert mode
"C-b" #'backward-word
"C-f" #'forward-word
;; textmate-esque deletion
[s-backspace] #'doom/backward-kill-to-bol-and-indent)
(define-key! evil-ex-completion-map
"C-s" (if (featurep! :completion ivy)
#'counsel-minibuffer-history
#'helm-minibuffer-history)
"C-a" #'move-beginning-of-line
"C-b" #'backward-word
"C-f" #'forward-word)
(define-key! view-mode-map :package 'view [escape] #'View-quit-all)
(define-key! 'normal Man-mode-map :package 'man "q" #'kill-this-buffer))
;; Restore common editing keys (and ESC) in minibuffer
(let ((maps `(minibuffer-local-map
minibuffer-local-ns-map
minibuffer-local-completion-map
minibuffer-local-must-match-map
minibuffer-local-isearch-map
read-expression-map
,@(if (featurep! :completion ivy) '(ivy-minibuffer-map)))))
(define-key! :keymaps maps
"C-s" (if (featurep! :completion ivy)
#'counsel-minibuffer-history
#'helm-minibuffer-history)
"C-a" #'move-beginning-of-line
"C-w" #'backward-kill-word
"C-u" #'backward-kill-sentence
"C-b" #'backward-word
"C-f" #'forward-word
"C-z" (λ! (ignore-errors (call-interactively #'undo))))
(when (featurep! :feature evil +everywhere)
(define-key! :keymaps maps
[escape] #'abort-recursive-edit
"C-r" #'evil-paste-from-register
"C-j" #'next-line
"C-k" #'previous-line
"C-S-j" #'scroll-up-command
"C-S-k" #'scroll-down-command)))
;;
;; Universal motion repeating keys
(defvar +default-repeat-forward-key ";")
(defvar +default-repeat-backward-key ",")
(defmacro do-repeat! (command next-func prev-func)
"Makes ; and , the universal repeat-keys in evil-mode. These keys can be
customized by changing `+default-repeat-forward-key' and
`+default-repeat-backward-key'."
(let ((fn-sym (intern (format "+default*repeat-%s" (doom-unquote command)))))
`(progn
(defun ,fn-sym (&rest _)
(define-key! 'motion
+default-repeat-forward-key #',next-func
+default-repeat-backward-key #',prev-func))
(advice-add #',command :before #',fn-sym))))
;; n/N
(do-repeat! evil-ex-search-next evil-ex-search-next evil-ex-search-previous)
(do-repeat! evil-ex-search-previous evil-ex-search-next evil-ex-search-previous)
(do-repeat! evil-ex-search-forward evil-ex-search-next evil-ex-search-previous)
(do-repeat! evil-ex-search-backward evil-ex-search-next evil-ex-search-previous)
;; f/F/t/T/s/S
(setq evil-snipe-repeat-keys nil
evil-snipe-override-evil-repeat-keys nil) ; causes problems with remapped ;
(do-repeat! evil-snipe-f evil-snipe-repeat evil-snipe-repeat-reverse)
(do-repeat! evil-snipe-F evil-snipe-repeat evil-snipe-repeat-reverse)
(do-repeat! evil-snipe-t evil-snipe-repeat evil-snipe-repeat-reverse)
(do-repeat! evil-snipe-T evil-snipe-repeat evil-snipe-repeat-reverse)
(do-repeat! evil-snipe-s evil-snipe-repeat evil-snipe-repeat-reverse)
(do-repeat! evil-snipe-S evil-snipe-repeat evil-snipe-repeat-reverse)
(do-repeat! evil-snipe-x evil-snipe-repeat evil-snipe-repeat-reverse)
(do-repeat! evil-snipe-X evil-snipe-repeat evil-snipe-repeat-reverse)
;; */#
(do-repeat! evil-visualstar/begin-search-forward
evil-ex-search-next evil-ex-search-previous)
(do-repeat! evil-visualstar/begin-search-backward
evil-ex-search-previous evil-ex-search-next)

View file

@ -1,137 +0,0 @@
;;; config/default/+evil-commands.el -*- lexical-binding: t; -*-
;;;###if (featurep! :feature evil)
(defalias 'ex! 'evil-ex-define-cmd)
(evil-define-command doom:cleanup-session (bang)
(interactive "<!>")
(doom/cleanup-session bang))
(evil-define-operator doom:open-scratch-buffer (bang)
(interactive "<!>")
(doom/open-scratch-buffer bang))
(evil-define-command doom:pwd (bang)
"Display the current working directory. If BANG, copy it to your clipboard."
(interactive "<!>")
(if (not bang)
(pwd)
(kill-new default-directory)
(message "Copied to clipboard")))
(evil-define-command doom:make (command &optional from-pwd)
"Run the current project Makefile's COMMAND. If FROM-PWD (bang), run the make
command from the current directory instead of the project root."
(interactive "<sh><!>")
(let ((default-directory (if from-pwd default-directory (doom-project-root t))))
(compile (or (if command (evil-ex-replace-special-filenames command))
(eval compile-command)))))
(evil-define-command doom:reverse-lines (beg end)
"Reverse lines between BEG and END."
(interactive "<r>")
(reverse-region beg end))
;;
;; Commands
;;; these are defined in feature/evil
;;(ex! "al[ign]" #'+evil:align)
;;(ex! "g[lobal]" #'+evil:global)
;;; Custom commands
;; Editing
(ex! "@" #'+evil:macro-on-all-lines) ; TODO Test me
(ex! "al[ign]" #'+evil:align)
(ex! "ral[ign]" #'+evil:align-right)
(ex! "enhtml" #'+web:encode-html-entities)
(ex! "dehtml" #'+web:decode-html-entities)
(ex! "mc" #'+evil:mc)
(ex! "iedit" #'evil-multiedit-ex-match)
(ex! "na[rrow]" #'+evil:narrow-buffer)
(ex! "retab" #'+evil:retab)
(ex! "rev[erse]" #'doom:reverse-lines)
;; External resources
;; TODO (ex! "db" #'doom:db)
;; TODO (ex! "dbu[se]" #'doom:db-select)
;; TODO (ex! "go[ogle]" #'doom:google-search)
(ex! "lo[okup]" #'+lookup:online)
(ex! "dash" #'+lookup:dash)
(ex! "http" #'httpd-start) ; start http server
(ex! "repl" #'+eval:repl) ; invoke or send to repl
;; TODO (ex! "rx" 'doom:regex) ; open re-builder
(ex! "sh[ell]" #'+eshell:run)
(ex! "t[mux]" #'+tmux:run) ; send to tmux
(ex! "tcd" #'+tmux:cd-here) ; cd to default-directory in tmux
(ex! "pad" #'doom:open-scratch-buffer)
;; GIT
(ex! "gist" #'+gist:send) ; send current buffer/region to gist
(ex! "gistl" #'+gist:list) ; list gists by user
(ex! "gbrowse" #'+vc:git-browse) ; show file in github/gitlab
(ex! "gissues" #'+vc/git-browse-issues) ; show github issues
(ex! "git" #'magit-status) ; open magit status window
(ex! "gstage" #'magit-stage)
(ex! "gunstage" #'magit-unstage)
(ex! "gblame" #'magit-blame)
(ex! "grevert" #'git-gutter:revert-hunk)
;; Dealing with buffers
(ex! "clean[up]" #'doom:cleanup-session)
(ex! "k[ill]" #'doom/kill-this-buffer)
(ex! "k[ill]all" #'+default:kill-all-buffers)
(ex! "k[ill]m" #'+default:kill-matching-buffers)
(ex! "k[ill]o" #'doom/kill-other-buffers)
(ex! "l[ast]" #'doom/popup-restore)
(ex! "m[sg]" #'view-echo-area-messages)
(ex! "pop[up]" #'doom/popup-this-buffer)
;; Project navigation
(ex! "a" #'projectile-find-other-file)
(ex! "cd" #'+default:cd)
(ex! "pwd" #'doom:pwd)
(cond ((featurep! :completion ivy)
(ex! "ag" #'+ivy:ag)
(ex! "agc[wd]" #'+ivy:ag-from-cwd)
(ex! "rg" #'+ivy:rg)
(ex! "rgc[wd]" #'+ivy:rg-from-cwd)
(ex! "pt" #'+ivy:pt)
(ex! "ptc[wd]" #'+ivy:pt-from-cwd)
(ex! "grep" #'+ivy:grep)
(ex! "grepc[wd]" #'+ivy:grep-from-cwd)
(ex! "sw[iper]" #'+ivy:swiper)
(ex! "todo" #'+ivy:todo))
((featurep! :completion helm)
(ex! "ag" #'+helm:ag)
(ex! "agc[wd]" #'+helm:ag-from-cwd)
(ex! "rg" #'+helm:rg)
(ex! "rgc[wd]" #'+helm:rg-from-cwd)
(ex! "pt" #'+helm:pt)
(ex! "ptc[wd]" #'+helm:pt-from-cwd)
(ex! "grep" #'+helm:grep)
(ex! "grepc[wd]" #'+helm:grep-from-cwd)
;; (ex! "todo" #'+helm:todo) TODO implement `+helm:todo'
))
;; Project tools
(ex! "mak[e]" #'doom:make)
(ex! "debug" #'+debug/run)
(ex! "er[rors]" #'flycheck-list-errors)
;; File operations
(ex! "cp" #'+evil:copy-this-file)
(ex! "mv" #'+evil:move-this-file)
(ex! "rm" #'+evil:delete-this-file)
;; Sessions/tabs
(ex! "sclear" #'+workspace/kill-session)
(ex! "sl[oad]" #'+workspace:load-session)
(ex! "ss[ave]" #'+workspace:save-session)
(ex! "tabc[lose]" #'+workspace:delete)
(ex! "tabclear" #'doom/kill-all-buffers)
(ex! "tabl[ast]" #'+workspace/switch-to-last)
(ex! "tabload" #'+workspace:load)
(ex! "tabn[ew]" #'+workspace:new)
(ex! "tabn[ext]" #'+workspace:switch-next)
(ex! "tabp[rev]" #'+workspace:switch-previous)
(ex! "tabr[ename]" #'+workspace:rename)
(ex! "tabs" #'+workspace/display)
(ex! "tabsave" #'+workspace:save)
;; Org-mode
(ex! "cap" #'org-capture)

View file

@ -73,3 +73,14 @@ If ARG (universal argument), runs `compile' from the current directory."
;;;###autoload
(defalias '+default/newline #'newline)
;;;###autoload
(defun +default/new-buffer ()
"TODO"
(interactive)
(if (featurep! 'evil)
(call-interactively #'evil-buffer-new)
(let ((buffer (generate-new-buffer "*new*")))
(set-window-buffer nil buffer)
(with-current-buffer buffer
(funcall (default-value 'major-mode))))))

View file

@ -1,11 +1,5 @@
;;; config/default/config.el -*- lexical-binding: t; -*-
(if (featurep! +bindings) (load! "+bindings"))
;;
;; Config
;; Don't store authinfo in plain text!
(setq auth-sources
(list (expand-file-name "authinfo.gpg" doom-etc-dir)
@ -86,47 +80,10 @@
(advice-add #'newline-and-indent :around #'doom*newline-indent-and-continue-comments))
(when (featurep 'evil)
(when (featurep! +evil-commands)
(load! "+evil-commands"))
;;
;; Doom's keybinding scheme
(when (featurep! +bindings)
(defvar +default-repeat-forward-key ";")
(defvar +default-repeat-backward-key ",")
(eval-when-compile
(defmacro do-repeat! (command next-func prev-func)
"Makes ; and , the universal repeat-keys in evil-mode. These keys can be
customized by changing `+default-repeat-forward-key' and
`+default-repeat-backward-key'."
(let ((fn-sym (intern (format "+evil*repeat-%s" (doom-unquote command)))))
`(progn
(defun ,fn-sym (&rest _)
(define-key! evil-motion-state-map
+default-repeat-forward-key #',next-func
+default-repeat-backward-key #',prev-func))
(advice-add #',command :before #',fn-sym)))))
;; n/N
(do-repeat! evil-ex-search-next evil-ex-search-next evil-ex-search-previous)
(do-repeat! evil-ex-search-previous evil-ex-search-next evil-ex-search-previous)
(do-repeat! evil-ex-search-forward evil-ex-search-next evil-ex-search-previous)
(do-repeat! evil-ex-search-backward evil-ex-search-next evil-ex-search-previous)
;; f/F/t/T/s/S
(setq evil-snipe-repeat-keys nil
evil-snipe-override-evil-repeat-keys nil) ; causes problems with remapped ;
(do-repeat! evil-snipe-f evil-snipe-repeat evil-snipe-repeat-reverse)
(do-repeat! evil-snipe-F evil-snipe-repeat evil-snipe-repeat-reverse)
(do-repeat! evil-snipe-t evil-snipe-repeat evil-snipe-repeat-reverse)
(do-repeat! evil-snipe-T evil-snipe-repeat evil-snipe-repeat-reverse)
(do-repeat! evil-snipe-s evil-snipe-repeat evil-snipe-repeat-reverse)
(do-repeat! evil-snipe-S evil-snipe-repeat evil-snipe-repeat-reverse)
(do-repeat! evil-snipe-x evil-snipe-repeat evil-snipe-repeat-reverse)
(do-repeat! evil-snipe-X evil-snipe-repeat evil-snipe-repeat-reverse)
;; */#
(do-repeat! evil-visualstar/begin-search-forward
evil-ex-search-next evil-ex-search-previous)
(do-repeat! evil-visualstar/begin-search-backward
evil-ex-search-previous evil-ex-search-next)))
(when (featurep! +bindings)
(if (featurep 'evil)
(load! "+evil-bindings")
(load! "+emacs-bindings")))

View file

@ -123,27 +123,24 @@ You should use `det-eshell-alias!' to change this.")
(defun +eshell|init-keymap ()
"Setup eshell keybindings. This must be done in a hook because eshell-mode
redefines its keys every time `eshell-mode' is enabled."
(when (featurep 'evil)
(evil-define-key* 'normal eshell-mode-map
[return] #'+eshell/goto-end-of-prompt
"c" #'+eshell/evil-change
"C" #'+eshell/evil-change-line
"d" #'+eshell/evil-delete
"D" #'+eshell/evil-delete-line)
(evil-define-key* 'insert eshell-mode-map
[tab] #'+eshell/pcomplete
"\C-j" #'evil-window-down
"\C-k" #'evil-window-up
"\C-h" #'evil-window-left
"\C-l" #'evil-window-right
"\C-d" #'+eshell/quit-or-delete-char
"\C-p" #'eshell-previous-input
"\C-n" #'eshell-next-input))
(define-key! eshell-mode-map
(kbd "C-s") #'+eshell/search-history
(kbd "C-c s") #'+eshell/split-below
(kbd "C-c v") #'+eshell/split-right
(kbd "C-c x") #'+eshell/kill-and-close
(map! :map eshell-mode-map
:n [return] #'+eshell/goto-end-of-prompt
:n "c" #'+eshell/evil-change
:n "C" #'+eshell/evil-change-line
:n "d" #'+eshell/evil-delete
:n "D" #'+eshell/evil-delete-line
:i [tab] #'+eshell/pcomplete
:i "C-j" #'evil-window-down
:i "C-k" #'evil-window-up
:i "C-h" #'evil-window-left
:i "C-l" #'evil-window-right
:i "C-d" #'+eshell/quit-or-delete-char
:i "C-p" #'eshell-previous-input
:i "C-n" #'eshell-next-input
"C-s" #'+eshell/search-history
"C-c s" #'+eshell/split-below
"C-c v" #'+eshell/split-right
"C-c x" #'+eshell/kill-and-close
[remap split-window-below] #'+eshell/split-below
[remap split-window-right] #'+eshell/split-right
[remap doom/backward-to-bol-or-indent] #'eshell-bol

View file

@ -17,6 +17,15 @@
(funcall runner beg end)
(quickrun-region beg end))))
;;;###autoload
(defun +eval/buffer-or-region ()
"Evaluate the whole buffer."
(interactive)
(call-interactively
(if (use-region-p)
#'+eval/region
#'+eval/buffer)))
;;;###autoload
(defun +eval/region-and-replace (beg end)
"Evaluation a region between BEG and END, and replace it with the result."

View file

@ -39,6 +39,8 @@ line with a linewise comment.")
evil-want-keybinding (not (featurep! +everywhere)))
:config
(load! "+commands")
(add-hook 'doom-post-init-hook #'evil-mode)
(evil-select-search-module 'evil-search-module 'evil-search)

View file

@ -62,7 +62,11 @@
(add-hook! 'emacs-lisp-mode-hook #'(rainbow-delimiters-mode highlight-quoted-mode))
;; Recenter window after following definition
(advice-add #'elisp-def :after #'doom*recenter))
(advice-add #'elisp-def :after #'doom*recenter)
(map! :localleader
:map emacs-lisp-mode-map
"e" #'macrostep-expand))
;;

View file

@ -24,7 +24,7 @@
:localleader :n ";" 'reftex-toc)
(add-hook! 'reftex-toc-mode-hook
(reftex-toc-rescan)
(map! :local
(map! :map 'local
:e "j" #'next-line
:e "k" #'previous-line
:e "q" #'kill-buffer-and-window

View file

@ -23,35 +23,31 @@
(add-hook 'markdown-mode-hook #'+markdown|set-fill-column-and-line-spacing)
(add-hook 'markdown-mode-hook #'auto-fill-mode)
(define-key! markdown-mode-map
[remap find-file-at-point] #'markdown-follow-thing-at-point
(kbd "M-*") #'markdown-insert-list-item
(kbd "M-b") #'markdown-insert-bold
(kbd "M-i") #'markdown-insert-italic
(kbd "M-`") #'+markdown/insert-del)
(when (featurep! :feature evil +everywhere)
(evil-define-key* 'motion markdown-mode-map
"gj" #'markdown-next-visible-heading
"gk" #'markdown-previous-visible-heading
;; TODO: Make context sensitive
"]h" #'markdown-next-visible-heading
"[h" #'markdown-previous-visible-heading
"[p" #'markdown-promote
"]p" #'markdown-demote
"[l" #'markdown-previous-link
"]l" #'markdown-next-link)
(evil-define-key* 'insert markdown-mode-map
(kbd "M--") #'markdown-insert-hr)
(evil-define-key* 'normal markdown-mode-map
(kbd "M-r") #'browse-url-of-file))
(map! :map markdown-mode-map
:localleader
:nv "o" #'markdown-open
:nv "b" #'markdown-preview
[remap find-file-at-point] #'markdown-follow-thing-at-point
"M-*" #'markdown-insert-list-item
"M-b" #'markdown-insert-bold
"M-i" #'markdown-insert-italic
"M-`" #'+markdown/insert-del
(:when (featurep! :feature evil +everywhere)
:m "gj" #'markdown-next-visible-heading
:m "gk" #'markdown-previous-visible-heading
;; TODO: Make context sensitive
:m "]h" #'markdown-next-visible-heading
:m "[h" #'markdown-previous-visible-heading
:m "[p" #'markdown-promote
:m "]p" #'markdown-demote
:m "[l" #'markdown-previous-link
:m "]l" #'markdown-next-link
:i "M--" #'markdown-insert-hr
:n "M-r" #'browse-url-of-file)
(:localleader
"o" #'markdown-open
"b" #'markdown-preview
(:prefix "i"
:nv "t" #'markdown-toc-generate-toc
:nv "i" #'markdown-insert-image
:nv "l" #'markdown-insert-link)))
"t" #'markdown-toc-generate-toc
"i" #'markdown-insert-image
"l" #'markdown-insert-link))))
(def-package! pandoc-mode
:when (featurep! +pandoc)

View file

@ -15,7 +15,7 @@
(apply orig-fn args)))
(advice-add #'restclient-http-do :around #'+rest*permit-self-signed-ssl)
(map! :mode restclient-mode
(map! :map restclient-mode-map
:n [return] #'+rest/dwim-at-point
:n "za" #'restclient-toggle-body-visibility
:n "zm" #'+rest/fold-all

View file

@ -37,6 +37,7 @@
(string-match-p "^\\*ein: .*" (buffer-name buf)))
(add-to-list 'doom-real-buffer-functions #'+ein-buffer-p nil #'eq)
;; Ace-link on notebook list buffers
(after! ein-notebooklist
(define-key ein:notebooklist-mode-map "o" #'+ein/ace-link-ein)))
(map! :map ein:notebook-mode-map
"M-s" #'ein:notebook-save-notebook-command
:map ein:notebooklist-mode-map
"o" #'+ein/ace-link-ein))

View file

@ -45,12 +45,7 @@ what features are available.")
#'hide-mode-line-mode)
;; properly kill leftover magit buffers on quit
(define-key magit-status-mode-map [remap magit-mode-bury-buffer] #'+magit/quit)
;; Don't replace the leader key
;; FIXME remove me when general.el is integrated
(when doom-leader-key
(define-key magit-diff-mode-map (kbd doom-leader-key) nil)))
(define-key magit-status-mode-map [remap magit-mode-bury-buffer] #'+magit/quit))
(def-package! magit-todos
@ -94,11 +89,7 @@ what features are available.")
(setq evil-magit-state 'normal
evil-magit-use-z-for-folds t)
:config
(define-key! magit-mode-map ; replaced by z1, z2, z3, etc
(kbd "M-1") nil
(kbd "M-2") nil
(kbd "M-3") nil
(kbd "M-4") nil)
(unmap! magit-mode-map "M-1" "M-2" "M-3" "M-4") ; replaced by z1, z2, z3, etc
(evil-define-key* '(normal visual) magit-mode-map
"zz" #'evil-scroll-line-to-center
"%" #'magit-gitflow-popup)
@ -108,6 +99,4 @@ what features are available.")
(cdr key)))
(evil-define-key* evil-magit-state git-rebase-mode-map
"gj" #'git-rebase-move-line-down
"gk" #'git-rebase-move-line-up))
(define-key! (magit-mode-map magit-blame-read-only-mode-map)
(kbd doom-leader-key) nil))
"gk" #'git-rebase-move-line-up)))

View file

@ -138,26 +138,25 @@ PLIST can have the following properties:
[remap backward-button] #'+doom-dashboard/backward-button
"n" #'forward-button
"p" #'backward-button
"\C-n" #'forward-button
"\C-p" #'backward-button
"C-n" #'forward-button
"C-p" #'backward-button
[down] #'forward-button
[up] #'backward-button
[tab] #'forward-button
[backtab] #'backward-button)
(when (featurep 'evil)
(evil-define-key* 'normal +doom-dashboard-mode-map
"j" #'forward-button
"k" #'backward-button
"n" #'forward-button
"p" #'backward-button
"\C-n" #'forward-button
"\C-p" #'backward-button
[down] #'forward-button
[up] #'backward-button
[tab] #'forward-button
[backtab] #'backward-button)
(define-key! +doom-dashboard-mode-map
(map! :when (featurep 'evil)
:map +doom-dashboard-mode-map
:n "j" #'forward-button
:n "k" #'backward-button
:n "n" #'forward-button
:n "p" #'backward-button
:n "C-n" #'forward-button
:n "C-p" #'backward-button
:n [down] #'forward-button
:n [up] #'backward-button
:n [tab] #'forward-button
:n [backtab] #'backward-button
[left-margin mouse-1] #'ignore
[remap evil-next-visual-line] #'forward-button
[remap evil-previous-visual-line] #'backward-button
@ -170,7 +169,7 @@ PLIST can have the following properties:
[remap evil-change] #'ignore
[remap evil-change-line] #'ignore
[remap evil-visual-char] #'ignore
[remap evil-visual-line] #'ignore))
[remap evil-visual-line] #'ignore)
;;