[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 3b7198dc470: Merge from origin/emacs-29
From: |
Eli Zaretskii |
Subject: |
master 3b7198dc470: Merge from origin/emacs-29 |
Date: |
Sat, 30 Dec 2023 04:53:26 -0500 (EST) |
branch: master
commit 3b7198dc4703671fa8b00ed3bf159cb56d4d7ba3
Merge: aa0037aaf7c 53031528725
Author: Eli Zaretskii <eliz@gnu.org>
Commit: Eli Zaretskii <eliz@gnu.org>
Merge from origin/emacs-29
53031528725 Revert "Fix treesit-node-field-name and friends (bug#66674)"
fa0bb88302b ; * src/buffer.c (syms_of_buffer) <default-directory>: Do...
44517037aed ; Fix typo
ccf46acefd2 ; Fix last change.
c86b039dffc ; * etc/DEBUG: Improve advice for debugging native-compil...
9afba605bbc Explain status "r" in `epa-list-keys`
62714221968 ; * lisp/dired.el (dired--make-directory-clickable): Refo...
fcbb0044899 Fix mouse clicks on directory line in Dired
be8a7155b48 Fix 'split-root-window-right' and 'split-root-window-below'
eb19984c4db Mark icalendar.el as maintained by emacs-devel
03dc914fd37 ; Fix footnotes in ELisp Intro manual
ceacf753958 Fix usage of `setq-default' and offer more suggestions
2701da0eee5 Fix python-ts-mode triple quote syntax (bug#67262)
683c7c96871 Increment parser timestamp when narrowing changes (bug#67...
8ae42c825e1 ruby-ts-mode: Fix indentation for string_array closer
9cfa498e0ab treesit-major-mode-setup: Use 'treesit--syntax-propertize...
da2e440462b ruby-ts-mode: Fix an out-of-bounds error with heredoc at eob
6ea507296a7 Correctly refontify changed region in tree-sitter modes (...
---
doc/lispintro/emacs-lisp-intro.texi | 35 ++++++----
doc/lispref/control.texi | 2 +-
doc/lispref/parsing.texi | 4 +-
etc/DEBUG | 12 +++-
lisp/calendar/icalendar.el | 1 +
lisp/dired.el | 19 +++++-
lisp/epa.el | 2 +-
lisp/progmodes/python.el | 17 +++++
lisp/progmodes/ruby-ts-mode.el | 22 ++----
lisp/treesit.el | 78 +++++++++++++++++++++-
lisp/window.el | 6 +-
src/buffer.c | 4 +-
src/treesit.c | 13 ++--
src/treesit.h | 4 +-
test/lisp/progmodes/ruby-mode-resources/ruby-ts.rb | 4 ++
15 files changed, 175 insertions(+), 48 deletions(-)
diff --git a/doc/lispintro/emacs-lisp-intro.texi
b/doc/lispintro/emacs-lisp-intro.texi
index 4a0e8dfa1fc..673e1f0cfdf 100644
--- a/doc/lispintro/emacs-lisp-intro.texi
+++ b/doc/lispintro/emacs-lisp-intro.texi
@@ -16892,8 +16892,14 @@ remember to look here to remind myself.
@node Text and Auto-fill
@section Text and Auto Fill Mode
-Now we come to the part that turns on Text mode and
-Auto Fill mode.
+Now we come to the part that turns on Text mode and Auto Fill
+mode@footnote{
+This section suggests settings that are more suitable for writers.
+For programmers, the default mode will be set to the corresponding
+prog-mode automatically based on the type of the file. And it's
+perfectly fine if you want to keep the fundamental mode as the default
+mode.
+}.
@smallexample
@group
@@ -16945,21 +16951,26 @@ Here is the line again; how does it work?
@cindex Text Mode turned on
@smallexample
-(setq major-mode 'text-mode)
+(setq-default major-mode 'text-mode)
@end smallexample
@noindent
This line is a short, but complete Emacs Lisp expression.
-We are already familiar with @code{setq}. It sets the following
-variable, @code{major-mode}, to the subsequent value, which is
-@code{text-mode}. The single-quote before @code{text-mode} tells
-Emacs to deal directly with the @code{text-mode} symbol, not with
-whatever it might stand for. @xref{setq, , Setting the Value of
-a Variable}, for a reminder of how @code{setq} works. The main point
-is that there is no difference between the procedure you use to set
-a value in your @file{.emacs} file and the procedure you use anywhere
-else in Emacs.
+We are already familiar with @code{setq}. We use a similar macro
+@code{setq-default} to set the following variable,
+@code{major-mode}@footnote{
+We use @code{setq-default} here because @code{text-mode} is
+buffer-local. If we use @code{setq}, it will only apply to the
+current buffer, whereas using @code{setq-default} will also apply to
+newly created buffers. This is not recommended for programmers.
+}, to the subsequent value, which is @code{text-mode}. The
+single-quote before @code{text-mode} tells Emacs to deal directly with
+the @code{text-mode} symbol, not with whatever it might stand for.
+@xref{setq, , Setting the Value of a Variable}, for a reminder of how
+@code{setq} works. The main point is that there is no difference
+between the procedure you use to set a value in your @file{.emacs}
+file and the procedure you use anywhere else in Emacs.
@need 800
Here is the next line:
diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi
index d4bd8c14ae3..25c7be3adf5 100644
--- a/doc/lispref/control.texi
+++ b/doc/lispref/control.texi
@@ -729,7 +729,7 @@ has over @code{cl-case}
;; symbol
('success (message "Done!"))
('would-block (message "Sorry, can't do it now"))
- ('read-only (message "The shmliblick is read-only"))
+ ('read-only (message "The schmilblick is read-only"))
('access-denied (message "You do not have the needed rights"))
@end group
@group
diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi
index 36238c1e1d7..df81a805e67 100644
--- a/doc/lispref/parsing.texi
+++ b/doc/lispref/parsing.texi
@@ -1071,8 +1071,8 @@ This function returns the field name of the @var{n}'th
child of
@var{node}. It returns @code{nil} if there is no @var{n}'th child, or
the @var{n}'th child doesn't have a field name.
-Note that @var{n} counts named nodes only, and @var{n} can be
-negative, e.g., @minus{}1 represents the last child.
+Note that @var{n} counts both named and anonymous children, and
+@var{n} can be negative, e.g., @minus{}1 represents the last child.
@end defun
@defun treesit-node-child-count node &optional named
diff --git a/etc/DEBUG b/etc/DEBUG
index 86bff45e7d9..55cec02c1c9 100644
--- a/etc/DEBUG
+++ b/etc/DEBUG
@@ -605,7 +605,17 @@ recommend to follow the procedure below to try to identify
the cause:
. Reduce the problematic .el file to the minimum by bisection, and
try identifying the function that causes the problem.
- . Reduce the problematic function to the minimal code that still
+ . Try natively compiling the problematic file with
+ 'native-comp-speed' set to 1 or even zero. If doing that solves
+ the problem, you can use
+
+ (declare (speed 1))
+
+ at the beginning of the body of suspected function(s) to change
+ 'native-comp-speed' only for those functions -- this could help you
+ identify the function(s) which cause(s) the problem.
+
+ . Reduce the problematic function(s) to the minimal code that still
reproduces the problem.
. Study the problem's artifacts, like Lisp or C backtraces, to try
diff --git a/lisp/calendar/icalendar.el b/lisp/calendar/icalendar.el
index 51e6a7d1170..0eca31b7dc4 100644
--- a/lisp/calendar/icalendar.el
+++ b/lisp/calendar/icalendar.el
@@ -3,6 +3,7 @@
;; Copyright (C) 2002-2023 Free Software Foundation, Inc.
;; Author: Ulf Jasper <ulf.jasper@web.de>
+;; Maintainer: emacs-devel@gnu.org
;; Created: August 2002
;; Keywords: calendar
;; Human-Keywords: calendar, diary, iCalendar, vCalendar
diff --git a/lisp/dired.el b/lisp/dired.el
index 5239e568de1..6b3d7303096 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -2017,9 +2017,22 @@ mouse-2: visit this file in other window"
keymap ,(let* ((current-dir dir)
(click (lambda ()
(interactive)
- (if (assoc current-dir
dired-subdir-alist)
- (dired-goto-subdir current-dir)
- (dired current-dir)))))
+ (cond
+ ((assoc current-dir dired-subdir-alist)
+ (dired-goto-subdir current-dir))
+ ;; If there is a wildcard chars
+ ;; in the directory name, don't
+ ;; use the alternate file machinery
+ ;; which tries to keep only one
+ ;; dired buffer open at once.
+ ;;
+ ;; FIXME: Is this code path reachable?
+ ((insert-directory-wildcard-in-dir-p
+ current-dir)
+ (dired current-dir))
+ (t
+ (dired--find-possibly-alternative-file
+ current-dir))))))
(define-keymap
"<mouse-2>" click
"<follow-link>" 'mouse-face
diff --git a/lisp/epa.el b/lisp/epa.el
index 8126584e4fb..b8af2a960f0 100644
--- a/lisp/epa.el
+++ b/lisp/epa.el
@@ -384,7 +384,7 @@ DOC is documentation text to insert at the start."
(epa--list-keys name nil
"The letters at the start of a line have these meanings.
e expired key. n never trust. m trust marginally. u trust ultimately.
-f trust fully (keys you have signed, usually).
+f trust fully (keys you have signed, usually). r revoked key.
q trust status questionable. - trust status unspecified.
See GPG documentation for more explanation.
\n"))
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 211969140ab..ff9402eaaaf 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -1238,6 +1238,21 @@ For NODE, OVERRIDE, START, END, and ARGS, see
(treesit-node-start node) (treesit-node-end node)
'font-lock-variable-use-face override start end)))
+(defun python--treesit-syntax-propertize (start end)
+ "Propertize triple-quote strings between START and END."
+ (save-excursion
+ (goto-char start)
+ (while (re-search-forward (rx (or "\"\"\"" "'''")) end t)
+ (let ((node (treesit-node-at (point))))
+ ;; The triple quotes surround a non-empty string.
+ (when (equal (treesit-node-type node) "string_content")
+ (let ((start (treesit-node-start node))
+ (end (treesit-node-end node)))
+ (put-text-property (1- start) start
+ 'syntax-table (string-to-syntax "|"))
+ (put-text-property end (min (1+ end) (point-max))
+ 'syntax-table (string-to-syntax "|"))))))))
+
;;; Indentation
@@ -6854,6 +6869,8 @@ implementations: `python-mode' and `python-ts-mode'."
#'python--treesit-defun-name)
(treesit-major-mode-setup)
+ (setq-local syntax-propertize-function #'python--treesit-syntax-propertize)
+
(python-skeleton-add-menu-items)
(when python-indent-guess-indent-offset
diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el
index c7e0b8f49ad..78a911d2189 100644
--- a/lisp/progmodes/ruby-ts-mode.el
+++ b/lisp/progmodes/ruby-ts-mode.el
@@ -753,8 +753,9 @@ a statement container is a node that matches
((match "}" "hash") ruby-ts--parent-call-or-bol 0)
((parent-is "hash") ruby-ts--parent-call-or-bol ruby-indent-level)
- ((match "]" "array") ruby-ts--parent-call-or-bol 0)
- ((parent-is "array") ruby-ts--parent-call-or-bol ruby-indent-level)
+ ((match "]" "^array") ruby-ts--parent-call-or-bol 0)
+ ((parent-is "^array") ruby-ts--parent-call-or-bol ruby-indent-level)
+ ((match ")" "string_array") ruby-ts--parent-call-or-bol 0)
((parent-is "pair") ruby-ts--parent-call-or-bol 0)
@@ -1063,8 +1064,9 @@ leading double colon is not added."
('heredoc
(put-text-property (treesit-node-start node) (1+ (treesit-node-start
node))
'syntax-table (string-to-syntax "\""))
- (put-text-property (treesit-node-end node) (1+ (treesit-node-end
node))
- 'syntax-table (string-to-syntax "\"")))
+ (when (< (treesit-node-end node) (point-max))
+ (put-text-property (treesit-node-end node) (1+ (treesit-node-end
node))
+ 'syntax-table (string-to-syntax "\""))))
('percent
;; FIXME: Put the first one on the first paren in both %Q{} and %().
;; That would stop electric-pair-mode from pairing, though. Hmm.
@@ -1192,20 +1194,8 @@ leading double colon is not added."
(treesit-major-mode-setup)
- (treesit-parser-add-notifier (car (treesit-parser-list))
- #'ruby-ts--parser-after-change)
-
(setq-local syntax-propertize-function #'ruby-ts--syntax-propertize))
-(defun ruby-ts--parser-after-change (ranges parser)
- ;; Make sure we re-syntax-propertize the full node that is being
- ;; edited. This is most pertinent to multi-line complex nodes such
- ;; as heredocs.
- (when ranges
- (with-current-buffer (treesit-parser-buffer parser)
- (syntax-ppss-flush-cache (cl-loop for r in ranges
- minimize (car r))))))
-
(if (treesit-ready-p 'ruby)
;; Copied from ruby-mode.el.
(add-to-list 'auto-mode-alist
diff --git a/lisp/treesit.el b/lisp/treesit.el
index c6b9d8ff4bc..d4857dea72e 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -385,7 +385,6 @@ If NAMED is non-nil, collect named child only."
"Return the index of NODE in its parent.
If NAMED is non-nil, count named child only."
(let ((count 0))
- ;; TODO: Use next-sibling as it's more efficient.
(while (setq node (treesit-node-prev-sibling node named))
(cl-incf count))
count))
@@ -393,7 +392,7 @@ If NAMED is non-nil, count named child only."
(defun treesit-node-field-name (node)
"Return the field name of NODE as a child of its parent."
(when-let ((parent (treesit-node-parent node))
- (idx (treesit-node-index node t)))
+ (idx (treesit-node-index node)))
(treesit-node-field-name-for-child parent idx)))
(defun treesit-node-get (node instructions)
@@ -1331,6 +1330,72 @@ parser notifying of the change."
(with-silent-modifications
(put-text-property (car range) (cdr range) 'fontified nil)))))
+(defvar-local treesit--syntax-propertize-start nil
+ "If non-nil, next `syntax-propertize' should start at this position.
+
+When tree-sitter parser reparses, it calls
+`treesit--syntax-propertize-notifier' with the affected region,
+and that function sets this variable to the start of the affected
+region.")
+
+(defun treesit--syntax-propertize-notifier (ranges parser)
+ "Sets `treesit--syntax-propertize-start' to the smallest start.
+Specifically, the smallest start position among all the ranges in
+RANGES for PARSER."
+ (with-current-buffer (treesit-parser-buffer parser)
+ (when-let* ((range-starts (mapcar #'car ranges))
+ (min-range-start
+ (seq-reduce
+ #'min (cdr range-starts) (car range-starts))))
+ (if (null treesit--syntax-propertize-start)
+ (setq treesit--syntax-propertize-start min-range-start)
+ (setq treesit--syntax-propertize-start
+ (min treesit--syntax-propertize-start min-range-start))))))
+
+(defvar-local treesit--pre-redisplay-tick nil
+ "The last `buffer-chars-modified-tick' that we've processed.
+Because `pre-redisplay-functions' could be called multiple times
+during a single command loop, we use this variable to debounce
+calls to `treesit--pre-redisplay'.")
+
+(defun treesit--pre-redisplay (&rest _)
+ "Force reparse and consequently run all notifiers.
+
+One of the notifiers is `treesit--font-lock-notifier', which will
+mark the region whose syntax has changed to \"need to refontify\".
+
+For example, when the user types the final slash of a C block
+comment /* xxx */, not only do we need to fontify the slash, but
+also the whole block comment, which previously wasn't fontified
+as comment due to incomplete parse tree."
+ (unless (eq treesit--pre-redisplay-tick (buffer-chars-modified-tick))
+ ;; `treesit-update-ranges' will force the host language's parser to
+ ;; reparse and set correct ranges for embedded parsers. Then
+ ;; `treesit-parser-root-node' will force those parsers to reparse.
+ (treesit-update-ranges)
+ ;; Force repase on _all_ the parsers might not be necessary, but
+ ;; this is probably the most robust way.
+ (dolist (parser (treesit-parser-list))
+ (treesit-parser-root-node parser))
+ (setq treesit--pre-redisplay-tick (buffer-chars-modified-tick))))
+
+(defun treesit--pre-syntax-ppss (start end)
+ "Force reparse and consequently run all notifiers.
+
+Similar to font-lock, we want to update the `syntax' text
+property before `syntax-ppss' starts working on the text. We
+also want to extend the to-be-propertized region to include the
+whole region affected by the last reparse.
+
+START and END mark the current to-be-propertized region."
+ (treesit--pre-redisplay)
+ (let ((new-start treesit--syntax-propertize-start))
+ (if (and new-start (< new-start start))
+ (progn
+ (setq treesit--syntax-propertize-start nil)
+ (cons new-start end))
+ nil)))
+
;;; Indent
(define-error 'treesit-indent-error
@@ -2853,7 +2918,14 @@ before calling this function."
(treesit-font-lock-recompute-features)
(dolist (parser (treesit-parser-list))
(treesit-parser-add-notifier
- parser #'treesit--font-lock-notifier)))
+ parser #'treesit--font-lock-notifier))
+ (add-hook 'pre-redisplay-functions #'treesit--pre-redisplay 0 t))
+ ;; Syntax
+ (dolist (parser (treesit-parser-list))
+ (treesit-parser-add-notifier
+ parser #'treesit--syntax-propertize-notifier))
+ (add-hook 'syntax-propertize-extend-region-functions
+ #'treesit--pre-syntax-ppss 0 t)
;; Indent.
(when treesit-simple-indent-rules
(setq-local treesit-simple-indent-rules
diff --git a/lisp/window.el b/lisp/window.el
index 40070a4d929..24495b21e10 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -5737,7 +5737,8 @@ The current window configuration is retained in the top
window,
the lower window takes up the whole width of the frame. SIZE is
handled as in `split-window-below', and interactively is the
prefix numeric argument."
- (interactive "p")
+ (interactive `(,(when current-prefix-arg
+ (prefix-numeric-value current-prefix-arg))))
(split-window-below size (frame-root-window)))
(defun split-window-right (&optional size window-to-split)
@@ -5777,7 +5778,8 @@ The current window configuration is retained within the
left
window, and a new window is created on the right, taking up the
whole height of the frame. SIZE is treated as by
`split-window-right' and interactively, is the prefix numeric argument."
- (interactive "p")
+ (interactive `(,(when current-prefix-arg
+ (prefix-numeric-value current-prefix-arg))))
(split-window-right size (frame-root-window)))
;;; Balancing windows.
diff --git a/src/buffer.c b/src/buffer.c
index 637830704e6..5b4c4ea390e 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -5367,8 +5367,8 @@ visual lines rather than logical lines. See the
documentation of
Qstringp,
doc: /* Name of default directory of current buffer.
It should be an absolute directory name; on GNU and Unix systems,
-these names start with `/' or `~' and end with `/'.
-To interactively change the default directory, use command `cd'. */);
+these names start with "/" or "~" and end with "/".
+To interactively change the default directory, use the command `cd'. */);
DEFVAR_PER_BUFFER ("auto-fill-function", &BVAR (current_buffer,
auto_fill_function),
Qnil,
diff --git a/src/treesit.c b/src/treesit.c
index c65873a28f7..296a404a9d1 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -948,7 +948,10 @@ treesit_sync_visible_region (Lisp_Object parser)
this function is called), we need to reparse. */
if (visible_beg != BUF_BEGV_BYTE (buffer)
|| visible_end != BUF_ZV_BYTE (buffer))
- XTS_PARSER (parser)->need_reparse = true;
+ {
+ XTS_PARSER (parser)->need_reparse = true;
+ XTS_PARSER (parser)->timestamp++;
+ }
/* Before we parse or set ranges, catch up with the narrowing
situation. We change visible_beg and visible_end to match
@@ -1722,6 +1725,7 @@ buffer. */)
ranges);
XTS_PARSER (parser)->need_reparse = true;
+ XTS_PARSER (parser)->timestamp++;
return Qnil;
}
@@ -2066,8 +2070,9 @@ DEFUN ("treesit-node-field-name-for-child",
Return nil if there's no Nth child, or if it has no field.
If NODE is nil, return nil.
-Note that N counts named nodes only. Also, N could be negative, e.g.,
--1 represents the last child. */)
+N counts all children, i.e., named ones and anonymous ones.
+
+N could be negative, e.g., -1 represents the last child. */)
(Lisp_Object node, Lisp_Object n)
{
if (NILP (node))
@@ -2081,7 +2086,7 @@ Note that N counts named nodes only. Also, N could be
negative, e.g.,
/* Process negative index. */
if (idx < 0)
- idx = ts_node_named_child_count (treesit_node) + idx;
+ idx = ts_node_child_count (treesit_node) + idx;
if (idx < 0)
return Qnil;
if (idx > UINT32_MAX)
diff --git a/src/treesit.h b/src/treesit.h
index ef7e2e15317..75d3ed778c4 100644
--- a/src/treesit.h
+++ b/src/treesit.h
@@ -61,7 +61,9 @@ struct Lisp_TS_Parser
/* Re-parsing an unchanged buffer is not free for tree-sitter, so we
only make it re-parse when need_reparse == true. That usually
means some change is made in the buffer. But others could set
- this field to true to force tree-sitter to re-parse. */
+ this field to true to force tree-sitter to re-parse. When you
+ set this to true, you should _always_ also increment
+ timestamp. */
bool need_reparse;
/* These two positions record the buffer byte position (1-based) of
the "visible region" that tree-sitter sees. Before re-parse, we
diff --git a/test/lisp/progmodes/ruby-mode-resources/ruby-ts.rb
b/test/lisp/progmodes/ruby-mode-resources/ruby-ts.rb
index 4be532a5e9d..8e372de6e45 100644
--- a/test/lisp/progmodes/ruby-mode-resources/ruby-ts.rb
+++ b/test/lisp/progmodes/ruby-mode-resources/ruby-ts.rb
@@ -85,6 +85,10 @@ foo(foo, bar:
foo(foo, :bar =>
tee)
+foo = %w[
+ asd
+]
+
# Local Variables:
# mode: ruby-ts
# ruby-after-operator-indent: t