Merge remote-tracking branch 'origin/master' into feature/android

This commit is contained in:
Po Lu 2023-04-16 08:16:07 +08:00
commit fe9e48a16a
49 changed files with 115919 additions and 766 deletions

View file

@ -321,7 +321,7 @@ them right the first time, so here are guidelines for formatting them:
** Committing your changes.
When you commit changes, Git invokes several scripts that test the
commit for validity, and may abort the commit of some of the tests
commit for validity, and may abort the commit if some of the tests
fail. These scripts live in the '.git/hooks/' subdirectory of the
top-level directory of the repository, and they perform the following
tests:

114348
ChangeLog.4 Normal file

File diff suppressed because it is too large Load diff

View file

@ -68,16 +68,25 @@ General steps (for each step, check for possible errors):
PREFERRED_BRANCH = emacs-NN
where NN is the version on the release branch from which you are
producing the tarball. If NN is incorrect, update Makefile.in and
re-run 'configure' to update Makefile.
producing the tarball. If NN is incorrect (which it usually is
when starting a pretest of a new major release), update
Makefile.in and re-run 'configure' to update Makefile.
If the versioned ChangeLog.N file is too large, start a new one
by bumping N, and also update the line in top-level Makefile.in
which says
For the first pretest of a new major release, consider starting a
new top-level ChangeLog.N file if the last versioned ChangeLog.N
file is too large. A good point to start a new ChangeLog.N file
is when the last one gets larger than 1.5 MiB. If so, start a new
one by bumping N, and also update the line in top-level
Makefile.in which says
CHANGELOG_HISTORY_INDEX_MAX = N
by incrementing the value of N by 1; then regenerate Makefile.
After bumping N, you need to actually create and commit
ChangeLog.N with the updated N, otherwise "M-x authors" below will
fail. The easiest way of creating the new ChangeLog.N is to
rename the file ChangeLog (without the .N suffix) left over from
the last major release (it is usually unversioned) and commit it.
Now:
@ -99,11 +108,12 @@ General steps (for each step, check for possible errors):
the relevant entry. If a file was deleted or renamed, consider
adding an appropriate entry to variables authors-ignored-files,
authors-valid-file-names, or authors-renamed-files-alist in
authors.el.
authors.el. If some authors are "ignored", consider adding
entries to the author-aliases variable.
If necessary, repeat 'C-u M-x authors' after making those changes.
Save the "*Authors*" buffer as etc/AUTHORS.
Check the diff looks reasonable. Maybe add entries to
Check the diff looks reasonable. Maybe add more entries to
authors-ambiguous-files or authors-aliases, and repeat.
Commit any fixes to authors.el.
@ -169,7 +179,13 @@ General steps (for each step, check for possible errors):
messages from TeX, but those seem to be harmless, as the result
looks just fine.)
5. Copy lisp/loaddefs.el to lisp/ldefs-boot.el.
5. Copy lisp/loaddefs.el to lisp/ldefs-boot.el. After copying, edit
ldefs-boot.el to add
;; no-byte-compile: t
to its file-local variables section, otherwise make-dist will
complain.
Commit ChangeLog.N, etc/AUTHORS, lisp/ldefs-boot.el, and the files
changed by M-x set-version. Note that the set-version changes

View file

@ -2249,7 +2249,8 @@ case "$opsys" in
## Motif needs -lgen.
unixware) LIBS_SYSTEM="-lsocket -lnsl -lelf -lgen" ;;
haiku) LIBS_SYSTEM="-lnetwork" ;;
# Haiku needs -lbsd for cfsetspeed.
haiku) LIBS_SYSTEM="-lnetwork -lbsd" ;;
esac
AC_SUBST([LIBS_SYSTEM])

View file

@ -2289,10 +2289,15 @@ behavior by using the options @code{image-auto-resize} and
@code{image-auto-resize-on-window-resize}.
@findex image-transform-fit-to-window
@kindex s w (Image mode)
@findex image-transform-set-percent
@kindex s p (Image mode)
@findex image-transform-set-scale
@kindex s s (Image mode)
@findex image-transform-reset-to-initial
@kindex s 0 (Image mode)
@findex image-transform-reset-to-original
@kindex s o (Image mode)
To resize the image manually you can use the command
@code{image-transform-fit-to-window} bound to @kbd{s w} that fits the
image to both the window height and width. To scale the image to a
@ -2353,6 +2358,94 @@ frames at once. You can go to a specific frame with @kbd{F}
(@code{image-reverse-speed}) reverses it. The command @kbd{a 0}
(@code{image-reset-speed}) resets the speed to the original value.
In addition to the above key bindings, which are specific to Image
mode, images shown in any Emacs buffer have special key bindings when
point is at or inside the image:
@table @kbd
@cindex resize images
@cindex image resize
@findex image-increase-size
@kindex i + (Image mode)
@item i +
Increase the image size (@code{image-increase-size}) by 20%. Prefix
numeric argument controls the increment; the value of @var{n} means to
multiply the size by the factor of @w{@code{1 + @var{n} / 10}}, so
@w{@kbd{C-u 5 i +}} means to increase the size by 50%.
@findex image-decrease-size
@kindex i - (Image mode)
@item i -
Decrease the image size (@code{image-increase-size}) by 20%. Prefix
numeric argument controls the decrement; the value of @var{n} means to
multiply the size by the factor of @w{@code{1 - @var{n} / 10}}, so
@w{@kbd{C-u 3 i -}} means to decrease the size by 30%.
@cindex rotating images
@cindex image rotation
@findex image-rotate
@kindex i r (Image mode)
@item i r
Rotate the image by 90 degrees clockwise (@code{image-rotate}).
With the prefix argument, rotate by 90 degrees counter-clockwise instead.
Note that this command is not available for sliced images.
@findex image-flip-horizontally
@kindex i h (Image mode)
@item i h
Flip the image horizontally (@code{image-flip-horizontally}). This
presents the image as if reflected in a vertical mirror.
Note that this command is not available for sliced images.
@findex image-flip-vertically
@kindex i v (Image mode)
@item i v
Flip the image vertically (@code{image-flip-vertically}). This
presents the image as if reflected in a horizontal mirror.
Note that this command is not available for sliced images.
@findex image-save
@kindex i o (Image mode)
@item i o
Save the image to a file (@code{image-save}). This command prompts
you for the name of the file to save the image.
@cindex cropping images
@vindex image-crop-crop-command
@findex image-crop
@kindex i c (Image mode)
@item i c
Crop the image (@code{image-crop}). This command is available only if
your system has an external program installed that can be used for
cropping and cutting of images; the user option
@code{image-crop-crop-command} determines what program to use, and
defaults to the ImageMagick's @command{convert} program. The command
displays the image with a rectangular frame superimposed on it, and
lets you use the mouse to move and resize the frame. Type @kbd{m} to
cause mouse movements to move the frame instead of resizing it; type
@kbd{s} to move a square frame instead. When you are satisfied with
the position and size of the cropping frame, type @kbd{@key{RET}} to
actually crop the part under the frame; or type @kbd{q} to exit
without cropping. You can then save the cropped image using @w{@kbd{i
o}} or @w{@kbd{M-x image-save}}.
@findex image-cut
@kindex i x (Image mode)
@vindex image-cut-color
@vindex image-crop-cut-command
@item i x
Cut a rectangle from the image (@code{image-cut}). This works the
same as @code{image-crop} (and also requires an external program,
defined by the variable @code{image-crop-cut-command}, to perform the
image cut), but instead of cropping the image, it removes the part
inside the frame and fills that part with the color specified by
@code{image-cut-color}. With prefix argument, the command prompts for
the color to use.
@end table
The size and rotation commands are ``repeating'', which means that you
can continue adjusting the image without using the @kbd{i} prefix.
@cindex ImageMagick support
@vindex imagemagick-enabled-types
@vindex imagemagick-types-inhibit

View file

@ -578,3 +578,80 @@ from the package directory (@pxref{Package Files}) to your checkout
and initializes the code. Note that you might have to use
@code{package-vc-refresh} to repeat the initialization and update the
autoloads.
@subsection Specifying Package Sources
@cindex package specification
@cindex specification, for source packages
To install a package from source, Emacs must know where to get the
package's source code (such as a code repository) and basic
information about the structure of the code (such as the main file in
a multi-file package). A @dfn{package specification} describes these
properties.
When supported by a package archive (@pxref{Package
Archives,,,elisp, The Emacs Lisp Reference Manual}), Emacs can
automatically download a package's specification from said archive.
If the first argument passed to @code{package-vc-install} is a symbol
naming a package, then Emacs will use the specification provided by
the archive for that package.
@example
@group
;; Emacs will download BBDB's specification from GNU ELPA:
(package-vc-install 'bbdb)
@end group
@end example
The first argument to @code{package-vc-install} may also be a
package specification. This allows you to install source packages
from locations other than the known archives listed in the user option
@code{package-archives}. A package specification is a list of the
form @code{(@var{name} . @var{spec})}, in which @var{spec} should be a
property list using any of the keys in the table below.
For definitions of basic terms for working with code repositories and
version control systems, see @ref{VCS Concepts,,,emacs, The GNU Emacs
Manual}.
@table @code
@item :url
A string providing the URL that specifies the repository from which to
fetch the package's source code.
@item :branch
A string providing the revision of the code to install. Do not
confuse this with a package's version number.
@item :lisp-dir
A string providing the repository-relative name of the directory to
use for loading the Lisp sources, which defaults to the root directory
of the repository.
@item :main-file
A string providing the main file of the project, from which to gather
package metadata. If not given, the default is the package name with
".el" appended to it.
@item :doc
A string providing the repository-relative name of the documentation
file from which to build an Info file. This can be a Texinfo file or
an Org file.
@item :vc-backend
A symbol naming the VC backend to use for downloading a copy of the
package's repository (@pxref{Version Control Systems,,,emacs, The GNU
Emacs Manual}). If omitted, Emacs will attempt to make a guess based
on the provided URL, or, failing that, the process will fall back onto
the value of @code{package-vc-default-backend}.
@end table
@example
@group
;; Specifying information manually:
(package-vc-install
'(bbdb :url "https://git.savannah.nongnu.org/git/bbdb.git"
:lisp-dir "lisp"
:doc "doc/bbdb.texi"))
@end group
@end example

View file

@ -959,9 +959,9 @@ infinite recursion.
@defun buffer-match-p condition buffer-or-name &optional arg
This function checks if a buffer designated by @code{buffer-or-name}
satisfies a @code{condition}. Optional third argument @var{arg} is
passed to the predicate function in @var{condition}. A condition can
be one of the following:
satisfies the specified @code{condition}. Optional third argument
@var{arg} is passed to the predicate function in @var{condition}. A
valid @var{condition} can be one of the following:
@itemize @bullet{}
@item
A string, interpreted as a regular expression. The buffer
@ -990,21 +990,23 @@ Satisfied if @emph{all} the conditions in @var{conds} satisfy
Satisfied if the buffer's major mode derives from @var{expr}.
@item major-mode
Satisfied if the buffer's major mode is equal to @var{expr}. Prefer
using @code{derived-mode} instead when both can work.
using @code{derived-mode} instead, when both can work.
@end table
@item t
Satisfied by any buffer. A convenient alternative to @code{""} (empty
string), @code{(and)} (empty conjunction) or @code{always}.
string) or @code{(and)} (empty conjunction).
@end itemize
@end defun
@defun match-buffers condition &optional buffer-list arg
This function returns a list of all buffers that satisfy a
@code{condition}, as defined for @code{buffer-match-p}. By default
all buffers are considered, but this can be restricted via the second
optional @code{buffer-list} argument. Optional third argument
@var{arg} will be used by @var{condition} in the same way as
@code{buffer-match-p} does.
This function returns a list of all buffers that satisfy the
@code{condition}. If no buffers match, the function returns
@code{nil}. The argument @var{condition} is as defined in
@code{buffer-match-p} above. By default, all the buffers are
considered, but this can be restricted via the optional argument
@code{buffer-list}, which should be a list of buffers to consider.
Optional third argument @var{arg} will be passed to @var{condition} in
the same way as @code{buffer-match-p} does.
@end defun
@node Creating Buffers

View file

@ -6877,7 +6877,7 @@ This function puts image @var{image} in front of @var{pos} in the
current buffer. The argument @var{pos} should be an integer or a
marker. It specifies the buffer position where the image should appear.
The argument @var{string} specifies the text that should hold the image
as an alternative to the default.
as an alternative to the default @samp{x}.
The argument @var{image} must be an image descriptor, perhaps returned
by @code{create-image} or stored by @code{defimage}.
@ -6890,7 +6890,7 @@ buffer's text.
Internally, this function creates an overlay, and gives it a
@code{before-string} property containing text that has a @code{display}
property whose value is the image. (Whew!)
property whose value is the image. (Whew! that was a mouthful@dots{})
@end defun
@defun remove-images start end &optional buffer
@ -6937,41 +6937,47 @@ This function returns @code{t} if point is on an image, and @code{nil}
otherwise.
@end defun
@cindex operations on images
Images inserted with the insertion functions above also get a local
keymap installed in the text properties (or overlays) that span the
displayed image. This keymap defines the following commands:
@table @kbd
@findex image-increase-size
@item i +
Increase the image size (@code{image-increase-size}). A prefix value
of @samp{4} means to increase the size by 40%. The default is 20%.
Increase the image size (@code{image-increase-size})
@findex image-decrease-size
@item i -
Decrease the image size (@code{image-increase-size}). A prefix value
of @samp{4} means to decrease the size by 40%. The default is 20%.
Decrease the image size (@code{image-decrease-size}).
@findex image-rotate
@item i r
Rotate the image by 90 degrees clockwise (@code{image-rotate}).
A prefix means to rotate by 90 degrees counter-clockwise instead.
Rotate the image (@code{image-rotate}).
@findex image-flip-horizontally
@item i h
Flip the image horizontally (@code{image-flip-horizontally}).
@findex image-flip-vertically
@item i v
Flip the image vertically (@code{image-flip-vertically}).
@findex image-save
@item i o
Save the image to a file (@code{image-save}).
@findex image-crop
@item i c
Crop the image interactively (@code{image-crop}).
Interactively crop the image (@code{image-crop}).
@findex image-cut
@item i x
Cut a rectangle from the image interactively (@code{image-cut}).
Interactively cut a rectangle from the image (@code{image-cut}).
@end table
The size and rotation commands are ``repeating'', which means that you
can continue adjusting the image without using the @kbd{i} prefix.
@xref{Image Mode,,, emacs, The GNU Emacs Manual}, for more details
about these image-specific key bindings.
@node Multi-Frame Images
@subsection Multi-Frame Images

View file

@ -4675,7 +4675,7 @@ has the same meaning as the @var{action} argument to
Emacs implements receiving text and URLs individually for each
window system, and does not by default support receiving other kinds
of data as drops. To support receiving other kinds of data, use the
X-specific interface described below:
X-specific interface described below.
@vindex x-dnd-test-function
@vindex x-dnd-known-types
@ -4704,29 +4704,71 @@ depending on the specific drag-and-drop protocol being used. For
example, the data type used for plain text may be either
@code{"STRING"} or @code{"text/plain"}.
@cindex XDS
@cindex direct save protocol
@vindex x-dnd-direct-save-function
@c FIXME: This description is overly-complicated and confusing. In
@c particular, the two calls to the function basically sound
@c identical, so it is unclear how should the function distinguish
@c between the first and the second one. The description of who asks
@c whom to do what is also very hard to understand. Needs rewording,
@c and needs shorter sentences. Perhaps examples could help.
However, @code{x-dnd-types-alist} does not handle a special kind of
drop sent by a program that wants Emacs to tell it where to save a
file in a specific location determined by the user. These drops are
instead handled by a function that is the value of the variable
@code{x-dnd-direct-save-function}. This function should accept two arguments.
If the first argument is non-@code{nil}, then the second argument is a
file name to save (with leading directories) that the other
program recommends, and the
function should return the full file name under which it should be
saved. After the function completes, Emacs will ask the other program
to save the file under the name that was returned, and if the file was
successfully saved, call the function again with the first argument
set to a non-@code{nil} value and the second argument set to the file
name that was returned. The function should then perform whatever
action is appropriate (i.e., opening the file or refreshing a
directory listing.)
When Emacs runs on X window system, it supports the X Direct Save
(@acronym{XDS}) protocol, which allows users to save a file by
dragging and dropping it onto an Emacs window, such as a Dired window.
To comply with the unique requirements of @acronym{XDS}, these
drag-and-drop requests are processed specially: instead of being
handled according to @code{x-dnd-types-alist}, they are handled by the
@dfn{direct-save function} that is the value of the variable
@code{x-dnd-direct-save-function}. The value should be a function of
two arguments, @var{need-name} and @var{filename}. The @acronym{XDS}
protocol uses a two-step procedure for dragging files:
@enumerate 1
@item
The application from which the file is dragged asks Emacs to provide
the full file name under which to save the file. For this purpose,
the direct-save function is called with its first argument
@var{need-name} non-@code{nil}, and the second argument @var{filename}
set to the basename of the file to be saved. It should return the
fully-expanded absolute file name under which to save the file. For
example, if a file is dragged to a Dired window, the natural directory
for the file is the directory of the file shown at location of the
drop. If saving the file is not possible for some reason, the
function should return @code{nil}, which will cancel the drag-and-drop
operation.
@item
The application from which the file is dragged saves the file under
the name returned by the first call to the direct-save function. If
it succeeds in saving the file, the direct-save function is called
again, this time with the first argument @var{need-name} set to
@code{nil} and the second argument @var{filename} set to the full
absolute name of the saved file. The function is then expected to do
whatever is needed given the fact that file was saved. For example,
Dired should update the directory on display by showing the new file
there.
@end enumerate
The default value of @code{x-dnd-direct-save-function} is
@code{x-dnd-save-direct}.
@defun x-dnd-save-direct need-name filename
When called with the @var{need-name} argument non-@code{nil}, this
function prompts the user for the absolute file name under which it
should be saved. If the specified file already exists, it
additionally asks the user whether to overwrite it, and returns the
absolute file name only if the user confirms the overwriting.
When called with the @var{need-name} argument @code{nil}, it reverts
the Dired listing if the current buffer is in Dired mode or one of its
descendants, and otherwise visits the file by calling @code{find-file}
(@pxref{Visiting Functions}).
@end defun
@defun x-dnd-save-direct-immediately need-name filename
This function works like @code{x-dnd-save-direct}, but when called
with its @var{need-name} argument non-@code{nil}, it doesn't prompt
the user for the full name of the file to be saved; instead, it
returns its argument @var{filename} expanded against the current
buffer's default directory (@pxref{File Name Expansion}). (It still
asks for confirmation if a file by that name already exists in the
default directory.)
@end defun
@cindex initiating drag-and-drop
On capable window systems, Emacs also supports dragging contents

View file

@ -3216,7 +3216,7 @@ any window it creates as dedicated to its buffer (@pxref{Dedicated
Windows}). It does that by calling @code{set-window-dedicated-p} with
the chosen window as first argument and the entry's value as second.
Side windows are by default dedicated with the value @code{side}
((@pxref{Side Window Options and Functions}).
(@pxref{Side Window Options and Functions}).
@vindex preserve-size@r{, a buffer display action alist entry}
@item preserve-size

View file

@ -5394,7 +5394,7 @@ a variable containing a vector of rules.
1: [merge, secsqr] 1: [a/x + b/x := (a + b)/x, ... ]
. .
' [merge,sinsqr] @key{RET} =
' [merge,secsqr] @key{RET} =
@end group
@end smallexample

View file

@ -3133,13 +3133,23 @@ example, you can put the following in your init file:
To avoid the slightly distracting visual effect of Emacs starting with
its default frame size and then growing to fullscreen, you can add an
@samp{Emacs.Geometry} entry to the Windows registry settings.
@xref{X Resources,,, emacs, The GNU Emacs Manual}.
To compute the correct values for width and height, first maximize the
Emacs frame and then evaluate @code{(frame-height)} and
@samp{Emacs.Geometry} entry to the Windows Registry settings. @xref{X
Resources,,, emacs, The GNU Emacs Manual}. To compute the correct
values for width and height you use in the Registry settings, first
maximize the Emacs frame and then evaluate @code{(frame-height)} and
@code{(frame-width)} with @kbd{M-:}.
Alternatively, you can avoid the visual effect of Emacs changing its
frame size entirely in your init file (i.e., without using the
Registry), like this:
@lisp
(setq frame-resize-pixelwise t)
(set-frame-position nil 0 0)
(set-frame-size nil (display-pixel-width) (display-pixel-height) t)
@end lisp
@node Emacs in a Linux console
@section How can I alleviate the limitations of the Linux console?
@cindex Console, Linux console, TTY, fbterm

View file

@ -10528,9 +10528,9 @@ article (@code{gnus-summary-refer-references}).
@kindex A T @r{(Summary)}
Display the full thread where the current article appears
(@code{gnus-summary-refer-thread}). By default this command looks for
articles only in the current group. Some backends (currently only
@code{nnimap}) know how to find articles in the thread directly. In
other cases each header in the current group must be fetched and
articles only in the current group. If the group belongs to a backend
that has an associated search engine, articles are found by searching.
In other cases each header in the current group must be fetched and
examined, so it usually takes a while. If you do it often, you may
consider setting @code{gnus-fetch-old-headers} to @code{invisible}
(@pxref{Filling In Threads}). This won't have any visible effects
@ -10538,19 +10538,22 @@ normally, but it'll make this command work a whole lot faster. Of
course, it'll make group entry somewhat slow.
@vindex gnus-refer-thread-use-search
If @code{gnus-refer-thread-use-search} is non-@code{nil} then those backends
that know how to find threads directly will search not just in the
current group but all groups on the same server.
If @code{gnus-refer-thread-use-search} is @code{nil} (the default)
then thread-referral only looks for articles in the current group. If
this variable is @code{t} the server to which the current group
belongs is searched (provided that searching is available for the
server's backend). If this variable is a list of servers, each server
in the list is searched.
@vindex gnus-refer-thread-limit
The @code{gnus-refer-thread-limit} variable says how many old (i.e.,
articles before the first displayed in the current group) headers to
fetch when doing this command. The default is 200. If @code{t}, all
the available headers will be fetched. This variable can be overridden
by giving the @kbd{A T} command a numerical prefix.
fetch when referring a thread. The default is 500. If @code{t}, all
the available headers will be fetched. This variable can be
overridden by giving the @kbd{A T} command a numerical prefix.
@vindex gnus-refer-thread-limit-to-thread
In most cases @code{gnus-refer-thread} adds any articles it finds to
@code{gnus-summary-refer-thread} tries to add any articles it finds to
the current summary buffer. (When @code{gnus-refer-thread-use-search}
is true and the initial referral starts from a summary buffer for a
non-virtual group this may not be possible. In this case a new

View file

@ -222,9 +222,9 @@ In previous Emacs versions, images have had the '+', '-' and 'r' keys
bound when point is over an image. In Emacs 29.1, additional commands
were added, and this made it more likely that users would trigger the
image commands by mistake. To avoid this, all image commands have
moved to the 'i' keymap, so '+' is now 'i +', '-' is now 'i -', and
'r' is now 'i r'. In addition, these commands are now repeating, so
you can rotate an image twice by saying 'i r r', for instance.
moved to the 'i' prefix keymap, so '+' is now 'i +', '-' is now 'i -',
and 'r' is now 'i r'. In addition, these commands are now repeating,
so, for example, you can rotate an image twice by typing 'i r r'.
+++
** Emacs now picks the correct coding-system for X input methods.
@ -1577,6 +1577,11 @@ This input method is based on the russian-computer input method, and
is intended for typing in the Chuvash language written in the Cyrillic
script.
---
*** New input method 'cyrillic-mongolian'.
This input method is for typing in the Mongolian language using the
Cyrillic script.
* Changes in Specialized Modes and Packages in Emacs 29.1
@ -2623,11 +2628,6 @@ This controls whether or not to show a message when opening certain
image formats saying how to edit it as text. The default is to show
this message for SVG and XPM.
+++
*** New commands: 'image-flip-horizontally' and 'image-flip-vertically'.
These commands horizontally and vertically flip the image under point,
and are bound to 'i h' and 'i v', respectively.
+++
*** New command 'image-transform-set-percent'.
It allows setting the image size to a percentage of its original size,
@ -2643,6 +2643,19 @@ The old name was confusing, and is now an obsolete function alias.
** Images
+++
** New commands 'image-crop' and 'image-cut'.
These commands allow interactively cropping/cutting the image at
point. The commands are bound to keys 'i c' and 'i x' (respectively)
in the local keymap over images. They rely on external programs, by
default "convert" from ImageMagick, to do the actual cropping/eliding
of the image file.
+++
*** New commands: 'image-flip-horizontally' and 'image-flip-vertically'.
These commands horizontally and vertically flip the image under point,
and are bound to 'i h' and 'i v', respectively.
+++
*** Users can now add special image conversion functions.
This is done via 'image-converter-add-handler'.
@ -3238,14 +3251,6 @@ macro, which allows you to isolate package configuration in your init
file in a way that is declarative, tidy, and performance-oriented.
See the new Info manual "(use-package) Top" for more.
+++
** New commands 'image-crop' and 'image-cut'.
These commands allow interactively cropping/cutting the image at
point. The commands are bound to keys 'i c' and 'i x' (respectively)
in the local keymap over images. They rely on external programs, by
default "convert" from ImageMagick, to do the actual cropping/eliding
of the image file.
---
** New package 'wallpaper'.
This package provides the command 'wallpaper-set', which sets the

View file

@ -74,7 +74,7 @@ AUTOGENEL = ${loaddefs} ${srcdir}/cus-load.el ${srcdir}/finder-inf.el \
# Set load-prefer-newer for the benefit of the non-bootstrappers.
BYTE_COMPILE_FLAGS = \
--eval "(setq load-prefer-newer t byte-compile-warnings 'all)" \
$(BYTE_COMPILE_EXTRA_FLAGS)
--eval "(setq org--built-in-p t)" $(BYTE_COMPILE_EXTRA_FLAGS)
# ... but we must prefer .elc files for those in the early bootstrap.
compile-first: BYTE_COMPILE_FLAGS = $(BYTE_COMPILE_EXTRA_FLAGS)
@ -543,12 +543,4 @@ $(lisp)/progmodes/cc-styles.elc: $(lisp)/progmodes/cc-vars.elc \
$(lisp)/progmodes/js.elc: $(lisp)/progmodes/cc-defs.elc \
$(lisp)/progmodes/cc-engine.elc $(lisp)/progmodes/cc-mode.elc
# When org-version.el gets updated with a new version, all the Org
# files need to be recompiled, or else the build will fail due to
# version mismatch, prompting the naive users to bootstrap. So we
# make all the Org *.elc files dependent of org-version.el, to trigger
# their recompilation automatically.
$(lisp)/org/org.elc $(filter-out $(lisp)/org/org-version.elc,$(filter-out $(lisp)/org/org.elc,$(wildcard $(lisp)/org/*.elc))): \
$(lisp)/org/org-version.el
# Makefile ends here.

View file

@ -147,32 +147,9 @@ is a symbol designating the package and SPEC is one of:
- nil, if any package version can be installed;
- a version string, if that specific revision is to be installed;
- a property list, describing a package specification. Valid
key/value pairs are
`:url' (string)
The URL of the repository used to fetch the package source.
`:branch' (string)
If given, the name of the branch to checkout after cloning the directory.
`:lisp-dir' (string)
The repository-relative name of the directory to use for loading the Lisp
sources. If not given, the value defaults to the root directory
of the repository.
`:main-file' (string)
The main file of the project, relevant to gather package metadata.
If not given, the assumed default is the package name with \".el\"
appended to it.
`:vc-backend' (symbol)
A symbol of the VC backend to use for cloning the package. The
value ought to be a member of `vc-handled-backends'. If omitted,
`vc-clone' will fall back onto the archive default or on
`package-vc-default-backend'.
All other keys are ignored.
- a property list, describing a package specification. For more
details, please consult the subsection \"Specifying Package
Sources\" in the Info node `(emacs)Fetching Package Sources'.
This user option will be automatically updated to store package
specifications for packages that are not specified in any
@ -186,6 +163,7 @@ archive."
(:branch string)
(:lisp-dir string)
(:main-file string)
(:doc string)
(:vc-backend symbol)))))
:version "29.1")

View file

@ -167,7 +167,7 @@ To override this, give an argument to `ff-find-other-file'."
:type 'boolean)
(defcustom ff-quiet-mode nil
"If non-nil, trace which directories are being searched."
"If non-nil, do not trace which directories are being searched."
:type 'boolean)
;;;###autoload
@ -351,7 +351,7 @@ Variables of interest include:
If non-nil, always attempt to create the other file if it was not found.
- `ff-quiet-mode'
If non-nil, traces which directories are being searched.
If non-nil, does not trace which directories are being searched.
- `ff-special-constructs'
A list of regular expressions specifying how to recognize special

View file

@ -1066,7 +1066,9 @@ Responsible for handling and, or, and parenthetical expressions.")
_srv query-spec groups)
(let ((artlist []))
(dolist (group groups)
(let* ((gnus-newsgroup-selection (nnselect-get-artlist group))
(let* ((gnus-newsgroup-selection
(or
(nnselect-get-artlist group) (nnselect-generate-artlist group)))
(group-spec
(nnselect-categorize
(mapcar 'car
@ -2174,37 +2176,53 @@ remaining string, then adds all that to the top-level spec."
(declare-function gnus-registry-get-id-key "gnus-registry" (id key))
(defun gnus-search-thread (header)
"Make an nnselect group based on the thread containing the article
header. The current server will be searched. If the registry is
installed, the server that the registry reports the current
article came from is also searched."
(let* ((ids (cons (mail-header-id header)
(split-string
(or (mail-header-references header)
""))))
(query
(list (cons 'query (mapconcat (lambda (i)
(format "id:%s" i))
ids " or "))
(cons 'thread t)))
(server
(list (list (gnus-method-to-server
(gnus-find-method-for-group gnus-newsgroup-name)))))
(registry-group (and
(bound-and-true-p gnus-registry-enabled)
(car (gnus-registry-get-id-key
(mail-header-id header) 'group))))
(registry-server
(and registry-group
(gnus-method-to-server
(gnus-find-method-for-group registry-group)))))
(when registry-server
(cl-pushnew (list registry-server) server :test #'equal))
(gnus-group-make-search-group nil (list
(cons 'search-query-spec query)
(cons 'search-group-spec server)))
(gnus-summary-goto-subject (gnus-id-to-article (mail-header-id header)))))
(defun gnus-search-thread (header &optional group server)
"Find articles in the thread containing HEADER from GROUP on SERVER.
If gnus-refer-thread-use-search is nil only the current group is
checked for articles; if t all groups on the server containing
the article's group will be searched; if a list then all servers
in this list will be searched. If possible the newly found
articles are added to the summary buffer; otherwise the full
thread is displayed in a new ephemeral nnselect buffer."
(let* ((group (or group gnus-newsgroup-name))
(server (or server (gnus-group-server group)))
(query
(list
(cons 'query
(mapconcat (lambda (i) (format "id:%s" i))
(cons (mail-header-id header)
(split-string
(or (mail-header-references header) "")))
" or "))
(cons 'thread t)))
(gnus-search-use-parsed-queries t))
(if (not gnus-refer-thread-use-search)
;; Search only the current group and send the headers back to
;; the caller to add to the summary buffer.
(gnus-fetch-headers
(sort
(mapcar (lambda (x) (elt x 1))
(gnus-search-run-query
(list (cons 'search-query-spec query)
(cons 'search-group-spec
(list (list server group))))))
#'<) nil t)
;; Otherwise create an ephemeral search group. If we return to
;; the current summary buffer after exiting the thread we would
;; end up overwriting any changes we made, so we exit the
;; current summary buffer first.
(gnus-summary-exit)
(gnus-group-read-ephemeral-search-group
nil
(list (cons 'search-query-spec query)
(cons 'search-group-spec
(if (listp gnus-refer-thread-use-search)
gnus-refer-thread-use-search
(list (list server))))))
(if (gnus-id-to-article (mail-header-id header))
(gnus-summary-goto-subject
(gnus-id-to-article (mail-header-id header)))
(message "Thread search failed")))))
(defun gnus-search-get-active (srv)
(let ((method (gnus-server-to-method srv))

View file

@ -80,6 +80,8 @@
(autoload 'nnselect-article-rsv "nnselect" nil nil)
(autoload 'nnselect-article-group "nnselect" nil nil)
(autoload 'gnus-nnselect-group-p "nnselect" nil nil)
(autoload 'gnus-search-thread "gnus-search" nil nil)
(autoload 'gnus-search-server-to-engine "gnus-search" nil nil)
(defcustom gnus-kill-summary-on-exit t
"If non-nil, kill the summary buffer when you exit from it.
@ -141,12 +143,17 @@ If t, fetch all the available old headers."
'gnus-refer-thread-use-search "28.1")
(defcustom gnus-refer-thread-use-search nil
"Search an entire server when referring threads.
A nil value will only search for thread-related articles in the
current group."
"Specify where to find articles when referring threads.
A nil value restricts searches for thread-related articles to the
current group; a value of t searches all groups on the server; a
list of servers and groups (where each element is a list whose
car is the server and whose cdr is a list of groups on this
server or nil to search the entire server) searches these
server/groups. This may usefully be set as a group parameter."
:version "28.1"
:group 'gnus-thread
:type 'boolean)
:type '(restricted-sexp :match-alternatives
(listp 't 'nil)))
(defcustom gnus-refer-thread-limit-to-thread nil
"If non-nil referring a thread will limit the summary buffer to
@ -9009,64 +9016,72 @@ Return the number of articles fetched."
(defun gnus-summary-refer-thread (&optional limit)
"Fetch all articles in the current thread.
For backends that know how to search for threads (currently only
`nnimap') a non-numeric prefix arg will search the entire server;
without a prefix arg only the current group is searched. If the
variable `gnus-refer-thread-use-search' is non-nil the prefix arg
has the reverse meaning. If no backend-specific `request-thread'
function is available fetch LIMIT (the numerical prefix) old
headers. If LIMIT is non-numeric or nil fetch the number
specified by the `gnus-refer-thread-limit' variable."
A non-numeric prefix arg will search the entire server; without a
prefix arg only the current group is searched. If the variable
`gnus-refer-thread-use-search' is t the prefix arg has the
reverse meaning. If searching is not enabled for the current
group, fetch LIMIT (the numerical prefix) old headers. If LIMIT
is non-numeric or nil fetch the number specified by the
`gnus-refer-thread-limit' variable."
(interactive "P" gnus-summary-mode)
(let* ((header (gnus-summary-article-header))
(id (mail-header-id header))
(gnus-inhibit-demon t)
(gnus-summary-ignore-duplicates t)
(gnus-read-all-available-headers t)
(gnus-refer-thread-use-search
(if (and (not (null limit)) (listp limit))
(not gnus-refer-thread-use-search) gnus-refer-thread-use-search))
(new-headers
(if (gnus-check-backend-function
'request-thread gnus-newsgroup-name)
(gnus-request-thread header gnus-newsgroup-name)
(let* ((limit (if (numberp limit) (prefix-numeric-value limit)
gnus-refer-thread-limit))
(last (if (numberp limit)
(min (+ (mail-header-number header)
limit)
gnus-newsgroup-highest)
gnus-newsgroup-highest))
(subject (gnus-simplify-subject
(mail-header-subject header)))
(refs (split-string (or (mail-header-references header)
"")))
(gnus-parse-headers-hook
(let* ((group gnus-newsgroup-name)
(header (gnus-summary-article-header))
(id (mail-header-id header))
(gnus-inhibit-demon t)
(gnus-summary-ignore-duplicates t)
(gnus-read-all-available-headers t)
(gnus-refer-thread-use-search
(if (or (null limit) (numberp limit))
gnus-refer-thread-use-search
(if (booleanp gnus-refer-thread-use-search)
(not gnus-refer-thread-use-search)
gnus-refer-thread-use-search)))
article-ids new-unreads
(new-headers
(cond
;; If there is a backend-specific method, use it.
((gnus-check-backend-function
'request-thread group)
(gnus-request-thread header group))
;; If a search engine is configured, use it.
((ignore-errors
(gnus-search-server-to-engine (gnus-group-server group)))
(gnus-search-thread header))
;; Otherwise just retrieve some headers.
(t
(let* ((limit (if (numberp limit)
limit
gnus-refer-thread-limit))
(last (if (numberp limit)
(min (+ (mail-header-number header) limit)
gnus-newsgroup-highest)
gnus-newsgroup-highest))
(subject (gnus-simplify-subject
(mail-header-subject header)))
(refs (split-string
(or (mail-header-references header) "")))
(gnus-parse-headers-hook
(let ((refs (append refs (list id subject))))
(lambda ()
(goto-char (point-min))
(keep-lines (regexp-opt refs))))))
(gnus-fetch-headers (list last) (if (numberp limit)
(* 2 limit) limit)
t))))
article-ids new-unreads)
(lambda () (goto-char (point-min))
(keep-lines (regexp-opt refs))))))
(gnus-fetch-headers
(list last) (if (numberp limit) (* 2 limit) limit) t))))))
(when (listp new-headers)
(dolist (header new-headers)
(push (mail-header-number header) article-ids))
(push (mail-header-number header) article-ids))
(setq article-ids (nreverse article-ids))
(setq new-unreads
(gnus-sorted-intersection gnus-newsgroup-unselected article-ids))
(gnus-sorted-intersection gnus-newsgroup-unselected article-ids))
(setq gnus-newsgroup-unselected
(gnus-sorted-ndifference gnus-newsgroup-unselected new-unreads))
(gnus-sorted-ndifference gnus-newsgroup-unselected new-unreads))
(setq gnus-newsgroup-unreads
(gnus-sorted-nunion gnus-newsgroup-unreads new-unreads))
(gnus-sorted-nunion gnus-newsgroup-unreads new-unreads))
(setq gnus-newsgroup-headers
(gnus-delete-duplicate-headers
(cl-merge
'list gnus-newsgroup-headers new-headers
'gnus-article-sort-by-number)))
(cl-merge 'list gnus-newsgroup-headers new-headers
'gnus-article-sort-by-number)))
(setq gnus-newsgroup-articles
(gnus-sorted-nunion gnus-newsgroup-articles article-ids))
(gnus-sorted-nunion gnus-newsgroup-articles article-ids))
(gnus-summary-limit-include-thread id gnus-refer-thread-limit-to-thread)))
(gnus-summary-show-thread))

View file

@ -98,7 +98,7 @@ This is only used if `mm-inline-large-images' is set to
(truncate (* mm-inline-large-images-proportion
(- (nth 3 edges) (nth 1 edges)))))))
image))
" ")
"x")
(insert "\n")
(mm-handle-set-undisplayer
handle

View file

@ -1908,19 +1908,7 @@ If LIMIT, first try to limit the search to the N last articles."
(autoload 'nnselect-search-thread "nnselect")
(deffoo nnimap-request-thread (header &optional group server)
(if gnus-refer-thread-use-search
(nnselect-search-thread header)
(when (nnimap-change-group group server)
(let* ((cmd (nnimap-make-thread-query header))
(result (with-current-buffer (nnimap-buffer)
(nnimap-command "UID SEARCH %s" cmd))))
(when result
(gnus-fetch-headers
(and (car result)
(delete 0 (mapcar #'string-to-number
(cdr (assoc "SEARCH" (cdr result))))))
nil t))))))
(make-obsolete 'nnimap-request-thread 'gnus-search-thread "29.1")
(defun nnimap-change-group (group &optional server no-reconnect read-only)
"Change group to GROUP if non-nil.

View file

@ -86,14 +86,14 @@
(let (selection)
(pcase-dolist (`(,artgroup . ,arts)
(nnselect-categorize artlist #'nnselect-artitem-group))
(let (list)
(let (list)
(pcase-dolist (`(,rsv . ,articles)
(nnselect-categorize
(nnselect-categorize
arts #'nnselect-artitem-rsv #'nnselect-artitem-number))
(push (cons rsv (gnus-compress-sequence (sort articles #'<)))
list))
(push (cons artgroup list) selection)))
selection)))
(push (cons artgroup (sort list 'car-less-than-car)) selection)))
(sort selection (lambda (x y) (string< (car x) (car y)))))))
(defun nnselect-uncompress-artlist (artlist)
"Uncompress ARTLIST."
@ -101,17 +101,20 @@
artlist
(let (selection)
(pcase-dolist (`(,artgroup . ,list) artlist)
(pcase-dolist (`(,artrsv . ,artseq) list)
(setq selection
(vconcat
(cl-map 'vector
(lambda (art)
(vector artgroup art artrsv))
(gnus-uncompress-sequence artseq)) selection))))
selection)))
(pcase-dolist (`(,artrsv . ,artseq) list)
(setq selection
(vconcat selection
(cl-map 'vector
(lambda (art)
(vector artgroup art artrsv))
(gnus-uncompress-sequence artseq))))))
(sort selection
(lambda (x y)
(< (nnselect-artitem-rsv x) (nnselect-artitem-rsv y)))))))
(make-obsolete 'nnselect-group-server 'gnus-group-server "28.1")
(make-obsolete 'nnselect-run 'nnselect-generate-artlist "29.1")
(make-obsolete 'nnselect-search-thread 'gnus-search-thread "29.1")
;; Data type article list.
@ -268,18 +271,79 @@ If this variable is nil, or if the provided function returns nil,
:version "28.1"
:type '(repeat function))
(defun nnselect-generate-artlist (group &optional specs)
"Generate the artlist for GROUP using SPECS.
SPECS should be an alist including an `nnselect-function' and an
`nnselect-args'. The former applied to the latter should create
the artlist. If SPECS is nil retrieve the specs from the group
parameters."
(defmacro nnselect-get-artlist (group)
"Get the stored list of articles for GROUP.
If the group parameter `nnselect-get-artlist-override-function'
is non-nil call this function with argument GROUP to get the
artlist; if the group parameter `nnselect-always-regenerate' is
non-nil, return nil to regenerate the artlist; otherwise retrieve
the stored artlist from the group parameters."
`(when (gnus-nnselect-group-p ,group)
(let ((override (gnus-group-get-parameter
,group
'nnselect-get-artlist-override-function)))
(cond
(override (funcall override ,group))
((gnus-group-get-parameter ,group 'nnselect-always-regenerate)
nil)
(t
(nnselect-uncompress-artlist
(gnus-group-get-parameter ,group 'nnselect-artlist t)))))))
(defmacro nnselect-store-artlist (group artlist)
"Store the ARTLIST for GROUP.
If the group parameter `nnselect-store-artlist-override-function'
is non-nil call this function on GROUP and ARTLIST; if the group
parameter `nnselect-always-regenerate' is non-nil don't store the
artlist; otherwise store the ARTLIST in the group parameters.
The active range is also stored."
`(let ((override (gnus-group-get-parameter
,group
'nnselect-store-artlist-override-function)))
(gnus-group-set-parameter ,group 'active
(cons 1 (nnselect-artlist-length ,artlist)))
(cond
(override (funcall override ,group ,artlist))
((gnus-group-get-parameter ,group 'nnselect-always-regenerate)
(gnus-group-remove-parameter ,group 'nnselect-artlist))
(t
(gnus-group-set-parameter ,group 'nnselect-artlist
(nnselect-compress-artlist ,artlist))))))
(defun nnselect-generate-artlist (group &optional specs info)
"Generate and return the artlist for GROUP using SPECS.
The artlist is sorted by rsv, lexically over groups, and by
article number. SPECS should be an alist including an
`nnselect-function' and an `nnselect-args'. The former applied
to the latter should create the artlist. If SPECS is nil
retrieve the specs from the group parameters. If INFO update the
group info."
(let* ((specs
(or specs (gnus-group-get-parameter group 'nnselect-specs t)))
(function (alist-get 'nnselect-function specs))
(args (alist-get 'nnselect-args specs)))
(condition-case-unless-debug err
(funcall function args)
(progn
(let ((gnus-newsgroup-selection
(sort
(funcall function args)
(lambda (x y)
(let ((xgroup (nnselect-artitem-group x))
(ygroup (nnselect-artitem-group y))
(xrsv (nnselect-artitem-rsv x))
(yrsv (nnselect-artitem-rsv y)))
(or (< xrsv yrsv)
(and (eql xrsv yrsv)
(or (string< xgroup ygroup)
(and (string= xgroup ygroup)
(< (nnselect-artitem-number x)
(nnselect-artitem-number y)))))))))))
(when info
(if gnus-newsgroup-selection
(nnselect-request-update-info group info)
(gnus-set-active group '(1 . 0))))
(nnselect-store-artlist group gnus-newsgroup-selection)
gnus-newsgroup-selection))
;; Don't swallow gnus-search errors; the user should be made
;; aware of them.
(gnus-search-error
@ -290,41 +354,6 @@ parameters."
"nnselect-generate-artlist: %s on %s gave error %s" function args err)
[]))))
(defmacro nnselect-get-artlist (group)
"Get the list of articles for GROUP.
If the group parameter `nnselect-get-artlist-override-function' is
non-nil call this function with argument GROUP to get the
artlist; if the group parameter `nnselect-always-regenerate' is
non-nil, regenerate the artlist; otherwise retrieve the artlist
directly from the group parameters."
`(when (gnus-nnselect-group-p ,group)
(let ((override (gnus-group-get-parameter
,group
'nnselect-get-artlist-override-function)))
(cond
(override (funcall override ,group))
((gnus-group-get-parameter ,group 'nnselect-always-regenerate)
(nnselect-generate-artlist ,group))
(t
(nnselect-uncompress-artlist
(gnus-group-get-parameter ,group 'nnselect-artlist t)))))))
(defmacro nnselect-store-artlist (group artlist)
"Store the ARTLIST for GROUP.
If the group parameter `nnselect-store-artlist-override-function'
is non-nil call this function on GROUP and ARTLIST; if the group
parameter `nnselect-always-regenerate' is non-nil don't store the
artlist; otherwise store the ARTLIST in the group parameters."
`(let ((override (gnus-group-get-parameter
,group
'nnselect-store-artlist-override-function)))
(cond
(override (funcall override ,group ,artlist))
((gnus-group-get-parameter ,group 'nnselect-always-regenerate) t)
(t
(gnus-group-set-parameter ,group 'nnselect-artlist
(nnselect-compress-artlist ,artlist))))))
;; Gnus backend interface functions.
(deffoo nnselect-open-server (server &optional definitions)
@ -345,85 +374,82 @@ artlist; otherwise store the ARTLIST in the group parameters."
(deffoo nnselect-request-group (group &optional _server _dont-check info)
(let* ((group (nnselect-add-prefix group))
(nnselect-artlist (nnselect-get-artlist group))
length)
;; Check for cached select result or run the selection and cache
;; the result.
(unless nnselect-artlist
(nnselect-store-artlist group
(setq nnselect-artlist (nnselect-generate-artlist group)))
(nnselect-request-update-info
group (or info (gnus-get-info group))))
(if (zerop (setq length (nnselect-artlist-length nnselect-artlist)))
(progn
(nnheader-report 'nnselect "Selection produced empty results.")
(when (gnus-ephemeral-group-p group)
(gnus-kill-ephemeral-group group)
(setq gnus-ephemeral-servers
(assq-delete-all 'nnselect gnus-ephemeral-servers)))
(nnheader-insert ""))
(length (cdr (gnus-group-get-parameter group 'active t))))
(when (or (null length)
(gnus-group-get-parameter group 'nnselect-always-regenerate))
(setq length (nnselect-artlist-length
(nnselect-generate-artlist group nil info))))
(if (and (zerop length) (gnus-ephemeral-group-p group))
(progn
(nnheader-report 'nnselect "Selection produced empty results.")
(gnus-kill-ephemeral-group group)
(setq gnus-ephemeral-servers
(assq-delete-all 'nnselect gnus-ephemeral-servers))
(nnheader-insert ""))
(with-current-buffer nntp-server-buffer
(nnheader-insert "211 %d %d %d %s\n"
length ; total #
1 ; first #
length ; last #
group))) ; group name
nnselect-artlist))
(nnheader-insert "211 %d %d %d %s\n"
length ; total #
(if (zerop length) 0 1) ; first #
length ; last #
group))))) ; group name
(deffoo nnselect-retrieve-headers (articles group &optional _server fetch-old)
(let ((group (nnselect-add-prefix group)))
(let ((group (nnselect-add-prefix group))
(gnus-inhibit-demon t))
(with-current-buffer (gnus-summary-buffer-name group)
(setq gnus-newsgroup-selection (or gnus-newsgroup-selection
(nnselect-get-artlist group)))
(let ((gnus-inhibit-demon t)
(gartids (ids-by-group articles))
headers)
(with-current-buffer nntp-server-buffer
(pcase-dolist (`(,artgroup . ,artids) gartids)
(let ((artlist (sort (mapcar #'cdr artids) #'<))
(gnus-override-method (gnus-find-method-for-group artgroup))
(fetch-old
(or
(car-safe
(gnus-group-find-parameter artgroup
'gnus-fetch-old-headers t))
fetch-old)))
(setq gnus-newsgroup-selection
(or gnus-newsgroup-selection
(nnselect-get-artlist group)
;; maybe don't need to update the info?
;; (nnselect-generate-artlist group nil (gnus-get-info group))))
(nnselect-generate-artlist group)))
(let ((gartids (ids-by-group articles))
headers)
(with-current-buffer nntp-server-buffer
(pcase-dolist (`(,artgroup . ,artids) gartids)
(let ((artlist (sort (mapcar #'cdr artids) #'<))
(gnus-override-method (gnus-find-method-for-group artgroup))
(fetch-old
(or
(car-safe
(gnus-group-find-parameter artgroup
'gnus-fetch-old-headers t))
fetch-old)))
(gnus-request-group artgroup)
(erase-buffer)
(pcase (setq gnus-headers-retrieved-by
(or
(and
nnselect-retrieve-headers-override-function
(funcall
nnselect-retrieve-headers-override-function
artlist artgroup))
(gnus-retrieve-headers
artlist artgroup fetch-old)))
('nov
(goto-char (point-min))
(while (not (eobp))
(nnselect-add-novitem
(nnheader-parse-nov))
(forward-line 1)))
('headers
(gnus-run-hooks 'gnus-parse-headers-hook)
(let ((nnmail-extra-headers gnus-extra-headers))
(goto-char (point-min))
(while (not (eobp))
(nnselect-add-novitem
(nnheader-parse-head))
(forward-line 1))))
((pred listp)
(dolist (novitem gnus-headers-retrieved-by)
(nnselect-add-novitem novitem)))
(_ (error "Unknown header type %s while requesting articles \
of group %s" gnus-headers-retrieved-by artgroup)))))
(setq headers
(sort
headers
(lambda (x y)
(< (mail-header-number x) (mail-header-number y))))))))))
(erase-buffer)
(pcase (setq gnus-headers-retrieved-by
(or
(and
nnselect-retrieve-headers-override-function
(funcall
nnselect-retrieve-headers-override-function
artlist artgroup))
(gnus-retrieve-headers
artlist artgroup fetch-old)))
('nov
(goto-char (point-min))
(while (not (eobp))
(nnselect-add-novitem
(nnheader-parse-nov))
(forward-line 1)))
('headers
(gnus-run-hooks 'gnus-parse-headers-hook)
(let ((nnmail-extra-headers gnus-extra-headers))
(goto-char (point-min))
(while (not (eobp))
(nnselect-add-novitem
(nnheader-parse-head))
(forward-line 1))))
((pred listp)
(dolist (novitem gnus-headers-retrieved-by)
(nnselect-add-novitem novitem)))
(_ (error "Unknown header type %s while requesting articles \
of group %s" gnus-headers-retrieved-by artgroup)))))
(setq headers
(sort
headers
(lambda (x y)
(< (mail-header-number x) (mail-header-number y))))))))))
(deffoo nnselect-request-article (article &optional _group server to-buffer)
@ -567,9 +593,9 @@ artlist; otherwise store the ARTLIST in the group parameters."
(artnumber (nnselect-article-number article))
(gmark (gnus-request-update-mark artgroup artnumber mark)))
(when (and artnumber
(memq mark gnus-auto-expirable-marks)
(= mark gmark)
(gnus-group-auto-expirable-p artgroup))
(memq mark gnus-auto-expirable-marks)
(= mark gmark)
(gnus-group-auto-expirable-p artgroup))
(setq gmark gnus-expirable-mark))
gmark))
@ -656,57 +682,48 @@ artlist; otherwise store the ARTLIST in the group parameters."
(deffoo nnselect-request-thread (header &optional group server)
(with-current-buffer gnus-summary-buffer
(let ((group (nnselect-add-prefix group))
;; find the best group for the originating article. if its a
;; pseudo-article look for real articles in the same thread
;; and see where they come from.
(artgroup (nnselect-article-group
(if (> (mail-header-number header) 0)
(mail-header-number header)
(if (> (gnus-summary-article-number) 0)
(gnus-summary-article-number)
(let ((thread
(gnus-id-to-thread (mail-header-id header))))
(when thread
(cl-some (lambda (x)
(when (and x (> x 0)) x))
(gnus-articles-in-thread thread)))))))))
;; Check if search-based thread referral is permitted, and
;; available.
(if (and gnus-refer-thread-use-search
(gnus-search-server-to-engine
(gnus-method-to-server
(gnus-find-method-for-group artgroup))))
;; If so we perform the query, massage the result, and return
;; the new headers back to the caller to incorporate into the
;; current summary buffer.
(let* ((gnus-search-use-parsed-queries t)
(let* ((group (nnselect-add-prefix group))
;; Find the best group for the originating article. If its
;; a pseudo-article check for real articles in the same
;; thread to see where they come from.
(artgroup
(nnselect-article-group
(cond
((> (mail-header-number header) 0)
(mail-header-number header))
((> (gnus-summary-article-number) 0)
(gnus-summary-article-number))
(t (cl-some
(lambda (x) (when (and x (> x 0)) x))
(gnus-articles-in-thread
(gnus-id-to-thread (mail-header-id header))))))))
(server (or server (gnus-group-server artgroup))))
;; Check if search-based thread referral is available.
(if (ignore-errors (gnus-search-server-to-engine server))
;; We perform the query, massage the result, and return
;; the new headers back to the caller to incorporate into
;; the current summary buffer.
(let* ((gnus-search-use-parsed-queries t)
(group-spec
(list (delq nil (list
(or server (gnus-group-server artgroup))
(unless gnus-refer-thread-use-search
artgroup)))))
(ids (cons (mail-header-id header)
(split-string
(or (mail-header-references header)
""))))
(query-spec
(list (cons 'query (mapconcat (lambda (i)
(format "id:%s" i))
ids " or "))
(cons 'thread t)))
(last (nnselect-artlist-length gnus-newsgroup-selection))
(first (1+ last))
(new-nnselect-artlist
(gnus-search-run-query
(list (cons 'search-query-spec query-spec)
(cons 'search-group-spec group-spec))))
old-arts seq
headers)
(mapc
(if (not gnus-refer-thread-use-search)
(list (list server artgroup))
(if (listp gnus-refer-thread-use-search)
gnus-refer-thread-use-search
(list (list server)))))
(ids (cons (mail-header-id header)
(split-string
(or (mail-header-references header)
""))))
(query-spec
(list (cons 'query
(mapconcat (lambda (i) (format "id:%s" i))
ids " or ")) (cons 'thread t)))
(last (nnselect-artlist-length gnus-newsgroup-selection))
(first (1+ last))
old-arts seq headers)
(mapc
(lambda (article)
(if
(setq seq
(if (setq seq
(cl-position
article
gnus-newsgroup-selection
@ -714,48 +731,61 @@ artlist; otherwise store the ARTLIST in the group parameters."
(lambda (x y)
(and (equal (nnselect-artitem-group x)
(nnselect-artitem-group y))
(eql (nnselect-artitem-number x)
(eql (nnselect-artitem-number x)
(nnselect-artitem-number y))))))
(push (1+ seq) old-arts)
(setq gnus-newsgroup-selection
(vconcat gnus-newsgroup-selection (vector article)))
(cl-incf last)))
new-nnselect-artlist)
(setq headers
(gnus-fetch-headers
(append (sort old-arts #'<)
(number-sequence first last))
nil t))
(nnselect-store-artlist group gnus-newsgroup-selection)
(when (>= last first)
(let (new-marks)
(pcase-dolist (`(,artgroup . ,artids)
(ids-by-group (number-sequence first last)))
(pcase-dolist (`(,type . ,marked)
(gnus-info-marks (gnus-get-info artgroup)))
(setq marked (gnus-uncompress-sequence marked))
(when (setq new-marks
(delq nil
(mapcar
(gnus-search-run-query
(list (cons 'search-query-spec query-spec)
(cons 'search-group-spec group-spec))))
(setq headers
(gnus-fetch-headers
(append (sort old-arts #'<) (number-sequence first last))
nil t))
(nnselect-store-artlist group gnus-newsgroup-selection)
(when (>= last first)
(let (new-marks)
(pcase-dolist (`(,artgroup . ,artids)
(ids-by-group (number-sequence first last)))
(pcase-dolist (`(,type . ,marked)
(gnus-info-marks (gnus-get-info artgroup)))
(when
(setq new-marks
(delq nil
(if (eq (gnus-article-mark-to-type type)
'tuple)
(mapcar
(lambda (art)
(let ((mtup
(assq (cdr art) marked)))
(when mtup
(cons (car art) (cdr mtup)))))
artids)
(setq marked
(gnus-uncompress-sequence marked))
(mapcar
(lambda (art)
(when (memq (cdr art) marked)
(car art)))
artids)))
(nconc
(symbol-value
(intern
(format "gnus-newsgroup-%s"
(car (rassq type gnus-article-mark-lists)))))
new-marks)))))
(setq gnus-newsgroup-active
(cons 1 (nnselect-artlist-length gnus-newsgroup-selection)))
(gnus-set-active
group
(cons 1 (nnselect-artlist-length gnus-newsgroup-selection))))
headers)
;; If we can't or won't use search, just warp to the original
;; group and punt back to gnus-summary-refer-thread.
(and (gnus-warp-to-article) (gnus-summary-refer-thread))))))
artids))))
(nconc
(symbol-value
(intern
(format "gnus-newsgroup-%s"
(car
(rassq type gnus-article-mark-lists)))))
new-marks)))))
(gnus-set-active
group
(setq
gnus-newsgroup-active
(cons 1 (nnselect-artlist-length gnus-newsgroup-selection)))))
headers)
;; If we can't use search, just warp to the original group and
;; punt back to gnus-summary-refer-thread.
(and (gnus-warp-to-article) (gnus-summary-refer-thread))))))
(deffoo nnselect-close-group (group &optional _server)
@ -774,23 +804,23 @@ artlist; otherwise store the ARTLIST in the group parameters."
(message "Creating nnselect group %s" group)
(let* ((group (gnus-group-prefixed-name group '(nnselect "nnselect")))
(specs (assq 'nnselect-specs args))
(artlist (alist-get 'nnselect-artlist args))
(otherargs (assq-delete-all 'nnselect-specs args))
(function-spec
(or (alist-get 'nnselect-function specs)
(intern (completing-read "Function: " obarray #'functionp))))
(intern (completing-read "Function: " obarray #'functionp))))
(args-spec
(or (alist-get 'nnselect-args specs)
(read-from-minibuffer "Args: " nil nil t nil "nil")))
(nnselect-specs (list (cons 'nnselect-function function-spec)
(cons 'nnselect-args args-spec))))
(cons 'nnselect-args args-spec))))
(gnus-group-set-parameter group 'nnselect-specs nnselect-specs)
(dolist (arg otherargs)
(gnus-group-set-parameter group (car arg) (cdr arg)))
(nnselect-store-artlist
group
(or (alist-get 'nnselect-artlist args)
(nnselect-generate-artlist group nnselect-specs)))
(nnselect-request-update-info group (gnus-get-info group)))
(if artlist
(nnselect-store-artlist group artlist)
(nnselect-generate-artlist group nnselect-specs
(gnus-get-info group))))
t)
@ -820,11 +850,12 @@ artlist; otherwise store the ARTLIST in the group parameters."
(deffoo nnselect-request-group-scan (group &optional _server _info)
(let* ((group (nnselect-add-prefix group))
(artlist (nnselect-generate-artlist group)))
(gnus-set-active group (cons 1 (nnselect-artlist-length
artlist)))
(nnselect-store-artlist group artlist)))
(let ((group (nnselect-add-prefix group)))
(unless (gnus-group-find-parameter group 'nnselect-always-regenerate)
(let ((artlist (nnselect-generate-artlist group)))
(gnus-set-active group (cons 1 (nnselect-artlist-length
artlist))))))
t)
;; Add any undefined required backend functions

View file

@ -51,7 +51,7 @@ static \\(unsigned \\)?char \\1_bits" . xbm)
("\\`\\(?:MM\0\\*\\|II\\*\0\\)" . tiff)
("\\`[\t\n\r ]*%!PS" . postscript)
("\\`\xff\xd8" . jpeg) ; used to be (image-jpeg-p . jpeg)
("\\`RIFF....WEBPVP8" . webp)
("\\`RIFF[^z-a][^z-a][^z-a][^z-a]WEBPVP8" . webp)
(,(let* ((incomment-re "\\(?:[^-]\\|-[^-]\\)")
(comment-re (concat "\\(?:!--" incomment-re "*-->[ \t\r\n]*<\\)")))
(concat "\\(?:<\\?xml[ \t\r\n]+[^>]*>\\)?[ \t\r\n]*<"
@ -172,22 +172,27 @@ or \"ffmpeg\") is installed."
(define-error 'unknown-image-type "Unknown image type")
(defvar-keymap image-map
:doc "Map put into text properties on images."
(defvar-keymap image-slice-map
:doc "Map put into text properties on sliced images."
"i" (define-keymap
"-" #'image-decrease-size
"+" #'image-increase-size
"r" #'image-rotate
"o" #'image-save
"c" #'image-crop
"x" #'image-cut
"h" #'image-flip-horizontally
"v" #'image-flip-vertically)
"x" #'image-cut)
"C-<wheel-down>" #'image-mouse-decrease-size
"C-<mouse-5>" #'image-mouse-decrease-size
"C-<wheel-up>" #'image-mouse-increase-size
"C-<mouse-4>" #'image-mouse-increase-size)
(defvar-keymap image-map
:doc "Map put into text properties on images."
:parent image-slice-map
"i" (define-keymap
"r" #'image-rotate
"h" #'image-flip-horizontally
"v" #'image-flip-vertically))
(defun image-load-path-for-library (library image &optional path no-error)
"Return a suitable search path for images used by LIBRARY.
@ -665,7 +670,9 @@ is non-nil, this is inhibited."
image)
rear-nonsticky t
inhibit-isearch ,inhibit-isearch
keymap ,image-map))))
keymap ,(if slice
image-slice-map
image-map)))))
;;;###autoload
@ -701,8 +708,8 @@ The image is automatically split into ROWS x COLS slices."
(insert string)
(add-text-properties start (point)
`(display ,(list (list 'slice x y dx dy) image)
rear-nonsticky (display)
keymap ,image-map))
rear-nonsticky (display keymap)
keymap ,image-slice-map))
(setq x (+ x dx))))
(setq x 0.0
y (+ y dy))

View file

@ -35,6 +35,7 @@
(declare-function image-property "image.el" (image property))
(declare-function image-size "image.c" (spec &optional pixels frame))
(declare-function imagep "image.c" (spec))
(declare-function image--get-image "image.el" (&optional position))
(defgroup image-crop ()
"Image cropping."
@ -113,18 +114,14 @@ and the cropped image data.")
(defun image-cut (&optional color)
"Cut a rectangle from the image under point, filling it with COLOR.
COLOR defaults to the value of `image-cut-color'.
Interactively, with prefix argument, prompt for COLOR to use."
(interactive (list (and current-prefix-arg (read-color "Use color: "))))
(image-crop (if (zerop (length color)) image-cut-color color)))
Interactively, with prefix argument, prompt for COLOR to use.
;;;###autoload
(defun image-crop (&optional cut)
"Crop the image under point.
If CUT is non-nil, remove a rectangle from the image instead of
cropping the image. In that case CUT should be the name of a
color to fill the rectangle.
This command presents the image with a rectangular area superimposed
on it, and allows moving and resizing the area to define which
part of it to cut.
While cropping the image, the following key bindings are available:
While moving/resizing the cutting area, the following key bindings
are available:
`q': Exit without changing anything.
`RET': Crop/cut the image.
@ -132,15 +129,51 @@ While cropping the image, the following key bindings are available:
rectangle shape.
`s': Same as `m', but make the rectangle into a square first.
After cropping an image, you can save it by `M-x image-save' or
After cutting the image, you can save it by `M-x image-save' or
\\<image-map>\\[image-save] when point is over the image."
(interactive (list (and current-prefix-arg
(read-color "Color to use for filling: "))))
(image-crop (if (zerop (length color)) image-cut-color color)))
;;;###autoload
(defun image-crop (&optional cut)
"Crop the image under point.
This command presents the image with a rectangular area superimposed
on it, and allows moving and resizing the area to define which
part of it to crop.
While moving/resizing the cropping area, the following key bindings
are available:
`q': Exit without changing anything.
`RET': Crop/cut the image.
`m': Make mouse movements move the rectangle instead of altering the
rectangle shape.
`s': Same as `m', but make the rectangle into a square first.
After cropping the image, you can save it by `M-x image-save' or
\\<image-map>\\[image-save] when point is over the image.
When called from Lisp, if CUT is non-nil, remove a rectangle from
the image instead of cropping the image. In that case, CUT should
be the name of a color to fill the rectangle."
(interactive)
(unless (image-type-available-p 'svg)
(error "SVG support is needed to crop images"))
(unless (executable-find (car image-crop-crop-command))
(error "Couldn't find %s command to crop the image"
(car image-crop-crop-command)))
(let ((image (get-text-property (point) 'display)))
(error "SVG support is needed to crop and cut images"))
(let* ((crop-cmd (car image-crop-crop-command))
(found (executable-find crop-cmd)))
(unless found
(error "Couldn't find `%s' command to crop/cut the image" crop-cmd))
(if (and (memq system-type '(windows-nt ms-dos))
;; MS-Windows has an incompatible convert.exe, used to
;; convert filesystems...
(string-equal crop-cmd "convert")
(= 0 (string-search "Invalid drive specification."
(shell-command-to-string
(format "%s %s" crop-cmd null-device)))))
(error "The program `%s' is not an image conversion program"
found)))
(let ((image (image--get-image)))
(unless (imagep image)
(user-error "No image under point"))
(when (overlays-at (point))

View file

@ -1995,7 +1995,8 @@ Remaining args are for FUNC."
(defun quail-minibuffer-message (string)
(message nil)
(let ((point-max (point-max))
(inhibit-quit t))
(inhibit-quit t)
(deactivate-mark nil))
(save-excursion
(goto-char point-max)
(insert string))

View file

@ -574,15 +574,14 @@ With optional CLEANUP, kill any associated buffers."
(cl-return-from jsonrpc--process-filter))
(when (buffer-live-p (process-buffer proc))
(with-current-buffer (process-buffer proc)
(let* ((inhibit-read-only t)
(jsonrpc--in-process-filter t)
(let* ((jsonrpc--in-process-filter t)
(connection (process-get proc 'jsonrpc-connection))
(expected-bytes (jsonrpc--expected-bytes connection)))
;; Insert the text, advancing the process marker.
;;
(save-excursion
(goto-char (process-mark proc))
(insert string)
(let ((inhibit-read-only t)) (insert string))
(set-marker (process-mark proc) (point)))
;; Loop (more than one message might have arrived)
;;
@ -631,7 +630,8 @@ With optional CLEANUP, kill any associated buffers."
(jsonrpc-connection-receive connection
json-message)))))
(goto-char message-end)
(delete-region (point-min) (point))
(let ((inhibit-read-only t))
(delete-region (point-min) (point)))
(setq expected-bytes nil))))
(t
;; Message is still incomplete

View file

@ -1844,6 +1844,125 @@ Doubling the postfix separates the letter and postfix
("E**" ["У*"])
("e**" ["у*"]))
;; Mongolian layout: Mongolian alphabet has 2 letters: Ө Ү,
;; and the layout is quite different from other cyrillic layouts.
;; Written by Garid Zorigoo.
(quail-define-package
"cyrillic-mongolian" "Mongolian" "MN-" t
"Input method for cyrillic Mongolian"
nil t nil nil nil nil nil nil nil nil t)
;; № - " ₮ : . _ , % ? е щ
;; Ф Ц У Ж Э Н Г Ш Ү З К Ъ
;; Й Ы Б Ө А Х Р О Л Д П
;; Я Ч Ё С М И Т Ь В Ю
(quail-define-rules
;; (lowercase 1st row)
("q" )
("w" )
("e" ?у)
("r" )
("t" )
("y" )
("u" ?г)
("i" )
("o" ?ү)
("p" )
("[" )
("]" )
;; (lowercase 2nd row)
("a" )
("s" )
("d" ?б)
("f" )
("g" ?а)
("h" ?х)
("j" ?р)
("k" ?о)
("l" )
(";" )
("'" ?п)
;; (lowercase 3rd row)
("z" )
("x" )
("c" )
("v" ?с)
("b" )
("n" )
("m" )
("," )
("." )
("/" )
;; (uppercase 1st row)
("Q" )
("W" )
("E" ?У)
("R" )
("T" )
("Y" ?Н)
("U" )
("I" )
("O" ?Ү)
("P" ?З)
("{" ?К)
("}" )
;; (uppercase 2nd row)
("A" )
("S" )
("D" )
("F" )
("G" ?А)
("H" ?Х)
("J" ?Р)
("K" ?О)
("L" )
(":" )
("\"" )
;; (uppercase 3rd row)
("Z" )
("X" )
("C" )
("V" ?С)
("B" ?М)
("N" )
("M" ?Т)
("<" ?Ь)
(">" ?В)
("?" )
;; (number row without shift)
("1" ?№)
("2" ?-)
("3" ?\")
("4" ?₮)
("5" ?:)
("6" ?.)
("7" ?_)
("8" ?,)
("9" ?%)
("0" ??)
("-" ?е)
("=" )
;; (number row with shift)
("!" ?1)
("@" ?2)
("#" ?3)
("$" ?4)
("%" ?5)
("^" ?6)
("&" ?7)
("*" ?8)
("(" ?9)
(")" ?0)
("_" ?Е)
("+" ))
;; Local Variables:
;; coding: utf-8
;; End:

View file

@ -533,7 +533,8 @@ Some context functions add menu items below the separator."
(i 0))
(dolist (item (reverse yank-menu))
(when (consp item)
(define-key submenu (vector (setq i (1+ i)))
(define-key submenu
(vector (intern (format "kill-%d" (setq i (1+ i)))))
`(menu-item ,(cadr item)
,(lambda () (interactive)
(mouse-yank-from-menu click (car item)))))))

View file

@ -326,7 +326,7 @@ parameter, and should return the (possibly) transformed URL."
"<mouse-2>" #'eww-follow-link)
(defvar-keymap eww-image-link-keymap
:parent shr-map
:parent shr-image-map
"RET" #'eww-follow-link)
(defun eww-suggested-uris nil

View file

@ -276,7 +276,7 @@ and other things:
(defvar-keymap shr-map
"a" #'shr-show-alt-text
"i" #'shr-browse-image
"M-i" #'shr-browse-image
"z" #'shr-zoom-image
"TAB" #'shr-next-link
"C-M-i" #'shr-previous-link

View file

@ -79,6 +79,7 @@
(declare-function treesit-node-type "treesit.c")
(declare-function treesit-node-prev-sibling "treesit.c")
(declare-function treesit-node-first-child-for-pos "treesit.c")
(declare-function treesit-node-next-sibling "treesit.c")
;;; Custom variables
@ -192,6 +193,10 @@ To set the default indent style globally, use
(c-ts-mode--get-indent-style
(if (derived-mode-p 'c-ts-mode) 'c 'cpp))))))
(defvar c-ts-mode-emacs-devel nil
"If the value is t, enable Emacs source-specific features.
This needs to be set before enabling `c-ts-mode'.")
;;; Syntax table
(defvar c-ts-mode--syntax-table
@ -802,7 +807,14 @@ Return nil if NODE is not a defun node or doesn't have a name."
((or "struct_specifier" "enum_specifier"
"union_specifier" "class_specifier"
"namespace_definition")
(treesit-node-child-by-field-name node "name")))
(treesit-node-child-by-field-name node "name"))
;; DEFUNs in Emacs source.
("expression_statement"
(let* ((call-exp-1 (treesit-node-child node 0))
(call-exp-2 (treesit-node-child call-exp-1 0))
(arg-list (treesit-node-child call-exp-2 1))
(name (treesit-node-child arg-list 1 t)))
name)))
t))
;;; Defun navigation
@ -810,28 +822,29 @@ Return nil if NODE is not a defun node or doesn't have a name."
(defun c-ts-mode--defun-valid-p (node)
"Return non-nil if NODE is a valid defun node.
Ie, NODE is not nested."
(not (or (and (member (treesit-node-type node)
'("struct_specifier"
"enum_specifier"
"union_specifier"
"declaration"))
;; If NODE's type is one of the above, make sure it is
;; top-level.
(treesit-node-top-level
node (rx (or "function_definition"
"type_definition"
"struct_specifier"
(or (c-ts-mode--emacs-defun-p node)
(not (or (and (member (treesit-node-type node)
'("struct_specifier"
"enum_specifier"
"union_specifier"
"declaration"))))
"declaration"))
;; If NODE's type is one of the above, make sure it is
;; top-level.
(treesit-node-top-level
node (rx (or "function_definition"
"type_definition"
"struct_specifier"
"enum_specifier"
"union_specifier"
"declaration"))))
(and (equal (treesit-node-type node) "declaration")
;; If NODE is a declaration, make sure it is not a
;; function declaration.
(equal (treesit-node-type
(treesit-node-child-by-field-name
node "declarator"))
"function_declarator")))))
(and (equal (treesit-node-type node) "declaration")
;; If NODE is a declaration, make sure it is not a
;; function declaration.
(equal (treesit-node-type
(treesit-node-child-by-field-name
node "declarator"))
"function_declarator"))))))
(defun c-ts-mode--defun-for-class-in-imenu-p (node)
"Check if NODE is a valid entry for the Class subindex.
@ -859,17 +872,85 @@ the semicolon. This function skips the semicolon."
(goto-char (match-end 0)))
(treesit-default-defun-skipper))
(defun c-ts-base--before-indent (args)
(pcase-let ((`(,node ,parent ,bol) args))
(when (null node)
(let ((smallest-node (treesit-node-at (point))))
;; "Virtual" closer curly added by the
;; parser's error recovery.
(when (and (equal (treesit-node-type smallest-node) "}")
(equal (treesit-node-end smallest-node)
(treesit-node-start smallest-node)))
(setq parent (treesit-node-parent smallest-node)))))
(list node parent bol)))
(defun c-ts-mode--emacs-defun-p (node)
"Return non-nil if NODE is a DEFUN in Emacs source files."
(and (equal (treesit-node-type node) "expression_statement")
(equal (treesit-node-text
(treesit-node-child-by-field-name
(treesit-node-child
(treesit-node-child node 0) 0)
"function")
t)
"DEFUN")))
(defun c-ts-mode--emacs-defun-at-point (&optional range)
"Return the current defun node.
This function recognizes DEFUNs in Emacs source files.
Note that for the case of a DEFUN, it is made of two separate
nodes, one for the declaration and one for the body, this
function returns the declaration node.
If RANGE is non-nil, return (BEG . END) where BEG end END
encloses the whole defun. This solves the problem of only
returning the declaration part for DEFUN."
(or (when-let ((node (treesit-defun-at-point)))
(if range
(cons (treesit-node-start node)
(treesit-node-end node))
node))
(and c-ts-mode-emacs-devel
(let ((candidate-1 ; For when point is in the DEFUN statement.
(treesit-node-prev-sibling
(treesit-node-top-level
(treesit-node-at (point))
"compound_statement")))
(candidate-2 ; For when point is in the body.
(treesit-node-top-level
(treesit-node-at (point))
"expression_statement")))
(when-let
((node (or (and (c-ts-mode--emacs-defun-p candidate-1)
candidate-1)
(and (c-ts-mode--emacs-defun-p candidate-2)
candidate-2))))
(if range
(cons (treesit-node-start node)
(treesit-node-end
(treesit-node-next-sibling node)))
node))))))
(defun c-ts-mode-indent-defun ()
"Indent the current top-level declaration syntactically.
`treesit-defun-type-regexp' defines what constructs to indent."
(interactive "*")
(when-let ((orig-point (point-marker))
(node (treesit-defun-at-point)))
(indent-region (treesit-node-start node)
(treesit-node-end node))
(range (c-ts-mode--emacs-defun-at-point t)))
(indent-region (car range) (cdr range))
(goto-char orig-point)))
(defun c-ts-mode--emacs-current-defun-name ()
"Return the name of the current defun.
This is used for `add-log-current-defun-function'. This
recognizes DEFUN in Emacs sources, in addition to normal function
definitions."
(or (treesit-add-log-current-defun)
(c-ts-mode--defun-name (c-ts-mode--emacs-defun-at-point))))
;;; Modes
(defvar-keymap c-ts-base-mode-map
@ -933,6 +1014,11 @@ the semicolon. This function skips the semicolon."
;; function_definitions, so we need to find the top-level node.
(setq-local treesit-defun-prefer-top-level t)
;; When the code is in incomplete state, try to make a better guess
;; about which node to indent against.
(add-function :filter-args (local 'treesit-indent-function)
#'c-ts-base--before-indent)
;; Indent.
(when (eq c-ts-mode-indent-style 'linux)
(setq-local indent-tabs-mode t))
@ -1008,7 +1094,11 @@ in your configuration."
(setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'c))
;; Navigation.
(setq-local treesit-defun-tactic 'top-level)
(treesit-major-mode-setup)))
(treesit-major-mode-setup)
(when c-ts-mode-emacs-devel
(setq-local add-log-current-defun-function
#'c-ts-mode--emacs-current-defun-name))))
;;;###autoload
(define-derived-mode c++-ts-mode c-ts-base-mode "C++"
@ -1050,8 +1140,43 @@ recommended to enable `electric-pair-mode' with this mode."
;; Font-lock.
(setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'cpp))
(treesit-major-mode-setup)
(when c-ts-mode-emacs-devel
(setq-local add-log-current-defun-function
#'c-ts-mode--emacs-current-defun-name))))
(treesit-major-mode-setup)))
(easy-menu-define c-ts-mode-menu (list c-ts-mode-map c++-ts-mode-map)
"Menu for `c-ts-mode' and `c++-ts-mode'."
'("C/C++"
["Comment Out Region" comment-region
:enable mark-active
:help "Comment out the region between the mark and point"]
["Uncomment Region" (comment-region (region-beginning)
(region-end) '(4))
:enable mark-active
:help "Uncomment the region between the mark and point"]
["Indent Top-level Expression" c-ts-mode-indent-defun
:help "Indent/reindent top-level function, class, etc."]
["Indent Line or Region" indent-for-tab-command
:help "Indent current line or region, or insert a tab"]
["Forward Expression" forward-sexp
:help "Move forward across one balanced expression"]
["Backward Expression" backward-sexp
:help "Move back across one balanced expression"]
"--"
("Style..."
["Set Indentation Style..." c-ts-mode-set-style
:help "Set C/C++ indentation style for current buffer"]
["Show Current Indentation Style" (message "Indentation Style: %s"
c-ts-mode-indent-style)
:help "Show the name of the C/C++ indentation style for current buffer"]
["Set Comment Style" c-ts-mode-toggle-comment-style
:help "Toglle C/C++ comment style between block and line comments"])
"--"
("Toggle..."
["SubWord Mode" subword-mode
:style toggle :selected subword-mode
:help "Toggle sub-word movement and editing mode"])))
;; We could alternatively use parsers, but if this works well, I don't
;; see the need to change. This is copied verbatim from cc-guess.el.

View file

@ -250,7 +250,11 @@ chosen (interactively or automatically)."
("csharp-ls"))))
(purescript-mode . ("purescript-language-server" "--stdio"))
((perl-mode cperl-mode) . ("perl" "-MPerl::LanguageServer" "-e" "Perl::LanguageServer::run"))
(markdown-mode . ("marksman" "server")))
(markdown-mode
. ,(eglot-alternatives
'(("marksman" "server")
("vscode-markdown-language-server" "--stdio"))))
(graphviz-dot-mode . ("dot-language-server" "--stdio")))
"How the command `eglot' guesses the server to start.
An association list of (MAJOR-MODE . CONTACT) pairs. MAJOR-MODE
identifies the buffers that are to be managed by a specific

View file

@ -1227,7 +1227,10 @@ To continue searching for the next match, use the
command \\[fileloop-continue]."
(interactive "sSearch (regexp): ")
(fileloop-initialize-search
regexp (project-files (project-current t)) 'default)
regexp
;; XXX: See the comment in project-query-replace-regexp.
(cl-delete-if-not #'file-regular-p (project-files (project-current t)))
'default)
(fileloop-continue))
;;;###autoload

View file

@ -1904,13 +1904,13 @@ See `add-log-current-defun-function'."
(progn
(unless (string-equal "self" (car mn)) ; def self.foo
;; def C.foo
(let ((ml (nreverse mlist)))
(let ((ml (reverse mlist)))
;; If the method name references one of the
;; containing modules, drop the more nested ones.
(while ml
(if (string-equal (car ml) (car mn))
(setq mlist (nreverse (cdr ml)) ml nil))
(or (setq ml (cdr ml)) (nreverse mlist))))
(setq ml (cdr ml))))
(if mlist
(setcdr (last mlist) (butlast mn))
(setq mlist (butlast mn))))

View file

@ -1539,13 +1539,7 @@ implementations. Currently there are two: `sh-mode' and
(lambda (terminator)
(if (eq terminator ?')
"'\\'"
"\\")))
;; Parse or insert magic number for exec, and set all variables depending
;; on the shell thus determined.
(sh-set-shell (sh--guess-shell) nil nil)
(add-hook 'flymake-diagnostic-functions #'sh-shellcheck-flymake nil t)
(add-hook 'hack-local-variables-hook
#'sh-after-hack-local-variables nil t))
"\\"))))
;;;###autoload
(define-derived-mode sh-mode sh-base-mode "Shell-script"
@ -1605,7 +1599,13 @@ with your script for an edit-interpret-debug cycle."
nil nil
((?/ . "w") (?~ . "w") (?. . "w") (?- . "w") (?_ . "w")) nil
(font-lock-syntactic-face-function
. ,#'sh-font-lock-syntactic-face-function))))
. ,#'sh-font-lock-syntactic-face-function)))
;; Parse or insert magic number for exec, and set all variables depending
;; on the shell thus determined.
(sh-set-shell (sh--guess-shell) nil nil)
(add-hook 'flymake-diagnostic-functions #'sh-shellcheck-flymake nil t)
(add-hook 'hack-local-variables-hook
#'sh-after-hack-local-variables nil t))
;;;###autoload
(defalias 'shell-script-mode 'sh-mode)
@ -1617,6 +1617,10 @@ This mode automatically falls back to `sh-mode' if the buffer is
not written in Bash or sh."
:syntax-table sh-mode-syntax-table
(when (treesit-ready-p 'bash)
(sh-set-shell "bash" nil nil)
(add-hook 'flymake-diagnostic-functions #'sh-shellcheck-flymake nil t)
(add-hook 'hack-local-variables-hook
#'sh-after-hack-local-variables nil t)
(treesit-parser-create 'bash)
(setq-local treesit-font-lock-feature-list
'(( comment function)

View file

@ -1555,31 +1555,32 @@ EVENT may be an event or an event type. If EVENT is a symbol
that has never been used in an event that has been read as input
in the current Emacs session, then this function may fail to include
the `click' modifier."
(let ((type event))
(if (listp type)
(setq type (car type)))
(if (symbolp type)
;; Don't read event-symbol-elements directly since we're not
;; sure the symbol has already been parsed.
(cdr (internal-event-symbol-parse-modifiers type))
(let ((list nil)
(char (logand type (lognot (logior ?\M-\0 ?\C-\0 ?\S-\0
?\H-\0 ?\s-\0 ?\A-\0)))))
(if (not (zerop (logand type ?\M-\0)))
(push 'meta list))
(if (or (not (zerop (logand type ?\C-\0)))
(< char 32))
(push 'control list))
(if (or (not (zerop (logand type ?\S-\0)))
(/= char (downcase char)))
(push 'shift list))
(or (zerop (logand type ?\H-\0))
(push 'hyper list))
(or (zerop (logand type ?\s-\0))
(push 'super list))
(or (zerop (logand type ?\A-\0))
(push 'alt list))
list))))
(unless (stringp event)
(let ((type event))
(if (listp type)
(setq type (car type)))
(if (symbolp type)
;; Don't read event-symbol-elements directly since we're not
;; sure the symbol has already been parsed.
(cdr (internal-event-symbol-parse-modifiers type))
(let ((list nil)
(char (logand type (lognot (logior ?\M-\0 ?\C-\0 ?\S-\0
?\H-\0 ?\s-\0 ?\A-\0)))))
(if (not (zerop (logand type ?\M-\0)))
(push 'meta list))
(if (or (not (zerop (logand type ?\C-\0)))
(< char 32))
(push 'control list))
(if (or (not (zerop (logand type ?\S-\0)))
(/= char (downcase char)))
(push 'shift list))
(or (zerop (logand type ?\H-\0))
(push 'hyper list))
(or (zerop (logand type ?\s-\0))
(push 'super list))
(or (zerop (logand type ?\A-\0))
(push 'alt list))
list)))))
(defun event-basic-type (event)
"Return the basic type of the given event (all modifiers removed).
@ -1587,17 +1588,18 @@ The value is a printing character (not upper case) or a symbol.
EVENT may be an event or an event type. If EVENT is a symbol
that has never been used in an event that has been read as input
in the current Emacs session, then this function may return nil."
(if (consp event)
(setq event (car event)))
(if (symbolp event)
(car (get event 'event-symbol-elements))
(let* ((base (logand event (1- ?\A-\0)))
(uncontrolled (if (< base 32) (logior base 64) base)))
;; There are some numbers that are invalid characters and
;; cause `downcase' to get an error.
(condition-case ()
(downcase uncontrolled)
(error uncontrolled)))))
(unless (stringp event)
(if (consp event)
(setq event (car event)))
(if (symbolp event)
(car (get event 'event-symbol-elements))
(let* ((base (logand event (1- ?\A-\0)))
(uncontrolled (if (< base 32) (logior base 64) base)))
;; There are some numbers that are invalid characters and
;; cause `downcase' to get an error.
(condition-case ()
(downcase uncontrolled)
(error uncontrolled))))))
(defsubst mouse-movement-p (object)
"Return non-nil if OBJECT is a mouse movement event."
@ -7208,12 +7210,13 @@ CONDITION is either:
(funcall match (list condition))))
(defun match-buffers (condition &optional buffers arg)
"Return a list of buffers that match CONDITION.
See `buffer-match-p' for details on CONDITION. By default all
buffers are checked, this can be restricted by passing an
optional argument BUFFERS, set to a list of buffers to check.
ARG is passed to `buffer-match', for predicate conditions in
CONDITION."
"Return a list of buffers that match CONDITION, or nil if none match.
See `buffer-match-p' for various supported CONDITIONs.
By default all buffers are checked, but the optional
argument BUFFERS can restrict that: its value should be
an explicit list of buffers to check.
Optional argument ARG is passed to `buffer-match-p', for
predicate conditions in CONDITION."
(let (bufs)
(dolist (buf (or buffers (buffer-list)))
(when (buffer-match-p condition (get-buffer buf) arg)

View file

@ -214,12 +214,14 @@ Must be greater than 1."
((file-readable-p "/usr/share/lib/dict/words")
"/usr/share/lib/dict/words")
((file-readable-p "/sys/dict") "/sys/dict"))
"Alternate plain word-list dictionary for spelling help."
"Alternate plain word-list dictionary for spelling help.
This is also used by `ispell-lookup-words' and `ispell-complete-word'."
:type '(choice file (const :tag "None" nil)))
(defcustom ispell-complete-word-dict nil
"Plain word-list dictionary used for word completion if
different from `ispell-alternate-dictionary'."
different from `ispell-alternate-dictionary'.
This is also used by `ispell-lookup-words' and `ispell-complete-word'."
:type '(choice file (const :tag "None" nil)))
(defcustom ispell-message-dictionary-alist nil
@ -2510,7 +2512,9 @@ Otherwise the variable `ispell-grep-command' contains the command
Optional second argument contains the dictionary to use; the default is
`ispell-alternate-dictionary', overridden by `ispell-complete-word-dict'
if defined."
if defined. If none of LOOKUP-DICT, `ispell-alternate-dictionary',
and `ispell-complete-word-dict' name an existing word-list file,
this function signals an error."
;; We don't use the filter for this function, rather the result is written
;; into a buffer. Hence there is no need to save the filter values.
(if (null lookup-dict)
@ -3685,7 +3689,12 @@ If APPEND is non-nil, don't erase previous debugging output."
If optional INTERIOR-FRAG is non-nil, then the word may be a character
sequence inside of a word.
Standard ispell choices are then available."
Standard ispell choices are then available.
This command uses a word-list file specified
by `ispell-alternate-dictionary' or by `ispell-complete-word-dict';
if none of those name an existing word-list file, this command
signals an error."
;; FIXME: completion-at-point-function.
(interactive "P")
(let ((case-fold-search-val case-fold-search)

View file

@ -88,6 +88,7 @@
(declare-function treesit-search-forward "treesit.c")
(declare-function treesit-induce-sparse-tree "treesit.c")
(declare-function treesit-subtree-stat "treesit.c")
(declare-function treesit-node-match-p "treesit.c")
(declare-function treesit-available-p "treesit.c")
@ -245,21 +246,19 @@ is nil, try to guess the language at BEG using `treesit-language-at'."
Specifically, return the highest parent of NODE that has the same
type as it. If no such parent exists, return nil.
If PRED is non-nil, match each parent's type with PRED as a
regexp, rather than using NODE's type. PRED can also be a
function that takes the node as an argument, and return
non-nil/nil for match/no match.
If PRED is non-nil, match each parent's type with PRED rather
than using NODE's type. PRED can also be a predicate function,
and more. See `treesit-thing-settings' for details.
If INCLUDE-NODE is non-nil, return NODE if it satisfies PRED."
(let ((pred (or pred (treesit-node-type node)))
(let ((pred (or pred (rx-to-string
`(bos ,(treesit-node-type node) eos))))
(result nil))
(cl-loop for cursor = (if include-node node
(treesit-node-parent node))
then (treesit-node-parent cursor)
while cursor
if (if (stringp pred)
(string-match-p pred (treesit-node-type cursor))
(funcall pred cursor))
if (treesit-node-match-p cursor pred)
do (setq result cursor))
result))
@ -1887,21 +1886,10 @@ nil.")
"The delimiter used to connect several defun names.
This is used in `treesit-add-log-current-defun'.")
(defsubst treesit--thing-unpack-pattern (pattern)
"Unpack PATTERN in the shape of `treesit-defun-type-regexp'.
Basically,
(unpack REGEXP) = (REGEXP . nil)
(unpack (REGEXP . PRED)) = (REGEXP . PRED)"
(if (consp pattern)
pattern
(cons pattern nil)))
(defun treesit-beginning-of-thing (pattern &optional arg tactic)
(defun treesit-beginning-of-thing (pred &optional arg tactic)
"Like `beginning-of-defun', but generalized into things.
PATTERN is like `treesit-defun-type-regexp', ARG
PRED is like `treesit-defun-type-regexp', ARG
is the same as in `beginning-of-defun'.
TACTIC determines how does this function move between things. It
@ -1916,17 +1904,15 @@ should there be one. If omitted, TACTIC is considered to be
Return non-nil if successfully moved, nil otherwise."
(pcase-let* ((arg (or arg 1))
(`(,regexp . ,pred) (treesit--thing-unpack-pattern
pattern))
(dest (treesit--navigate-thing
(point) (- arg) 'beg regexp pred tactic)))
(point) (- arg) 'beg pred tactic)))
(when dest
(goto-char dest))))
(defun treesit-end-of-thing (pattern &optional arg tactic)
(defun treesit-end-of-thing (pred &optional arg tactic)
"Like `end-of-defun', but generalized into things.
PATTERN is like `treesit-defun-type-regexp', ARG is the same as
PRED is like `treesit-defun-type-regexp', ARG is the same as
in `end-of-defun'.
TACTIC determines how does this function move between things. It
@ -1941,10 +1927,8 @@ should there be one. If omitted, TACTIC is considered to be
Return non-nil if successfully moved, nil otherwise."
(pcase-let* ((arg (or arg 1))
(`(,regexp . ,pred) (treesit--thing-unpack-pattern
pattern))
(dest (treesit--navigate-thing
(point) arg 'end regexp pred tactic)))
(point) arg 'end pred tactic)))
(when dest
(goto-char dest))))
@ -2069,7 +2053,7 @@ the current line if the beginning of the defun is indented."
;; parent:
;; 1. node covers pos
;; 2. smallest such node
(defun treesit--things-around (pos regexp &optional pred)
(defun treesit--things-around (pos pred)
"Return the previous, next, and parent thing around POS.
Return a list of (PREV NEXT PARENT), where PREV and NEXT are
@ -2077,7 +2061,8 @@ previous and next sibling things around POS, and PARENT is the
parent thing surrounding POS. All of three could be nil if no
sound things exists.
REGEXP and PRED are the same as in `treesit-thing-at-point'."
PRED can be a regexp, a predicate function, and more. See
`treesit-thing-settings' for details."
(let* ((node (treesit-node-at pos))
(result (list nil nil nil)))
;; 1. Find previous and next sibling defuns.
@ -2100,9 +2085,7 @@ REGEXP and PRED are the same as in `treesit-thing-at-point'."
when node
do (let ((cursor node)
(iter-pred (lambda (node)
(and (string-match-p
regexp (treesit-node-type node))
(or (null pred) (funcall pred node))
(and (treesit-node-match-p node pred)
(funcall pos-pred node)))))
;; Find the node just before/after POS to start searching.
(save-excursion
@ -2116,13 +2099,11 @@ REGEXP and PRED are the same as in `treesit-thing-at-point'."
(setf (nth idx result)
(treesit-node-top-level cursor iter-pred t))
(setq cursor (treesit-search-forward
cursor regexp backward backward)))))
cursor pred backward backward)))))
;; 2. Find the parent defun.
(let ((cursor (or (nth 0 result) (nth 1 result) node))
(iter-pred (lambda (node)
(and (string-match-p
regexp (treesit-node-type node))
(or (null pred) (funcall pred node))
(and (treesit-node-match-p node pred)
(not (treesit-node-eq node (nth 0 result)))
(not (treesit-node-eq node (nth 1 result)))
(< (treesit-node-start node)
@ -2132,15 +2113,6 @@ REGEXP and PRED are the same as in `treesit-thing-at-point'."
(treesit-parent-until cursor iter-pred)))
result))
(defun treesit--top-level-thing (node regexp &optional pred)
"Return the top-level parent thing of NODE.
REGEXP and PRED are the same as in `treesit-thing-at-point'."
(treesit-node-top-level
node (lambda (node)
(and (string-match-p regexp (treesit-node-type node))
(or (null pred) (funcall pred node))))
t))
;; The basic idea for nested defun navigation is that we first try to
;; move across sibling defuns in the same level, if no more siblings
;; exist, we move to parents's beg/end, rinse and repeat. We never
@ -2168,7 +2140,7 @@ REGEXP and PRED are the same as in `treesit-thing-at-point'."
;; -> Obviously we don't want to go to parent's end, instead, we
;; want to go to parent's prev-sibling's end. Again, we recurse
;; in the function to do that.
(defun treesit--navigate-thing (pos arg side regexp &optional pred tactic recursing)
(defun treesit--navigate-thing (pos arg side pred &optional tactic recursing)
"Navigate thing ARG steps from POS.
If ARG is positive, move forward that many steps, if negative,
@ -2179,7 +2151,8 @@ This function doesn't actually move point, it just returns the
position it would move to. If there aren't enough things to move
across, return nil.
REGEXP and PRED are the same as in `treesit-thing-at-point'.
PRED can be a regexp, a predicate function, and more. See
`treesit-thing-settings' for details.
TACTIC determines how does this function move between things. It
can be `nested', `top-level', `restricted', or nil. `nested'
@ -2208,14 +2181,13 @@ function is called recursively."
(while (> counter 0)
(pcase-let
((`(,prev ,next ,parent)
(treesit--things-around pos regexp pred)))
(treesit--things-around pos pred)))
;; When PARENT is nil, nested and top-level are the same, if
;; there is a PARENT, make PARENT to be the top-level parent
;; and pretend there is no nested PREV and NEXT.
(when (and (eq tactic 'top-level)
parent)
(setq parent (treesit--top-level-thing
parent regexp pred)
(setq parent (treesit-node-top-level parent pred t)
prev nil
next nil))
;; If TACTIC is `restricted', the implementation is very simple.
@ -2247,7 +2219,7 @@ function is called recursively."
;; the end of next before recurring.)
(setq pos (or (treesit--navigate-thing
(treesit-node-end (or next parent))
1 'beg regexp pred tactic t)
1 'beg pred tactic t)
(throw 'term nil)))
;; Normal case.
(setq pos (funcall advance (or next parent))))
@ -2259,7 +2231,7 @@ function is called recursively."
;; Special case: go to prev end-of-defun.
(setq pos (or (treesit--navigate-thing
(treesit-node-start (or prev parent))
-1 'end regexp pred tactic t)
-1 'end pred tactic t)
(throw 'term nil)))
;; Normal case.
(setq pos (funcall advance (or prev parent))))))
@ -2269,21 +2241,17 @@ function is called recursively."
(if (eq counter 0) pos nil)))
;; TODO: In corporate into thing-at-point.
(defun treesit-thing-at-point (pattern tactic)
(defun treesit-thing-at-point (pred tactic)
"Return the thing node at point or nil if none is found.
\"Thing\" is defined by PATTERN, which can be either a string
REGEXP or a cons cell (REGEXP . PRED): if a node's type matches
REGEXP, it is a thing. The \"thing\" could be further restricted
by PRED: if non-nil, PRED should be a function that takes a node
and returns t if the node is a \"thing\", and nil if not.
\"Thing\" is defined by PRED, which can be a regexp, a
predication function, and more, see `treesit-thing-settings'
for details.
Return the top-level defun if TACTIC is `top-level', return the
immediate parent thing if TACTIC is `nested'."
(pcase-let* ((`(,regexp . ,pred)
(treesit--thing-unpack-pattern pattern))
(`(,_ ,next ,parent)
(treesit--things-around (point) regexp pred))
(pcase-let* ((`(,_ ,next ,parent)
(treesit--things-around (point) pred))
;; If point is at the beginning of a thing, we
;; prioritize that thing over the parent in nested
;; mode.
@ -2291,7 +2259,7 @@ immediate parent thing if TACTIC is `nested'."
next)
parent)))
(if (eq tactic 'top-level)
(treesit--top-level-thing node regexp pred)
(treesit-node-top-level node pred t)
node)))
(defun treesit-defun-at-point ()

View file

@ -1594,7 +1594,7 @@ After check-out, runs the normal hook `vc-checkout-hook'."
(vc-call make-version-backups-p file)
(vc-up-to-date-p file)
(vc-make-version-backup file))
(let ((backend (vc-backend file)))
(let ((backend (or (bound-and-true-p vc-dir-backend) (vc-backend file))))
(with-vc-properties (list file)
(condition-case err
(vc-call-backend backend 'checkout file rev)

View file

@ -34,20 +34,20 @@
;;; Customizable variables
(defcustom x-dnd-test-function #'x-dnd-default-test-function
"The function drag and drop uses to determine if to accept or reject a drop.
The function takes three arguments, WINDOW, ACTION and TYPES.
WINDOW is where the mouse is when the function is called. WINDOW
may be a frame if the mouse isn't over a real window (i.e. menu
bar, tool bar or scroll bar). ACTION is the suggested action
from the drag and drop source, one of the symbols move, copy,
link or ask. TYPES is a vector of available types for the drop.
Each element of TYPE should either be a string (containing the
"Function to be used by drag-and-drop to determine whether to accept a drop.
The function takes three arguments: WINDOW, ACTION, and TYPES.
WINDOW is where the window under the mouse is when the function is called.
WINDOW may be a frame if the mouse isn't over a real window (e.g., menu
bar, tool bar, scroll bar, etc.).
ACTION is the suggested action from the drag and drop source, one of the
symbols `move', `copy', `link' or `ask'.
TYPES is a vector of available types for the drop.
Each element of TYPES should either be a string (containing the
name of the type's X atom), or a symbol, whose name will be used.
The function shall return nil to reject the drop or a cons with
two values, the wanted action as car and the wanted type as cdr.
The wanted action can be copy, move, link, ask or private.
two values, the wanted action as `car' and the wanted type as `cdr'.
The wanted action can be `copy', `move', `link', `ask' or `private'.
The default value for this variable is `x-dnd-default-test-function'."
:version "22.1"
@ -70,14 +70,18 @@ The default value for this variable is `x-dnd-default-test-function'."
(,(purecopy "DndTypeFile") . x-dnd-handle-offix-file)
(,(purecopy "DndTypeFiles") . x-dnd-handle-offix-files)
(,(purecopy "DndTypeText") . dnd-insert-text))
"Which function to call to handle a drop of that type.
If the type for the drop is not present, or the function is nil,
the drop is rejected. The function takes three arguments, WINDOW, ACTION
and DATA. WINDOW is where the drop occurred, ACTION is the action for
this drop (copy, move, link, private or ask) as determined by a previous
call to `x-dnd-test-function'. DATA is the drop data.
The function shall return the action used (copy, move, link or private)
if drop is successful, nil if not."
"Functions to call to handle drag-and-drop of known types.
If the type of the drop is not present in the alist, or the
function corresponding to the type is nil, the drop of that
type will be rejected.
Each function takes three arguments: WINDOW, ACTION, and DATA.
WINDOW is the window where the drop occurred.
ACTION is the action for this drop (`copy', `move', `link', `private'
or `ask'), as determined by a previous call to `x-dnd-test-function'.
DATA is the drop data.
The function shall return the action it used (one of the above,
excluding `ask') if drop is successful, nil if not."
:version "22.1"
:type 'alist
:group 'x)
@ -122,22 +126,27 @@ like xterm) for text."
:group 'x)
(defcustom x-dnd-direct-save-function #'x-dnd-save-direct
"Function called when a file is dropped that Emacs must save.
It is called with two arguments: the first is either nil or t,
and the second is a string.
"Function called when a file is dropped via XDS protocol.
The value should be a function of two arguments that supports
the X Direct Save (XDS) protocol. The function will be called
twice during the protocol execution.
If the first argument is t, the second argument is the name the
dropped file should be saved under. The function should return a
complete file name describing where the file should be saved.
When the function is called with the first argument non-nil,
it should return an absolute file name whose base name is
the value of the second argument, a string. The return value
is the file name for the dragged file to be saved. The function
can also return nil if saving the file should be refused for some
reason; in that case the drop will be canceled.
It can also return nil, which means to cancel the drop.
If the first argument is nil, the second is the name of the file
that was dropped."
When the function is called with the first argument nil, the
second argument specifies the file name where the file was saved;
the function should then do whatever is appropriate when such a
file is saved, like show the file in the Dired buffer or visit
the file."
:version "29.1"
:type '(choice (const :tag "Prompt for name before saving"
:type '(choice (const :tag "Prompt for file name to save"
x-dnd-save-direct)
(const :tag "Save and open immediately without prompting"
(const :tag "Save in `default-directory' without prompting"
x-dnd-save-direct-immediately)
(function :tag "Other function"))
:group 'x)
@ -222,14 +231,14 @@ any protocol specific data.")
(cdr (x-dnd-get-state-cons-for-frame frame-or-window)))
(defun x-dnd-default-test-function (_window _action types)
"The default test function for drag and drop.
"The default test function for drag-and-drop.
WINDOW is where the mouse is when this function is called. It
may be a frame if the mouse is over the menu bar, scroll bar or
tool bar. ACTION is the suggested action from the source, and
TYPES are the types the drop data can have. This function only
accepts drops with types in `x-dnd-known-types'. It always
returns the action `private', unless `types' contains a value
inside `x-dnd-copy-types'."
inside `x-dnd-copy-types', in which case it may return `copy'."
(let ((type (x-dnd-choose-type types)))
(when type (let ((list x-dnd-copy-types))
(catch 'out
@ -1564,17 +1573,24 @@ was taken, or the direct save failed."
(when (not (equal file-name original-file-name))
(delete-file file-name)))))
(defun x-dnd-save-direct (need-name name)
"Handle dropping a file that should be saved immediately.
NEED-NAME tells whether or not the file was not yet saved. NAME
is either the name of the file, or the name the drop source wants
us to save under.
(defun x-dnd-save-direct (need-name filename)
"Handle dropping a file FILENAME that should be saved first, asking the user.
NEED-NAME non-nil means the caller requests the full absolute
file name of FILENAME under which to save it; FILENAME is just
the base name in that case. The function then prompts the user
for where to save to file and returns the result to the caller.
Prompt the user for a file name, then open it."
NEED-NAME nil means the file was saved as FILENAME (which should
be the full absolute file name in that case). The function then
refreshes the Dired display, if the current buffer is in Dired
mode, or visits the file otherwise.
This function is intended to be the value of `x-dnd-direct-save-function',
which see."
(if need-name
(let ((file-name (read-file-name "Write file: "
default-directory
nil nil name)))
nil nil filename)))
(when (file-exists-p file-name)
(unless (y-or-n-p (format-message
"File `%s' exists; overwrite? " file-name))
@ -1584,18 +1600,18 @@ Prompt the user for a file name, then open it."
;; interface can be found.
(if (derived-mode-p 'dired-mode)
(revert-buffer)
(find-file name))))
(find-file filename))))
(defun x-dnd-save-direct-immediately (need-name name)
"Save and open a dropped file, like `x-dnd-save-direct'.
NEED-NAME tells whether or not the file was not yet saved. NAME
is either the name of the file, or the name the drop source wants
us to save under.
(defun x-dnd-save-direct-immediately (need-name filename)
"Handle dropping a file FILENAME that should be saved first.
Like `x-dnd-save-direct', but do not prompt for the file name;
instead, return its absolute file name for saving in the current
directory.
Unlike `x-dnd-save-direct', do not prompt for the name by which
to save the file. Simply save it in the current directory."
This function is intended to be the value of `x-dnd-direct-save-function',
which see."
(if need-name
(let ((file-name (expand-file-name name)))
(let ((file-name (expand-file-name filename)))
(when (file-exists-p file-name)
(unless (y-or-n-p (format-message
"File `%s' exists; overwrite? " file-name))
@ -1605,7 +1621,7 @@ to save the file. Simply save it in the current directory."
;; interface can be found.
(if (derived-mode-p 'dired-mode)
(revert-buffer)
(find-file name))))
(find-file filename))))
(defun x-dnd-handle-octet-stream-for-drop (save-to)
"Save the contents of the XDS selection to SAVE-TO.

View file

@ -632,21 +632,35 @@ static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
#define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face) \
do { \
CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face)); \
CGContextSetFillColorWithColor (context, refcol_) ; \
CGColorRelease (refcol_); \
CGColorRef refcol = get_cgcolor (NS_FACE_FOREGROUND (face)); \
CGContextSetFillColorWithColor (context, refcol); \
CGColorRelease (refcol); \
} while (0)
#define CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND(context, face) \
do { \
CGColorRef refcol_ = get_cgcolor (NS_FACE_BACKGROUND (face)); \
CGContextSetFillColorWithColor (context, refcol_); \
CGColorRelease (refcol_); \
CGColorRef refcol = get_cgcolor (NS_FACE_BACKGROUND (face)); \
CGContextSetFillColorWithColor (context, refcol); \
CGColorRelease (refcol); \
} while (0)
#define CG_SET_FILL_COLOR_WITH_FRAME_CURSOR(context, frame) \
do { \
CGColorRef refcol \
= get_cgcolor_from_nscolor (FRAME_CURSOR_COLOR (frame), frame); \
CGContextSetFillColorWithColor (context, refcol); \
CGColorRelease (refcol); \
} while (0)
#define CG_SET_FILL_COLOR_WITH_FRAME_BACKGROUND(context, frame) \
do { \
CGColorRef refcol \
= get_cgcolor_from_nscolor (FRAME_BACKGROUND_COLOR (frame), frame); \
CGContextSetFillColorWithColor (context, refcol); \
CGColorRelease (refcol); \
} while (0)
#define CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND(context, face) \
do { \
CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face)); \
CGContextSetStrokeColorWithColor (context, refcol_); \
CGColorRelease (refcol_); \
CGColorRef refcol = get_cgcolor (NS_FACE_FOREGROUND (face)); \
CGContextSetStrokeColorWithColor (context, refcol); \
CGColorRelease (refcol); \
} while (0)
@ -2933,9 +2947,12 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no
{
if (s->hl == DRAW_CURSOR)
{
CGColorRef colorref = get_cgcolor_from_nscolor (FRAME_CURSOR_COLOR (f), f);
CGContextSetFillColorWithColor (context, colorref);
CGColorRelease (colorref);
if (face && (NS_FACE_BACKGROUND (face)
== [(NSColor *) FRAME_CURSOR_COLOR (f)
unsignedLong]))
CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face);
else
CG_SET_FILL_COLOR_WITH_FRAME_CURSOR (context, f);
}
else
CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face);
@ -2949,9 +2966,12 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no
CGContextScaleCTM (context, 1, -1);
if (s->hl == DRAW_CURSOR)
{
CGColorRef colorref = get_cgcolor_from_nscolor (FRAME_BACKGROUND_COLOR (f), f);
CGContextSetFillColorWithColor (context, colorref);
CGColorRelease (colorref);
if (face && (NS_FACE_BACKGROUND (face)
== [(NSColor *) FRAME_CURSOR_COLOR (f)
unsignedLong]))
CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face);
else
CG_SET_FILL_COLOR_WITH_FRAME_BACKGROUND (context, f);
}
else
CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face);

View file

@ -3750,14 +3750,18 @@ Function modeled after x_draw_glyph_string_box ().
{
struct face *face = s->face;
if (!face->stipple)
{
if (s->hl != DRAW_CURSOR)
[(NS_FACE_BACKGROUND (face) != 0
? [NSColor colorWithUnsignedLong:NS_FACE_BACKGROUND (face)]
: FRAME_BACKGROUND_COLOR (s->f)) set];
else
[FRAME_CURSOR_COLOR (s->f) set];
}
{
if (s->hl != DRAW_CURSOR)
[(NS_FACE_BACKGROUND (face) != 0
? [NSColor colorWithUnsignedLong:NS_FACE_BACKGROUND (face)]
: FRAME_BACKGROUND_COLOR (s->f)) set];
else if (face && (NS_FACE_BACKGROUND (face)
== [(NSColor *) FRAME_CURSOR_COLOR (s->f)
unsignedLong]))
[[NSColor colorWithUnsignedLong:NS_FACE_FOREGROUND (face)] set];
else
[FRAME_CURSOR_COLOR (s->f) set];
}
else
{
struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);

View file

@ -421,10 +421,17 @@ static Lisp_Object Vtreesit_str_match;
static Lisp_Object Vtreesit_str_pred;
/* This is the limit on recursion levels for some tree-sitter
functions. Remember to update docstrings when changing this
value. */
const ptrdiff_t treesit_recursion_limit = 1000;
bool treesit_initialized = false;
functions. Remember to update docstrings when changing this value.
If we think of programs and AST, it is very rare for any program to
have a very deep AST. For example, you would need 1000+ levels of
nested if-statements, or a struct somehow nested for 1000+ levels.
Its hard for me to imagine any hand-written or machine generated
program to be like that. So I think 1000 is already generous. If
we look at xdisp.c, its AST only have 30 levels. */
#define TREESIT_RECURSION_LIMIT 1000
static bool treesit_initialized = false;
static bool
load_tree_sitter_if_necessary (bool required)
@ -478,40 +485,47 @@ treesit_initialize (void)
static void
treesit_symbol_to_c_name (char *symbol_name)
{
for (int idx = 0; idx < strlen (symbol_name); idx++)
size_t len = strlen (symbol_name);
for (int idx = 0; idx < len; idx++)
{
if (symbol_name[idx] == '-')
symbol_name[idx] = '_';
}
}
/* Find the override name for LANGUAGE_SYMBOL in
treesit-load-name-override-list. Set NAME and C_SYMBOL to the
override name, and return true if there exists one, otherwise
return false.
This function may signal if treesit-load-name-override-list is
malformed. */
static bool
treesit_find_override_name (Lisp_Object language_symbol, Lisp_Object *name,
Lisp_Object *c_symbol)
{
Lisp_Object tem;
CHECK_LIST (Vtreesit_load_name_override_list);
Lisp_Object tail = Vtreesit_load_name_override_list;
tem = Vtreesit_load_name_override_list;
FOR_EACH_TAIL (tem)
FOR_EACH_TAIL (tail)
{
Lisp_Object lang = XCAR (XCAR (tem));
Lisp_Object entry = XCAR (tail);
CHECK_LIST (entry);
Lisp_Object lang = XCAR (entry);
CHECK_SYMBOL (lang);
if (EQ (lang, language_symbol))
{
*name = Fnth (make_fixnum (1), XCAR (tem));
*name = Fnth (make_fixnum (1), entry);
CHECK_STRING (*name);
*c_symbol = Fnth (make_fixnum (2), XCAR (tem));
*c_symbol = Fnth (make_fixnum (2), entry);
CHECK_STRING (*c_symbol);
return true;
}
}
CHECK_LIST_END (tem, Vtreesit_load_name_override_list);
CHECK_LIST_END (tail, Vtreesit_load_name_override_list);
return false;
}
@ -1619,6 +1633,9 @@ buffer. */)
TSRange *treesit_ranges = xmalloc (sizeof (TSRange) * len);
struct buffer *buffer = XBUFFER (XTS_PARSER (parser)->buffer);
/* We can use XFUXNUM, XCAR, XCDR freely because we have checked
the input by treesit_check_range_argument. */
for (int idx = 0; !NILP (ranges); idx++, ranges = XCDR (ranges))
{
Lisp_Object range = XCAR (ranges);
@ -1639,9 +1656,6 @@ buffer. */)
}
success = ts_parser_set_included_ranges (XTS_PARSER (parser)->parser,
treesit_ranges, len);
/* Although XFIXNUM could signal, it should be impossible
because we have checked the input by treesit_check_range_argument.
So there is no need for unwind-protect. */
xfree (treesit_ranges);
}
@ -2295,11 +2309,11 @@ See Info node `(elisp)Pattern Matching' for detailed explanation. */)
{
if (BASE_EQ (pattern, QCanchor))
return Vtreesit_str_dot;
if (BASE_EQ (pattern, intern_c_string (":?")))
if (BASE_EQ (pattern, QCquestion))
return Vtreesit_str_question_mark;
if (BASE_EQ (pattern, intern_c_string (":*")))
if (BASE_EQ (pattern, QCstar))
return Vtreesit_str_star;
if (BASE_EQ (pattern, intern_c_string (":+")))
if (BASE_EQ (pattern, QCplus))
return Vtreesit_str_plus;
if (BASE_EQ (pattern, QCequal))
return Vtreesit_str_pound_equal;
@ -3008,7 +3022,7 @@ treesit_cursor_helper (TSTreeCursor *cursor, TSNode node, Lisp_Object parser)
TSNode root = ts_tree_root_node (XTS_PARSER (parser)->tree);
*cursor = ts_tree_cursor_new (root);
bool success = treesit_cursor_helper_1 (cursor, &node, end_pos,
treesit_recursion_limit);
TREESIT_RECURSION_LIMIT);
if (!success)
ts_tree_cursor_delete (cursor);
return success;
@ -3139,17 +3153,80 @@ treesit_traverse_child_helper (TSTreeCursor *cursor,
}
}
/* Assq but doesn't signal. */
static Lisp_Object
safe_assq (Lisp_Object key, Lisp_Object alist)
{
Lisp_Object tail = alist;
FOR_EACH_TAIL_SAFE (tail)
if (CONSP (XCAR (tail)) && EQ (XCAR (XCAR (tail)), key))
return XCAR (tail);
return Qnil;
}
/* Given a symbol THING, and a language symbol LANGUAGE, find the
corresponding predicate definition in treesit-things-settings.
Don't check for the type of THING and LANGUAGE.
If there isn't one, return Qnil. */
static Lisp_Object
treesit_traverse_get_predicate (Lisp_Object thing, Lisp_Object language)
{
Lisp_Object cons = safe_assq (language, Vtreesit_thing_settings);
if (NILP (cons))
return Qnil;
Lisp_Object definitions = XCDR (cons);
Lisp_Object entry = safe_assq (thing, definitions);
if (NILP (entry))
return Qnil;
/* ENTRY looks like (THING PRED). */
Lisp_Object cdr = XCDR (entry);
if (!CONSP (cdr))
return Qnil;
return XCAR (cdr);
}
/* Validate the PRED passed to treesit_traverse_match_predicate. If
there's an error, set SIGNAL_DATA to something signal accepts, and
return false, otherwise return true. */
return false, otherwise return true. This function also check for
recusion levels: we place a arbitrary 100 level limit on recursive
predicates. RECURSION_LEVEL is the current recursion level (that
starts at 0), if it goes over 99, return false and set
SIGNAL_DATA. LANGUAGE is a LANGUAGE symbol. */
static bool
treesit_traverse_validate_predicate (Lisp_Object pred,
Lisp_Object *signal_data)
Lisp_Object language,
Lisp_Object *signal_data,
ptrdiff_t recursion_level)
{
if (recursion_level > 99)
{
*signal_data = list1 (build_string ("Predicate recursion level "
"exceeded: it must not exceed "
"100 levels"));
return false;
}
if (STRINGP (pred))
return true;
else if (FUNCTIONP (pred))
return true;
else if (SYMBOLP (pred))
{
Lisp_Object definition = treesit_traverse_get_predicate (pred,
language);
if (NILP (definition))
{
*signal_data = list2 (build_string ("Cannot find the definition "
"of the predicate in "
"`treesit-things-settings'"),
pred);
return false;
}
return treesit_traverse_validate_predicate (definition,
language,
signal_data,
recursion_level + 1);
}
else if (CONSP (pred))
{
Lisp_Object car = XCAR (pred);
@ -3172,7 +3249,9 @@ treesit_traverse_validate_predicate (Lisp_Object pred,
return false;
}
return treesit_traverse_validate_predicate (XCAR (cdr),
signal_data);
language,
signal_data,
recursion_level + 1);
}
else if (BASE_EQ (car, Qor))
{
@ -3187,7 +3266,9 @@ treesit_traverse_validate_predicate (Lisp_Object pred,
FOR_EACH_TAIL (cdr)
{
if (!treesit_traverse_validate_predicate (XCAR (cdr),
signal_data))
language,
signal_data,
recursion_level + 1))
return false;
}
return true;
@ -3195,8 +3276,7 @@ treesit_traverse_validate_predicate (Lisp_Object pred,
else if (STRINGP (car) && FUNCTIONP (cdr))
return true;
}
*signal_data = list2 (build_string ("Invalid predicate, see TODO for "
"valid forms of predicate"),
*signal_data = list2 (build_string ("Invalid predicate, see `treesit-thing-settings' for valid forms of predicate"),
pred);
return false;
}
@ -3232,6 +3312,14 @@ treesit_traverse_match_predicate (TSTreeCursor *cursor, Lisp_Object pred,
Lisp_Object lisp_node = make_treesit_node (parser, node);
return !NILP (CALLN (Ffuncall, pred, lisp_node));
}
else if (SYMBOLP (pred))
{
Lisp_Object language = XTS_PARSER (parser)->language_symbol;
Lisp_Object definition = treesit_traverse_get_predicate (pred,
language);
return treesit_traverse_match_predicate (cursor, definition,
parser, named);
}
else if (CONSP (pred))
{
Lisp_Object car = XCAR (pred);
@ -3268,10 +3356,11 @@ treesit_traverse_match_predicate (TSTreeCursor *cursor, Lisp_Object pred,
return false;
}
/* Traverse the parse tree starting from CURSOR. See TODO for the
shapes PRED can have. If the node satisfies PRED, leave CURSOR on
that node and return true. If no node satisfies PRED, move CURSOR
back to starting position and return false.
/* Traverse the parse tree starting from CURSOR. See
`treesit-thing-settings' for the shapes PRED can have. If the
node satisfies PRED, leave CURSOR on that node and return true. If
no node satisfies PRED, move CURSOR back to starting position and
return false.
LIMIT is the number of levels we descend in the tree. FORWARD
controls the direction in which we traverse the tree, true means
@ -3384,13 +3473,9 @@ Return the first matched node, or nil if none matches. */)
CHECK_SYMBOL (all);
CHECK_SYMBOL (backward);
Lisp_Object signal_data = Qnil;
if (!treesit_traverse_validate_predicate (predicate, &signal_data))
xsignal1 (Qtreesit_invalid_predicate, signal_data);
/* We use a default limit of 1000. See bug#59426 for the
discussion. */
ptrdiff_t the_limit = treesit_recursion_limit;
ptrdiff_t the_limit = TREESIT_RECURSION_LIMIT;
if (!NILP (depth))
{
CHECK_FIXNUM (depth);
@ -3400,6 +3485,13 @@ Return the first matched node, or nil if none matches. */)
treesit_initialize ();
Lisp_Object parser = XTS_NODE (node)->parser;
Lisp_Object language = XTS_PARSER (parser)->language_symbol;
Lisp_Object signal_data = Qnil;
if (!treesit_traverse_validate_predicate (predicate, language,
&signal_data, 0))
xsignal1 (Qtreesit_invalid_predicate, signal_data);
Lisp_Object return_value = Qnil;
TSTreeCursor cursor;
if (!treesit_cursor_helper (&cursor, XTS_NODE (node)->node, parser))
@ -3455,13 +3547,16 @@ always traverse leaf nodes first, then upwards. */)
CHECK_SYMBOL (all);
CHECK_SYMBOL (backward);
Lisp_Object signal_data = Qnil;
if (!treesit_traverse_validate_predicate (predicate, &signal_data))
xsignal1 (Qtreesit_invalid_predicate, signal_data);
treesit_initialize ();
Lisp_Object parser = XTS_NODE (start)->parser;
Lisp_Object language = XTS_PARSER (parser)->language_symbol;
Lisp_Object signal_data = Qnil;
if (!treesit_traverse_validate_predicate (predicate, language,
&signal_data, 0))
xsignal1 (Qtreesit_invalid_predicate, signal_data);
Lisp_Object return_value = Qnil;
TSTreeCursor cursor;
if (!treesit_cursor_helper (&cursor, XTS_NODE (start)->node, parser))
@ -3572,16 +3667,12 @@ a regexp. */)
{
CHECK_TS_NODE (root);
Lisp_Object signal_data = Qnil;
if (!treesit_traverse_validate_predicate (predicate, &signal_data))
xsignal1 (Qtreesit_invalid_predicate, signal_data);
if (!NILP (process_fn))
CHECK_TYPE (FUNCTIONP (process_fn), Qfunctionp, process_fn);
/* We use a default limit of 1000. See bug#59426 for the
discussion. */
ptrdiff_t the_limit = treesit_recursion_limit;
ptrdiff_t the_limit = TREESIT_RECURSION_LIMIT;
if (!NILP (depth))
{
CHECK_FIXNUM (depth);
@ -3591,6 +3682,13 @@ a regexp. */)
treesit_initialize ();
Lisp_Object parser = XTS_NODE (root)->parser;
Lisp_Object language = XTS_PARSER (parser)->language_symbol;
Lisp_Object signal_data = Qnil;
if (!treesit_traverse_validate_predicate (predicate, language,
&signal_data, 0))
xsignal1 (Qtreesit_invalid_predicate, signal_data);
Lisp_Object parent = Fcons (Qnil, Qnil);
/* In this function we never traverse above NODE, so we don't need
to use treesit_cursor_helper. */
@ -3612,6 +3710,40 @@ a regexp. */)
return parent;
}
DEFUN ("treesit-node-match-p",
Ftreesit_node_match_p,
Streesit_node_match_p, 2, 2, 0,
doc: /* Check whether NODE matches PREDICATE.
PREDICATE can be a regexp matching node type, a predicate function,
and more, see `treesit-things-definition' for detail. Return non-nil
if NODE matches PRED, nil otherwise. */)
(Lisp_Object node, Lisp_Object predicate)
{
CHECK_TS_NODE (node);
Lisp_Object parser = XTS_NODE (node)->parser;
Lisp_Object language = XTS_PARSER (parser)->language_symbol;
Lisp_Object signal_data = Qnil;
if (!treesit_traverse_validate_predicate (predicate, language,
&signal_data, 0))
xsignal1 (Qtreesit_invalid_predicate, signal_data);
TSTreeCursor cursor = ts_tree_cursor_new (XTS_NODE (node)->node);
specpdl_ref count = SPECPDL_INDEX ();
record_unwind_protect_ptr (treesit_traverse_cleanup_cursor, &cursor);
bool match = false;
match = treesit_traverse_match_predicate (&cursor, predicate,
parser, false);
unbind_to (count, Qnil);
return match ? Qt : Qnil;
}
DEFUN ("treesit-subtree-stat",
Ftreesit_subtree_stat,
Streesit_subtree_stat, 1, 1, 0,
@ -3709,6 +3841,9 @@ syms_of_treesit (void)
DEFSYM (Qnot, "not");
DEFSYM (QCanchor, ":anchor");
DEFSYM (QCquestion, ":?");
DEFSYM (QCstar, ":*");
DEFSYM (QCplus, ":+");
DEFSYM (QCequal, ":equal");
DEFSYM (QCmatch, ":match");
DEFSYM (QCpred, ":pred");
@ -3760,7 +3895,8 @@ syms_of_treesit (void)
"This parser is deleted and cannot be used",
Qtreesit_error);
define_error (Qtreesit_invalid_predicate,
"Invalid predicate, see TODO for valid forms for a predicate",
"Invalid predicate, see `treesit-thing-settings' "
"for valid forms for a predicate",
Qtreesit_error);
DEFVAR_LISP ("treesit-load-name-override-list",
@ -3792,6 +3928,33 @@ then in the `tree-sitter' subdirectory of `user-emacs-directory', and
then in the system default locations for dynamic libraries, in that order. */);
Vtreesit_extra_load_path = Qnil;
DEFVAR_LISP ("treesit-thing-settings",
Vtreesit_thing_settings,
doc:
/* A list defining things.
The value should be an alist of (LANGUAGE . DEFINITIONS), where
LANGUAGE is a language symbol, and DEFINITIONS is a list of
(THING PRED)
THING is a symbol representing the thing, like `defun', `sexp', or
`block'; PRED defines what kind of node can be qualified as THING.
PRED can be a regexp string that matches the type of the node; it can
be a predicate function that takes the node as the sole argument and
returns t if the node is the thing; it can be a cons (REGEXP . FN),
which is a combination of a regexp and a predicate function, and the
node has to match both to qualify as the thing.
PRED can also be recursively defined. It can be (or PRED...), meaning
satisfying anyone of the inner PREDs qualifies the node; or (not
PRED), meaning not satisfying the inner PRED qualifies the node.
Finally, PRED can refer to other THINGs defined in this list by using
the symbol of that THING. For example, (or block sexp). */);
Vtreesit_thing_settings = Qnil;
staticpro (&Vtreesit_str_libtree_sitter);
Vtreesit_str_libtree_sitter = build_pure_c_string ("libtree-sitter-");
staticpro (&Vtreesit_str_tree_sitter);
@ -3879,6 +4042,7 @@ then in the system default locations for dynamic libraries, in that order. */);
defsubr (&Streesit_search_subtree);
defsubr (&Streesit_search_forward);
defsubr (&Streesit_induce_sparse_tree);
defsubr (&Streesit_node_match_p);
defsubr (&Streesit_subtree_stat);
#endif /* HAVE_TREE_SITTER */
defsubr (&Streesit_available_p);

View file

@ -543,7 +543,14 @@ typedef LANGID (WINAPI *GetUserDefaultUILanguage_Proc) (void);
typedef COORD (WINAPI *GetConsoleFontSize_Proc) (HANDLE, DWORD);
#if _WIN32_WINNT < 0x0501
/* Old versions of mingw.org's MinGW, before v5.2.0, don't have a
_WIN32_WINNT guard for CONSOLE_FONT_INFO in wincon.h, and so don't
need the conditional definition below, which causes compilation
errors. Note: MinGW64 sets _WIN32_WINNT to a higher version, and
its w32api.h version stays fixed at 3.14. */
#if _WIN32_WINNT < 0x0501 \
&& (__W32API_MAJOR_VERSION > 5 \
|| (__W32API_MAJOR_VERSION == 5 && __W32API_MINOR_VERSION >= 2))
typedef struct
{
DWORD nFont;

View file

@ -24,7 +24,8 @@
(require 'wallpaper)
(ert-deftest wallpaper--find-setter ()
(skip-unless (executable-find "touch"))
(skip-unless (and (executable-find "touch")
(wallpaper--use-default-set-function-p)))
(let (wallpaper--current-setter
(wallpaper--default-setters
(wallpaper--default-methods-create
@ -32,7 +33,8 @@
(should (wallpaper--find-setter))))
(ert-deftest wallpaper--find-setter/call-predicate ()
(skip-unless (executable-find "touch"))
(skip-unless (and (executable-find "touch")
(wallpaper--use-default-set-function-p)))
(let* ( wallpaper--current-setter called
(wallpaper--default-setters
(wallpaper--default-methods-create
@ -43,7 +45,8 @@
(should called)))
(ert-deftest wallpaper--find-setter/set-current-setter ()
(skip-unless (executable-find "touch"))
(skip-unless (and (executable-find "touch")
(wallpaper--use-default-set-function-p)))
(let (wallpaper--current-setter
(wallpaper--default-setters
(wallpaper--default-methods-create
@ -52,7 +55,8 @@
(should wallpaper--current-setter)))
(ert-deftest wallpaper-set/runs-command ()
(skip-unless (executable-find "touch"))
(skip-unless (and (executable-find "touch")
(wallpaper--use-default-set-function-p)))
(ert-with-temp-file fil-jpg
:suffix ".jpg"
(ert-with-temp-file fil
@ -70,7 +74,8 @@
(should (file-exists-p fil)))))))
(ert-deftest wallpaper-set/runs-command/detach ()
(skip-unless (executable-find "touch"))
(skip-unless (and (executable-find "touch")
(wallpaper--use-default-set-function-p)))
(ert-with-temp-file fil-jpg
:suffix ".jpg"
(ert-with-temp-file fil
@ -89,7 +94,8 @@
(should (file-exists-p fil))))))
(ert-deftest wallpaper-set/calls-init-action ()
(skip-unless (executable-find "touch"))
(skip-unless (and (executable-find "touch")
(wallpaper--use-default-set-function-p)))
(ert-with-temp-file fil-jpg
:suffix ".jpg"
(ert-with-temp-file fil
@ -108,7 +114,8 @@
(should called)))))
(ert-deftest wallpaper-set/calls-wallpaper-set-function ()
(skip-unless (executable-find "touch"))
(skip-unless (and (executable-find "touch")
(wallpaper--use-default-set-function-p)))
(ert-with-temp-file fil-jpg
:suffix ".jpg"
(let* ( wallpaper--current-setter called
@ -122,12 +129,16 @@
(should (equal called fil-jpg)))))
(ert-deftest wallpaper--find-command/return-string ()
(should (or (not (wallpaper--find-command))
(stringp (wallpaper--find-command)))))
(let ((cmd (wallpaper--find-command)))
(should (or (not cmd)
(stringp cmd)))))
(ert-deftest wallpaper--find-command-args/return-list ()
(should (or (not (wallpaper--find-command-args))
(listp (wallpaper--find-command-args)))))
(let ((cmdargs (wallpaper--find-command-args)))
(if (functionp cmdargs)
(setq cmdargs (funcall cmdargs)))
(should (or (not cmdargs)
(listp cmdargs)))))
(ert-deftest wallpaper--image-file-regexp/return-string ()
(should (stringp (wallpaper--image-file-regexp))))

View file

@ -464,3 +464,17 @@ main (void)
|
}
=-=-=
Name: Empty Line (Block Start)
=-=
int
main (void)
{
|
=-=
int
main (void)
{
|
=-=-=

View file

@ -804,6 +804,7 @@ int main() {
(ert-deftest eglot-test-json-basic ()
"Test basic autocompletion in vscode-json-languageserver."
(skip-unless (executable-find "vscode-json-languageserver"))
(skip-unless (fboundp 'yas-minor-mode))
(eglot--with-fixture
'(("project" .
(("p.json" . "{\"foo.b")

View file

@ -567,6 +567,22 @@ VALUES-PLIST is a list with alternating index and value elements."
(search-backward "_")
(should (string= (ruby-add-log-current-method) "C::D#foo"))))
(ert-deftest ruby-add-log-current-method-singleton-referencing-outer ()
(ruby-with-temp-buffer (ruby-test-string
"module M
| module N
| module C
| class D
| def C.foo
| _
| end
| end
| end
| end
|end")
(search-backward "_")
(should (string= (ruby-add-log-current-method) "M::N::C.foo"))))
(ert-deftest ruby-add-log-current-method-after-inner-class ()
(ruby-with-temp-buffer (ruby-test-string
"module M

View file

@ -916,8 +916,6 @@ and \"]\"."
collect
(cl-loop for pos in record
collect (alist-get pos marker-alist))))
(`(,regexp . ,pred) (treesit--thing-unpack-pattern
treesit-defun-type-regexp))
;; Collect positions each function returns.
(positions
(treesit--ert-collect-positions
@ -929,7 +927,7 @@ and \"]\"."
(if-let ((pos (funcall
#'treesit--navigate-thing
(point) (car conf) (cdr conf)
regexp pred tactic)))
treesit-defun-type-regexp tactic)))
(save-excursion
(goto-char pos)
(funcall treesit-defun-skipper)