1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-06 06:20:55 -08:00

Merge from origin/emacs-29

267fc6d00c ruby-smie-rules: Fix misindentation of a method call afte...
0fde314f6f * lib-src/etags.c (process_file_name): Free malloc'ed var...
dde9d149af ; Improve documentation of loading *.eln files
7c552be89d ; Another doc fix in eglot.el
75c65fcc98 ; Fix last change
a3d15c1f74 ; Fix last change
ca79b138d4 Eglot: rename and redocument encoding-related functions (...
3e3e6d71be Eglot: support positionEncoding LSP capability (bug#61726)
b0e87e930e Eglot: use faster strategy for moving to LSP positions (b...
5b174b9683 Fix mule-tests in UTF-8 locales
5256392a7e Fix 'vertical-motion' when display strings are around
0db88d625a ; * src/treesit.c (treesit_predicate_match): Fix typo.
This commit is contained in:
Stefan Kangas 2023-02-27 06:30:20 +01:00
commit c640dc9ef5
10 changed files with 146 additions and 79 deletions

View file

@ -1556,18 +1556,26 @@ command prompts for a @dfn{library name} rather than a file name; it
searches through each directory in the Emacs Lisp load path, trying to searches through each directory in the Emacs Lisp load path, trying to
find a file matching that library name. If the library name is find a file matching that library name. If the library name is
@samp{@var{foo}}, it tries looking for files named @samp{@var{foo}}, it tries looking for files named
@file{@var{foo}.elc}, @file{@var{foo}.el}, and @file{@var{foo}}. The @file{@var{foo}.elc}, @file{@var{foo}.el}, and @file{@var{foo}}. (If
default behavior is to load the first file found. This command Emacs was built with native compilation enabled, @code{load-library}
prefers @file{.elc} files over @file{.el} files because compiled files looks for a @samp{.eln} file that corresponds to @file{@var{foo}.el}
load and run faster. If it finds that @file{@var{lib}.el} is newer and loads it instead of @file{@var{foo}.elc}.) The default behavior
than @file{@var{lib}.elc}, it issues a warning, in case someone made is to load the first file found. This command prefers @file{.eln}
changes to the @file{.el} file and forgot to recompile it, but loads files over @file{.elc} files, and prefers @file{.elc} files over
the @file{.elc} file anyway. (Due to this behavior, you can save @file{.el} files, because compiled files load and run faster. If it
unfinished edits to Emacs Lisp source files, and not recompile until finds that @file{@var{lib}.el} is newer than @file{@var{lib}.elc}, it
your changes are ready for use.) If you set the option issues a warning, in case someone made changes to the @file{.el} file
@code{load-prefer-newer} to a non-@code{nil} value, however, then and forgot to recompile it, but loads the @file{.elc} file anyway.
rather than the procedure described above, Emacs loads whichever (Due to this behavior, you can save unfinished edits to Emacs Lisp
version of the file is newest. source files, and not recompile until your changes are ready for use.)
If you set the option @code{load-prefer-newer} to a non-@code{nil}
value, however, then rather than the procedure described above, Emacs
loads whichever version of the file is newest. If Emacs was built
with native compilation, and it cannot find the @samp{.eln} file
corresponding to @file{@var{lib}.el}, it will load a
@file{@var{lib}.elc} and start native compilation of
@file{@var{lib}.el} in the background, then load the @samp{.eln} file
when it finishes compilation.
Emacs Lisp programs usually load Emacs Lisp files using the Emacs Lisp programs usually load Emacs Lisp files using the
@code{load} function. This is similar to @code{load-library}, but is @code{load} function. This is similar to @code{load-library}, but is
@ -1604,6 +1612,11 @@ It is customary to put locally installed libraries in the
@code{load-path}, or in some subdirectory of @file{site-lisp}. This @code{load-path}, or in some subdirectory of @file{site-lisp}. This
way, you don't need to modify the default value of @code{load-path}. way, you don't need to modify the default value of @code{load-path}.
@vindex native-comp-eln-load-path
Similarly to @code{load-path}, the list of directories where Emacs
looks for @file{*.eln} files with natively-compiled Lisp code is
specified by the variable @code{native-comp-eln-load-path}.
@cindex autoload @cindex autoload
Some commands are @dfn{autoloaded}; when you run them, Emacs Some commands are @dfn{autoloaded}; when you run them, Emacs
automatically loads the associated library first. For instance, the automatically loads the associated library first. For instance, the

View file

@ -75,17 +75,20 @@ file exists, and Emacs was compiled with native-compilation support
(@pxref{Native Compilation}), @code{load} attempts to find a (@pxref{Native Compilation}), @code{load} attempts to find a
corresponding @samp{.eln} file, and if found, loads it instead of corresponding @samp{.eln} file, and if found, loads it instead of
@file{@var{filename}.elc}. Otherwise, it loads @file{@var{filename}.elc}. Otherwise, it loads
@file{@var{filename}.elc}. If there is no file by that name, then @file{@var{filename}.elc} (and starts a background native compilation
@code{load} looks for a file named @file{@var{filename}.el}. If that to produce the missing @samp{.eln} file, followed by loading that
file exists, it is loaded. If Emacs was compiled with support for file). If there is no @file{@var{filename}.elc}, then @code{load}
dynamic modules (@pxref{Dynamic Modules}), @code{load} next looks for looks for a file named @file{@var{filename}.el}. If that file exists,
a file named @file{@var{filename}.@var{ext}}, where @var{ext} is a it is loaded. If Emacs was compiled with support for dynamic modules
system-dependent file-name extension of shared libraries. Finally, if (@pxref{Dynamic Modules}), @code{load} next looks for a file named
neither of those names is found, @code{load} looks for a file named @file{@var{filename}.@var{ext}}, where @var{ext} is a system-dependent
@var{filename} with nothing appended, and loads it if it exists. (The file-name extension of shared libraries (@samp{.so} on GNU and Unix
@code{load} function is not clever about looking at @var{filename}. systems). Finally, if neither of those names is found, @code{load}
In the perverse case of a file named @file{foo.el.el}, evaluation of looks for a file named @var{filename} with nothing appended, and loads
@code{(load "foo.el")} will indeed find it.) it if it exists. (The @code{load} function is not clever about
looking at @var{filename}. In the perverse case of a file named
@file{foo.el.el}, evaluation of @code{(load "foo.el")} will indeed
find it.)
If Auto Compression mode is enabled, as it is by default, then if If Auto Compression mode is enabled, as it is by default, then if
@code{load} can not find a file, it searches for a compressed version @code{load} can not find a file, it searches for a compressed version

View file

@ -1732,6 +1732,8 @@ process_file_name (char *file, language *lang)
char *cmd = xmalloc (buf_len); char *cmd = xmalloc (buf_len);
snprintf (cmd, buf_len, "%s %s > %s", snprintf (cmd, buf_len, "%s %s > %s",
compr->command, new_real_name, new_tmp_name); compr->command, new_real_name, new_tmp_name);
free (new_real_name);
free (new_tmp_name);
#endif #endif
inf = (system (cmd) == -1 inf = (system (cmd) == -1
? NULL ? NULL

View file

@ -816,6 +816,7 @@ treated as in `eglot--dbind'."
`(:valueSet `(:valueSet
[,@(mapcar [,@(mapcar
#'car eglot--tag-faces)]))) #'car eglot--tag-faces)])))
:general (list :positionEncodings ["utf-32" "utf-8" "utf-16"])
:experimental eglot--{}))) :experimental eglot--{})))
(cl-defgeneric eglot-workspace-folders (server) (cl-defgeneric eglot-workspace-folders (server)
@ -1439,20 +1440,32 @@ CONNECT-ARGS are passed as additional arguments to
(let ((warning-minimum-level :error)) (let ((warning-minimum-level :error))
(display-warning 'eglot (apply #'format format args) :warning))) (display-warning 'eglot (apply #'format format args) :warning)))
(defun eglot-current-column () (- (point) (line-beginning-position)))
;;; Encoding fever
;;;
(define-obsolete-function-alias
'eglot-lsp-abiding-column 'eglot-utf-16-linepos "29.1")
(define-obsolete-function-alias
'eglot-current-column 'eglot-utf-32-linepos "29.1")
(define-obsolete-variable-alias
'eglot-current-column-function 'eglot-current-linepos-function "29.1")
(defvar eglot-current-column-function #'eglot-lsp-abiding-column (defvar eglot-current-linepos-function #'eglot-utf-16-linepos
"Function to calculate the current column. "Function calculating position relative to line beginning.
This is the inverse operation of This is the inverse of `eglot-move-to-linepos-function' (which see).
`eglot-move-to-column-function' (which see). It is a function of It is a function of no arguments returning the number of code units
no arguments returning a column number. For buffers managed by or bytes or codepoints corresponding to the current position of point,
fully LSP-compliant servers, this should be set to relative to line beginning, as expected by the function that is the
`eglot-lsp-abiding-column' (the default), and value of `eglot-move-to-linepos-function'.")
`eglot-current-column' for all others.")
(defun eglot-lsp-abiding-column (&optional lbp) (defun eglot-utf-8-linepos ()
"Calculate current COLUMN as defined by the LSP spec. "Calculate number of UTF-8 bytes from line beginning."
(length (encode-coding-region (line-beginning-position) (point)
'utf-8-unix t)))
(defun eglot-utf-16-linepos (&optional lbp)
"Calculate number of UTF-16 code units from position given by LBP.
LBP defaults to `line-beginning-position'." LBP defaults to `line-beginning-position'."
(/ (- (length (encode-coding-region (or lbp (line-beginning-position)) (/ (- (length (encode-coding-region (or lbp (line-beginning-position))
;; Fix github#860 ;; Fix github#860
@ -1460,51 +1473,71 @@ LBP defaults to `line-beginning-position'."
2) 2)
2)) 2))
(defun eglot-utf-32-linepos ()
"Calculate number of Unicode codepoints from line beginning."
(- (point) (line-beginning-position)))
(defun eglot--pos-to-lsp-position (&optional pos) (defun eglot--pos-to-lsp-position (&optional pos)
"Convert point POS to LSP position." "Convert point POS to LSP position."
(eglot--widening (eglot--widening
;; LSP line is zero-origin; emacs is one-origin. ;; LSP line is zero-origin; emacs is one-origin.
(list :line (1- (line-number-at-pos pos t)) (list :line (1- (line-number-at-pos pos t))
:character (progn (when pos (goto-char pos)) :character (progn (when pos (goto-char pos))
(funcall eglot-current-column-function))))) (funcall eglot-current-linepos-function)))))
(defvar eglot-move-to-column-function #'eglot-move-to-lsp-abiding-column (define-obsolete-function-alias
"Function to move to a column reported by the LSP server. 'eglot-move-to-current-column 'eglot-move-to-utf-32-linepos "29.1")
(define-obsolete-function-alias
'eglot-move-to-lsp-abiding-column 'eglot-move-to-utf-16-linepos "29.1")
(define-obsolete-variable-alias
'eglot-move-to-column-function 'eglot-move-to-linepos-function "29.1")
According to the standard, LSP column/character offsets are based (defvar eglot-move-to-linepos-function #'eglot-move-to-utf-16-linepos
on a count of UTF-16 code units, not actual visual columns. So "Function to move to a position within a line reported by the LSP server.
when LSP says position 3 of a line containing just \"aXbc\",
where X is a multi-byte character, it actually means `b', not
`c'. However, many servers don't follow the spec this closely.
For buffers managed by fully LSP-compliant servers, this should Per the LSP spec, character offsets in LSP Position objects count
be set to `eglot-move-to-lsp-abiding-column' (the default), and UTF-16 code units, not actual code points. So when LSP says
`eglot-move-to-column' for all others.") position 3 of a line containing just \"aXbc\", where X is a funny
looking character in the UTF-16 \"supplementary plane\", it
actually means `b', not `c'. The default value
`eglot-move-to-utf-16-linepos' accounts for this.
(defun eglot-move-to-column (column) This variable can also be set to `eglot-move-to-utf-8-linepos' or
"Move to COLUMN without closely following the LSP spec." `eglot-move-to-utf-32-linepos' for servers not closely following
the spec. Also, since LSP 3.17 server and client may agree on an
encoding and Eglot will set this variable automatically.")
(defun eglot-move-to-utf-8-linepos (n)
"Move to line's Nth byte as computed by LSP's UTF-8 criterion."
(let* ((bol (line-beginning-position))
(goal-byte (+ (position-bytes bol) n))
(eol (line-end-position)))
(goto-char bol)
(while (and (< (position-bytes (point)) goal-byte) (< (point) eol))
;; raw bytes take 2 bytes in the buffer
(when (>= (char-after) #x3fff80) (setq goal-byte (1+ goal-byte)))
(forward-char 1))))
(defun eglot-move-to-utf-16-linepos (n)
"Move to line's Nth code unit as computed by LSP's UTF-16 criterion."
(let* ((bol (line-beginning-position))
(goal-char (+ bol n))
(eol (line-end-position)))
(goto-char bol)
(while (and (< (point) goal-char) (< (point) eol))
;; code points in the "supplementary place" use two code units
(when (<= #x010000 (char-after) #x10ffff) (setq goal-char (1- goal-char)))
(forward-char 1))))
(defun eglot-move-to-utf-32-linepos (n)
"Move to line's Nth codepoint as computed by LSP's UTF-32 criterion."
;; We cannot use `move-to-column' here, because it moves to *visual* ;; We cannot use `move-to-column' here, because it moves to *visual*
;; columns, which can be different from LSP columns in case of ;; columns, which can be different from LSP characters in case of
;; `whitespace-mode', `prettify-symbols-mode', etc. (github#296, ;; `whitespace-mode', `prettify-symbols-mode', etc. (github#296,
;; github#297) ;; github#297)
(goto-char (min (+ (line-beginning-position) column) (goto-char (min (+ (line-beginning-position) n)
(line-end-position)))) (line-end-position))))
(defun eglot-move-to-lsp-abiding-column (column)
"Move to COLUMN abiding by the LSP spec."
(save-restriction
(cl-loop
with lbp = (line-beginning-position)
initially
(narrow-to-region lbp (line-end-position))
(move-to-column column)
for diff = (- column
(eglot-lsp-abiding-column lbp))
until (zerop diff)
do (condition-case eob-err
(forward-char (/ (if (> diff 0) (1+ diff) (1- diff)) 2))
(end-of-buffer (cl-return eob-err))))))
(defun eglot--lsp-position-to-point (pos-plist &optional marker) (defun eglot--lsp-position-to-point (pos-plist &optional marker)
"Convert LSP position POS-PLIST to Emacs point. "Convert LSP position POS-PLIST to Emacs point.
If optional MARKER, return a marker instead" If optional MARKER, return a marker instead"
@ -1515,16 +1548,17 @@ If optional MARKER, return a marker instead"
(forward-line (min most-positive-fixnum (forward-line (min most-positive-fixnum
(plist-get pos-plist :line))) (plist-get pos-plist :line)))
(unless (eobp) ;; if line was excessive leave point at eob (unless (eobp) ;; if line was excessive leave point at eob
(let ((tab-width 1) (let ((col (plist-get pos-plist :character)))
(col (plist-get pos-plist :character)))
(unless (wholenump col) (unless (wholenump col)
(eglot--warn (eglot--warn
"Caution: LSP server sent invalid character position %s. Using 0 instead." "Caution: LSP server sent invalid character position %s. Using 0 instead."
col) col)
(setq col 0)) (setq col 0))
(funcall eglot-move-to-column-function col))) (funcall eglot-move-to-linepos-function col)))
(if marker (copy-marker (point-marker)) (point))))) (if marker (copy-marker (point-marker)) (point)))))
;;; More helpers
(defconst eglot--uri-path-allowed-chars (defconst eglot--uri-path-allowed-chars
(let ((vec (copy-sequence url-path-allowed-chars))) (let ((vec (copy-sequence url-path-allowed-chars)))
(aset vec ?: nil) ;; see github#639 (aset vec ?: nil) ;; see github#639
@ -1758,6 +1792,14 @@ Use `eglot-managed-p' to determine if current buffer is managed.")
:init-value nil :lighter nil :keymap eglot-mode-map :init-value nil :lighter nil :keymap eglot-mode-map
(cond (cond
(eglot--managed-mode (eglot--managed-mode
(pcase (plist-get (eglot--capabilities (eglot-current-server))
:positionEncoding)
("utf-32"
(eglot--setq-saving eglot-current-linepos-function #'eglot-utf-32-linepos)
(eglot--setq-saving eglot-move-to-linepos-function #'eglot-move-to-utf-32-linepos))
("utf-8"
(eglot--setq-saving eglot-current-linepos-function #'eglot-utf-8-linepos)
(eglot--setq-saving eglot-move-to-linepos-function #'eglot-move-to-utf-8-linepos)))
(add-hook 'after-change-functions 'eglot--after-change nil t) (add-hook 'after-change-functions 'eglot--after-change nil t)
(add-hook 'before-change-functions 'eglot--before-change nil t) (add-hook 'before-change-functions 'eglot--before-change nil t)
(add-hook 'kill-buffer-hook #'eglot--managed-mode-off nil t) (add-hook 'kill-buffer-hook #'eglot--managed-mode-off nil t)
@ -2591,7 +2633,7 @@ Try to visit the target file for a richer summary line."
(add-face-text-property hi-beg hi-end 'xref-match (add-face-text-property hi-beg hi-end 'xref-match
t substring) t substring)
(list substring (line-number-at-pos (point) t) (list substring (line-number-at-pos (point) t)
(eglot-current-column) (- end beg)))))) (eglot-utf-32-linepos) (- end beg))))))
(`(,summary ,line ,column ,length) (`(,summary ,line ,column ,length)
(cond (cond
(visiting (with-current-buffer visiting (funcall collect))) (visiting (with-current-buffer visiting (funcall collect)))

View file

@ -909,7 +909,9 @@ This only affects the output of the command `ruby-toggle-block'."
"<<=" ">>=" "&&=" "||=" "and" "or")) "<<=" ">>=" "&&=" "||=" "and" "or"))
(cond (cond
((not ruby-after-operator-indent) ((not ruby-after-operator-indent)
(ruby-smie--indent-to-stmt ruby-indent-level)) (ruby-smie--indent-to-stmt (if (smie-indent--hanging-p)
ruby-indent-level
0)))
((and (smie-rule-parent-p ";" nil) ((and (smie-rule-parent-p ";" nil)
(smie-indent--hanging-p)) (smie-indent--hanging-p))
ruby-indent-level))) ruby-indent-level)))

View file

@ -2401,7 +2401,7 @@ whether or not it is currently displayed in some window. */)
last line that it occupies. */ last line that it occupies. */
if (it_start < ZV) if (it_start < ZV)
{ {
if ((it.bidi_it.scan_dir > 0) if ((it.bidi_it.scan_dir >= 0 || it.vpos == vpos_init)
? IT_CHARPOS (it) < it_start ? IT_CHARPOS (it) < it_start
: IT_CHARPOS (it) > it_start) : IT_CHARPOS (it) > it_start)
{ {

View file

@ -2484,7 +2484,7 @@ treesit_predicate_match (Lisp_Object args, struct capture_range captures)
{ {
if (XFIXNUM (Flength (args)) != 2) if (XFIXNUM (Flength (args)) != 2)
xsignal2 (Qtreesit_query_error, xsignal2 (Qtreesit_query_error,
build_string ("Predicate `equal' requires two " build_string ("Predicate `match' requires two "
"arguments but only given"), "arguments but only given"),
Flength (args)); Flength (args));

View file

@ -119,9 +119,10 @@ provide HTML fragments. Some tests override those variables."
(ert-deftest sgml-html-meta-no-post-less-than-10lines () (ert-deftest sgml-html-meta-no-post-less-than-10lines ()
"No '</head>', detect charset in the first 10 lines." "No '</head>', detect charset in the first 10 lines."
(let ((sgml-html-meta-post "")) (let ((sgml-html-meta-post ""))
(should (eq 'utf-8 (sgml-html-meta-run (should (eq 'utf-8 (coding-system-base
(sgml-html-meta-run
(concat "\n\n\n\n\n\n\n\n\n" (concat "\n\n\n\n\n\n\n\n\n"
"<meta charset='utf-8'>")))))) "<meta charset='utf-8'>")))))))
(ert-deftest sgml-html-meta-no-post-10lines () (ert-deftest sgml-html-meta-no-post-10lines ()
"No '</head>', do not detect charset after the first 10 lines." "No '</head>', do not detect charset after the first 10 lines."

View file

@ -856,8 +856,8 @@ pylsp prefers autopep over yafp, despite its README stating the contrary."
'((c-mode . ("clangd"))))) '((c-mode . ("clangd")))))
(with-current-buffer (with-current-buffer
(eglot--find-file-noselect "project/foo.c") (eglot--find-file-noselect "project/foo.c")
(setq-local eglot-move-to-column-function #'eglot-move-to-lsp-abiding-column) (setq-local eglot-move-to-linepos-function #'eglot-move-to-utf-16-linepos)
(setq-local eglot-current-column-function #'eglot-lsp-abiding-column) (setq-local eglot-current-linepos-function #'eglot-utf-16-linepos)
(eglot--sniffing (:client-notifications c-notifs) (eglot--sniffing (:client-notifications c-notifs)
(eglot--tests-connect) (eglot--tests-connect)
(end-of-line) (end-of-line)
@ -866,12 +866,12 @@ pylsp prefers autopep over yafp, despite its README stating the contrary."
(eglot--wait-for (c-notifs 2) (&key params &allow-other-keys) (eglot--wait-for (c-notifs 2) (&key params &allow-other-keys)
(should (equal 71 (cadddr (cadadr (aref (cadddr params) 0)))))) (should (equal 71 (cadddr (cadadr (aref (cadddr params) 0))))))
(beginning-of-line) (beginning-of-line)
(should (eq eglot-move-to-column-function #'eglot-move-to-lsp-abiding-column)) (should (eq eglot-move-to-linepos-function #'eglot-move-to-utf-16-linepos))
(funcall eglot-move-to-column-function 71) (funcall eglot-move-to-linepos-function 71)
(should (looking-at "p"))))))) (should (looking-at "p")))))))
(ert-deftest eglot-test-lsp-abiding-column () (ert-deftest eglot-test-lsp-abiding-column ()
"Test basic `eglot-lsp-abiding-column' and `eglot-move-to-lsp-abiding-column'." "Test basic LSP character counting logic."
(skip-unless (executable-find "clangd")) (skip-unless (executable-find "clangd"))
(eglot-tests--lsp-abiding-column-1)) (eglot-tests--lsp-abiding-column-1))

View file

@ -10,6 +10,10 @@ qux = 4 + 5 *
foo = obj.bar { |m| tee(m) } + foo = obj.bar { |m| tee(m) } +
obj.qux { |m| hum(m) } obj.qux { |m| hum(m) }
some_variable = abc + some_method(
some_argument
)
foo. foo.
bar bar
.baz .baz