lsp-iedit.el (5283B)
1 ;;; lsp-iedit.el --- `iedit' integration -*- lexical-binding: t -*- 2 ;; 3 ;; Copyright (C) 2020 emacs-lsp maintainers 4 ;; 5 ;; This program is free software; you can redistribute it and/or modify 6 ;; it under the terms of the GNU General Public License as published by 7 ;; the Free Software Foundation, either version 3 of the License, or 8 ;; (at your option) any later version. 9 10 ;; This program is distributed in the hope that it will be useful, 11 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 12 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 ;; GNU General Public License for more details. 14 15 ;; You should have received a copy of the GNU General Public License 16 ;; along with this program. If not, see <https://www.gnu.org/licenses/>. 17 18 ;;; Commentary: 19 20 ;; This module provides features that allow starting `iedit' on various 21 ;; different lsp-based, semantic units (like documentHighlights, and 22 ;; linkedEditingRanges in the future). 23 24 ;;; Code: 25 26 (require 'lsp-mode) 27 (require 'dash) 28 29 (declare-function iedit-make-occurrence-overlay "iedit-lib" (begin end)) 30 (declare-function iedit-start-buffering "iedit-lib" ()) 31 (declare-function iedit-lib-start "iedit-lib" (mode-exit-func)) 32 (declare-function iedit-done "iedit" ()) 33 (declare-function evil-multiedit-mode "evil-multiedit" (mode)) 34 (declare-function evil-iedit-state "evil-iedit-state" ()) 35 36 (defvar iedit-mode) 37 (defvar iedit-auto-buffering) 38 (defvar iedit-occurrences-overlays) 39 (defvar iedit-occurrence-keymap) 40 (defvar iedit-mode-occurrence-keymap) 41 (defvar evil-multiedit--dont-recall) 42 43 (defun lsp-iedit--on-ranges (ranges) 44 "Start an `iedit' operation using RANGES. 45 RANGES shall be a list of lsp-`&Range's. They can be acquired 46 from various lsp protocol requests, e.g. 47 `textDocument/documentHighlight', ...." 48 (require 'iedit) 49 (unless (seq-empty-p ranges) 50 (mapc (-lambda ((&RangeToPoint :start :end)) 51 (push (iedit-make-occurrence-overlay start end) 52 iedit-occurrences-overlays)) 53 ranges) 54 ;; See `iedit-start'; TODO: upstream this 55 (setq iedit-occurrence-keymap iedit-mode-occurrence-keymap) 56 (setq iedit-mode t) 57 (when iedit-auto-buffering 58 (iedit-start-buffering)) 59 (iedit-lib-start 'iedit-done) 60 (run-hooks 'iedit-mode-hook) 61 (add-hook 'before-revert-hook 'iedit-done nil t) 62 (add-hook 'kbd-macro-termination-hook 'iedit-done nil t) 63 (add-hook 'change-major-mode-hook 'iedit-done nil t) 64 (add-hook 'iedit-aborting-hook 'iedit-done nil t) 65 (message "%d occurrences of \"%s\"" 66 (seq-length ranges) 67 (lsp--range-text (lsp-seq-first ranges))))) 68 69 ;; iedit 70 71 ;;;###autoload 72 (defun lsp-iedit-highlights () 73 "Start an `iedit' operation on the documentHighlights at point. 74 This can be used as a primitive `lsp-rename' replacement if the 75 language server doesn't support renaming. 76 77 See also `lsp-enable-symbol-highlighting'." 78 (interactive) 79 (let ((highlights (lsp-request "textDocument/documentHighlight" 80 (lsp--text-document-position-params))) 81 (-compare-fn (-lambda ((&Location :range (&Range :start l-start :end l-end)) 82 (&Location :range (&Range :start r-start :end r-end))) 83 (and (lsp--position-equal l-start r-start) 84 (lsp--position-equal l-end r-end))))) 85 (lsp-iedit--on-ranges (mapcar #'lsp:document-highlight-range (-distinct highlights))))) 86 87 ;;;###autoload 88 (defun lsp-iedit-linked-ranges () 89 "Start an `iedit' for `textDocument/linkedEditingRange'" 90 (interactive) 91 (unless (lsp-feature? "textDocument/linkedEditingRange") 92 (user-error "`textDocument/linkedEditingRange' is not supported by current server")) 93 94 (-> (lsp-request "textDocument/linkedEditingRange" (lsp--text-document-position-params)) 95 (lsp:linked-editing-ranges-ranges) 96 (or (user-error "No editing ranges found")) 97 (lsp-iedit--on-ranges))) 98 99 100 ;; evil-multi-edit 101 102 ;;;###autoload 103 (defun lsp-evil-multiedit-highlights () 104 "Start an `evil-multiedit' operation on the documentHighlights at point. 105 This can be used as a primitive `lsp-rename' replacement if the 106 language server doesn't support renaming. 107 108 See also `lsp-enable-symbol-highlighting'." 109 (interactive) 110 (require 'evil-multiedit) 111 (when (fboundp 'ahs-clear) (ahs-clear)) 112 (setq evil-multiedit--dont-recall t) 113 (lsp-iedit-highlights) 114 (evil-multiedit-mode +1)) 115 116 ;;;###autoload 117 (defun lsp-evil-multiedit-linked-ranges () 118 "Start an `evil-multiedit' for `textDocument/linkedEditingRange'" 119 (interactive) 120 (require 'evil-multiedit) 121 (when (fboundp 'ahs-clear) (ahs-clear)) 122 (setq evil-multiedit--dont-recall t) 123 (lsp-iedit-linked-ranges) 124 (evil-multiedit-mode +1)) 125 126 ;; evil-evil-state 127 128 ;;;###autoload 129 (defun lsp-evil-state-highlights () 130 "Start `iedit-mode'. for `textDocument/documentHighlight'" 131 (interactive "P") 132 (if (fboundp 'ahs-clear) (ahs-clear)) 133 (lsp-iedit-highlights) 134 (evil-iedit-state)) 135 136 ;;;###autoload 137 (defun lsp-evil-state-linked-ranges () 138 "Start `iedit-mode'. for `textDocument/linkedEditingRange'" 139 (interactive "P") 140 (if (fboundp 'ahs-clear) (ahs-clear)) 141 (lsp-iedit-linked-ranges) 142 (evil-iedit-state)) 143 144 145 146 (lsp-consistency-check lsp-iedit) 147 148 (provide 'lsp-iedit) 149 ;;; lsp-iedit.el ends here