From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Philip Kaludercic Newsgroups: gmane.emacs.bugs Subject: bug#60338: [PATCH] Add option to present server changes as diffs Date: Sun, 11 Jun 2023 21:33:40 +0000 Message-ID: <877cs97kgb.fsf@posteo.net> References: <87ilhy1dub.fsf@posteo.net> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="13576"; mail-complaints-to="usenet@ciao.gmane.io" To: 60338@debbugs.gnu.org, =?UTF-8?Q?Jo=C3=A3o_?= =?UTF-8?Q?T=C3=A1vora?= Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sun Jun 11 23:34:25 2023 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1q8Shc-0003Kn-GG for geb-bug-gnu-emacs@m.gmane-mx.org; Sun, 11 Jun 2023 23:34:24 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1q8ShI-0008Fz-M8; Sun, 11 Jun 2023 17:34:04 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1q8ShG-0008Fr-Ro for bug-gnu-emacs@gnu.org; Sun, 11 Jun 2023 17:34:02 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1q8ShG-0001ZP-Hj for bug-gnu-emacs@gnu.org; Sun, 11 Jun 2023 17:34:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1q8ShG-0008Cc-DO for bug-gnu-emacs@gnu.org; Sun, 11 Jun 2023 17:34:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Philip Kaludercic Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 11 Jun 2023 21:34:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 60338 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 60338-submit@debbugs.gnu.org id=B60338.168651923131506 (code B ref 60338); Sun, 11 Jun 2023 21:34:02 +0000 Original-Received: (at 60338) by debbugs.gnu.org; 11 Jun 2023 21:33:51 +0000 Original-Received: from localhost ([127.0.0.1]:37787 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1q8Sh4-0008C5-CU for submit@debbugs.gnu.org; Sun, 11 Jun 2023 17:33:50 -0400 Original-Received: from mout01.posteo.de ([185.67.36.65]:48001) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1q8Sh1-0008Bo-2t for 60338@debbugs.gnu.org; Sun, 11 Jun 2023 17:33:48 -0400 Original-Received: from submission (posteo.de [185.67.36.169]) by mout01.posteo.de (Postfix) with ESMTPS id 52584240028 for <60338@debbugs.gnu.org>; Sun, 11 Jun 2023 23:33:41 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=posteo.net; s=2017; t=1686519221; bh=0oMNeE9uEwHNkkXEXFBHLU5AFc5P6wlqT7QzDy4R824=; h=From:To:Subject:Autocrypt:Date:Message-ID:MIME-Version:From; b=p79NsalpTgXw+kdrG0Pp6+uuL49h4H4lKRfMgSqy2k74DCFojApNTFIJjyqcaG2Yc lcsh33HGD5tUTI8sTA/TbRl9TpzSKSFCYRih3/RRq4sVev3GcnlndphUGS0Yt6ct2h kNnvPCEwptd9ONUVlYd58LvvDOVMAZMsdjFAqAWyRuO2OgGdbFb5WmhysL/udja5eS oCJ9spIKKVgPEJSGywWl3QWiTU5K79ORRiXK9L1qu4nm+O5upcmFOm0Fy+imNcaoZF OOR9yVkGy6CjSrHYn2WJYtWqRrXUQ+Pqcn0twXwD2zjXQCwvx5T5l7uwGq/JejX4Az WhMG0QgfwvfLw== Original-Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4QfSjw6zszz6tmv; Sun, 11 Jun 2023 23:33:40 +0200 (CEST) In-Reply-To: <87ilhy1dub.fsf@posteo.net> (Philip Kaludercic's message of "Mon, 26 Dec 2022 13:42:04 +0000") Autocrypt: addr=philipk@posteo.net; keydata= mDMEZBBQQhYJKwYBBAHaRw8BAQdAHJuofBrfqFh12uQu0Yi7mrl525F28eTmwUDflFNmdui0QlBo aWxpcCBLYWx1ZGVyY2ljIChnZW5lcmF0ZWQgYnkgYXV0b2NyeXB0LmVsKSA8cGhpbGlwa0Bwb3N0 ZW8ubmV0PoiWBBMWCAA+FiEEDg7HY17ghYlni8XN8xYDWXahwukFAmQQUEICGwMFCQHhM4AFCwkI BwIGFQoJCAsCBBYCAwECHgECF4AACgkQ8xYDWXahwulikAEA77hloUiSrXgFkUVJhlKBpLCHUjA0 mWZ9j9w5d08+jVwBAK6c4iGP7j+/PhbkxaEKa4V3MzIl7zJkcNNjHCXmvFcEuDgEZBBQQhIKKwYB BAGXVQEFAQEHQI5NLiLRjZy3OfSt1dhCmFyn+fN/QKELUYQetiaoe+MMAwEIB4h+BBgWCAAmFiEE Dg7HY17ghYlni8XN8xYDWXahwukFAmQQUEICGwwFCQHhM4AACgkQ8xYDWXahwukm+wEA8cml4JpK NeAu65rg+auKrPOP6TP/4YWRCTIvuYDm0joBALw98AMz7/qMHvSCeU/hw9PL6u6R2EScxtpKnWof z4oM X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:263260 Archived-At: --=-=-= Content-Type: text/plain 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'. --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-Allow-for-LSP-edits-to-be-generated-as-diffs.patch >From 7263d821c2d217c5748965aad57df8c0311f7e95 Mon Sep 17 00:00:00 2001 From: Philip Kaludercic 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 --=-=-= Content-Type: text/plain 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? --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0002-Add-command-to-apply-an-entire-diff-at-once.patch >From 1cf6f09318860a8232f5850c0d1ca497d8c621f9 Mon Sep 17 00:00:00 2001 From: Philip Kaludercic 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 --=-=-= Content-Type: text/plain Philip Kaludercic 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 --=-=-=--