Skip to content

Commit 04ccb81

Browse files
author
Sebastian Sturm
committed
Use font-lock-keywords for semantic tokens
1 parent 9ee3832 commit 04ccb81

File tree

1 file changed

+52
-90
lines changed

1 file changed

+52
-90
lines changed

lsp-semantic-tokens.el

Lines changed: 52 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,9 @@ Unless overridden by a more specific face association."
277277
Faces to use for semantic token modifiers if
278278
`lsp-semantic-tokens-apply-modifiers' is non-nil.")
279279

280+
(defconst lsp--semantic-tokens-font-lock-keywords
281+
'((lsp--semantic-tokens-fontify)))
282+
280283
(defun lsp--semantic-tokens-capabilities ()
281284
`((semanticTokens
282285
. ((dynamicRegistration . t)
@@ -354,7 +357,7 @@ When non-nil, `lsp--semantic-tokens-cache' should adhere to the
354357
following lsp-interface:
355358
`(_SemanticTokensCache
356359
(:_documentVersion)
357-
(:response :_region :_truncated))'.")
360+
(:response :_region))'.")
358361

359362
(defsubst lsp--semantic-tokens-putcache (k v)
360363
"Set key K of `lsp--semantic-tokens-cache' to V."
@@ -446,7 +449,7 @@ If FONTIFY-IMMEDIATELY is non-nil, fontification will be performed immediately
446449
(lsp--semantic-tokens-putcache :_documentVersion lsp--cur-version)
447450
(lsp--semantic-tokens-putcache :_region final-region)
448451
(funcall response-handler response)
449-
(when (or fontify-immediately (plist-get lsp--semantic-tokens-cache :_truncated)) (font-lock-flush)))
452+
(when fontify-immediately (font-lock-flush)))
450453
:error-handler ;; buffer is not captured in `error-handler', it is in `callback'
451454
(let ((buf (current-buffer)))
452455
(lambda (&rest _)
@@ -470,45 +473,19 @@ given workspace/language-server combination.
470473
This cache should be flushed every time any modifier
471474
configuration changes.")
472475

473-
(defun lsp-semantic-tokens--fontify (old-fontify-region beg-orig end-orig &optional loudly)
474-
"Apply fonts to retrieved semantic tokens.
475-
OLD-FONTIFY-REGION is the underlying region fontification function,
476-
e.g., `font-lock-fontify-region'.
477-
BEG-ORIG and END-ORIG deliminate the requested fontification region and maybe
478-
modified by OLD-FONTIFY-REGION.
479-
LOUDLY will be forwarded to OLD-FONTIFY-REGION as-is."
476+
(defun lsp--semantic-tokens-fontify (end)
477+
"Apply semantic tokens from point to END."
480478
;; TODO: support multiple language servers per buffer?
481479
(let ((faces (seq-some #'lsp--workspace-semantic-tokens-faces lsp--buffer-workspaces))
482480
(modifier-faces
483481
(when lsp-semantic-tokens-apply-modifiers
484-
(seq-some #'lsp--workspace-semantic-tokens-modifier-faces lsp--buffer-workspaces)))
485-
old-bounds
486-
beg end)
487-
(cond
488-
((or (eq nil faces)
489-
(eq nil lsp--semantic-tokens-cache)
490-
(eq nil (plist-get lsp--semantic-tokens-cache :response)))
491-
;; default to non-semantic highlighting until first response has arrived
492-
(funcall old-fontify-region beg-orig end-orig loudly))
493-
((not (= lsp--cur-version (plist-get lsp--semantic-tokens-cache :_documentVersion)))
494-
;; delay fontification until we have fresh tokens
495-
'(jit-lock-bounds 0 . 0))
496-
(t
497-
(setq old-bounds (funcall old-fontify-region beg-orig end-orig loudly))
498-
;; this is to prevent flickering when semantic token highlighting
499-
;; is layered on top of, e.g., tree-sitter-hl, or clojure-mode's syntax highlighting.
500-
(setq beg (min beg-orig (cadr old-bounds))
501-
end (max end-orig (cddr old-bounds)))
502-
;; if we're using the response to a ranged request, we'll only be able to fontify within
503-
;; that range (and hence shouldn't clear any highlights outside of that range)
504-
(let ((token-region (plist-get lsp--semantic-tokens-cache :_region)))
505-
(if token-region
506-
(progn
507-
(lsp--semantic-tokens-putcache :_truncated (or (< beg (car token-region))
508-
(> end (cdr token-region))))
509-
(setq beg (max beg (car token-region)))
510-
(setq end (min end (cdr token-region))))
511-
(lsp--semantic-tokens-putcache :_truncated nil)))
482+
(seq-some #'lsp--workspace-semantic-tokens-modifier-faces lsp--buffer-workspaces))))
483+
(unless (or (eq nil faces)
484+
(eq nil lsp--semantic-tokens-cache)
485+
(eq nil (plist-get lsp--semantic-tokens-cache :response))
486+
;; NOTE: perhaps we'd rather have stale highlights than temporarily dropping them altogether?
487+
(not (= lsp--cur-version (plist-get lsp--semantic-tokens-cache :_documentVersion))))
488+
512489
(-let* ((inhibit-field-text-motion t)
513490
(data (lsp-get (plist-get lsp--semantic-tokens-cache :response) :data))
514491
(i0 0)
@@ -517,44 +494,40 @@ LOUDLY will be forwarded to OLD-FONTIFY-REGION as-is."
517494
(line-delta)
518495
(column 0)
519496
(face)
497+
(beg)
520498
(line-start-pos)
521499
(line-min)
522-
(line-max-inclusive)
523500
(text-property-beg)
524501
(text-property-end))
525-
(save-mark-and-excursion
526-
(save-restriction
527-
(widen)
528-
(goto-char beg)
529-
(goto-char (line-beginning-position))
530-
(setq line-min (line-number-at-pos))
531-
(with-silent-modifications
532-
(goto-char end)
533-
(goto-char (line-end-position))
534-
(setq line-max-inclusive (line-number-at-pos))
535-
(forward-line (- line-min line-max-inclusive))
536-
(let ((skip-lines (- line-min current-line)))
537-
(while (and (<= i0 i-max) (< (aref data i0) skip-lines))
538-
(setq skip-lines (- skip-lines (aref data i0)))
539-
(setq i0 (+ i0 5)))
540-
(setq current-line (- line-min skip-lines)))
541-
(forward-line (- current-line line-min))
542-
(setq line-start-pos (point))
543-
(cl-loop
544-
for i from i0 to i-max by 5 do
545-
(setq line-delta (aref data i))
546-
(unless (= line-delta 0)
547-
(forward-line line-delta)
548-
(setq line-start-pos (point))
549-
(setq column 0)
550-
(setq current-line (+ current-line line-delta)))
551-
(setq column (+ column (aref data (1+ i))))
552-
(setq face (aref faces (aref data (+ i 3))))
553-
(setq text-property-beg (+ line-start-pos column))
554-
(setq text-property-end
555-
(min (if lsp-semantic-tokens-enable-multiline-token-support
556-
(point-max) (line-end-position))
557-
(+ text-property-beg (aref data (+ i 2)))))
502+
;; TODO: do we need to save mark and excursion within function-type font-lock keywords?
503+
(save-restriction
504+
(widen)
505+
(setq line-min (line-number-at-pos))
506+
(setq beg (point))
507+
(with-silent-modifications
508+
(let ((skip-lines (- line-min current-line)))
509+
(while (and (<= i0 i-max) (< (aref data i0) skip-lines))
510+
(setq skip-lines (- skip-lines (aref data i0)))
511+
(setq i0 (+ i0 5)))
512+
(setq current-line (- line-min skip-lines)))
513+
(forward-line (- current-line line-min))
514+
(setq line-start-pos (point))
515+
(cl-loop
516+
for i from i0 to i-max by 5 do
517+
(setq line-delta (aref data i))
518+
(unless (= line-delta 0)
519+
(forward-line line-delta)
520+
(setq line-start-pos (point))
521+
(setq column 0)
522+
(setq current-line (+ current-line line-delta)))
523+
(setq column (+ column (aref data (1+ i))))
524+
(setq face (aref faces (aref data (+ i 3))))
525+
(setq text-property-beg (+ line-start-pos column))
526+
(setq text-property-end
527+
(min (if lsp-semantic-tokens-enable-multiline-token-support
528+
(point-max) (line-end-position))
529+
(+ text-property-beg (aref data (+ i 2)))))
530+
(unless (< text-property-beg beg)
558531
(when face
559532
(put-text-property text-property-beg text-property-end 'face face))
560533
;; Deal with modifiers. We cache common combinations of
@@ -569,9 +542,8 @@ LOUDLY will be forwarded to OLD-FONTIFY-REGION as-is."
569542
(push (aref modifier-faces j) faces-to-apply)))
570543
(puthash modifier-code faces-to-apply semantic-token-modifier-cache))
571544
(dolist (face faces-to-apply)
572-
(add-face-text-property text-property-beg text-property-end face)))
573-
when (> current-line line-max-inclusive) return nil)))))
574-
`(jit-lock-bounds ,beg . ,end)))))
545+
(add-face-text-property text-property-beg text-property-end face))))
546+
when (>= (point) end) return nil)))))))
575547

576548
(defun lsp-semantic-tokens--request-update ()
577549
"Request semantic-tokens update."
@@ -670,28 +642,18 @@ Please adapt your config to prevent unnecessary mode reinitialization in the fut
670642
(defun lsp--semantic-tokens-initialize-buffer ()
671643
"Initialize the buffer for semantic tokens.
672644
IS-RANGE-PROVIDER is non-nil when server supports range requests."
673-
(let* ((old-extend-region-functions font-lock-extend-region-functions)
674-
;; make sure font-lock always fontifies entire lines (TODO: do we also have
675-
;; to change some jit-lock-...-region functions/variables?)
676-
(new-extend-region-functions
677-
(if (memq 'font-lock-extend-region-wholelines old-extend-region-functions)
678-
old-extend-region-functions
679-
(cons 'font-lock-extend-region-wholelines old-extend-region-functions)))
680-
(buffer (current-buffer)))
645+
(let* ((buffer (current-buffer)))
681646
(setq lsp--semantic-tokens-cache nil)
682-
(setq font-lock-extend-region-functions new-extend-region-functions)
683-
(add-function :around (local 'font-lock-fontify-region-function) #'lsp-semantic-tokens--fontify)
684647
(add-hook 'lsp-on-change-hook #'lsp-semantic-tokens--request-update nil t)
685648
(lsp-semantic-tokens--request-update)
686649
(setq lsp--semantic-tokens-teardown
687650
(lambda ()
651+
(font-lock-remove-keywords nil lsp--semantic-tokens-font-lock-keywords)
688652
(setq lsp--semantic-tokens-pending-full-token-requests
689653
(--remove (eq buffer (car it)) lsp--semantic-tokens-pending-full-token-requests))
690-
(setq font-lock-extend-region-functions old-extend-region-functions)
691654
(setq lsp--semantic-tokens-cache nil)
692-
(remove-function (local 'font-lock-fontify-region-function)
693-
#'lsp-semantic-tokens--fontify)
694-
(remove-hook 'lsp-on-change-hook #'lsp-semantic-tokens--request-update t)))))
655+
(remove-hook 'lsp-on-change-hook #'lsp-semantic-tokens--request-update t)))
656+
(font-lock-add-keywords nil lsp--semantic-tokens-font-lock-keywords)))
695657

696658
(defun lsp--semantic-tokens-build-face-map (identifiers faces category varname)
697659
"Build map of FACES for IDENTIFIERS using CATEGORY and VARNAME."
@@ -859,8 +821,8 @@ This is a debugging tool, and may incur significant performance penalties."
859821

860822
(defun lsp-log-full-response (response)
861823
(setq lsp-semantic-tokens--prev-response `(:request-type "full"
862-
:response ,response
863-
:version ,lsp--cur-version)))
824+
:response ,response
825+
:version ,lsp--cur-version)))
864826
(advice-add 'lsp--semantic-tokens-ingest-full-response :before 'lsp-log-full-response)
865827

866828
(defun lsp-log-range-response (response)

0 commit comments

Comments
 (0)