Skip to content

Commit a2d1a6e

Browse files
committed
Refactor lsp--create-filter-function for better performance
Signed-off-by: Eval EXEC <execvy@gmail.com>
1 parent dc75f2a commit a2d1a6e

File tree

1 file changed

+48
-62
lines changed

1 file changed

+48
-62
lines changed

lsp-mode.el

Lines changed: 48 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -7092,6 +7092,23 @@ server. WORKSPACE is the active workspace."
70927092
(json-false nil))
70937093
(json-read-from-string ,str))))
70947094

7095+
(defmacro lsp-json-read-string (str)
7096+
"Read json from the current buffer."
7097+
(if (progn
7098+
(require 'json)
7099+
(fboundp 'json-parse-string))
7100+
`(json-parse-string ,str :object-type (if lsp-use-plists
7101+
'plist
7102+
'hash-table)
7103+
:null-object nil
7104+
:false-object nil)
7105+
`(let ((json-array-type 'vector)
7106+
(json-object-type (if lsp-use-plists
7107+
'plist
7108+
'hash-table))
7109+
(json-false nil))
7110+
(json-read-string ,str))))
7111+
70957112
(defmacro lsp-json-read-buffer ()
70967113
"Read json from the current buffer."
70977114
(if (progn
@@ -7151,69 +7168,38 @@ server. WORKSPACE is the active workspace."
71517168
('request (lsp--on-request workspace json-data)))))))
71527169

71537170
(defun lsp--create-filter-function (workspace)
7154-
"Make filter for the workspace."
7155-
(let ((body-received 0)
7156-
leftovers body-length body chunk)
7171+
"Efficiently filter/process LSP messages for WORKSPACE."
7172+
(let ((input-buffer (generate-new-buffer " *lsp-input*")))
71577173
(lambda (_proc input)
7158-
(setf chunk (if (s-blank? leftovers)
7159-
(encode-coding-string input 'utf-8-unix t)
7160-
(concat leftovers (encode-coding-string input 'utf-8-unix t))))
7161-
7162-
(let (messages)
7163-
(while (not (s-blank? chunk))
7164-
(if (not body-length)
7165-
;; Read headers
7166-
(if-let* ((body-sep-pos (string-match-p "\r\n\r\n" chunk)))
7167-
;; We've got all the headers, handle them all at once:
7168-
(setf body-length (lsp--get-body-length
7169-
(mapcar #'lsp--parse-header
7170-
(split-string
7171-
(substring-no-properties chunk
7172-
(or (string-match-p "Content-Length" chunk)
7173-
(error "Unable to find Content-Length header."))
7174-
body-sep-pos)
7175-
"\r\n")))
7176-
body-received 0
7177-
leftovers nil
7178-
chunk (substring-no-properties chunk (+ body-sep-pos 4)))
7179-
7180-
;; Haven't found the end of the headers yet. Save everything
7181-
;; for when the next chunk arrives and await further input.
7182-
(setf leftovers chunk
7183-
chunk nil))
7184-
(let* ((chunk-length (string-bytes chunk))
7185-
(left-to-receive (- body-length body-received))
7186-
(this-body (if (< left-to-receive chunk-length)
7187-
(prog1 (substring-no-properties chunk 0 left-to-receive)
7188-
(setf chunk (substring-no-properties chunk left-to-receive)))
7189-
(prog1 chunk
7190-
(setf chunk nil))))
7191-
(body-bytes (string-bytes this-body)))
7192-
(push this-body body)
7193-
(setf body-received (+ body-received body-bytes))
7194-
(when (>= chunk-length left-to-receive)
7195-
(condition-case err
7196-
(with-temp-buffer
7197-
(apply #'insert
7198-
(nreverse
7199-
(prog1 body
7200-
(setf leftovers nil
7201-
body-length nil
7202-
body-received nil
7203-
body nil))))
7204-
(decode-coding-region (point-min)
7205-
(point-max)
7206-
'utf-8)
7207-
(goto-char (point-min))
7208-
(push (lsp-json-read-buffer) messages))
7209-
7210-
(error
7211-
(lsp-warn "Failed to parse the following chunk:\n'''\n%s\n'''\nwith message %s"
7212-
(concat leftovers input)
7213-
err)))))))
7214-
(mapc (lambda (msg)
7215-
(lsp--parser-on-message msg workspace))
7216-
(nreverse messages))))))
7174+
(with-current-buffer input-buffer
7175+
;; Insert raw input at the end
7176+
(goto-char (point-max))
7177+
(insert input) ; Keep as raw bytes initially
7178+
(goto-char (point-min))
7179+
(cl-loop
7180+
while (let ((header-end (search-forward "\r\n\r\n" nil t))
7181+
(header-start (search-backward "Content-Length:" nil t)))
7182+
(when header-end
7183+
(let* ((headers (buffer-substring-no-properties header-start (- header-end 4)))
7184+
(header-lines (split-string headers "\r\n" t))
7185+
(parsed-headers (mapcar #'lsp--parse-header header-lines))
7186+
(body-length (lsp--get-body-length parsed-headers))
7187+
(body-start header-end)
7188+
(body-end (+ header-end body-length)))
7189+
(when (<= body-end (point-max))
7190+
;; Extract and decode the JSON body separately
7191+
(let ((json-string (decode-coding-string
7192+
(buffer-substring-no-properties body-start body-end)
7193+
'utf-8)))
7194+
(condition-case err
7195+
(let ((msg (lsp-json-read-string json-string)))
7196+
(lsp--parser-on-message msg workspace))
7197+
(error
7198+
(message "LSP JSON parse error: %S" err))))
7199+
;; Remove the processed message
7200+
(delete-region (point-min) body-end)
7201+
(goto-char (point-min))
7202+
t)))))))))
72177203

72187204
(defvar-local lsp--line-col-to-point-hash-table nil
72197205
"Hash table with keys (line . col) and values that are either point positions

0 commit comments

Comments
 (0)