From: Philip Kaludercic <philipk@posteo.net>
To: 60338@debbugs.gnu.org, "João Távora" <joaotavora@gmail.com>
Subject: bug#60338: [PATCH] Add option to present server changes as diffs
Date: Sun, 11 Jun 2023 21:33:40 +0000 [thread overview]
Message-ID: <877cs97kgb.fsf@posteo.net> (raw)
In-Reply-To: <87ilhy1dub.fsf@posteo.net> (Philip Kaludercic's message of "Mon, 26 Dec 2022 13:42:04 +0000")
[-- Attachment #1: Type: text/plain, Size: 156 bytes --]
The previous patch couldn't be applied onto master anymore, so I have
adjusted it and merged the user option into 'eglot-confirm-server-initiated-edits'.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Allow-for-LSP-edits-to-be-generated-as-diffs.patch --]
[-- Type: text/x-diff, Size: 6524 bytes --]
From 7263d821c2d217c5748965aad57df8c0311f7e95 Mon Sep 17 00:00:00 2001
From: Philip Kaludercic <philipk@posteo.net>
Date: Sun, 11 Jun 2023 23:18:12 +0200
Subject: [PATCH 1/2] Allow for LSP edits to be generated as diffs
* doc/misc/eglot.texi (Eglot Variables): Document the new behaviour.
* lisp/progmodes/eglot.el (eglot-confirm-server-initiated-edits): Add
new value 'diff'.
(eglot-execute): Check if 'eglot-confirm-server-initiated-edits' is
set to 'diff'.
(eglot--apply-workspace-edit): Respect the new 'diff' value.
(eglot-rename): Pass 'eglot-confirm-server-initiated-edits' instead of
just the value 'current-prefix-arg'. (Bug#60338)
---
doc/misc/eglot.texi | 6 ++--
lisp/progmodes/eglot.el | 62 +++++++++++++++++++++++++++++++----------
2 files changed, 51 insertions(+), 17 deletions(-)
diff --git a/doc/misc/eglot.texi b/doc/misc/eglot.texi
index 962e6c914ce..305feda43a6 100644
--- a/doc/misc/eglot.texi
+++ b/doc/misc/eglot.texi
@@ -833,9 +833,11 @@ Eglot Variables
@item eglot-confirm-server-initiated-edits
Various Eglot commands and code actions result in the language server
sending editing commands to Emacs. If this option's value is
-non-@code{nil} (the default), Eglot will ask for confirmation before
+@code{confirm} (the default), Eglot will ask for confirmation before
performing edits initiated by the server or edits whose scope affects
-buffers other than the one where the user initiated the request.
+buffers other than the one where the user initiated the request. If
+set to @code{diff}, Eglot will generate and display a diff to display
+the changes.
@item eglot-ignored-server-capabilities
This variable's value is a list of language server capabilities that
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index 7d5d786dea3..9c9c3152472 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -108,6 +108,7 @@
(require 'filenotify)
(require 'ert)
(require 'text-property-search nil t)
+(require 'diff)
;; These dependencies are also GNU ELPA core packages. Because of
;; bug#62576, since there is a risk that M-x package-install, despite
@@ -386,9 +387,14 @@ eglot-events-buffer-size
:type '(choice (const :tag "No limit" nil)
(integer :tag "Number of characters")))
(defcustom eglot-confirm-server-initiated-edits 'confirm
- "Non-nil if server-initiated edits should be confirmed with user."
+ "Control how server edits are applied.
+If set to `confirm', a prompt is presented to confirm server
+changes. If set to `diff', a buffer will pop up with changes
+that can be applied manually. If set to nil, modifications are
+made automatically."
:type '(choice (const :tag "Don't show confirmation prompt" nil)
+ (const :tag "Present as diffs in a buffer" diff)
(const :tag "Show confirmation prompt" confirm)))
(defcustom eglot-extend-to-xref nil
@@ -740,7 +746,8 @@ eglot-execute
(eglot--dcase action
(((Command)) (eglot--request server :workspace/executeCommand action))
(((CodeAction) edit command)
- (when edit (eglot--apply-workspace-edit edit))
+ (when edit
+ (eglot--apply-workspace-edit edit (eq eglot-confirm-server-initiated-edits t)))
(when command (eglot--request server :workspace/executeCommand command))))))
(cl-defgeneric eglot-initialization-options (server)
@@ -3408,18 +3415,43 @@ eglot--apply-workspace-edit
;; prefer documentChanges over changes.
(cl-loop for (uri edits) on changes by #'cddr
do (push (list (eglot--uri-to-path uri) edits) prepared)))
- (if (or confirm
- (cl-notevery #'find-buffer-visiting
- (mapcar #'car prepared)))
- (unless (y-or-n-p
+ (cond
+ ((eq confirm 'diff)
+ (with-current-buffer (get-buffer-create " *Changes*")
+ (buffer-disable-undo (current-buffer))
+ (let ((buffer-read-only t))
+ (diff-mode))
+ (let ((inhibit-read-only t)
+ (target (current-buffer)))
+ (erase-buffer)
+ (pcase-dolist (`(,path ,edits ,_) prepared)
+ (with-temp-buffer
+ (let ((diff (current-buffer)))
+ (with-temp-buffer
+ (insert-file-contents path)
+ (eglot--apply-text-edits edits)
+ (diff-no-select path (current-buffer)
+ nil t diff))
+ (with-current-buffer target
+ (insert-buffer-substring diff))))))
+ (setq-local buffer-read-only t)
+ (buffer-enable-undo (current-buffer))
+ (goto-char (point-min))
+ (pop-to-buffer (current-buffer))
+ (font-lock-ensure)))
+ ((and (or (eq confirm 'confirm)
+ (cl-find-if-not #'find-buffer-visiting prepared
+ :key #'car))
+ ;; Should the list of buffers be popped up temporarily in
+ ;; a buffer instead of resizing the minibufffer?
+ (not (y-or-n-p
(format "[eglot] Server wants to edit:\n %s\n Proceed? "
- (mapconcat #'identity (mapcar #'car prepared) "\n ")))
- (jsonrpc-error "User canceled server edit")))
- (cl-loop for edit in prepared
- for (path edits version) = edit
- do (with-current-buffer (find-file-noselect path)
- (eglot--apply-text-edits edits version))
- finally (eldoc) (eglot--message "Edit successful!")))))
+ (mapconcat #'identity (mapcar #'car prepared) "\n ")))))
+ (jsonrpc-error "User canceled server edit"))
+ ((cl-loop for (path edits version) in prepared
+ do (with-current-buffer (find-file-noselect path)
+ (eglot--apply-text-edits edits version))
+ finally (eldoc) (eglot--message "Edit successful!")))))))
(defun eglot-rename (newname)
"Rename the current symbol to NEWNAME."
@@ -3434,7 +3466,7 @@ eglot-rename
(eglot--request (eglot--current-server-or-lose)
:textDocument/rename `(,@(eglot--TextDocumentPositionParams)
:newName ,newname))
- current-prefix-arg))
+ (and current-prefix-arg eglot-confirm-server-initiated-edits)))
(defun eglot--region-bounds ()
"Region bounds if active, else bounds of things at point."
--
2.39.2
[-- Attachment #3: Type: text/plain, Size: 183 bytes --]
In addition to that, here is a cheap command that would allow for a
patch to be applied with a single command. I've bound it to C-c C-x,
but perhaps there is a more intuitive key?
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0002-Add-command-to-apply-an-entire-diff-at-once.patch --]
[-- Type: text/x-diff, Size: 1351 bytes --]
From 1cf6f09318860a8232f5850c0d1ca497d8c621f9 Mon Sep 17 00:00:00 2001
From: Philip Kaludercic <philipk@posteo.net>
Date: Sun, 11 Jun 2023 23:30:03 +0200
Subject: [PATCH 2/2] Add command to apply an entire diff at once
* lisp/vc/diff-mode.el (diff-mode-map): Bind 'diff-apply-everything'.
(diff-apply-everything): Add new command.
---
lisp/vc/diff-mode.el | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el
index d776375d681..d81f0af365e 100644
--- a/lisp/vc/diff-mode.el
+++ b/lisp/vc/diff-mode.el
@@ -216,6 +216,7 @@ diff-mode-map
"C-x 4 A" #'diff-add-change-log-entries-other-window
;; Misc operations.
"C-c C-a" #'diff-apply-hunk
+ "C-c C-x" #'diff-apply-everything
"C-c C-e" #'diff-ediff-patch
"C-c C-n" #'diff-restrict-view
"C-c C-s" #'diff-split-hunk
@@ -2033,6 +2034,16 @@ diff-apply-hunk
(when diff-advance-after-apply-hunk
(diff-hunk-next))))))
+(defun diff-apply-everything ()
+ "Apply the entire diff."
+ (interactive)
+ (save-excursion
+ (goto-char (point-min))
+ (while (let ((inhibit-message t)
+ (start (point)))
+ (diff-hunk-next)
+ (/= start (point)))
+ (diff-apply-hunk))))
(defun diff-test-hunk (&optional reverse)
"See whether it's possible to apply the current hunk.
--
2.39.2
[-- Attachment #5: Type: text/plain, Size: 774 bytes --]
Philip Kaludercic <philipk@posteo.net> writes:
> X-CC-Debbugs:
>
> I'd like to propose adding an option that makes server modifications by
> Eglot less invasive. The current behaviour is to make the changes
> directly in a buffer and open the remaining files to make the
> modifications in those as well (?). If `eglot-use-diffs' is enabled,
> all confirmations are prepared as patches in a pop-up buffer that the
> user can review and apply at will. To my knowledge there is no general
> `diff-apply-hunk' that will apply all the changes from a buffer, but
> that is a separate issue that can be fixed in a separate patch.
>
> (Note, I'm still testing emacs-29, so the patch was developed on that
> branch. But it should be applied to master)
--
Philip Kaludercic
next prev parent reply other threads:[~2023-06-11 21:33 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-12-26 13:42 bug#60338: [PATCH] Add option to present server changes as diffs Philip Kaludercic
2022-12-29 0:01 ` Yuan Fu
2022-12-29 14:28 ` Philip Kaludercic
2022-12-29 14:36 ` João Távora
2022-12-29 14:39 ` Philip Kaludercic
2022-12-30 13:13 ` João Távora
2022-12-30 15:09 ` Philip Kaludercic
2023-01-04 20:56 ` Felician Nemeth
2023-06-09 7:55 ` Philip Kaludercic
2023-06-11 21:33 ` Philip Kaludercic [this message]
2023-06-12 11:56 ` Eli Zaretskii
2023-06-12 12:35 ` Philip Kaludercic
2023-06-12 12:52 ` Eli Zaretskii
2023-06-12 13:29 ` Philip Kaludercic
2023-06-12 13:41 ` Eli Zaretskii
2023-06-13 21:34 ` Philip Kaludercic
2023-06-14 6:00 ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-06-14 11:27 ` Philip Kaludercic
2023-06-18 11:38 ` Philip Kaludercic
2023-06-18 15:18 ` João Távora
2023-06-18 22:37 ` João Távora
2023-06-24 16:53 ` Philip Kaludercic
2023-09-01 0:06 ` João Távora
2023-09-01 5:18 ` Philip Kaludercic
2023-09-01 21:12 ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-01 21:19 ` João Távora
2023-09-01 22:01 ` João Távora
2023-09-02 6:13 ` Eshel Yaron via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-09-02 9:55 ` João Távora
2023-09-07 1:00 ` Dmitry Gutov
2023-09-07 6:28 ` Juri Linkov
2023-09-07 12:41 ` Dmitry Gutov
2023-09-07 12:45 ` Dmitry Gutov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=877cs97kgb.fsf@posteo.net \
--to=philipk@posteo.net \
--cc=60338@debbugs.gnu.org \
--cc=joaotavora@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.