diff --git a/modules/editor/evil/+commands.el b/modules/editor/evil/+commands.el index 69e1a2dd0..de2058f01 100644 --- a/modules/editor/evil/+commands.el +++ b/modules/editor/evil/+commands.el @@ -1,100 +1,6 @@ ;;; editor/evil/+commands.el -*- lexical-binding: t; -*- -(evil-define-operator +evil:open-scratch-buffer (bang) - (interactive "") - (doom/open-scratch-buffer bang)) - -(evil-define-command +evil: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 +evil:make (arguments &optional bang) - "Run make with ARGUMENTS. -If BANG is non-nil, open compilation output in a comint buffer. - -If BANG, then run ARGUMENTS as a full command. This command understands vim file -modifiers (like %:p:h). See `+evil-resolve-vim-path-a' for details." - (interactive "") - (+evil:compile (format "make %s" - (evil-ex-replace-special-filenames - arguments)) - bang)) - -(evil-define-command +evil:compile (arguments &optional bang) - "Run `compile-command' with ARGUMENTS. -If BANG is non-nil, open compilation output in a comint buffer. - -This command understands vim file modifiers (like %:p:h). See -`+evil-resolve-vim-path-a' for details." - (interactive "") - (compile (evil-ex-replace-special-filenames - (format "%s %s" - (eval compile-command) - arguments)) - bang)) - -(evil-define-command +evil:reverse-lines (beg end) - "Reverse lines between BEG and END." - (interactive "") - (reverse-region beg end)) - -(evil-define-command +evil:cd (&optional path) - "Change `default-directory' with `cd'." - (interactive "") - (let ((path (or path "~"))) - (cd path) - (message "Changed directory to '%s'" (abbreviate-file-name (expand-file-name path))))) - -(evil-define-command +evil:kill-all-buffers (&optional bang) - "Kill all buffers. If BANG, kill current session too." - (interactive "") - (if (and bang (fboundp '+workspace/kill-session)) - (+workspace/kill-session) - (doom/kill-all-buffers))) - -(evil-define-command +evil:kill-matching-buffers (&optional bang pattern) - "Kill all buffers matching PATTERN regexp. If BANG, only match project -buffers." - (interactive "") - (doom/kill-matching-buffers pattern bang)) - -(evil-define-command +evil:help (&optional bang query) - "Look up help documentation for QUERY in Emacs documentation. - -If BANG, search Doom documentation." - (interactive "") - (if bang - (doom/help-search query) - (cond ((or (null query) (string-empty-p (string-trim query))) - (call-interactively - (or (command-remapping #'apropos) - #'apropos))) - ((string-match-p "^ *:[a-z]" query) - (let* ((modules - (cl-loop for path in (doom-module-load-path 'all) - for (cat . mod) = (doom-module-from-path path) - for format = (format "%s %s" cat mod) - if (doom-module-p cat mod) - collect (propertize format 'module (list cat mod)) - else if (and cat mod) - collect (propertize format - 'face 'font-lock-comment-face - 'module (list cat mod)))) - (module (completing-read "Describe module: " modules nil t query)) - (key (get-text-property 0 'module module))) - (doom/help-modules key))) - ((and (string-match-p "\\(?:SPC\\|[CMsSH]-[^ ]\\|<[^>]+>\\)" query) - (helpful-key (kbd (string-trim query))))) - ((apropos query t))))) - - ;; -;; Commands - ;;; Custom commands ;; Editing (evil-ex-define-cmd "@" #'+evil:macro-on-all-lines) ; TODO Test me diff --git a/modules/editor/evil/autoload/evil.el b/modules/editor/evil/autoload/evil.el index 06b266cea..4cb4bd7c3 100644 --- a/modules/editor/evil/autoload/evil.el +++ b/modules/editor/evil/autoload/evil.el @@ -11,72 +11,6 @@ (evil-set-initial-state modes state)))) -;; -;;; Custom arg handlers - -(defvar +evil--flag nil) - -(defun +evil--ex-match-init (name &optional face update-hook) - (with-current-buffer evil-ex-current-buffer - (cond - ((eq +evil--flag 'start) - (evil-ex-make-hl name - :face (or face 'evil-ex-substitute-matches) - :update-hook (or update-hook #'evil-ex-pattern-update-ex-info)) - (setq +evil--flag 'update)) - - ((eq +evil--flag 'stop) - (evil-ex-delete-hl name))))) - -(defun +evil--ex-buffer-match (arg &optional hl-name flags beg end) - (when (and (eq +evil--flag 'update) - evil-ex-substitute-highlight-all - (not (zerop (length arg)))) - (condition-case lossage - (let ((pattern (evil-ex-make-substitute-pattern - arg - (or flags (list)))) - (range (or (evil-copy-range evil-ex-range) - (evil-range (or beg (line-beginning-position)) - (or end (line-end-position)) - 'line - :expanded t)))) - (evil-expand-range range) - (evil-ex-hl-set-region hl-name - (max (evil-range-beginning range) (window-start)) - (min (evil-range-end range) (window-end))) - (evil-ex-hl-change hl-name pattern)) - (end-of-file - (evil-ex-pattern-update-ex-info nil "incomplete replacement")) - (user-error - (evil-ex-pattern-update-ex-info nil (format "?%s" lossage)))))) - -;;;###autoload -(defun +evil-ex-buffer-match (flag &optional arg) - (let ((hl-name 'evil-ex-buffer-match) - (+evil--flag flag)) - (with-selected-window (minibuffer-selected-window) - (+evil--ex-match-init hl-name) - (+evil--ex-buffer-match arg hl-name (list (if evil-ex-substitute-global ?g)))))) - -;;;###autoload -(defun +evil-ex-global-match (flag &optional arg) - (let ((hl-name 'evil-ex-global-match) - (+evil--flag flag)) - (with-selected-window (minibuffer-selected-window) - (+evil--ex-match-init hl-name) - (+evil--ex-buffer-match arg hl-name nil (point-min) (point-max))))) - -;;;###autoload -(defun +evil-ex-global-delim-match (flag &optional arg) - (let ((hl-name 'evil-ex-global-delim-match) - (+evil--flag flag)) - (with-selected-window (minibuffer-selected-window) - (+evil--ex-match-init hl-name) - (let ((result (car-safe (evil-delimited-arguments arg 2)))) - (+evil--ex-buffer-match result hl-name nil (point-min) (point-max)))))) - - ;; ;;; Interactive commands @@ -166,28 +100,6 @@ integration." t)) prefix))))) -;;;###autoload (autoload '+evil:align "editor/evil/autoload/evil" nil t) -(evil-define-operator +evil:align (beg end pattern &optional bang) - "Ex interface to `align-regexp'. PATTERN is a vim-style regexp. If BANG, -repeat the alignment for all matches (otherwise just the first match on each -line)." - (interactive "") - (align-regexp - beg end - (concat "\\(\\s-*\\)" (evil-transform-vim-style-regexp pattern)) - 1 1 bang)) - -;;;###autoload (autoload '+evil:align-right "editor/evil/autoload/evil" nil t) -(evil-define-operator +evil:align-right (beg end pattern &optional bang) - "Like `+evil:align', except alignments are right-justified. PATTERN is a -vim-style regexp. If BANG, repeat the alignment for all matches (otherwise just -the first match on each line)." - (interactive "") - (align-regexp - beg end - (concat "\\(" (evil-transform-vim-style-regexp pattern) "\\)") - -1 1 bang)) - ;;;###autoload (autoload '+evil:apply-macro "editor/evil/autoload/evil" nil t) (evil-define-operator +evil:apply-macro (beg end) "Apply macro to each line." diff --git a/modules/editor/evil/autoload/ex.el b/modules/editor/evil/autoload/ex.el new file mode 100644 index 000000000..ab7c4919a --- /dev/null +++ b/modules/editor/evil/autoload/ex.el @@ -0,0 +1,183 @@ +;;; editor/evil/autoload/ex.el -*- lexical-binding: t; -*- + +(defvar +evil--flag nil) + +(defun +evil--ex-match-init (name &optional face update-hook) + (with-current-buffer evil-ex-current-buffer + (cond + ((eq +evil--flag 'start) + (evil-ex-make-hl name + :face (or face 'evil-ex-lazy-highlight) + :update-hook (or update-hook #'evil-ex-pattern-update-ex-info)) + (setq +evil--flag 'update)) + + ((eq +evil--flag 'stop) + (evil-ex-delete-hl name))))) + +(defun +evil--ex-buffer-match (arg &optional hl-name flags beg end) + (when (and (eq +evil--flag 'update) + evil-ex-substitute-highlight-all + (not (zerop (length arg)))) + (condition-case lossage + (let* ((pattern (evil-ex-make-substitute-pattern + arg + (or flags (list)))) + (range (or (evil-copy-range evil-ex-range) + (evil-range (or beg (line-beginning-position)) + (or end (line-end-position)) + 'line + :expanded t)))) + (evil-expand-range range) + (evil-ex-hl-set-region hl-name + (max (evil-range-beginning range) (window-start)) + (min (evil-range-end range) (window-end))) + (evil-ex-hl-change hl-name pattern)) + (end-of-file + (evil-ex-pattern-update-ex-info nil "incomplete replacement")) + (user-error + (evil-ex-pattern-update-ex-info nil (format "?%s" lossage)))))) + +;;;###autoload +(defun +evil-ex-regexp-match (flag &optional arg invert) + (let ((hl-name 'evil-ex-buffer-match) + (+evil--flag flag)) + (with-selected-window (minibuffer-selected-window) + (+evil--ex-match-init hl-name) + (cl-destructuring-bind (&optional arg flags) + (evil-delimited-arguments arg 2) + (let ((evil-ex-substitute-global + (if invert + (not evil-ex-substitute-global) + evil-ex-substitute-global))) + (+evil--ex-buffer-match + arg hl-name (string-to-list flags))))))) + + +;; +;;; Ex Commands + +;;;###autoload (autoload '+evil:align "editor/evil/autoload/ex" nil t) +(evil-define-operator +evil:align (beg end pattern &optional flags) + "Ex interface to `align-regexp'. PATTERN is a vim-style regexp. If BANG, +repeat the alignment for all matches (otherwise just the first match on each +line)." + (interactive "") + (align-regexp + beg end + (concat "\\(\\s-*\\)" (evil-transform-vim-style-regexp pattern)) + 1 1 (memq ?g flags))) + +;;;###autoload (autoload '+evil:align-right "editor/evil/autoload/ex" nil t) +(evil-define-operator +evil:align-right (beg end pattern &optional flags) + "Like `+evil:align', except alignments are right-justified. PATTERN is a +vim-style regexp. If BANG, repeat the alignment for all matches (otherwise just +the first match on each line)." + (interactive "") + (align-regexp + beg end + (concat "\\(" (evil-transform-vim-style-regexp pattern) "\\)") + -1 1 (memq ?g flags))) + +;; ;;;###autoload (autoload '+evil:sort "editor/evil/autoload/ex" nil nil) +;; (evil-define-command +evil:sort (beg end &optional pattern flags reverse) +;; (interactive "")) + +;;;###autoload (autoload '+evil:open-scratch-buffer "editor/evil/autoload/ex" nil t) +(evil-define-operator +evil:open-scratch-buffer (bang) + (interactive "") + (doom/open-scratch-buffer bang)) + +;;;###autoload (autoload '+evil:pwd "editor/evil/autoload/ex" nil t) +(evil-define-command +evil: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"))) + +;;;###autoload (autoload '+evil:make "editor/evil/autoload/ex" nil t) +(evil-define-command +evil:make (arguments &optional bang) + "Run make with ARGUMENTS. +If BANG is non-nil, open compilation output in a comint buffer. + +If BANG, then run ARGUMENTS as a full command. This command understands vim file +modifiers (like %:p:h). See `+evil-resolve-vim-path-a' for details." + (interactive "") + (+evil:compile (format "make %s" + (evil-ex-replace-special-filenames + arguments)) + bang)) + +;;;###autoload (autoload '+evil:compile "editor/evil/autoload/ex" nil t) +(evil-define-command +evil:compile (arguments &optional bang) + "Run `compile-command' with ARGUMENTS. +If BANG is non-nil, open compilation output in a comint buffer. + +This command understands vim file modifiers (like %:p:h). See +`+evil-resolve-vim-path-a' for details." + (interactive "") + (compile (evil-ex-replace-special-filenames + (format "%s %s" + (eval compile-command) + arguments)) + bang)) + +;;;###autoload (autoload '+evil:reverse-lines "editor/evil/autoload/ex" nil t) +(evil-define-command +evil:reverse-lines (beg end) + "Reverse lines between BEG and END." + (interactive "") + (reverse-region beg end)) + +;;;###autoload (autoload '+evil:cd "editor/evil/autoload/ex" nil t) +(evil-define-command +evil:cd (&optional path) + "Change `default-directory' with `cd'." + (interactive "") + (let ((path (or path "~"))) + (cd path) + (message "Changed directory to '%s'" (abbreviate-file-name (expand-file-name path))))) + +;;;###autoload (autoload '+evil:kill-all-buffers "editor/evil/autoload/ex" nil t) +(evil-define-command +evil:kill-all-buffers (&optional bang) + "Kill all buffers. If BANG, kill current session too." + (interactive "") + (if (and bang (fboundp '+workspace/kill-session)) + (+workspace/kill-session) + (doom/kill-all-buffers))) + +;;;###autoload (autoload '+evil:kill-matching-buffers "editor/evil/autoload/ex" nil t) +(evil-define-command +evil:kill-matching-buffers (&optional bang pattern) + "Kill all buffers matching PATTERN regexp. If BANG, only match project +buffers." + (interactive "") + (doom/kill-matching-buffers pattern bang)) + +;;;###autoload (autoload '+evil:help "editor/evil/autoload/ex" nil t) +(evil-define-command +evil:help (&optional bang query) + "Look up help documentation for QUERY in Emacs documentation. + +If BANG, search Doom documentation." + (interactive "") + (if bang + (doom/help-search query) + (cond ((or (null query) (string-empty-p (string-trim query))) + (call-interactively + (or (command-remapping #'apropos) + #'apropos))) + ((string-match-p "^ *:[a-z]" query) + (let* ((modules + (cl-loop for path in (doom-module-load-path 'all) + for (cat . mod) = (doom-module-from-path path) + for format = (format "%s %s" cat mod) + if (doom-module-p cat mod) + collect (propertize format 'module (list cat mod)) + else if (and cat mod) + collect (propertize format + 'face 'font-lock-comment-face + 'module (list cat mod)))) + (module (completing-read "Describe module: " modules nil t query)) + (key (get-text-property 0 'module module))) + (doom/help-modules key))) + ((and (string-match-p "\\(?:SPC\\|[CMsSH]-[^ ]\\|<[^>]+>\\)" query) + (helpful-key (kbd (string-trim query))))) + ((apropos query t))))) diff --git a/modules/editor/evil/config.el b/modules/editor/evil/config.el index b4591e090..8415db801 100644 --- a/modules/editor/evil/config.el +++ b/modules/editor/evil/config.el @@ -144,32 +144,41 @@ directives. By default, this only recognizes C directives.") ;; --- custom interactive codes ----------- ;; These arg types will highlight matches in the current buffer - (evil-ex-define-argument-type buffer-match :runner +evil-ex-buffer-match) - (evil-ex-define-argument-type global-match :runner +evil-ex-global-match) + (evil-ex-define-argument-type regexp-match + :runner (lambda (flag &optional arg) (+evil-ex-regexp-match flag arg 'inverted))) + (evil-ex-define-argument-type regexp-global-match + :runner +evil-ex-regexp-match) + + (defun +evil--regexp-match-args (arg) + (when (evil-ex-p) + (cl-destructuring-bind (&optional arg flags) + (evil-delimited-arguments arg 2) + (list arg (string-to-list flags))))) + ;; Other commands can make use of this (evil-define-interactive-code "" - :ex-arg buffer-match (list (if (evil-ex-p) evil-ex-argument))) - (evil-define-interactive-code "" - :ex-arg global-match (list (if (evil-ex-p) evil-ex-argument))) + :ex-arg regexp-match + (+evil--regexp-match-args evil-ex-argument)) - ;; By default :g[lobal] doesn't highlight matches in the current buffer. I've - ;; got to write my own argument type and interactive code to get it to do so. - (evil-ex-define-argument-type global-delim-match :runner +evil-ex-global-delim-match) - (dolist (sym '(evil-ex-global evil-ex-global-inverted)) - (evil-set-command-property sym :ex-arg 'global-delim-match)) + (evil-define-interactive-code "" + :ex-arg regexp-global-match + (+evil--regexp-match-args evil-ex-argument)) ;; Forward declare these so that ex completion works, even if the autoloaded ;; functions aren't loaded yet. - (evil-set-command-properties - '+evil:align :move-point t :ex-arg 'buffer-match :ex-bang t :keep-visual t :suppress-operator t) + (evil-add-command-properties '+evil:align :ex-arg 'regexp-match) + (evil-add-command-properties '+evil:align-right :ex-arg 'regexp-match) + (evil-add-command-properties '+multiple-cursors:evil-mc :ex-arg 'regexp-global-match) ;; `evil-collection' (when (and (featurep! +everywhere) (not doom-reloading-p)) (load! "+everywhere")) - ;; Custom evil ex commands - (load! "+commands")) + ;; Lazy load evil ex commands + (delq! 'evil-ex features) + (add-transient-hook! 'evil-ex (provide 'evil-ex)) + (after! evil-ex (load! "+commands"))) ;; @@ -296,6 +305,15 @@ directives. By default, this only recognizes C directives.") :config (global-evil-surround-mode 1)) +(use-package! evil-traces + :after evil-ex + :config + (pushnew! evil-traces-argument-type-alist + '(+evil:align . evil-traces-global) + '(+evil:align-right . evil-traces-global)) + (evil-traces-mode)) + + ;; Allows you to use the selection for * and # (use-package! evil-visualstar :commands (evil-visualstar/begin-search diff --git a/modules/editor/evil/packages.el b/modules/editor/evil/packages.el index 3e0e1f8ef..aed8f38bc 100644 --- a/modules/editor/evil/packages.el +++ b/modules/editor/evil/packages.el @@ -10,9 +10,10 @@ (package! evil-exchange) (package! evil-indent-plus) (package! evil-numbers :recipe (:host github :repo "janpath/evil-numbers")) -(package! evil-textobj-anyblock) (package! evil-snipe) (package! evil-surround) +(package! evil-textobj-anyblock) +(package! evil-traces) (package! evil-visualstar) (package! exato)