From: João Távora Date: Tue, 8 May 2018 12:37:35 +0000 (+0100) Subject: Support textdocument/rename X-Git-Tag: emacs-29.0.90~1616^2~524^2~4^2~610 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=ca678a54c8f2634c6c68f26f25837777b1211e19;p=emacs.git Support textdocument/rename * README.md: Mention rename support. * eglot.el (eglot--uri-to-path): Handle uri hidden in keywords. (eglot--apply-text-edits): New helper. (eglot-rename): New interactive command. (eglot--client-capabilities): Add rename capability. --- diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index c5c99f2e78e..9ba87ef5bbc 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -199,6 +199,7 @@ CONTACT is as `eglot--contact'. Returns a process object." :definition `(:dynamicRegistration :json-false) :documentSymbol `(:dynamicRegistration :json-false) :documentHighlight `(:dynamicRegistration :json-false) + :rename `(:dynamicRegistration :json-false) :publishDiagnostics `(:relatedInformation :json-false)) :experimental (eglot--obj))) @@ -729,6 +730,7 @@ Meaning only return locally if successful, otherwise exit non-locally." (defun eglot--uri-to-path (uri) "Convert URI to a file path." + (when (keywordp uri) (setq uri (substring (symbol-name uri) 1))) (url-filename (url-generic-parse-url (url-unhex-string uri)))) (defconst eglot--kind-names @@ -1368,6 +1370,62 @@ DUMMY is ignored" entries)) (funcall oldfun))) +(defun eglot--apply-text-edits (uri edits proc &optional version) + "Apply the EDITS for buffer of URI and return it." + (let* ((path (eglot--uri-to-path uri)) + (buffer (and path + (find-file-noselect path)))) + (unless buffer + (eglot--error "Can't find `%s' to perform server edits")) + (with-current-buffer buffer + (unless (eq proc (eglot--current-process)) + (eglot--error "Buffer `%s' for `%s' isn't managed by %s" + (current-buffer) uri proc)) + (unless (or (not version) + (equal version eglot--versioned-identifier)) + (eglot--error "Edits on `%s' require version %d, you have %d" + uri version eglot--versioned-identifier)) + (eglot--mapply + (eglot--lambda (&key range newText) + (save-restriction + (widen) + (save-excursion + (let ((start (eglot--lsp-position-to-point (plist-get range :start)))) + (goto-char start) + (delete-region start + (eglot--lsp-position-to-point (plist-get range :end))) + (insert newText))))) + edits) + (eglot--message "%s: %s edits" (current-buffer) (length edits))) + buffer)) + +(defun eglot-rename (newname) + "Rename the current symbol to NEWNAME." + (interactive + (list + (read-from-minibuffer (format "Rename `%s' to: " (symbol-at-point))))) + (unless (eglot--server-capable :renameProvider) + (eglot--error "Server can't rename!")) + (let* ((proc (eglot--current-process-or-lose)) + (workspace-edit + (eglot--sync-request proc + :textDocument/rename + (append + (eglot--current-buffer-TextDocumentPositionParams) + (eglot--obj :newName newname)))) + performed) + (cl-destructuring-bind (&key changes documentChanges) + workspace-edit + (cl-loop for change on documentChanges + do (push + (cl-destructuring-bind (&key textDocument edits) change + (cl-destructuring-bind (&key uri version) textDocument + (eglot--apply-text-edits uri edits proc version))) + performed)) + (cl-loop for (uri edits) on changes by #'cddr + do (push (eglot--apply-text-edits uri edits proc) + performed))))) + ;;; Dynamic registration ;;;