emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 82f45b95806 1/2: Eglot: handle unsaved buffers in new eglot--prop


From: João Távora
Subject: master 82f45b95806 1/2: Eglot: handle unsaved buffers in new eglot--propose-changes-as-diff
Date: Fri, 1 Sep 2023 17:58:00 -0400 (EDT)

branch: master
commit 82f45b958063e1128f183f4a54628428408910dc
Author: João Távora <joaotavora@gmail.com>
Commit: João Távora <joaotavora@gmail.com>

    Eglot: handle unsaved buffers in new eglot--propose-changes-as-diff
    
    * lisp/progmodes/eglot.el (eglot--confirm-server-edits): Add docstring.
    (eglot--propose-changes-as-diff): Rework.  Handle unsaved buffers.
    (eglot--apply-workspace-edit): Rework.
---
 lisp/progmodes/eglot.el | 62 +++++++++++++++++++++++++++++++++----------------
 1 file changed, 42 insertions(+), 20 deletions(-)

diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index 8d95019c3ed..810c6cb4638 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -3459,6 +3459,10 @@ If SILENT, don't echo progress in mode-line."
         (progress-reporter-done reporter)))))
 
 (defun eglot--confirm-server-edits (origin _prepared)
+  "Helper for `eglot--apply-workspace-edit.
+ORIGIN is a symbol designating a command.  Reads the
+`eglot-confirm-server-edits' user option and returns a symbol
+like `diff', `summary' or nil."
   (let (v)
     (cond ((symbolp eglot-confirm-server-edits) eglot-confirm-server-edits)
           ((setq v (assoc origin eglot-confirm-server-edits)) (cdr v))
@@ -3466,7 +3470,9 @@ If SILENT, don't echo progress in mode-line."
 
 (defun eglot--propose-changes-as-diff (prepared)
   "Helper for `eglot--apply-workspace-edit'.
-PREPARED is a list ((FILENAME EDITS VERSION)...)."
+Goal is to popup a `diff-mode' buffer containing all the changes
+of PREPARED, ready to apply with C-c C-a.  PREPARED is a
+list ((FILENAME EDITS VERSION)...)."
   (with-current-buffer (get-buffer-create "*EGLOT proposed server changes*")
     (buffer-disable-undo (current-buffer))
     (let ((buffer-read-only t))
@@ -3476,12 +3482,30 @@ PREPARED is a list ((FILENAME EDITS VERSION)...)."
       (erase-buffer)
       (pcase-dolist (`(,path ,edits ,_) prepared)
         (with-temp-buffer
-          (let ((diff (current-buffer)))
+          (let* ((diff (current-buffer))
+                 (existing-buf (find-buffer-visiting path))
+                 (existing-buf-label (prin1-to-string existing-buf)))
+            ;; `existing-buf' might be an unsaved buffer, so we do
+            ;; this complicated little dance to diff it with a
+            ;; temporary file with the proposed changes applied.
             (with-temp-buffer
-              (insert-file-contents path)
-              (eglot--apply-text-edits edits)
-              (diff-no-select path (current-buffer)
-                              nil t diff))
+              (if existing-buf
+                  (let ((temp (current-buffer)))
+                    (with-current-buffer existing-buf
+                      (copy-to-buffer temp (point-min) (point-max))))
+                (insert-file-contents path))
+              (eglot--apply-text-edits edits nil t)
+              (diff-no-select (or existing-buf path) (current-buffer)
+                              nil t diff)
+              (when existing-buf
+                ;; Here we have to pretend the label of the unsaved
+                ;; buffer is the actual file, just so that we can
+                ;; diff-apply without troubles.  If there's a better
+                ;; way, it probably involves changes to `diff.el'.
+                (with-current-buffer diff
+                  (goto-char (point-min))
+                  (while (search-forward existing-buf-label nil t)
+                    (replace-match (buffer-file-name existing-buf))))))
             (with-current-buffer target
               (insert-buffer-substring diff))))))
     (setq-local buffer-read-only t)
@@ -3491,7 +3515,7 @@ PREPARED is a list ((FILENAME EDITS VERSION)...)."
     (font-lock-ensure)))
 
 (defun eglot--apply-workspace-edit (wedit origin)
-  "Apply the workspace edit WEDIT.
+  "Apply (or offer to apply) the workspace edit WEDIT.
 ORIGIN is a symbol designating the command that originated this
 edit proposed by the server."
   (eglot--dbind ((WorkspaceEdit) changes documentChanges) wedit
@@ -3510,16 +3534,15 @@ edit proposed by the server."
       (cl-flet ((notevery-visited-p ()
                   (cl-notevery #'find-buffer-visiting
                                (mapcar #'car prepared)))
-                (prompt ()
-                  (unless (y-or-n-p
-                           (format "[eglot] Server wants to edit:\n%sProceed? "
-                                   (cl-loop
-                                    for (f eds _) in prepared
-                                    concat (format
-                                            "  %s (%d change%s)\n"
-                                            f (length eds)
-                                            (if (> (length eds) 1) "s" "")))))
-                    (jsonrpc-error "User canceled server edit")))
+                (accept-p ()
+                  (y-or-n-p
+                   (format "[eglot] Server wants to edit:\n%sProceed? "
+                           (cl-loop
+                            for (f eds _) in prepared
+                            concat (format
+                                    "  %s (%d change%s)\n"
+                                    f (length eds)
+                                    (if (> (length eds) 1) "s" ""))))))
                 (apply ()
                   (cl-loop for edit in prepared
                    for (path edits version) = edit
@@ -3531,10 +3554,9 @@ edit proposed by the server."
            ((or (eq decision 'diff)
                 (and (eq decision 'maybe-diff) (notevery-visited-p)))
             (eglot--propose-changes-as-diff prepared))
-           ((or (eq decision 'summary)
+           ((or (memq decision '(t summary))
                 (and (eq decision 'maybe-summary) (notevery-visited-p)))
-            (prompt)
-            (apply))
+            (when (accept-p) (apply)))
            (t
             (apply))))))))
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]