Skip to content

Commit

Permalink
Fix #124: Move to LSP char positions exactly according to spec
Browse files Browse the repository at this point in the history
* eglot-tests.el (issue-124): New test.

* eglot.el (eglot--lsp-char-to-column): New helper.
(eglot--lsp-position-to-point): Use eglot--lsp-char-to-column.

* fixtures/utf16.cpp: New test fixture
  • Loading branch information
joaotavora committed Nov 8, 2018
1 parent d6e0ba3 commit 3bbc937
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 13 deletions.
9 changes: 9 additions & 0 deletions eglot-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,15 @@ Pass TIMEOUT to `eglot--with-timeout'."
(should-not (eglot--server-capable :foobarbaz))
(should-not (eglot--server-capable :textDocumentSync :foobarbaz))))


(ert-deftest issue-124 ()
"Test LSP's UTF-16 quirks."
(with-current-buffer (find-file-noselect "fixtures/utf16.cpp")
(should (eql (eglot--lsp-position-to-point '(:character 8 :line 2)) 22))
(should (eql (eglot--lsp-position-to-point '(:character 19 :line 2)) 33))
(should (eql (eglot--lsp-position-to-point '(:character 50 :line 2)) 63))
(should (eql (eglot--lsp-position-to-point '(:character 60 :line 2)) 73))))

(provide 'eglot-tests)
;;; eglot-tests.el ends here

Expand Down
41 changes: 28 additions & 13 deletions eglot.el
Original file line number Diff line number Diff line change
Expand Up @@ -728,16 +728,31 @@ CONNECT-ARGS are passed as additional arguments to
:character (- (goto-char (or pos (point)))
(line-beginning-position)))))

(defun eglot--lsp-char-to-column (lsp-charpos)
"Helper for `eglot--lsp-position-to-point'."
(let ((line (buffer-substring-no-properties (line-beginning-position)
(line-end-position))))
(with-temp-buffer
(save-excursion (insert line))
(cl-loop with start-filepos =
(bufferpos-to-filepos (point) 'exact 'utf-16-unix)
for current-pos = start-filepos
then (bufferpos-to-filepos (point) 'exact 'utf-16-unix)
while (and (not (eolp))
(< (/ (- current-pos start-filepos) 2)
lsp-charpos))
do (forward-char)
finally do (cl-return (1- (point)))))))

(defun eglot--lsp-position-to-point (pos-plist &optional marker)
"Convert LSP position POS-PLIST to Emacs point.
If optional MARKER, return a marker instead"
(save-excursion (goto-char (point-min))
(forward-line (min most-positive-fixnum
(plist-get pos-plist :line)))
(forward-char (min (plist-get pos-plist :character)
(- (line-end-position)
(line-beginning-position))))
(if marker (copy-marker (point-marker)) (point))))
(save-excursion
(goto-char (point-min))
(forward-line (min most-positive-fixnum
(plist-get pos-plist :line)))
(forward-char (eglot--lsp-char-to-column (plist-get pos-plist :character)))
(if marker (copy-marker (point-marker)) (point))))

(defun eglot--path-to-uri (path)
"URIfy PATH."
Expand Down Expand Up @@ -1392,12 +1407,12 @@ DUMMY is ignored."
(let* ((rich-identifier
(car (member identifier eglot--xref-known-symbols)))
(definitions
(if rich-identifier
(get-text-property 0 :locations rich-identifier)
(jsonrpc-request (eglot--current-server-or-lose)
:textDocument/definition
(get-text-property
0 :textDocumentPositionParams identifier))))
(if rich-identifier
(get-text-property 0 :locations rich-identifier)
(jsonrpc-request (eglot--current-server-or-lose)
:textDocument/definition
(get-text-property
0 :textDocumentPositionParams identifier))))
(locations
(and definitions
(if (vectorp definitions) definitions (vector definitions)))))
Expand Down
Binary file added fixtures/utf16.cpp
Binary file not shown.

0 comments on commit 3bbc937

Please sign in to comment.