]> git.eshelyaron.com Git - emacs.git/commitdiff
eglot.el: Require `track-changes` unconditionally
authorStefan Monnier <monnier@iro.umontreal.ca>
Sun, 5 May 2024 21:23:29 +0000 (17:23 -0400)
committerEshel Yaron <me@eshelyaron.com>
Mon, 6 May 2024 16:56:19 +0000 (18:56 +0200)
* lisp/emacs-lisp/track-changes.el: Bump version.

* lisp/progmodes/eglot.el: Require `track-changes` unconditionally.
(Package-Requires:): Add `track-changes`.
(eglot--track-changes-signal, eglot--signal-textDocument/didChange)
(eglot--managed-mode): Remove non-track-changes alternative code.
(eglot--before-change, eglot--after-change): Delete functions.

(cherry picked from commit 44036b32ba398cf284320285b60be35874b6eea5)

lisp/emacs-lisp/track-changes.el
lisp/progmodes/eglot.el

index 6562cc7eb86b4b11ec868a27cf66c7ffe44a75af..2824a70586d4d5a804907e4a063d5ece8d3637e9 100644 (file)
@@ -3,7 +3,7 @@
 ;; Copyright (C) 2024  Free Software Foundation, Inc.
 
 ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
-;; Version: 1.1
+;; Version: 1.2
 ;; Package-Requires: ((emacs "24"))
 
 ;; This file is part of GNU Emacs.
 ;;                     id (lambda (beg end before)
 ;;                          ..DO THE THING..))))))))
 
+;;; News:
+
+;; Since v1.1:
+;;
+;; - New function `track-changes-inconsistent-state-p'.
+
 ;;; Code:
 
 ;; Random ideas:
index 89e0aa63db40a001431b7631726c78e6bec68a22..1f2e31ed0facb785959a6729fe65722b430391ee 100644 (file)
@@ -7,7 +7,7 @@
 ;; Maintainer: João Távora <joaotavora@gmail.com>
 ;; URL: https://github.com/joaotavora/eglot
 ;; Keywords: convenience, languages
-;; Package-Requires: ((emacs "26.3") (jsonrpc "1.0.24") (flymake "1.2.1") (project "0.9.8") (xref "1.6.2") (eldoc "1.14.0") (seq "2.23") (external-completion "0.1") (compat "27.1"))
+;; Package-Requires: ((emacs "26.3") (compat "27.1") (eldoc "1.14.0") (external-completion "0.1") (flymake "1.2.1") (jsonrpc "1.0.24") (project "0.9.8") (seq "2.23") (track-changes "1.2") (xref "1.6.2"))
 
 ;; This is a GNU ELPA :core package.  Avoid adding functionality
 ;; that is not available in the version of Emacs recorded above or any
 (require 'pcase)
 (require 'compile) ; for some faces
 (require 'warnings)
-(eval-when-compile
-  (require 'subr-x))
 (require 'filenotify)
 (require 'ert)
 (require 'text-property-search nil t)
 (require 'diff-mode)
 (require 'diff)
-(require 'track-changes nil t)
+(require 'track-changes)
 (require 'compat)
 
 ;; These dependencies are also GNU ELPA core packages.  Because of
     ;; the loaded file is not the one that should have been loaded.
     (mapc reload '(project flymake xref jsonrpc external-completion))))
 
+;; Keep the eval-when-compile requires at the end, in case it's already been
+;; required unconditionally by some earlier `require'.
+(eval-when-compile (require 'subr-x))
+
 ;; forward-declare, but don't require (Emacs 28 doesn't seem to care)
 (defvar markdown-fontify-code-blocks-natively)
 (defvar company-backends)
@@ -1983,13 +1985,10 @@ Use `eglot-managed-p' to determine if current buffer is managed.")
       ("utf-8"
        (eglot--setq-saving eglot-current-linepos-function #'eglot-utf-8-linepos)
        (eglot--setq-saving eglot-move-to-linepos-function #'eglot-move-to-utf-8-linepos)))
-    (if (fboundp 'track-changes-register)
-        (unless eglot--track-changes
-          (setq eglot--track-changes
-           (track-changes-register
-            #'eglot--track-changes-signal :disjoint t)))
-      (add-hook 'after-change-functions #'eglot--after-change nil t)
-      (add-hook 'before-change-functions #'eglot--before-change nil t))
+    (unless eglot--track-changes
+      (setq eglot--track-changes
+            (track-changes-register
+             #'eglot--track-changes-signal :disjoint t)))
     (add-hook 'kill-buffer-hook #'eglot--managed-mode-off nil t)
     ;; Prepend "didClose" to the hook after the "nonoff", so it will run first
     (add-hook 'kill-buffer-hook #'eglot--signal-textDocument/didClose nil t)
@@ -2027,8 +2026,6 @@ Use `eglot-managed-p' to determine if current buffer is managed.")
     (when eglot--track-changes
       (track-changes-unregister eglot--track-changes)
       (setq eglot--track-changes nil))
-    (remove-hook 'after-change-functions #'eglot--after-change t)
-    (remove-hook 'before-change-functions #'eglot--before-change t)
     (remove-hook 'kill-buffer-hook #'eglot--managed-mode-off t)
     (remove-hook 'kill-buffer-hook #'eglot--signal-textDocument/didClose t)
     (remove-hook 'before-revert-hook #'eglot--signal-textDocument/didClose t)
@@ -2608,7 +2605,7 @@ buffer."
           `(:triggerKind 2 :triggerCharacter ,trigger) `(:triggerKind 1)))))
 
 (defvar-local eglot--recent-changes nil
-  "Recent buffer changes as collected by `eglot--before-change'.")
+  "Recent buffer changes as collected by `eglot--track-changes-fetch'.")
 
 (cl-defmethod jsonrpc-connection-ready-p ((_server eglot-lsp-server) _what)
   "Tell if SERVER is ready for WHAT in current buffer."
@@ -2616,56 +2613,9 @@ buffer."
 
 (defvar-local eglot--change-idle-timer nil "Idle timer for didChange signals.")
 
-(defun eglot--before-change (beg end)
-  "Hook onto `before-change-functions' with BEG and END."
-  (when (listp eglot--recent-changes)
-    ;; Records BEG and END, crucially convert them into LSP
-    ;; (line/char) positions before that information is lost (because
-    ;; the after-change thingy doesn't know if newlines were
-    ;; deleted/added).  Also record markers of BEG and END
-    ;; (github#259)
-    (push `(,(eglot--pos-to-lsp-position beg)
-            ,(eglot--pos-to-lsp-position end)
-            (,beg . ,(copy-marker beg nil))
-            (,end . ,(copy-marker end t)))
-          eglot--recent-changes)))
-
 (defvar eglot--document-changed-hook '(eglot--signal-textDocument/didChange)
   "Internal hook for doing things when the document changes.")
 
-(defun eglot--after-change (beg end pre-change-length)
-  "Hook onto `after-change-functions'.
-Records BEG, END and PRE-CHANGE-LENGTH locally."
-  (cl-incf eglot--versioned-identifier)
-  (pcase (car-safe eglot--recent-changes)
-    (`(,lsp-beg ,lsp-end
-                (,b-beg . ,b-beg-marker)
-                (,b-end . ,b-end-marker))
-     ;; github#259 and github#367: with `capitalize-word' & friends,
-     ;; `before-change-functions' records the whole word's `b-beg' and
-     ;; `b-end'.  Similarly, when `fill-paragraph' coalesces two
-     ;; lines, `b-beg' and `b-end' mark end of first line and end of
-     ;; second line, resp.  In both situations, `beg' and `end'
-     ;; received here seemingly contradict that: they will differ by 1
-     ;; and encompass the capitalized character or, in the coalescing
-     ;; case, the replacement of the newline with a space.  We keep
-     ;; both markers and positions to detect and correct this.  In
-     ;; this specific case, we ignore `beg', `len' and
-     ;; `pre-change-len' and send richer information about the region
-     ;; from the markers.  I've also experimented with doing this
-     ;; unconditionally but it seems to break when newlines are added.
-     (if (and (= b-end b-end-marker) (= b-beg b-beg-marker)
-              (or (/= beg b-beg) (/= end b-end)))
-         (setcar eglot--recent-changes
-                 `(,lsp-beg ,lsp-end ,(- b-end-marker b-beg-marker)
-                            ,(buffer-substring-no-properties b-beg-marker
-                                                             b-end-marker)))
-       (setcar eglot--recent-changes
-               `(,lsp-beg ,lsp-end ,pre-change-length
-                          ,(buffer-substring-no-properties beg end)))))
-    (_ (setf eglot--recent-changes :emacs-messup)))
-  (eglot--track-changes-signal nil))
-
 (defun eglot--track-changes-fetch (id)
   (if (eq eglot--recent-changes :pending) (setq eglot--recent-changes nil))
   (track-changes-fetch
@@ -2705,15 +2655,14 @@ Records BEG, END and PRE-CHANGE-LENGTH locally."
          (lambda (buf)
            (eglot--when-live-buffer buf
              (when eglot--managed-mode
-               (if (and (fboundp 'track-changes-inconsistent-state-p)
-                        (track-changes-inconsistent-state-p))
+               (if (track-changes-inconsistent-state-p)
                    ;; Not a good time (e.g. in the middle of Quail thingy,
                    ;; bug#70541): reschedule for the next idle period.
-                (eglot--add-one-shot-hook
-                 'post-command-hook
-                 (lambda ()
-                   (eglot--when-live-buffer buf
-                     (eglot--track-changes-signal id))))
+                   (eglot--add-one-shot-hook
+                    'post-command-hook
+                    (lambda ()
+                      (eglot--when-live-buffer buf
+                        (eglot--track-changes-signal id))))
                  (run-hooks 'eglot--document-changed-hook)
                  (setq eglot--change-idle-timer nil)))))
          (current-buffer))))
@@ -2820,8 +2769,7 @@ When called interactively, use the currently active server"
 
 (defun eglot--signal-textDocument/didChange ()
   "Send textDocument/didChange to server."
-  (when eglot--track-changes
-    (eglot--track-changes-fetch eglot--track-changes))
+  (eglot--track-changes-fetch eglot--track-changes)
   (when eglot--recent-changes
     (let* ((server (eglot--current-server-or-lose))
            (sync-capability (eglot-server-capable :textDocumentSync))
@@ -2839,12 +2787,6 @@ When called interactively, use the currently active server"
                               (buffer-substring-no-properties (point-min)
                                                               (point-max)))))
           (cl-loop for (beg end len text) in (reverse eglot--recent-changes)
-                   ;; github#259: `capitalize-word' and commands based
-                   ;; on `casify_region' will cause multiple duplicate
-                   ;; empty entries in `eglot--before-change' calls
-                   ;; without an `eglot--after-change' reciprocal.
-                   ;; Weed them out here.
-                   when (numberp len) ;FIXME: Not needed with `track-changes'.
                    vconcat `[,(list :range `(:start ,beg :end ,end)
                                     :rangeLength len :text text)]))))
       (setq eglot--recent-changes nil)