[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
feature/android b434d2e1e4c: Merge remote-tracking branch 'origin/master
From: |
Po Lu |
Subject: |
feature/android b434d2e1e4c: Merge remote-tracking branch 'origin/master' into feature/android |
Date: |
Fri, 19 May 2023 21:48:21 -0400 (EDT) |
branch: feature/android
commit b434d2e1e4c658a8210a421089c30d904dacf6eb
Merge: 6d3cc725cd8 156973639cc
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>
Merge remote-tracking branch 'origin/master' into feature/android
---
doc/lispref/lists.texi | 9 +++++----
doc/lispref/records.texi | 3 +++
etc/NEWS | 3 +++
lisp/emacs-lisp/shortdoc.el | 2 ++
lisp/subr.el | 14 +++++++-------
lisp/treesit.el | 26 +++++++++++++++++++++-----
test/lisp/subr-tests.el | 31 +++++++++++++++++++++++++++++++
7 files changed, 72 insertions(+), 16 deletions(-)
diff --git a/doc/lispref/lists.texi b/doc/lispref/lists.texi
index 22a5f7f1239..16ed0358974 100644
--- a/doc/lispref/lists.texi
+++ b/doc/lispref/lists.texi
@@ -696,16 +696,17 @@ not a list, the sequence's elements do not become
elements of the
resulting list. Instead, the sequence becomes the final @sc{cdr}, like
any other non-list final argument.
-@defun copy-tree tree &optional vecp
+@defun copy-tree tree &optional vector-like-p
This function returns a copy of the tree @var{tree}. If @var{tree} is a
cons cell, this makes a new cons cell with the same @sc{car} and
@sc{cdr}, then recursively copies the @sc{car} and @sc{cdr} in the
same way.
Normally, when @var{tree} is anything other than a cons cell,
-@code{copy-tree} simply returns @var{tree}. However, if @var{vecp} is
-non-@code{nil}, it copies vectors too (and operates recursively on
-their elements). This function cannot cope with circular lists.
+@code{copy-tree} simply returns @var{tree}. However, if
+@var{vector-like-p} is non-@code{nil}, it copies vectors and records
+too (and operates recursively on their elements). This function
+cannot cope with circular lists.
@end defun
@defun flatten-tree tree
diff --git a/doc/lispref/records.texi b/doc/lispref/records.texi
index 26c6f30a6b5..ebc4569c388 100644
--- a/doc/lispref/records.texi
+++ b/doc/lispref/records.texi
@@ -81,6 +81,9 @@ This function returns a new record with type @var{type} and
@end example
@end defun
+To copy records, use @code{copy-tree} with its optional second argument
+non-@code{nil}. @xref{Building Lists, copy-tree}.
+
@node Backward Compatibility
@section Backward Compatibility
diff --git a/etc/NEWS b/etc/NEWS
index d16eee547de..614b4b9169a 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -621,6 +621,9 @@ Since circular alias chains now cannot occur,
'function-alias-p',
'indirect-function' and 'indirect-variable' will never signal an error.
Their 'noerror' arguments have no effect and are therefore obsolete.
++++
+** 'copy-tree' now copies records when its optional 2nd argument is non-nil.
+
* Changes in Emacs 30.1 on Non-Free Operating Systems
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index 9a6f5dd12ce..6580e0e4e0c 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -833,6 +833,8 @@ A FUNC form can have any number of `:no-eval' (or
`:no-value'),
(seq-subseq
:eval (seq-subseq [1 2 3 4 5] 1 3)
:eval (seq-subseq [1 2 3 4 5] 1))
+ (copy-tree
+ :eval (copy-tree [1 2 3 4]))
"Mapping Over Vectors"
(mapcar
:eval (mapcar #'identity [1 2 3]))
diff --git a/lisp/subr.el b/lisp/subr.el
index d49c9cb155e..b67d881c969 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -824,26 +824,26 @@ of course, also replace TO with a slightly larger value
next (+ from (* n inc)))))
(nreverse seq))))
-(defun copy-tree (tree &optional vecp)
+(defun copy-tree (tree &optional vector-like-p)
"Make a copy of TREE.
If TREE is a cons cell, this recursively copies both its car and its cdr.
Contrast to `copy-sequence', which copies only along the cdrs. With second
-argument VECP, this copies vectors as well as conses."
+argument VECTOR-LIKE-P, this copies vectors and records as well as conses."
(declare (side-effect-free error-free))
(if (consp tree)
(let (result)
(while (consp tree)
(let ((newcar (car tree)))
- (if (or (consp (car tree)) (and vecp (vectorp (car tree))))
- (setq newcar (copy-tree (car tree) vecp)))
+ (if (or (consp (car tree)) (and vector-like-p (or (vectorp (car
tree)) (recordp (car tree)))))
+ (setq newcar (copy-tree (car tree) vector-like-p)))
(push newcar result))
(setq tree (cdr tree)))
(nconc (nreverse result)
- (if (and vecp (vectorp tree)) (copy-tree tree vecp) tree)))
- (if (and vecp (vectorp tree))
+ (if (and vector-like-p (or (vectorp tree) (recordp tree)))
(copy-tree tree vector-like-p) tree)))
+ (if (and vector-like-p (or (vectorp tree) (recordp tree)))
(let ((i (length (setq tree (copy-sequence tree)))))
(while (>= (setq i (1- i)) 0)
- (aset tree i (copy-tree (aref tree i) vecp)))
+ (aset tree i (copy-tree (aref tree i) vector-like-p)))
tree)
tree)))
diff --git a/lisp/treesit.el b/lisp/treesit.el
index 49eeba64a14..cc7ec977851 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -1791,12 +1791,28 @@ however, smaller in scope than sentences. This is used
by
(defun treesit-forward-sexp (&optional arg)
"Tree-sitter implementation for `forward-sexp-function'.
-ARG is described in the docstring of `forward-sexp-function'."
+
+ARG is described in the docstring of `forward-sexp-function'. If
+there are no further sexps to move across, signal `scan-error'
+like `forward-sexp' does. If point is already at top-level,
+return nil without moving point."
(interactive "^p")
- (or arg (setq arg 1))
- (funcall
- (if (> arg 0) #'treesit-end-of-thing #'treesit-beginning-of-thing)
- treesit-sexp-type-regexp (abs arg) 'restricted))
+ (let ((arg (or arg 1))
+ (pred treesit-sexp-type-regexp))
+ (or (if (> arg 0)
+ (treesit-end-of-thing pred (abs arg) 'restricted)
+ (treesit-beginning-of-thing pred (abs arg) 'restricted))
+ ;; If we couldn't move, we should signal an error and report
+ ;; the obstacle, like `forward-sexp' does. If we couldn't
+ ;; find a parent, we simply return nil without moving point,
+ ;; then functions like `up-list' will signal "at top level".
+ (when-let* ((parent (nth 2 (treesit--things-around (point) pred)))
+ (boundary (if (> arg 0)
+ (treesit-node-child parent -1)
+ (treesit-node-child parent 0))))
+ (signal 'scan-error (list "No more sexp to move across"
+ (treesit-node-start boundary)
+ (treesit-node-end boundary)))))))
(defun treesit-transpose-sexps (&optional arg)
"Tree-sitter `transpose-sexps' function.
diff --git a/test/lisp/subr-tests.el b/test/lisp/subr-tests.el
index 8f46c2af136..4ebb68556be 100644
--- a/test/lisp/subr-tests.el
+++ b/test/lisp/subr-tests.el
@@ -1206,5 +1206,36 @@ final or penultimate step during initialization."))
(should (equal a-dedup '("a" "b" "a" "b" "c")))
(should (eq a a-dedup))))
+(ert-deftest subr--copy-tree ()
+ (should (eq (copy-tree nil) nil))
+ (let* ((a (list (list "a") "b" (list "c") "g"))
+ (copy1 (copy-tree a))
+ (copy2 (copy-tree a t)))
+ (should (equal a copy1))
+ (should (equal a copy2))
+ (should-not (eq a copy1))
+ (should-not (eq a copy2)))
+ (let* ((a (list (list "a") "b" (list "c" (record 'foo "d")) (list ["e" "f"])
"g"))
+ (copy1 (copy-tree a))
+ (copy2 (copy-tree a t)))
+ (should (equal a copy1))
+ (should (equal a copy2))
+ (should-not (eq a copy1))
+ (should-not (eq a copy2)))
+ (let* ((a (record 'foo "a" (record 'bar "b")))
+ (copy1 (copy-tree a))
+ (copy2 (copy-tree a t)))
+ (should (equal a copy1))
+ (should (equal a copy2))
+ (should (eq a copy1))
+ (should-not (eq a copy2)))
+ (let* ((a ["a" "b" ["c" ["d"]]])
+ (copy1 (copy-tree a))
+ (copy2 (copy-tree a t)))
+ (should (equal a copy1))
+ (should (equal a copy2))
+ (should (eq a copy1))
+ (should-not (eq a copy2))))
+
(provide 'subr-tests)
;;; subr-tests.el ends here