doomemacs/modules/editor/multiple-cursors/config.el
Andrew Whatson 99a5ff2025 Fix loading of multiple-cursors configuration
The package is split in a way that `multiple-cursors.el` is normally not
required when autoloading from commands; `multiple-cursors-core.el` is
always loaded.

Unfortunately the `mc/list-file` location is still not being set
properly, a fix has been submitted: magnars/multiple-cursors.el#355
2019-03-13 14:24:20 +10:00

115 lines
5.3 KiB
EmacsLisp

;;; editor/multiple-cursors/config.el -*- lexical-binding: t; -*-
(def-package! evil-mc
:when (featurep! :feature evil)
:commands (evil-mc-make-cursor-here evil-mc-make-all-cursors
evil-mc-undo-all-cursors evil-mc-pause-cursors
evil-mc-resume-cursors evil-mc-make-and-goto-first-cursor
evil-mc-make-and-goto-last-cursor
evil-mc-make-cursor-move-next-line
evil-mc-make-cursor-move-prev-line evil-mc-make-cursor-at-pos
evil-mc-has-cursors-p evil-mc-make-and-goto-next-cursor
evil-mc-skip-and-goto-next-cursor evil-mc-make-and-goto-prev-cursor
evil-mc-skip-and-goto-prev-cursor evil-mc-make-and-goto-next-match
evil-mc-skip-and-goto-next-match evil-mc-skip-and-goto-next-match
evil-mc-make-and-goto-prev-match evil-mc-skip-and-goto-prev-match)
:init
(defvar evil-mc-key-map (make-sparse-keymap))
:config
(global-evil-mc-mode +1)
(after! smartparens
;; Make evil-mc cooperate with smartparens better
(let ((vars (cdr (assq :default evil-mc-cursor-variables))))
(unless (memq (car sp--mc/cursor-specific-vars) vars)
(setcdr (assq :default evil-mc-cursor-variables)
(append vars sp--mc/cursor-specific-vars)))))
;; Add custom commands to whitelisted commands
(dolist (fn '(doom/backward-to-bol-or-indent doom/forward-to-last-non-comment-or-eol
doom/backward-kill-to-bol-and-indent delete-char))
(add-to-list 'evil-mc-custom-known-commands `(,fn (:default . evil-mc-execute-default-call-with-count))))
;; Have evil-mc work with explicit `evil-escape' (typically bound to C-g)
(add-to-list 'evil-mc-custom-known-commands '(evil-escape (:default . evil-mc-execute-default-evil-normal-state)))
;; Activate evil-mc cursors upon switching to insert mode
(add-hook 'evil-insert-state-entry-hook #'evil-mc-resume-cursors)
;; disable evil-escape in evil-mc; causes unwanted text on invocation
(add-to-list 'evil-mc-incompatible-minor-modes 'evil-escape-mode nil #'eq)
(defun +multiple-cursors|escape-multiple-cursors ()
"Clear evil-mc cursors and restore state."
(when (evil-mc-has-cursors-p)
(evil-mc-undo-all-cursors)
(evil-mc-resume-cursors)
t))
(add-hook 'doom-escape-hook #'+multiple-cursors|escape-multiple-cursors)
;; Forward declare these so that ex completion and evil-mc support is
;; recognized before the autoloaded functions are loaded.
(evil-add-command-properties '+evil:align :evil-mc t)
(evil-set-command-properties '+multiple-cursors:evil-mc
:move-point nil
:ex-arg 'global-match
:ex-bang t
:evil-mc t))
(after! multiple-cursors-core
(setq mc/list-file (concat doom-etc-dir "mc-lists.el"))
;; TODO multiple-cursors config for Emacs users?
;; mc doesn't play well with evil, this attempts to assuage some of its
;; problems so that any plugins that depend on multiple-cursors (which I have
;; no control over) can still use it in relative safety.
(when (featurep! :feature evil)
(evil-define-key* '(normal emacs) mc/keymap [escape] #'mc/keyboard-quit)
(defvar +mc--compat-evil-prev-state nil)
(defvar +mc--compat-mark-was-active nil)
(defun +multiple-cursors|compat-switch-to-emacs-state ()
(when (and (bound-and-true-p evil-mode)
(not (memq evil-state '(insert emacs))))
(setq +mc--compat-evil-prev-state evil-state)
(when (region-active-p)
(setq +mc--compat-mark-was-active t))
(let ((mark-before (mark))
(point-before (point)))
(evil-emacs-state 1)
(when (or +mc--compat-mark-was-active (region-active-p))
(goto-char point-before)
(set-mark mark-before)))))
(add-hook 'multiple-cursors-mode-enabled-hook #'+multiple-cursors|compat-switch-to-emacs-state)
(defun +multiple-cursors|compat-back-to-previous-state ()
(when +mc--compat-evil-prev-state
(unwind-protect
(case +mc--compat-evil-prev-state
((normal visual) (evil-force-normal-state))
(t (message "Don't know how to handle previous state: %S"
+mc--compat-evil-prev-state)))
(setq +mc--compat-evil-prev-state nil)
(setq +mc--compat-mark-was-active nil))))
(add-hook 'multiple-cursors-mode-disabled-hook #'+multiple-cursors|compat-back-to-previous-state)
;; When running edit-lines, point will return (position + 1) as a
;; result of how evil deals with regions
(defun +multiple-cursors*adjust-mark-for-evil (&rest _)
(when (and (bound-and-true-p evil-mode)
(not (memq evil-state '(insert emacs))))
(if (> (point) (mark))
(goto-char (1- (point)))
(push-mark (1- (mark))))))
(advice-add #'mc/edit-lines :before #'+multiple-cursors*adjust-mark-for-evil)
(defun +multiple-cursors|evil-compat-rect-switch-state ()
(if rectangular-region-mode
(+multiple-cursors|compat-switch-to-emacs-state)
(setq +mc--compat-evil-prev-state nil)))
(add-hook 'rectangular-region-mode-hook '+multiple-cursors|evil-compat-rect-switch-state)
(defvar mc--default-cmds-to-run-once nil)))