mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-27 07:37:33 +00:00
Merge remote-tracking branch 'origin/master' into feature/android
This commit is contained in:
commit
19eb27d477
@ -111,7 +111,7 @@
|
||||
|
||||
2017-03-21 Noam Postavsky <npostavs@gmail.com>
|
||||
|
||||
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
|
||||
|
@ -204741,7 +204741,7 @@
|
||||
|
||||
2017-03-21 Noam Postavsky <npostavs@gmail.com>
|
||||
|
||||
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
|
||||
|
@ -223,9 +223,9 @@
|
||||
</p>
|
||||
<div class="example">
|
||||
<pre class="example">;; 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))
|
||||
</pre><pre class="example">
|
||||
|
||||
</pre><pre class="example">;; Set CSS ranges.
|
||||
|
@ -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
|
||||
|
@ -7216,6 +7216,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])
|
||||
|
@ -893,6 +893,12 @@ permissions of the file itself.)
|
||||
If the file does not exist, or if there was trouble determining
|
||||
whether the file exists, this function returns @code{nil}.
|
||||
|
||||
@cindex empty file name, and @code{file-exists-p}
|
||||
Since a file name that is an empty string is interpreted relative to
|
||||
the current buffer's default directory (@pxref{Relative File Names}),
|
||||
calling @code{file-exists-p} with an argument that is an empty string
|
||||
will report about the buffer's default directory.
|
||||
|
||||
@cindex dangling symlinks, testing for existence
|
||||
Directories are files, so @code{file-exists-p} can return @code{t}
|
||||
when given a directory. However, because @code{file-exists-p} follows
|
||||
@ -2352,6 +2358,10 @@ form.
|
||||
@end example
|
||||
@end defun
|
||||
|
||||
@cindex empty file name
|
||||
A file name that is an empty string stands for the current buffer's
|
||||
default directory.
|
||||
|
||||
@node Directory Names
|
||||
@subsection Directory Names
|
||||
@cindex directory name
|
||||
@ -2541,6 +2551,7 @@ This is for the sake of filesystems that have the concept of a
|
||||
superroot above the root directory @file{/}. On other filesystems,
|
||||
@file{/../} is interpreted exactly the same as @file{/}.
|
||||
|
||||
@cindex empty file names, and @code{expand-file-name}
|
||||
Expanding @file{.} or the empty string returns the default directory:
|
||||
|
||||
@example
|
||||
|
@ -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
|
||||
@ -970,10 +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 parsing node
|
||||
@cindex live node, tree-sitter
|
||||
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}, or @code{has-error}.
|
||||
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
|
||||
@ -1584,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
|
||||
|
@ -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
|
||||
|
@ -1061,18 +1061,6 @@ For example, the scope of the @code{magit-branch-configure} transient is
|
||||
the branch whose variables are being configured.
|
||||
@end defmac
|
||||
|
||||
It is possible to define one or more groups independently of a prefix
|
||||
definition, which is useful when those groups are to be used by more
|
||||
than just one prefix command.
|
||||
|
||||
@defmac transient-define-groups name group...
|
||||
This macro defines one or more groups of infix and suffix commands
|
||||
and stores them in a property of the symbol @var{NAME}. @var{GROUP} has the
|
||||
same form as for @code{transient-define-prefix}. Subsequently @var{NAME} can
|
||||
be used in a @var{GROUP} of @code{transient-define-prefix}, as described in the
|
||||
next section.
|
||||
@end defmac
|
||||
|
||||
@node Binding Suffix and Infix Commands
|
||||
@section Binding Suffix and Infix Commands
|
||||
|
||||
@ -1199,22 +1187,8 @@ a table.
|
||||
|
||||
Inside group specifications, including inside contained suffix
|
||||
specifications, nothing has to be quoted and quoting anyway is
|
||||
invalid.
|
||||
|
||||
How symbols are treated, depends on context. Inside suffix
|
||||
specifications they often name functions. However if they appear in
|
||||
a place where a group is expected, then they are treated as indirect
|
||||
group specifications. Such a symbol must have an associated group
|
||||
specification, created using @code{transient-define-groups}.
|
||||
|
||||
Likewise a symbol can appear in a place where a suffix specification
|
||||
is expected. The value of the @code{transient--layout} property of that
|
||||
symbol must be a single suffix specification or a list of such
|
||||
specifications. Currently no macro exist that would create such a
|
||||
symbol, and this feature should usually not be used.
|
||||
|
||||
The value following a keyword, can be explicitly unquoted using @code{,}.
|
||||
This feature is experimental and should be avoided as well.
|
||||
invalid. The value following a keyword, can be explicitly unquoted
|
||||
using @code{,}. This feature is experimental and should be avoided.
|
||||
|
||||
The form of suffix specifications is documented in the next node.
|
||||
|
||||
|
7
etc/NEWS
7
etc/NEWS
@ -71,6 +71,13 @@ Many touch screen gestures are now implemented, as is support for
|
||||
tapping buttons and opening menus.
|
||||
|
||||
|
||||
---
|
||||
** 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
|
||||
|
@ -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
|
||||
;; where: stack-ref(0) = dup (works both ways)
|
||||
;; discard(0) = no-op
|
||||
;; discardN-preserve-tos(0) = no-op
|
||||
;;
|
||||
((and (memq (car lap0) '(byte-stack-ref byte-dup))
|
||||
(or (eq (car lap1) 'byte-discardN-preserve-tos)
|
||||
(and (eq (car lap1) 'byte-stack-set)
|
||||
(eql (cdr lap1) 1)))
|
||||
;; Don't apply if immediately preceding a `return',
|
||||
;; since there are more effective rules for that case.
|
||||
(not (eq (car lap2) 'byte-return)))
|
||||
(let ((x (if (eq (car lap0) 'byte-dup) 0 (cdr lap0)))
|
||||
(y (cdr lap1)))
|
||||
(cl-assert (> 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<deleted>" 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:
|
||||
;;
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -181,8 +181,11 @@ to a package-local <package>-loaddefs.el file.")
|
||||
(put 'define-category 'doc-string-elt 2)
|
||||
;; CL
|
||||
(put 'defconstant 'doc-string-elt 3)
|
||||
(put 'define-compiler-macro 'doc-string-elt 3)
|
||||
(put 'define-setf-expander 'doc-string-elt 3)
|
||||
(put 'defparameter 'doc-string-elt 3)
|
||||
(put 'defstruct 'doc-string-elt 2)
|
||||
(put 'deftype 'doc-string-elt 3)
|
||||
|
||||
(defvar lisp-doc-string-elt-property 'doc-string-elt
|
||||
"The symbol property that holds the docstring position info.")
|
||||
|
@ -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)
|
||||
|
@ -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."
|
||||
|
@ -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))))
|
||||
@ -255,21 +255,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))))
|
||||
@ -282,7 +285,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
|
||||
@ -290,8 +294,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))
|
||||
@ -301,8 +306,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))
|
||||
@ -311,10 +317,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)))
|
||||
|
||||
|
@ -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<))
|
||||
|
@ -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 <img src=\"data:...base64...\">, 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
|
||||
<img src=\"data:...base64...\">.
|
||||
|
||||
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")
|
||||
|
||||
|
@ -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
|
||||
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)
|
||||
(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)))
|
||||
@ -405,8 +407,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
|
||||
|
@ -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)
|
||||
@ -466,8 +468,4 @@ default value at the prompt."
|
||||
|
||||
(provide 'image-dired-external)
|
||||
|
||||
;; Local Variables:
|
||||
;; nameless-current-name: "image-dired"
|
||||
;; End:
|
||||
|
||||
;;; image-dired-external.el ends here
|
||||
|
@ -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))
|
||||
@ -378,8 +380,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
|
||||
|
@ -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"))
|
||||
@ -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
|
||||
|
@ -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)))
|
||||
|
@ -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)))
|
||||
|
||||
@ -439,7 +439,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."
|
||||
@ -471,7 +471,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
|
||||
|
@ -1931,7 +1931,7 @@ even if the header display is currently pruned."
|
||||
(progn (require 'rmailout)
|
||||
(list (rmail-output-read-file-name)
|
||||
(prefix-numeric-value current-prefix-arg))))
|
||||
(let ((i 0) prev-msg)
|
||||
(let ((i 0) prev-msg curmsg)
|
||||
(while
|
||||
(and (< i n)
|
||||
(progn (rmail-summary-goto-msg)
|
||||
@ -1942,7 +1942,11 @@ even if the header display is currently pruned."
|
||||
(setq i (1+ i))
|
||||
(with-current-buffer rmail-buffer
|
||||
(let ((rmail-delete-after-output nil))
|
||||
(setq curmsg rmail-current-message)
|
||||
(rmail-output file-name 1)))
|
||||
;; rmail-output sometimes moves to the next message; undo that.
|
||||
(or (= curmsg (rmail-summary-msg-number))
|
||||
(rmail-summary-goto-msg curmsg))
|
||||
(if rmail-delete-after-output
|
||||
(rmail-summary-delete-forward nil)
|
||||
(if (< i n)
|
||||
|
@ -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)
|
||||
|
@ -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)))
|
||||
|
@ -221,7 +221,8 @@ chosen (interactively or automatically)."
|
||||
"--client-id" "emacs.eglot-dart"))
|
||||
(elixir-mode . ("language_server.sh"))
|
||||
(ada-mode . ("ada_language_server"))
|
||||
(scala-mode . ("metals-emacs"))
|
||||
(scala-mode . ,(eglot-alternatives
|
||||
'("metals" "metals-emacs")))
|
||||
(racket-mode . ("racket" "-l" "racket-langserver"))
|
||||
((tex-mode context-mode texinfo-mode bibtex-mode)
|
||||
. ,(eglot-alternatives '("digestif" "texlab")))
|
||||
|
@ -4192,8 +4192,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
|
||||
|
@ -632,7 +632,8 @@ If `transient-save-history' is nil, then do nothing."
|
||||
(transient-non-suffix :initarg :transient-non-suffix :initform nil)
|
||||
(incompatible :initarg :incompatible :initform nil)
|
||||
(suffix-description :initarg :suffix-description)
|
||||
(variable-pitch :initarg :variable-pitch :initform nil))
|
||||
(variable-pitch :initarg :variable-pitch :initform nil)
|
||||
(unwind-suffix :documentation "Internal use." :initform nil))
|
||||
"Transient prefix command.
|
||||
|
||||
Each transient prefix command consists of a command, which is
|
||||
@ -876,18 +877,6 @@ to the setup function:
|
||||
(list ,@(cl-mapcan (lambda (s) (transient--parse-child name s))
|
||||
suffixes))))))
|
||||
|
||||
(defmacro transient-define-groups (name &rest groups)
|
||||
"Define one or more GROUPS and store them in symbol NAME.
|
||||
GROUPS, defined using this macro, can be used inside the
|
||||
definition of transient prefix commands, by using the symbol
|
||||
NAME where a group vector is expected. GROUPS has the same
|
||||
form as for `transient-define-prefix'."
|
||||
(declare (debug (&define name [&rest vectorp]))
|
||||
(indent defun))
|
||||
`(put ',name 'transient--layout
|
||||
(list ,@(cl-mapcan (lambda (group) (transient--parse-child name group))
|
||||
groups))))
|
||||
|
||||
(defmacro transient-define-suffix (name arglist &rest args)
|
||||
"Define NAME as a transient suffix command.
|
||||
|
||||
@ -1411,17 +1400,6 @@ Usually it remains current while the transient is active.")
|
||||
|
||||
(defvar transient--history nil)
|
||||
|
||||
(defvar transient--abort-commands
|
||||
'(abort-minibuffers ; (minibuffer-quit-recursive-edit)
|
||||
abort-recursive-edit ; (throw 'exit t)
|
||||
exit-recursive-edit ; (throw 'exit nil)
|
||||
keyboard-escape-quit ; dwim
|
||||
keyboard-quit ; (signal 'quit nil)
|
||||
minibuffer-keyboard-quit ; (abort-minibuffers)
|
||||
minibuffer-quit-recursive-edit ; (throw 'exit (lambda ()
|
||||
; (signal 'minibuffer-quit nil)))
|
||||
top-level)) ; (throw 'top-level nil)
|
||||
|
||||
(defvar transient--scroll-commands
|
||||
'(transient-scroll-up
|
||||
transient-scroll-down
|
||||
@ -1476,10 +1454,11 @@ probably use this instead:
|
||||
(lambda (obj)
|
||||
(eq (transient--suffix-command obj)
|
||||
(or command
|
||||
;; When `this-command' is `transient-set-level',
|
||||
;; its reader needs to know what command is being
|
||||
;; configured.
|
||||
this-original-command)))
|
||||
(if (eq this-command 'transient-set-level)
|
||||
;; This is how it can look up for which
|
||||
;; command it is setting the level.
|
||||
this-original-command
|
||||
this-command))))
|
||||
(or transient--suffixes
|
||||
transient-current-suffixes))))
|
||||
(or (and (cdr suffixes)
|
||||
@ -1657,6 +1636,7 @@ See `transient-enable-popup-navigation'.")
|
||||
(define-key map [universal-argument] #'transient--do-stay)
|
||||
(define-key map [negative-argument] #'transient--do-minus)
|
||||
(define-key map [digit-argument] #'transient--do-stay)
|
||||
(define-key map [top-level] #'transient--do-quit-all)
|
||||
(define-key map [transient-quit-all] #'transient--do-quit-all)
|
||||
(define-key map [transient-quit-one] #'transient--do-quit-one)
|
||||
(define-key map [transient-quit-seq] #'transient--do-stay)
|
||||
@ -1717,8 +1697,8 @@ of the corresponding object.")
|
||||
|
||||
(defun transient--pop-keymap (var)
|
||||
(let ((map (symbol-value var)))
|
||||
(transient--debug " pop %s%s" var (if map "" " VOID"))
|
||||
(when map
|
||||
(transient--debug " pop %s" var)
|
||||
(with-demoted-errors "transient--pop-keymap: %S"
|
||||
(internal-pop-keymap map 'overriding-terminal-local-map)))))
|
||||
|
||||
@ -2042,6 +2022,7 @@ value. Otherwise return CHILDREN as is."
|
||||
(transient--push-keymap 'transient--redisplay-map)
|
||||
(add-hook 'pre-command-hook #'transient--pre-command)
|
||||
(add-hook 'post-command-hook #'transient--post-command)
|
||||
(advice-add 'recursive-edit :around #'transient--recursive-edit)
|
||||
(when transient--exitp
|
||||
;; This prefix command was invoked as the suffix of another.
|
||||
;; Prevent `transient--post-command' from removing the hooks
|
||||
@ -2077,11 +2058,14 @@ value. Otherwise return CHILDREN as is."
|
||||
(not (memq this-command '(transient-quit-one
|
||||
transient-quit-all
|
||||
transient-help))))
|
||||
(setq this-command 'transient-set-level))
|
||||
(setq this-command 'transient-set-level)
|
||||
(transient--wrap-command))
|
||||
(t
|
||||
(setq transient--exitp nil)
|
||||
(when (eq (transient--do-pre-command) transient--exit)
|
||||
(transient--pre-exit))))))
|
||||
(let ((exitp (eq (transient--do-pre-command) transient--exit)))
|
||||
(transient--wrap-command)
|
||||
(when exitp
|
||||
(transient--pre-exit)))))))
|
||||
|
||||
(defun transient--do-pre-command ()
|
||||
(if-let ((fn (transient--get-predicate-for this-command)))
|
||||
@ -2163,7 +2147,7 @@ value. Otherwise return CHILDREN as is."
|
||||
(remove-hook 'pre-command-hook #'transient--pre-command)
|
||||
(remove-hook 'post-command-hook #'transient--post-command))
|
||||
|
||||
(defun transient--resume-override ()
|
||||
(defun transient--resume-override (&optional _ignore)
|
||||
(transient--debug 'resume-override)
|
||||
(when (and transient--showp transient-hide-during-minibuffer-read)
|
||||
(transient--show))
|
||||
@ -2172,6 +2156,19 @@ value. Otherwise return CHILDREN as is."
|
||||
(add-hook 'pre-command-hook #'transient--pre-command)
|
||||
(add-hook 'post-command-hook #'transient--post-command))
|
||||
|
||||
(defun transient--recursive-edit (fn)
|
||||
(transient--debug 'recursive-edit)
|
||||
(if (not transient--prefix)
|
||||
(funcall fn)
|
||||
(transient--suspend-override (bound-and-true-p edebug-active))
|
||||
(funcall fn) ; Already unwind protected.
|
||||
(cond ((memq this-command '(top-level abort-recursive-edit))
|
||||
(setq transient--exitp t)
|
||||
(transient--post-exit)
|
||||
(transient--delete-window))
|
||||
(transient--prefix
|
||||
(transient--resume-override)))))
|
||||
|
||||
(defmacro transient--with-suspended-override (&rest body)
|
||||
(let ((depth (make-symbol "depth"))
|
||||
(setup (make-symbol "setup"))
|
||||
@ -2199,76 +2196,69 @@ value. Otherwise return CHILDREN as is."
|
||||
(remove-hook 'minibuffer-exit-hook ,exit)))
|
||||
,@body)))
|
||||
|
||||
(defun transient--post-command-hook ()
|
||||
(run-hooks 'transient--post-command-hook))
|
||||
(defun transient--wrap-command ()
|
||||
(let* ((prefix transient--prefix)
|
||||
(suffix this-command)
|
||||
(advice nil)
|
||||
(advice-interactive
|
||||
(lambda (spec)
|
||||
(let ((abort t))
|
||||
(unwind-protect
|
||||
(prog1 (advice-eval-interactive-spec spec)
|
||||
(setq abort nil))
|
||||
(when abort
|
||||
(when-let ((unwind (oref prefix unwind-suffix)))
|
||||
(transient--debug 'unwind-interactive)
|
||||
(funcall unwind suffix))
|
||||
(if (symbolp suffix)
|
||||
(advice-remove suffix advice)
|
||||
(remove-function suffix advice))
|
||||
(oset prefix unwind-suffix nil))))))
|
||||
(advice-body
|
||||
(lambda (fn &rest args)
|
||||
(unwind-protect
|
||||
(apply fn args)
|
||||
(when-let ((unwind (oref prefix unwind-suffix)))
|
||||
(transient--debug 'unwind-command)
|
||||
(funcall unwind suffix))
|
||||
(if (symbolp suffix)
|
||||
(advice-remove suffix advice)
|
||||
(remove-function suffix advice))
|
||||
(oset prefix unwind-suffix nil)))))
|
||||
(setq advice `(lambda (fn &rest args)
|
||||
(interactive ,advice-interactive)
|
||||
(apply ',advice-body fn args)))
|
||||
(if (symbolp suffix)
|
||||
(advice-add suffix :around advice '((depth . -99)))
|
||||
(add-function :around (var suffix) advice '((depth . -99))))))
|
||||
|
||||
(add-hook 'post-command-hook #'transient--post-command-hook)
|
||||
|
||||
(defun transient--delay-post-command (&optional abort-only)
|
||||
(transient--debug 'delay-post-command)
|
||||
(let ((depth (minibuffer-depth))
|
||||
(command this-command)
|
||||
(delayed (if transient--exitp
|
||||
(apply-partially #'transient--post-exit this-command)
|
||||
#'transient--resume-override))
|
||||
outside-interactive post-command abort-minibuffer)
|
||||
(unless abort-only
|
||||
(setq post-command
|
||||
(lambda () "@transient--delay-post-command"
|
||||
(let ((act (and (not (equal (this-command-keys-vector) []))
|
||||
(or (eq this-command command)
|
||||
;; `execute-extended-command' was
|
||||
;; used to call another command
|
||||
;; that also uses the minibuffer.
|
||||
(equal
|
||||
(ignore-errors
|
||||
(string-to-multibyte (this-command-keys)))
|
||||
(format "\M-x%s\r" this-command))
|
||||
;; Minibuffer used outside `interactive'.
|
||||
(and outside-interactive 'post-cmd)))))
|
||||
(transient--debug 'post-command-hook "act: %s" act)
|
||||
(when act
|
||||
(remove-hook 'transient--post-command-hook post-command)
|
||||
(remove-hook 'minibuffer-exit-hook abort-minibuffer)
|
||||
(funcall delayed)))))
|
||||
(add-hook 'transient--post-command-hook post-command))
|
||||
(setq abort-minibuffer
|
||||
(lambda () "@transient--delay-post-command"
|
||||
(let ((act (and (= (minibuffer-depth) depth)
|
||||
(or (memq this-command transient--abort-commands)
|
||||
(equal (this-command-keys) "")
|
||||
(prog1 nil
|
||||
(setq outside-interactive t))))))
|
||||
(transient--debug
|
||||
'abort-minibuffer
|
||||
"mini: %s|%s, act: %s" (minibuffer-depth) depth
|
||||
(or act (and outside-interactive '->post-cmd)))
|
||||
(when act
|
||||
(remove-hook 'transient--post-command-hook post-command)
|
||||
(remove-hook 'minibuffer-exit-hook abort-minibuffer)
|
||||
(funcall delayed)))))
|
||||
(add-hook 'minibuffer-exit-hook abort-minibuffer)))
|
||||
(defun transient--premature-post-command ()
|
||||
(and (equal (this-command-keys-vector) [])
|
||||
(= (minibuffer-depth)
|
||||
(1+ transient--minibuffer-depth))
|
||||
(progn
|
||||
(transient--debug 'premature-post-command)
|
||||
(transient--suspend-override)
|
||||
(oset (or transient--prefix transient-current-prefix)
|
||||
unwind-suffix
|
||||
(if transient--exitp
|
||||
#'transient--post-exit
|
||||
#'transient--resume-override))
|
||||
t)))
|
||||
|
||||
(defun transient--post-command ()
|
||||
(transient--debug 'post-command)
|
||||
(transient--with-emergency-exit
|
||||
(cond
|
||||
((and (equal (this-command-keys-vector) [])
|
||||
(= (minibuffer-depth)
|
||||
(1+ transient--minibuffer-depth)))
|
||||
(transient--suspend-override)
|
||||
(transient--delay-post-command (eq transient--exitp 'replace)))
|
||||
(transient--exitp
|
||||
(transient--post-exit))
|
||||
((eq this-command (oref transient--prefix command)))
|
||||
(t
|
||||
(let ((old transient--redisplay-map)
|
||||
(new (transient--make-redisplay-map)))
|
||||
(unless (equal old new)
|
||||
(transient--pop-keymap 'transient--redisplay-map)
|
||||
(setq transient--redisplay-map new)
|
||||
(transient--push-keymap 'transient--redisplay-map)))
|
||||
(transient--redisplay)))))
|
||||
(unless (transient--premature-post-command)
|
||||
(transient--debug 'post-command)
|
||||
(transient--with-emergency-exit
|
||||
(cond (transient--exitp (transient--post-exit))
|
||||
((eq this-command (oref transient--prefix command)))
|
||||
((let ((old transient--redisplay-map)
|
||||
(new (transient--make-redisplay-map)))
|
||||
(unless (equal old new)
|
||||
(transient--pop-keymap 'transient--redisplay-map)
|
||||
(setq transient--redisplay-map new)
|
||||
(transient--push-keymap 'transient--redisplay-map))
|
||||
(transient--redisplay)))))))
|
||||
|
||||
(defun transient--post-exit (&optional command)
|
||||
(transient--debug 'post-exit)
|
||||
@ -2289,7 +2279,8 @@ value. Otherwise return CHILDREN as is."
|
||||
(setq transient--exitp nil)
|
||||
(transient--stack-zap)))))
|
||||
(remove-hook 'pre-command-hook #'transient--pre-command)
|
||||
(remove-hook 'post-command-hook #'transient--post-command))
|
||||
(remove-hook 'post-command-hook #'transient--post-command)
|
||||
(advice-remove 'recursive-edit #'transient--recursive-edit))
|
||||
(setq transient-current-prefix nil)
|
||||
(setq transient-current-command nil)
|
||||
(setq transient-current-suffixes nil)
|
||||
@ -2358,7 +2349,7 @@ value. Otherwise return CHILDREN as is."
|
||||
(when transient--debug
|
||||
(let ((inhibit-message (not (eq transient--debug 'message))))
|
||||
(if (symbolp arg)
|
||||
(message "-- %-18s (cmd: %s, event: %S, exit: %s%s)"
|
||||
(message "-- %-22s (cmd: %s, event: %S, exit: %s%s)"
|
||||
arg
|
||||
(or (ignore-errors (transient--suffix-symbol this-command))
|
||||
(if (byte-code-function-p this-command)
|
||||
@ -3994,23 +3985,6 @@ search instead."
|
||||
|
||||
;;;; Edebug
|
||||
|
||||
(defun transient--edebug--recursive-edit (fn arg-mode)
|
||||
(transient--debug 'edebug--recursive-edit)
|
||||
(if (not transient--prefix)
|
||||
(funcall fn arg-mode)
|
||||
(transient--suspend-override t)
|
||||
(funcall fn arg-mode)
|
||||
(transient--resume-override)))
|
||||
|
||||
(advice-add 'edebug--recursive-edit :around #'transient--edebug--recursive-edit)
|
||||
|
||||
(defun transient--abort-edebug ()
|
||||
(when (bound-and-true-p edebug-active)
|
||||
(transient--emergency-exit)))
|
||||
|
||||
(advice-add 'abort-recursive-edit :before #'transient--abort-edebug)
|
||||
(advice-add 'top-level :before #'transient--abort-edebug)
|
||||
|
||||
(defun transient--edebug-command-p ()
|
||||
(and (bound-and-true-p edebug-active)
|
||||
(or (memq this-command '(top-level abort-recursive-edit))
|
||||
@ -4105,7 +4079,8 @@ we stop there."
|
||||
(regexp-opt (list "transient-define-prefix"
|
||||
"transient-define-infix"
|
||||
"transient-define-argument"
|
||||
"transient-define-suffix")
|
||||
"transient-define-suffix"
|
||||
"transient-define-groups")
|
||||
t)
|
||||
"\\_>[ \t'(]*"
|
||||
"\\(\\(?:\\sw\\|\\s_\\)+\\)?")
|
||||
|
@ -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
|
||||
|
@ -2525,7 +2525,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
|
||||
|
||||
|
17
src/fns.c
17
src/fns.c
@ -5813,8 +5813,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
|
||||
@ -5848,12 +5849,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
|
||||
|
@ -1538,7 +1538,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)))
|
||||
|
38
src/insdel.c
38
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. */
|
||||
|
||||
|
@ -4121,6 +4121,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 *);
|
||||
@ -5227,6 +5228,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)
|
||||
|
312
src/textconv.c
Normal file
312
src/textconv.c
Normal file
@ -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 <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* 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 <config.h>
|
||||
|
||||
#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;
|
||||
}
|
109
src/textconv.h
Normal file
109
src/textconv.h
Normal file
@ -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 <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#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_ */
|
@ -1475,6 +1475,15 @@ This symbol is the one used to create the parser. */)
|
||||
return XTS_PARSER (parser)->language_symbol;
|
||||
}
|
||||
|
||||
/* Return true if PARSER is not deleted and its buffer is live. */
|
||||
static bool
|
||||
treesit_parser_live_p (Lisp_Object parser)
|
||||
{
|
||||
CHECK_TS_PARSER (parser);
|
||||
return ((!XTS_PARSER (parser)->deleted) &&
|
||||
(!NILP (Fbuffer_live_p (XTS_PARSER (parser)->buffer))));
|
||||
}
|
||||
|
||||
/*** Parser API */
|
||||
|
||||
DEFUN ("treesit-parser-root-node",
|
||||
@ -1908,7 +1917,8 @@ DEFUN ("treesit-node-check",
|
||||
Ftreesit_node_check, Streesit_node_check, 2, 2, 0,
|
||||
doc: /* Return non-nil if NODE has PROPERTY, nil otherwise.
|
||||
|
||||
PROPERTY could be `named', `missing', `extra', `outdated', or `has-error'.
|
||||
PROPERTY could be `named', `missing', `extra', `outdated',
|
||||
`has-error', or `live'.
|
||||
|
||||
Named nodes correspond to named rules in the language definition,
|
||||
whereas "anonymous" nodes correspond to string literals in the
|
||||
@ -1924,7 +1934,10 @@ A node is "outdated" if the parser has reparsed at least once after
|
||||
the node was created.
|
||||
|
||||
A node "has error" if itself is a syntax error or contains any syntax
|
||||
errors. */)
|
||||
errors.
|
||||
|
||||
A node is "live" if its parser is not deleted and its buffer is
|
||||
live. */)
|
||||
(Lisp_Object node, Lisp_Object property)
|
||||
{
|
||||
if (NILP (node)) return Qnil;
|
||||
@ -1947,9 +1960,11 @@ errors. */)
|
||||
result = ts_node_is_extra (treesit_node);
|
||||
else if (EQ (property, Qhas_error))
|
||||
result = ts_node_has_error (treesit_node);
|
||||
else if (EQ (property, Qlive))
|
||||
result = treesit_parser_live_p (XTS_NODE (node)->parser);
|
||||
else
|
||||
signal_error ("Expecting `named', `missing', `extra', "
|
||||
"`outdated', or `has-error', but got",
|
||||
"`outdated', `has-error', or `live', but got",
|
||||
property);
|
||||
return result ? Qt : Qnil;
|
||||
}
|
||||
@ -3135,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),
|
||||
@ -3152,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 ();
|
||||
@ -3307,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.
|
||||
@ -3319,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),
|
||||
@ -3331,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 ();
|
||||
@ -3448,6 +3463,7 @@ syms_of_treesit (void)
|
||||
DEFSYM (Qextra, "extra");
|
||||
DEFSYM (Qoutdated, "outdated");
|
||||
DEFSYM (Qhas_error, "has-error");
|
||||
DEFSYM (Qlive, "live");
|
||||
|
||||
DEFSYM (QCanchor, ":anchor");
|
||||
DEFSYM (QCequal, ":equal");
|
||||
|
15
src/window.c
15
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. */
|
||||
|
303
src/xfns.c
303
src/xfns.c
@ -37,6 +37,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
#include "termhooks.h"
|
||||
#include "font.h"
|
||||
|
||||
#ifdef HAVE_X_I18N
|
||||
#include "textconv.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
@ -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);
|
||||
|
41
src/xterm.c
41
src/xterm.c
@ -636,6 +636,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
#include "xterm.h"
|
||||
#include <X11/cursorfont.h>
|
||||
|
||||
#ifdef HAVE_X_I18N
|
||||
#include "textconv.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_XCB
|
||||
#include <xcb/xproto.h>
|
||||
#include <xcb/xcb.h>
|
||||
@ -31565,7 +31569,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)
|
||||
{
|
||||
@ -31579,8 +31613,11 @@ init_xterm (void)
|
||||
gdk_disable_multidevice ();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_X_I18N
|
||||
register_texconv_interface (&text_conversion_interface);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
mark_xterm (void)
|
||||
|
@ -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)))))
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
=-=-=
|
||||
|
@ -100,6 +100,7 @@
|
||||
(should (eq nil (treesit-node-check root-node 'missing)))
|
||||
(should (eq nil (treesit-node-check root-node 'extra)))
|
||||
(should (eq nil (treesit-node-check root-node 'has-error)))
|
||||
(should (eq t (treesit-node-check root-node 'live)))
|
||||
;; `treesit-node-child'.
|
||||
(setq doc-node (treesit-node-child root-node 0))
|
||||
(should (equal "array" (treesit-node-type doc-node)))
|
||||
@ -160,7 +161,18 @@
|
||||
:type 'args-out-of-range)
|
||||
;; `treesit-node-eq'.
|
||||
(should (treesit-node-eq root-node root-node))
|
||||
(should (not (treesit-node-eq root-node doc-node))))))
|
||||
(should (not (treesit-node-eq root-node doc-node)))
|
||||
|
||||
;; Further test for `treesit-node-check'.
|
||||
(treesit-parser-delete parser)
|
||||
(should (equal nil (treesit-node-check root-node 'live)))
|
||||
;; Recreate parser.
|
||||
(setq parser (treesit-parser-create 'json))
|
||||
(setq root-node (treesit-parser-root-node
|
||||
parser))
|
||||
(should (equal t (treesit-node-check root-node 'live)))
|
||||
(kill-buffer)
|
||||
(should (equal nil (treesit-node-check root-node 'live))))))
|
||||
|
||||
;;; Indirect buffer
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user