From b04cce02ff41a2ecb850e9772ab8d415cc6c8b50 Mon Sep 17 00:00:00 2001
From: Eli Zaretskii
;; Create parsers. -(setq html (treesit-get-parser-create 'html)) -(setq css (treesit-get-parser-create 'css)) -(setq js (treesit-get-parser-create 'javascript)) +(setq html (treesit-parser-create 'html)) +(setq css (treesit-parser-create 'css)) +(setq js (treesit-parser-create 'javascript))
;; Set CSS ranges.
diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi
index 6e13af9a20f..53787d7e54d 100644
--- a/doc/lispref/parsing.texi
+++ b/doc/lispref/parsing.texi
@@ -1589,9 +1589,9 @@ ranges for @acronym{CSS} and JavaScript parsers:
@example
@group
;; Create parsers.
-(setq html (treesit-get-parser-create 'html))
-(setq css (treesit-get-parser-create 'css))
-(setq js (treesit-get-parser-create 'javascript))
+(setq html (treesit-parser-create 'html))
+(setq css (treesit-parser-create 'css))
+(setq js (treesit-parser-create 'javascript))
@end group
@group
From f5789aefc2e245075b5cced402edb086fefb60ef Mon Sep 17 00:00:00 2001
From: Yuan Fu
Date: Thu, 9 Feb 2023 23:25:57 -0800
Subject: [PATCH 09/24] Rename LIMIT to DEPTH in tree-sitter functions
(bug#61231)
I only changed the Lisp functions, internal functions are left
unchanged.
* doc/lispref/parsing.texi (Retrieving Nodes): Update manual.
* src/treesit.c (Ftreesit_search_subtree)
(Ftreesit_induce_sparse_tree): Change LIMIT to DEPTH.
---
doc/lispref/parsing.texi | 12 ++++++------
src/treesit.c | 24 ++++++++++++------------
2 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi
index 53787d7e54d..b22b3eb25c3 100644
--- a/doc/lispref/parsing.texi
+++ b/doc/lispref/parsing.texi
@@ -734,7 +734,7 @@ is non-@code{nil}, it looks for smallest named child.
@heading Searching for node
-@defun treesit-search-subtree node predicate &optional backward all limit
+@defun treesit-search-subtree node predicate &optional backward all depth
This function traverses the subtree of @var{node} (including
@var{node} itself), looking for a node for which @var{predicate}
returns non-@code{nil}. @var{predicate} is a regexp that is matched
@@ -745,9 +745,9 @@ the first node that matches, or @code{nil} if none does.
By default, this function only traverses named nodes, but if @var{all}
is non-@code{nil}, it traverses all the nodes. If @var{backward} is
non-@code{nil}, it traverses backwards (i.e., it visits the last child
-first when traversing down the tree). If @var{limit} is
+first when traversing down the tree). If @var{depth} is
non-@code{nil}, it must be a number that limits the tree traversal to
-that many levels down the tree. If @var{limit} is @code{nil}, it
+that many levels down the tree. If @var{depth} is @code{nil}, it
defaults to 1000.
@end defun
@@ -805,7 +805,7 @@ Arguments @var{predicate}, @var{backward} and @var{all} are the same
as in @code{treesit-search-forward}.
@end defun
-@defun treesit-induce-sparse-tree root predicate &optional process-fn limit
+@defun treesit-induce-sparse-tree root predicate &optional process-fn depth
This function creates a sparse tree from @var{root}'s subtree.
It takes the subtree under @var{root}, and combs it so only the nodes
@@ -836,8 +836,8 @@ b 1 2 b | | b c d
If @var{process-fn} is non-@code{nil}, instead of returning the
matched nodes, this function passes each node to @var{process-fn} and
-uses the returned value instead. If non-@code{nil}, @var{limit} is
-the number of levels to go down from @var{root}. If @var{limit} is
+uses the returned value instead. If non-@code{nil}, @var{depth} is
+the number of levels to go down from @var{root}. If @var{depth} is
@code{nil}, it defaults to 1000.
Each node in the returned tree looks like
diff --git a/src/treesit.c b/src/treesit.c
index 01c7621c6ea..cab2f0d5354 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -3150,13 +3150,13 @@ the way. PREDICATE is a regexp string that matches against each
node's type, or a function that takes a node and returns nil/non-nil.
By default, only traverse named nodes, but if ALL is non-nil, traverse
-all nodes. If BACKWARD is non-nil, traverse backwards. If LIMIT is
+all nodes. If BACKWARD is non-nil, traverse backwards. If DEPTH is
non-nil, only traverse nodes up to that number of levels down in the
-tree. If LIMIT is nil, default to 1000.
+tree. If DEPTH is nil, default to 1000.
Return the first matched node, or nil if none matches. */)
(Lisp_Object node, Lisp_Object predicate, Lisp_Object backward,
- Lisp_Object all, Lisp_Object limit)
+ Lisp_Object all, Lisp_Object depth)
{
CHECK_TS_NODE (node);
CHECK_TYPE (STRINGP (predicate) || FUNCTIONP (predicate),
@@ -3167,10 +3167,10 @@ Return the first matched node, or nil if none matches. */)
/* We use a default limit of 1000. See bug#59426 for the
discussion. */
ptrdiff_t the_limit = treesit_recursion_limit;
- if (!NILP (limit))
+ if (!NILP (depth))
{
- CHECK_FIXNUM (limit);
- the_limit = XFIXNUM (limit);
+ CHECK_FIXNUM (depth);
+ the_limit = XFIXNUM (depth);
}
treesit_initialize ();
@@ -3322,8 +3322,8 @@ If PROCESS-FN is non-nil, it should be a function of one argument. In
that case, instead of returning the matched nodes, pass each node to
PROCESS-FN, and use its return value instead.
-If non-nil, LIMIT is the number of levels to go down the tree from
-ROOT. If LIMIT is nil or omitted, it defaults to 1000.
+If non-nil, DEPTH is the number of levels to go down the tree from
+ROOT. If DEPTH is nil or omitted, it defaults to 1000.
Each node in the returned tree looks like (NODE . (CHILD ...)). The
root of this tree might be nil, if ROOT doesn't match PREDICATE.
@@ -3334,7 +3334,7 @@ PREDICATE can also be a function that takes a node and returns
nil/non-nil, but it is slower and more memory consuming than using
a regexp. */)
(Lisp_Object root, Lisp_Object predicate, Lisp_Object process_fn,
- Lisp_Object limit)
+ Lisp_Object depth)
{
CHECK_TS_NODE (root);
CHECK_TYPE (STRINGP (predicate) || FUNCTIONP (predicate),
@@ -3346,10 +3346,10 @@ a regexp. */)
/* We use a default limit of 1000. See bug#59426 for the
discussion. */
ptrdiff_t the_limit = treesit_recursion_limit;
- if (!NILP (limit))
+ if (!NILP (depth))
{
- CHECK_FIXNUM (limit);
- the_limit = XFIXNUM (limit);
+ CHECK_FIXNUM (depth);
+ the_limit = XFIXNUM (depth);
}
treesit_initialize ();
From 9ac242ce93d7c4fbc34b556f4fa0d2ac2ebac604 Mon Sep 17 00:00:00 2001
From: Eli Zaretskii
Date: Fri, 10 Feb 2023 14:14:05 +0200
Subject: [PATCH 10/24] ; Fix recent changes in treesit docs
* doc/lispref/parsing.texi (Accessing Node Information): Fix
wording and indexing, and add cross-reference.
---
doc/lispref/parsing.texi | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi
index b22b3eb25c3..fd65fa3e75b 100644
--- a/doc/lispref/parsing.texi
+++ b/doc/lispref/parsing.texi
@@ -970,15 +970,15 @@ A node ``has error'' if the text it spans contains a syntax error. It
can be that the node itself has an error, or one of its descendants
has an error.
-@cindex tree-sitter live node
+@cindex tree-sitter, live parsing node
@cindex live node, tree-sitter
-A node is ``live'' if its parser is not deleted, and the buffer it
-belongs to is live.
+A node is considered @dfn{live} if its parser is not deleted, and the
+buffer to which it belongs to is a live buffer (@pxref{Killing Buffers}).
@defun treesit-node-check node property
-This function checks if @var{node} has the specified @var{property}.
-@var{property} can be @code{named}, @code{missing}, @code{extra},
-@code{outdated}, @code{has-error}, or @code{live}.
+This function returns non-@code{nil} if @var{node} has the specified
+@var{property}. @var{property} can be @code{named}, @code{missing},
+@code{extra}, @code{outdated}, @code{has-error}, or @code{live}.
@end defun
@defun treesit-node-type node
From 10af9fbcad107ae76f50d408e0d6d04e082cc6d8 Mon Sep 17 00:00:00 2001
From: "Basil L. Contovounesios"
Date: Fri, 10 Feb 2023 15:24:45 +0000
Subject: [PATCH 11/24] ; * admin/notes/tree-sitter/starter-guide: Typos.
Reported by Romanos Skiadas .
---
admin/notes/tree-sitter/starter-guide | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/admin/notes/tree-sitter/starter-guide b/admin/notes/tree-sitter/starter-guide
index 606f7891dfa..b8910aab5ca 100644
--- a/admin/notes/tree-sitter/starter-guide
+++ b/admin/notes/tree-sitter/starter-guide
@@ -45,7 +45,7 @@ You can use this script that I put together here:
You can also find them under this directory in /build-modules.
This script automatically pulls and builds language definitions for C,
-C++, Rust, JSON, Go, HTML, Javascript, CSS, Python, Typescript,
+C++, Rust, JSON, Go, HTML, JavaScript, CSS, Python, Typescript,
and C#. Better yet, I pre-built these language definitions for
GNU/Linux and macOS, they can be downloaded here:
@@ -271,7 +271,7 @@ Matchers and anchors are functions that takes (NODE PARENT BOL &rest
_). Matches return nil/non-nil for no match/match, and anchors return
the anchor point. Below are some convenient builtin matchers and anchors.
-For MATHCER we have
+For MATCHER we have
(parent-is TYPE) => matches if PARENT’s type matches TYPE as regexp
(node-is TYPE) => matches NODE’s type
From 4f053afe8e792c6261d4be0376e2ef0c91353188 Mon Sep 17 00:00:00 2001
From: Tassilo Horn
Date: Fri, 10 Feb 2023 19:22:56 +0100
Subject: [PATCH 12/24] bug-reference: prevent match-data clobbering
(bug#61395)
* lisp/progmodes/bug-reference.el (bug-reference-fontify): Wrap call
to syntax-ppss in save-match-data since it can clobber our
match-data (bug#61395).
---
lisp/progmodes/bug-reference.el | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lisp/progmodes/bug-reference.el b/lisp/progmodes/bug-reference.el
index 9f1439e6a04..bc280284588 100644
--- a/lisp/progmodes/bug-reference.el
+++ b/lisp/progmodes/bug-reference.el
@@ -174,7 +174,7 @@ subexpression 10."
(re-search-forward bug-reference-bug-regexp end-line 'move))
(when (or (not bug-reference-prog-mode)
;; This tests for both comment and string syntax.
- (nth 8 (syntax-ppss)))
+ (nth 8 (save-match-data (syntax-ppss))))
(let* ((bounds (bug-reference--overlay-bounds))
(overlay (or
(let ((ov (pop overlays)))
From dbe7803aa1e8249bd70f67f25f19aedabeb9cc22 Mon Sep 17 00:00:00 2001
From: Theodor Thornhill
Date: Mon, 6 Feb 2023 09:36:08 +0100
Subject: [PATCH 13/24] Add more java indentation tests
* test/lisp/progmodes/java-ts-mode-resources/indent.erts: Use default
indent offset, and tweak the indentation examples.
---
.../java-ts-mode-resources/indent.erts | 91 +++++++++++++++----
1 file changed, 75 insertions(+), 16 deletions(-)
diff --git a/test/lisp/progmodes/java-ts-mode-resources/indent.erts b/test/lisp/progmodes/java-ts-mode-resources/indent.erts
index c8e0ac71708..4fca74dd2e1 100644
--- a/test/lisp/progmodes/java-ts-mode-resources/indent.erts
+++ b/test/lisp/progmodes/java-ts-mode-resources/indent.erts
@@ -1,7 +1,7 @@
Code:
(lambda ()
(setq indent-tabs-mode nil)
- (setq java-ts-mode-indent-offset 2)
+ (setq java-ts-mode-indent-offset 4)
(java-ts-mode)
(indent-region (point-min) (point-max)))
@@ -11,9 +11,9 @@ Name: Basic
=-=
public class Basic {
- public void basic() {
- return;
- }
+ public void basic() {
+ return;
+ }
}
=-=-=
@@ -21,9 +21,9 @@ Name: Empty Line
=-=
public class EmptyLine {
- public void emptyLine() {
- |
- }
+ public void emptyLine() {
+ |
+ }
}
=-=-=
@@ -31,15 +31,15 @@ Name: Statements
=-=
if (x) {
- for (var foo : foos) {
- |
- }
+ for (var foo : foos) {
+ |
+ }
} else if (y) {
- for (int i = 0; x < foos.size(); i++) {
- return;
- }
+ for (int i = 0; x < foos.size(); i++) {
+ return;
+ }
} else {
- return;
+ return;
}
=-=-=
@@ -47,7 +47,66 @@ Name: Field declaration without access modifier (bug#61115)
=-=
public class T {
- @Autowired
- String a;
+ @Autowired
+ String a;
+}
+=-=-=
+
+Name: Array initializer
+
+=-=
+public class Java {
+ void foo() {
+ return new String[]{
+ "foo", // These
+ "bar"
+ }
+ }
+}
+=-=-=
+
+Name: Advanced bracket matching indentation (bug#61142)
+
+=-=
+public class Java {
+
+ public Java(
+ String foo) {
+ this.foo = foo;
+ }
+
+ void foo(
+ String foo) {
+
+ for (var f : rs)
+ return new String[]{
+ "foo",
+ "bar"
+ };
+ if (a == 0
+ && b == 1
+ && foo) {
+ return 0;
+ } else if (a == 1) {
+ return 1;
+ } else if (true)
+ return 5;
+ else {
+ if (a == 0
+ && b == 1
+ && foo)
+ while (true)
+ for (
+ ;;)
+ if (true)
+ return 5;
+ else if (false) {
+ return 6;
+ } else
+ if (true
+ && false)
+ return 6;
+ }
+ }
}
=-=-=
From 900f7e07275405d8e40ce19b91eca3f5b0f3a870 Mon Sep 17 00:00:00 2001
From: Eli Zaretskii
Date: Sat, 11 Feb 2023 11:48:48 +0200
Subject: [PATCH 14/24] ; Remove extraneous local variables from
image-dired-*.el files
These cause annoying prompts when visiting these files, and evidently
belong to a third-party package.
* lisp/image/image-dired-external.el:
* lisp/image/image-dired-tags.el:
* lisp/image/image-dired-dired.el:
* lisp/image/image-dired-util.el: Remove unsafe local-variables.
---
lisp/image/image-dired-dired.el | 4 ----
lisp/image/image-dired-external.el | 4 ----
lisp/image/image-dired-tags.el | 4 ----
lisp/image/image-dired-util.el | 4 ----
4 files changed, 16 deletions(-)
diff --git a/lisp/image/image-dired-dired.el b/lisp/image/image-dired-dired.el
index 85bdd537c27..3e2b47a618f 100644
--- a/lisp/image/image-dired-dired.el
+++ b/lisp/image/image-dired-dired.el
@@ -405,8 +405,4 @@ matching tag will be marked in the Dired buffer."
(provide 'image-dired-dired)
-;; Local Variables:
-;; nameless-current-name: "image-dired"
-;; End:
-
;;; image-dired-dired.el ends here
diff --git a/lisp/image/image-dired-external.el b/lisp/image/image-dired-external.el
index b3ee4b36ad3..6e14fb1dab3 100644
--- a/lisp/image/image-dired-external.el
+++ b/lisp/image/image-dired-external.el
@@ -466,8 +466,4 @@ default value at the prompt."
(provide 'image-dired-external)
-;; Local Variables:
-;; nameless-current-name: "image-dired"
-;; End:
-
;;; image-dired-external.el ends here
diff --git a/lisp/image/image-dired-tags.el b/lisp/image/image-dired-tags.el
index 039a7a6617a..b36c526fde0 100644
--- a/lisp/image/image-dired-tags.el
+++ b/lisp/image/image-dired-tags.el
@@ -378,8 +378,4 @@ tags to their respective image file. Internal function used by
(provide 'image-dired-tags)
-;; Local Variables:
-;; nameless-current-name: "image-dired"
-;; End:
-
;;; image-dired-tags.el ends here
diff --git a/lisp/image/image-dired-util.el b/lisp/image/image-dired-util.el
index c03f9d2e3d3..ebde531f723 100644
--- a/lisp/image/image-dired-util.el
+++ b/lisp/image/image-dired-util.el
@@ -179,8 +179,4 @@ Should be used by commands in `image-dired-thumbnail-mode'."
(provide 'image-dired-util)
-;; Local Variables:
-;; nameless-current-name: "image-dired"
-;; End:
-
;;; image-dired-util.el ends here
From 2d1e43436da93defe13ad125de46e3bce41172c3 Mon Sep 17 00:00:00 2001
From: Eli Zaretskii
Date: Sat, 11 Feb 2023 12:28:43 +0200
Subject: [PATCH 15/24] ; Improve documentation of hash functions.
* src/fns.c (Fsecure_hash, Fmd5): Document the length of the
return values.
* lisp/subr.el (sha1): Describe the return value in more detail.
* doc/lispref/text.texi (Checksum/Hash): Document 'sha1'.
Document the length of the strings returned by each hashing
algorithm.
---
doc/lispref/text.texi | 47 +++++++++++++++++++++++++++++++++++++------
lisp/subr.el | 4 ++--
src/fns.c | 17 ++++++++--------
3 files changed, 52 insertions(+), 16 deletions(-)
diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index 326c111cac5..0a48beab8b8 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -4947,16 +4947,38 @@ computed for the whole of @var{object}.
If the argument @var{binary} is omitted or @code{nil}, the function
returns the @dfn{text form} of the hash, as an ordinary Lisp string.
If @var{binary} is non-@code{nil}, it returns the hash in @dfn{binary
-form}, as a sequence of bytes stored in a unibyte string.
+form}, as a sequence of bytes stored in a unibyte string. The length
+of the returned string depends on @var{algorithm}:
+
+@itemize
+@item
+For @code{md5}: 32 characters (32 bytes if @var{binary} is
+non-@code{nil}).
+@item
+For @code{sha1}: 40 characters (40 bytes if @var{binary} is
+non-@code{nil}).
+@item
+For @code{sha224}: 56 characters (56 bytes if @var{binary} is
+non-@code{nil}).
+@item
+For @code{sha256}: 64 characters (64 bytes if @var{binary} is
+non-@code{nil}).
+@item
+For @code{sha384}: 96 characters (96 bytes if @var{binary} is
+non-@code{nil}).
+@item
+For @code{sha512}: 128 characters (128 bytes if @var{binary} is
+non-@code{nil}).
+@end itemize
This function does not compute the hash directly from the internal
representation of @var{object}'s text (@pxref{Text Representations}).
Instead, it encodes the text using a coding system (@pxref{Coding
Systems}), and computes the hash from that encoded text. If
@var{object} is a buffer, the coding system used is the one which
-would be chosen by default for writing the text into a file. If
-@var{object} is a string, the user's preferred coding system is used
-(@pxref{Recognize Coding,,, emacs, GNU Emacs Manual}).
+would be chosen by default for writing the text of that buffer into a
+file. If @var{object} is a string, the user's preferred coding system
+is used (@pxref{Recognize Coding,,, emacs, GNU Emacs Manual}).
@end defun
@defun md5 object &optional start end coding-system noerror
@@ -4964,7 +4986,7 @@ This function returns an MD5 hash. It is semi-obsolete, since for
most purposes it is equivalent to calling @code{secure-hash} with
@code{md5} as the @var{algorithm} argument. The @var{object},
@var{start} and @var{end} arguments have the same meanings as in
-@code{secure-hash}.
+@code{secure-hash}. The function returns a 32-character string.
If @var{coding-system} is non-@code{nil}, it specifies a coding system
to use to encode the text; if omitted or @code{nil}, the default
@@ -4987,7 +5009,20 @@ It should be somewhat more efficient on larger buffers than
@code{secure-hash} is, and should not allocate more memory.
@c Note that we do not document what hashing function we're using, or
@c even whether it's a cryptographic hash, since that may change
-@c according to what we find useful.
+@c according to what we find useful. We also don't document the
+@c length of the hash string it returns, since that can be used to
+@c guess the hashing function being used.
+@end defun
+
+@defun sha1 object &optional start end binary
+This function is equivalent to calling @code{secure-hash} like this:
+
+@lisp
+(secure-hash 'sha1 object start end binary)
+@end lisp
+
+It returns a 40-character string if @var{binary} is @code{nil}, or a
+40-byte unibyte string otherwise.
@end defun
@node Suspicious Text
diff --git a/lisp/subr.el b/lisp/subr.el
index 32c997425cf..9e6388987df 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -4160,8 +4160,8 @@ or byte-code."
"Return the SHA-1 (Secure Hash Algorithm) of an OBJECT.
OBJECT is either a string or a buffer. Optional arguments START and
END are character positions specifying which portion of OBJECT for
-computing the hash. If BINARY is non-nil, return a string in binary
-form.
+computing the hash. If BINARY is non-nil, return a 40-byte unibyte
+string; otherwise returna 40-character string.
Note that SHA-1 is not collision resistant and should not be used
for anything security-related. See `secure-hash' for
diff --git a/src/fns.c b/src/fns.c
index 3984e318feb..ff364c65e26 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -5804,8 +5804,9 @@ secure_hash (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start,
DEFUN ("md5", Fmd5, Smd5, 1, 5, 0,
doc: /* Return MD5 message digest of OBJECT, a buffer or string.
-A message digest is a cryptographic checksum of a document, and the
-algorithm to calculate it is defined in RFC 1321.
+A message digest is the string representation of the cryptographic checksum
+of a document, and the algorithm to calculate it is defined in RFC 1321.
+The MD5 digest is 32-character long.
The two optional arguments START and END are character positions
specifying for which part of OBJECT the message digest should be
@@ -5839,12 +5840,12 @@ anything security-related. See `secure-hash' for alternatives. */)
DEFUN ("secure-hash", Fsecure_hash, Ssecure_hash, 2, 5, 0,
doc: /* Return the secure hash of OBJECT, a buffer or string.
ALGORITHM is a symbol specifying the hash to use:
-- md5 corresponds to MD5
-- sha1 corresponds to SHA-1
-- sha224 corresponds to SHA-2 (SHA-224)
-- sha256 corresponds to SHA-2 (SHA-256)
-- sha384 corresponds to SHA-2 (SHA-384)
-- sha512 corresponds to SHA-2 (SHA-512)
+- md5 corresponds to MD5, produces a 32-character signature
+- sha1 corresponds to SHA-1, produces a 40-character signature
+- sha224 corresponds to SHA-2 (SHA-224), produces a 56-character signature
+- sha256 corresponds to SHA-2 (SHA-256), produces a 64-character signature
+- sha384 corresponds to SHA-2 (SHA-384), produces a 96-character signature
+- sha512 corresponds to SHA-2 (SHA-512), produces a 128-character signature
The two optional arguments START and END are positions specifying for
which part of OBJECT to compute the hash. If nil or omitted, uses the
From dc3604cadfa8f4bc3e5d9346029e48b4268fcd60 Mon Sep 17 00:00:00 2001
From: Alan Mackenzie
Date: Sat, 11 Feb 2023 10:45:31 +0000
Subject: [PATCH 16/24] Make edebug see unused variables when lexical-binding
is non-nil
This fixes bug #59213.
* lisp/emacs-lisp/cconv.el (cconv-dont-trim-unused-variables): New variable.
(cconv-fv, cconv-make-interpreted-closure): Add/amend doc strings.
(cconv-make-interpreted-closure): Test cconv-dont-trim-unused-variables, and
if non-nil, don't "optimize" the lexical environment.
* lisp/emacs-lisp/edebug.el (edebug-make-enter-wrapper): Compile a binding of
cconv-dont-trim-unused-variables to t around the call of edebug-enter.
* lisp/emacs-lisp/testconver.el (testcover-analyze-coverage): Add a new arm to
the pcase form to handle the new form of edebug-enter.
---
lisp/emacs-lisp/cconv.el | 31 +++++++++++++++++++++++--------
lisp/emacs-lisp/edebug.el | 20 ++++++++++----------
lisp/emacs-lisp/testcover.el | 5 +++++
3 files changed, 38 insertions(+), 18 deletions(-)
diff --git a/lisp/emacs-lisp/cconv.el b/lisp/emacs-lisp/cconv.el
index 570c9e66060..b8121aeba55 100644
--- a/lisp/emacs-lisp/cconv.el
+++ b/lisp/emacs-lisp/cconv.el
@@ -113,6 +113,10 @@ is less than this number.")
(defvar cconv--dynbound-variables nil
"List of variables known to be dynamically bound.")
+(defvar cconv-dont-trim-unused-variables nil
+ "When bound to non-nil, don't remove unused variables from the environment.
+This is intended for use by edebug and similar.")
+
;;;###autoload
(defun cconv-closure-convert (form &optional dynbound-vars)
"Main entry point for closure conversion.
@@ -834,10 +838,13 @@ This function does not return anything but instead fills the
(define-obsolete-function-alias 'cconv-analyse-form #'cconv-analyze-form "25.1")
(defun cconv-fv (form lexvars dynvars)
- "Return the list of free variables in FORM.
-LEXVARS is the list of statically scoped vars in the context
-and DYNVARS is the list of dynamically scoped vars in the context.
-Returns a pair (LEXV . DYNV) of those vars actually used by FORM."
+ "Return the free variables used in FORM.
+FORM is usually a function #\\='(lambda ...), but may be any valid
+form. LEXVARS is a list of symbols, each of which is lexically
+bound in FORM's context. DYNVARS is a list of symbols, each of
+which is dynamically bound in FORM's context.
+Returns a cons (LEXV . DYNV), the car and cdr being lists of the
+lexically and dynamically bound symbols actually used by FORM."
(let* ((fun
;; Wrap FORM into a function because the analysis code we
;; have only computes freevars for functions.
@@ -875,11 +882,19 @@ Returns a pair (LEXV . DYNV) of those vars actually used by FORM."
(cons fvs dyns)))))
(defun cconv-make-interpreted-closure (fun env)
+ "Make a closure for the interpreter.
+This function is evaluated both at compile time and run time.
+FUN, the closure's function, must be a lambda form.
+ENV, the closure's environment, is a mixture of lexical bindings of the form
+(SYMBOL . VALUE) and symbols which indicate dynamic bindings of those
+symbols."
(cl-assert (eq (car-safe fun) 'lambda))
(let ((lexvars (delq nil (mapcar #'car-safe env))))
- (if (null lexvars)
- ;; The lexical environment is empty, so there's no need to
- ;; look for free variables.
+ (if (or cconv-dont-trim-unused-variables (null lexvars))
+ ;; The lexical environment is empty, or needs to be preserved,
+ ;; so there's no need to look for free variables.
+ ;; Attempting to replace ,(cdr fun) by a macroexpanded version
+ ;; causes bootstrap to fail.
`(closure ,env . ,(cdr fun))
;; We could try and cache the result of the macroexpansion and
;; `cconv-fv' analysis. Not sure it's worth the trouble.
@@ -896,7 +911,7 @@ Returns a pair (LEXV . DYNV) of those vars actually used by FORM."
(pcase expanded-form
(`#'(lambda . ,cdr) cdr)
(_ (cdr fun))))
-
+
(dynvars (delq nil (mapcar (lambda (b) (if (symbolp b) b)) env)))
(fvs (cconv-fv expanded-form lexvars dynvars))
(newenv (nconc (mapcar (lambda (fv) (assq fv env)) (car fvs))
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el
index 2f7d03e9d79..735a358cdba 100644
--- a/lisp/emacs-lisp/edebug.el
+++ b/lisp/emacs-lisp/edebug.el
@@ -1217,16 +1217,16 @@ purpose by adding an entry to this alist, and setting
(setq edebug-old-def-name nil))
(setq edebug-def-name
(or edebug-def-name edebug-old-def-name (gensym "edebug-anon")))
- `(edebug-enter
- (quote ,edebug-def-name)
- ,(if edebug-inside-func
- `(list
- ;; Doesn't work with more than one def-body!!
- ;; But the list will just be reversed.
- ,@(nreverse edebug-def-args))
- 'nil)
- (function (lambda () ,@forms))
- ))
+ `(let ((cconv-dont-trim-unused-variables t))
+ (edebug-enter
+ (quote ,edebug-def-name)
+ ,(if edebug-inside-func
+ `(list
+ ;; Doesn't work with more than one def-body!!
+ ;; But the list will just be reversed.
+ ,@(nreverse edebug-def-args))
+ 'nil)
+ (function (lambda () ,@forms)))))
(defvar edebug-form-begin-marker) ; the mark for def being instrumented
diff --git a/lisp/emacs-lisp/testcover.el b/lisp/emacs-lisp/testcover.el
index ed31b90ca32..1212905f08a 100644
--- a/lisp/emacs-lisp/testcover.el
+++ b/lisp/emacs-lisp/testcover.el
@@ -442,6 +442,11 @@ or return multiple values."
(let ((testcover-vector (get sym 'edebug-coverage)))
(testcover-analyze-coverage-progn body)))
+ (`(let ((cconv-dont-trim-unused-variables t))
+ (edebug-enter ',sym ,_ (function (lambda nil . ,body))))
+ (let ((testcover-vector (get sym 'edebug-coverage)))
+ (testcover-analyze-coverage-progn body)))
+
(`(edebug-after ,(and before-form
(or `(edebug-before ,before-id) before-id))
,after-id ,wrapped-form)
From 85a2eb2c789e7f9c1afa838817b3e9ebecb49da4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?=
Date: Fri, 10 Feb 2023 14:38:26 +0100
Subject: [PATCH 17/24] LAP peephole optimiser improvementsa
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
Make the improvements:
- Add the rule
stack-ref(X) discardN-preserve-tos(Y)
--> discard(Y) stack-ref(X-Y), X≥Y
discard(X) discardN-preserve-tos(Y-X-1), X OP return
where OP is a unary operation such as `not` or `car`.
- Generalise a previous rule to
NOEFFECT PRODUCER return --> PRODUCER return
where PRODUCER is now any op that pushes a value without looking at
the stack: const, varref, point etc.
---
lisp/emacs-lisp/byte-opt.el | 101 ++++++++++++++++++++++++++++++++++--
1 file changed, 97 insertions(+), 4 deletions(-)
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index 3eef8f385b5..833e88887f9 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -2415,11 +2415,18 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
(setq keep-going t))
;;
- ;; OP const return --> const return
- ;; where OP is side-effect-free (or mere stack manipulation).
+ ;; NOEFFECT PRODUCER return --> PRODUCER return
+ ;; where NOEFFECT lacks effects beyond stack change,
+ ;; PRODUCER pushes a result without looking at the stack:
+ ;; const, varref, point etc.
;;
- ((and (eq (car lap1) 'byte-constant)
- (eq (car (nth 2 rest)) 'byte-return)
+ ((and (eq (car (nth 2 rest)) 'byte-return)
+ (memq (car lap1) '( byte-constant byte-varref
+ byte-point byte-point-max byte-point-min
+ byte-following-char byte-preceding-char
+ byte-current-column
+ byte-eolp byte-eobp byte-bolp byte-bobp
+ byte-current-buffer byte-widen))
(or (memq (car lap0) '( byte-discard byte-discardN
byte-discardN-preserve-tos
byte-stack-set))
@@ -2430,6 +2437,35 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
(byte-compile-log-lap " %s %s %s\t-->\t%s %s"
lap0 lap1 (nth 2 rest) lap1 (nth 2 rest)))
+ ;;
+ ;; discardN-preserve-tos OP return --> OP return
+ ;; dup OP return --> OP return
+ ;; where OP is 1->1 in stack use, like `not'.
+ ;;
+ ;; FIXME: ideally we should run this backwards, so that we could do
+ ;; discardN-preserve-tos OP1...OPn return -> OP1..OPn return
+ ;; but that would require a different approach.
+ ;;
+ ((and (eq (car (nth 2 rest)) 'byte-return)
+ (memq (car lap1)
+ '( byte-not
+ byte-symbolp byte-consp byte-stringp
+ byte-listp byte-integerp byte-numberp
+ byte-list1
+ byte-car byte-cdr byte-car-safe byte-cdr-safe
+ byte-length
+ byte-add1 byte-sub1 byte-negate byte-nreverse
+ ;; There are more of these but the list is
+ ;; getting long and the gain is small.
+ ))
+ (or (memq (car lap0) '(byte-discardN-preserve-tos byte-dup))
+ (and (eq (car lap0) 'byte-stack-set)
+ (eql (cdr lap0) 1))))
+ (setq keep-going t)
+ (setcdr prev (cdr rest)) ; eat lap0
+ (byte-compile-log-lap " %s %s %s\t-->\t%s %s"
+ lap0 lap1 (nth 2 rest) lap1 (nth 2 rest)))
+
;;
;; goto-*-else-pop X ... X: goto-if-* --> whatever
;; goto-*-else-pop X ... X: discard --> whatever
@@ -2659,6 +2695,63 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
(setcdr prev (cdr rest))
(byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1 lap1))
+ ;;
+ ;; stack-ref(X) discardN-preserve-tos(Y)
+ ;; --> discard(Y) stack-ref(X-Y), X≥Y
+ ;; discard(X) discardN-preserve-tos(Y-X-1), X y 0))
+ (cond
+ ((>= x y) ; --> discard(Y) stack-ref(X-Y)
+ (let ((new0 (if (= y 1)
+ (cons 'byte-discard nil)
+ (cons 'byte-discardN y)))
+ (new1 (if (= x y)
+ (cons 'byte-dup nil)
+ (cons 'byte-stack-ref (- x y)))))
+ (byte-compile-log-lap " %s %s\t-->\t%s %s"
+ lap0 lap1 new0 new1)
+ (setcar rest new0)
+ (setcar (cdr rest) new1)))
+ ((= x 0) ; --> discardN-preserve-tos(Y-1)
+ (setcdr prev (cdr rest)) ; eat lap0
+ (if (> y 1)
+ (let ((new (cons 'byte-discardN-preserve-tos (- y 1))))
+ (byte-compile-log-lap " %s %s\t-->\t%s"
+ lap0 lap1 new)
+ (setcar (cdr prev) new))
+ (byte-compile-log-lap " %s %s\t-->\t" lap0 lap1)
+ (setcdr prev (cddr prev)))) ; eat lap1
+ ((= y (+ x 1)) ; --> discard(X)
+ (setcdr prev (cdr rest)) ; eat lap0
+ (let ((new (if (= x 1)
+ (cons 'byte-discard nil)
+ (cons 'byte-discardN x))))
+ (byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1 new)
+ (setcar (cdr prev) new)))
+ (t ; --> discard(X) discardN-preserve-tos(Y-X-1)
+ (let ((new0 (if (= x 1)
+ (cons 'byte-discard nil)
+ (cons 'byte-discardN x)))
+ (new1 (cons 'byte-discardN-preserve-tos (- y x 1))))
+ (byte-compile-log-lap " %s %s\t-->\t%s %s"
+ lap0 lap1 new0 new1)
+ (setcar rest new0)
+ (setcar (cdr rest) new1)))))
+ (setq keep-going t))
+
;;
;; goto-X ... X: discard ==> discard goto-Y ... X: discard Y:
;;
From 074008ee2d24167ca21d5846e3d5a4466a1691a2 Mon Sep 17 00:00:00 2001
From: Eli Zaretskii
Date: Sat, 11 Feb 2023 16:49:54 +0200
Subject: [PATCH 18/24] ; Fix doc strings in lisp/image/ directory
* lisp/image/wallpaper.el (wallpaper-setter)
(wallpaper--find-command, wallpaper--x-monitor-name)
(wallpaper--format-arg):
* lisp/image/image-dired-util.el
(image-dired-associated-dired-buffer)
(image-dired--with-dired-buffer):
* lisp/image/image-dired-tags.el (image-dired--with-db-file)
(image-dired-remove-tag, image-dired-list-tags)
(image-dired-tag-files, image-dired-write-comments)
(image-dired-update-property):
* lisp/image/image-dired-external.el (image-dired-cmd-pngnq-options)
(image-dired-cmd-pngcrush-program)
(image-dired-cmd-pngcrush-options)
(image-dired-cmd-optipng-options)
(image-dired-cmd-create-standard-thumbnail-options)
(image-dired-cmd-rotate-original-program)
(image-dired-cmd-rotate-original-options)
(image-dired-cmd-write-exif-data-options, image-dired-queue)
(image-dired-queue-active-limit, image-dired-pngnq-thumb)
(image-dired-pngcrush-thumb, image-dired-optipng-thumb)
(image-dired-thumb-queue-run, image-dired-get-exif-file-name)
(image-dired-thumbnail-set-image-description):
* lisp/image/image-dired.el (image-dired-thumbnail-storage)
(image-dired-tags-db-file)
(image-dired-rotate-original-ask-before-overwrite)
(image-dired-line-up-method, image-dired-track-movement)
(image-dired-display-properties-format)
(image-dired-external-viewer)
(image-dired-show-all-from-dir-max-files)
(image-dired-insert-image)
(image-dired-dired-with-window-configuration)
(image-dired-restore-window-configuration)
(image-dired-track-original-file)
(image-dired-toggle-movement-tracking)
(image-dired-format-properties-string)
(image-dired--on-file-in-dired-buffer)
(image-dired-thumbnail-display-external)
(image-dired-display-image, image-dired-copy-filename-as-kill):
* lisp/image/image-dired-dired.el
(image-dired-dired-toggle-marked-thumbs)
(image-dired-dired-after-readin-hook)
(image-dired-next-line-and-display)
(image-dired-previous-line-and-display)
(image-dired-mark-and-display-next, image-dired-track-thumbnail)
(image-dired-dired-next-line, image-dired-dired-previous-line)
(image-dired-dired-display-external)
(image-dired-copy-with-exif-file-name)
(image-dired-mark-tagged-files)
(image-dired-dired-display-properties):
* lisp/image/image-crop.el (image-crop-exif-rotate)
(image-crop-resize-command, image-crop-cut-command)
(image-crop-crop-command, image-crop-rotate-command)
(image-crop-buffer-text-function, image-cut-color):
* lisp/image/image-converter.el (image-converter)
(image-convert-to-format, image-converter-regexp)
(image-converter--converters, image-convert-p, image-convert)
(image-converter--value, image-converter--probe)
(image-converter--find-converter, image-converter--convert)
(image-converter-add-handler):
* lisp/image/exif.el (exif-parse-buffer, exif-field)
(exif-orientation, exif--direct-ascii-value)
(exif--process-value, exif--read-chunk, exif--read-number-be)
(exif--read-number-le, exif--read-number): Fix doc strings.
---
lisp/image/exif.el | 47 ++++++++++-------
lisp/image/image-converter.el | 71 +++++++++++++------------
lisp/image/image-crop.el | 48 ++++++++---------
lisp/image/image-dired-dired.el | 52 +++++++++---------
lisp/image/image-dired-external.el | 48 +++++++++--------
lisp/image/image-dired-tags.el | 16 +++---
lisp/image/image-dired-util.el | 4 +-
lisp/image/image-dired.el | 84 ++++++++++++++++--------------
lisp/image/wallpaper.el | 8 +--
9 files changed, 197 insertions(+), 181 deletions(-)
diff --git a/lisp/image/exif.el b/lisp/image/exif.el
index c561ea729af..503e3ffadc7 100644
--- a/lisp/image/exif.el
+++ b/lisp/image/exif.el
@@ -110,7 +110,7 @@ from the return value of this function."
(exif-parse-buffer)))
(defun exif-parse-buffer (&optional buffer)
- "Parse BUFFER (which should be a JPEG file) and return the Exif data, if any.
+ "Parse BUFFER (which should visit a JPEG file) and return Exif data, if any.
The return value is a list of Exif items.
If the data is invalid, an `exif-error' is signaled.
@@ -134,17 +134,17 @@ from the return value of this function."
(exif--parse-exif-chunk app1))))))
(defun exif-field (field data)
- "Return raw FIELD from EXIF.
+ "Return raw FIELD from Exif DATA.
If FIELD is not present in the data, return nil.
FIELD is a symbol in the cdr of `exif-tag-alist'.
-DATA is the result of calling `exif-parse-file'."
+DATA is the result of calling `exif-parse-file' or `exif-parse-buffer'."
(plist-get (seq-find (lambda (e)
(eq field (plist-get e :tag-name)))
data)
:value))
(defun exif-orientation (exif)
- "Return the orientation (in degrees) in EXIF.
+ "Return the orientation (in degrees) in EXIF data.
If the orientation isn't present in the data, return nil."
(let ((code (exif-field 'orientation exif)))
(cadr (assq code exif--orientation))))
@@ -254,21 +254,24 @@ If the orientation isn't present in the data, return nil."
;; We've reached the end of the directories.
dir))))
-(defun exif--direct-ascii-value (value bytes le)
- "Make VALUE into a zero-terminated string.
-VALUE is an integer representing BYTES characters."
+(defun exif--direct-ascii-value (value nbytes le)
+ "Make a string representing VALUE with NBYTES bytes according to LE endianness.
+VALUE is an integer value of NBYTES bytes.
+The return value is a null-terminated unibyte string whose length is
+NBYTES+1 bytes. If LE is non-nil, the returned string representation of
+VALUE is little-endian, otherwise it is big-endian."
(with-temp-buffer
(set-buffer-multibyte nil)
(if le
- (dotimes (i bytes)
+ (dotimes (i nbytes)
(insert (logand (ash value (* i -8)) 255)))
- (dotimes (i bytes)
- (insert (logand (ash value (* (- (1- bytes) i) -8)) 255))))
+ (dotimes (i nbytes)
+ (insert (logand (ash value (* (- (1- nbytes) i) -8)) 255))))
(insert 0)
(buffer-string)))
(defun exif--process-value (value type le)
- "Do type-based post-processing of the value."
+ "Do type-based post-processing of the VALUE whose endianness is per LE."
(cl-case type
;; Chop off trailing zero byte.
(ascii (substring value 0 (1- (length value))))
@@ -281,7 +284,8 @@ VALUE is an integer representing BYTES characters."
(otherwise value)))
(defun exif--read-chunk (bytes)
- "Return BYTES octets from the buffer and advance point that much."
+ "Return BYTES octets from the current buffer and advance point that much.
+This function assumes that the current buffer is unibyte."
(when (> (+ (point) bytes) (point-max))
(signal 'exif-error "Premature end of file"))
(prog1
@@ -289,8 +293,9 @@ VALUE is an integer representing BYTES characters."
(forward-char bytes)))
(defun exif--read-number-be (bytes)
- "Read BYTES octets from the buffer as a chunk of big-endian bytes.
-Advance point to after the read bytes."
+ "Read BYTES octets from the current buffer as a chunk of big-endian bytes.
+Advance point to after the read bytes.
+This function assumes that the current buffer is unibyte."
(when (> (+ (point) bytes) (point-max))
(signal 'exif-error "Premature end of file"))
(let ((sum 0))
@@ -300,8 +305,9 @@ Advance point to after the read bytes."
sum))
(defun exif--read-number-le (bytes)
- "Read BYTES octets from the buffer as a chunk of low-endian bytes.
-Advance point to after the read bytes."
+ "Read BYTES octets from the current buffer as a chunk of little-endian bytes.
+Advance point to after the read bytes.
+This function assumes that the current buffer is unibyte."
(when (> (+ (point) bytes) (point-max))
(signal 'exif-error "Premature end of file"))
(let ((sum 0))
@@ -310,10 +316,11 @@ Advance point to after the read bytes."
(forward-char 1))
sum))
-(defun exif--read-number (bytes lower-endian)
- "Read BYTES octets from the buffer with endianness determined by LOWER-ENDIAN.
-Advance point to after the read bytes."
- (if lower-endian
+(defun exif--read-number (bytes little-endian)
+ "Read BYTES octets from current buffer with endianness given by LITTLE-ENDIAN.
+Advance point to after the read bytes.
+This function assumes that the current buffer is unibyte."
+ (if little-endian
(exif--read-number-le bytes)
(exif--read-number-be bytes)))
diff --git a/lisp/image/image-converter.el b/lisp/image/image-converter.el
index 596e623357e..ff9d4ad0d82 100644
--- a/lisp/image/image-converter.el
+++ b/lisp/image/image-converter.el
@@ -38,9 +38,9 @@ If nil, Emacs will try to find one of the supported converters
installed on the system.
The actual range of image formats that will be converted depends
-on what image formats the chosen converter reports being able to
-handle. `auto-mode-alist' is then used to further filter what
-formats that are to be supported: Only the suffixes that map to
+on the image formats which the chosen converter is able to
+handle. `auto-mode-alist' is then used to further filter the
+formats that are to be supported: only the suffixes that map to
`image-mode' will be handled."
:group 'image
:type 'symbol
@@ -48,16 +48,16 @@ formats that are to be supported: Only the suffixes that map to
(defcustom image-convert-to-format "png"
"The image format to convert to.
-This should be a string like \"png\" or \"ppm\" or some
+This should be a string like \"png\" or \"ppm\", or some
other (preferably lossless) format that Emacs understands
-natively. The converter chosen has to support the format, and if
-not, conversion will fail."
+natively. The converter chosen has to support this format; if
+not, the conversion will fail."
:group 'image
:version "29.1"
:type 'string)
(defvar image-converter-regexp nil
- "A regexp that matches the file name suffixes that can be converted.")
+ "A regexp that matches the file name suffixes which can be converted.")
(defvar image-converter-file-name-extensions nil
"A list of file name suffixes that can be converted.")
@@ -66,7 +66,7 @@ not, conversion will fail."
'((graphicsmagick :command ("gm" "convert") :probe ("-list" "format"))
(ffmpeg :command "ffmpeg" :probe "-decoders")
(imagemagick :command "convert" :probe ("-list" "format")))
- "List of supported image converters to try.")
+ "List of supported image converters to try and required command-line switches.")
(defvar image-converter--extra-converters (make-hash-table :test #'equal))
@@ -80,8 +80,8 @@ This also determines which external formats we can parse."
"Return `image-convert' if SOURCE is an image that can be converted.
SOURCE can either be a file name or a string containing image
data. In the latter case, DATA-P should be non-nil. If DATA-P
-is a string, it should be a MIME format string like
-\"image/gif\"."
+is a string, it should be a MIME format string specifying the image type,
+like \"image/gif\"."
(image-converter-initialize)
;; When image-converter was customized
(when (and image-converter (not image-converter-regexp))
@@ -101,22 +101,21 @@ is a string, it should be a MIME format string like
'image-convert))
(defun image-convert (image &optional image-format)
- "Convert IMAGE file to an image format Emacs understands.
-This will usually be \"png\", but this is controlled by the
-`image-convert-to-format' user option.
+ "Convert IMAGE to an image format which Emacs understands.
+This will usually be \"png\", but is controlled by the value
+of the `image-convert-to-format' user option.
-IMAGE can either be a file name or image data.
-
-To pass in image data, IMAGE should a string containing the image
-data, and IMAGE-FORMAT should be a symbol with a MIME format name
-like \"image/webp\". For instance:
+IMAGE can either be a file name, an image object returned
+by `create-image', or a string with image data. In the latter
+case, IMAGE-FORMAT should be a symbol whose name is a MIME
+specification of image format, such as \"image/webp\".
+For instance:
(image-convert data-string \\='image/bmp)
-IMAGE can also be an image object as returned by `create-image'.
-
-This function converts the image the preferred format, and the
-converted image data is returned as a string."
+This function converts the image to the preferred format, per
+the value of `image-convert-to-format', and returns the
+converted image data as a string."
(image-converter-initialize)
(unless image-converter
(error "No external image converters available"))
@@ -152,14 +151,14 @@ converted image data is returned as a string."
(buffer-string))))
(defun image-converter--value (type elem)
- "Return the value of ELEM of image converter TYPE."
+ "Return the value of property ELEM for image converter TYPE."
(let ((value (plist-get (cdr (assq type image-converter--converters)) elem)))
(if (stringp value)
(list value)
value)))
(cl-defmethod image-converter--probe ((type (eql 'graphicsmagick)))
- "Check whether the system has GraphicsMagick installed."
+ "Check whether the system has GraphicsMagick installed that's usable converter."
(with-temp-buffer
(let ((command (image-converter--value type :command))
formats)
@@ -177,7 +176,7 @@ converted image data is returned as a string."
(nreverse formats)))))
(cl-defmethod image-converter--probe ((type (eql 'imagemagick)))
- "Check whether the system has ImageMagick installed."
+ "Check whether the system has ImageMagick installed that's a usable converter."
(with-temp-buffer
(let ((command (image-converter--value type :command))
formats)
@@ -197,7 +196,7 @@ converted image data is returned as a string."
(nreverse formats))))
(cl-defmethod image-converter--probe ((type (eql 'ffmpeg)))
- "Check whether the system has ffmpeg installed."
+ "Check whether the system has ffmpeg installed that's a usable converter."
(with-temp-buffer
(let ((command (image-converter--value type :command))
formats)
@@ -215,7 +214,7 @@ converted image data is returned as a string."
(nreverse formats)))))
(defun image-converter--find-converter ()
- "Find an installed image converter."
+ "Find an installed image converter Emacs can use."
(catch 'done
(dolist (elem image-converter--converters)
(when-let ((formats (image-converter--filter-formats
@@ -239,12 +238,12 @@ Only suffixes that map to `image-mode' are returned."
(cl-defmethod image-converter--convert ((type (eql 'graphicsmagick)) source
image-format)
- "Convert using GraphicsMagick."
+ "Convert image in SOURCE using GraphicsMagick."
(image-converter--convert-magick type source image-format))
(cl-defmethod image-converter--convert ((type (eql 'imagemagick)) source
image-format)
- "Convert using ImageMagick."
+ "Convert image in SOURCE using ImageMagick."
(image-converter--convert-magick type source image-format))
(defun image-converter--mime-type (image-format)
@@ -281,7 +280,7 @@ Only suffixes that map to `image-mode' are returned."
(cl-defmethod image-converter--convert ((type (eql 'ffmpeg)) source
image-format)
- "Convert using ffmpeg."
+ "Convert image in SOURCE using ffmpeg."
(let ((command (image-converter--value type :command))
(coding-system-for-read 'no-conversion))
(unless (zerop (if image-format
@@ -308,12 +307,12 @@ Only suffixes that map to `image-mode' are returned."
;;;###autoload
(defun image-converter-add-handler (suffix converter)
- "Make Emacs use CONVERTER to parse image files that end with SUFFIX.
-CONVERTER is a function with two parameters, where the first is
-the file name or a string with the image data, and the second is
-non-nil if the first parameter is image data. The converter
-should output the image in the current buffer, converted to
-`image-convert-to-format'."
+ "Make Emacs use CONVERTER to parse image files whose names end with SUFFIX.
+CONVERTER is a function with two arguments, the file name or a string
+with the image data, and a non-nil value if the first argument is image data.
+The converter should produce the image in the current buffer, converted to
+the format given by `image-convert-to-format'.
+SUFFIX should not include the leading dot."
(cl-pushnew suffix image-converter-file-name-extensions :test #'equal)
(setq image-converter-file-name-extensions
(sort image-converter-file-name-extensions #'string<))
diff --git a/lisp/image/image-crop.el b/lisp/image/image-crop.el
index e6e5abf53d8..be6e22bc606 100644
--- a/lisp/image/image-crop.el
+++ b/lisp/image/image-crop.el
@@ -41,71 +41,71 @@
:group 'image)
(defvar image-crop-exif-rotate nil
- "If non-nil, rotate images by updating exif data.
+ "If non-nil, rotate images by updating Exif data.
If nil, rotate the images \"physically\".")
(defcustom image-crop-resize-command '("convert" "-resize" "%wx" "-" "%f:-")
- "Command to resize an image.
-The following `format-spec' elements are allowed:
+ "List of command and command-line arguments to resize an image.
+The following `format-spec' elements are allowed in the value:
%w: Width.
-%f: Result file type."
+%f: File type to produce."
:type '(repeat string)
:version "29.1")
(defcustom image-crop-cut-command '("convert" "-draw" "rectangle %l,%t %r,%b"
"-fill" "%c"
"-" "%f:-")
- "Command to cut a rectangle out of an image.
+ "List of command and its command-line arguments to cut a rectangle out of image.
-The following `format-spec' elements are allowed:
+The following `format-spec' elements are allowed in the value:
%l: Left.
%t: Top.
%r: Right.
%b: Bottom.
%c: Color.
-%f: Result file type."
+%f: File type to produce."
:type '(repeat string)
:version "29.1")
(defcustom image-crop-crop-command '("convert" "+repage" "-crop" "%wx%h+%l+%t"
"-" "%f:-")
- "Command to crop an image.
+ "List of command and its command-line arguments to crop an image.
-The following `format-spec' elements are allowed:
+The following `format-spec' elements are allowed in the value:
%l: Left.
%t: Top.
%w: Width.
%h: Height.
-%f: Result file type."
+%f: File type to produce."
:type '(repeat string)
:version "29.1")
(defcustom image-crop-rotate-command '("convert" "-rotate" "%r" "-" "%f:-")
- "Command to rotate an image.
+ "List of command and its command-line arguments to rotate an image.
-The following `format-spec' elements are allowed:
+The following `format-spec' elements are allowed in the value:
%r: Rotation (in degrees).
-%f: Result file type."
+%f: File type to produce."
:type '(repeat string)
:version "29.1")
(defvar image-crop-buffer-text-function #'image-crop--default-buffer-text
- "Function to return the buffer text for the cropped image.
-After cropping an image, the displayed image will be updated to
-show the cropped image in the buffer. Different modes will have
-different ways to represent this image data in a buffer. For
-instance, an HTML-based mode might want to represent the image
-with
, but that's up to the mode.
+ "Function to return the buffer text corresponding to the cropped image.
+After cropping an image, the displayed image in the buffer will be updated
+to show the cropped image. Different modes will have different ways to
+represent this image data in a buffer, but that's up to the mode. For
+instance, an HTML-based mode might want to represent the image with
+
.
-The default action is to not alter the buffer text at all.
+The default action is to not alter the image's text in the buffer, and
+just return it.
-The function is called with two arguments: The first is the
-original buffer text, and the second parameter is the cropped
-image data.")
+The function is called with two arguments: the original buffer text,
+and the cropped image data.")
(defcustom image-cut-color "black"
- "Color to use for the rectangle cut from the image."
+ "Color to use for the rectangle that was cut from the image."
:type 'string
:version "29.1")
diff --git a/lisp/image/image-dired-dired.el b/lisp/image/image-dired-dired.el
index 3e2b47a618f..15230c9e42a 100644
--- a/lisp/image/image-dired-dired.el
+++ b/lisp/image/image-dired-dired.el
@@ -57,11 +57,12 @@ Dired and you might want to turn it off."
;;;###autoload
(defun image-dired-dired-toggle-marked-thumbs (&optional arg)
- "Toggle thumbnails in front of file names in the Dired buffer.
-If no marked file could be found, insert or hide thumbnails on the
-current line. ARG, if non-nil, specifies the files to use instead
-of the marked files. If ARG is an integer, use the next ARG (or
-previous -ARG, if ARG<0) files."
+ "Toggle thumbnails in front of marked file names in the Dired buffer.
+If no file is marked, toggle display of thumbnail on the current file's line.
+ARG, if non-nil (interactively, the prefix argument), specifies the files
+whose thumbnail display to toggle instead of the marked files: if ARG is an
+integer, use the next ARG (or previous -ARG, if ARG<0) files; any other
+value of ARG means toggle thumbnail display of the current line's file."
(interactive "P" dired-mode)
(setq image-dired--generate-thumbs-start (current-time))
(dired-map-over-marks
@@ -91,8 +92,8 @@ previous -ARG, if ARG<0) files."
(defun image-dired-dired-after-readin-hook ()
"Relocate existing thumbnail overlays in Dired buffer after reverting.
-Move them to their corresponding files if they still exist.
-Otherwise, delete overlays.
+Move each overlay to its corresponding file if it still exists.
+Otherwise, delete the overlay.
Used by `image-dired-dired-toggle-marked-thumbs'."
(mapc (lambda (overlay)
(when (overlay-get overlay 'put-image)
@@ -104,7 +105,7 @@ Used by `image-dired-dired-toggle-marked-thumbs'."
(overlays-in (point-min) (point-max))))
(defun image-dired-next-line-and-display ()
- "Move to next Dired line and display thumbnail image."
+ "Move to next Dired line and display its thumbnail image."
(interactive nil dired-mode)
(dired-next-line 1)
(image-dired-display-thumbs t image-dired-dired-append-when-browsing t)
@@ -112,7 +113,7 @@ Used by `image-dired-dired-toggle-marked-thumbs'."
(image-dired-dired-display-properties)))
(defun image-dired-previous-line-and-display ()
- "Move to previous Dired line and display thumbnail image."
+ "Move to previous Dired line and display its thumbnail image."
(interactive nil dired-mode)
(dired-previous-line 1)
(image-dired-display-thumbs t image-dired-dired-append-when-browsing t)
@@ -130,7 +131,7 @@ Used by `image-dired-dired-toggle-marked-thumbs'."
"off")))
(defun image-dired-mark-and-display-next ()
- "Mark current file in Dired and display next thumbnail image."
+ "Mark current file in Dired and display the next thumbnail image."
(interactive nil dired-mode)
(dired-mark 1)
(image-dired-display-thumbs t image-dired-dired-append-when-browsing t)
@@ -148,7 +149,7 @@ Used by `image-dired-dired-toggle-marked-thumbs'."
"off")))
(defun image-dired-track-thumbnail ()
- "Track current Dired file's thumb in `image-dired-thumbnail-buffer'.
+ "Move to thumbnail of the current Dired file in `image-dired-thumbnail-buffer'.
This is almost the same as what `image-dired-track-original-file' does,
but the other way around."
(let ((file (dired-get-filename))
@@ -170,18 +171,18 @@ but the other way around."
(image-dired--update-header-line))))))
(defun image-dired-dired-next-line (&optional arg)
- "Call `dired-next-line', then track thumbnail.
+ "Call `dired-next-line', while tracking the file's thumbnail.
This can safely replace `dired-next-line'.
-With prefix argument, move ARG lines."
+With prefix argument ARG, move that many lines."
(interactive "P" dired-mode)
(dired-next-line (or arg 1))
(if image-dired-track-movement
(image-dired-track-thumbnail)))
(defun image-dired-dired-previous-line (&optional arg)
- "Call `dired-previous-line', then track thumbnail.
+ "Call `dired-previous-line', while tracking the file's thumbnail.
This can safely replace `dired-previous-line'.
-With prefix argument, move ARG lines."
+With prefix argument ARG, move that many lines."
(interactive "P" dired-mode)
(dired-previous-line (or arg 1))
(if image-dired-track-movement
@@ -307,7 +308,8 @@ With prefix argument ARG, create thumbnails even if they already exist
;;;###autoload
(defun image-dired-dired-display-external ()
- "Display file at point using an external viewer."
+ "Display file at point using an external viewer.
+The viewer is specified by the value of `image-dired-external-viewer'."
(interactive nil dired-mode)
(let ((file (dired-get-filename)))
(start-process "image-dired-external" nil
@@ -323,15 +325,15 @@ See documentation for `image-dired-display-image' for more information."
(defun image-dired-copy-with-exif-file-name ()
"Copy file with unique name to main image directory.
-Copy current or all marked files in Dired to a new file in your
-main image directory, using a file name generated by
+Copy current or all files marked in Dired to new file(s) in your
+main image directory, using file name(s) generated by
`image-dired-get-exif-file-name'. A typical usage for this if when
copying images from a digital camera into the image directory.
- Typically, you would open up the folder with the incoming
+Typically, you would open up the folder with the incoming
digital images, mark the files to be copied, and execute this
-function. The result is a couple of new files in
-`image-dired-main-image-directory' called
+command. The result is one or more new files in
+`image-dired-main-image-directory', named like
2005_05_08_12_52_00_dscn0319.jpg,
2005_05_08_14_27_45_dscn0320.jpg etc."
(interactive nil dired-mode)
@@ -350,11 +352,11 @@ function. The result is a couple of new files in
;;;###autoload
(defun image-dired-mark-tagged-files (regexp)
- "Use REGEXP to mark files with matching tag.
+ "Mark files whose tag matches REGEXP.
A `tag' is a keyword, a piece of meta data, associated with an
image file and stored in image-dired's database file. This command
-lets you input a regexp and this will be matched against all tags
-on all image files in the database file. The files that have a
+promts for a regexp, and then matches it against all the tags
+of all the image files in the database file. The files that have a
matching tag will be marked in the Dired buffer."
(interactive "sMark tagged files (regexp): " dired-mode)
(image-dired-sane-db-file)
@@ -386,7 +388,7 @@ matching tag will be marked in the Dired buffer."
(message "%d files with matching tag marked" hits)))
(defun image-dired-dired-display-properties ()
- "Display properties for Dired file in the echo area."
+ "Show in the echo area the image-related properties of a file in Dired buffer."
(interactive nil dired-mode)
(let* ((file-name (dired-get-filename))
(dired-buf (buffer-name (current-buffer)))
diff --git a/lisp/image/image-dired-external.el b/lisp/image/image-dired-external.el
index 6e14fb1dab3..9f35e17a7e6 100644
--- a/lisp/image/image-dired-external.el
+++ b/lisp/image/image-dired-external.el
@@ -86,15 +86,15 @@ using the NeuQuant algorithm."
(if (executable-find "pngquant")
'("--ext" "-nq8.png" "%t") ; same extension as "pngnq"
'("-f" "%t"))
- "Arguments to pass `image-dired-cmd-pngnq-program'.
-Available format specifiers are the same as in
+ "Arguments to pass to `image-dired-cmd-pngnq-program'.
+Value can use the same format specifiers as in
`image-dired-cmd-create-thumbnail-options'."
:type '(repeat (string :tag "Argument"))
:version "29.1")
(defcustom image-dired-cmd-pngcrush-program (executable-find "pngcrush")
"The file name of the `pngcrush' program.
-It optimizes the compression of PNG images. Also it adds PNG textual chunks
+It optimizes the compression of PNG images. It also adds PNG textual chunks
with the information required by the Thumbnail Managing Standard."
:type '(choice (const :tag "Not Set" nil) file))
@@ -110,7 +110,7 @@ with the information required by the Thumbnail Managing Standard."
"-text" "b" "Thumb::URI" "file://%f"
"%q" "%t")
"Arguments for `image-dired-cmd-pngcrush-program'.
-The available %-format specifiers are the same as in
+The value can use the same %-format specifiers as in
`image-dired-cmd-create-thumbnail-options', with \"%q\" for a
temporary file name (typically generated by pnqnq)."
:version "26.1"
@@ -123,7 +123,7 @@ temporary file name (typically generated by pnqnq)."
(defcustom image-dired-cmd-optipng-options '("-o5" "%t")
"Arguments passed to `image-dired-cmd-optipng-program'.
-Available format specifiers are described in
+The value can use format specifiers described in
`image-dired-cmd-create-thumbnail-options'."
:version "26.1"
:type '(repeat (string :tag "Argument"))
@@ -139,14 +139,14 @@ Available format specifiers are described in
"-thumbnail" "%wx%h>" "png:%t")))
(if (executable-find "gm") (cons "convert" opts) opts))
"Options for creating thumbnails according to the Thumbnail Managing Standard.
-The available %-format specifiers are the same as in
+The value can use the same %-format specifiers as in
`image-dired-cmd-create-thumbnail-options', with \"%m\" for file
modification time."
:type '(repeat (string :tag "Argument"))
:version "29.1")
(defcustom image-dired-cmd-rotate-original-program "jpegtran"
- "Executable used to rotate original image.
+ "Executable program used to rotate original image.
Used together with `image-dired-cmd-rotate-original-options'."
:type 'file)
@@ -154,11 +154,11 @@ Used together with `image-dired-cmd-rotate-original-options'."
'("-rotate" "%d" "-copy" "all" "-outfile" "%t" "%o")
"Arguments of command used to rotate original image.
Used with `image-dired-cmd-rotate-original-program'.
-Available format specifiers are: %d which is replaced by the
-number of (positive) degrees to rotate the image, normally 90 or
-270 \(for 90 degrees right and left), %o which is replaced by the
-original image file name and %t which is replaced by
-`image-dired-temp-image-file'."
+The value can use the following format specifiers:
+%d which is replaced by the number of (positive) degrees
+to rotate the image, normally 90 or 270 (for 90 degrees right and left),
+%o which is replaced by the original image file name
+and %t which is replaced by `image-dired-temp-image-file'."
:version "26.1"
:type '(repeat (string :tag "Argument")))
@@ -176,9 +176,10 @@ Used together with `image-dired-cmd-write-exif-data-options'."
(defcustom image-dired-cmd-write-exif-data-options '("-%t=%v" "%f")
"Arguments of command used to write EXIF data.
Used with `image-dired-cmd-write-exif-data-program'.
-Available format specifiers are: %f which is replaced by
-the image file name, %t which is replaced by the tag name and %v
-which is replaced by the tag value."
+The value can use the following format specifiers are:
+%f which is replaced by the image file name,
+%t which is replaced by the tag name
+and %v which is replaced by the tag value."
:version "26.1"
:type '(repeat (string :tag "Argument")))
@@ -206,7 +207,7 @@ which is replaced by the tag value."
"Time when `display-thumbs' was called.")
(defvar image-dired-queue nil
- "List of items in the queue.
+ "List of items in the Image-Dired queue.
Each item has the form (ORIGINAL-FILE TARGET-FILE).")
(defvar image-dired-queue-active-jobs 0
@@ -214,13 +215,13 @@ Each item has the form (ORIGINAL-FILE TARGET-FILE).")
(defvar image-dired-queue-active-limit (min 4 (max 2 (/ (num-processors) 2)))
"Maximum number of concurrent jobs permitted for generating images.
-Increase at own risk. If you want to experiment with this,
+Increase at your own risk. If you want to experiment with this,
consider setting `image-dired-debug' to a non-nil value to see
the time spent on generating thumbnails. Run `clear-image-cache'
and remove the cached thumbnail files between each trial run.")
(defun image-dired-pngnq-thumb (spec)
- "Quantize thumbnail described by format SPEC with pngnq(1)."
+ "Quantize thumbnail described by format SPEC with command `pngnq'."
(let ((process
(apply #'start-process "image-dired-pngnq" nil
image-dired-cmd-pngnq-program
@@ -243,7 +244,7 @@ and remove the cached thumbnail files between each trial run.")
process))
(defun image-dired-pngcrush-thumb (spec)
- "Optimize thumbnail described by format SPEC with pngcrush(1)."
+ "Optimize thumbnail described by format SPEC with command `pngcrush'."
;; If pngnq wasn't run, then the THUMB-nq8.png file does not exist.
;; pngcrush needs an infile and outfile, so we just copy THUMB to
;; THUMB-nq8.png and use the latter as a temp file.
@@ -268,7 +269,7 @@ and remove the cached thumbnail files between each trial run.")
process))
(defun image-dired-optipng-thumb (spec)
- "Optimize thumbnail described by format SPEC with optipng(1)."
+ "Optimize thumbnail described by format SPEC with command `optipng'."
(let ((process
(apply #'start-process "image-dired-optipng" nil
image-dired-cmd-optipng-program
@@ -354,7 +355,8 @@ and remove the cached thumbnail files between each trial run.")
(defun image-dired-thumb-queue-run ()
"Run a queued job if one exists and not too many jobs are running.
-Queued items live in `image-dired-queue'."
+Queued items live in `image-dired-queue'.
+Number of simultaneous jobs is limited by `image-dired-queue-active-limit'."
(while (and image-dired-queue
(< image-dired-queue-active-jobs
image-dired-queue-active-limit))
@@ -414,7 +416,7 @@ The new file will be named THUMBNAIL-FILE."
The file name should be unique as long as you do not take more than
one picture per second. The original file name is suffixed at the end
for traceability. The format of the returned file name is
-YYYY_MM_DD_HH_MM_DD_ORIG_FILE_NAME.jpg. Used from
+YYYY_MM_DD_HH_MM_ss_ORIG_FILE_NAME.jpg. Used from
`image-dired-copy-with-exif-file-name'."
(let (data no-exif-data-found)
(if (not (eq 'jpeg (image-type (expand-file-name file))))
@@ -434,7 +436,7 @@ YYYY_MM_DD_HH_MM_DD_ORIG_FILE_NAME.jpg. Used from
(file-name-nondirectory file))))
(defun image-dired-thumbnail-set-image-description ()
- "Set the ImageDescription EXIF tag for the original image.
+ "Set the ImageDescription EXIF tag for the original image at point.
If the image already has a value for this tag, it is used as the
default value at the prompt."
(interactive nil image-dired-thumbnail-mode)
diff --git a/lisp/image/image-dired-tags.el b/lisp/image/image-dired-tags.el
index b36c526fde0..b9c1a811850 100644
--- a/lisp/image/image-dired-tags.el
+++ b/lisp/image/image-dired-tags.el
@@ -39,7 +39,7 @@
(defmacro image-dired--with-db-file (&rest body)
"Run BODY in a temp buffer containing `image-dired-tags-db-file'.
-Return the last form in BODY."
+Return the value of last form in BODY."
(declare (indent 0) (debug t))
`(with-temp-buffer
(if (file-exists-p image-dired-tags-db-file)
@@ -91,7 +91,8 @@ FILE-TAGS is an alist in the following form:
(save-buffer))))
(defun image-dired-remove-tag (files tag)
- "For all FILES, remove TAG from the image database."
+ "For each file in FILES, remove TAG from the image database.
+FILES can be a name of a single file (a string) or a list of file names."
(image-dired-sane-db-file)
(image-dired--with-db-file
(setq buffer-file-name image-dired-tags-db-file)
@@ -119,7 +120,8 @@ FILE-TAGS is an alist in the following form:
(save-buffer)))
(defun image-dired-list-tags (file)
- "Read all tags for image FILE from the image database."
+ "Read all tags for image FILE from the image database.
+Value is a list of all tags for FILE."
(image-dired-sane-db-file)
(image-dired--with-db-file
(let (end (tags ""))
@@ -136,7 +138,8 @@ FILE-TAGS is an alist in the following form:
;;;###autoload
(defun image-dired-tag-files (arg)
- "Tag marked file(s) in Dired. With prefix ARG, tag file at point."
+ "Tag file(s) which are marked in a Dired buffer.
+With prefix ARG, tag the file at point."
(interactive "P" dired-mode)
(let ((tag (completing-read
"Tags to add (separate tags with a semicolon): "
@@ -187,8 +190,7 @@ With prefix argument ARG, remove tag from file at point."
'tags (image-dired-list-tags (image-dired-original-file-name))))))
(defun image-dired-write-comments (file-comments)
- "Write file comments to database.
-Write file comments to one or more files.
+ "Write file comments specified by FILE-COMMENTS comments to database.
FILE-COMMENTS is an alist on the following form:
((FILE . COMMENT) ... )"
(image-dired-sane-db-file)
@@ -224,7 +226,7 @@ FILE-COMMENTS is an alist on the following form:
(save-buffer))))
(defun image-dired-update-property (prop value)
- "Update text property PROP with value VALUE at point."
+ "Set text property PROP of text at point to have the given VALUE."
(let ((inhibit-read-only t))
(put-text-property
(point) (1+ (point))
diff --git a/lisp/image/image-dired-util.el b/lisp/image/image-dired-util.el
index ebde531f723..a80b3afc0f3 100644
--- a/lisp/image/image-dired-util.el
+++ b/lisp/image/image-dired-util.el
@@ -110,11 +110,11 @@ See also `image-dired-thumbnail-storage'."
(abbreviate-file-name f)))
(defun image-dired-associated-dired-buffer ()
- "Get associated Dired buffer at point."
+ "Get associated Dired buffer for thumbnail at point."
(get-text-property (point) 'associated-dired-buffer))
(defmacro image-dired--with-dired-buffer (&rest body)
- "Run BODY in associated Dired buffer.
+ "Run BODY in the Dired buffer associated with thumbnail at point.
Should be used by commands in `image-dired-thumbnail-mode'."
(declare (indent defun) (debug t))
(let ((file (make-symbol "file"))
diff --git a/lisp/image/image-dired.el b/lisp/image/image-dired.el
index 0c6fd74392c..49b8d9f03c8 100644
--- a/lisp/image/image-dired.el
+++ b/lisp/image/image-dired.el
@@ -171,7 +171,7 @@ thumbnails:
sharing of thumbnails across different programs. Thumbnails
will be stored in \"$XDG_CACHE_HOME/thumbnails/\"
- Set this user option to one of the following values:
+ To use this way, set this user option to one of the following values:
- `standard' means use thumbnails sized 128x128.
- `standard-large' means use thumbnails sized 256x256.
@@ -181,20 +181,20 @@ thumbnails:
2. In the Image-Dired specific directory indicated by
`image-dired-dir'.
- Set this user option to `image-dired' to use it (or
- `use-image-dired-dir', which means the same thing for
- backwards-compatibility reasons).
+ To use this way, set this user option to `image-dired' (or
+ to `use-image-dired-dir', which means the same thing for
+ backward-compatibility reasons).
3. In a subdirectory \".image-dired\" in the same directory
where the image files are.
- Set this user option to `per-directory' to use it.
+ To use this way, set this user option to `per-directory'.
-To change the default size of thumbnails with (2) and (3) above,
-customize `image-dired-thumb-size'.
+To control the default size of thumbnails for alternatives (2)
+and (3) above, customize the value of `image-dired-thumb-size'.
With Thumbnail Managing Standard, save thumbnails in the PNG
-format, as mandated by that standard, and otherwise as JPEG.
+format, as mandated by that standard; otherwise save them as JPEG.
For more information on the Thumbnail Managing Standard, see:
https://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html"
@@ -216,13 +216,13 @@ https://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html
'image-dired-tags-db-file "29.1")
(defcustom image-dired-tags-db-file
(expand-file-name ".image-dired_db" image-dired-dir)
- "Database file where file names and their associated tags are stored."
+ "Database file where image-dired file names and associated tags are stored."
:type 'file)
(defcustom image-dired-rotate-original-ask-before-overwrite t
- "Confirm overwrite of original file after rotate operation.
+ "Confirm overwriting of original file after image-rotate operation.
If non-nil, ask user for confirmation before overwriting the
-original file with `image-dired-temp-rotate-image-file'."
+original image file by `image-dired-temp-rotate-image-file'."
:type 'boolean)
(defcustom image-dired-thumb-size
@@ -261,11 +261,12 @@ deletion."
(defcustom image-dired-line-up-method 'dynamic
"Default method for line-up of thumbnails in thumbnail buffer.
-Used by `image-dired-display-thumbs' and other functions that needs
-to line-up thumbnails. Dynamic means to use the available width of
-the window containing the thumbnail buffer, Fixed means to use
-`image-dired-thumbs-per-row', Interactive is for asking the user,
-and No line-up means that no automatic line-up will be done."
+Used by `image-dired-display-thumbs' and other functions that need
+to line-up thumbnails. The value `dynamic' means to use the
+available width of the window containing the thumbnail buffer,
+the value `fixed' means to use `image-dired-thumbs-per-row',
+the value `interactive' means ask the user, and the
+value `none' means that no automatic line-up will be done."
:type '(choice :tag "Default line-up method"
(const :tag "Dynamic" dynamic)
(const :tag "Fixed" fixed)
@@ -277,8 +278,8 @@ and No line-up means that no automatic line-up will be done."
:type 'natnum)
(defcustom image-dired-track-movement t
- "The current state of the tracking and mirroring.
-For more information, see the documentation for
+ "The current state of the Image-Dired tracking and mirroring of thumbnails.
+For more information, see the documentation of
`image-dired-toggle-movement-tracking'."
:type 'boolean)
@@ -286,14 +287,14 @@ For more information, see the documentation for
"Display format for thumbnail properties.
This is used for the header line in the Image-Dired buffer.
-The following %-specs are replaced by `format-spec' before
+The following %-specs in the value are replaced by `format-spec' before
displaying:
\"%f\" The file name (without a directory) of the
original image file.
\"%n\" The number of this image out of the total (e.g. 1/10).
\"%b\" The associated Dired buffer name.
- \"%d\" The name of the directory that the file is in.
+ \"%d\" The name of the file's directory.
\"%s\" The image file size.
\"%t\" The list of tags (from the Image-Dired database).
\"%c\" The comment (from the Image-Dired database)."
@@ -310,9 +311,9 @@ displaying:
((executable-find "xli") "xli")
((executable-find "qiv") "qiv -t")
((executable-find "xloadimage") "xloadimage"))
- "Name of external viewer.
-Including parameters. Used when displaying original image from
-`image-dired-thumbnail-mode'."
+ "Shell command to invoke the external image viewer program.
+Should include command-line arguments if needed. Used when displaying
+original image from `image-dired-thumbnail-mode'."
:version "29.1"
:type '(choice string
(const :tag "Not Set" nil)))
@@ -325,14 +326,14 @@ Used by `image-dired-copy-with-exif-file-name'."
:version "29.1")
(defcustom image-dired-show-all-from-dir-max-files 1000
- "Maximum number of files in directory before prompting.
+ "Maximum number of files in directory to show before prompting.
-If there are more image files than this in a selected directory,
+If there are more image files in a selected directory than this number,
the `image-dired-show-all-from-dir' command will ask for
confirmation before creating the thumbnail buffer. If this
-variable is nil, it will never ask."
+variable is nil, never ask."
:type '(choice integer
- (const :tag "Disable warning" nil))
+ (const :tag "Don't ask for confirmation" nil))
:version "29.1")
(defcustom image-dired-marking-shows-next t
@@ -401,7 +402,7 @@ This affects the following commands:
(image-file-name-regexp)))
(defun image-dired-insert-image (file type relief margin)
- "Insert image FILE of image TYPE, using RELIEF and MARGIN, at point."
+ "Insert at point image FILE of image TYPE, using RELIEF and MARGIN."
(let ((i `(image :type ,type
:file ,file
:relief ,relief
@@ -495,9 +496,9 @@ by exactly one space or one newline character."
Convenience command that:
- - Opens Dired in folder DIR
- - Splits windows in most useful (?) way
- - Sets `truncate-lines' to t
+ - opens Dired in folder DIR;
+ - splits windows in most useful (?) way; and
+ - sets `truncate-lines' to t
After the command has finished, you would typically mark some
image files in Dired and type
@@ -525,7 +526,7 @@ calling `image-dired-restore-window-configuration'."
(other-window -2)))))
(defun image-dired-restore-window-configuration ()
- "Restore window configuration.
+ "Restore window configuration altered by Image-Dired.
Restore any changes to the window configuration made by calling
`image-dired-dired-with-window-configuration'."
(interactive nil image-dired-thumbnail-mode)
@@ -632,7 +633,7 @@ never ask for confirmation."
;;; Movement tracking
(defun image-dired-track-original-file ()
- "Track the original file in the associated Dired buffer.
+ "Track in the associated Dired buffer the file that corresponds to thumbnail.
See `image-dired-toggle-movement-tracking'. Interactive use is
only useful if `image-dired-track-movement' is nil."
(interactive nil image-dired-thumbnail-mode image-dired-image-mode)
@@ -646,8 +647,8 @@ only useful if `image-dired-track-movement' is nil."
(defun image-dired-toggle-movement-tracking ()
"Turn on and off `image-dired-track-movement'.
Tracking of the movements between thumbnail and Dired buffer so that
-they are \"mirrored\" in the dired buffer. When this is on, moving
-around in the thumbnail or dired buffer will find the matching
+the movements are \"mirrored\" in the Dired buffer. When this is on,
+moving around in the thumbnail or Dired buffer will move to the matching
position in the other buffer."
(interactive nil image-dired-thumbnail-mode image-dired-image-mode)
(setq image-dired-track-movement (not image-dired-track-movement))
@@ -751,7 +752,9 @@ On reaching end or beginning of buffer, stop and show a message."
;;; Header line
(defun image-dired-format-properties-string (buf file image-count props comment)
- "Format display properties.
+ "Format display properties for Image-Dired.
+The properties are formatted according to specification
+in `image-dired-display-properties-format', which see.
BUF is the associated Dired buffer, FILE is the original image
file name, IMAGE-COUNT is a string like \"N/M\" where N is the
number of this image and M is the total number of images, PROPS
@@ -816,7 +819,7 @@ for. The default is to look for `dired-marker-char'."
(image-dired-dired-file-marked-p dired-del-marker))
(defmacro image-dired--on-file-in-dired-buffer (&rest body)
- "Run BODY with point on file at point in Dired buffer.
+ "Run BODY in associated Dired buffer with point on current file's line.
Should be called from commands in `image-dired-thumbnail-mode'."
(declare (indent defun) (debug t))
`(if-let ((file-name (image-dired-original-file-name)))
@@ -1192,7 +1195,8 @@ Ask user how many thumbnails should be displayed per row."
;;; Display image from thumbnail buffer
(defun image-dired-thumbnail-display-external ()
- "Display original image for thumbnail at point using external viewer."
+ "Display original image for thumbnail at point using external viewer.
+The viewer command is specified by `image-dired-external-viewer'."
(interactive nil image-dired-thumbnail-mode)
(let ((file (image-dired-original-file-name)))
(if (not (image-dired-image-at-point-p))
@@ -1205,7 +1209,7 @@ Ask user how many thumbnails should be displayed per row."
(defun image-dired-display-image (file &optional _ignored)
"Display image FILE in the image buffer window.
-If it is an image, the window will use `image-dired-image-mode'
+If FILE is an image, the window will use `image-dired-image-mode'
which is based on `image-mode'."
(declare (advertised-calling-convention (file) "29.1"))
(setq file (expand-file-name file))
@@ -1293,7 +1297,7 @@ overwritten. This confirmation can be turned off using
(defun image-dired-copy-filename-as-kill (&optional arg)
"Copy names of marked (or next ARG) files into the kill ring.
-This works as `dired-copy-filename-as-kill' (which see)."
+This works like `dired-copy-filename-as-kill' (which see)."
(interactive "P" image-dired-thumbnail-mode)
(image-dired--with-dired-buffer
(dired-copy-filename-as-kill arg)))
diff --git a/lisp/image/wallpaper.el b/lisp/image/wallpaper.el
index c497e1f429b..a2f175e4628 100644
--- a/lisp/image/wallpaper.el
+++ b/lisp/image/wallpaper.el
@@ -109,7 +109,7 @@ COMMAND is the executable to run to set the wallpaper.
ARGS is the default list of command line arguments for COMMAND.
PREDICATE is a function that will be called without any arguments
-and returns non-nil if this setter should be used.
+and should return non-nil if this setter should be used.
INIT-ACTION is a function that will be called without any
arguments before trying to set the wallpaper.
@@ -304,7 +304,7 @@ order in which they appear.")
(throw 'found setter))))))))
(defun wallpaper--find-command ()
- "Return a valid command to set the wallpaper in this environment."
+ "Return the appropriate command to set the wallpaper."
(when-let ((setter (wallpaper--find-setter)))
(wallpaper-setter-command setter)))
@@ -437,7 +437,7 @@ See also `wallpaper-default-width'.")
On a graphical display, try using the same monitor as the current
frame.
On a non-graphical display, try to get the name by connecting to
-the display server directly, and run \"xrandr\" if that doesn't
+the display server directly, or run \"xrandr\" if that doesn't
work. Prompt for the monitor name if neither method works.
This function is meaningful only on X and is used only there."
@@ -469,7 +469,7 @@ This function is meaningful only on X and is used only there."
(read-string (format-prompt "Monitor name" nil)))))
(defun wallpaper--format-arg (format file)
- "Format a `wallpaper-command-args' argument ARG.
+ "Format a `wallpaper-command-args' argument ARG using FORMAT.
FILE is the image file name."
(format-spec
format
From 838415525bd4e77a79e18af8e4f01ed004196c71 Mon Sep 17 00:00:00 2001
From: Michael Albinus
Date: Sat, 11 Feb 2023 18:11:56 +0100
Subject: [PATCH 19/24] Support Tramp user name completion
* lisp/net/tramp.el (tramp-build-completion-file-name-regexp)
(tramp-completion-handle-expand-file-name)
(tramp-completion-handle-file-name-directory): Support user name
completion.
* test/lisp/net/tramp-tests.el
(tramp-test26-interactive-file-name-completion): Fix test.
---
lisp/net/tramp.el | 24 +++++--
test/lisp/net/tramp-tests.el | 126 ++++++++++++++++++-----------------
2 files changed, 83 insertions(+), 67 deletions(-)
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 36305dda496..1cda8fc4c61 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -1211,9 +1211,12 @@ The `ftp' syntax does not support methods.")
(? (regexp tramp-completion-method-regexp)
;; Method separator, user name and host name.
(? (regexp tramp-postfix-method-regexp)
- ;; This is a little bit lax, but it serves.
- (? (regexp tramp-host-regexp))))
-
+ (? (regexp tramp-user-regexp)
+ (regexp tramp-postfix-user-regexp))
+ (? (| (regexp tramp-host-regexp) ;; This includes a user.
+ (: (regexp tramp-prefix-ipv6-regexp)
+ (? (regexp tramp-ipv6-regexp)
+ (? (regexp tramp-postfix-ipv6-regexp))))))))
eos)))
(defvar tramp-completion-file-name-regexp
@@ -2958,7 +2961,8 @@ not in completion mode."
(concat dir filename))
((string-match-p
(rx bos (regexp tramp-prefix-regexp)
- (? (regexp tramp-method-regexp) (regexp tramp-postfix-method-regexp))
+ (? (regexp tramp-method-regexp) (regexp tramp-postfix-method-regexp)
+ (? (regexp tramp-user-regexp) (regexp tramp-postfix-user-regexp)))
eos)
dir)
(concat dir filename))
@@ -3250,11 +3254,21 @@ PARTIAL-USER must match USER, PARTIAL-HOST must match HOST."
(rx (group
(regexp tramp-prefix-regexp)
(group (regexp tramp-method-regexp))
- (regexp tramp-postfix-method-regexp)))
+ (regexp tramp-postfix-method-regexp)
+ (? (regexp tramp-user-regexp)
+ (regexp tramp-postfix-user-regexp))))
filename)
;; Is it a valid method?
(assoc (match-string 2 filename) tramp-methods))
(match-string 1 filename))
+ ((and (string-empty-p tramp-method-regexp)
+ (string-match
+ (rx (group
+ (regexp tramp-prefix-regexp)
+ (? (regexp tramp-user-regexp)
+ (regexp tramp-postfix-user-regexp))))
+ filename))
+ (match-string 1 filename))
((string-match
(rx (group (regexp tramp-prefix-regexp))
(regexp tramp-completion-method-regexp) eos)
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index 85714e79bc0..33afe820c58 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -4643,13 +4643,15 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
"Check interactive completion with different `completion-styles'."
(tramp-cleanup-connection tramp-test-vec nil 'keep-password)
-;; Method and host name in completion mode. This kind of completion
+ ;; Method and host name in completion mode. This kind of completion
;; does not work on MS Windows.
(unless (memq system-type '(cygwin windows-nt))
(let ((method (file-remote-p ert-remote-temporary-file-directory 'method))
+ (user (file-remote-p ert-remote-temporary-file-directory 'user))
(host (file-remote-p ert-remote-temporary-file-directory 'host))
(orig-syntax tramp-syntax)
- (non-essential t))
+ (non-essential t)
+ (inhibit-message t))
(when (and (stringp host) (string-match tramp-host-with-port-regexp host))
(setq host (match-string 1 host)))
@@ -4689,68 +4691,70 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
tramp-postfix-ipv6-format))
test result completions)
- ;; Complete method name.
- (unless (string-empty-p tramp-method-regexp)
- (ignore-errors (kill-buffer "*Completions*"))
- (discard-input)
- (setq test (concat
- tramp-prefix-format
- (substring-no-properties method 0 2))
- unread-command-events
- (mapcar #'identity (concat test "\t\t\n"))
- completions nil
- result (read-file-name "Prompt: "))
- (if (not (get-buffer "*Completions*"))
- (progn
- (tramp--test-message
- "syntax: %s style: %s test: %s result: %s"
- syntax style test result)
- (should
- (string-prefix-p
- (concat tramp-prefix-format method-string)
- result)))
- (with-current-buffer "*Completions*"
- ;; We must remove leading `default-directory'.
- (goto-char (point-min))
- (let ((inhibit-read-only t))
- (while (re-search-forward "//" nil 'noerror)
- (delete-region (line-beginning-position) (point))))
- (goto-char (point-min))
- (re-search-forward
- (rx bol (1+ nonl) "possible completions:" eol))
- (forward-line 1)
- (setq completions
- (split-string
- (buffer-substring-no-properties (point) (point-max))
- (rx (any "\r\n")) 'omit)))
- (tramp--test-message
- "syntax: %s style: %s test: %s result: %s completions: %S"
- syntax style test result completions)
- (should (member method-string completions))))
+ (dolist
+ (test-and-result
+ ;; These are triples (TEST-STRING SINGLE-RESULT
+ ;; COMPLETION-RESULT).
+ (append
+ ;; Complete method name.
+ (unless (string-empty-p tramp-method-regexp)
+ `((,(concat
+ tramp-prefix-format
+ (substring-no-properties method 0 2))
+ ,(concat tramp-prefix-format method-string)
+ ,method-string)))
+ ;; Complete user name.
+ (unless (tramp-string-empty-or-nil-p user)
+ `((,(concat
+ tramp-prefix-format method-string
+ (substring-no-properties user 0 2))
+ ,(concat
+ tramp-prefix-format method-string
+ user tramp-postfix-user-format)
+ ,(concat
+ user tramp-postfix-user-format))))
+ ;; Complete host name.
+ (unless (tramp-string-empty-or-nil-p host)
+ `((,(concat
+ tramp-prefix-format method-string
+ ipv6-prefix (substring-no-properties host 0 2))
+ ,(concat
+ tramp-prefix-format method-string
+ ipv6-prefix host
+ ipv6-postfix tramp-postfix-host-format)
+ ,(concat
+ ipv6-prefix host
+ ipv6-postfix tramp-postfix-host-format))))
+ ;; Complete user and host name.
+ (unless (or (tramp-string-empty-or-nil-p user)
+ (tramp-string-empty-or-nil-p host))
+ `((,(concat
+ tramp-prefix-format method-string
+ user tramp-postfix-user-format
+ ipv6-prefix (substring-no-properties host 0 2))
+ ,(concat
+ tramp-prefix-format method-string
+ user tramp-postfix-user-format
+ ipv6-prefix host
+ ipv6-postfix tramp-postfix-host-format)
+ ,(concat
+ ipv6-prefix host
+ ipv6-postfix tramp-postfix-host-format))))))
- ;; Complete host name.
- (unless (or (tramp-string-empty-or-nil-p host)
- (tramp--test-gvfs-p method))
(ignore-errors (kill-buffer "*Completions*"))
(discard-input)
- (setq test (concat
- tramp-prefix-format method-string
- (substring-no-properties host 0 2))
+ (setq test (car test-and-result)
unread-command-events
(mapcar #'identity (concat test "\t\t\n"))
completions nil
result (read-file-name "Prompt: "))
(if (not (get-buffer "*Completions*"))
(progn
- (tramp--test-message
- "syntax: %s style: %s test: %s result: %s"
- syntax style test result)
- (should
- (string-equal
- (concat
- tramp-prefix-format method-string
- ipv6-prefix host ipv6-postfix tramp-postfix-host-format)
- result)))
+ ;; (tramp--test-message
+ ;; "syntax: %s style: %s test: %s result: %s"
+ ;; syntax style test result)
+ (should (string-prefix-p (cadr test-and-result) result)))
+
(with-current-buffer "*Completions*"
;; We must remove leading `default-directory'.
(goto-char (point-min))
@@ -4765,13 +4769,11 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(split-string
(buffer-substring-no-properties (point) (point-max))
(rx (any "\r\n")) 'omit)))
- (tramp--test-message
- "syntax: %s style: %s test: %s result: %s completions: %S"
- syntax style test result completions)
- (should
- (member
- (concat host tramp-postfix-host-format)
- completions)))))))
+
+ ;; (tramp--test-message
+ ;; "syntax: %s style: %s test: %s result: %s completions: %S"
+ ;; syntax style test result completions)
+ (should (member (caddr test-and-result) completions)))))))
;; Cleanup.
(tramp-change-syntax orig-syntax)))))
From 14c97db7366435b1edbf2854f485058a9d7c6071 Mon Sep 17 00:00:00 2001
From: Jim Porter
Date: Sat, 11 Feb 2023 12:37:32 -0800
Subject: [PATCH 20/24] Make sure core Eshell modules are loaded
Previously, if you removed all (or most) extension modules from
Eshell, it failed to load esh-var.el, meaning that you couldn't use
variable expansions. To avoid this issue, we now explicitly load the
core modules in esh-mode.el.
* lisp/eshell/esh-mode.el: Explicitly require core Eshell modules.
---
lisp/eshell/esh-mode.el | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el
index 654e26777e0..46c3c2fa175 100644
--- a/lisp/eshell/esh-mode.el
+++ b/lisp/eshell/esh-mode.el
@@ -58,10 +58,16 @@
;;; Code:
-(require 'esh-util)
-(require 'esh-module)
+;; Load the core Eshell modules; we'll call their initialization
+;; functions below in `eshell-mode'.
+(require 'esh-arg)
(require 'esh-cmd)
-(require 'esh-arg) ;For eshell-parse-arguments
+(require 'esh-ext)
+(require 'esh-io)
+(require 'esh-module)
+(require 'esh-proc)
+(require 'esh-util)
+(require 'esh-var)
(defgroup eshell-mode nil
"This module contains code for handling input from the user."
From 4da398d8b57aae740f054b4d04cba72735a4044c Mon Sep 17 00:00:00 2001
From: Stefan Kangas
Date: Sun, 12 Feb 2023 03:23:13 +0100
Subject: [PATCH 21/24] ; Fix typos
---
ChangeLog.2 | 2 +-
ChangeLog.3 | 2 +-
lisp/image/image-dired-dired.el | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/ChangeLog.2 b/ChangeLog.2
index cde9e63df88..11e6049b0bd 100644
--- a/ChangeLog.2
+++ b/ChangeLog.2
@@ -111,7 +111,7 @@
2017-03-21 Noam Postavsky
- Narrow scope of modification hook renabling in org-src fontification
+ Narrow scope of modification hook re-enabling in org-src fontification
Modification hooks should be enabled while modifying text in the
org-src temp buffer, but in 2017-01-29 "Call modification hooks in
diff --git a/ChangeLog.3 b/ChangeLog.3
index 3d733804e39..c254f595e89 100644
--- a/ChangeLog.3
+++ b/ChangeLog.3
@@ -204741,7 +204741,7 @@
2017-03-21 Noam Postavsky
- Narrow scope of modification hook renabling in org-src fontification
+ Narrow scope of modification hook re-enabling in org-src fontification
Modification hooks should be enabled while modifying text in the
org-src temp buffer, but in 2017-01-29 "Call modification hooks in
diff --git a/lisp/image/image-dired-dired.el b/lisp/image/image-dired-dired.el
index 15230c9e42a..6b932601df0 100644
--- a/lisp/image/image-dired-dired.el
+++ b/lisp/image/image-dired-dired.el
@@ -355,7 +355,7 @@ command. The result is one or more new files in
"Mark files whose tag matches REGEXP.
A `tag' is a keyword, a piece of meta data, associated with an
image file and stored in image-dired's database file. This command
-promts for a regexp, and then matches it against all the tags
+prompts for a regexp, and then matches it against all the tags
of all the image files in the database file. The files that have a
matching tag will be marked in the Dired buffer."
(interactive "sMark tagged files (regexp): " dired-mode)
From 8f3091defb3ec4396ccea563f67c005044b822ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Mart=C3=ADn?=
Date: Sun, 12 Feb 2023 01:32:20 +0100
Subject: [PATCH 22/24] ; Fix typo in buffer.h
---
src/buffer.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/buffer.h b/src/buffer.h
index 23340b4c0ee..c0e38ce9659 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -690,7 +690,7 @@ struct buffer
display optimizations must be used. */
bool_bf long_line_optimizations_p : 1;
- /* The inveral tree containing this buffer's overlays. */
+ /* The interval tree containing this buffer's overlays. */
struct itree_tree *overlays;
/* Changes in the buffer are recorded here for undo, and t means
From ae4ff4f25fbf704446f8f38d8e818f223b79042b Mon Sep 17 00:00:00 2001
From: Po Lu
Date: Sun, 12 Feb 2023 19:55:28 +0800
Subject: [PATCH 23/24] Support input method ``text conversion'' on X Windows
* configure.ac (HAVE_TEXT_CONVERSION): Define on X.
* etc/NEWS: Announce new change.
* src/emacs.c (main): Always call init_xterm.
* src/frame.c (do_switch_frame): Use `fset_selected_window'.
* src/insdel.c (struct safe_del_range_context): New structure.
(safe_del_range_1, safe_del_range_2, safe_del_range): New
functions.
* src/lisp.h: Export new functions.
* src/window.c (run_window_change_functions): Report selected
window and buffer changes so that the input method can be reset.
* src/xfns.c (XICCallback, Xxic_preedit_caret_callback)
(Xxic_preedit_done_callback, Xxic_preedit_start_callback)
(Xxic_preedit_draw_callback): Fix coding style.
(Xxic_string_conversion_callback): New callback.
(create_frame_xic): Register string conversion callback.
(struct x_xim_text_conversion_data): New field `size'.
(x_encode_xim_text_1, x_encode_xim_text): New functions.
(xic_string_conversion_callback): New function.
* src/xterm.c (x_reset_conversion): New function.
(text_conversion_interface): New variable.
(init_xterm): Initialize text conversion interface.
---
configure.ac | 6 +
etc/NEWS | 7 ++
src/emacs.c | 3 +-
src/frame.c | 2 +-
src/insdel.c | 38 +++++++
src/lisp.h | 6 +
src/window.c | 15 +++
src/xfns.c | 303 +++++++++++++++++++++++++++++++++++++++++++++++++--
src/xterm.c | 41 ++++++-
9 files changed, 407 insertions(+), 14 deletions(-)
diff --git a/configure.ac b/configure.ac
index fc17dbd8318..7bb0df88cb3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6502,6 +6502,12 @@ if test "$window_system" != "none"; then
AC_DEFINE([POLL_FOR_INPUT], [1],
[Define if you poll periodically to detect C-g.])
WINDOW_SYSTEM_OBJ="fontset.o fringe.o image.o"
+
+ if test "$window_system" = "x11"; then
+ AC_DEFINE([HAVE_TEXT_CONVERSION], [1],
+ [Define if the window system has text conversion support.])
+ WINDOW_SYSTEM_OBJ="$WINDOW_SYSTEM_OBJ textconv.o"
+ fi
fi
AC_SUBST([WINDOW_SYSTEM_OBJ])
diff --git a/etc/NEWS b/etc/NEWS
index e0175bacfdf..d3eafaadf19 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -59,6 +59,13 @@ This allows the user to customize the prompt that is appended by
* Editing Changes in Emacs 30.1
+---
+** On X, Emacs now supports input methods which perform "string conversion".
+This means an input method can now ask Emacs to delete text
+surrounding point and replace it with something else, as well as query
+Emacs for surrounding text. If your input method allows you to "undo"
+mistaken compositions, this will now work as well.
+
---
** New command 'kill-matching-buffers-no-ask'.
This works like 'kill-matching-buffers', but without asking for
diff --git a/src/emacs.c b/src/emacs.c
index 214e2e2a296..282e2f48100 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -2447,7 +2447,8 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
#ifdef HAVE_DBUS
init_dbusbind ();
#endif
-#if defined(USE_GTK) && !defined(HAVE_PGTK)
+
+#ifdef HAVE_X_WINDOWS
init_xterm ();
#endif
diff --git a/src/frame.c b/src/frame.c
index 983424b0bee..2cea96d4a32 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -1526,7 +1526,7 @@ do_switch_frame (Lisp_Object frame, int for_deletion, Lisp_Object norecord)
if (f->select_mini_window_flag
&& !NILP (Fminibufferp (XWINDOW (f->minibuffer_window)->contents, Qt)))
- f->selected_window = f->minibuffer_window;
+ fset_selected_window (f, f->minibuffer_window);
f->select_mini_window_flag = false;
if (! FRAME_MINIBUF_ONLY_P (XFRAME (selected_frame)))
diff --git a/src/insdel.c b/src/insdel.c
index e459d0cfa17..b65a3fbd805 100644
--- a/src/insdel.c
+++ b/src/insdel.c
@@ -1715,6 +1715,44 @@ del_range (ptrdiff_t from, ptrdiff_t to)
del_range_1 (from, to, 1, 0);
}
+struct safe_del_range_context
+{
+ /* From and to positions. */
+ ptrdiff_t from, to;
+};
+
+static Lisp_Object
+safe_del_range_1 (void *ptr)
+{
+ struct safe_del_range_context *context;
+
+ context = ptr;
+ del_range (context->from, context->to);
+ return Qnil;
+}
+
+static Lisp_Object
+safe_del_range_2 (enum nonlocal_exit type, Lisp_Object value)
+{
+ return Qt;
+}
+
+/* Like del_range; however, catch all non-local exits. Value is 0 if
+ the buffer contents were really deleted. Otherwise, it is 1. */
+
+int
+safe_del_range (ptrdiff_t from, ptrdiff_t to)
+{
+ struct safe_del_range_context context;
+
+ context.from = from;
+ context.to = to;
+
+ return !NILP (internal_catch_all (safe_del_range_1,
+ &context,
+ safe_del_range_2));
+}
+
/* Like del_range; PREPARE says whether to call prepare_to_modify_buffer.
RET_STRING says to return the deleted text. */
diff --git a/src/lisp.h b/src/lisp.h
index 0bc400ba78f..cacd318c26f 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4116,6 +4116,7 @@ extern void del_range_byte (ptrdiff_t, ptrdiff_t);
extern void del_range_both (ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, bool);
extern Lisp_Object del_range_2 (ptrdiff_t, ptrdiff_t,
ptrdiff_t, ptrdiff_t, bool);
+extern int safe_del_range (ptrdiff_t, ptrdiff_t);
extern void modify_text (ptrdiff_t, ptrdiff_t);
extern void prepare_to_modify_buffer (ptrdiff_t, ptrdiff_t, ptrdiff_t *);
extern void prepare_to_modify_buffer_1 (ptrdiff_t, ptrdiff_t, ptrdiff_t *);
@@ -5212,6 +5213,11 @@ extern void syms_of_profiler (void);
extern char *emacs_root_dir (void);
#endif /* DOS_NT */
+#ifdef HAVE_TEXT_CONVERSION
+/* Defined in textconv.c. */
+extern void report_selected_window_change (struct frame *);
+#endif
+
#ifdef HAVE_NATIVE_COMP
INLINE bool
SUBR_NATIVE_COMPILEDP (Lisp_Object a)
diff --git a/src/window.c b/src/window.c
index 6201a6f4a36..9334f922f89 100644
--- a/src/window.c
+++ b/src/window.c
@@ -3856,6 +3856,9 @@ run_window_change_functions_1 (Lisp_Object symbol, Lisp_Object buffer,
*
* This function does not save and restore match data. Any functions
* it calls are responsible for doing that themselves.
+ *
+ * Additionally, report changes to each frame's selected window to the
+ * input method in textconv.c.
*/
void
run_window_change_functions (void)
@@ -4015,6 +4018,18 @@ run_window_change_functions (void)
run_window_change_functions_1
(Qwindow_selection_change_functions, Qnil, frame);
+#if defined HAVE_TEXT_CONVERSION
+
+ /* If the buffer or selected window has changed, also reset the
+ input method composition state. */
+
+ if ((frame_selected_window_change || frame_buffer_change)
+ && FRAME_LIVE_P (f)
+ && FRAME_WINDOW_P (f))
+ report_selected_window_change (f);
+
+#endif
+
/* A frame has changed state when a size or buffer change
occurred, its selected window has changed, when it was
(de-)selected or its window state change flag was set. */
diff --git a/src/xfns.c b/src/xfns.c
index 3a129211463..9e004f6a678 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -37,6 +37,10 @@ along with GNU Emacs. If not, see . */
#include "termhooks.h"
#include "font.h"
+#ifdef HAVE_X_I18N
+#include "textconv.h"
+#endif
+
#include
#include
@@ -2671,24 +2675,50 @@ append_wm_protocols (struct x_display_info *dpyinfo,
#ifdef HAVE_X_I18N
-static void xic_preedit_draw_callback (XIC, XPointer, XIMPreeditDrawCallbackStruct *);
-static void xic_preedit_caret_callback (XIC, XPointer, XIMPreeditCaretCallbackStruct *);
+static void xic_preedit_draw_callback (XIC, XPointer,
+ XIMPreeditDrawCallbackStruct *);
+static void xic_preedit_caret_callback (XIC, XPointer,
+ XIMPreeditCaretCallbackStruct *);
static void xic_preedit_done_callback (XIC, XPointer, XPointer);
static int xic_preedit_start_callback (XIC, XPointer, XPointer);
+static void xic_string_conversion_callback (XIC, XPointer,
+ XIMStringConversionCallbackStruct *);
#ifndef HAVE_XICCALLBACK_CALLBACK
#define XICCallback XIMCallback
#define XICProc XIMProc
#endif
-static XIMCallback Xxic_preedit_draw_callback = { NULL,
- (XIMProc) xic_preedit_draw_callback };
-static XIMCallback Xxic_preedit_caret_callback = { NULL,
- (XIMProc) xic_preedit_caret_callback };
-static XIMCallback Xxic_preedit_done_callback = { NULL,
- (XIMProc) xic_preedit_done_callback };
-static XICCallback Xxic_preedit_start_callback = { NULL,
- (XICProc) xic_preedit_start_callback };
+static XIMCallback Xxic_preedit_draw_callback =
+ {
+ NULL,
+ (XIMProc) xic_preedit_draw_callback,
+ };
+
+static XIMCallback Xxic_preedit_caret_callback =
+ {
+ NULL,
+ (XIMProc) xic_preedit_caret_callback,
+ };
+
+static XIMCallback Xxic_preedit_done_callback =
+ {
+ NULL,
+ (XIMProc) xic_preedit_done_callback,
+ };
+
+static XICCallback Xxic_preedit_start_callback =
+ {
+ NULL,
+ (XICProc) xic_preedit_start_callback,
+ };
+
+static XIMCallback Xxic_string_conversion_callback =
+ {
+ /* This is actually an XICCallback! */
+ NULL,
+ (XIMProc) xic_string_conversion_callback,
+ };
#if defined HAVE_X_WINDOWS && defined USE_X_TOOLKIT
/* Create an X fontset on frame F with base font name BASE_FONTNAME. */
@@ -3094,6 +3124,8 @@ create_frame_xic (struct frame *f)
XNFocusWindow, FRAME_X_WINDOW (f),
XNStatusAttributes, status_attr,
XNPreeditAttributes, preedit_attr,
+ XNStringConversionCallback,
+ &Xxic_string_conversion_callback,
NULL);
else if (preedit_attr)
xic = XCreateIC (xim,
@@ -3101,6 +3133,8 @@ create_frame_xic (struct frame *f)
XNClientWindow, FRAME_X_WINDOW (f),
XNFocusWindow, FRAME_X_WINDOW (f),
XNPreeditAttributes, preedit_attr,
+ XNStringConversionCallback,
+ &Xxic_string_conversion_callback,
NULL);
else if (status_attr)
xic = XCreateIC (xim,
@@ -3108,12 +3142,16 @@ create_frame_xic (struct frame *f)
XNClientWindow, FRAME_X_WINDOW (f),
XNFocusWindow, FRAME_X_WINDOW (f),
XNStatusAttributes, status_attr,
+ XNStringConversionCallback,
+ &Xxic_string_conversion_callback,
NULL);
else
xic = XCreateIC (xim,
XNInputStyle, xic_style,
XNClientWindow, FRAME_X_WINDOW (f),
XNFocusWindow, FRAME_X_WINDOW (f),
+ XNStringConversionCallback,
+ &Xxic_string_conversion_callback,
NULL);
if (!xic)
@@ -3377,6 +3415,7 @@ struct x_xim_text_conversion_data
struct coding_system *coding;
char *source;
struct x_display_info *dpyinfo;
+ size_t size;
};
static Lisp_Object
@@ -3411,6 +3450,38 @@ x_xim_text_to_utf8_unix_1 (ptrdiff_t nargs, Lisp_Object *args)
return Qnil;
}
+static Lisp_Object
+x_encode_xim_text_1 (ptrdiff_t nargs, Lisp_Object *args)
+{
+ struct x_xim_text_conversion_data *data;
+ ptrdiff_t nbytes;
+ Lisp_Object coding_system;
+
+ data = xmint_pointer (args[0]);
+
+ if (SYMBOLP (Vx_input_coding_system))
+ coding_system = Vx_input_coding_system;
+ else if (!NILP (data->dpyinfo->xim_coding))
+ coding_system = data->dpyinfo->xim_coding;
+ else
+ coding_system = Vlocale_coding_system;
+
+ nbytes = data->size;
+
+ data->coding->destination = NULL;
+
+ setup_coding_system (coding_system, data->coding);
+ data->coding->mode |= (CODING_MODE_LAST_BLOCK
+ | CODING_MODE_SAFE_ENCODING);
+ data->coding->source = (const unsigned char *) data->source;
+ data->coding->dst_bytes = 2048;
+ data->coding->destination = xmalloc (2048);
+ encode_coding_object (data->coding, Qnil, 0, 0,
+ nbytes, nbytes, Qnil);
+
+ return Qnil;
+}
+
static Lisp_Object
x_xim_text_to_utf8_unix_2 (Lisp_Object val, ptrdiff_t nargs,
Lisp_Object *args)
@@ -3468,6 +3539,46 @@ x_xim_text_to_utf8_unix (struct x_display_info *dpyinfo,
return (char *) coding.destination;
}
+/* Convert SIZE bytes of the specified text from Emacs's internal
+ coding system to the input method coding system. Return the
+ result, its byte length in *LENGTH, and its character length in
+ *CHARS, or NULL.
+
+ The string returned is not NULL terminated. */
+
+static char *
+x_encode_xim_text (struct x_display_info *dpyinfo, char *text,
+ size_t size, ptrdiff_t *length,
+ ptrdiff_t *chars)
+{
+ struct coding_system coding;
+ struct x_xim_text_conversion_data data;
+ Lisp_Object arg;
+ bool was_waiting_for_input_p;
+
+ data.coding = &coding;
+ data.source = text;
+ data.dpyinfo = dpyinfo;
+ data.size = size;
+
+ was_waiting_for_input_p = waiting_for_input;
+ /* Otherwise Fsignal will crash. */
+ waiting_for_input = false;
+
+ arg = make_mint_ptr (&data);
+ internal_condition_case_n (x_encode_xim_text_1, 1, &arg,
+ Qt, x_xim_text_to_utf8_unix_2);
+ waiting_for_input = was_waiting_for_input_p;
+
+ if (length)
+ *length = coding.produced;
+
+ if (chars)
+ *chars = coding.produced_char;
+
+ return (char *) coding.destination;
+}
+
static void
xic_preedit_draw_callback (XIC xic, XPointer client_data,
XIMPreeditDrawCallbackStruct *call_data)
@@ -3664,6 +3775,128 @@ xic_set_xfontset (struct frame *f, const char *base_fontname)
FRAME_XIC_FONTSET (f) = xfs;
}
+
+
+/* String conversion support. See textconv.c for more details. */
+
+static void
+xic_string_conversion_callback (XIC ic, XPointer client_data,
+ XIMStringConversionCallbackStruct *call_data)
+{
+ struct textconv_callback_struct request;
+ ptrdiff_t length;
+ struct frame *f;
+ int rc;
+
+ /* Find the frame associated with this IC. */
+ f = x_xic_to_frame (ic);
+
+ if (!f)
+ goto failure;
+
+ /* Fill in CALL_DATA as early as possible. */
+ call_data->text->feedback = NULL;
+ call_data->text->encoding_is_wchar = False;
+
+ /* Now translate the conversion request to the format understood by
+ textconv.c. */
+ request.position = call_data->position;
+
+ switch (call_data->direction)
+ {
+ case XIMForwardChar:
+ request.direction = TEXTCONV_FORWARD_CHAR;
+ break;
+
+ case XIMBackwardChar:
+ request.direction = TEXTCONV_BACKWARD_CHAR;
+ break;
+
+ case XIMForwardWord:
+ request.direction = TEXTCONV_FORWARD_WORD;
+ break;
+
+ case XIMBackwardWord:
+ request.direction = TEXTCONV_BACKWARD_WORD;
+ break;
+
+ case XIMCaretUp:
+ request.direction = TEXTCONV_CARET_UP;
+ break;
+
+ case XIMCaretDown:
+ request.direction = TEXTCONV_CARET_DOWN;
+ break;
+
+ case XIMNextLine:
+ request.direction = TEXTCONV_NEXT_LINE;
+ break;
+
+ case XIMPreviousLine:
+ request.direction = TEXTCONV_PREVIOUS_LINE;
+ break;
+
+ case XIMLineStart:
+ request.direction = TEXTCONV_LINE_START;
+ break;
+
+ case XIMLineEnd:
+ request.direction = TEXTCONV_LINE_END;
+ break;
+
+ case XIMAbsolutePosition:
+ request.direction = TEXTCONV_ABSOLUTE_POSITION;
+ break;
+
+ default:
+ goto failure;
+ }
+
+ /* factor is signed in call_data but is actually a CARD16. */
+ request.factor = call_data->factor;
+
+ if (call_data->operation == XIMStringConversionSubstitution)
+ request.operation = TEXTCONV_SUBSTITUTION;
+ else
+ request.operation = TEXTCONV_RETRIEVAL;
+
+ /* Now perform the string conversion. */
+ rc = textconv_query (f, &request);
+
+ if (rc)
+ {
+ xfree (request.text.text);
+ goto failure;
+ }
+
+ /* Encode the text in the locale coding system and give it back to
+ the input method. */
+ request.text.text = NULL;
+ call_data->text->string.mbs
+ = x_encode_xim_text (FRAME_DISPLAY_INFO (f),
+ request.text.text,
+ request.text.bytes, NULL,
+ &length);
+ call_data->text->length = length;
+
+ /* Free the encoded text. This is always set to something
+ valid. */
+ xfree (request.text.text);
+
+ /* Detect failure. */
+ if (!call_data->text->string.mbs)
+ goto failure;
+
+ return;
+
+ failure:
+ /* Return a string of length 0 using the C library malloc. This
+ assumes XFree is able to free data allocated with our malloc
+ wrapper. */
+ call_data->text->length = 0;
+ call_data->text->string.mbs = malloc (0);
+}
+
#endif /* HAVE_X_I18N */
@@ -9771,6 +10004,53 @@ This should be called from a variable watcher for `x-gtk-use-native-input'. */)
return Qnil;
}
+
+#if 0
+
+DEFUN ("x-test-string-conversion", Fx_test_string_conversion,
+ Sx_test_string_conversion, 5, 5, 0,
+ doc: /* Perform tests on the XIM string conversion support. */)
+ (Lisp_Object frame, Lisp_Object position,
+ Lisp_Object direction, Lisp_Object operation, Lisp_Object factor)
+{
+ struct frame *f;
+ XIMStringConversionCallbackStruct call_data;
+ XIMStringConversionText text;
+
+ f = decode_window_system_frame (frame);
+
+ if (!FRAME_XIC (f))
+ error ("No XIC on FRAME!");
+
+ CHECK_FIXNUM (position);
+ CHECK_FIXNUM (direction);
+ CHECK_FIXNUM (operation);
+ CHECK_FIXNUM (factor);
+
+ /* xic_string_conversion_callback (XIC ic, XPointer client_data,
+ XIMStringConversionCallbackStruct *call_data) */
+
+ call_data.position = XFIXNUM (position);
+ call_data.direction = XFIXNUM (direction);
+ call_data.operation = XFIXNUM (operation);
+ call_data.factor = XFIXNUM (factor);
+ call_data.text = &text;
+
+ block_input ();
+ xic_string_conversion_callback (FRAME_XIC (f), NULL,
+ &call_data);
+ unblock_input ();
+
+ /* Place a breakpoint here to inspect TEXT! */
+
+ while (1)
+ maybe_quit ();
+
+ return Qnil;
+}
+
+#endif
+
/***********************************************************************
Initialization
@@ -10217,6 +10497,9 @@ eliminated in future versions of Emacs. */);
defsubr (&Sx_display_set_last_user_time);
defsubr (&Sx_translate_coordinates);
defsubr (&Sx_get_modifier_masks);
+#if 0
+ defsubr (&Sx_test_string_conversion);
+#endif
tip_timer = Qnil;
staticpro (&tip_timer);
diff --git a/src/xterm.c b/src/xterm.c
index 1325d923be9..5feaa4aef0f 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -636,6 +636,10 @@ along with GNU Emacs. If not, see . */
#include "xterm.h"
#include
+#ifdef HAVE_X_I18N
+#include "textconv.h"
+#endif
+
#ifdef USE_XCB
#include
#include
@@ -31506,7 +31510,37 @@ x_initialize (void)
XSetIOErrorHandler (x_io_error_quitter);
}
-#ifdef USE_GTK
+#ifdef HAVE_X_I18N
+
+/* Notice that a change has occured on F that requires its input
+ method state to be reset. */
+
+static void
+x_reset_conversion (struct frame *f)
+{
+ char *string;
+
+ if (FRAME_XIC (f))
+ {
+ string = XmbResetIC (FRAME_XIC (f));
+
+ /* string is actually any string that was being composed at the
+ time of the reset. */
+
+ if (string)
+ XFree (string);
+ }
+}
+
+/* Interface used to control input method ``text conversion''. */
+
+static struct textconv_interface text_conversion_interface =
+ {
+ x_reset_conversion,
+ };
+
+#endif
+
void
init_xterm (void)
{
@@ -31520,8 +31554,11 @@ init_xterm (void)
gdk_disable_multidevice ();
#endif
#endif
-}
+
+#ifdef HAVE_X_I18N
+ register_texconv_interface (&text_conversion_interface);
#endif
+}
void
mark_xterm (void)
From 9510e8ad68271f58b4813478703a4b8eb1ba597b Mon Sep 17 00:00:00 2001
From: Po Lu
Date: Sun, 12 Feb 2023 19:56:11 +0800
Subject: [PATCH 24/24] Check in new files
* src/textconv.c (copy_buffer):
(textconv_query):
(report_selected_window_change):
(register_texconv_interface):
* src/textconv.h (struct textconv_interface):
(enum textconv_caret_direction):
(enum textconv_operation):
(struct textconv_conversion_text):
(struct textconv_callback_struct): New files.
---
src/textconv.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++++
src/textconv.h | 109 +++++++++++++++++
2 files changed, 421 insertions(+)
create mode 100644 src/textconv.c
create mode 100644 src/textconv.h
diff --git a/src/textconv.c b/src/textconv.c
new file mode 100644
index 00000000000..e91e127b71c
--- /dev/null
+++ b/src/textconv.c
@@ -0,0 +1,312 @@
+/* String conversion support for graphics terminals.
+
+Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs. If not, see . */
+
+/* String conversion support.
+
+ Many input methods require access to text surrounding the cursor.
+ They may then request that the text editor remove or substitute
+ that text for something else, for example when providing the
+ ability to ``undo'' or ``edit'' previously composed text. This is
+ most commonly seen in input methods for CJK laguages for X Windows,
+ and is extensively used throughout Android by input methods for all
+ kinds of scripts. */
+
+#include
+
+#include "textconv.h"
+#include "buffer.h"
+#include "syntax.h"
+
+
+
+/* The window system's text conversion interface.
+ NULL when the window system has not set up text conversion.
+
+ This interface will later be heavily extended on the
+ feature/android branch to deal with Android's much less
+ straightforward text conversion protocols. */
+
+static struct textconv_interface *text_interface;
+
+
+
+/* Copy the portion of the current buffer described by BEG, BEG_BYTE,
+ END, END_BYTE to the buffer BUFFER, which is END_BYTE - BEG_BYTEs
+ long. */
+
+static void
+copy_buffer (ptrdiff_t beg, ptrdiff_t beg_byte,
+ ptrdiff_t end, ptrdiff_t end_byte,
+ char *buffer)
+{
+ ptrdiff_t beg0, end0, beg1, end1, size;
+
+ if (beg_byte < GPT_BYTE && GPT_BYTE < end_byte)
+ {
+ /* Two regions, before and after the gap. */
+ beg0 = beg_byte;
+ end0 = GPT_BYTE;
+ beg1 = GPT_BYTE + GAP_SIZE - BEG_BYTE;
+ end1 = end_byte + GAP_SIZE - BEG_BYTE;
+ }
+ else
+ {
+ /* The only region. */
+ beg0 = beg_byte;
+ end0 = end_byte;
+ beg1 = -1;
+ end1 = -1;
+ }
+
+ size = end0 - beg0;
+ memcpy (buffer, BYTE_POS_ADDR (beg0), size);
+ if (beg1 != -1)
+ memcpy (buffer, BEG_ADDR + beg1, end1 - beg1);
+}
+
+
+
+/* Conversion query. */
+
+/* Perform the text conversion operation specified in QUERY and return
+ the results.
+
+ Find the text between QUERY->position from point on F's selected
+ window and QUERY->factor times QUERY->direction from that
+ position. Return it in QUERY->text.
+
+ Then, either delete that text from the buffer if QUERY->operation
+ is TEXTCONV_SUBSTITUTION, or return 0.
+
+ Value is 0 if QUERY->operation was not TEXTCONV_SUBSTITUTION
+ or if deleting the text was successful, and 1 otherwise. */
+
+int
+textconv_query (struct frame *f, struct textconv_callback_struct *query)
+{
+ specpdl_ref count;
+ ptrdiff_t pos, pos_byte, end, end_byte;
+ ptrdiff_t temp, temp1;
+ char *buffer;
+
+ /* Save the excursion, as there will be extensive changes to the
+ selected window. */
+ count = SPECPDL_INDEX ();
+ record_unwind_protect_excursion ();
+
+ /* Inhibit quitting. */
+ specbind (Qinhibit_quit, Qt);
+
+ /* Temporarily switch to F's selected window. */
+ Fselect_window (f->selected_window, Qt);
+
+ /* Now find the appropriate text bounds for QUERY. First, move
+ point QUERY->position steps forward or backwards. */
+
+ pos = PT;
+
+ /* If pos is outside the accessible part of the buffer or if it
+ overflows, move back to point or to the extremes of the
+ accessible region. */
+
+ if (INT_ADD_WRAPV (pos, query->position, &pos))
+ pos = PT;
+
+ if (pos < BEGV)
+ pos = BEGV;
+
+ if (pos > ZV)
+ pos = ZV;
+
+ /* Move to pos. */
+ set_point (pos);
+ pos = PT;
+ pos_byte = PT_BYTE;
+
+ /* Now scan forward or backwards according to what is in QUERY. */
+
+ switch (query->direction)
+ {
+ case TEXTCONV_FORWARD_CHAR:
+ /* Move forward by query->factor characters. */
+ if (INT_ADD_WRAPV (pos, query->factor, &end) || end > ZV)
+ end = ZV;
+
+ end_byte = CHAR_TO_BYTE (end);
+ break;
+
+ case TEXTCONV_BACKWARD_CHAR:
+ /* Move backward by query->factor characters. */
+ if (INT_SUBTRACT_WRAPV (pos, query->factor, &end) || end < BEGV)
+ end = BEGV;
+
+ end_byte = CHAR_TO_BYTE (end);
+ break;
+
+ case TEXTCONV_FORWARD_WORD:
+ /* Move forward by query->factor word. */
+ end = scan_words (pos, (EMACS_INT) query->factor);
+
+ if (!end)
+ {
+ end = ZV;
+ end_byte = ZV_BYTE;
+ }
+ else
+ end_byte = CHAR_TO_BYTE (end);
+
+ break;
+
+ case TEXTCONV_BACKWARD_WORD:
+ /* Move backwards by query->factor word. */
+ end = scan_words (pos, 0 - (EMACS_INT) query->factor);
+
+ if (!end)
+ {
+ end = BEGV;
+ end_byte = BEGV_BYTE;
+ }
+ else
+ end_byte = CHAR_TO_BYTE (end);
+
+ break;
+
+ case TEXTCONV_CARET_UP:
+ /* Move upwards one visual line, keeping the column intact. */
+ Fvertical_motion (Fcons (Fcurrent_column (), make_fixnum (-1)),
+ Qnil, Qnil);
+ end = PT;
+ end_byte = PT_BYTE;
+ break;
+
+ case TEXTCONV_CARET_DOWN:
+ /* Move downwards one visual line, keeping the column
+ intact. */
+ Fvertical_motion (Fcons (Fcurrent_column (), make_fixnum (1)),
+ Qnil, Qnil);
+ end = PT;
+ end_byte = PT_BYTE;
+ break;
+
+ case TEXTCONV_NEXT_LINE:
+ /* Move one line forward. */
+ scan_newline (pos, pos_byte, ZV, ZV_BYTE,
+ query->factor, false);
+ end = PT;
+ end_byte = PT_BYTE;
+ break;
+
+ case TEXTCONV_PREVIOUS_LINE:
+ /* Move one line backwards. */
+ scan_newline (pos, pos_byte, BEGV, BEGV_BYTE,
+ 0 - (EMACS_INT) query->factor, false);
+ end = PT;
+ end_byte = PT_BYTE;
+ break;
+
+ case TEXTCONV_LINE_START:
+ /* Move to the beginning of the line. */
+ Fbeginning_of_line (Qnil);
+ end = PT;
+ end_byte = PT_BYTE;
+ break;
+
+ case TEXTCONV_LINE_END:
+ /* Move to the end of the line. */
+ Fend_of_line (Qnil);
+ end = PT;
+ end_byte = PT_BYTE;
+ break;
+
+ case TEXTCONV_ABSOLUTE_POSITION:
+ /* How to implement this is unclear. */
+ SET_PT (query->factor);
+ end = PT;
+ end_byte = PT_BYTE;
+ break;
+
+ default:
+ unbind_to (count, Qnil);
+ return 1;
+ }
+
+ /* Sort end and pos. */
+
+ if (end < pos)
+ {
+ eassert (end_byte < pos_byte);
+ temp = pos_byte;
+ temp1 = pos;
+ pos_byte = end_byte;
+ pos = end;
+ end = temp1;
+ end_byte = temp;
+ }
+
+ /* Return the string first. */
+ buffer = xmalloc (end_byte - pos_byte);
+ copy_buffer (pos, pos_byte, end, end_byte, buffer);
+ query->text.text = buffer;
+ query->text.length = end - pos;
+ query->text.bytes = end_byte - pos_byte;
+
+ /* Next, perform any operation specified. */
+
+ switch (query->operation)
+ {
+ case TEXTCONV_SUBSTITUTION:
+ if (safe_del_range (pos, end))
+ {
+ /* Undo any changes to the excursion. */
+ unbind_to (count, Qnil);
+ return 1;
+ }
+
+ default:
+ }
+
+ /* Undo any changes to the excursion. */
+ unbind_to (count, Qnil);
+ return 0;
+}
+
+
+
+/* Window system interface. These are called from the rest of
+ Emacs. */
+
+/* Notice that F's selected window has been set from redisplay.
+ Reset F's input method state. */
+
+void
+report_selected_window_change (struct frame *f)
+{
+ if (!text_interface)
+ return;
+
+ text_interface->reset (f);
+}
+
+/* Register INTERFACE as the text conversion interface. */
+
+void
+register_texconv_interface (struct textconv_interface *interface)
+{
+ text_interface = interface;
+}
diff --git a/src/textconv.h b/src/textconv.h
new file mode 100644
index 00000000000..f6e7eb7925f
--- /dev/null
+++ b/src/textconv.h
@@ -0,0 +1,109 @@
+/* String conversion support for graphics terminals.
+
+Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs. If not, see . */
+
+#ifndef _TEXTCONV_H_
+
+#include "lisp.h"
+#include "frame.h"
+
+/* The function pointers in this structure should be filled out by
+ each GUI backend interested in supporting text conversion.
+
+ Finally, register_texconv_interface must be called at some point
+ during terminal initialization. */
+
+struct textconv_interface
+{
+ /* Notice that the text conversion context has changed (which can
+ happen if the window is deleted or switches buffers, or an
+ unexpected buffer change occurs.) */
+ void (*reset) (struct frame *);
+};
+
+
+
+enum textconv_caret_direction
+ {
+ TEXTCONV_FORWARD_CHAR,
+ TEXTCONV_BACKWARD_CHAR,
+ TEXTCONV_FORWARD_WORD,
+ TEXTCONV_BACKWARD_WORD,
+ TEXTCONV_CARET_UP,
+ TEXTCONV_CARET_DOWN,
+ TEXTCONV_NEXT_LINE,
+ TEXTCONV_PREVIOUS_LINE,
+ TEXTCONV_LINE_START,
+ TEXTCONV_LINE_END,
+ TEXTCONV_ABSOLUTE_POSITION,
+ };
+
+enum textconv_operation
+ {
+ TEXTCONV_SUBSTITUTION,
+ TEXTCONV_RETRIEVAL,
+ };
+
+/* Structure describing text in a buffer corresponding to a ``struct
+ textconv_callback_struct''. */
+
+struct textconv_conversion_text
+{
+ /* Length of the text in characters and bytes. */
+ size_t length, bytes;
+
+ /* Pointer to the text data. This must be deallocated by the
+ caller. */
+ char *text;
+};
+
+/* Structure describing a single query submitted by the input
+ method. */
+
+struct textconv_callback_struct
+{
+ /* Character position, relative to the current spot location, from
+ where on text should be returned. */
+ EMACS_INT position;
+
+ /* The type of scanning to perform to determine either the start or
+ the end of the conversion. */
+ enum textconv_caret_direction direction;
+
+ /* The the number of times for which to repeat the scanning in order
+ to determine the starting position of the text to return. */
+ unsigned short factor;
+
+ /* The operation to perform upon the current buffer contents.
+
+ If this is TEXTCONV_SUBSTITUTION, then the text that is returned
+ will be deleted from the buffer itself.
+
+ Otherwise, the text is simply returned without modifying the
+ buffer contents. */
+ enum textconv_operation operation;
+
+ /* Structure that will be filled with a description of the resulting
+ text. */
+ struct textconv_conversion_text text;
+};
+
+extern int textconv_query (struct frame *, struct textconv_callback_struct *);
+extern void register_texconv_interface (struct textconv_interface *);
+
+#endif /* _TEXTCONV_H_ */