diff --git a/core/core-editor.el b/core/core-editor.el index 4def0117d..859013d97 100644 --- a/core/core-editor.el +++ b/core/core-editor.el @@ -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 diff --git a/core/core-keybinds.el b/core/core-keybinds.el index 9e0e1b927..1e4e05db9 100644 --- a/core/core-keybinds.el +++ b/core/core-keybinds.el @@ -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 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) + +;; +(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))) + +;; +(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,202 +137,197 @@ 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 - :v visual - :i insert - :e emacs - :o operator - :m motion - :r replace + :n normal + :v visual + :i insert + :e emacs + :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 - \"C-x C-r\" 'a-global-keybind + (map! :map magit-mode-map + :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 "")) - ((eq key :localleader) - (push 'doom-localleader-key rest) - (setq key :prefix - desc ""))) - (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)))) + (:when IS-MAC + :n \"M-s\" 'some-fn + :i \"M-o\" (lambda (interactive) (message \"Hi\"))))" + (doom--map-process rest)) (provide 'core-keybinds) ;;; core-keybinds.el ends here diff --git a/core/core-lib.el b/core/core-lib.el index 0a23b3146..88f89a3da 100644 --- a/core/core-lib.el +++ b/core/core-lib.el @@ -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'). diff --git a/core/core-os.el b/core/core-os.el index 2ada973de..ada518047 100644 --- a/core/core-os.el +++ b/core/core-os.el @@ -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 diff --git a/core/packages.el b/core/packages.el index 344b0dbec..72a218963 100644 --- a/core/packages.el +++ b/core/packages.el @@ -41,6 +41,7 @@ (package! projectile) ;; core-keybinds.el +(package! general) (package! which-key) (package! hydra) diff --git a/core/test/test-core-keybinds.el b/core/test/test-core-keybinds.el new file mode 100644 index 000000000..a3be4dc20 --- /dev/null +++ b/core/test/test-core-keybinds.el @@ -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)))))))) diff --git a/init.example.el b/init.example.el index f6baad4a3..b32fa440a 100644 --- a/init.example.el +++ b/init.example.el @@ -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)) diff --git a/modules/app/irc/config.el b/modules/app/irc/config.el index f76dbeec2..3aec7eb78 100644 --- a/modules/app/irc/config.el +++ b/modules/app/irc/config.el @@ -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 diff --git a/modules/completion/helm/config.el b/modules/completion/helm/config.el index afca72d1a..32441b5cc 100644 --- a/modules/completion/helm/config.el +++ b/modules/completion/helm/config.el @@ -34,25 +34,25 @@ be negative.") ;; Packages (def-package! helm-mode - :defer 1 + :defer t :after-call pre-command-hook :init - (define-key! 'global - [remap apropos] #'helm-apropos - [remap find-library] #'helm-locate-library - [remap bookmark-jump] #'helm-bookmarks - [remap execute-extended-command] #'helm-M-x - [remap find-file] #'helm-find-files - [remap imenu-anywhere] #'helm-imenu-anywhere - [remap imenu] #'helm-semantic-or-imenu - [remap noop-show-kill-ring] #'helm-show-kill-ring - [remap persp-switch-to-buffer] #'+helm/workspace-mini - [remap switch-to-buffer] #'helm-buffers-list - [remap projectile-find-file] #'+helm/projectile-find-file - [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) + (map! [remap apropos] #'helm-apropos + [remap find-library] #'helm-locate-library + [remap bookmark-jump] #'helm-bookmarks + [remap execute-extended-command] #'helm-M-x + [remap find-file] #'helm-find-files + [remap imenu-anywhere] #'helm-imenu-anywhere + [remap imenu] #'helm-semantic-or-imenu + [remap noop-show-kill-ring] #'helm-show-kill-ring + [remap persp-switch-to-buffer] #'+helm/workspace-mini + [remap switch-to-buffer] #'helm-buffers-list + [remap projectile-find-file] #'+helm/projectile-find-file + [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 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)) diff --git a/modules/completion/ivy/config.el b/modules/completion/ivy/config.el index 533348e68..b13c673b9 100644 --- a/modules/completion/ivy/config.el +++ b/modules/completion/ivy/config.el @@ -58,10 +58,9 @@ 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 - [remap persp-switch-to-buffer] #'+ivy/switch-workspace-buffer - [remap imenu-anywhere] #'ivy-imenu-anywhere) + (map! [remap switch-to-buffer] #'ivy-switch-buffer + [remap persp-switch-to-buffer] #'+ivy/switch-workspace-buffer + [remap imenu-anywhere] #'ivy-imenu-anywhere) (ivy-mode +1) @@ -91,21 +90,21 @@ 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 - [remap bookmark-jump] #'counsel-bookmark - [remap describe-face] #'counsel-faces - [remap describe-function] #'counsel-describe-function - [remap describe-variable] #'counsel-describe-variable - [remap execute-extended-command] #'counsel-M-x - [remap find-file] #'counsel-find-file - [remap find-library] #'counsel-find-library - [remap info-lookup-symbol] #'counsel-info-lookup-symbol - [remap imenu] #'counsel-imenu - [remap recentf-open-files] #'counsel-recentf - [remap org-capture] #'counsel-org-capture - [remap swiper] #'counsel-grep-or-swiper) - + (map! [remap apropos] #'counsel-apropos + [remap bookmark-jump] #'counsel-bookmark + [remap describe-face] #'counsel-faces + [remap describe-function] #'counsel-describe-function + [remap describe-variable] #'counsel-describe-variable + [remap execute-extended-command] #'counsel-M-x + [remap find-file] #'counsel-find-file + [remap find-library] #'counsel-find-library + [remap info-lookup-symbol] #'counsel-info-lookup-symbol + [remap imenu] #'counsel-imenu + [remap recentf-open-files] #'counsel-recentf + [remap org-capture] #'counsel-org-capture + [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,13 +159,12 @@ 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 - [remap projectile-find-dir] #'counsel-projectile-find-dir - [remap projectile-switch-to-buffer] #'counsel-projectile-switch-to-buffer - [remap projectile-grep] #'counsel-projectile-grep - [remap projectile-ag] #'counsel-projectile-ag - [remap projectile-switch-project] #'counsel-projectile-switch-project) + (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 + [remap projectile-ag] #'counsel-projectile-ag + [remap projectile-switch-project] #'counsel-projectile-switch-project) :config ;; no highlighting visited files; slows down the filtering (ivy-set-display-transformer #'counsel-projectile-find-file nil)) @@ -232,43 +230,36 @@ immediately runs it on the current candidate (ending the ivy session)." (map! :when (featurep! :feature evil +everywhere) :after ivy + :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 "" #'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 "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 - + :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 - :n "D" #'ivy-occur-delete-candidate - :n "C-d" #'evil-scroll-down - :n "d" #'ivy-occur-delete-candidate - :n "C-x C-q" #'ivy-wgrep-change-to-wgrep-mode - :n "i" #'ivy-wgrep-change-to-wgrep-mode - :n "gd" #'ivy-occur-delete-candidate - :n [mouse-1] #'ivy-occur-click - :n "" #'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 "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) + :v "j" #'evil-next-line + :v "k" #'evil-previous-line + :n "D" #'ivy-occur-delete-candidate + :n "C-d" #'evil-scroll-down + :n "d" #'ivy-occur-delete-candidate + :n "C-x C-q" #'ivy-wgrep-change-to-wgrep-mode + :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 + :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 + :n "q" #'quit-window) diff --git a/modules/config/default/+bindings.el b/modules/config/default/+bindings.el deleted file mode 100644 index 363975d76..000000000 --- a/modules/config/default/+bindings.el +++ /dev/null @@ -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 < " #'+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 - "" #'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 - "" #'+snippets/goto-end-of-field - "" #'+snippets/goto-start-of-field - "" #'+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 - "" nil - "" nil - "" 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)) - - -;; -;; - -(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)) diff --git a/modules/config/default/+emacs-bindings.el b/modules/config/default/+emacs-bindings.el new file mode 100644 index 000000000..fea63ab5e --- /dev/null +++ b/modules/config/default/+emacs-bindings.el @@ -0,0 +1,3 @@ +;;; config/default/+emacs-bindings.el -*- lexical-binding: t; -*- + +;; TODO diff --git a/modules/config/default/+evil-bindings.el b/modules/config/default/+evil-bindings.el new file mode 100644 index 000000000..41a1bfff2 --- /dev/null +++ b/modules/config/default/+evil-bindings.el @@ -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 < " #'+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 + "" #'+snippets/goto-end-of-field + "" #'+snippets/goto-start-of-field + "" #'+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 + "" nil + "" nil + "" nil)) + + +;; +;; + +(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) diff --git a/modules/config/default/+evil-commands.el b/modules/config/default/+evil-commands.el deleted file mode 100644 index 88ef9fd6f..000000000 --- a/modules/config/default/+evil-commands.el +++ /dev/null @@ -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 "") - (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 "") - (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) - diff --git a/modules/config/default/autoload/default.el b/modules/config/default/autoload/default.el index 81d673ab1..966872055 100644 --- a/modules/config/default/autoload/default.el +++ b/modules/config/default/autoload/default.el @@ -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)))))) diff --git a/modules/config/default/config.el b/modules/config/default/config.el index 5ddddc0c9..4d74aa7f8 100644 --- a/modules/config/default/config.el +++ b/modules/config/default/config.el @@ -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"))) diff --git a/modules/emacs/eshell/config.el b/modules/emacs/eshell/config.el index 1fb2194b1..7d1691dcd 100644 --- a/modules/emacs/eshell/config.el +++ b/modules/emacs/eshell/config.el @@ -123,33 +123,30 @@ 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 - [remap split-window-below] #'+eshell/split-below - [remap split-window-right] #'+eshell/split-right - [remap doom/backward-to-bol-or-indent] #'eshell-bol - [remap doom/backward-kill-to-bol-and-indent] #'eshell-kill-input - [remap evil-window-split] #'+eshell/split-below - [remap evil-window-vsplit] #'+eshell/split-right)) + (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 + [remap doom/backward-kill-to-bol-and-indent] #'eshell-kill-input + [remap evil-window-split] #'+eshell/split-below + [remap evil-window-vsplit] #'+eshell/split-right)) (add-hook 'eshell-first-time-mode-hook #'+eshell|init-keymap)) diff --git a/modules/feature/eval/autoload/eval.el b/modules/feature/eval/autoload/eval.el index 75006b142..2a1738cd9 100644 --- a/modules/feature/eval/autoload/eval.el +++ b/modules/feature/eval/autoload/eval.el @@ -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." diff --git a/modules/feature/evil/config.el b/modules/feature/evil/config.el index fd56b336d..3af427662 100644 --- a/modules/feature/evil/config.el +++ b/modules/feature/evil/config.el @@ -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) diff --git a/modules/lang/emacs-lisp/config.el b/modules/lang/emacs-lisp/config.el index 6d16fb904..5c02080df 100644 --- a/modules/lang/emacs-lisp/config.el +++ b/modules/lang/emacs-lisp/config.el @@ -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)) ;; diff --git a/modules/lang/latex/+ref.el b/modules/lang/latex/+ref.el index 83460ca8f..75136a077 100644 --- a/modules/lang/latex/+ref.el +++ b/modules/lang/latex/+ref.el @@ -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 diff --git a/modules/lang/markdown/config.el b/modules/lang/markdown/config.el index e71ec63e6..ef0a43f9e 100644 --- a/modules/lang/markdown/config.el +++ b/modules/lang/markdown/config.el @@ -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 - (:prefix "i" - :nv "t" #'markdown-toc-generate-toc - :nv "i" #'markdown-insert-image - :nv "l" #'markdown-insert-link))) + [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" + "t" #'markdown-toc-generate-toc + "i" #'markdown-insert-image + "l" #'markdown-insert-link)))) (def-package! pandoc-mode :when (featurep! +pandoc) diff --git a/modules/lang/rest/config.el b/modules/lang/rest/config.el index a9ad7b7e7..014840039 100644 --- a/modules/lang/rest/config.el +++ b/modules/lang/rest/config.el @@ -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 diff --git a/modules/tools/ein/config.el b/modules/tools/ein/config.el index e9b2f0412..ab3f6d409 100644 --- a/modules/tools/ein/config.el +++ b/modules/tools/ein/config.el @@ -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)) diff --git a/modules/tools/magit/config.el b/modules/tools/magit/config.el index 25e992688..928680797 100644 --- a/modules/tools/magit/config.el +++ b/modules/tools/magit/config.el @@ -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))) diff --git a/modules/ui/doom-dashboard/config.el b/modules/ui/doom-dashboard/config.el index a53f0704e..d108a111c 100644 --- a/modules/ui/doom-dashboard/config.el +++ b/modules/ui/doom-dashboard/config.el @@ -138,39 +138,38 @@ 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 - [left-margin mouse-1] #'ignore - [remap evil-next-visual-line] #'forward-button - [remap evil-previous-visual-line] #'backward-button - [remap evil-delete] #'ignore - [remap evil-delete-line] #'ignore - [remap evil-insert] #'ignore - [remap evil-append] #'ignore - [remap evil-replace] #'ignore - [remap evil-replace-state] #'ignore - [remap evil-change] #'ignore - [remap evil-change-line] #'ignore - [remap evil-visual-char] #'ignore - [remap evil-visual-line] #'ignore)) +(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 + [remap evil-delete] #'ignore + [remap evil-delete-line] #'ignore + [remap evil-insert] #'ignore + [remap evil-append] #'ignore + [remap evil-replace] #'ignore + [remap evil-replace-state] #'ignore + [remap evil-change] #'ignore + [remap evil-change-line] #'ignore + [remap evil-visual-char] #'ignore + [remap evil-visual-line] #'ignore) ;;