150 lines
5.2 KiB
EmacsLisp
150 lines
5.2 KiB
EmacsLisp
|
;;; lsp-iedit.el --- `iedit' integration -*- lexical-binding: t -*-
|
|||
|
;;
|
|||
|
;; Copyright (C) 2020 emacs-lsp maintainers
|
|||
|
;;
|
|||
|
;; This program is free software; you can redistribute it and/or modify
|
|||
|
;; it under the terms of the GNU General Public License as published by
|
|||
|
;; the Free Software Foundation, either version 3 of the License, or
|
|||
|
;; (at your option) any later version.
|
|||
|
|
|||
|
;; This program is distributed in the hope that it will be useful,
|
|||
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
|
;; GNU General Public License for more details.
|
|||
|
|
|||
|
;; You should have received a copy of the GNU General Public License
|
|||
|
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
|
|||
|
;;; Commentary:
|
|||
|
|
|||
|
;; This module provides features that allow starting `iedit' on various
|
|||
|
;; different lsp-based, semantic units (like documentHighlights, and
|
|||
|
;; linkedEditingRanges in the future).
|
|||
|
|
|||
|
;;; Code:
|
|||
|
|
|||
|
(require 'lsp-mode)
|
|||
|
(require 'dash)
|
|||
|
|
|||
|
(declare-function iedit-make-occurrence-overlay "iedit-lib" (begin end))
|
|||
|
(declare-function iedit-start-buffering "iedit-lib" ())
|
|||
|
(declare-function iedit-lib-start "iedit-lib" (mode-exit-func))
|
|||
|
(declare-function iedit-done "iedit" ())
|
|||
|
(declare-function evil-multiedit-mode "evil-multiedit" (mode))
|
|||
|
(declare-function evil-iedit-state "evil-iedit-state" ())
|
|||
|
|
|||
|
(defvar iedit-mode)
|
|||
|
(defvar iedit-auto-buffering)
|
|||
|
(defvar iedit-occurrences-overlays)
|
|||
|
(defvar iedit-occurrence-keymap)
|
|||
|
(defvar iedit-mode-occurrence-keymap)
|
|||
|
(defvar evil-multiedit--dont-recall)
|
|||
|
|
|||
|
(defun lsp-iedit--on-ranges (ranges)
|
|||
|
"Start an `iedit' operation using RANGES.
|
|||
|
RANGES shall be a list of lsp-`&Range's. They can be acquired
|
|||
|
from various lsp protocol requests, e.g.
|
|||
|
`textDocument/documentHighlight', ...."
|
|||
|
(require 'iedit)
|
|||
|
(unless (seq-empty-p ranges)
|
|||
|
(mapc (-lambda ((&RangeToPoint :start :end))
|
|||
|
(push (iedit-make-occurrence-overlay start end)
|
|||
|
iedit-occurrences-overlays))
|
|||
|
ranges)
|
|||
|
;; See `iedit-start'; TODO: upstream this
|
|||
|
(setq iedit-occurrence-keymap iedit-mode-occurrence-keymap)
|
|||
|
(setq iedit-mode t)
|
|||
|
(when iedit-auto-buffering
|
|||
|
(iedit-start-buffering))
|
|||
|
(iedit-lib-start 'iedit-done)
|
|||
|
(run-hooks 'iedit-mode-hook)
|
|||
|
(add-hook 'before-revert-hook 'iedit-done nil t)
|
|||
|
(add-hook 'kbd-macro-termination-hook 'iedit-done nil t)
|
|||
|
(add-hook 'change-major-mode-hook 'iedit-done nil t)
|
|||
|
(add-hook 'iedit-aborting-hook 'iedit-done nil t)
|
|||
|
(message "%d occurrences of \"%s\""
|
|||
|
(seq-length ranges)
|
|||
|
(lsp--range-text (lsp-seq-first ranges)))))
|
|||
|
|
|||
|
;; iedit
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun lsp-iedit-highlights ()
|
|||
|
"Start an `iedit' operation on the documentHighlights at point.
|
|||
|
This can be used as a primitive `lsp-rename' replacement if the
|
|||
|
language server doesn't support renaming.
|
|||
|
|
|||
|
See also `lsp-enable-symbol-highlighting'."
|
|||
|
(interactive)
|
|||
|
(let ((highlights (lsp-request "textDocument/documentHighlight"
|
|||
|
(lsp--text-document-position-params)))
|
|||
|
(-compare-fn (-lambda ((&Location :range (&Range :start l-start :end l-end))
|
|||
|
(&Location :range (&Range :start r-start :end r-end)))
|
|||
|
(and (lsp--position-equal l-start r-start)
|
|||
|
(lsp--position-equal l-end r-end)))))
|
|||
|
(lsp-iedit--on-ranges (mapcar #'lsp:document-highlight-range (-distinct highlights)))))
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun lsp-iedit-linked-ranges ()
|
|||
|
"Start an `iedit' for `textDocument/linkedEditingRange'"
|
|||
|
(interactive)
|
|||
|
(unless (lsp-feature? "textDocument/linkedEditingRange")
|
|||
|
(user-error "`textDocument/linkedEditingRange' is not supported by current server"))
|
|||
|
|
|||
|
(-> (lsp-request "textDocument/linkedEditingRange" (lsp--text-document-position-params))
|
|||
|
(lsp:linked-editing-ranges-ranges)
|
|||
|
(or (user-error "No editing ranges found"))
|
|||
|
(lsp-iedit--on-ranges)))
|
|||
|
|
|||
|
|
|||
|
;; evil-multi-edit
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun lsp-evil-multiedit-highlights ()
|
|||
|
"Start an `evil-multiedit' operation on the documentHighlights at point.
|
|||
|
This can be used as a primitive `lsp-rename' replacement if the
|
|||
|
language server doesn't support renaming.
|
|||
|
|
|||
|
See also `lsp-enable-symbol-highlighting'."
|
|||
|
(interactive)
|
|||
|
(require 'evil-multiedit)
|
|||
|
(when (fboundp 'ahs-clear) (ahs-clear))
|
|||
|
(setq evil-multiedit--dont-recall t)
|
|||
|
(lsp-iedit-highlights)
|
|||
|
(evil-multiedit-mode +1))
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun lsp-evil-multiedit-linked-ranges ()
|
|||
|
"Start an `evil-multiedit' for `textDocument/linkedEditingRange'"
|
|||
|
(interactive)
|
|||
|
(require 'evil-multiedit)
|
|||
|
(when (fboundp 'ahs-clear) (ahs-clear))
|
|||
|
(setq evil-multiedit--dont-recall t)
|
|||
|
(lsp-iedit-linked-ranges)
|
|||
|
(evil-multiedit-mode +1))
|
|||
|
|
|||
|
;; evil-evil-state
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun lsp-evil-state-highlights ()
|
|||
|
"Start `iedit-mode'. for `textDocument/documentHighlight'"
|
|||
|
(interactive "P")
|
|||
|
(if (fboundp 'ahs-clear) (ahs-clear))
|
|||
|
(lsp-iedit-highlights)
|
|||
|
(evil-iedit-state))
|
|||
|
|
|||
|
;;;###autoload
|
|||
|
(defun lsp-evil-state-linked-ranges ()
|
|||
|
"Start `iedit-mode'. for `textDocument/linkedEditingRange'"
|
|||
|
(interactive "P")
|
|||
|
(if (fboundp 'ahs-clear) (ahs-clear))
|
|||
|
(lsp-iedit-linked-ranges)
|
|||
|
(evil-iedit-state))
|
|||
|
|
|||
|
|
|||
|
|
|||
|
(lsp-consistency-check lsp-iedit)
|
|||
|
|
|||
|
(provide 'lsp-iedit)
|
|||
|
;;; lsp-iedit.el ends here
|