[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/elpa 9665a3e 051/139: Fix textDocument/didChange
From: |
João Távora |
Subject: |
[elpa] externals/elpa 9665a3e 051/139: Fix textDocument/didChange |
Date: |
Mon, 14 May 2018 09:53:33 -0400 (EDT) |
branch: externals/elpa
commit 9665a3eec28fcf1bc52542cbe5e99d16f4fbc03a
Author: João Távora <address@hidden>
Commit: João Távora <address@hidden>
Fix textDocument/didChange
* eglot.el (eglot-editing-mode): Manage before-change-functions.
(eglot--recent-changes): Deleted.
(eglot--recent-before-changes): New var.
(eglot--recent-after-changes): Renamed from eglot--recent-changes.
(eglot--pos-to-lsp-position, eglot--before-change): New helpers.
(eglot--after-change): Rework.
(eglot--signal-textDocument/didChange): Rework.
---
eglot.el | 98 +++++++++++++++++++++++++++++++++++++++++++---------------------
1 file changed, 66 insertions(+), 32 deletions(-)
diff --git a/eglot.el b/eglot.el
index 469d3f7..1bf0d56 100644
--- a/eglot.el
+++ b/eglot.el
@@ -611,6 +611,7 @@ identifier. ERROR is non-nil if this is an error."
(eglot-editing-mode
(eglot-mode 1)
(add-hook 'after-change-functions 'eglot--after-change nil t)
+ (add-hook 'before-change-functions 'eglot--before-change nil t)
(add-hook 'flymake-diagnostic-functions 'eglot-flymake-backend nil t)
(add-hook 'kill-buffer-hook 'eglot--signal-textDocument/didClose nil t)
(flymake-mode 1)
@@ -620,6 +621,7 @@ identifier. ERROR is non-nil if this is an error."
(t
(remove-hook 'flymake-diagnostic-functions 'eglot-flymake-backend t)
(remove-hook 'after-change-functions 'eglot--after-change t)
+ (remove-hook 'before-change-functions 'eglot--before-change t)
(remove-hook 'kill-buffer-hook 'eglot--signal-textDocument/didClose t))))
(define-minor-mode eglot-mode
@@ -868,7 +870,9 @@ running. INTERACTIVE is t if called interactively."
(t
(eglot--message "OK so %s isn't visited" filename)))))
-(defvar eglot--recent-changes nil
+(defvar eglot--recent-before-changes nil
+ "List of recent changes as collected by `eglot--before-change'.")
+(defvar eglot--recent-after-changes nil
"List of recent changes as collected by `eglot--after-change'.")
(defvar-local eglot--versioned-identifier 0)
@@ -895,46 +899,76 @@ running. INTERACTIVE is t if called interactively."
(widen)
(buffer-substring-no-properties (point-min) (point-max))))))
-(defun eglot--after-change (start end length)
+(defun eglot--pos-to-lsp-position (pos)
+ "Convert point POS to LSP position."
+ (save-excursion
+ (eglot--obj :line
+ ;; F!@(#*&#$)CKING OFF-BY-ONE
+ (1- (line-number-at-pos pos t))
+ :character
+ (- (goto-char pos)
+ (line-beginning-position)))))
+
+(defun eglot--before-change (start end)
+ "Hook onto `before-change-functions'.
+Records START 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)"
+ (push (list (eglot--pos-to-lsp-position start)
+ (eglot--pos-to-lsp-position end))
+ eglot--recent-before-changes))
+
+(defun eglot--after-change (start end pre-change-length)
"Hook onto `after-change-functions'.
-Records START, END and LENGTH locally."
+Records START, END and PRE-CHANGE-LENGTH locally."
(cl-incf eglot--versioned-identifier)
- (push (list start end length) eglot--recent-changes)
- ;; (eglot--message "start is %s, end is %s, length is %s" start end length)
- )
+ (push (list start end pre-change-length) eglot--recent-after-changes))
(defun eglot--signal-textDocument/didChange ()
"Send textDocument/didChange to server."
- (when eglot--recent-changes
+ (when (and eglot--recent-before-changes
+ eglot--recent-after-changes)
(save-excursion
(save-restriction
(widen)
- (let* ((start (cl-reduce #'min (mapcar #'car eglot--recent-changes)))
- (end (cl-reduce #'max (mapcar #'cadr eglot--recent-changes))))
- (eglot--notify
- (eglot--current-process-or-lose)
- :textDocument/didChange
- (eglot--obj
- :textDocument
(eglot--current-buffer-VersionedTextDocumentIdentifier)
- :contentChanges
- (vector
+ (if (/= (length eglot--recent-before-changes)
+ (length eglot--recent-after-changes))
+ (eglot--notify
+ (eglot--current-process-or-lose)
+ :textDocument/didChange
(eglot--obj
- :range (eglot--obj
- :start
- (eglot--obj :line
- (line-number-at-pos start t)
- :character
- (- (goto-char start)
- (line-beginning-position)))
- :end
- (eglot--obj :line
- (line-number-at-pos end t)
- :character
- (- (goto-char end)
- (line-beginning-position))))
- :rangeLength (- end start)
- :text (buffer-substring-no-properties start end))))))))
- (setq eglot--recent-changes nil)))
+ :textDocument
(eglot--current-buffer-VersionedTextDocumentIdentifier)
+ :contentChanges
+ (vector
+ (eglot--obj
+ :text (buffer-substring-no-properties (point-min)
(point-max))))))
+ (let ((combined (cl-mapcar 'append
+ eglot--recent-before-changes
+ eglot--recent-after-changes)))
+ (eglot--notify
+ (eglot--current-process-or-lose)
+ :textDocument/didChange
+ (eglot--obj
+ :textDocument
(eglot--current-buffer-VersionedTextDocumentIdentifier)
+ :contentChanges
+ (apply
+ #'vector
+ (mapcar (pcase-lambda (`(,before-start-position
+ ,before-end-position
+ ,after-start
+ ,after-end
+ ,len))
+ (eglot--obj
+ :range
+ (eglot--obj
+ :start before-start-position
+ :end before-end-position)
+ :rangeLength len
+ :text (buffer-substring-no-properties after-start
after-end)))
+ (reverse combined))))))))))
+ (setq eglot--recent-before-changes nil
+ eglot--recent-after-changes nil))
(defun eglot--signal-textDocument/didOpen ()
"Send textDocument/didOpen to server."
- [elpa] externals/elpa 1add335 078/139: Workaround two suspected Emacs bugs, (continued)
- [elpa] externals/elpa 1add335 078/139: Workaround two suspected Emacs bugs, João Távora, 2018/05/14
- [elpa] externals/elpa 9d404c9 054/139: Update README.md, João Távora, 2018/05/14
- [elpa] externals/elpa c417eb4 009/139: Cancel timeouts when process dies unexpectedly, João Távora, 2018/05/14
- [elpa] externals/elpa 6689a15 026/139: Add eglot-clear-status interactive command, João Távora, 2018/05/14
- [elpa] externals/elpa 63f2208 030/139: Less obstrusive flymake stuff for now, João Távora, 2018/05/14
- [elpa] externals/elpa 3403f86 027/139: Correctly report what we currently are capable of, João Távora, 2018/05/14
- [elpa] externals/elpa 92bf3a0 038/139: Signal textDocument/didClose, João Távora, 2018/05/14
- [elpa] externals/elpa 7ec0dcf 029/139: Events buffer uses eglot-mode, source buffers use eglot-editing-mode, João Távora, 2018/05/14
- [elpa] externals/elpa 17e0ca4 047/139: Fix Flymake diagnostic positions, João Távora, 2018/05/14
- [elpa] externals/elpa 0e95167 042/139: Watch for files opened under umbrella of existing process, João Távora, 2018/05/14
- [elpa] externals/elpa 9665a3e 051/139: Fix textDocument/didChange,
João Távora <=
- [elpa] externals/elpa 1514e0f 052/139: Fix a couple of Rust-related edge cases, João Távora, 2018/05/14
- [elpa] externals/elpa d90efdf 001/139: Initial commit, João Távora, 2018/05/14
- [elpa] externals/elpa 29d4103 056/139: Fix mode-line mouse-clicks from outside selected window, João Távora, 2018/05/14
- [elpa] externals/elpa ea918ab 066/139: Include source info in diagnostics, João Távora, 2018/05/14
- [elpa] externals/elpa 2b61a3b 048/139: Delete two useless forward declarations, João Távora, 2018/05/14
- [elpa] externals/elpa 7d0bf64 062/139: Workaround RLS's regusal to treat nil as empty json object, João Távora, 2018/05/14
- [elpa] externals/elpa e7ffc31 067/139: Make reported capabilities into its own function, João Távora, 2018/05/14
- [elpa] externals/elpa c2862f4 063/139: Don't auto-reconnect if last attempt lasted less than 3 seconds, João Távora, 2018/05/14
- [elpa] externals/elpa e86f9b4 073/139: New helper eglot--sync-request, João Távora, 2018/05/14
- [elpa] externals/elpa 95187cf 058/139: Connect to LSP server via TCP, João Távora, 2018/05/14