1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-05 22:20:24 -08:00

Eglot: adjust semtok delta request debouncing

When a response to a semtok request is received, it's important
to remember which regions to flush.  Font-lock logic will then
do its magic and coalesce those regions into one before invoking
eglot--semtok-font-lock, and eglot--semtok-font-lock-1 will have
up-to-date data to work with.

* lisp/progmodes/eglot.el (eglot--semtok-request): Rework.
(eglot--semtok-inflight): Adjust docstring.
This commit is contained in:
João Távora 2025-11-12 20:47:34 +00:00
parent c34e32e4b0
commit b55e6b77eb

View file

@ -4626,7 +4626,7 @@ If NOERROR, return predicate, else erroring function."
"Cache of the last response from the server.") "Cache of the last response from the server.")
(defvar-local eglot--semtok-inflight nil (defvar-local eglot--semtok-inflight nil
"Non nil if there's an inflight full-buffer delta semtok request.") "List of (BEG . END) regions of inflight semtok requests.")
(defsubst eglot--semtok-apply-delta-edits (old-data edits) (defsubst eglot--semtok-apply-delta-edits (old-data edits)
"Apply EDITS obtained from full/delta request to OLD-DATA." "Apply EDITS obtained from full/delta request to OLD-DATA."
@ -4656,7 +4656,6 @@ If NOERROR, return predicate, else erroring function."
;; "data: " ;; "data: "
;; (length (cl-getf response :data))) ;; (length (cl-getf response :data)))
(eglot--when-live-buffer buf (eglot--when-live-buffer buf
(setq eglot--semtok-inflight nil)
;; A user edit may have come in while the request ;; A user edit may have come in while the request
;; was inflight, changing the state of the buffer... ;; was inflight, changing the state of the buffer...
(when (eq id eglot--versioned-identifier) (when (eq id eglot--versioned-identifier)
@ -4669,25 +4668,27 @@ If NOERROR, return predicate, else erroring function."
;; this response is out-of-date, ;; this response is out-of-date,
;; `eglot--semtok-font-lock' should just trigger ;; `eglot--semtok-font-lock' should just trigger
;; another request. ;; another request.
(font-lock-flush beg end))) (cl-loop for (b . e) in eglot--semtok-inflight
do (font-lock-flush b e))
;; (trace-values "Flushed" (length eglot--semtok-inflight)
;; "regions")
(setq eglot--semtok-inflight nil)))
:hint method)) :hint method))
(cache-get (&rest path) (cache-get (&rest path)
(let ((x eglot--semtok-cache)) (let ((x eglot--semtok-cache))
(dolist (op path x) (setq x (if (natnump op) (aref x op) (dolist (op path x) (setq x (if (natnump op) (aref x op)
(plist-get x op))))))) (plist-get x op)))))))
(push (cons beg end) eglot--semtok-inflight)
(cond (cond
((and (eglot-server-capable :semanticTokensProvider :full :delta) ((and (eglot-server-capable :semanticTokensProvider :full :delta)
(cache-get :response :data) (cache-get :response :data)
(not (eq :textDocument/semanticTokens/range (cache-get :method)))) (not (eq :textDocument/semanticTokens/range (cache-get :method))))
;; JT@2025-11-12: many back-to-back calls for ;; JT@2025-11-12: many back-to-back calls for
;; `eglot--semtok-request' and small regions occur even on trivial ;; `eglot--semtok-request' and small regions occur even on
;; fast edits. Even though it's cheap and harmless to send many ;; trivial/fast edits. Even though it's fairly cheap to send
;; delta rquests, it's nicer to just send just one. The ;; multiple delta requests, it's nicer to just send just one.
;; debouncing from jsonrpc-async-request (which see) almost (when (cdr eglot--semtok-inflight)
;; suffices, but sometimes two requests creep in. Use this (cl-return-from eglot--semtok-request))
;; simple flag to avoid.
(when eglot--semtok-inflight (cl-return-from eglot--semtok-request))
(setq eglot--semtok-inflight t)
(req :textDocument/semanticTokens/full/delta (point-min) (point-max) (req :textDocument/semanticTokens/full/delta (point-min) (point-max)
(list :textDocument (eglot--TextDocumentIdentifier) (list :textDocument (eglot--TextDocumentIdentifier)
:previousResultId (cache-get :response :resultId)) :previousResultId (cache-get :response :resultId))