Skip to content

Commit

Permalink
Fix #124: Treat :character offsets as UTF-16 code units
Browse files Browse the repository at this point in the history
The spec says that :character offsets are based on a UTF-16
representation.  Previously we were assuming that :character specifies
the number of characters.

* eglot.el (eglot--count-utf-16-code-units): New function.
(eglot--pos-to-lsp-position):
(eglot--lsp-position-to-point): Use it.
  • Loading branch information
mkcms committed Oct 3, 2018
1 parent 821b498 commit 1599c73
Showing 1 changed file with 27 additions and 10 deletions.
37 changes: 27 additions & 10 deletions eglot.el
Expand Up @@ -674,23 +674,40 @@ CONNECT-ARGS are passed as additional arguments to
(let ((warning-minimum-level :error))
(display-warning 'eglot (apply #'format format args) :warning)))

(defun eglot--count-utf-16-code-units (beg end)
"Get the number of UTF-16 code units in region BEG END."
(/
(-
(length (encode-coding-region beg end 'utf-16 t))
;; The first two bytes are utf-16 signature.
2)
;; Each code unit takes two bytes, so divide by two.
2))

(defun eglot--pos-to-lsp-position (&optional pos)
"Convert point POS to LSP position."
(eglot--widening
(list :line (1- (line-number-at-pos pos t)) ; F!@&#$CKING OFF-BY-ONE
:character (- (goto-char (or pos (point)))
(line-beginning-position)))))
(and pos (goto-char pos))
(list :line (1- (line-number-at-pos (point) t)) ; F!@&#$CKING OFF-BY-ONE
:character
(eglot--count-utf-16-code-units (line-beginning-position) (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)))
(let ((lsp-pos (min
(plist-get pos-plist :character)
(eglot--count-utf-16-code-units
(line-beginning-position) (line-end-position))))
(pos 0))
(while (< pos lsp-pos)
(cl-incf pos (eglot--count-utf-16-code-units (point) (1+ (point))))
(forward-char 1)))
(if marker (copy-marker (point-marker)) (point))))

(defun eglot--path-to-uri (path)
"URIfy PATH."
Expand Down

0 comments on commit 1599c73

Please sign in to comment.