@@ -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