summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Mackenzie <acm@muc.de>2022-01-14 19:28:07 +0000
committerAlan Mackenzie <acm@muc.de>2022-01-14 19:28:07 +0000
commitd87a34597c9f0be967f75ff8cfd0ace4392da63f (patch)
treec9474eb0156af143ce61a0c5bcec659546b56300
parent57b698f15913385aec7bc9745016b961c0aa5c55 (diff)
parentd29291d665e808307126bf52c3e748fef78f0f9c (diff)
downloademacs-d87a34597c9f0be967f75ff8cfd0ace4392da63f.tar.gz
Merge branch 'master' into scratch/correct-warning-pos
Merge branch: commit d29291d665e808307126bf52c3e748fef78f0f9c (HEAD -> master, origin/master, origin/HEAD) Author: Stefan Monnier <monnier@iro.umontreal.ca> Date: Fri Jan 14 12:26:30 2022 -0500 (macroexp--expand-all): Fix bug#53227 and bug#46636
-rw-r--r--INSTALL27
-rw-r--r--Makefile.in3
-rw-r--r--admin/grammars/Makefile.in4
-rw-r--r--admin/unidata/Makefile.in3
-rw-r--r--doc/emacs/frames.texi10
-rw-r--r--doc/emacs/maintaining.texi27
-rw-r--r--doc/emacs/search.texi25
-rw-r--r--doc/lispref/functions.texi16
-rw-r--r--doc/lispref/modes.texi3
-rw-r--r--doc/lispref/windows.texi7
-rw-r--r--doc/misc/Makefile.in4
-rw-r--r--doc/misc/eshell.texi120
-rw-r--r--doc/misc/gnus.texi3
-rw-r--r--doc/misc/tramp.texi4
-rw-r--r--etc/NEWS40
-rw-r--r--leim/Makefile.in5
-rw-r--r--lib-src/Makefile.in3
-rw-r--r--lisp/Makefile.in5
-rw-r--r--lisp/auth-source.el2
-rw-r--r--lisp/battery.el2
-rw-r--r--lisp/cedet/ede/project-am.el3
-rw-r--r--lisp/emacs-lisp/easy-mmode.el6
-rw-r--r--lisp/emacs-lisp/ert.el17
-rw-r--r--lisp/emacs-lisp/inline.el2
-rw-r--r--lisp/emacs-lisp/macroexp.el8
-rw-r--r--lisp/emacs-lisp/shortdoc.el3
-rw-r--r--lisp/eshell/esh-opt.el90
-rw-r--r--lisp/ffap.el11
-rw-r--r--lisp/files.el14
-rw-r--r--lisp/frame.el75
-rw-r--r--lisp/gnus/gnus-art.el6
-rw-r--r--lisp/gnus/gnus-registry.el25
-rw-r--r--lisp/gnus/nnimap.el2
-rw-r--r--lisp/gnus/nntp.el8
-rw-r--r--lisp/help-fns.el6
-rw-r--r--lisp/hi-lock.el20
-rw-r--r--lisp/image-dired.el4
-rw-r--r--lisp/isearch.el21
-rw-r--r--lisp/jsonrpc.el6
-rw-r--r--lisp/ldefs-boot.el203
-rw-r--r--lisp/leim/quail/emoji.el2003
-rw-r--r--lisp/man.el24
-rw-r--r--lisp/menu-bar.el10
-rw-r--r--lisp/mouse.el33
-rw-r--r--lisp/net/mailcap.el7
-rw-r--r--lisp/net/tramp-crypt.el2
-rw-r--r--lisp/progmodes/gud.el8
-rw-r--r--lisp/progmodes/python.el12
-rw-r--r--lisp/progmodes/xref.el33
-rw-r--r--lisp/subr.el24
-rw-r--r--lisp/vc/pcvs-info.el8
-rw-r--r--src/buffer.c2
-rw-r--r--src/data.c16
-rw-r--r--src/font.c43
-rw-r--r--src/frame.c5
-rw-r--r--src/ftfont.c21
-rw-r--r--src/gtkutil.c11
-rw-r--r--src/haiku_draw_support.cc2
-rw-r--r--src/haiku_support.cc30
-rw-r--r--src/haikuterm.c7
-rw-r--r--src/window.c3
-rw-r--r--src/xdisp.c14
-rw-r--r--src/xfns.c4
-rw-r--r--src/xterm.c157
-rw-r--r--src/xwidget.c4
-rw-r--r--test/Makefile.in8
-rw-r--r--test/lisp/emacs-lisp/edebug-tests.el10
-rw-r--r--test/lisp/emacs-lisp/ert-tests.el3
-rw-r--r--test/lisp/eshell/esh-opt-tests.el151
-rw-r--r--test/lisp/ffap-tests.el17
-rw-r--r--test/lisp/help-fns-tests.el9
-rw-r--r--test/lisp/so-long-tests/spelling-tests.el16
-rw-r--r--test/lisp/subr-tests.el17
73 files changed, 3247 insertions, 310 deletions
diff --git a/INSTALL b/INSTALL
index 02d5a09d63c..7cb7e0526a2 100644
--- a/INSTALL
+++ b/INSTALL
@@ -226,6 +226,33 @@ e.g. 'emacs25'). On Red Hat-based systems, the corresponding command is
On FreeBSD, the command is 'pkg install -y `pkg rquery %dn emacs-devel`'.
+* Alternative window systems
+
+If you want to use Emacs on one of the alternative window systems
+available on GNU/Linux and some Unix systems, such as Wayland or
+Broadway, you can build the PGTK ("Pure GTK") port of Emacs, which
+utilizes the GTK+ toolkit to support those window systems. To this
+end, invoke the configure script with the '--with-pgtk' option, like
+this:
+
+ ./configure --with-pgtk
+
+This build is only supported with GTK+ version 3, and it is an error
+to specify any other X-specific configuration option when PGTK is
+enabled.
+
+With the PGTK build, you will be able to switch between running Emacs
+on X, Wayland and Broadway using the 'GDK_BACKEND' environment
+variable. GTK+ should automatically detect and use the correct value
+for your system, but you can also specify it manually. For example,
+to force GTK+ to run under Broadway, start Emacs like this:
+
+ GDK_BACKEND=broadway emacs ...
+
+(where '...' denotes any further options you may want to pass to Emacs).
+
+The GNUstep build also supports the Wayland window system. If that is
+what you want, see nextstep/INSTALL.
DETAILED BUILDING AND INSTALLATION:
diff --git a/Makefile.in b/Makefile.in
index b72127dde67..8ac6f527469 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -319,6 +319,9 @@ GLIB_COMPILE_SCHEMAS = glib-compile-schemas
# Program name transformation.
TRANSFORM = @program_transform_name@
+# Prevent any settings in the user environment causing problems.
+unexport EMACSDATA EMACSDOC EMACSLOADPATH EMACSPATH
+
# What emacs should be called when installed.
EMACS_NAME = `echo emacs | sed '$(TRANSFORM)'`
EMACS = ${EMACS_NAME}${EXEEXT}
diff --git a/admin/grammars/Makefile.in b/admin/grammars/Makefile.in
index 83ac2ef46ef..6f699430895 100644
--- a/admin/grammars/Makefile.in
+++ b/admin/grammars/Makefile.in
@@ -31,10 +31,10 @@ top_builddir = @top_builddir@
-include ${top_builddir}/src/verbose.mk
# Prevent any settings in the user environment causing problems.
-unexport EMACSDATA EMACSDOC EMACSPATH
+unexport EMACSDATA EMACSDOC EMACSLOADPATH EMACSPATH
EMACS = ${top_builddir}/src/emacs
-emacs = EMACSLOADPATH= "${EMACS}" -batch --no-site-file --no-site-lisp --eval '(setq load-prefer-newer t)'
+emacs = "${EMACS}" -batch --no-site-file --no-site-lisp --eval '(setq load-prefer-newer t)'
make_bovine = ${emacs} -l semantic/bovine/grammar -f bovine-batch-make-parser
make_wisent = ${emacs} -l semantic/wisent/grammar -f wisent-batch-make-parser
diff --git a/admin/unidata/Makefile.in b/admin/unidata/Makefile.in
index 45bba85213b..e75010dc2b8 100644
--- a/admin/unidata/Makefile.in
+++ b/admin/unidata/Makefile.in
@@ -29,6 +29,9 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
+# Prevent any settings in the user environment causing problems.
+unexport EMACSDATA EMACSDOC EMACSLOADPATH EMACSPATH
+
EMACS = ${top_builddir}/src/emacs
unidir = ${top_srcdir}/lisp/international
emacs = "${EMACS}" -batch --no-site-file --no-site-lisp
diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
index ce43408101d..c641b8ccb14 100644
--- a/doc/emacs/frames.texi
+++ b/doc/emacs/frames.texi
@@ -512,6 +512,16 @@ frames by specifying @dfn{frame parameters}. @xref{Frame Parameters}.
Delete the selected frame (@code{delete-frame}). This signals an
error if there is only one frame.
+@item C-x 5 u
+@kindex C-x 5 u
+@findex undelete-frame
+@findex undelete-frame-mode
+When @code{undelete-frame-mode} is enabled, undelete one of the 16
+most recently deleted frames. Without a prefix argument, undelete the
+most recently deleted frame. With a numerical prefix argument between
+1 and 16, where 1 is the most recently deleted frame, undelete the
+corresponding deleted frame.
+
@item C-z
@kindex C-z @r{(X windows)}
Minimize (or iconify) the selected Emacs frame
diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi
index 9a23f23e0ed..edcc6075f75 100644
--- a/doc/emacs/maintaining.texi
+++ b/doc/emacs/maintaining.texi
@@ -2317,10 +2317,15 @@ them.
@item M-?
Find all the references for the identifier at point.
-@item M-x xref-query-replace-in-results @key{RET} @var{regexp} @key{RET} @var{replacement} @key{RET}
+@item M-x xref-query-replace-in-results @key{RET} @var{replacement} @key{RET}
+@itemx C-u M-x xref-query-replace-in-results @key{RET} @var{regexp} @key{RET} @var{replacement} @key{RET}
Interactively replace @var{regexp} with @var{replacement} in the names
of all the identifiers shown in the @file{*xref*} buffer.
+@item M-x xref-find-references-and-replace @key{RET} @var{from} @key{RET} @var{to} @key{RET}
+Interactively rename all instances of the identifier @var{from} to the
+new name @var{to}.
+
@item M-x tags-search @key{RET} @var{regexp} @key{RET}
Search for @var{regexp} through the files in the selected tags
table.
@@ -2358,13 +2363,21 @@ shown. The default value is @code{nil}, which just shows the results
in the @file{*xref*} buffer, but doesn't select any of them.
@findex xref-query-replace-in-results
- @kbd{M-x xref-query-replace-in-results} reads a regexp to match identifier
-names and a replacement string, just like ordinary @kbd{M-x
-query-replace-regexp}. It then performs the specified replacement in
-the names of the matching identifiers in all the places in all the
-files where these identifiers are referenced. This is useful when you
+ @kbd{M-x xref-query-replace-in-results} reads a @var{replacement}
+string, just like ordinary @kbd{M-x query-replace-regexp}. It then
+renames the identifiers shown in the @file{*xref*} buffer in all the
+places in all the files where these identifiers are referenced, such
+that their new name is @var{replacement}. This is useful when you
rename your identifiers as part of refactoring. This command should
-be invoked in the @file{*xref*} buffer generated by @kbd{M-?}.
+be invoked in the @file{*xref*} buffer generated by @kbd{M-?}. With a
+prefix argument, the command also prompts for a regexp to match
+identifier names, and renames that regexp in the names of the matching
+identifiers with @var{replacement}.
+
+@findex xref-find-references-and-replace
+ @kbd{M-x xref-find-references-and-replace} works similarly to
+@code{xref-query-replace-in-results}, but is more convenient when you
+want to rename a single identifier specified by its name @var{from}.
@findex tags-search
@kbd{M-x tags-search} reads a regexp using the minibuffer, then
diff --git a/doc/emacs/search.texi b/doc/emacs/search.texi
index c12992c239a..fa1b0eee7c3 100644
--- a/doc/emacs/search.texi
+++ b/doc/emacs/search.texi
@@ -436,14 +436,6 @@ incremental search adds the @samp{control-S} character to the search
string.
@item
-@findex isearch-char-by-name
-@kindex C-x 8 RET @r{(Incremental Search)}
-Type @kbd{C-x 8 @key{RET}} (@code{isearch-char-by-name}), followed by
-a Unicode name or code-point in hex. This adds the specified
-character into the search string, similar to the usual
-@code{insert-char} command (@pxref{Inserting Text}).
-
-@item
@kindex C-^ @r{(Incremental Search)}
@findex isearch-toggle-input-method
@findex isearch-toggle-specified-input-method
@@ -473,6 +465,23 @@ character to the search string using an input method, and
automatically disable the input method afterwards.
@end itemize
+@findex isearch-char-by-name
+@kindex C-x 8 RET @r{(Incremental Search)}
+Type @kbd{C-x 8 @key{RET}} (@code{isearch-char-by-name}), followed by
+a Unicode name or code-point in hex. This adds the specified
+character into the search string, similar to the usual
+@code{insert-char} command (@pxref{Inserting Text}).
+
+@findex isearch-emoji-by-name
+@kindex C-x 8 e RET @r{(Incremental Search)}
+ You can also include Emoji sequences in the search string. Type
+@w{@kbd{C-x 8 e @key{RET}}} (@code{isearch-emoji-by-name}), followed
+by the Unicode name of an Emoji (for example, @kbd{smiling face} or
+@kbd{heart with arrow}). This adds the specified Emoji to the search
+string. If you don't know the name of the Emoji you want to search
+for, you can use @kbd{C-x 8 e l} (@code{emoji-list}) and @kbd{C-x 8 e
+d} (@code{emoji-describe}) (@pxref{Input Methods}).
+
@kindex M-s o @r{(Incremental Search)}
@findex isearch-occur
Typing @kbd{M-s o} in incremental search invokes
diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi
index 96fecc8c892..2378e9efd7e 100644
--- a/doc/lispref/functions.texi
+++ b/doc/lispref/functions.texi
@@ -669,6 +669,22 @@ purposes, it is better to use @code{fset}, which does not keep such
records. @xref{Function Cells}.
@end defun
+@defun function-alias-p object &optional noerror
+Checks whether @var{object} is a function alias. If it is, it returns
+a list of symbols representing the function alias chain, else
+@code{nil}. For instance, if @code{a} is an alias for @code{b}, and
+@code{b} is an alias for @code{c}:
+
+@example
+(function-alias-p 'a)
+ @result{} (b c)
+@end example
+
+If there's a loop in the definitions, an error will be signalled. If
+@var{noerror} is non-@code{nil}, the non-looping parts of the chain is
+returned instead.
+@end defun
+
You cannot create a new primitive function with @code{defun} or
@code{defalias}, but you can use them to change the function definition of
any symbol, even one such as @code{car} or @code{x-popup-menu} whose
diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi
index 5fc831536e8..e2b39836e66 100644
--- a/doc/lispref/modes.texi
+++ b/doc/lispref/modes.texi
@@ -762,6 +762,9 @@ uncompression packages: an entry of the form @code{("\\.gz\\'"
@var{function} t)} can uncompress the file and then put the uncompressed
file in the proper mode according to the name sans @samp{.gz}.
+If @code{auto-mode-alist} has more than one element whose @var{regexp}
+matches the file name, Emacs will use the first match.
+
Here is an example of how to prepend several pattern pairs to
@code{auto-mode-alist}. (You might use this sort of expression in your
init file.)
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 56b4bc5183e..bbf8988e5c4 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -5281,13 +5281,6 @@ other window is selected. When it is non-@code{nil} and the
minibuffer is selected, it takes precedence over
@code{other-window-scroll-buffer}. @xref{Definition of
minibuffer-scroll-window}.
-
-When the minibuffer is active, it is the next window if the selected
-window is the one at the bottom right corner. In this case,
-@code{scroll-other-window} attempts to scroll the minibuffer. If the
-minibuffer contains just one line, it has nowhere to scroll to, so the
-line reappears after the echo area momentarily displays the message
-@samp{End of buffer}.
@end deffn
@deffn Command scroll-other-window-down &optional count
diff --git a/doc/misc/Makefile.in b/doc/misc/Makefile.in
index 6c1e9cbc910..d348dbc194b 100644
--- a/doc/misc/Makefile.in
+++ b/doc/misc/Makefile.in
@@ -234,6 +234,10 @@ ${buildinfodir}/tramp.info tramp.html: ${srcdir}/trampver.texi
abs_top_builddir = @abs_top_builddir@
+
+# Prevent any settings in the user environment causing problems.
+unexport EMACSDATA EMACSDOC EMACSLOADPATH EMACSPATH
+
EMACS = ${abs_top_builddir}/src/emacs
emacs = "${EMACS}" -batch --no-site-file --no-site-lisp --eval '(setq load-prefer-newer t)'
diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index 83d324c7e1b..f1d7c638056 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -694,6 +694,126 @@ Print the current user. This Eshell version of @command{whoami}
supports Tramp.
@end table
+@subsection Defining new built-in commands
+While Eshell can run Lisp functions directly as commands, it may be
+more convenient to provide a special built-in command for
+Eshell. Built-in commands are just ordinary Lisp functions designed
+to be called from Eshell. When defining an Eshell-specific version of
+an existing function, you can give that function a name starting with
+@code{eshell/} so that Eshell knows to use it.
+
+@defmac eshell-eval-using-options name macro-args options body@dots{}
+This macro processes a list of @var{macro-args} for the command
+@var{name} using a set of command line @var{options}. If the
+arguments are parsed successfully, it will store the resulting values
+in local symbols and execute @var{body}; any remaining arguments will
+be available in the locally let-bound variable @code{args}. The
+return value is the value of the last form in @var{body}.
+
+If an unknown option was passed in @var{macro-args} and an external
+command was specified (see below), this macro will start a process for
+that command and throw the tag @code{eshell-external} with the new
+process as its value.
+
+@var{options} should be a list beginning with one or more elements of
+the following form, with each element representing a particular
+command-line switch:
+
+@example
+(@var{short} @var{long} @var{value} @var{symbol} @var{help-string})
+@end example
+
+@table @var
+@item short
+This element, if non-nil, should be a character to be used as a short
+switch, like @code{-@var{short}}. At least one of this element and
+@var{long} must be non-nil.
+
+@item long
+This element, if non-nil, should be a string to be used as a long
+switch, like @code{--@var{long}}.
+
+@item value
+This element is the value associated with the option. It can be
+either:
+
+@table @asis
+@item @code{t}
+The option needs a value to be specified after the switch.
+
+@item @code{nil}
+The option is given the value @code{t}.
+
+@item anything else
+The option is given the specified value.
+@end table
+
+@item symbol
+This element is the Lisp symbol that will be bound to @var{value}. If
+@var{symbol} is @code{nil}, specifying this switch will instead call
+@code{eshell-show-usage}, and so is appropriate for an option like
+@code{--help}.
+
+@item help-string
+This element is a documentation string for the option, which will be
+displayed when @code{eshell-show-usage} is invoked.
+@end table
+
+After the list of command-line switch elements, @var{options} can
+include additional keyword arguments to control how
+@code{eshell-eval-using-options} behaves. Some of these take
+arguments, while others don't. The recognized keywords are:
+
+@table @code
+@item :external @var{string}
+Specify @var{string} as an external command to run if there are
+unknown switches in @var{macro-args}.
+
+@item :usage @var{string}
+Set @var{string} as the initial part of the command's documentation
+string. It appears before the options are listed.
+
+@item :post-usage @var{string}
+Set @var{string} to be the (optional) trailing part of the command's
+documentation string. It appears after the list of options, but
+before the final part of the documentation about the associated
+external command, if there is one.
+
+@item :show-usage
+If present, then show the usage message if the command is called with
+no arguments.
+
+@item :preserve-args
+Normally, @code{eshell-eval-using-options} flattens the list of
+arguments in @var{macro-args} and converts each to a string. If this
+keyword is present, avoid doing that, instead preserving the original
+arguments. This is useful for commands which want to accept arbitrary
+Lisp objects.
+
+@item :parse-leading-options-only
+If present, do not parse dash or switch arguments after the first
+positional argument. Instead, treat them as positional arguments
+themselves.
+@end table
+
+For example, you could handle a subset of the options for the
+@code{ls} command like this:
+
+@example
+(eshell-eval-using-options
+ "ls" macro-args
+ '((?a nil nil show-all "show all files")
+ (?I "ignore" t ignore-pattern "ignore files matching pattern")
+ (nil "help" nil nil "show this help message")
+ :external "ls"
+ :usage "[OPTION]... [FILE]...
+ List information about FILEs (the current directory by default).")
+ ;; List the files in ARGS somehow...
+ )
+@end example
+
+@end defmac
+
@subsection Built-in variables
Eshell knows a few built-in variables:
diff --git a/doc/misc/gnus.texi b/doc/misc/gnus.texi
index 61870311ed8..b3efdfbacba 100644
--- a/doc/misc/gnus.texi
+++ b/doc/misc/gnus.texi
@@ -12223,7 +12223,6 @@ controlling variable is a predicate list, as described above.
@vindex gnus-treat-highlight-citation
@vindex gnus-treat-highlight-headers
@vindex gnus-treat-highlight-signature
-@vindex gnus-treat-play-sounds
@vindex gnus-treat-x-pgp-sig
@vindex gnus-treat-unfold-headers
@vindex gnus-treat-fold-headers
@@ -12359,8 +12358,6 @@ is controlled by @code{gnus-body-boundary-delimiter}.
@xref{Article Highlighting}.
-@vindex gnus-treat-play-sounds
-@item gnus-treat-play-sounds
@item gnus-treat-ansi-sequences (t)
@vindex gnus-treat-x-pgp-sig
@item gnus-treat-x-pgp-sig (head)
diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi
index 3c159558600..6a198e9bfb5 100644
--- a/doc/misc/tramp.texi
+++ b/doc/misc/tramp.texi
@@ -2857,7 +2857,7 @@ similar user option as auto-save files, called
original file.
If you change @code{lock-file-name-transforms} in order to keep file
-locks for remote files somewhere else, you will loose Emacs' feature
+locks for remote files somewhere else, you will lose Emacs's feature
to warn you, if a file is changed in parallel from different Emacs
sessions, or via different remote connections. Be careful with such
settings.
@@ -2926,7 +2926,7 @@ you, for example, mark the remote directory
@file{@trampfn{nextcloud,user@@host,/path/to/dir}} for encryption, the
configuration file is saved as
@file{tramp-%2Fnextcloud%3Auser%40host%3A%2Fpath%2Fto%2Fdir%2F.encfs6.xml}
-in @code{user-emacs-directory}. Do not loose this file and the
+in @code{user-emacs-directory}. Do not lose this file and the
corresponding password; otherwise there is no way to decrypt your
encrypted files.
diff --git a/etc/NEWS b/etc/NEWS
index d7281467c68..ea9ba49892f 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -223,6 +223,8 @@ inserted.
This command will tell you the name of the Emoji at point. (This
command also works for non-Emoji characters.)
+*** New input method 'emoji'.
+
** Help
---
@@ -271,10 +273,15 @@ height use 'window-height' in combination with 'body-lines'.
*** 'other-window-scroll-default' can define the other window to scroll.
-** Rcirc
+** Frames
+++
-*** New command 'rcirc-when'.
+*** Deleted frames can now be undeleted.
+The 16 most recently deleted frames can be undeleted with 'C-x 5 u' when
+'undelete-frame-mode' is enabled. Without a prefix argument, undelete
+the most recently deleted frame. With a numerical prefix argument
+between 1 and 16, where 1 is the most recently deleted frame, undelete
+the corresponding deleted frame.
** Tab Bars and Tab Lines
@@ -307,6 +314,11 @@ The Emacs server will be automatically stopped when certain conditions
are met. The conditions are given by the argument, which can be
'empty', 'delete-frame' or 'kill-terminal'.
+** Rcirc
+
++++
+*** New command 'rcirc-when'.
+
* Editing Changes in Emacs 29.1
---
@@ -392,6 +404,13 @@ the *Completions* buffer.
+++
*** New user option 'char-fold-override' disables default character equivalences.
++++
+*** New command 'isearch-emoji-by-name'.
+It is bound to 'C-x 8 e RET' during an incremental search. The
+command accepts the Unicode name of an Emoji (for example, "smiling
+face" or "heart with arrow"), like 'C-x 8 e e', with minibuffer
+completion, and adds the Emoji into the search string.
+
** New minor mode 'glyphless-display-mode'.
This allows an easy way to toggle seeing all glyphless characters in
the current buffer.
@@ -575,6 +594,12 @@ to enable the display of the buffer list.
It is bound to 'C-M-,' and jumps to the location where 'xref-go-back'
('M-,', also known as 'xref-pop-marker-stack') was invoked previously.
+*** 'xref-query-replace-in-results' does not prompt for FROM when
+called without prefix argument, to make the most common case faster:
+replacing entire matches.
+
+*** New command 'xref-find-references-and-replace' to rename one identifier.
+
** File notifications
+++
@@ -917,6 +942,11 @@ The input must be encoded text.
* Lisp Changes in Emacs 29.1
+++
+** New function 'function-alias-p'.
+This predicate says whether an object is a function alias, and if it
+is, the alias chain is returned.
+
++++
** New variable 'lisp-directory' holds the directory of Emacs's own Lisp files.
+++
@@ -1090,6 +1120,12 @@ dimensions.
Specifying a cons as the from argument allows to start measuring text
from a specified amount of pixels above or below a position.
+---
+** 'eshell-eval-using-options' now follows POSIX/GNU argument syntax conventions.
+Built-in commands in Eshell now accept command-line options with
+values passed as a single token, such as '-oVALUE' or
+'--option=VALUE'.
+
** XDG support
*** New function 'xdg-state-home' returns 'XDG_STATE_HOME' environment variable.
diff --git a/leim/Makefile.in b/leim/Makefile.in
index a574a108454..2a477d868b3 100644
--- a/leim/Makefile.in
+++ b/leim/Makefile.in
@@ -35,15 +35,14 @@ EXEEXT = @EXEEXT@
-include ${top_builddir}/src/verbose.mk
# Prevent any settings in the user environment causing problems.
-unexport EMACSDATA EMACSDOC EMACSPATH
+unexport EMACSDATA EMACSDOC EMACSLOADPATH EMACSPATH
# Which Emacs to use to convert TIT files to Emacs Lisp files,
# and generate the file leim-list.el.
EMACS = ../src/emacs${EXEEXT}
# How to run Emacs.
-# Prevent any setting of EMACSLOADPATH in user environment causing problems.
-RUN_EMACS = EMACSLOADPATH= '$(EMACS)' -batch --no-site-file --no-site-lisp
+RUN_EMACS = '$(EMACS)' -batch --no-site-file --no-site-lisp
MKDIR_P = @MKDIR_P@
diff --git a/lib-src/Makefile.in b/lib-src/Makefile.in
index c25ba5c974d..0453b935068 100644
--- a/lib-src/Makefile.in
+++ b/lib-src/Makefile.in
@@ -20,6 +20,9 @@
SHELL = @SHELL@
+# Prevent any settings in the user environment causing problems.
+unexport EMACSDATA EMACSDOC EMACSLOADPATH EMACSPATH
+
# Following ../lisp/Makefile.in.
EMACS = ../src/emacs${EXEEXT}
EMACSOPT = -batch --no-site-file --no-site-lisp
diff --git a/lisp/Makefile.in b/lisp/Makefile.in
index d29dec08a5e..3a72034463c 100644
--- a/lisp/Makefile.in
+++ b/lisp/Makefile.in
@@ -101,11 +101,10 @@ MAIN_FIRST = ./emacs-lisp/eieio.el ./emacs-lisp/eieio-base.el \
./cedet/semantic/db.el ./emacs-lisp/cconv.el
# Prevent any settings in the user environment causing problems.
-unexport EMACSDATA EMACSDOC EMACSPATH
+unexport EMACSDATA EMACSDOC EMACSLOADPATH EMACSPATH
# The actual Emacs command run in the targets below.
-# Prevent any setting of EMACSLOADPATH in user environment causing problems.
-emacs = EMACSLOADPATH= '$(EMACS)' $(EMACSOPT)
+emacs = '$(EMACS)' $(EMACSOPT)
## Subdirectories, relative to builddir.
SUBDIRS = $(sort $(shell find ${srcdir} -type d -print))
diff --git a/lisp/auth-source.el b/lisp/auth-source.el
index 046a685d744..8a425cf9bc0 100644
--- a/lisp/auth-source.el
+++ b/lisp/auth-source.el
@@ -861,7 +861,7 @@ while \(:host t) would find all host entries."
secret)))
(defun auth-source-pick-first-password (&rest spec)
- "Pick the first secret found from applying SPEC to `auth-source-search'."
+ "Pick the first secret found by applying 'auth-source-search' to SPEC."
(auth-info-password (car (apply #'auth-source-search (plist-put spec :max 1)))))
(defun auth-source-format-prompt (prompt alist)
diff --git a/lisp/battery.el b/lisp/battery.el
index 45334163fa6..b7b81a11a1c 100644
--- a/lisp/battery.el
+++ b/lisp/battery.el
@@ -96,12 +96,14 @@ Value does not include \".\" or \"..\"."
(cond ((member battery-upower-service (dbus-list-activatable-names))
#'battery-upower)
((and (eq system-type 'gnu/linux)
+ (file-readable-p "/sys/")
(battery--find-linux-sysfs-batteries))
#'battery-linux-sysfs)
((and (eq system-type 'gnu/linux)
(file-directory-p "/proc/acpi/battery"))
#'battery-linux-proc-acpi)
((and (eq system-type 'gnu/linux)
+ (file-readable-p "/proc/")
(file-readable-p "/proc/apm"))
#'battery-linux-proc-apm)
((and (eq system-type 'berkeley-unix)
diff --git a/lisp/cedet/ede/project-am.el b/lisp/cedet/ede/project-am.el
index 2803e1c3071..544e39b8729 100644
--- a/lisp/cedet/ede/project-am.el
+++ b/lisp/cedet/ede/project-am.el
@@ -191,8 +191,9 @@ other meta-variable based on this name.")
"Encode one makefile.")
;;; Code:
-(cl-defmethod project-add-file ((ot project-am-target))
+(cl-defmethod project-add-file ((ot project-am-target) &optional _file)
"Add the current buffer into a project.
+_FILE is ignored.
OT is the object target. DIR is the directory to start in."
(let* ((target (if ede-object (error "Already associated w/ a target")
(let ((amf (project-am-load default-directory)))
diff --git a/lisp/emacs-lisp/easy-mmode.el b/lisp/emacs-lisp/easy-mmode.el
index 56e84ab339a..7bcb2f2936d 100644
--- a/lisp/emacs-lisp/easy-mmode.el
+++ b/lisp/emacs-lisp/easy-mmode.el
@@ -697,7 +697,11 @@ Valid keywords and arguments are:
(defmacro easy-mmode-defmap (m bs doc &rest args)
"Define a constant M whose value is the result of `easy-mmode-define-keymap'.
The M, BS, and ARGS arguments are as per that function. DOC is
-the constant's documentation."
+the constant's documentation.
+
+This macro is deprecated; use `defvar-keymap' instead."
+ ;; FIXME: Declare obsolete in favor of `defvar-keymap'. It is still
+ ;; used for `gud-menu-map' and `gud-minor-mode-map', so fix that first.
(declare (doc-string 3) (indent 1))
`(defconst ,m
(easy-mmode-define-keymap ,bs nil (if (boundp ',m) ,m) ,(cons 'list args))
diff --git a/lisp/emacs-lisp/ert.el b/lisp/emacs-lisp/ert.el
index e31ebf5f7bb..9c6b0e15bbe 100644
--- a/lisp/emacs-lisp/ert.el
+++ b/lisp/emacs-lisp/ert.el
@@ -335,15 +335,20 @@ It should only be stopped when ran from inside `ert--run-test-internal'."
(unless (eql ,value ',default-value)
(list :value ,value))
(unless (eql ,value ',default-value)
- (let ((-explainer-
- (and (symbolp ',fn-name)
- (get ',fn-name 'ert-explainer))))
- (when -explainer-
- (list :explanation
- (apply -explainer- ,args))))))
+ (when-let ((-explainer-
+ (ert--get-explainer ',fn-name)))
+ (list :explanation
+ (apply -explainer- ,args)))))
value)
,value))))))))
+(defun ert--get-explainer (fn-name)
+ (when (symbolp fn-name)
+ (cl-loop for fn in (cons fn-name (function-alias-p fn-name))
+ for explainer = (get fn 'ert-explainer)
+ when explainer
+ return explainer)))
+
(defun ert--expand-should (whole form inner-expander)
"Helper function for the `should' macro and its variants.
diff --git a/lisp/emacs-lisp/inline.el b/lisp/emacs-lisp/inline.el
index 963e117ff34..de0112db631 100644
--- a/lisp/emacs-lisp/inline.el
+++ b/lisp/emacs-lisp/inline.el
@@ -71,7 +71,7 @@
(defmacro inline-quote (_exp)
"Similar to backquote, but quotes code and only accepts , and not ,@."
- (declare (debug backquote-form))
+ (declare (debug (backquote-form)))
(error "inline-quote can only be used within define-inline"))
(defmacro inline-const-p (_exp)
diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el
index faf0b1619e0..27a7a8f8cf1 100644
--- a/lisp/emacs-lisp/macroexp.el
+++ b/lisp/emacs-lisp/macroexp.el
@@ -382,14 +382,17 @@ Assumes the caller has bound `macroexpand-all-environment'."
(macroexp--all-forms args)
form)
(macroexp--expand-all newform))))
- (`(funcall . ,(or `(,exp . ,args) pcase--dontcare))
+ (`(funcall ,exp . ,args)
(let ((eexp (macroexp--expand-all exp))
(eargs (macroexp--all-forms args)))
;; Rewrite (funcall #'foo bar) to (foo bar), in case `foo'
;; has a compiler-macro, or to unfold it.
(pcase eexp
- (`#',f (macroexp--expand-all `(,f . ,eargs)))
+ ((and `#',f
+ (guard (not (or (special-form-p f) (macrop f))))) ;; bug#46636
+ (macroexp--expand-all `(,f . ,eargs)))
(_ `(funcall ,eexp . ,eargs)))))
+ (`(funcall . ,_) form) ;bug#53227
(`(,func . ,_)
(let ((handler (function-get func 'compiler-macro))
(funargs (function-get func 'funarg-positions)))
@@ -430,7 +433,6 @@ Assumes the caller has bound `macroexpand-all-environment'."
newform
(macroexp--expand-all newform)))
(macroexp--expand-all newform))))))
-
(_ form)))
(pop byte-compile-form-stack)))
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index 870d34527b0..658edd67527 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -1299,6 +1299,9 @@ If FUNCTION is non-nil, place point on the entry for FUNCTION (if any)."
(text-property-search-forward 'shortdoc-function function t)
(beginning-of-line)))
+;;;###autoload
+(defalias 'shortdoc #'shortdoc-display-group)
+
(defun shortdoc--display-function (data)
(let ((function (pop data))
(start-section (point))
diff --git a/lisp/eshell/esh-opt.el b/lisp/eshell/esh-opt.el
index d96b77ddd37..bba1c4ad25d 100644
--- a/lisp/eshell/esh-opt.el
+++ b/lisp/eshell/esh-opt.el
@@ -187,49 +187,82 @@ passed to this command, the external version `%s'
will be called instead." extcmd)))))
(throw 'eshell-usage usage)))
-(defun eshell--set-option (name ai opt options opt-vals)
+(defun eshell--split-switch (switch kind)
+ "Split SWITCH into its option name and potential value, if any.
+KIND should be the integer 0 if SWITCH is a short option, or 1 if it's
+a long option."
+ (if (eq kind 0)
+ ;; Short option
+ (cons (aref switch 0)
+ (and (> (length switch) 1) (substring switch 1)))
+ ;; Long option
+ (save-match-data
+ (string-match "\\([^=]*\\)\\(?:=\\(.*\\)\\)?" switch)
+ (cons (match-string 1 switch) (match-string 2 switch)))))
+
+(defun eshell--set-option (name ai opt value options opt-vals)
"Using NAME's remaining args (index AI), set the OPT within OPTIONS.
-If the option consumes an argument for its value, the argument list
-will be modified."
+VALUE is the potential value of the OPT, coming from args like
+\"-fVALUE\" or \"--foo=VALUE\", or nil if no value was supplied. If
+OPT doesn't consume a value, return VALUE unchanged so that it can be
+processed later; otherwsie, return nil.
+
+If the OPT consumes an argument for its value and VALUE is nil, the
+argument list will be modified."
(if (not (nth 3 opt))
(eshell-show-usage name options)
- (setcdr (assq (nth 3 opt) opt-vals)
- (if (eq (nth 2 opt) t)
- (if (> ai (length eshell--args))
- (error "%s: missing option argument" name)
- (pop (nthcdr ai eshell--args)))
- (or (nth 2 opt) t)))))
+ (if (eq (nth 2 opt) t)
+ (progn
+ (setcdr (assq (nth 3 opt) opt-vals)
+ (or value
+ (if (> ai (length eshell--args))
+ (error "%s: missing option argument" name)
+ (pop (nthcdr ai eshell--args)))))
+ nil)
+ (setcdr (assq (nth 3 opt) opt-vals)
+ (or (nth 2 opt) t))
+ value)))
(defun eshell--process-option (name switch kind ai options opt-vals)
"For NAME, process SWITCH (of type KIND), from args at index AI.
The SWITCH will be looked up in the set of OPTIONS.
-SWITCH should be either a string or character. KIND should be the
-integer 0 if it's a character, or 1 if it's a string.
-
-The SWITCH is then be matched against OPTIONS. If no matching handler
-is found, and an :external command is defined (and available), it will
-be called; otherwise, an error will be triggered to say that the
-switch is unrecognized."
- (let* ((opts options)
- found)
+SWITCH should be a string starting with the option to process,
+possibly followed by its value, e.g. \"u\" or \"uUSER\". KIND should
+be the integer 0 if it's a short option, or 1 if it's a long option.
+
+The SWITCH is then be matched against OPTIONS. If KIND is 0 and the
+SWITCH matches an option that doesn't take a value, return the
+remaining characters in SWITCH to be processed later as further short
+options.
+
+If no matching handler is found, and an :external command is defined
+(and available), it will be called; otherwise, an error will be
+triggered to say that the switch is unrecognized."
+ (let ((switch (eshell--split-switch switch kind))
+ (opts options)
+ found remaining)
(while opts
(if (and (listp (car opts))
- (nth kind (car opts))
- (equal switch (nth kind (car opts))))
+ (equal (car switch) (nth kind (car opts))))
(progn
- (eshell--set-option name ai (car opts) options opt-vals)
+ (setq remaining (eshell--set-option name ai (car opts)
+ (cdr switch) options opt-vals))
+ (when (and remaining (eq kind 1))
+ (error "%s: option --%s doesn't allow an argument"
+ name (car switch)))
(setq found t opts nil))
(setq opts (cdr opts))))
- (unless found
+ (if found
+ remaining
(let ((extcmd (memq ':external options)))
(when extcmd
(setq extcmd (eshell-search-path (cadr extcmd)))
(if extcmd
(throw 'eshell-ext-command extcmd)
- (error (if (characterp switch) "%s: unrecognized option -%c"
+ (error (if (characterp (car switch)) "%s: unrecognized option -%c"
"%s: unrecognized option --%s")
- name switch)))))))
+ name (car switch))))))))
(defun eshell--process-args (name args options)
"Process the given ARGS using OPTIONS."
@@ -262,12 +295,9 @@ switch is unrecognized."
(if (> (length switch) 0)
(eshell--process-option name switch 1 ai options opt-vals)
(setq ai (length eshell--args)))
- (let ((len (length switch))
- (index 0))
- (while (< index len)
- (eshell--process-option name (aref switch index)
- 0 ai options opt-vals)
- (setq index (1+ index))))))))
+ (while (> (length switch) 0)
+ (setq switch (eshell--process-option name switch 0
+ ai options opt-vals)))))))
(nconc (mapcar #'cdr opt-vals) eshell--args)))
(provide 'esh-opt)
diff --git a/lisp/ffap.el b/lisp/ffap.el
index f9220817a71..b5d2a02cd1d 100644
--- a/lisp/ffap.el
+++ b/lisp/ffap.el
@@ -1449,10 +1449,13 @@ which may actually result in an URL rather than a filename."
(ffap-file-exists-string (substring name 0 (match-beginning 0)))))
;; If it contains a colon, get rid of it (and return if exists)
((and (string-match path-separator name)
- (setq name (ffap-string-at-point 'nocolon))
- (> (length name) 0)
- (ffap-file-exists-string name)))
- ;; File does not exist, try the alist:
+ (let ((this-name (ffap-string-at-point 'nocolon)))
+ ;; But don't interpret the first part if ":/bin" as
+ ;; the empty string.
+ (when (> (length this-name) 0)
+ (setq name this-name)
+ (ffap-file-exists-string name)))))
+ ;; File does not exist, try the alist:
((let ((alist ffap-alist) tem try case-fold-search)
(while (and alist (not try))
(setq tem (car alist) alist (cdr alist))
diff --git a/lisp/files.el b/lisp/files.el
index 48e0252e060..1d9d450e4d3 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -483,12 +483,16 @@ If `silently', don't ask the user before saving."
(defcustom lock-file-name-transforms nil
"Transforms to apply to buffer file name before making a lock file name.
-This has the same syntax as
-`auto-save-file-name-transforms' (which see), but instead of
-applying to auto-save file names, it's applied to lock file names.
+This has the same syntax as `auto-save-file-name-transforms',
+but applies to lock file names instead of auto-save file names.
-By default, a lock file is put into the same directory as the
-file it's locking, and it has the same name, but with \".#\" prepended."
+By default, Emacs puts each lock file into the same directory as the
+file it locks, prepending \".#\" to the base file name.
+
+Note that changing this could break lock file functionality, e.g.:
+if different users access the same file, using different lock file settings;
+if accessing files on a shared file system from different hosts,
+using a transform that puts the lock files on a local file system."
:group 'files
:type '(repeat (list (regexp :tag "Regexp")
(string :tag "Replacement")
diff --git a/lisp/frame.el b/lisp/frame.el
index 62b73f3157b..599ffe591a5 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -2529,6 +2529,80 @@ deleting them."
(if iconify (iconify-frame this) (delete-frame this)))
(setq this next))))
+(eval-when-compile (require 'frameset))
+
+(defvar undelete-frame--deleted-frames nil
+ "Internal variable used by `undelete-frame--handle-delete-frame'.")
+
+(defun undelete-frame--handle-delete-frame (frame)
+ "Save the configuration of frames deleted with `delete-frame'.
+Only the 16 most recently deleted frames are saved."
+ (when (frame-live-p frame)
+ (setq undelete-frame--deleted-frames
+ (cons
+ (cons
+ (display-graphic-p)
+ (frameset-save
+ (list frame)
+ ;; When the daemon is started from a graphical
+ ;; environment, TTY frames have a 'display' parameter set
+ ;; to the value of $DISPLAY (see the note in
+ ;; `server--on-display-p'). Do not store that parameter
+ ;; in the frameset, otherwise `frameset-restore' attempts
+ ;; to restore a graphical frame.
+ :filters (if (display-graphic-p)
+ frameset-filter-alist
+ (cons '(display . :never)
+ frameset-filter-alist))))
+ undelete-frame--deleted-frames))
+ (if (> (length undelete-frame--deleted-frames) 16)
+ (setq undelete-frame--deleted-frames
+ (butlast undelete-frame--deleted-frames)))))
+
+(define-minor-mode undelete-frame-mode
+ "Enable the `undelete-frame' command."
+ :group 'frames
+ :global t
+ (if undelete-frame-mode
+ (add-hook 'delete-frame-functions
+ #'undelete-frame--handle-delete-frame -75)
+ (remove-hook 'delete-frame-functions
+ #'undelete-frame--handle-delete-frame)
+ (setq undelete-frame--deleted-frames nil)))
+
+(defun undelete-frame (&optional arg)
+ "Undelete a frame deleted with `delete-frame'.
+Without a prefix argument, undelete the most recently deleted
+frame.
+With a numerical prefix argument ARG between 1 and 16, where 1 is
+most recently deleted frame, undelete the ARGth deleted frame.
+When called from Lisp, returns the new frame."
+ (interactive "P")
+ (if (not undelete-frame-mode)
+ (user-error "Undelete-Frame mode is disabled")
+ (if (consp arg)
+ (user-error "Missing deleted frame number argument")
+ (let* ((number (pcase arg ('nil 1) ('- -1) (_ arg)))
+ (frames (frame-list))
+ (frameset (nth (1- number) undelete-frame--deleted-frames))
+ (graphic (display-graphic-p)))
+ (if (not (<= 1 number 16))
+ (user-error "%d is not a valid deleted frame number argument"
+ number)
+ (if (not frameset)
+ (user-error "No deleted frame with number %d" number)
+ (if (not (eq graphic (car frameset)))
+ (user-error
+ "Cannot undelete a %s display frame on a %s display"
+ (if graphic "non-graphic" "graphic")
+ (if graphic "graphic" "non-graphic"))
+ (setq undelete-frame--deleted-frames
+ (delq frameset undelete-frame--deleted-frames))
+ (frameset-restore (cdr frameset))
+ (let ((frame (car (seq-difference (frame-list) frames))))
+ (when frame
+ (select-frame-set-input-focus frame)
+ frame)))))))))
;;; Window dividers.
(defgroup window-divider nil
@@ -2873,6 +2947,7 @@ See also `toggle-frame-maximized'."
(define-key ctl-x-5-map "o" #'other-frame)
(define-key ctl-x-5-map "5" #'other-frame-prefix)
(define-key ctl-x-5-map "c" #'clone-frame)
+(define-key ctl-x-5-map "u" #'undelete-frame)
(define-key global-map [f11] #'toggle-frame-fullscreen)
(define-key global-map [(meta f10)] #'toggle-frame-maximized)
(define-key esc-map [f10] #'toggle-frame-maximized)
diff --git a/lisp/gnus/gnus-art.el b/lisp/gnus/gnus-art.el
index f26ab6ab4c7..a286c446724 100644
--- a/lisp/gnus/gnus-art.el
+++ b/lisp/gnus/gnus-art.el
@@ -1159,13 +1159,15 @@ predicate. See Info node `(gnus)Customizing Articles'."
:link '(custom-manual "(gnus)Customizing Articles")
:type gnus-article-treat-head-custom)
-(defcustom gnus-treat-emphasize 50000
+(defcustom gnus-treat-emphasize '(and 50000
+ (not (typep "text/html")))
"Emphasize text.
Valid values are nil, t, `head', `first', `last', an integer or a
predicate. See Info node `(gnus)Customizing Articles'."
:group 'gnus-article-treat
:link '(custom-manual "(gnus)Customizing Articles")
- :type gnus-article-treat-custom)
+ :type gnus-article-treat-custom
+ :version "29.1")
(put 'gnus-treat-emphasize 'highlight t)
(defcustom gnus-treat-strip-cr nil
diff --git a/lisp/gnus/gnus-registry.el b/lisp/gnus/gnus-registry.el
index 0c281a997f8..edeacbc919e 100644
--- a/lisp/gnus/gnus-registry.el
+++ b/lisp/gnus/gnus-registry.el
@@ -355,8 +355,13 @@ This is not required after changing `gnus-registry-cache-file'."
"Load the registry from the cache file."
(interactive)
(let ((file gnus-registry-cache-file))
+ (gnus-message 5 "Initializing the registry")
(condition-case nil
- (gnus-registry-read file)
+ (progn
+ (gnus-registry-read file)
+ (gnus-registry-install-hooks)
+ (gnus-registry-install-shortcuts)
+ (setq gnus-registry-enabled t))
(file-error
;; Fix previous mis-naming of the registry file.
(let ((old-file-name
@@ -846,9 +851,9 @@ Overrides existing keywords with FORCE set non-nil."
(defun gnus-registry-register-message-ids ()
"Register the Message-ID of every article in the group."
- (unless (or (gnus-parameter-registry-ignore gnus-newsgroup-name)
- (null gnus-registry-register-all)
- (null (eieio-object-p gnus-registry-db)))
+ (unless (or (null gnus-registry-enabled)
+ (null gnus-registry-register-all)
+ (gnus-parameter-registry-ignore gnus-newsgroup-name))
(dolist (article gnus-newsgroup-articles)
(let* ((id (gnus-registry-fetch-message-id-fast article))
(groups (gnus-registry-get-id-key id 'group)))
@@ -1175,7 +1180,8 @@ non-nil."
(defun gnus-registry-clear ()
"Clear the registry."
(gnus-registry-unload-hook)
- (setq gnus-registry-db nil))
+ (setq gnus-registry-db nil
+ gnus-registry-enabled nil))
(gnus-add-shutdown 'gnus-registry-clear 'gnus)
@@ -1183,16 +1189,12 @@ non-nil."
(defun gnus-registry-initialize ()
"Initialize the Gnus registry."
(interactive)
- (gnus-message 5 "Initializing the registry")
- (gnus-registry-install-hooks)
- (gnus-registry-install-shortcuts)
(if (gnus-alive-p)
(gnus-registry-load)
(add-hook 'gnus-read-newsrc-el-hook #'gnus-registry-load)))
(defun gnus-registry-install-hooks ()
"Install the registry hooks."
- (setq gnus-registry-enabled t)
(add-hook 'gnus-summary-article-move-hook #'gnus-registry-action)
(add-hook 'gnus-summary-article-delete-hook #'gnus-registry-action)
(add-hook 'gnus-summary-article-expire-hook #'gnus-registry-action)
@@ -1212,10 +1214,9 @@ non-nil."
(remove-hook 'gnus-save-newsrc-hook #'gnus-registry-save)
(remove-hook 'gnus-read-newsrc-el-hook #'gnus-registry-load)
- (remove-hook 'gnus-summary-prepare-hook #'gnus-registry-register-message-ids)
- (setq gnus-registry-enabled nil))
+ (remove-hook 'gnus-summary-prepare-hook #'gnus-registry-register-message-ids))
-(add-hook 'gnus-registry-unload-hook #'gnus-registry-unload-hook)
+(add-hook 'gnus-registry-unload-hook #'gnus-registry-clear)
(defun gnus-registry-install-p ()
"Return non-nil if the registry is enabled (and maybe enable it first).
diff --git a/lisp/gnus/nnimap.el b/lisp/gnus/nnimap.el
index 090cb9b245b..cff628061e9 100644
--- a/lisp/gnus/nnimap.el
+++ b/lisp/gnus/nnimap.el
@@ -246,7 +246,7 @@ during splitting, which may be slow."
(nnimap-header-parameters))
t)
(unless (process-live-p (get-buffer-process (current-buffer)))
- (error "Server closed connection"))
+ (error "IMAP server %S closed connection" nnimap-address))
(nnimap-transform-headers)
(nnheader-remove-cr-followed-by-lf))
(insert-buffer-substring
diff --git a/lisp/gnus/nntp.el b/lisp/gnus/nntp.el
index 624c64d4d75..0dcff9743ad 100644
--- a/lisp/gnus/nntp.el
+++ b/lisp/gnus/nntp.el
@@ -306,7 +306,7 @@ backend doesn't catch this error.")
(nntp-record-command string))
(process-send-string process (concat string nntp-end-of-line))
(or (memq (process-status process) '(open run))
- (nntp-report "Server closed connection")))
+ (nntp-report "NNTP server %S closed connection" nntp-address)))
(defun nntp-record-command (string)
"Record the command STRING."
@@ -369,7 +369,7 @@ retried once before actually displaying the error report."
(nntp-snarf-error-message)
nil))
((not (memq (process-status process) '(open run)))
- (nntp-report "Server closed connection"))
+ (nntp-report "NNTP server %S closed connection" nntp-address))
(t
(goto-char (point-max))
(let ((limit (point-min))
@@ -1431,7 +1431,7 @@ If SEND-IF-FORCE, only send authinfo to the server if the
;; be the process's former output buffer (i.e. now killed)
(or (and process
(memq (process-status process) '(open run)))
- (nntp-report "Server closed connection")))))
+ (nntp-report "NNTP server %S closed connection" nntp-address)))))
(defun nntp-accept-response ()
"Wait for output from the process that outputs to BUFFER."
@@ -1450,7 +1450,7 @@ If SEND-IF-FORCE, only send authinfo to the server if the
(when group
(let ((entry (nntp-find-connection-entry nntp-server-buffer)))
(cond ((not entry)
- (nntp-report "Server closed connection"))
+ (nntp-report "NNTP server %S closed connection" nntp-address))
((not (equal group (caddr entry)))
(with-current-buffer (process-buffer (car entry))
(erase-buffer)
diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index d408efeeb9e..e000a68a823 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -829,11 +829,7 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED REAL-DEF)."
(symbol-name function)))))))
(real-def (cond
((and aliased (not (subrp def)))
- (let ((f real-function))
- (while (and (fboundp f)
- (symbolp (symbol-function f)))
- (setq f (symbol-function f)))
- f))
+ (car (function-alias-p real-function t)))
((subrp def) (intern (subr-name def)))
(t def))))
diff --git a/lisp/hi-lock.el b/lisp/hi-lock.el
index fbd698e234a..b70d4a75690 100644
--- a/lisp/hi-lock.el
+++ b/lisp/hi-lock.el
@@ -854,6 +854,26 @@ SPACES-REGEXP is a regexp to substitute spaces in font-lock search."
;; continue standard unloading
nil)
+;;; Mouse support
+(defun hi-lock-symbol-at-mouse (event)
+ "Highlight symbol at mouse click EVENT."
+ (interactive "e")
+ (save-excursion
+ (mouse-set-point event)
+ (highlight-symbol-at-point)))
+
+;;;###autoload
+(defun hi-lock-context-menu (menu click)
+ "Populate MENU with a menu item to highlight symbol at CLICK."
+ (save-excursion
+ (mouse-set-point click)
+ (when (symbol-at-point)
+ (define-key-after menu [highlight-search-separator] menu-bar-separator)
+ (define-key-after menu [highlight-search-mouse]
+ '(menu-item "Highlight Symbol" highlight-symbol-at-mouse
+ :help "Highlight symbol at point"))))
+ menu)
+
(provide 'hi-lock)
;;; hi-lock.el ends here
diff --git a/lisp/image-dired.el b/lisp/image-dired.el
index 536f29441ae..b81df8567bd 100644
--- a/lisp/image-dired.el
+++ b/lisp/image-dired.el
@@ -609,9 +609,7 @@ See also `image-dired-thumbnail-storage'."
((eq 'use-image-dired-dir image-dired-thumbnail-storage)
(let* ((f (expand-file-name file))
(hash
- ;; SHA1 is slightly faster than MD5, so let's use it.
- ;; (We don't need anything crytographically strong.)
- (sha1 (file-name-as-directory (file-name-directory f)))))
+ (md5 (file-name-as-directory (file-name-directory f)))))
(format "%s%s%s.thumb.%s"
(file-name-as-directory (expand-file-name (image-dired-dir)))
(file-name-base f)
diff --git a/lisp/isearch.el b/lisp/isearch.el
index 7593a0ec980..833d031c562 100644
--- a/lisp/isearch.el
+++ b/lisp/isearch.el
@@ -668,6 +668,7 @@ This is like `describe-bindings', but displays only Isearch keys."
;; The key translations defined in the C-x 8 prefix should add
;; characters to the search string. See iso-transl.el.
(define-key map "\C-x8\r" 'isearch-char-by-name)
+ (define-key map "\C-x8e\r" 'isearch-emoji-by-name)
map)
"Keymap for `isearch-mode'.")
@@ -758,6 +759,8 @@ This is like `describe-bindings', but displays only Isearch keys."
:help "Search for literal char"]
["Search for char by name" isearch-char-by-name
:help "Search for character by name"]
+ ["Search for Emoji by name" isearch-emoji-by-name
+ :help "Search for Emoji by its Unicode name"]
"---"
["Toggle input method" isearch-toggle-input-method
:help "Toggle input method for search"]
@@ -2747,6 +2750,24 @@ With argument, add COUNT copies of the character."
(mapconcat 'isearch-text-char-description
string ""))))))))
+(defun isearch-emoji-by-name (&optional count)
+ "Read an Emoji name and add it to the search string COUNT times.
+COUNT (interactively, the prefix argument) defaults to 1.
+The command accepts Unicode names like \"smiling face\" or
+\"heart with arrow\", and completion is available."
+ (interactive "p")
+ (with-isearch-suspended
+ (let ((emoji (with-temp-buffer
+ (emoji-search)
+ (if (and (integerp count) (> count 1))
+ (apply 'concat (make-list count (buffer-string)))
+ (buffer-string)))))
+ (when emoji
+ (setq isearch-new-string (concat isearch-string emoji)
+ isearch-new-message (concat isearch-message
+ (mapconcat 'isearch-text-char-description
+ emoji "")))))))
+
(defun isearch-search-and-update ()
"Do the search and update the display."
(when (or isearch-success
diff --git a/lisp/jsonrpc.el b/lisp/jsonrpc.el
index 84d0ef9179b..b84e9b74b1f 100644
--- a/lisp/jsonrpc.el
+++ b/lisp/jsonrpc.el
@@ -4,7 +4,7 @@
;; Author: João Távora <joaotavora@gmail.com>
;; Keywords: processes, languages, extensions
-;; Version: 1.0.14
+;; Version: 1.0.15
;; Package-Requires: ((emacs "25.2"))
;; This is a GNU ELPA :core package. Avoid functionality that is not
@@ -698,7 +698,9 @@ TIMEOUT is nil)."
(defun jsonrpc--debug (server format &rest args)
"Debug message for SERVER with FORMAT and ARGS."
(jsonrpc--log-event
- server (if (stringp format)`(:message ,(format format args)) format)))
+ server (if (stringp format)
+ `(:message ,(apply #'format format args))
+ format)))
(defun jsonrpc--warn (format &rest args)
"Warning message with FORMAT and ARGS."
diff --git a/lisp/ldefs-boot.el b/lisp/ldefs-boot.el
index 6d5b0d84e6b..05d461e41e9 100644
--- a/lisp/ldefs-boot.el
+++ b/lisp/ldefs-boot.el
@@ -8861,8 +8861,12 @@ Define a constant M whose value is the result of `easy-mmode-define-keymap'.
The M, BS, and ARGS arguments are as per that function. DOC is
the constant's documentation.
+This macro is deprecated; use `defvar-keymap' instead.
+
\(fn M BS DOC &rest ARGS)" nil t)
+(function-put 'easy-mmode-defmap 'doc-string-elt '3)
+
(function-put 'easy-mmode-defmap 'lisp-indent-function '1)
(autoload 'easy-mmode-defsyntax "easy-mmode" "\
@@ -8871,6 +8875,8 @@ CSS contains a list of syntax specifications of the form (CHAR . SYNTAX).
\(fn ST CSS DOC &rest ARGS)" nil t)
+(function-put 'easy-mmode-defsyntax 'doc-string-elt '3)
+
(function-put 'easy-mmode-defsyntax 'lisp-indent-function '1)
(register-definition-prefixes "easy-mmode" '("easy-mmode-"))
@@ -10291,6 +10297,31 @@ disabled.
;;;### (autoloads nil "elide-head" "elide-head.el" (0 0 0 0))
;;; Generated autoloads from elide-head.el
+(autoload 'elide-head-mode "elide-head" "\
+Toggle eliding (hiding) header material in the current buffer.
+
+This is a minor mode. If called interactively, toggle the `Elide-Head
+mode' mode. If the prefix argument is positive, enable the mode, and
+if it is zero or negative, disable the mode.
+
+If called from Lisp, toggle the mode if ARG is `toggle'. Enable the
+mode if ARG is nil, omitted, or is a positive number. Disable the
+mode if ARG is a negative number.
+
+To check whether the minor mode is enabled in the current buffer,
+evaluate `elide-head-mode'.
+
+The mode's hook is called both when the mode is enabled and when it is
+disabled.
+
+When Elide Header mode is enabled, headers are hidden according
+to `elide-head-headers-to-hide'.
+
+This is suitable as an entry on `find-file-hook' or appropriate
+mode hooks.
+
+\(fn &optional ARG)" t nil)
+
(autoload 'elide-head "elide-head" "\
Hide header material in buffer according to `elide-head-headers-to-hide'.
@@ -10301,6 +10332,8 @@ This is suitable as an entry on `find-file-hook' or appropriate mode hooks.
\(fn &optional ARG)" t nil)
+(make-obsolete 'elide-head 'elide-head-mode '"29.1")
+
(register-definition-prefixes "elide-head" '("elide-head-"))
;;;***
@@ -16764,6 +16797,11 @@ be found in variable `hi-lock-interactive-patterns'." t nil)
(autoload 'hi-lock-find-patterns "hi-lock" "\
Add patterns from the current buffer to the list of hi-lock patterns." t nil)
+(autoload 'hi-lock-context-menu "hi-lock" "\
+Populate MENU with a menu item to highlight symbol at CLICK.
+
+\(fn MENU CLICK)" nil nil)
+
(register-definition-prefixes "hi-lock" '("hi-lock-" "turn-on-hi-lock-if-enabled"))
;;;***
@@ -19155,25 +19193,37 @@ system." t nil)
(put 'info-lookup-symbol 'info-file "emacs")
(autoload 'info-lookup-symbol "info-look" "\
-Display the definition of SYMBOL, as found in the relevant manual.
-When this command is called interactively, it reads SYMBOL from the
-minibuffer. In the minibuffer, use \\<minibuffer-local-completion-map>\\[next-history-element] to yank the default argument
-value into the minibuffer so you can edit it. The default symbol is the
-one found at point.
+Look up and display documentation of SYMBOL in the relevant Info manual.
+SYMBOL should be an identifier: a function or method, a macro, a variable,
+a data type, a class, etc.
-With prefix arg MODE a query for the symbol help mode is offered.
+Interactively, prompt for SYMBOL; you can use \\<minibuffer-local-completion-map>\\[next-history-element] in the minibuffer
+to yank the default argument value into the minibuffer so you can edit it.
+The default symbol is the one found at point.
+
+MODE is the major mode whose Info manuals to search for the documentation
+of SYMBOL. It defaults to the current buffer's `major-mode'; if that
+mode doesn't have any Info manuals known to Emacs, the command will
+prompt for MODE to use, with completion. With prefix arg, the command
+always prompts for MODE.
\(fn SYMBOL &optional MODE)" t nil)
(put 'info-lookup-file 'info-file "emacs")
(autoload 'info-lookup-file "info-look" "\
-Display the documentation of a file.
-When this command is called interactively, it reads FILE from the minibuffer.
-In the minibuffer, use \\<minibuffer-local-completion-map>\\[next-history-element] to yank the default file name
-into the minibuffer so you can edit it.
+Look up and display documentation of FILE in the relevant Info manual.
+FILE should be the name of a file; a notable example is a standard header
+file that is part of the C or C++ standard library.
+
+Interactively, prompt for FILE; you can use \\<minibuffer-local-completion-map>\\[next-history-element] in the minibuffer
+to yank the default argument value into the minibuffer so you can edit it.
The default file name is the one found at point.
-With prefix arg MODE a query for the file help mode is offered.
+MODE is the major mode whose Info manuals to search for the documentation
+of FILE. It defaults to the current buffer's `major-mode'; if that
+mode doesn't have any Info manuals known to Emacs, the command will
+prompt for MODE to use, with completion. With prefix arg, the command
+always prompts for MODE.
\(fn FILE &optional MODE)" t nil)
@@ -19859,7 +19909,7 @@ one of the aforementioned options instead of using this mode.
;;;### (autoloads nil "jsonrpc" "jsonrpc.el" (0 0 0 0))
;;; Generated autoloads from jsonrpc.el
-(push (purecopy '(jsonrpc 1 0 14)) package--builtin-versions)
+(push (purecopy '(jsonrpc 1 0 15)) package--builtin-versions)
(register-definition-prefixes "jsonrpc" '("jsonrpc-"))
@@ -21311,6 +21361,11 @@ Default bookmark handler for Man buffers.
\(fn BOOKMARK)" nil nil)
+(autoload 'Man-context-menu "man" "\
+Populate MENU with commands that open a man page at point.
+
+\(fn MENU CLICK)" nil nil)
+
(register-definition-prefixes "man" '("Man-" "man"))
;;;***
@@ -31067,6 +31122,8 @@ If FUNCTION is non-nil, place point on the entry for FUNCTION (if any).
\(fn GROUP &optional FUNCTION)" t nil)
+(defalias 'shortdoc #'shortdoc-display-group)
+
(register-definition-prefixes "shortdoc" '("alist" "buffer" "define-short-documentation-group" "file" "hash-table" "keymaps" "list" "number" "overlay" "process" "regexp" "sequence" "shortdoc-" "string" "text-properties" "vector"))
;;;***
@@ -39394,6 +39451,32 @@ unless `windmove-create-window' is non-nil and a new window is created.
\(fn &optional ARG)" t nil)
+(defvar windmove-mode t "\
+Non-nil if Windmove mode is enabled.
+See the `windmove-mode' command
+for a description of this minor mode.")
+
+(custom-autoload 'windmove-mode "windmove" nil)
+
+(autoload 'windmove-mode "windmove" "\
+Global minor mode for default windmove commands.
+
+This is a minor mode. If called interactively, toggle the `Windmove
+mode' mode. If the prefix argument is positive, enable the mode, and
+if it is zero or negative, disable the mode.
+
+If called from Lisp, toggle the mode if ARG is `toggle'. Enable the
+mode if ARG is nil, omitted, or is a positive number. Disable the
+mode if ARG is a negative number.
+
+To check whether the minor mode is enabled in the current buffer,
+evaluate `(default-value \\='windmove-mode)'.
+
+The mode's hook is called both when the mode is enabled and when it is
+disabled.
+
+\(fn &optional ARG)" t nil)
+
(autoload 'windmove-default-keybindings "windmove" "\
Set up keybindings for `windmove'.
Keybindings are of the form MODIFIERS-{left,right,up,down},
@@ -39969,24 +40052,23 @@ Zone out, completely." t nil)
;;;### (autoloads nil nil ("abbrev.el" "bindings.el" "buff-menu.el"
;;;;;; "button.el" "calc/calc-aent.el" "calc/calc-embed.el" "calc/calc-misc.el"
-;;;;;; "calc/calc-yank.el" "case-table.el" "cedet/ede/base.el" "cedet/ede/config.el"
-;;;;;; "cedet/ede/cpp-root.el" "cedet/ede/custom.el" "cedet/ede/dired.el"
-;;;;;; "cedet/ede/emacs.el" "cedet/ede/files.el" "cedet/ede/generic.el"
-;;;;;; "cedet/ede/linux.el" "cedet/ede/locate.el" "cedet/ede/make.el"
-;;;;;; "cedet/ede/shell.el" "cedet/ede/speedbar.el" "cedet/ede/system.el"
-;;;;;; "cedet/ede/util.el" "cedet/semantic/analyze.el" "cedet/semantic/analyze/complete.el"
-;;;;;; "cedet/semantic/analyze/refs.el" "cedet/semantic/bovine.el"
-;;;;;; "cedet/semantic/bovine/c-by.el" "cedet/semantic/bovine/c.el"
-;;;;;; "cedet/semantic/bovine/el.el" "cedet/semantic/bovine/gcc.el"
-;;;;;; "cedet/semantic/bovine/make-by.el" "cedet/semantic/bovine/make.el"
-;;;;;; "cedet/semantic/bovine/scm-by.el" "cedet/semantic/bovine/scm.el"
-;;;;;; "cedet/semantic/complete.el" "cedet/semantic/ctxt.el" "cedet/semantic/db-file.el"
-;;;;;; "cedet/semantic/db-find.el" "cedet/semantic/db-global.el"
-;;;;;; "cedet/semantic/db-mode.el" "cedet/semantic/db-typecache.el"
-;;;;;; "cedet/semantic/db.el" "cedet/semantic/debug.el" "cedet/semantic/decorate/include.el"
-;;;;;; "cedet/semantic/decorate/mode.el" "cedet/semantic/dep.el"
-;;;;;; "cedet/semantic/doc.el" "cedet/semantic/edit.el" "cedet/semantic/find.el"
-;;;;;; "cedet/semantic/format.el" "cedet/semantic/grammar-wy.el"
+;;;;;; "calc/calc-yank.el" "case-table.el" "cedet/ede/cpp-root.el"
+;;;;;; "cedet/ede/custom.el" "cedet/ede/dired.el" "cedet/ede/emacs.el"
+;;;;;; "cedet/ede/files.el" "cedet/ede/generic.el" "cedet/ede/linux.el"
+;;;;;; "cedet/ede/locate.el" "cedet/ede/make.el" "cedet/ede/speedbar.el"
+;;;;;; "cedet/ede/system.el" "cedet/ede/util.el" "cedet/semantic/analyze.el"
+;;;;;; "cedet/semantic/analyze/complete.el" "cedet/semantic/analyze/refs.el"
+;;;;;; "cedet/semantic/bovine.el" "cedet/semantic/bovine/c-by.el"
+;;;;;; "cedet/semantic/bovine/c.el" "cedet/semantic/bovine/el.el"
+;;;;;; "cedet/semantic/bovine/gcc.el" "cedet/semantic/bovine/make-by.el"
+;;;;;; "cedet/semantic/bovine/make.el" "cedet/semantic/bovine/scm-by.el"
+;;;;;; "cedet/semantic/bovine/scm.el" "cedet/semantic/complete.el"
+;;;;;; "cedet/semantic/ctxt.el" "cedet/semantic/db-file.el" "cedet/semantic/db-find.el"
+;;;;;; "cedet/semantic/db-global.el" "cedet/semantic/db-mode.el"
+;;;;;; "cedet/semantic/db-typecache.el" "cedet/semantic/db.el" "cedet/semantic/debug.el"
+;;;;;; "cedet/semantic/decorate/include.el" "cedet/semantic/decorate/mode.el"
+;;;;;; "cedet/semantic/dep.el" "cedet/semantic/doc.el" "cedet/semantic/edit.el"
+;;;;;; "cedet/semantic/find.el" "cedet/semantic/format.el" "cedet/semantic/grammar-wy.el"
;;;;;; "cedet/semantic/grm-wy-boot.el" "cedet/semantic/html.el"
;;;;;; "cedet/semantic/ia-sb.el" "cedet/semantic/ia.el" "cedet/semantic/idle.el"
;;;;;; "cedet/semantic/imenu.el" "cedet/semantic/lex-spp.el" "cedet/semantic/lex.el"
@@ -40005,8 +40087,8 @@ Zone out, completely." t nil)
;;;;;; "cedet/srecode/insert.el" "cedet/srecode/java.el" "cedet/srecode/map.el"
;;;;;; "cedet/srecode/mode.el" "cedet/srecode/srt-wy.el" "cedet/srecode/srt.el"
;;;;;; "cedet/srecode/template.el" "cedet/srecode/texi.el" "composite.el"
-;;;;;; "cus-face.el" "cus-start.el" "custom.el" "dired-aux.el" "dired-x.el"
-;;;;;; "electric.el" "emacs-lisp/backquote.el" "emacs-lisp/byte-run.el"
+;;;;;; "cus-face.el" "cus-load.el" "cus-start.el" "custom.el" "dired-aux.el"
+;;;;;; "dired-x.el" "electric.el" "emacs-lisp/backquote.el" "emacs-lisp/byte-run.el"
;;;;;; "emacs-lisp/cl-extra.el" "emacs-lisp/cl-macs.el" "emacs-lisp/cl-preloaded.el"
;;;;;; "emacs-lisp/cl-seq.el" "emacs-lisp/easymenu.el" "emacs-lisp/eieio-custom.el"
;;;;;; "emacs-lisp/eieio-opt.el" "emacs-lisp/float-sup.el" "emacs-lisp/lisp-mode.el"
@@ -40028,30 +40110,41 @@ Zone out, completely." t nil)
;;;;;; "eshell/em-pred.el" "eshell/em-prompt.el" "eshell/em-rebind.el"
;;;;;; "eshell/em-script.el" "eshell/em-smart.el" "eshell/em-term.el"
;;;;;; "eshell/em-tramp.el" "eshell/em-unix.el" "eshell/em-xtra.el"
-;;;;;; "faces.el" "files.el" "font-core.el" "font-lock.el" "format.el"
-;;;;;; "frame.el" "help.el" "hfy-cmap.el" "ibuf-ext.el" "indent.el"
-;;;;;; "international/characters.el" "international/charscript.el"
-;;;;;; "international/cp51932.el" "international/emoji-zwj.el" "international/eucjp-ms.el"
+;;;;;; "eshell/esh-groups.el" "faces.el" "files.el" "finder-inf.el"
+;;;;;; "font-core.el" "font-lock.el" "format.el" "frame.el" "help.el"
+;;;;;; "hfy-cmap.el" "ibuf-ext.el" "indent.el" "international/characters.el"
+;;;;;; "international/charprop.el" "international/charscript.el"
+;;;;;; "international/cp51932.el" "international/emoji-labels.el"
+;;;;;; "international/emoji-zwj.el" "international/eucjp-ms.el"
;;;;;; "international/iso-transl.el" "international/mule-cmds.el"
-;;;;;; "international/mule-conf.el" "international/mule.el" "isearch.el"
-;;;;;; "jit-lock.el" "jka-cmpr-hook.el" "keymap.el" "language/burmese.el"
-;;;;;; "language/cham.el" "language/chinese.el" "language/cyrillic.el"
-;;;;;; "language/czech.el" "language/english.el" "language/ethiopic.el"
-;;;;;; "language/european.el" "language/georgian.el" "language/greek.el"
-;;;;;; "language/hebrew.el" "language/indian.el" "language/japanese.el"
-;;;;;; "language/khmer.el" "language/korean.el" "language/lao.el"
-;;;;;; "language/misc-lang.el" "language/romanian.el" "language/sinhala.el"
-;;;;;; "language/slovak.el" "language/tai-viet.el" "language/thai.el"
-;;;;;; "language/tibetan.el" "language/utf-8-lang.el" "language/vietnamese.el"
-;;;;;; "ldefs-boot.el" "leim/ja-dic/ja-dic.el" "leim/leim-list.el"
-;;;;;; "leim/quail/4Corner.el" "leim/quail/ARRAY30.el" "leim/quail/CCDOSPY.el"
-;;;;;; "leim/quail/CTLau-b5.el" "leim/quail/CTLau.el" "leim/quail/ECDICT.el"
-;;;;;; "leim/quail/ETZY.el" "leim/quail/PY-b5.el" "leim/quail/PY.el"
-;;;;;; "leim/quail/Punct-b5.el" "leim/quail/Punct.el" "leim/quail/QJ-b5.el"
-;;;;;; "leim/quail/QJ.el" "leim/quail/SW.el" "leim/quail/TONEPY.el"
-;;;;;; "leim/quail/ZIRANMA.el" "leim/quail/ZOZY.el" "leim/quail/arabic.el"
-;;;;;; "leim/quail/cham.el" "leim/quail/compose.el" "leim/quail/croatian.el"
-;;;;;; "leim/quail/cyril-jis.el" "leim/quail/cyrillic.el" "leim/quail/czech.el"
+;;;;;; "international/mule-conf.el" "international/mule.el" "international/uni-bidi.el"
+;;;;;; "international/uni-brackets.el" "international/uni-category.el"
+;;;;;; "international/uni-combining.el" "international/uni-comment.el"
+;;;;;; "international/uni-decimal.el" "international/uni-decomposition.el"
+;;;;;; "international/uni-digit.el" "international/uni-lowercase.el"
+;;;;;; "international/uni-mirrored.el" "international/uni-name.el"
+;;;;;; "international/uni-numeric.el" "international/uni-old-name.el"
+;;;;;; "international/uni-special-lowercase.el" "international/uni-special-titlecase.el"
+;;;;;; "international/uni-special-uppercase.el" "international/uni-titlecase.el"
+;;;;;; "international/uni-uppercase.el" "isearch.el" "jit-lock.el"
+;;;;;; "jka-cmpr-hook.el" "keymap.el" "language/burmese.el" "language/cham.el"
+;;;;;; "language/chinese.el" "language/cyrillic.el" "language/czech.el"
+;;;;;; "language/english.el" "language/ethiopic.el" "language/european.el"
+;;;;;; "language/georgian.el" "language/greek.el" "language/hebrew.el"
+;;;;;; "language/indian.el" "language/japanese.el" "language/khmer.el"
+;;;;;; "language/korean.el" "language/lao.el" "language/misc-lang.el"
+;;;;;; "language/romanian.el" "language/sinhala.el" "language/slovak.el"
+;;;;;; "language/tai-viet.el" "language/thai.el" "language/tibetan.el"
+;;;;;; "language/utf-8-lang.el" "language/vietnamese.el" "ldefs-boot.el"
+;;;;;; "leim/ja-dic/ja-dic.el" "leim/leim-list.el" "leim/quail/4Corner.el"
+;;;;;; "leim/quail/ARRAY30.el" "leim/quail/CCDOSPY.el" "leim/quail/CTLau-b5.el"
+;;;;;; "leim/quail/CTLau.el" "leim/quail/ECDICT.el" "leim/quail/ETZY.el"
+;;;;;; "leim/quail/PY-b5.el" "leim/quail/PY.el" "leim/quail/Punct-b5.el"
+;;;;;; "leim/quail/Punct.el" "leim/quail/QJ-b5.el" "leim/quail/QJ.el"
+;;;;;; "leim/quail/SW.el" "leim/quail/TONEPY.el" "leim/quail/ZIRANMA.el"
+;;;;;; "leim/quail/ZOZY.el" "leim/quail/arabic.el" "leim/quail/cham.el"
+;;;;;; "leim/quail/compose.el" "leim/quail/croatian.el" "leim/quail/cyril-jis.el"
+;;;;;; "leim/quail/cyrillic.el" "leim/quail/czech.el" "leim/quail/emoji.el"
;;;;;; "leim/quail/georgian.el" "leim/quail/greek.el" "leim/quail/hanja-jis.el"
;;;;;; "leim/quail/hanja.el" "leim/quail/hanja3.el" "leim/quail/hebrew.el"
;;;;;; "leim/quail/ipa-praat.el" "leim/quail/latin-alt.el" "leim/quail/latin-ltx.el"
diff --git a/lisp/leim/quail/emoji.el b/lisp/leim/quail/emoji.el
new file mode 100644
index 00000000000..f9d3e170be5
--- /dev/null
+++ b/lisp/leim/quail/emoji.el
@@ -0,0 +1,2003 @@
+;;; emoji.el --- Quail package for emoji character composition -*- lexical-binding: t -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Author: Juri Linkov <juri@linkov.net>
+;; Keywords: multilingual, input method, i18n
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This input method supports the same key sequences as the names
+;; defined by the `C-x 8 e s' completions in emoji.el. Also it adds
+;; more emoji that enclosed in double colons.
+
+;; You can enable this input method transiently with `C-u C-x \ emoji RET'.
+;; Then typing `C-x \' will enable this input method temporarily, and
+;; after typing a key sequence it will be disabled. So typing
+;; e.g. `C-x \ : )' will insert the smiling character, and disable
+;; this input method automatically afterwards.
+
+;;; Code:
+
+(require 'quail)
+
+(quail-define-package
+ "emoji" "UTF-8" "🙂" t
+ "Emoji input method for inserting emoji characters.
+Examples:
+ slightly smiling face -> 🙂
+ :slightly_smiling_face: -> 🙂
+ :-) -> 🙂"
+ '(("\t" . quail-completion))
+ t nil nil nil nil nil nil nil nil t)
+
+(eval-when-compile
+ (require 'emoji)
+ (emoji--init)
+ (defmacro emoji--define-rules ()
+ `(quail-define-rules
+ ,@(let ((rules nil))
+ (maphash (lambda (from to)
+ (push (list from (if (stringp to)
+ (vector to)
+ to))
+ rules))
+ emoji--all-bases)
+ (append
+ rules
+ '((":hash:" ["#️⃣"])
+ (":keycap_star:" ["*️⃣"])
+ (":zero:" ["0️⃣"])
+ (":one:" ["1️⃣"])
+ (":two:" ["2️⃣"])
+ (":three:" ["3️⃣"])
+ (":four:" ["4️⃣"])
+ (":five:" ["5️⃣"])
+ (":six:" ["6️⃣"])
+ (":seven:" ["7️⃣"])
+ (":eight:" ["8️⃣"])
+ (":nine:" ["9️⃣"])
+ (":copyright:" ["©️"])
+ (":registered:" ["®️"])
+ (":mahjong:" ["🀄"])
+ (":black_joker:" ["🃏"])
+ (":a:" ["🅰️"])
+ (":b:" ["🅱️"])
+ (":o2:" ["🅾️"])
+ (":parking:" ["🅿️"])
+ (":ab:" ["🆎"])
+ (":cl:" ["🆑"])
+ (":cool:" ["🆒"])
+ (":free:" ["🆓"])
+ (":id:" ["🆔"])
+ (":new:" ["🆕"])
+ (":ng:" ["🆖"])
+ (":ok:" ["🆗"])
+ (":sos:" ["🆘"])
+ (":up:" ["🆙"])
+ (":vs:" ["🆚"])
+ (":flag-ac:" ["🇦🇨"])
+ (":flag-ad:" ["🇦🇩"])
+ (":flag-ae:" ["🇦🇪"])
+ (":flag-af:" ["🇦🇫"])
+ (":flag-ag:" ["🇦🇬"])
+ (":flag-ai:" ["🇦🇮"])
+ (":flag-al:" ["🇦🇱"])
+ (":flag-am:" ["🇦🇲"])
+ (":flag-ao:" ["🇦🇴"])
+ (":flag-aq:" ["🇦🇶"])
+ (":flag-ar:" ["🇦🇷"])
+ (":flag-as:" ["🇦🇸"])
+ (":flag-at:" ["🇦🇹"])
+ (":flag-au:" ["🇦🇺"])
+ (":flag-aw:" ["🇦🇼"])
+ (":flag-ax:" ["🇦🇽"])
+ (":flag-az:" ["🇦🇿"])
+ (":flag-ba:" ["🇧🇦"])
+ (":flag-bb:" ["🇧🇧"])
+ (":flag-bd:" ["🇧🇩"])
+ (":flag-be:" ["🇧🇪"])
+ (":flag-bf:" ["🇧🇫"])
+ (":flag-bg:" ["🇧🇬"])
+ (":flag-bh:" ["🇧🇭"])
+ (":flag-bi:" ["🇧🇮"])
+ (":flag-bj:" ["🇧🇯"])
+ (":flag-bl:" ["🇧🇱"])
+ (":flag-bm:" ["🇧🇲"])
+ (":flag-bn:" ["🇧🇳"])
+ (":flag-bo:" ["🇧🇴"])
+ (":flag-bq:" ["🇧🇶"])
+ (":flag-br:" ["🇧🇷"])
+ (":flag-bs:" ["🇧🇸"])
+ (":flag-bt:" ["🇧🇹"])
+ (":flag-bv:" ["🇧🇻"])
+ (":flag-bw:" ["🇧🇼"])
+ (":flag-by:" ["🇧🇾"])
+ (":flag-bz:" ["🇧🇿"])
+ (":flag-ca:" ["🇨🇦"])
+ (":flag-cc:" ["🇨🇨"])
+ (":flag-cd:" ["🇨🇩"])
+ (":flag-cf:" ["🇨🇫"])
+ (":flag-cg:" ["🇨🇬"])
+ (":flag-ch:" ["🇨🇭"])
+ (":flag-ci:" ["🇨🇮"])
+ (":flag-ck:" ["🇨🇰"])
+ (":flag-cl:" ["🇨🇱"])
+ (":flag-cm:" ["🇨🇲"])
+ (":cn:" ["🇨🇳"])
+ (":flag-cn:" ["🇨🇳"])
+ (":flag-co:" ["🇨🇴"])
+ (":flag-cp:" ["🇨🇵"])
+ (":flag-cr:" ["🇨🇷"])
+ (":flag-cu:" ["🇨🇺"])
+ (":flag-cv:" ["🇨🇻"])
+ (":flag-cw:" ["🇨🇼"])
+ (":flag-cx:" ["🇨🇽"])
+ (":flag-cy:" ["🇨🇾"])
+ (":flag-cz:" ["🇨🇿"])
+ (":de:" ["🇩🇪"])
+ (":flag-de:" ["🇩🇪"])
+ (":flag-dg:" ["🇩🇬"])
+ (":flag-dj:" ["🇩🇯"])
+ (":flag-dk:" ["🇩🇰"])
+ (":flag-dm:" ["🇩🇲"])
+ (":flag-do:" ["🇩🇴"])
+ (":flag-dz:" ["🇩🇿"])
+ (":flag-ea:" ["🇪🇦"])
+ (":flag-ec:" ["🇪🇨"])
+ (":flag-ee:" ["🇪🇪"])
+ (":flag-eg:" ["🇪🇬"])
+ (":flag-eh:" ["🇪🇭"])
+ (":flag-er:" ["🇪🇷"])
+ (":es:" ["🇪🇸"])
+ (":flag-es:" ["🇪🇸"])
+ (":flag-et:" ["🇪🇹"])
+ (":flag-eu:" ["🇪🇺"])
+ (":flag-fi:" ["🇫🇮"])
+ (":flag-fj:" ["🇫🇯"])
+ (":flag-fk:" ["🇫🇰"])
+ (":flag-fm:" ["🇫🇲"])
+ (":flag-fo:" ["🇫🇴"])
+ (":fr:" ["🇫🇷"])
+ (":flag-fr:" ["🇫🇷"])
+ (":flag-ga:" ["🇬🇦"])
+ (":gb:" ["🇬🇧"])
+ (":uk:" ["🇬🇧"])
+ (":flag-gb:" ["🇬🇧"])
+ (":flag-gd:" ["🇬🇩"])
+ (":flag-ge:" ["🇬🇪"])
+ (":flag-gf:" ["🇬🇫"])
+ (":flag-gg:" ["🇬🇬"])
+ (":flag-gh:" ["🇬🇭"])
+ (":flag-gi:" ["🇬🇮"])
+ (":flag-gl:" ["🇬🇱"])
+ (":flag-gm:" ["🇬🇲"])
+ (":flag-gn:" ["🇬🇳"])
+ (":flag-gp:" ["🇬🇵"])
+ (":flag-gq:" ["🇬🇶"])
+ (":flag-gr:" ["🇬🇷"])
+ (":flag-gs:" ["🇬🇸"])
+ (":flag-gt:" ["🇬🇹"])
+ (":flag-gu:" ["🇬🇺"])
+ (":flag-gw:" ["🇬🇼"])
+ (":flag-gy:" ["🇬🇾"])
+ (":flag-hk:" ["🇭🇰"])
+ (":flag-hm:" ["🇭🇲"])
+ (":flag-hn:" ["🇭🇳"])
+ (":flag-hr:" ["🇭🇷"])
+ (":flag-ht:" ["🇭🇹"])
+ (":flag-hu:" ["🇭🇺"])
+ (":flag-ic:" ["🇮🇨"])
+ (":flag-id:" ["🇮🇩"])
+ (":flag-ie:" ["🇮🇪"])
+ (":flag-il:" ["🇮🇱"])
+ (":flag-im:" ["🇮🇲"])
+ (":flag-in:" ["🇮🇳"])
+ (":flag-io:" ["🇮🇴"])
+ (":flag-iq:" ["🇮🇶"])
+ (":flag-ir:" ["🇮🇷"])
+ (":flag-is:" ["🇮🇸"])
+ (":it:" ["🇮🇹"])
+ (":flag-it:" ["🇮🇹"])
+ (":flag-je:" ["🇯🇪"])
+ (":flag-jm:" ["🇯🇲"])
+ (":flag-jo:" ["🇯🇴"])
+ (":jp:" ["🇯🇵"])
+ (":flag-jp:" ["🇯🇵"])
+ (":flag-ke:" ["🇰🇪"])
+ (":flag-kg:" ["🇰🇬"])
+ (":flag-kh:" ["🇰🇭"])
+ (":flag-ki:" ["🇰🇮"])
+ (":flag-km:" ["🇰🇲"])
+ (":flag-kn:" ["🇰🇳"])
+ (":flag-kp:" ["🇰🇵"])
+ (":kr:" ["🇰🇷"])
+ (":flag-kr:" ["🇰🇷"])
+ (":flag-kw:" ["🇰🇼"])
+ (":flag-ky:" ["🇰🇾"])
+ (":flag-kz:" ["🇰🇿"])
+ (":flag-la:" ["🇱🇦"])
+ (":flag-lb:" ["🇱🇧"])
+ (":flag-lc:" ["🇱🇨"])
+ (":flag-li:" ["🇱🇮"])
+ (":flag-lk:" ["🇱🇰"])
+ (":flag-lr:" ["🇱🇷"])
+ (":flag-ls:" ["🇱🇸"])
+ (":flag-lt:" ["🇱🇹"])
+ (":flag-lu:" ["🇱🇺"])
+ (":flag-lv:" ["🇱🇻"])
+ (":flag-ly:" ["🇱🇾"])
+ (":flag-ma:" ["🇲🇦"])
+ (":flag-mc:" ["🇲🇨"])
+ (":flag-md:" ["🇲🇩"])
+ (":flag-me:" ["🇲🇪"])
+ (":flag-mf:" ["🇲🇫"])
+ (":flag-mg:" ["🇲🇬"])
+ (":flag-mh:" ["🇲🇭"])
+ (":flag-mk:" ["🇲🇰"])
+ (":flag-ml:" ["🇲🇱"])
+ (":flag-mm:" ["🇲🇲"])
+ (":flag-mn:" ["🇲🇳"])
+ (":flag-mo:" ["🇲🇴"])
+ (":flag-mp:" ["🇲🇵"])
+ (":flag-mq:" ["🇲🇶"])
+ (":flag-mr:" ["🇲🇷"])
+ (":flag-ms:" ["🇲🇸"])
+ (":flag-mt:" ["🇲🇹"])
+ (":flag-mu:" ["🇲🇺"])
+ (":flag-mv:" ["🇲🇻"])
+ (":flag-mw:" ["🇲🇼"])
+ (":flag-mx:" ["🇲🇽"])
+ (":flag-my:" ["🇲🇾"])
+ (":flag-mz:" ["🇲🇿"])
+ (":flag-na:" ["🇳🇦"])
+ (":flag-nc:" ["🇳🇨"])
+ (":flag-ne:" ["🇳🇪"])
+ (":flag-nf:" ["🇳🇫"])
+ (":flag-ng:" ["🇳🇬"])
+ (":flag-ni:" ["🇳🇮"])
+ (":flag-nl:" ["🇳🇱"])
+ (":flag-no:" ["🇳🇴"])
+ (":flag-np:" ["🇳🇵"])
+ (":flag-nr:" ["🇳🇷"])
+ (":flag-nu:" ["🇳🇺"])
+ (":flag-nz:" ["🇳🇿"])
+ (":flag-om:" ["🇴🇲"])
+ (":flag-pa:" ["🇵🇦"])
+ (":flag-pe:" ["🇵🇪"])
+ (":flag-pf:" ["🇵🇫"])
+ (":flag-pg:" ["🇵🇬"])
+ (":flag-ph:" ["🇵🇭"])
+ (":flag-pk:" ["🇵🇰"])
+ (":flag-pl:" ["🇵🇱"])
+ (":flag-pm:" ["🇵🇲"])
+ (":flag-pn:" ["🇵🇳"])
+ (":flag-pr:" ["🇵🇷"])
+ (":flag-ps:" ["🇵🇸"])
+ (":flag-pt:" ["🇵🇹"])
+ (":flag-pw:" ["🇵🇼"])
+ (":flag-py:" ["🇵🇾"])
+ (":flag-qa:" ["🇶🇦"])
+ (":flag-re:" ["🇷🇪"])
+ (":flag-ro:" ["🇷🇴"])
+ (":flag-rs:" ["🇷🇸"])
+ (":ru:" ["🇷🇺"])
+ (":flag-ru:" ["🇷🇺"])
+ (":flag-rw:" ["🇷🇼"])
+ (":flag-sa:" ["🇸🇦"])
+ (":flag-sb:" ["🇸🇧"])
+ (":flag-sc:" ["🇸🇨"])
+ (":flag-sd:" ["🇸🇩"])
+ (":flag-se:" ["🇸🇪"])
+ (":flag-sg:" ["🇸🇬"])
+ (":flag-sh:" ["🇸🇭"])
+ (":flag-si:" ["🇸🇮"])
+ (":flag-sj:" ["🇸🇯"])
+ (":flag-sk:" ["🇸🇰"])
+ (":flag-sl:" ["🇸🇱"])
+ (":flag-sm:" ["🇸🇲"])
+ (":flag-sn:" ["🇸🇳"])
+ (":flag-so:" ["🇸🇴"])
+ (":flag-sr:" ["🇸🇷"])
+ (":flag-ss:" ["🇸🇸"])
+ (":flag-st:" ["🇸🇹"])
+ (":flag-sv:" ["🇸🇻"])
+ (":flag-sx:" ["🇸🇽"])
+ (":flag-sy:" ["🇸🇾"])
+ (":flag-sz:" ["🇸🇿"])
+ (":flag-ta:" ["🇹🇦"])
+ (":flag-tc:" ["🇹🇨"])
+ (":flag-td:" ["🇹🇩"])
+ (":flag-tf:" ["🇹🇫"])
+ (":flag-tg:" ["🇹🇬"])
+ (":flag-th:" ["🇹🇭"])
+ (":flag-tj:" ["🇹🇯"])
+ (":flag-tk:" ["🇹🇰"])
+ (":flag-tl:" ["🇹🇱"])
+ (":flag-tm:" ["🇹🇲"])
+ (":flag-tn:" ["🇹🇳"])
+ (":flag-to:" ["🇹🇴"])
+ (":flag-tr:" ["🇹🇷"])
+ (":flag-tt:" ["🇹🇹"])
+ (":flag-tv:" ["🇹🇻"])
+ (":flag-tw:" ["🇹🇼"])
+ (":flag-tz:" ["🇹🇿"])
+ (":flag-ua:" ["🇺🇦"])
+ (":flag-ug:" ["🇺🇬"])
+ (":flag-um:" ["🇺🇲"])
+ (":flag-un:" ["🇺🇳"])
+ (":us:" ["🇺🇸"])
+ (":flag-us:" ["🇺🇸"])
+ (":flag-uy:" ["🇺🇾"])
+ (":flag-uz:" ["🇺🇿"])
+ (":flag-va:" ["🇻🇦"])
+ (":flag-vc:" ["🇻🇨"])
+ (":flag-ve:" ["🇻🇪"])
+ (":flag-vg:" ["🇻🇬"])
+ (":flag-vi:" ["🇻🇮"])
+ (":flag-vn:" ["🇻🇳"])
+ (":flag-vu:" ["🇻🇺"])
+ (":flag-wf:" ["🇼🇫"])
+ (":flag-ws:" ["🇼🇸"])
+ (":flag-xk:" ["🇽🇰"])
+ (":flag-ye:" ["🇾🇪"])
+ (":flag-yt:" ["🇾🇹"])
+ (":flag-za:" ["🇿🇦"])
+ (":flag-zm:" ["🇿🇲"])
+ (":flag-zw:" ["🇿🇼"])
+ (":koko:" ["🈁"])
+ (":sa:" ["🈂️"])
+ (":u7121:" ["🈚"])
+ (":u6307:" ["🈯"])
+ (":u7981:" ["🈲"])
+ (":u7a7a:" ["🈳"])
+ (":u5408:" ["🈴"])
+ (":u6e80:" ["🈵"])
+ (":u6709:" ["🈶"])
+ (":u6708:" ["🈷️"])
+ (":u7533:" ["🈸"])
+ (":u5272:" ["🈹"])
+ (":u55b6:" ["🈺"])
+ (":ideograph_advantage:" ["🉐"])
+ (":accept:" ["🉑"])
+ (":cyclone:" ["🌀"])
+ (":foggy:" ["🌁"])
+ (":closed_umbrella:" ["🌂"])
+ (":night_with_stars:" ["🌃"])
+ (":sunrise_over_mountains:" ["🌄"])
+ (":sunrise:" ["🌅"])
+ (":city_sunset:" ["🌆"])
+ (":city_sunrise:" ["🌇"])
+ (":rainbow:" ["🌈"])
+ (":bridge_at_night:" ["🌉"])
+ (":ocean:" ["🌊"])
+ (":volcano:" ["🌋"])
+ (":milky_way:" ["🌌"])
+ (":earth_africa:" ["🌍"])
+ (":earth_americas:" ["🌎"])
+ (":earth_asia:" ["🌏"])
+ (":globe_with_meridians:" ["🌐"])
+ (":new_moon:" ["🌑"])
+ (":waxing_crescent_moon:" ["🌒"])
+ (":first_quarter_moon:" ["🌓"])
+ (":moon:" ["🌔"])
+ (":waxing_gibbous_moon:" ["🌔"])
+ (":full_moon:" ["🌕"])
+ (":waning_gibbous_moon:" ["🌖"])
+ (":last_quarter_moon:" ["🌗"])
+ (":waning_crescent_moon:" ["🌘"])
+ (":crescent_moon:" ["🌙"])
+ (":new_moon_with_face:" ["🌚"])
+ (":first_quarter_moon_with_face:" ["🌛"])
+ (":last_quarter_moon_with_face:" ["🌜"])
+ (":full_moon_with_face:" ["🌝"])
+ (":sun_with_face:" ["🌞"])
+ (":star2:" ["🌟"])
+ (":stars:" ["🌠"])
+ (":thermometer:" ["🌡️"])
+ (":mostly_sunny:" ["🌤️"])
+ (":sun_small_cloud:" ["🌤️"])
+ (":barely_sunny:" ["🌥️"])
+ (":sun_behind_cloud:" ["🌥️"])
+ (":partly_sunny_rain:" ["🌦️"])
+ (":sun_behind_rain_cloud:" ["🌦️"])
+ (":rain_cloud:" ["🌧️"])
+ (":snow_cloud:" ["🌨️"])
+ (":lightning:" ["🌩️"])
+ (":lightning_cloud:" ["🌩️"])
+ (":tornado:" ["🌪️"])
+ (":tornado_cloud:" ["🌪️"])
+ (":fog:" ["🌫️"])
+ (":wind_blowing_face:" ["🌬️"])
+ (":hotdog:" ["🌭"])
+ (":taco:" ["🌮"])
+ (":burrito:" ["🌯"])
+ (":chestnut:" ["🌰"])
+ (":seedling:" ["🌱"])
+ (":evergreen_tree:" ["🌲"])
+ (":deciduous_tree:" ["🌳"])
+ (":palm_tree:" ["🌴"])
+ (":cactus:" ["🌵"])
+ (":hot_pepper:" ["🌶️"])
+ (":tulip:" ["🌷"])
+ (":cherry_blossom:" ["🌸"])
+ (":rose:" ["🌹"])
+ (":hibiscus:" ["🌺"])
+ (":sunflower:" ["🌻"])
+ (":blossom:" ["🌼"])
+ (":corn:" ["🌽"])
+ (":ear_of_rice:" ["🌾"])
+ (":herb:" ["🌿"])
+ (":four_leaf_clover:" ["🍀"])
+ (":maple_leaf:" ["🍁"])
+ (":fallen_leaf:" ["🍂"])
+ (":leaves:" ["🍃"])
+ (":mushroom:" ["🍄"])
+ (":tomato:" ["🍅"])
+ (":eggplant:" ["🍆"])
+ (":grapes:" ["🍇"])
+ (":melon:" ["🍈"])
+ (":watermelon:" ["🍉"])
+ (":tangerine:" ["🍊"])
+ (":lemon:" ["🍋"])
+ (":banana:" ["🍌"])
+ (":pineapple:" ["🍍"])
+ (":apple:" ["🍎"])
+ (":green_apple:" ["🍏"])
+ (":pear:" ["🍐"])
+ (":peach:" ["🍑"])
+ (":cherries:" ["🍒"])
+ (":strawberry:" ["🍓"])
+ (":hamburger:" ["🍔"])
+ (":pizza:" ["🍕"])
+ (":meat_on_bone:" ["🍖"])
+ (":poultry_leg:" ["🍗"])
+ (":rice_cracker:" ["🍘"])
+ (":rice_ball:" ["🍙"])
+ (":rice:" ["🍚"])
+ (":curry:" ["🍛"])
+ (":ramen:" ["🍜"])
+ (":spaghetti:" ["🍝"])
+ (":bread:" ["🍞"])
+ (":fries:" ["🍟"])
+ (":sweet_potato:" ["🍠"])
+ (":dango:" ["🍡"])
+ (":oden:" ["🍢"])
+ (":sushi:" ["🍣"])
+ (":fried_shrimp:" ["🍤"])
+ (":fish_cake:" ["🍥"])
+ (":icecream:" ["🍦"])
+ (":shaved_ice:" ["🍧"])
+ (":ice_cream:" ["🍨"])
+ (":doughnut:" ["🍩"])
+ (":cookie:" ["🍪"])
+ (":chocolate_bar:" ["🍫"])
+ (":candy:" ["🍬"])
+ (":lollipop:" ["🍭"])
+ (":custard:" ["🍮"])
+ (":honey_pot:" ["🍯"])
+ (":cake:" ["🍰"])
+ (":bento:" ["🍱"])
+ (":stew:" ["🍲"])
+ (":fried_egg:" ["🍳"])
+ (":cooking:" ["🍳"])
+ (":fork_and_knife:" ["🍴"])
+ (":tea:" ["🍵"])
+ (":sake:" ["🍶"])
+ (":wine_glass:" ["🍷"])
+ (":cocktail:" ["🍸"])
+ (":tropical_drink:" ["🍹"])
+ (":beer:" ["🍺"])
+ (":beers:" ["🍻"])
+ (":baby_bottle:" ["🍼"])
+ (":knife_fork_plate:" ["🍽️"])
+ (":champagne:" ["🍾"])
+ (":popcorn:" ["🍿"])
+ (":ribbon:" ["🎀"])
+ (":gift:" ["🎁"])
+ (":birthday:" ["🎂"])
+ (":jack_o_lantern:" ["🎃"])
+ (":christmas_tree:" ["🎄"])
+ (":santa:" ["🎅"])
+ (":fireworks:" ["🎆"])
+ (":sparkler:" ["🎇"])
+ (":balloon:" ["🎈"])
+ (":tada:" ["🎉"])
+ (":confetti_ball:" ["🎊"])
+ (":tanabata_tree:" ["🎋"])
+ (":crossed_flags:" ["🎌"])
+ (":bamboo:" ["🎍"])
+ (":dolls:" ["🎎"])
+ (":flags:" ["🎏"])
+ (":wind_chime:" ["🎐"])
+ (":rice_scene:" ["🎑"])
+ (":school_satchel:" ["🎒"])
+ (":mortar_board:" ["🎓"])
+ (":medal:" ["🎖️"])
+ (":reminder_ribbon:" ["🎗️"])
+ (":studio_microphone:" ["🎙️"])
+ (":level_slider:" ["🎚️"])
+ (":control_knobs:" ["🎛️"])
+ (":film_frames:" ["🎞️"])
+ (":admission_tickets:" ["🎟️"])
+ (":carousel_horse:" ["🎠"])
+ (":ferris_wheel:" ["🎡"])
+ (":roller_coaster:" ["🎢"])
+ (":fishing_pole_and_fish:" ["🎣"])
+ (":microphone:" ["🎤"])
+ (":movie_camera:" ["🎥"])
+ (":cinema:" ["🎦"])
+ (":headphones:" ["🎧"])
+ (":art:" ["🎨"])
+ (":tophat:" ["🎩"])
+ (":circus_tent:" ["🎪"])
+ (":ticket:" ["🎫"])
+ (":clapper:" ["🎬"])
+ (":performing_arts:" ["🎭"])
+ (":video_game:" ["🎮"])
+ (":dart:" ["🎯"])
+ (":slot_machine:" ["🎰"])
+ (":8ball:" ["🎱"])
+ (":game_die:" ["🎲"])
+ (":bowling:" ["🎳"])
+ (":flower_playing_cards:" ["🎴"])
+ (":musical_note:" ["🎵"])
+ (":notes:" ["🎶"])
+ (":saxophone:" ["🎷"])
+ (":guitar:" ["🎸"])
+ (":musical_keyboard:" ["🎹"])
+ (":trumpet:" ["🎺"])
+ (":violin:" ["🎻"])
+ (":musical_score:" ["🎼"])
+ (":running_shirt_with_sash:" ["🎽"])
+ (":tennis:" ["🎾"])
+ (":ski:" ["🎿"])
+ (":basketball:" ["🏀"])
+ (":checkered_flag:" ["🏁"])
+ (":snowboarder:" ["🏂"])
+ (":woman-running:" ["🏃‍♀️"])
+ (":man-running:" ["🏃‍♂️"])
+ (":runner:" ["🏃"])
+ (":running:" ["🏃"])
+ (":woman-surfing:" ["🏄‍♀️"])
+ (":man-surfing:" ["🏄‍♂️"])
+ (":surfer:" ["🏄"])
+ (":sports_medal:" ["🏅"])
+ (":trophy:" ["🏆"])
+ (":horse_racing:" ["🏇"])
+ (":football:" ["🏈"])
+ (":rugby_football:" ["🏉"])
+ (":woman-swimming:" ["🏊‍♀️"])
+ (":man-swimming:" ["🏊‍♂️"])
+ (":swimmer:" ["🏊"])
+ (":woman-lifting-weights:" ["🏋️‍♀️"])
+ (":man-lifting-weights:" ["🏋️‍♂️"])
+ (":weight_lifter:" ["🏋️"])
+ (":woman-golfing:" ["🏌️‍♀️"])
+ (":man-golfing:" ["🏌️‍♂️"])
+ (":golfer:" ["🏌️"])
+ (":racing_motorcycle:" ["🏍️"])
+ (":racing_car:" ["🏎️"])
+ (":cricket_bat_and_ball:" ["🏏"])
+ (":volleyball:" ["🏐"])
+ (":field_hockey_stick_and_ball:" ["🏑"])
+ (":ice_hockey_stick_and_puck:" ["🏒"])
+ (":table_tennis_paddle_and_ball:" ["🏓"])
+ (":snow_capped_mountain:" ["🏔️"])
+ (":camping:" ["🏕️"])
+ (":beach_with_umbrella:" ["🏖️"])
+ (":building_construction:" ["🏗️"])
+ (":house_buildings:" ["🏘️"])
+ (":cityscape:" ["🏙️"])
+ (":derelict_house_building:" ["🏚️"])
+ (":classical_building:" ["🏛️"])
+ (":desert:" ["🏜️"])
+ (":desert_island:" ["🏝️"])
+ (":national_park:" ["🏞️"])
+ (":stadium:" ["🏟️"])
+ (":house:" ["🏠"])
+ (":house_with_garden:" ["🏡"])
+ (":office:" ["🏢"])
+ (":post_office:" ["🏣"])
+ (":european_post_office:" ["🏤"])
+ (":hospital:" ["🏥"])
+ (":bank:" ["🏦"])
+ (":atm:" ["🏧"])
+ (":hotel:" ["🏨"])
+ (":love_hotel:" ["🏩"])
+ (":convenience_store:" ["🏪"])
+ (":school:" ["🏫"])
+ (":department_store:" ["🏬"])
+ (":factory:" ["🏭"])
+ (":izakaya_lantern:" ["🏮"])
+ (":lantern:" ["🏮"])
+ (":japanese_castle:" ["🏯"])
+ (":european_castle:" ["🏰"])
+ (":rainbow-flag:" ["🏳️‍🌈"])
+ (":transgender_flag:" ["🏳️‍⚧️"])
+ (":waving_white_flag:" ["🏳️"])
+ (":pirate_flag:" ["🏴‍☠️"])
+ (":flag-england:" ["🏴󠁧󠁢󠁥󠁮󠁧󠁿"])
+ (":flag-scotland:" ["🏴󠁧󠁢󠁳󠁣󠁴󠁿"])
+ (":flag-wales:" ["🏴󠁧󠁢󠁷󠁬󠁳󠁿"])
+ (":waving_black_flag:" ["🏴"])
+ (":rosette:" ["🏵️"])
+ (":label:" ["🏷️"])
+ (":badminton_racquet_and_shuttlecock:" ["🏸"])
+ (":bow_and_arrow:" ["🏹"])
+ (":amphora:" ["🏺"])
+ (":skin-tone-2:" ["🏻"])
+ (":skin-tone-3:" ["🏼"])
+ (":skin-tone-4:" ["🏽"])
+ (":skin-tone-5:" ["🏾"])
+ (":skin-tone-6:" ["🏿"])
+ (":rat:" ["🐀"])
+ (":mouse2:" ["🐁"])
+ (":ox:" ["🐂"])
+ (":water_buffalo:" ["🐃"])
+ (":cow2:" ["🐄"])
+ (":tiger2:" ["🐅"])
+ (":leopard:" ["🐆"])
+ (":rabbit2:" ["🐇"])
+ (":black_cat:" ["🐈‍⬛"])
+ (":cat2:" ["🐈"])
+ (":dragon:" ["🐉"])
+ (":crocodile:" ["🐊"])
+ (":whale2:" ["🐋"])
+ (":snail:" ["🐌"])
+ (":snake:" ["🐍"])
+ (":racehorse:" ["🐎"])
+ (":ram:" ["🐏"])
+ (":goat:" ["🐐"])
+ (":sheep:" ["🐑"])
+ (":monkey:" ["🐒"])
+ (":rooster:" ["🐓"])
+ (":chicken:" ["🐔"])
+ (":service_dog:" ["🐕‍🦺"])
+ (":dog2:" ["🐕"])
+ (":pig2:" ["🐖"])
+ (":boar:" ["🐗"])
+ (":elephant:" ["🐘"])
+ (":octopus:" ["🐙"])
+ (":shell:" ["🐚"])
+ (":bug:" ["🐛"])
+ (":ant:" ["🐜"])
+ (":bee:" ["🐝"])
+ (":honeybee:" ["🐝"])
+ (":ladybug:" ["🐞"])
+ (":lady_beetle:" ["🐞"])
+ (":fish:" ["🐟"])
+ (":tropical_fish:" ["🐠"])
+ (":blowfish:" ["🐡"])
+ (":turtle:" ["🐢"])
+ (":hatching_chick:" ["🐣"])
+ (":baby_chick:" ["🐤"])
+ (":hatched_chick:" ["🐥"])
+ (":bird:" ["🐦"])
+ (":penguin:" ["🐧"])
+ (":koala:" ["🐨"])
+ (":poodle:" ["🐩"])
+ (":dromedary_camel:" ["🐪"])
+ (":camel:" ["🐫"])
+ (":dolphin:" ["🐬"])
+ (":flipper:" ["🐬"])
+ (":mouse:" ["🐭"])
+ (":cow:" ["🐮"])
+ (":tiger:" ["🐯"])
+ (":rabbit:" ["🐰"])
+ (":cat:" ["🐱"])
+ (":dragon_face:" ["🐲"])
+ (":whale:" ["🐳"])
+ (":horse:" ["🐴"])
+ (":monkey_face:" ["🐵"])
+ (":o)" ["🐵"])
+ (":dog:" ["🐶"])
+ (":pig:" ["🐷"])
+ (":frog:" ["🐸"])
+ (":hamster:" ["🐹"])
+ (":wolf:" ["🐺"])
+ (":polar_bear:" ["🐻‍❄️"])
+ (":bear:" ["🐻"])
+ (":panda_face:" ["🐼"])
+ (":pig_nose:" ["🐽"])
+ (":feet:" ["🐾"])
+ (":paw_prints:" ["🐾"])
+ (":chipmunk:" ["🐿️"])
+ (":eyes:" ["👀"])
+ (":eye-in-speech-bubble:" ["👁️‍🗨️"])
+ (":eye:" ["👁️"])
+ (":ear:" ["👂"])
+ (":nose:" ["👃"])
+ (":lips:" ["👄"])
+ (":tongue:" ["👅"])
+ (":point_up_2:" ["👆"])
+ (":point_down:" ["👇"])
+ (":point_left:" ["👈"])
+ (":point_right:" ["👉"])
+ (":facepunch:" ["👊"])
+ (":punch:" ["👊"])
+ (":wave:" ["👋"])
+ (":ok_hand:" ["👌"])
+ (":+1:" ["👍"])
+ (":thumbsup:" ["👍"])
+ (":-1:" ["👎"])
+ (":thumbsdown:" ["👎"])
+ (":clap:" ["👏"])
+ (":open_hands:" ["👐"])
+ (":crown:" ["👑"])
+ (":womans_hat:" ["👒"])
+ (":eyeglasses:" ["👓"])
+ (":necktie:" ["👔"])
+ (":shirt:" ["👕"])
+ (":tshirt:" ["👕"])
+ (":jeans:" ["👖"])
+ (":dress:" ["👗"])
+ (":kimono:" ["👘"])
+ (":bikini:" ["👙"])
+ (":womans_clothes:" ["👚"])
+ (":purse:" ["👛"])
+ (":handbag:" ["👜"])
+ (":pouch:" ["👝"])
+ (":mans_shoe:" ["👞"])
+ (":shoe:" ["👞"])
+ (":athletic_shoe:" ["👟"])
+ (":high_heel:" ["👠"])
+ (":sandal:" ["👡"])
+ (":boot:" ["👢"])
+ (":footprints:" ["👣"])
+ (":bust_in_silhouette:" ["👤"])
+ (":busts_in_silhouette:" ["👥"])
+ (":boy:" ["👦"])
+ (":girl:" ["👧"])
+ (":male-farmer:" ["👨‍🌾"])
+ (":male-cook:" ["👨‍🍳"])
+ (":man_feeding_baby:" ["👨‍🍼"])
+ (":male-student:" ["👨‍🎓"])
+ (":male-singer:" ["👨‍🎤"])
+ (":male-artist:" ["👨‍🎨"])
+ (":male-teacher:" ["👨‍🏫"])
+ (":male-factory-worker:" ["👨‍🏭"])
+ (":man-boy-boy:" ["👨‍👦‍👦"])
+ (":man-boy:" ["👨‍👦"])
+ (":man-girl-boy:" ["👨‍👧‍👦"])
+ (":man-girl-girl:" ["👨‍👧‍👧"])
+ (":man-girl:" ["👨‍👧"])
+ (":man-man-boy:" ["👨‍👨‍👦"])
+ (":man-man-boy-boy:" ["👨‍👨‍👦‍👦"])
+ (":man-man-girl:" ["👨‍👨‍👧"])
+ (":man-man-girl-boy:" ["👨‍👨‍👧‍👦"])
+ (":man-man-girl-girl:" ["👨‍👨‍👧‍👧"])
+ (":man-woman-boy:" ["👨‍👩‍👦"])
+ (":man-woman-boy-boy:" ["👨‍👩‍👦‍👦"])
+ (":man-woman-girl:" ["👨‍👩‍👧"])
+ (":man-woman-girl-boy:" ["👨‍👩‍👧‍👦"])
+ (":man-woman-girl-girl:" ["👨‍👩‍👧‍👧"])
+ (":male-technologist:" ["👨‍💻"])
+ (":male-office-worker:" ["👨‍💼"])
+ (":male-mechanic:" ["👨‍🔧"])
+ (":male-scientist:" ["👨‍🔬"])
+ (":male-astronaut:" ["👨‍🚀"])
+ (":male-firefighter:" ["👨‍🚒"])
+ (":man_with_probing_cane:" ["👨‍🦯"])
+ (":red_haired_man:" ["👨‍🦰"])
+ (":curly_haired_man:" ["👨‍🦱"])
+ (":bald_man:" ["👨‍🦲"])
+ (":white_haired_man:" ["👨‍🦳"])
+ (":man_in_motorized_wheelchair:" ["👨‍🦼"])
+ (":man_in_manual_wheelchair:" ["👨‍🦽"])
+ (":male-doctor:" ["👨‍⚕️"])
+ (":male-judge:" ["👨‍⚖️"])
+ (":male-pilot:" ["👨‍✈️"])
+ (":man-heart-man:" ["👨‍❤️‍👨"])
+ (":man-kiss-man:" ["👨‍❤️‍💋‍👨"])
+ (":man:" ["👨"])
+ (":female-farmer:" ["👩‍🌾"])
+ (":female-cook:" ["👩‍🍳"])
+ (":woman_feeding_baby:" ["👩‍🍼"])
+ (":female-student:" ["👩‍🎓"])
+ (":female-singer:" ["👩‍🎤"])
+ (":female-artist:" ["👩‍🎨"])
+ (":female-teacher:" ["👩‍🏫"])
+ (":female-factory-worker:" ["👩‍🏭"])
+ (":woman-boy-boy:" ["👩‍👦‍👦"])
+ (":woman-boy:" ["👩‍👦"])
+ (":woman-girl-boy:" ["👩‍👧‍👦"])
+ (":woman-girl-girl:" ["👩‍👧‍👧"])
+ (":woman-girl:" ["👩‍👧"])
+ (":woman-woman-boy:" ["👩‍👩‍👦"])
+ (":woman-woman-boy-boy:" ["👩‍👩‍👦‍👦"])
+ (":woman-woman-girl:" ["👩‍👩‍👧"])
+ (":woman-woman-girl-boy:" ["👩‍👩‍👧‍👦"])
+ (":woman-woman-girl-girl:" ["👩‍👩‍👧‍👧"])
+ (":female-technologist:" ["👩‍💻"])
+ (":female-office-worker:" ["👩‍💼"])
+ (":female-mechanic:" ["👩‍🔧"])
+ (":female-scientist:" ["👩‍🔬"])
+ (":female-astronaut:" ["👩‍🚀"])
+ (":female-firefighter:" ["👩‍🚒"])
+ (":woman_with_probing_cane:" ["👩‍🦯"])
+ (":red_haired_woman:" ["👩‍🦰"])
+ (":curly_haired_woman:" ["👩‍🦱"])
+ (":bald_woman:" ["👩‍🦲"])
+ (":white_haired_woman:" ["👩‍🦳"])
+ (":woman_in_motorized_wheelchair:" ["👩‍🦼"])
+ (":woman_in_manual_wheelchair:" ["👩‍🦽"])
+ (":female-doctor:" ["👩‍⚕️"])
+ (":female-judge:" ["👩‍⚖️"])
+ (":female-pilot:" ["👩‍✈️"])
+ (":woman-heart-man:" ["👩‍❤️‍👨"])
+ (":woman-heart-woman:" ["👩‍❤️‍👩"])
+ (":woman-kiss-man:" ["👩‍❤️‍💋‍👨"])
+ (":woman-kiss-woman:" ["👩‍❤️‍💋‍👩"])
+ (":woman:" ["👩"])
+ (":family:" ["👪"])
+ (":man_and_woman_holding_hands:" ["👫"])
+ (":woman_and_man_holding_hands:" ["👫"])
+ (":couple:" ["👫"])
+ (":two_men_holding_hands:" ["👬"])
+ (":men_holding_hands:" ["👬"])
+ (":two_women_holding_hands:" ["👭"])
+ (":women_holding_hands:" ["👭"])
+ (":female-police-officer:" ["👮‍♀️"])
+ (":male-police-officer:" ["👮‍♂️"])
+ (":cop:" ["👮"])
+ (":women-with-bunny-ears-partying:" ["👯‍♀️"])
+ (":woman-with-bunny-ears-partying:" ["👯‍♀️"])
+ (":men-with-bunny-ears-partying:" ["👯‍♂️"])
+ (":man-with-bunny-ears-partying:" ["👯‍♂️"])
+ (":dancers:" ["👯"])
+ (":woman_with_veil:" ["👰‍♀️"])
+ (":man_with_veil:" ["👰‍♂️"])
+ (":bride_with_veil:" ["👰"])
+ (":blond-haired-woman:" ["👱‍♀️"])
+ (":blond-haired-man:" ["👱‍♂️"])
+ (":person_with_blond_hair:" ["👱"])
+ (":man_with_gua_pi_mao:" ["👲"])
+ (":woman-wearing-turban:" ["👳‍♀️"])
+ (":man-wearing-turban:" ["👳‍♂️"])
+ (":man_with_turban:" ["👳"])
+ (":older_man:" ["👴"])
+ (":older_woman:" ["👵"])
+ (":baby:" ["👶"])
+ (":female-construction-worker:" ["👷‍♀️"])
+ (":male-construction-worker:" ["👷‍♂️"])
+ (":construction_worker:" ["👷"])
+ (":princess:" ["👸"])
+ (":japanese_ogre:" ["👹"])
+ (":japanese_goblin:" ["👺"])
+ (":ghost:" ["👻"])
+ (":angel:" ["👼"])
+ (":alien:" ["👽"])
+ (":space_invader:" ["👾"])
+ (":imp:" ["👿"])
+ (":skull:" ["💀"])
+ (":woman-tipping-hand:" ["💁‍♀️"])
+ (":man-tipping-hand:" ["💁‍♂️"])
+ (":information_desk_person:" ["💁"])
+ (":female-guard:" ["💂‍♀️"])
+ (":male-guard:" ["💂‍♂️"])
+ (":guardsman:" ["💂"])
+ (":dancer:" ["💃"])
+ (":lipstick:" ["💄"])
+ (":nail_care:" ["💅"])
+ (":woman-getting-massage:" ["💆‍♀️"])
+ (":man-getting-massage:" ["💆‍♂️"])
+ (":massage:" ["💆"])
+ (":woman-getting-haircut:" ["💇‍♀️"])
+ (":man-getting-haircut:" ["💇‍♂️"])
+ (":haircut:" ["💇"])
+ (":barber:" ["💈"])
+ (":syringe:" ["💉"])
+ (":pill:" ["💊"])
+ (":kiss:" ["💋"])
+ (":love_letter:" ["💌"])
+ (":ring:" ["💍"])
+ (":gem:" ["💎"])
+ (":couplekiss:" ["💏"])
+ (":bouquet:" ["💐"])
+ (":couple_with_heart:" ["💑"])
+ (":wedding:" ["💒"])
+ (":heartbeat:" ["💓"])
+ (":broken_heart:" ["💔"])
+ ("</3" ["💔"])
+ (":two_hearts:" ["💕"])
+ (":sparkling_heart:" ["💖"])
+ (":heartpulse:" ["💗"])
+ (":cupid:" ["💘"])
+ (":blue_heart:" ["💙"])
+ ("<3" ["💙"])
+ (":green_heart:" ["💚"])
+ ("<3" ["💚"])
+ (":yellow_heart:" ["💛"])
+ ("<3" ["💛"])
+ (":purple_heart:" ["💜"])
+ ("<3" ["💜"])
+ (":gift_heart:" ["💝"])
+ (":revolving_hearts:" ["💞"])
+ (":heart_decoration:" ["💟"])
+ (":diamond_shape_with_a_dot_inside:" ["💠"])
+ (":bulb:" ["💡"])
+ (":anger:" ["💢"])
+ (":bomb:" ["💣"])
+ (":zzz:" ["💤"])
+ (":boom:" ["💥"])
+ (":collision:" ["💥"])
+ (":sweat_drops:" ["💦"])
+ (":droplet:" ["💧"])
+ (":dash:" ["💨"])
+ (":hankey:" ["💩"])
+ (":poop:" ["💩"])
+ (":shit:" ["💩"])
+ (":muscle:" ["💪"])
+ (":dizzy:" ["💫"])
+ (":speech_balloon:" ["💬"])
+ (":thought_balloon:" ["💭"])
+ (":white_flower:" ["💮"])
+ (":100:" ["💯"])
+ (":moneybag:" ["💰"])
+ (":currency_exchange:" ["💱"])
+ (":heavy_dollar_sign:" ["💲"])
+ (":credit_card:" ["💳"])
+ (":yen:" ["💴"])
+ (":dollar:" ["💵"])
+ (":euro:" ["💶"])
+ (":pound:" ["💷"])
+ (":money_with_wings:" ["💸"])
+ (":chart:" ["💹"])
+ (":seat:" ["💺"])
+ (":computer:" ["💻"])
+ (":briefcase:" ["💼"])
+ (":minidisc:" ["💽"])
+ (":floppy_disk:" ["💾"])
+ (":cd:" ["💿"])
+ (":dvd:" ["📀"])
+ (":file_folder:" ["📁"])
+ (":open_file_folder:" ["📂"])
+ (":page_with_curl:" ["📃"])
+ (":page_facing_up:" ["📄"])
+ (":date:" ["📅"])
+ (":calendar:" ["📆"])
+ (":card_index:" ["📇"])
+ (":chart_with_upwards_trend:" ["📈"])
+ (":chart_with_downwards_trend:" ["📉"])
+ (":bar_chart:" ["📊"])
+ (":clipboard:" ["📋"])
+ (":pushpin:" ["📌"])
+ (":round_pushpin:" ["📍"])
+ (":paperclip:" ["📎"])
+ (":straight_ruler:" ["📏"])
+ (":triangular_ruler:" ["📐"])
+ (":bookmark_tabs:" ["📑"])
+ (":ledger:" ["📒"])
+ (":notebook:" ["📓"])
+ (":notebook_with_decorative_cover:" ["📔"])
+ (":closed_book:" ["📕"])
+ (":book:" ["📖"])
+ (":open_book:" ["📖"])
+ (":green_book:" ["📗"])
+ (":blue_book:" ["📘"])
+ (":orange_book:" ["📙"])
+ (":books:" ["📚"])
+ (":name_badge:" ["📛"])
+ (":scroll:" ["📜"])
+ (":memo:" ["📝"])
+ (":pencil:" ["📝"])
+ (":telephone_receiver:" ["📞"])
+ (":pager:" ["📟"])
+ (":fax:" ["📠"])
+ (":satellite_antenna:" ["📡"])
+ (":loudspeaker:" ["📢"])
+ (":mega:" ["📣"])
+ (":outbox_tray:" ["📤"])
+ (":inbox_tray:" ["📥"])
+ (":package:" ["📦"])
+ (":e-mail:" ["📧"])
+ (":incoming_envelope:" ["📨"])
+ (":envelope_with_arrow:" ["📩"])
+ (":mailbox_closed:" ["📪"])
+ (":mailbox:" ["📫"])
+ (":mailbox_with_mail:" ["📬"])
+ (":mailbox_with_no_mail:" ["📭"])
+ (":postbox:" ["📮"])
+ (":postal_horn:" ["📯"])
+ (":newspaper:" ["📰"])
+ (":iphone:" ["📱"])
+ (":calling:" ["📲"])
+ (":vibration_mode:" ["📳"])
+ (":mobile_phone_off:" ["📴"])
+ (":no_mobile_phones:" ["📵"])
+ (":signal_strength:" ["📶"])
+ (":camera:" ["📷"])
+ (":camera_with_flash:" ["📸"])
+ (":video_camera:" ["📹"])
+ (":tv:" ["📺"])
+ (":radio:" ["📻"])
+ (":vhs:" ["📼"])
+ (":film_projector:" ["📽️"])
+ (":prayer_beads:" ["📿"])
+ (":twisted_rightwards_arrows:" ["🔀"])
+ (":repeat:" ["🔁"])
+ (":repeat_one:" ["🔂"])
+ (":arrows_clockwise:" ["🔃"])
+ (":arrows_counterclockwise:" ["🔄"])
+ (":low_brightness:" ["🔅"])
+ (":high_brightness:" ["🔆"])
+ (":mute:" ["🔇"])
+ (":speaker:" ["🔈"])
+ (":sound:" ["🔉"])
+ (":loud_sound:" ["🔊"])
+ (":battery:" ["🔋"])
+ (":electric_plug:" ["🔌"])
+ (":mag:" ["🔍"])
+ (":mag_right:" ["🔎"])
+ (":lock_with_ink_pen:" ["🔏"])
+ (":closed_lock_with_key:" ["🔐"])
+ (":key:" ["🔑"])
+ (":lock:" ["🔒"])
+ (":unlock:" ["🔓"])
+ (":bell:" ["🔔"])
+ (":no_bell:" ["🔕"])
+ (":bookmark:" ["🔖"])
+ (":link:" ["🔗"])
+ (":radio_button:" ["🔘"])
+ (":back:" ["🔙"])
+ (":end:" ["🔚"])
+ (":on:" ["🔛"])
+ (":soon:" ["🔜"])
+ (":top:" ["🔝"])
+ (":underage:" ["🔞"])
+ (":keycap_ten:" ["🔟"])
+ (":capital_abcd:" ["🔠"])
+ (":abcd:" ["🔡"])
+ (":1234:" ["🔢"])
+ (":symbols:" ["🔣"])
+ (":abc:" ["🔤"])
+ (":fire:" ["🔥"])
+ (":flashlight:" ["🔦"])
+ (":wrench:" ["🔧"])
+ (":hammer:" ["🔨"])
+ (":nut_and_bolt:" ["🔩"])
+ (":hocho:" ["🔪"])
+ (":knife:" ["🔪"])
+ (":gun:" ["🔫"])
+ (":microscope:" ["🔬"])
+ (":telescope:" ["🔭"])
+ (":crystal_ball:" ["🔮"])
+ (":six_pointed_star:" ["🔯"])
+ (":beginner:" ["🔰"])
+ (":trident:" ["🔱"])
+ (":black_square_button:" ["🔲"])
+ (":white_square_button:" ["🔳"])
+ (":red_circle:" ["🔴"])
+ (":large_blue_circle:" ["🔵"])
+ (":large_orange_diamond:" ["🔶"])
+ (":large_blue_diamond:" ["🔷"])
+ (":small_orange_diamond:" ["🔸"])
+ (":small_blue_diamond:" ["🔹"])
+ (":small_red_triangle:" ["🔺"])
+ (":small_red_triangle_down:" ["🔻"])
+ (":arrow_up_small:" ["🔼"])
+ (":arrow_down_small:" ["🔽"])
+ (":om_symbol:" ["🕉️"])
+ (":dove_of_peace:" ["🕊️"])
+ (":kaaba:" ["🕋"])
+ (":mosque:" ["🕌"])
+ (":synagogue:" ["🕍"])
+ (":menorah_with_nine_branches:" ["🕎"])
+ (":clock1:" ["🕐"])
+ (":clock2:" ["🕑"])
+ (":clock3:" ["🕒"])
+ (":clock4:" ["🕓"])
+ (":clock5:" ["🕔"])
+ (":clock6:" ["🕕"])
+ (":clock7:" ["🕖"])
+ (":clock8:" ["🕗"])
+ (":clock9:" ["🕘"])
+ (":clock10:" ["🕙"])
+ (":clock11:" ["🕚"])
+ (":clock12:" ["🕛"])
+ (":clock130:" ["🕜"])
+ (":clock230:" ["🕝"])
+ (":clock330:" ["🕞"])
+ (":clock430:" ["🕟"])
+ (":clock530:" ["🕠"])
+ (":clock630:" ["🕡"])
+ (":clock730:" ["🕢"])
+ (":clock830:" ["🕣"])
+ (":clock930:" ["🕤"])
+ (":clock1030:" ["🕥"])
+ (":clock1130:" ["🕦"])
+ (":clock1230:" ["🕧"])
+ (":candle:" ["🕯️"])
+ (":mantelpiece_clock:" ["🕰️"])
+ (":hole:" ["🕳️"])
+ (":man_in_business_suit_levitating:" ["🕴️"])
+ (":female-detective:" ["🕵️‍♀️"])
+ (":male-detective:" ["🕵️‍♂️"])
+ (":sleuth_or_spy:" ["🕵️"])
+ (":dark_sunglasses:" ["🕶️"])
+ (":spider:" ["🕷️"])
+ (":spider_web:" ["🕸️"])
+ (":joystick:" ["🕹️"])
+ (":man_dancing:" ["🕺"])
+ (":linked_paperclips:" ["🖇️"])
+ (":lower_left_ballpoint_pen:" ["🖊️"])
+ (":lower_left_fountain_pen:" ["🖋️"])
+ (":lower_left_paintbrush:" ["🖌️"])
+ (":lower_left_crayon:" ["🖍️"])
+ (":raised_hand_with_fingers_splayed:" ["🖐️"])
+ (":middle_finger:" ["🖕"])
+ (":reversed_hand_with_middle_finger_extended:" ["🖕"])
+ (":spock-hand:" ["🖖"])
+ (":black_heart:" ["🖤"])
+ (":desktop_computer:" ["🖥️"])
+ (":printer:" ["🖨️"])
+ (":three_button_mouse:" ["🖱️"])
+ (":trackball:" ["🖲️"])
+ (":frame_with_picture:" ["🖼️"])
+ (":card_index_dividers:" ["🗂️"])
+ (":card_file_box:" ["🗃️"])
+ (":file_cabinet:" ["🗄️"])
+ (":wastebasket:" ["🗑️"])
+ (":spiral_note_pad:" ["🗒️"])
+ (":spiral_calendar_pad:" ["🗓️"])
+ (":compression:" ["🗜️"])
+ (":old_key:" ["🗝️"])
+ (":rolled_up_newspaper:" ["🗞️"])
+ (":dagger_knife:" ["🗡️"])
+ (":speaking_head_in_silhouette:" ["🗣️"])
+ (":left_speech_bubble:" ["🗨️"])
+ (":right_anger_bubble:" ["🗯️"])
+ (":ballot_box_with_ballot:" ["🗳️"])
+ (":world_map:" ["🗺️"])
+ (":mount_fuji:" ["🗻"])
+ (":tokyo_tower:" ["🗼"])
+ (":statue_of_liberty:" ["🗽"])
+ (":japan:" ["🗾"])
+ (":moyai:" ["🗿"])
+ (":grinning:" ["😀"])
+ (":D" ["😀"])
+ (":grin:" ["😁"])
+ (":joy:" ["😂"])
+ (":smiley:" ["😃"])
+ (":)" ["😃"])
+ ("=)" ["😃"])
+ ("=-)" ["😃"])
+ (":smile:" ["😄"])
+ (":)" ["😄"])
+ ("C:" ["😄"])
+ ("c:" ["😄"])
+ (":D" ["😄"])
+ (":-D" ["😄"])
+ (":sweat_smile:" ["😅"])
+ (":laughing:" ["😆"])
+ (":satisfied:" ["😆"])
+ (":>" ["😆"])
+ (":->" ["😆"])
+ (":innocent:" ["😇"])
+ (":smiling_imp:" ["😈"])
+ (":wink:" ["😉"])
+ (";)" ["😉"])
+ (";-)" ["😉"])
+ (":blush:" ["😊"])
+ (":)" ["😊"])
+ (":yum:" ["😋"])
+ (":relieved:" ["😌"])
+ (":heart_eyes:" ["😍"])
+ (":sunglasses:" ["😎"])
+ ("8)" ["😎"])
+ (":smirk:" ["😏"])
+ (":neutral_face:" ["😐"])
+ (":|" ["😐"])
+ (":-|" ["😐"])
+ (":expressionless:" ["😑"])
+ (":unamused:" ["😒"])
+ (":(" ["😒"])
+ (":sweat:" ["😓"])
+ (":pensive:" ["😔"])
+ (":confused:" ["😕"])
+ (":\\" ["😕"])
+ (":-\\" ["😕"])
+ (":/" ["😕"])
+ (":-/" ["😕"])
+ (":confounded:" ["😖"])
+ (":kissing:" ["😗"])
+ (":kissing_heart:" ["😘"])
+ (":*" ["😘"])
+ (":-*" ["😘"])
+ (":kissing_smiling_eyes:" ["😙"])
+ (":kissing_closed_eyes:" ["😚"])
+ (":stuck_out_tongue:" ["😛"])
+ (":p" ["😛"])
+ (":-p" ["😛"])
+ (":P" ["😛"])
+ (":-P" ["😛"])
+ (":b" ["😛"])
+ (":-b" ["😛"])
+ (":stuck_out_tongue_winking_eye:" ["😜"])
+ (";p" ["😜"])
+ (";-p" ["😜"])
+ (";b" ["😜"])
+ (";-b" ["😜"])
+ (";P" ["😜"])
+ (";-P" ["😜"])
+ (":stuck_out_tongue_closed_eyes:" ["😝"])
+ (":disappointed:" ["😞"])
+ (":(" ["😞"])
+ ("):" ["😞"])
+ (":-(" ["😞"])
+ (":worried:" ["😟"])
+ (":angry:" ["😠"])
+ (">:(" ["😠"])
+ (">:-(" ["😠"])
+ (":rage:" ["😡"])
+ (":cry:" ["😢"])
+ (":'(" ["😢"])
+ (":persevere:" ["😣"])
+ (":triumph:" ["😤"])
+ (":disappointed_relieved:" ["😥"])
+ (":frowning:" ["😦"])
+ (":anguished:" ["😧"])
+ ("D:" ["😧"])
+ (":fearful:" ["😨"])
+ (":weary:" ["😩"])
+ (":sleepy:" ["😪"])
+ (":tired_face:" ["😫"])
+ (":grimacing:" ["😬"])
+ (":sob:" ["😭"])
+ (":'(" ["😭"])
+ (":face_exhaling:" ["😮‍💨"])
+ (":open_mouth:" ["😮"])
+ (":o" ["😮"])
+ (":-o" ["😮"])
+ (":O" ["😮"])
+ (":-O" ["😮"])
+ (":hushed:" ["😯"])
+ (":cold_sweat:" ["😰"])
+ (":scream:" ["😱"])
+ (":astonished:" ["😲"])
+ (":flushed:" ["😳"])
+ (":sleeping:" ["😴"])
+ (":face_with_spiral_eyes:" ["😵‍💫"])
+ (":dizzy_face:" ["😵"])
+ (":face_in_clouds:" ["😶‍🌫️"])
+ (":no_mouth:" ["😶"])
+ (":mask:" ["😷"])
+ (":smile_cat:" ["😸"])
+ (":joy_cat:" ["😹"])
+ (":smiley_cat:" ["😺"])
+ (":heart_eyes_cat:" ["😻"])
+ (":smirk_cat:" ["😼"])
+ (":kissing_cat:" ["😽"])
+ (":pouting_cat:" ["😾"])
+ (":crying_cat_face:" ["😿"])
+ (":scream_cat:" ["🙀"])
+ (":slightly_frowning_face:" ["🙁"])
+ (":slightly_smiling_face:" ["🙂"])
+ (":)" ["🙂"])
+ ("(:" ["🙂"])
+ (":-)" ["🙂"])
+ (":upside_down_face:" ["🙃"])
+ (":face_with_rolling_eyes:" ["🙄"])
+ (":woman-gesturing-no:" ["🙅‍♀️"])
+ (":man-gesturing-no:" ["🙅‍♂️"])
+ (":no_good:" ["🙅"])
+ (":woman-gesturing-ok:" ["🙆‍♀️"])
+ (":man-gesturing-ok:" ["🙆‍♂️"])
+ (":ok_woman:" ["🙆"])
+ (":woman-bowing:" ["🙇‍♀️"])
+ (":man-bowing:" ["🙇‍♂️"])
+ (":bow:" ["🙇"])
+ (":see_no_evil:" ["🙈"])
+ (":hear_no_evil:" ["🙉"])
+ (":speak_no_evil:" ["🙊"])
+ (":woman-raising-hand:" ["🙋‍♀️"])
+ (":man-raising-hand:" ["🙋‍♂️"])
+ (":raising_hand:" ["🙋"])
+ (":raised_hands:" ["🙌"])
+ (":woman-frowning:" ["🙍‍♀️"])
+ (":man-frowning:" ["🙍‍♂️"])
+ (":person_frowning:" ["🙍"])
+ (":woman-pouting:" ["🙎‍♀️"])
+ (":man-pouting:" ["🙎‍♂️"])
+ (":person_with_pouting_face:" ["🙎"])
+ (":pray:" ["🙏"])
+ (":rocket:" ["🚀"])
+ (":helicopter:" ["🚁"])
+ (":steam_locomotive:" ["🚂"])
+ (":railway_car:" ["🚃"])
+ (":bullettrain_side:" ["🚄"])
+ (":bullettrain_front:" ["🚅"])
+ (":train2:" ["🚆"])
+ (":metro:" ["🚇"])
+ (":light_rail:" ["🚈"])
+ (":station:" ["🚉"])
+ (":tram:" ["🚊"])
+ (":train:" ["🚋"])
+ (":bus:" ["🚌"])
+ (":oncoming_bus:" ["🚍"])
+ (":trolleybus:" ["🚎"])
+ (":busstop:" ["🚏"])
+ (":minibus:" ["🚐"])
+ (":ambulance:" ["🚑"])
+ (":fire_engine:" ["🚒"])
+ (":police_car:" ["🚓"])
+ (":oncoming_police_car:" ["🚔"])
+ (":taxi:" ["🚕"])
+ (":oncoming_taxi:" ["🚖"])
+ (":car:" ["🚗"])
+ (":red_car:" ["🚗"])
+ (":oncoming_automobile:" ["🚘"])
+ (":blue_car:" ["🚙"])
+ (":truck:" ["🚚"])
+ (":articulated_lorry:" ["🚛"])
+ (":tractor:" ["🚜"])
+ (":monorail:" ["🚝"])
+ (":mountain_railway:" ["🚞"])
+ (":suspension_railway:" ["🚟"])
+ (":mountain_cableway:" ["🚠"])
+ (":aerial_tramway:" ["🚡"])
+ (":ship:" ["🚢"])
+ (":woman-rowing-boat:" ["🚣‍♀️"])
+ (":man-rowing-boat:" ["🚣‍♂️"])
+ (":rowboat:" ["🚣"])
+ (":speedboat:" ["🚤"])
+ (":traffic_light:" ["🚥"])
+ (":vertical_traffic_light:" ["🚦"])
+ (":construction:" ["🚧"])
+ (":rotating_light:" ["🚨"])
+ (":triangular_flag_on_post:" ["🚩"])
+ (":door:" ["🚪"])
+ (":no_entry_sign:" ["🚫"])
+ (":smoking:" ["🚬"])
+ (":no_smoking:" ["🚭"])
+ (":put_litter_in_its_place:" ["🚮"])
+ (":do_not_litter:" ["🚯"])
+ (":potable_water:" ["🚰"])
+ (":non-potable_water:" ["🚱"])
+ (":bike:" ["🚲"])
+ (":no_bicycles:" ["🚳"])
+ (":woman-biking:" ["🚴‍♀️"])
+ (":man-biking:" ["🚴‍♂️"])
+ (":bicyclist:" ["🚴"])
+ (":woman-mountain-biking:" ["🚵‍♀️"])
+ (":man-mountain-biking:" ["🚵‍♂️"])
+ (":mountain_bicyclist:" ["🚵"])
+ (":woman-walking:" ["🚶‍♀️"])
+ (":man-walking:" ["🚶‍♂️"])
+ (":walking:" ["🚶"])
+ (":no_pedestrians:" ["🚷"])
+ (":children_crossing:" ["🚸"])
+ (":mens:" ["🚹"])
+ (":womens:" ["🚺"])
+ (":restroom:" ["🚻"])
+ (":baby_symbol:" ["🚼"])
+ (":toilet:" ["🚽"])
+ (":wc:" ["🚾"])
+ (":shower:" ["🚿"])
+ (":bath:" ["🛀"])
+ (":bathtub:" ["🛁"])
+ (":passport_control:" ["🛂"])
+ (":customs:" ["🛃"])
+ (":baggage_claim:" ["🛄"])
+ (":left_luggage:" ["🛅"])
+ (":couch_and_lamp:" ["🛋️"])
+ (":sleeping_accommodation:" ["🛌"])
+ (":shopping_bags:" ["🛍️"])
+ (":bellhop_bell:" ["🛎️"])
+ (":bed:" ["🛏️"])
+ (":place_of_worship:" ["🛐"])
+ (":octagonal_sign:" ["🛑"])
+ (":shopping_trolley:" ["🛒"])
+ (":hindu_temple:" ["🛕"])
+ (":hut:" ["🛖"])
+ (":elevator:" ["🛗"])
+ (":hammer_and_wrench:" ["🛠️"])
+ (":shield:" ["🛡️"])
+ (":oil_drum:" ["🛢️"])
+ (":motorway:" ["🛣️"])
+ (":railway_track:" ["🛤️"])
+ (":motor_boat:" ["🛥️"])
+ (":small_airplane:" ["🛩️"])
+ (":airplane_departure:" ["🛫"])
+ (":airplane_arriving:" ["🛬"])
+ (":satellite:" ["🛰️"])
+ (":passenger_ship:" ["🛳️"])
+ (":scooter:" ["🛴"])
+ (":motor_scooter:" ["🛵"])
+ (":canoe:" ["🛶"])
+ (":sled:" ["🛷"])
+ (":flying_saucer:" ["🛸"])
+ (":skateboard:" ["🛹"])
+ (":auto_rickshaw:" ["🛺"])
+ (":pickup_truck:" ["🛻"])
+ (":roller_skate:" ["🛼"])
+ (":large_orange_circle:" ["🟠"])
+ (":large_yellow_circle:" ["🟡"])
+ (":large_green_circle:" ["🟢"])
+ (":large_purple_circle:" ["🟣"])
+ (":large_brown_circle:" ["🟤"])
+ (":large_red_square:" ["🟥"])
+ (":large_blue_square:" ["🟦"])
+ (":large_orange_square:" ["🟧"])
+ (":large_yellow_square:" ["🟨"])
+ (":large_green_square:" ["🟩"])
+ (":large_purple_square:" ["🟪"])
+ (":large_brown_square:" ["🟫"])
+ (":pinched_fingers:" ["🤌"])
+ (":white_heart:" ["🤍"])
+ (":brown_heart:" ["🤎"])
+ (":pinching_hand:" ["🤏"])
+ (":zipper_mouth_face:" ["🤐"])
+ (":money_mouth_face:" ["🤑"])
+ (":face_with_thermometer:" ["🤒"])
+ (":nerd_face:" ["🤓"])
+ (":thinking_face:" ["🤔"])
+ (":face_with_head_bandage:" ["🤕"])
+ (":robot_face:" ["🤖"])
+ (":hugging_face:" ["🤗"])
+ (":the_horns:" ["🤘"])
+ (":sign_of_the_horns:" ["🤘"])
+ (":call_me_hand:" ["🤙"])
+ (":raised_back_of_hand:" ["🤚"])
+ (":left-facing_fist:" ["🤛"])
+ (":right-facing_fist:" ["🤜"])
+ (":handshake:" ["🤝"])
+ (":crossed_fingers:" ["🤞"])
+ (":hand_with_index_and_middle_fingers_crossed:" ["🤞"])
+ (":i_love_you_hand_sign:" ["🤟"])
+ (":face_with_cowboy_hat:" ["🤠"])
+ (":clown_face:" ["🤡"])
+ (":nauseated_face:" ["🤢"])
+ (":rolling_on_the_floor_laughing:" ["🤣"])
+ (":drooling_face:" ["🤤"])
+ (":lying_face:" ["🤥"])
+ (":woman-facepalming:" ["🤦‍♀️"])
+ (":man-facepalming:" ["🤦‍♂️"])
+ (":face_palm:" ["🤦"])
+ (":sneezing_face:" ["🤧"])
+ (":face_with_raised_eyebrow:" ["🤨"])
+ (":face_with_one_eyebrow_raised:" ["🤨"])
+ (":star-struck:" ["🤩"])
+ (":grinning_face_with_star_eyes:" ["🤩"])
+ (":zany_face:" ["🤪"])
+ (":grinning_face_with_one_large_and_one_small_eye:" ["🤪"])
+ (":shushing_face:" ["🤫"])
+ (":face_with_finger_covering_closed_lips:" ["🤫"])
+ (":face_with_symbols_on_mouth:" ["🤬"])
+ (":serious_face_with_symbols_covering_mouth:" ["🤬"])
+ (":face_with_hand_over_mouth:" ["🤭"])
+ (":smiling_face_with_smiling_eyes_and_hand_covering_mouth:" ["🤭"])
+ (":face_vomiting:" ["🤮"])
+ (":face_with_open_mouth_vomiting:" ["🤮"])
+ (":exploding_head:" ["🤯"])
+ (":shocked_face_with_exploding_head:" ["🤯"])
+ (":pregnant_woman:" ["🤰"])
+ (":breast-feeding:" ["🤱"])
+ (":palms_up_together:" ["🤲"])
+ (":selfie:" ["🤳"])
+ (":prince:" ["🤴"])
+ (":woman_in_tuxedo:" ["🤵‍♀️"])
+ (":man_in_tuxedo:" ["🤵‍♂️"])
+ (":person_in_tuxedo:" ["🤵"])
+ (":mrs_claus:" ["🤶"])
+ (":mother_christmas:" ["🤶"])
+ (":woman-shrugging:" ["🤷‍♀️"])
+ (":man-shrugging:" ["🤷‍♂️"])
+ (":shrug:" ["🤷"])
+ (":woman-cartwheeling:" ["🤸‍♀️"])
+ (":man-cartwheeling:" ["🤸‍♂️"])
+ (":person_doing_cartwheel:" ["🤸"])
+ (":woman-juggling:" ["🤹‍♀️"])
+ (":man-juggling:" ["🤹‍♂️"])
+ (":juggling:" ["🤹"])
+ (":fencer:" ["🤺"])
+ (":woman-wrestling:" ["🤼‍♀️"])
+ (":man-wrestling:" ["🤼‍♂️"])
+ (":wrestlers:" ["🤼"])
+ (":woman-playing-water-polo:" ["🤽‍♀️"])
+ (":man-playing-water-polo:" ["🤽‍♂️"])
+ (":water_polo:" ["🤽"])
+ (":woman-playing-handball:" ["🤾‍♀️"])
+ (":man-playing-handball:" ["🤾‍♂️"])
+ (":handball:" ["🤾"])
+ (":diving_mask:" ["🤿"])
+ (":wilted_flower:" ["🥀"])
+ (":drum_with_drumsticks:" ["🥁"])
+ (":clinking_glasses:" ["🥂"])
+ (":tumbler_glass:" ["🥃"])
+ (":spoon:" ["🥄"])
+ (":goal_net:" ["🥅"])
+ (":first_place_medal:" ["🥇"])
+ (":second_place_medal:" ["🥈"])
+ (":third_place_medal:" ["🥉"])
+ (":boxing_glove:" ["🥊"])
+ (":martial_arts_uniform:" ["🥋"])
+ (":curling_stone:" ["🥌"])
+ (":lacrosse:" ["🥍"])
+ (":softball:" ["🥎"])
+ (":flying_disc:" ["🥏"])
+ (":croissant:" ["🥐"])
+ (":avocado:" ["🥑"])
+ (":cucumber:" ["🥒"])
+ (":bacon:" ["🥓"])
+ (":potato:" ["🥔"])
+ (":carrot:" ["🥕"])
+ (":baguette_bread:" ["🥖"])
+ (":green_salad:" ["🥗"])
+ (":shallow_pan_of_food:" ["🥘"])
+ (":stuffed_flatbread:" ["🥙"])
+ (":egg:" ["🥚"])
+ (":glass_of_milk:" ["🥛"])
+ (":peanuts:" ["🥜"])
+ (":kiwifruit:" ["🥝"])
+ (":pancakes:" ["🥞"])
+ (":dumpling:" ["🥟"])
+ (":fortune_cookie:" ["🥠"])
+ (":takeout_box:" ["🥡"])
+ (":chopsticks:" ["🥢"])
+ (":bowl_with_spoon:" ["🥣"])
+ (":cup_with_straw:" ["🥤"])
+ (":coconut:" ["🥥"])
+ (":broccoli:" ["🥦"])
+ (":pie:" ["🥧"])
+ (":pretzel:" ["🥨"])
+ (":cut_of_meat:" ["🥩"])
+ (":sandwich:" ["🥪"])
+ (":canned_food:" ["🥫"])
+ (":leafy_green:" ["🥬"])
+ (":mango:" ["🥭"])
+ (":moon_cake:" ["🥮"])
+ (":bagel:" ["🥯"])
+ (":smiling_face_with_3_hearts:" ["🥰"])
+ (":yawning_face:" ["🥱"])
+ (":smiling_face_with_tear:" ["🥲"])
+ (":partying_face:" ["🥳"])
+ (":woozy_face:" ["🥴"])
+ (":hot_face:" ["🥵"])
+ (":cold_face:" ["🥶"])
+ (":ninja:" ["🥷"])
+ (":disguised_face:" ["🥸"])
+ (":pleading_face:" ["🥺"])
+ (":sari:" ["🥻"])
+ (":lab_coat:" ["🥼"])
+ (":goggles:" ["🥽"])
+ (":hiking_boot:" ["🥾"])
+ (":womans_flat_shoe:" ["🥿"])
+ (":crab:" ["🦀"])
+ (":lion_face:" ["🦁"])
+ (":scorpion:" ["🦂"])
+ (":turkey:" ["🦃"])
+ (":unicorn_face:" ["🦄"])
+ (":eagle:" ["🦅"])
+ (":duck:" ["🦆"])
+ (":bat:" ["🦇"])
+ (":shark:" ["🦈"])
+ (":owl:" ["🦉"])
+ (":fox_face:" ["🦊"])
+ (":butterfly:" ["🦋"])
+ (":deer:" ["🦌"])
+ (":gorilla:" ["🦍"])
+ (":lizard:" ["🦎"])
+ (":rhinoceros:" ["🦏"])
+ (":shrimp:" ["🦐"])
+ (":squid:" ["🦑"])
+ (":giraffe_face:" ["🦒"])
+ (":zebra_face:" ["🦓"])
+ (":hedgehog:" ["🦔"])
+ (":sauropod:" ["🦕"])
+ (":t-rex:" ["🦖"])
+ (":cricket:" ["🦗"])
+ (":kangaroo:" ["🦘"])
+ (":llama:" ["🦙"])
+ (":peacock:" ["🦚"])
+ (":hippopotamus:" ["🦛"])
+ (":parrot:" ["🦜"])
+ (":raccoon:" ["🦝"])
+ (":lobster:" ["🦞"])
+ (":mosquito:" ["🦟"])
+ (":microbe:" ["🦠"])
+ (":badger:" ["🦡"])
+ (":swan:" ["🦢"])
+ (":mammoth:" ["🦣"])
+ (":dodo:" ["🦤"])
+ (":sloth:" ["🦥"])
+ (":otter:" ["🦦"])
+ (":orangutan:" ["🦧"])
+ (":skunk:" ["🦨"])
+ (":flamingo:" ["🦩"])
+ (":oyster:" ["🦪"])
+ (":beaver:" ["🦫"])
+ (":bison:" ["🦬"])
+ (":seal:" ["🦭"])
+ (":guide_dog:" ["🦮"])
+ (":probing_cane:" ["🦯"])
+ (":bone:" ["🦴"])
+ (":leg:" ["🦵"])
+ (":foot:" ["🦶"])
+ (":tooth:" ["🦷"])
+ (":female_superhero:" ["🦸‍♀️"])
+ (":male_superhero:" ["🦸‍♂️"])
+ (":superhero:" ["🦸"])
+ (":female_supervillain:" ["🦹‍♀️"])
+ (":male_supervillain:" ["🦹‍♂️"])
+ (":supervillain:" ["🦹"])
+ (":safety_vest:" ["🦺"])
+ (":ear_with_hearing_aid:" ["🦻"])
+ (":motorized_wheelchair:" ["🦼"])
+ (":manual_wheelchair:" ["🦽"])
+ (":mechanical_arm:" ["🦾"])
+ (":mechanical_leg:" ["🦿"])
+ (":cheese_wedge:" ["🧀"])
+ (":cupcake:" ["🧁"])
+ (":salt:" ["🧂"])
+ (":beverage_box:" ["🧃"])
+ (":garlic:" ["🧄"])
+ (":onion:" ["🧅"])
+ (":falafel:" ["🧆"])
+ (":waffle:" ["🧇"])
+ (":butter:" ["🧈"])
+ (":mate_drink:" ["🧉"])
+ (":ice_cube:" ["🧊"])
+ (":bubble_tea:" ["🧋"])
+ (":woman_standing:" ["🧍‍♀️"])
+ (":man_standing:" ["🧍‍♂️"])
+ (":standing_person:" ["🧍"])
+ (":woman_kneeling:" ["🧎‍♀️"])
+ (":man_kneeling:" ["🧎‍♂️"])
+ (":kneeling_person:" ["🧎"])
+ (":deaf_woman:" ["🧏‍♀️"])
+ (":deaf_man:" ["🧏‍♂️"])
+ (":deaf_person:" ["🧏"])
+ (":face_with_monocle:" ["🧐"])
+ (":farmer:" ["🧑‍🌾"])
+ (":cook:" ["🧑‍🍳"])
+ (":person_feeding_baby:" ["🧑‍🍼"])
+ (":mx_claus:" ["🧑‍🎄"])
+ (":student:" ["🧑‍🎓"])
+ (":singer:" ["🧑‍🎤"])
+ (":artist:" ["🧑‍🎨"])
+ (":teacher:" ["🧑‍🏫"])
+ (":factory_worker:" ["🧑‍🏭"])
+ (":technologist:" ["🧑‍💻"])
+ (":office_worker:" ["🧑‍💼"])
+ (":mechanic:" ["🧑‍🔧"])
+ (":scientist:" ["🧑‍🔬"])
+ (":astronaut:" ["🧑‍🚀"])
+ (":firefighter:" ["🧑‍🚒"])
+ (":people_holding_hands:" ["🧑‍🤝‍🧑"])
+ (":person_with_probing_cane:" ["🧑‍🦯"])
+ (":red_haired_person:" ["🧑‍🦰"])
+ (":curly_haired_person:" ["🧑‍🦱"])
+ (":bald_person:" ["🧑‍🦲"])
+ (":white_haired_person:" ["🧑‍🦳"])
+ (":person_in_motorized_wheelchair:" ["🧑‍🦼"])
+ (":person_in_manual_wheelchair:" ["🧑‍🦽"])
+ (":health_worker:" ["🧑‍⚕️"])
+ (":judge:" ["🧑‍⚖️"])
+ (":pilot:" ["🧑‍✈️"])
+ (":adult:" ["🧑"])
+ (":child:" ["🧒"])
+ (":older_adult:" ["🧓"])
+ (":woman_with_beard:" ["🧔‍♀️"])
+ (":man_with_beard:" ["🧔‍♂️"])
+ (":bearded_person:" ["🧔"])
+ (":person_with_headscarf:" ["🧕"])
+ (":woman_in_steamy_room:" ["🧖‍♀️"])
+ (":man_in_steamy_room:" ["🧖‍♂️"])
+ (":person_in_steamy_room:" ["🧖"])
+ (":woman_climbing:" ["🧗‍♀️"])
+ (":man_climbing:" ["🧗‍♂️"])
+ (":person_climbing:" ["🧗"])
+ (":woman_in_lotus_position:" ["🧘‍♀️"])
+ (":man_in_lotus_position:" ["🧘‍♂️"])
+ (":person_in_lotus_position:" ["🧘"])
+ (":female_mage:" ["🧙‍♀️"])
+ (":male_mage:" ["🧙‍♂️"])
+ (":mage:" ["🧙"])
+ (":female_fairy:" ["🧚‍♀️"])
+ (":male_fairy:" ["🧚‍♂️"])
+ (":fairy:" ["🧚"])
+ (":female_vampire:" ["🧛‍♀️"])
+ (":male_vampire:" ["🧛‍♂️"])
+ (":vampire:" ["🧛"])
+ (":mermaid:" ["🧜‍♀️"])
+ (":merman:" ["🧜‍♂️"])
+ (":merperson:" ["🧜"])
+ (":female_elf:" ["🧝‍♀️"])
+ (":male_elf:" ["🧝‍♂️"])
+ (":elf:" ["🧝"])
+ (":female_genie:" ["🧞‍♀️"])
+ (":male_genie:" ["🧞‍♂️"])
+ (":genie:" ["🧞"])
+ (":female_zombie:" ["🧟‍♀️"])
+ (":male_zombie:" ["🧟‍♂️"])
+ (":zombie:" ["🧟"])
+ (":brain:" ["🧠"])
+ (":orange_heart:" ["🧡"])
+ (":billed_cap:" ["🧢"])
+ (":scarf:" ["🧣"])
+ (":gloves:" ["🧤"])
+ (":coat:" ["🧥"])
+ (":socks:" ["🧦"])
+ (":red_envelope:" ["🧧"])
+ (":firecracker:" ["🧨"])
+ (":jigsaw:" ["🧩"])
+ (":test_tube:" ["🧪"])
+ (":petri_dish:" ["🧫"])
+ (":dna:" ["🧬"])
+ (":compass:" ["🧭"])
+ (":abacus:" ["🧮"])
+ (":fire_extinguisher:" ["🧯"])
+ (":toolbox:" ["🧰"])
+ (":bricks:" ["🧱"])
+ (":magnet:" ["🧲"])
+ (":luggage:" ["🧳"])
+ (":lotion_bottle:" ["🧴"])
+ (":thread:" ["🧵"])
+ (":yarn:" ["🧶"])
+ (":safety_pin:" ["🧷"])
+ (":teddy_bear:" ["🧸"])
+ (":broom:" ["🧹"])
+ (":basket:" ["🧺"])
+ (":roll_of_paper:" ["🧻"])
+ (":soap:" ["🧼"])
+ (":sponge:" ["🧽"])
+ (":receipt:" ["🧾"])
+ (":nazar_amulet:" ["🧿"])
+ (":ballet_shoes:" ["🩰"])
+ (":one-piece_swimsuit:" ["🩱"])
+ (":briefs:" ["🩲"])
+ (":shorts:" ["🩳"])
+ (":thong_sandal:" ["🩴"])
+ (":drop_of_blood:" ["🩸"])
+ (":adhesive_bandage:" ["🩹"])
+ (":stethoscope:" ["🩺"])
+ (":yo-yo:" ["🪀"])
+ (":kite:" ["🪁"])
+ (":parachute:" ["🪂"])
+ (":boomerang:" ["🪃"])
+ (":magic_wand:" ["🪄"])
+ (":pinata:" ["🪅"])
+ (":nesting_dolls:" ["🪆"])
+ (":ringed_planet:" ["🪐"])
+ (":chair:" ["🪑"])
+ (":razor:" ["🪒"])
+ (":axe:" ["🪓"])
+ (":diya_lamp:" ["🪔"])
+ (":banjo:" ["🪕"])
+ (":military_helmet:" ["🪖"])
+ (":accordion:" ["🪗"])
+ (":long_drum:" ["🪘"])
+ (":coin:" ["🪙"])
+ (":carpentry_saw:" ["🪚"])
+ (":screwdriver:" ["🪛"])
+ (":ladder:" ["🪜"])
+ (":hook:" ["🪝"])
+ (":mirror:" ["🪞"])
+ (":window:" ["🪟"])
+ (":plunger:" ["🪠"])
+ (":sewing_needle:" ["🪡"])
+ (":knot:" ["🪢"])
+ (":bucket:" ["🪣"])
+ (":mouse_trap:" ["🪤"])
+ (":toothbrush:" ["🪥"])
+ (":headstone:" ["🪦"])
+ (":placard:" ["🪧"])
+ (":rock:" ["🪨"])
+ (":fly:" ["🪰"])
+ (":worm:" ["🪱"])
+ (":beetle:" ["🪲"])
+ (":cockroach:" ["🪳"])
+ (":potted_plant:" ["🪴"])
+ (":wood:" ["🪵"])
+ (":feather:" ["🪶"])
+ (":anatomical_heart:" ["🫀"])
+ (":lungs:" ["🫁"])
+ (":people_hugging:" ["🫂"])
+ (":blueberries:" ["🫐"])
+ (":bell_pepper:" ["🫑"])
+ (":olive:" ["🫒"])
+ (":flatbread:" ["🫓"])
+ (":tamale:" ["🫔"])
+ (":fondue:" ["🫕"])
+ (":teapot:" ["🫖"])
+ (":bangbang:" ["‼️"])
+ (":interrobang:" ["⁉️"])
+ (":tm:" ["™️"])
+ (":information_source:" ["ℹ️"])
+ (":left_right_arrow:" ["↔️"])
+ (":arrow_up_down:" ["↕️"])
+ (":arrow_upper_left:" ["↖️"])
+ (":arrow_upper_right:" ["↗️"])
+ (":arrow_lower_right:" ["↘️"])
+ (":arrow_lower_left:" ["↙️"])
+ (":leftwards_arrow_with_hook:" ["↩️"])
+ (":arrow_right_hook:" ["↪️"])
+ (":watch:" ["⌚"])
+ (":hourglass:" ["⌛"])
+ (":keyboard:" ["⌨️"])
+ (":eject:" ["⏏️"])
+ (":fast_forward:" ["⏩"])
+ (":rewind:" ["⏪"])
+ (":arrow_double_up:" ["⏫"])
+ (":arrow_double_down:" ["⏬"])
+ (":black_right_pointing_double_triangle_with_vertical_bar:" ["⏭️"])
+ (":black_left_pointing_double_triangle_with_vertical_bar:" ["⏮️"])
+ (":black_right_pointing_triangle_with_double_vertical_bar:" ["⏯️"])
+ (":alarm_clock:" ["⏰"])
+ (":stopwatch:" ["⏱️"])
+ (":timer_clock:" ["⏲️"])
+ (":hourglass_flowing_sand:" ["⏳"])
+ (":double_vertical_bar:" ["⏸️"])
+ (":black_square_for_stop:" ["⏹️"])
+ (":black_circle_for_record:" ["⏺️"])
+ (":m:" ["Ⓜ️"])
+ (":black_small_square:" ["▪️"])
+ (":white_small_square:" ["▫️"])
+ (":arrow_forward:" ["▶️"])
+ (":arrow_backward:" ["◀️"])
+ (":white_medium_square:" ["◻️"])
+ (":black_medium_square:" ["◼️"])
+ (":white_medium_small_square:" ["◽"])
+ (":black_medium_small_square:" ["◾"])
+ (":sunny:" ["☀️"])
+ (":cloud:" ["☁️"])
+ (":umbrella:" ["☂️"])
+ (":snowman:" ["☃️"])
+ (":comet:" ["☄️"])
+ (":phone:" ["☎️"])
+ (":telephone:" ["☎️"])
+ (":ballot_box_with_check:" ["☑️"])
+ (":umbrella_with_rain_drops:" ["☔"])
+ (":coffee:" ["☕"])
+ (":shamrock:" ["☘️"])
+ (":point_up:" ["☝️"])
+ (":skull_and_crossbones:" ["☠️"])
+ (":radioactive_sign:" ["☢️"])
+ (":biohazard_sign:" ["☣️"])
+ (":orthodox_cross:" ["☦️"])
+ (":star_and_crescent:" ["☪️"])
+ (":peace_symbol:" ["☮️"])
+ (":yin_yang:" ["☯️"])
+ (":wheel_of_dharma:" ["☸️"])
+ (":white_frowning_face:" ["☹️"])
+ (":relaxed:" ["☺️"])
+ (":female_sign:" ["♀️"])
+ (":male_sign:" ["♂️"])
+ (":aries:" ["♈"])
+ (":taurus:" ["♉"])
+ (":gemini:" ["♊"])
+ (":cancer:" ["♋"])
+ (":leo:" ["♌"])
+ (":virgo:" ["♍"])
+ (":libra:" ["♎"])
+ (":scorpius:" ["♏"])
+ (":sagittarius:" ["♐"])
+ (":capricorn:" ["♑"])
+ (":aquarius:" ["♒"])
+ (":pisces:" ["♓"])
+ (":chess_pawn:" ["♟️"])
+ (":spades:" ["♠️"])
+ (":clubs:" ["♣️"])
+ (":hearts:" ["♥️"])
+ (":diamonds:" ["♦️"])
+ (":hotsprings:" ["♨️"])
+ (":recycle:" ["♻️"])
+ (":infinity:" ["♾️"])
+ (":wheelchair:" ["♿"])
+ (":hammer_and_pick:" ["⚒️"])
+ (":anchor:" ["⚓"])
+ (":crossed_swords:" ["⚔️"])
+ (":medical_symbol:" ["⚕️"])
+ (":staff_of_aesculapius:" ["⚕️"])
+ (":scales:" ["⚖️"])
+ (":alembic:" ["⚗️"])
+ (":gear:" ["⚙️"])
+ (":atom_symbol:" ["⚛️"])
+ (":fleur_de_lis:" ["⚜️"])
+ (":warning:" ["⚠️"])
+ (":zap:" ["⚡"])
+ (":transgender_symbol:" ["⚧️"])
+ (":white_circle:" ["⚪"])
+ (":black_circle:" ["⚫"])
+ (":coffin:" ["⚰️"])
+ (":funeral_urn:" ["⚱️"])
+ (":soccer:" ["⚽"])
+ (":baseball:" ["⚾"])
+ (":snowman_without_snow:" ["⛄"])
+ (":partly_sunny:" ["⛅"])
+ (":thunder_cloud_and_rain:" ["⛈️"])
+ (":ophiuchus:" ["⛎"])
+ (":pick:" ["⛏️"])
+ (":helmet_with_white_cross:" ["⛑️"])
+ (":chains:" ["⛓️"])
+ (":no_entry:" ["⛔"])
+ (":shinto_shrine:" ["⛩️"])
+ (":church:" ["⛪"])
+ (":mountain:" ["⛰️"])
+ (":umbrella_on_ground:" ["⛱️"])
+ (":fountain:" ["⛲"])
+ (":golf:" ["⛳"])
+ (":ferry:" ["⛴️"])
+ (":boat:" ["⛵"])
+ (":sailboat:" ["⛵"])
+ (":skier:" ["⛷️"])
+ (":ice_skate:" ["⛸️"])
+ (":woman-bouncing-ball:" ["⛹️‍♀️"])
+ (":man-bouncing-ball:" ["⛹️‍♂️"])
+ (":person_with_ball:" ["⛹️"])
+ (":tent:" ["⛺"])
+ (":fuelpump:" ["⛽"])
+ (":scissors:" ["✂️"])
+ (":white_check_mark:" ["✅"])
+ (":airplane:" ["✈️"])
+ (":email:" ["✉️"])
+ (":envelope:" ["✉️"])
+ (":fist:" ["✊"])
+ (":hand:" ["✋"])
+ (":raised_hand:" ["✋"])
+ (":v:" ["✌️"])
+ (":writing_hand:" ["✍️"])
+ (":pencil2:" ["✏️"])
+ (":black_nib:" ["✒️"])
+ (":heavy_check_mark:" ["✔️"])
+ (":heavy_multiplication_x:" ["✖️"])
+ (":latin_cross:" ["✝️"])
+ (":star_of_david:" ["✡️"])
+ (":sparkles:" ["✨"])
+ (":eight_spoked_asterisk:" ["✳️"])
+ (":eight_pointed_black_star:" ["✴️"])
+ (":snowflake:" ["❄️"])
+ (":sparkle:" ["❇️"])
+ (":x:" ["❌"])
+ (":negative_squared_cross_mark:" ["❎"])
+ (":question:" ["❓"])
+ (":grey_question:" ["❔"])
+ (":grey_exclamation:" ["❕"])
+ (":exclamation:" ["❗"])
+ (":heavy_exclamation_mark:" ["❗"])
+ (":heavy_heart_exclamation_mark_ornament:" ["❣️"])
+ (":heart_on_fire:" ["❤️‍🔥"])
+ (":mending_heart:" ["❤️‍🩹"])
+ (":heart:" ["❤️"])
+ ("<3" ["❤️"])
+ (":heavy_plus_sign:" ["➕"])
+ (":heavy_minus_sign:" ["➖"])
+ (":heavy_division_sign:" ["➗"])
+ (":arrow_right:" ["➡️"])
+ (":curly_loop:" ["➰"])
+ (":loop:" ["➿"])
+ (":arrow_heading_up:" ["⤴️"])
+ (":arrow_heading_down:" ["⤵️"])
+ (":arrow_left:" ["⬅️"])
+ (":arrow_up:" ["⬆️"])
+ (":arrow_down:" ["⬇️"])
+ (":black_large_square:" ["⬛"])
+ (":white_large_square:" ["⬜"])
+ (":star:" ["⭐"])
+ (":o:" ["⭕"])
+ (":wavy_dash:" ["〰️"])
+ (":part_alternation_mark:" ["〽️"])
+ (":congratulations:" ["㊗️"])
+ (":secret:" ["㊙️"])))))))
+
+(emoji--define-rules)
+
+(provide 'emoji)
+;;; emoji.el ends here
diff --git a/lisp/man.el b/lisp/man.el
index adf244a11ad..d6146a2c4dc 100644
--- a/lisp/man.el
+++ b/lisp/man.el
@@ -1976,6 +1976,30 @@ Uses `Man-name-local-regexp'."
(bookmark-default-handler
`("" (buffer . ,buf) . ,(bookmark-get-bookmark-record bookmark)))))
+;;; Mouse support
+(defun Man-at-mouse (e)
+ "Open man manual at point."
+ (interactive "e")
+ (save-excursion
+ (mouse-set-point e)
+ (man (Man-default-man-entry))))
+
+;;;###autoload
+(defun Man-context-menu (menu click)
+ "Populate MENU with commands that open a man page at point."
+ (save-excursion
+ (mouse-set-point click)
+ (when (save-excursion
+ (skip-syntax-backward "^ ")
+ (and (looking-at
+ "[[:space:]]*\\([[:alnum:]_-]+([[:alnum:]]+)\\)")
+ (match-string 1)))
+ (define-key-after menu [man-separator] menu-bar-separator)
+ (define-key-after menu [man-at-mouse]
+ '(menu-item "Open man page" man-at-mouse
+ :help "Open man page around mouse click"))))
+ menu)
+
;; Init the man package variables, if not already done.
(Man-init-defvars)
diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el
index e0cf6c588c4..36cbd6a9c51 100644
--- a/lisp/menu-bar.el
+++ b/lisp/menu-bar.el
@@ -109,6 +109,16 @@
(bindings--define-key menu [separator-tab]
menu-bar-separator))
+ (bindings--define-key menu [enable-undelete-frame-mode]
+ '(menu-item "Enable Undeleting Frames" undelete-frame-mode
+ :visible (null undelete-frame-mode)
+ :help "Enable undeleting frames in this session"))
+ (bindings--define-key menu [undelete-last-deleted-frame]
+ '(menu-item "Undelete Frame" undelete-frame
+ :visible (and undelete-frame-mode
+ (car undelete-frame--deleted-frames))
+ :help "Undelete the most recently deleted frame"))
+
;; Don't use delete-frame as event name because that is a special
;; event.
(bindings--define-key menu [delete-this-frame]
diff --git a/lisp/mouse.el b/lisp/mouse.el
index 1a76b9a0b66..46dd0397d7f 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -298,6 +298,9 @@ and should return the same menu with changes such as added new menu items."
(function-item context-menu-buffers)
(function-item context-menu-vc)
(function-item context-menu-ffap)
+ (function-item Man-context-menu)
+ (function-item hi-lock-context-menu)
+ (function-item context-menu-online-search)
(function :tag "Custom function")))
:version "28.1")
@@ -531,6 +534,16 @@ Some context functions add menu items below the separator."
:help "Find file or URL from text around mouse click"))))
menu)
+(defun context-menu-online-search (menu click)
+ "Populate MENU with command to search online."
+ (save-excursion
+ (mouse-set-point click)
+ (define-key-after menu [online-search-separator] menu-bar-separator)
+ (define-key-after menu [online-search-at-mouse]
+ '(menu-item "Online search" mouse-online-search-at-point
+ :help "Search for region or word online")))
+ menu)
+
(defvar context-menu-entry
`(menu-item ,(purecopy "Context Menu") ,(make-sparse-keymap)
:filter ,(lambda (_) (context-menu-map)))
@@ -3217,6 +3230,26 @@ is copied instead of being cut."
(with-current-buffer (window-buffer window)
(setq cursor-type (nth 3 state)))))))
+(defvar eww-search-prefix)
+(defun mouse-online-search-at-point (event)
+ "Query an online search engine at EVENT.
+If a region is active, the entire region will be sent, otherwise
+the symbol at point will be used. This command uses EWW's
+default search engine, as configured by `eww-search-prefix'."
+ (interactive "e")
+ (require 'eww)
+ (let ((query (if (use-region-p)
+ (buffer-substring (region-beginning)
+ (region-end))
+ (save-excursion
+ (mouse-set-point event)
+ (thing-at-point 'symbol)))))
+ (unless query
+ (user-error "Nothing to search for"))
+ (browse-url (concat
+ eww-search-prefix
+ (mapconcat #'url-hexify-string (split-string query) "+")))))
+
;;; Bindings for mouse commands.
diff --git a/lisp/net/mailcap.el b/lisp/net/mailcap.el
index bf3c8edd1e3..daa2d5a3fb3 100644
--- a/lisp/net/mailcap.el
+++ b/lisp/net/mailcap.el
@@ -439,9 +439,10 @@ MAILCAPS if set; otherwise (on Unix) use the path from RFC 1524, plus
("/usr/local/etc/mailcap" system)))))
(when (stringp path)
(setq path (mapcar #'list (split-string path path-separator t))))
- (when (seq-some (lambda (f)
- (file-has-changed-p (car f) 'mail-parse-mailcaps))
- path)
+ (when (or (null mailcap--computed-mime-data)
+ (seq-some (lambda (f)
+ (file-has-changed-p (car f) 'mail-parse-mailcaps))
+ path))
;; Clear out all old data.
(setq mailcap--computed-mime-data nil)
;; Add the Emacs-distributed defaults (which will be used as
diff --git a/lisp/net/tramp-crypt.el b/lisp/net/tramp-crypt.el
index 36443e09830..c2c3689c610 100644
--- a/lisp/net/tramp-crypt.el
+++ b/lisp/net/tramp-crypt.el
@@ -39,7 +39,7 @@
;; first time you access a crypted remote directory. It is kept in
;; your user directory "~/.emacs.d/" with the url-encoded directory
;; name as part of the basename, and ".encfs6.xml" as suffix. Do not
-;; loose this file and the corresponding password; otherwise there is
+;; lose this file and the corresponding password; otherwise there is
;; no way to decrypt your crypted files.
;; If the user option `tramp-crypt-save-encfs-config-remote' is
diff --git a/lisp/progmodes/gud.el b/lisp/progmodes/gud.el
index b1bef82842d..3f78c9eb15b 100644
--- a/lisp/progmodes/gud.el
+++ b/lisp/progmodes/gud.el
@@ -744,10 +744,10 @@ The option \"--fullname\" must be included in this value."
output))
-(easy-mmode-defmap gud-minibuffer-local-map
- '(("\C-i" . comint-dynamic-complete-filename))
- "Keymap for minibuffer prompting of gud startup command."
- :inherit minibuffer-local-map)
+(defvar-keymap gud-minibuffer-local-map
+ :doc "Keymap for minibuffer prompting of gud startup command."
+ :parent minibuffer-local-map
+ "C-i" #'comint-dynamic-complete-filename)
(defun gud-query-cmdline (minor-mode &optional init)
(let* ((hist-sym (gud-symbol 'history nil minor-mode))
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index edd3139a7aa..5889f2ab670 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -3216,11 +3216,13 @@ detecting a prompt at the end of the buffer."
(defun python-shell-send-string-no-output (string &optional process)
"Send STRING to PROCESS and inhibit output.
Return the output."
- (let ((process (or process (python-shell-get-process-or-error)))
- (comint-preoutput-filter-functions
- '(python-shell-output-filter))
- (python-shell-output-filter-in-progress t)
- (inhibit-quit t))
+ (or process (setq process (python-shell-get-process-or-error)))
+ (cl-letf (((process-filter process)
+ (lambda (_proc str)
+ (with-current-buffer (process-buffer process)
+ (python-shell-output-filter str))))
+ (python-shell-output-filter-in-progress t)
+ (inhibit-quit t))
(or
(with-local-quit
(python-shell-send-string string process)
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index 9ce63a8f8a1..066c051cfc3 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -738,11 +738,20 @@ quit the *xref* buffer."
"Perform interactive replacement of FROM with TO in all displayed xrefs.
This command interactively replaces FROM with TO in the names of the
-references displayed in the current *xref* buffer."
+references displayed in the current *xref* buffer.
+
+When called interactively, it uses '.*' as FROM, which means
+replace the whole name. Unless called with prefix argument, in
+which case the user is prompted for both FROM and TO."
(interactive
- (let ((fr (read-regexp "Xref query-replace (regexp)" ".*")))
- (list fr
- (read-regexp (format "Xref query-replace (regexp) %s with: " fr)))))
+ (let* ((fr
+ (if current-prefix-arg
+ (read-regexp "Query-replace (regexp)" ".*")
+ ".*"))
+ (prompt (if current-prefix-arg
+ (format "Query-replace (regexp) %s with: " fr)
+ "Query-replace all matches with: ")))
+ (list fr (read-regexp prompt))))
(let* (item xrefs iter)
(save-excursion
(while (setq item (xref--search-property 'xref-item))
@@ -1469,6 +1478,22 @@ is nil, prompt only if there's no usable symbol at point."
(interactive (list (xref--read-identifier "Find references of: ")))
(xref--find-xrefs identifier 'references identifier nil))
+(defun xref-find-references-and-replace (from to)
+ "Replace all references to identifier FROM with TO."
+ (interactive
+ (let ((common
+ (query-replace-read-args "Query replace identifier" nil)))
+ (list (nth 0 common) (nth 1 common))))
+ (require 'xref)
+ (with-current-buffer
+ (let ((xref-show-xrefs-function
+ ;; Some future-proofing (bug#44905).
+ (custom--standard-value 'xref-show-xrefs-function))
+ ;; Disable auto-jumping, it will mess up replacement logic.
+ xref-auto-jump-to-first-xref)
+ (xref-find-references from))
+ (xref-query-replace-in-results ".*" to)))
+
;;;###autoload
(defun xref-find-definitions-at-mouse (event)
"Find the definition of identifier at or around mouse click.
diff --git a/lisp/subr.el b/lisp/subr.el
index 7906324f80c..dd260dfe418 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -1971,7 +1971,7 @@ one will be removed."
(format "%s hook to remove: "
(if local "Buffer-local" "Global"))
fn-alist
- nil t)
+ nil t nil 'set-variable-value-history)
fn-alist nil nil #'string=)))
(list hook function local)))
(or (boundp hook) (set hook nil))
@@ -6537,4 +6537,26 @@ string will be displayed only if BODY takes longer than TIMEOUT seconds.
(lambda ()
,@body)))
+(defun function-alias-p (func &optional noerror)
+ "Return nil if FUNC is not a function alias.
+If FUNC is a function alias, return the function alias chain.
+
+If the function alias chain contains loops, an error will be
+signalled. If NOERROR, the non-loop parts of the chain is returned."
+ (declare (side-effect-free t))
+ (let ((chain nil)
+ (orig-func func))
+ (nreverse
+ (catch 'loop
+ (while (and (symbolp func)
+ (setq func (symbol-function func))
+ (symbolp func))
+ (when (or (memq func chain)
+ (eq func orig-func))
+ (if noerror
+ (throw 'loop chain)
+ (signal 'cyclic-function-indirection (list orig-func))))
+ (push func chain))
+ chain))))
+
;;; subr.el ends here
diff --git a/lisp/vc/pcvs-info.el b/lisp/vc/pcvs-info.el
index 11d14f95766..341fa243cfa 100644
--- a/lisp/vc/pcvs-info.el
+++ b/lisp/vc/pcvs-info.el
@@ -130,9 +130,11 @@ to confuse some users sometimes."
(defvar cvs-bakprefix ".#"
"The prefix that CVS prepends to files when rcsmerge'ing.")
-(easy-mmode-defmap cvs-status-map
- '(([(mouse-2)] . cvs-mode-toggle-mark))
- "Local keymap for text properties of status.")
+(autoload 'cvs-mode-toggle-mark "pcvs")
+
+(defvar-keymap cvs-status-map
+ :doc "Local keymap for text properties of status."
+ "<mouse-2>" #'cvs-mode-toggle-mark)
;; Constructor:
diff --git a/src/buffer.c b/src/buffer.c
index 10ac91915c6..a3091015d9b 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1247,7 +1247,7 @@ buffer_local_value (Lisp_Object variable, Lisp_Object buffer)
{ /* Look in local_var_alist. */
struct Lisp_Buffer_Local_Value *blv = SYMBOL_BLV (sym);
XSETSYMBOL (variable, sym); /* Update In case of aliasing. */
- result = Fassoc (variable, BVAR (buf, local_var_alist), Qnil);
+ result = assq_no_quit (variable, BVAR (buf, local_var_alist));
if (!NILP (result))
{
if (blv->fwd.fwdptr)
diff --git a/src/data.c b/src/data.c
index e999cee242e..7422348e392 100644
--- a/src/data.c
+++ b/src/data.c
@@ -2180,7 +2180,7 @@ Instead, use `add-hook' and specify t for the LOCAL argument. */)
/* Make sure this buffer has its own value of symbol. */
XSETSYMBOL (variable, sym); /* Update in case of aliasing. */
- tem = Fassq (variable, BVAR (current_buffer, local_var_alist));
+ tem = assq_no_quit (variable, BVAR (current_buffer, local_var_alist));
if (NILP (tem))
{
if (let_shadows_buffer_binding_p (sym))
@@ -2260,7 +2260,7 @@ From now on the default value will apply in this buffer. Return VARIABLE. */)
/* Get rid of this buffer's alist element, if any. */
XSETSYMBOL (variable, sym); /* Propagate variable indirection. */
- tem = Fassq (variable, BVAR (current_buffer, local_var_alist));
+ tem = assq_no_quit (variable, BVAR (current_buffer, local_var_alist));
if (!NILP (tem))
bset_local_var_alist
(current_buffer,
@@ -2301,7 +2301,7 @@ Also see `buffer-local-boundp'.*/)
case SYMBOL_PLAINVAL: return Qnil;
case SYMBOL_LOCALIZED:
{
- Lisp_Object tail, elt, tmp;
+ Lisp_Object tmp;
struct Lisp_Buffer_Local_Value *blv = SYMBOL_BLV (sym);
XSETBUFFER (tmp, buf);
XSETSYMBOL (variable, sym); /* Update in case of aliasing. */
@@ -2309,13 +2309,9 @@ Also see `buffer-local-boundp'.*/)
if (EQ (blv->where, tmp)) /* The binding is already loaded. */
return blv_found (blv) ? Qt : Qnil;
else
- for (tail = BVAR (buf, local_var_alist); CONSP (tail); tail = XCDR (tail))
- {
- elt = XCAR (tail);
- if (EQ (variable, XCAR (elt)))
- return Qt;
- }
- return Qnil;
+ return NILP (assq_no_quit (variable, BVAR (buf, local_var_alist)))
+ ? Qnil
+ : Qt;
}
case SYMBOL_FORWARDED:
{
diff --git a/src/font.c b/src/font.c
index 266e5bc75c6..7e0219181c9 100644
--- a/src/font.c
+++ b/src/font.c
@@ -2183,7 +2183,9 @@ font_score (Lisp_Object entity, Lisp_Object *spec_prop)
/* Score three style numeric fields. Maximum difference is 127. */
for (i = FONT_WEIGHT_INDEX; i <= FONT_WIDTH_INDEX; i++)
- if (! NILP (spec_prop[i]) && ! EQ (AREF (entity, i), spec_prop[i]))
+ if (! NILP (spec_prop[i])
+ && ! EQ (AREF (entity, i), spec_prop[i])
+ && FIXNUMP (AREF (entity, i)))
{
EMACS_INT diff = ((XFIXNUM (AREF (entity, i)) >> 8)
- (XFIXNUM (spec_prop[i]) >> 8));
@@ -2764,26 +2766,31 @@ font_delete_unmatched (Lisp_Object vec, Lisp_Object spec, int size)
{
if (FIXNUMP (AREF (spec, prop)))
{
- int required = XFIXNUM (AREF (spec, prop)) >> 8;
- int candidate = XFIXNUM (AREF (entity, prop)) >> 8;
+ if (!FIXNUMP (AREF (entity, prop)))
+ prop = FONT_SPEC_MAX;
+ else
+ {
+ int required = XFIXNUM (AREF (spec, prop)) >> 8;
+ int candidate = XFIXNUM (AREF (entity, prop)) >> 8;
- if (candidate != required
+ if (candidate != required
#ifdef HAVE_NTGUI
- /* A kludge for w32 font search, where listing a
- family returns only 4 standard weights: regular,
- italic, bold, bold-italic. For other values one
- must specify the font, not just the family in the
- :family attribute of the face. But specifying
- :family in the face attributes looks for regular
- weight, so if we require exact match, the
- non-regular font will be rejected. So we relax
- the accuracy of the match here, and let
- font_sort_entities find the best match. */
- && (prop != FONT_WEIGHT_INDEX
- || eabs (candidate - required) > 100)
+ /* A kludge for w32 font search, where listing a
+ family returns only 4 standard weights: regular,
+ italic, bold, bold-italic. For other values one
+ must specify the font, not just the family in the
+ :family attribute of the face. But specifying
+ :family in the face attributes looks for regular
+ weight, so if we require exact match, the
+ non-regular font will be rejected. So we relax
+ the accuracy of the match here, and let
+ font_sort_entities find the best match. */
+ && (prop != FONT_WEIGHT_INDEX
+ || eabs (candidate - required) > 100)
#endif
- )
- prop = FONT_SPEC_MAX;
+ )
+ prop = FONT_SPEC_MAX;
+ }
}
}
if (prop < FONT_SPEC_MAX
diff --git a/src/frame.c b/src/frame.c
index c0f4f3ecde3..e5d74edc168 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -2382,9 +2382,12 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
}
DEFUN ("delete-frame", Fdelete_frame, Sdelete_frame, 0, 2, "",
- doc: /* Delete FRAME, permanently eliminating it from use.
+ doc: /* Delete FRAME, eliminating it from use.
FRAME must be a live frame and defaults to the selected one.
+When `undelete-frame-mode' is enabled, the 16 most recently deleted
+frames can be undeleted with `undelete-frame', which see.
+
A frame may not be deleted if its minibuffer serves as surrogate
minibuffer for another frame. Normally, you may not delete a frame if
all other frames are invisible, but if the second optional argument
diff --git a/src/ftfont.c b/src/ftfont.c
index 2bdcce306bc..5797300d231 100644
--- a/src/ftfont.c
+++ b/src/ftfont.c
@@ -189,6 +189,24 @@ ftfont_pattern_entity (FcPattern *p, Lisp_Object extra)
return Qnil;
if (FcPatternGetInteger (p, FC_INDEX, 0, &idx) != FcResultMatch)
return Qnil;
+#ifdef FC_VARIABLE
+ /* This is a virtual/meta FcPattern for a variable weight font, from
+ which it is possible to extract an FcRange value specifying the
+ minimum and maximum weights available in this file. We don't
+ need to know that information explicitly, so skip it. We will be
+ called with an FcPattern for each actually available, non-virtual
+ weight.
+
+ Fontconfig started generating virtual/meta patterns for variable
+ weight fonts in the same release that FC_VARIABLE was added, so
+ we conditionalize on that constant. This also ensures that
+ FcPatternGetRange is available. */
+ FcRange *range;
+ if (FcPatternGetRange (p, FC_WEIGHT, 0, &range) == FcResultMatch
+ && FcPatternGetBool (p, FC_VARIABLE, 0, &b) == FcResultMatch
+ && b == FcTrue)
+ return Qnil;
+#endif /* FC_VARIABLE */
file = (char *) str;
key = Fcons (build_unibyte_string (file), make_fixnum (idx));
@@ -863,6 +881,9 @@ ftfont_list (struct frame *f, Lisp_Object spec)
#if defined HAVE_XFT && defined FC_COLOR
FC_COLOR,
#endif
+#ifdef FC_VARIABLE
+ FC_VARIABLE,
+#endif /* FC_VARIABLE */
NULL);
if (! objset)
goto err;
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 1db166b1bad..36ed55bc039 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -6255,16 +6255,19 @@ xg_widget_key_press_event_cb (GtkWidget *widget, GdkEvent *event,
kbd_buffer_store_buffered_event (&inev, &xg_pending_quit_event);
}
-#ifdef USABLE_SIGIO
- raise (SIGIO);
-#endif
+ XNoOp (FRAME_X_DISPLAY (f));
return true;
}
bool
xg_filter_key (struct frame *frame, XEvent *xkey)
{
- GdkEvent *xg_event = gdk_event_new (GDK_KEY_PRESS);
+ GdkEvent *xg_event = gdk_event_new ((xkey->type == ButtonPress
+#ifdef HAVE_XINPUT2
+ || (xkey->type == GenericEvent
+ && xkey->xgeneric.evtype == XI_KeyPress)
+#endif
+ ) ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
GdkDisplay *dpy = gtk_widget_get_display (FRAME_GTK_WIDGET (frame));
GdkKeymap *keymap = gdk_keymap_get_for_display (dpy);
GdkModifierType consumed;
diff --git a/src/haiku_draw_support.cc b/src/haiku_draw_support.cc
index 5d355ac2058..270a619b89b 100644
--- a/src/haiku_draw_support.cc
+++ b/src/haiku_draw_support.cc
@@ -313,7 +313,7 @@ BView_DrawBitmapWithEraseOp (void *view, void *bitmap, int x,
BRect bounds = bc.Bounds ();
for (int y = 0; y < BE_RECT_HEIGHT (bounds); ++y)
{
- for (int x = 0; x <= BE_RECT_WIDTH (bounds); ++x)
+ for (int x = 0; x < BE_RECT_WIDTH (bounds); ++x)
{
if (bits[y * (stride / 4) + x] == 0xFF000000)
bits[y * (stride / 4) + x] = RGB_COLOR_UINT32 (low_color);
diff --git a/src/haiku_support.cc b/src/haiku_support.cc
index 531dfb5c642..d49e319b98c 100644
--- a/src/haiku_support.cc
+++ b/src/haiku_support.cc
@@ -136,6 +136,15 @@ gui_abort (const char *msg)
emacs_abort ();
}
+/* Convert a raw character RAW produced by the keycode KEY into a key
+ symbol and place it in KEYSYM.
+
+ If RAW cannot be converted into a keysym, value is 0. If RAW can
+ be converted into a keysym, but it should be ignored, value is -1.
+
+ Any other value means success, and that the keysym should be used
+ instead of mapping the keycode into a character. */
+
static int
keysym_from_raw_char (int32 raw, int32 key, unsigned *code)
{
@@ -186,6 +195,19 @@ keysym_from_raw_char (int32 raw, int32 key, unsigned *code)
case B_FUNCTION_KEY:
*code = XK_F1 + key - 2;
+
+ if (*code - XK_F1 == 12)
+ *code = XK_Print;
+ else if (*code - XK_F1 == 13)
+ /* Okay, Scroll Lock is a bit too much: keyboard.c doesn't
+ know about it yet, and it shouldn't, since that's a
+ modifier key.
+
+ *code = XK_Scroll_Lock; */
+ return -1;
+ else if (*code - XK_F1 == 14)
+ *code = XK_Pause;
+
break;
default:
@@ -693,6 +715,7 @@ public:
rq.window = this;
int32 raw, key;
+ int ret;
msg->FindInt32 ("raw_char", &raw);
msg->FindInt32 ("key", &key);
@@ -711,9 +734,14 @@ public:
if (mods & B_OPTION_KEY)
rq.modifiers |= HAIKU_MODIFIER_SUPER;
- if (!keysym_from_raw_char (raw, key, &rq.keysym))
+ ret = keysym_from_raw_char (raw, key, &rq.keysym);
+
+ if (!ret)
rq.keysym = 0;
+ if (ret < 0)
+ return;
+
rq.multibyte_char = 0;
if (!rq.keysym)
diff --git a/src/haikuterm.c b/src/haikuterm.c
index be28649aef2..3e99cc1c8d9 100644
--- a/src/haikuterm.c
+++ b/src/haikuterm.c
@@ -2222,6 +2222,7 @@ haiku_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
void *view = FRAME_HAIKU_VIEW (XFRAME (WINDOW_FRAME (w)));
struct face *face = p->face;
+ block_input ();
BView_draw_lock (view);
BView_StartClip (view);
@@ -2256,6 +2257,7 @@ haiku_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
}
BView_EndClip (view);
BView_draw_unlock (view);
+ unblock_input ();
}
static void
@@ -3233,7 +3235,10 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
struct frame *f = haiku_window_to_frame (b->window);
if (!f)
- continue;
+ {
+ free (b->ref);
+ continue;
+ }
inev.kind = DRAG_N_DROP_EVENT;
inev.arg = build_string_from_utf8 (b->ref);
diff --git a/src/window.c b/src/window.c
index 7155f0e6bc3..2a5e4042a48 100644
--- a/src/window.c
+++ b/src/window.c
@@ -5861,7 +5861,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
/* We moved the window start towards ZV, so PT may be now
in the scroll margin at the top. */
- move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
+ if (IT_CHARPOS (it) < PT)
+ move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
if (IT_CHARPOS (it) == PT
&& it.current_y >= this_scroll_margin
&& it.current_y <= last_y - WINDOW_TAB_LINE_HEIGHT (w)
diff --git a/src/xdisp.c b/src/xdisp.c
index 2326df4300d..977d31703fb 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -18557,6 +18557,20 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp,
|| (NILP (g->object)
&& (g->charpos == PT
|| (g->charpos == 0 && endpos - 1 == PT)));
+ /* Perhaps the point position is inside
+ invisible text? In that case, we trust
+ 'set_cursor_from_row' to do its job and
+ find the best position for the cursor. */
+ if (!exact_match_p)
+ {
+ Lisp_Object val =
+ get_char_property_and_overlay (make_fixnum (PT),
+ Qinvisible,
+ Qnil, NULL);
+
+ if (TEXT_PROP_MEANS_INVISIBLE (val) != 0)
+ exact_match_p = true;
+ }
}
if (at_zv_p || exact_match_p)
{
diff --git a/src/xfns.c b/src/xfns.c
index 028ee29a4aa..ffad0bc3d1a 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -3347,6 +3347,8 @@ setup_xi_event_mask (struct frame *f)
XISetMask (m, XI_Motion);
XISetMask (m, XI_Enter);
XISetMask (m, XI_Leave);
+ XISetMask (m, XI_FocusIn);
+ XISetMask (m, XI_FocusOut);
XISetMask (m, XI_KeyPress);
XISetMask (m, XI_KeyRelease);
XISelectEvents (FRAME_X_DISPLAY (f),
@@ -3359,6 +3361,8 @@ setup_xi_event_mask (struct frame *f)
#ifdef USE_X_TOOLKIT
XISetMask (m, XI_KeyPress);
XISetMask (m, XI_KeyRelease);
+ XISetMask (m, XI_FocusIn);
+ XISetMask (m, XI_FocusOut);
XISelectEvents (FRAME_X_DISPLAY (f),
FRAME_OUTER_WINDOW (f),
diff --git a/src/xterm.c b/src/xterm.c
index 52715892703..ec415f5ffaf 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -20,6 +20,72 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
/* New display code by Gerd Moellmann <gerd@gnu.org>. */
/* Xt features made by Fred Pierresteguy. */
+/* X window system support for GNU Emacs
+
+ This file is part of the X window system support for GNU Emacs. It
+ contains subroutines comprising the redisplay interface, setting up
+ scroll bars and widgets, and handling input.
+
+ INPUT
+
+ Emacs handles input by running pselect in a loop, which returns
+ whenever there is input available on the connection to the X
+ server. On some systems, Emacs also arranges for any new input on
+ that connection to send an asynchronous signal. Whenever pselect
+ returns, or such a signal is received and input is not blocked,
+ XTread_socket is called and translates X11 events read by Xlib into
+ struct input_events, which are then stored in the keyboard buffer,
+ to be processed and acted upon at some later time. The function
+ handle_one_xevent is responsible for handling core events after
+ they are filtered, and filtering X Input Extension events. It also
+ performs actions on some special events, such as updating the
+ dimensions of a frame after a ConfigureNotify is sent by the X
+ server to inform us that it changed.
+
+ Before such events are translated, an Emacs build with
+ internationalization enabled (the default since X11R6) will filter
+ events through an X Input Method (XIM) or GTK, which might decide
+ to intercept the event and send a different one in its place, for
+ reasons such as enabling the user to insert international
+ characters that aren't on his keyboard by typing a sequence of
+ characters which are. See the function x_filter_event and its
+ callers for more details.
+
+ Events that cause Emacs to quit are treated specially by the code
+ that stores them in the keyboard buffer and generally cause an
+ immediate interrupt. Such an interrupt can lead to a longjmp from
+ the code that stored the keyboard event, which isn't safe inside
+ XTread_socket. To avoid this problem, XTread_socket is provided a
+ special event buffer named hold_quit. When a quit event is
+ encountered, it is stored inside this special buffer, which will
+ cause the keyboard code that called XTread_socket to store it at a
+ later time when it is safe to do so.
+
+ handle_one_xevent will generally have to determine which frame an
+ event should be attributed to. This is not easy, because events
+ can come from multiple X windows, and a frame can also have
+ multiple windows. handle_one_xevent usually calls the function
+ x_any_window_to_frame, which searches for a frame by toplevel
+ window and widget windows. There are also some other functions for
+ searching by specific types of window, such as
+ x_top_window_to_frame (which only searches for frames by toplevel
+ window), and x_menubar_window_to_frame (which will only search
+ through frame menu bars).
+
+ INPUT FOCUS
+
+ Under X, the window where keyboard input is sent is not always
+ explictly defined. When there is a focus window, it receives what
+ is referred to as "explicit focus", but when there is none, it
+ receives "implicit focus" whenever the pointer enters it, and loses
+ that focus when the pointer leaves. When the toplevel window of a
+ frame receives an explicit focus event (FocusIn or FocusOut), we
+ treat that frame as having the current input focus, but when there
+ is no focus window, we treat each frame as having the input focus
+ whenever the pointer enters it, and undo that treatment when the
+ pointer leaves it. See the callers of x_detect_focus_change for
+ more details. */
+
#include <config.h>
#include <stdlib.h>
#include <math.h>
@@ -4126,7 +4192,9 @@ x_draw_glyph_string (struct glyph_string *s)
area_max_x = area_x + area_width - 1;
decoration_width = s->width;
- if (area_max_x < (s->x + decoration_width - 1))
+ if (!s->row->mode_line_p
+ && !s->row->tab_line_p
+ && area_max_x < (s->x + decoration_width - 1))
decoration_width -= (s->x + decoration_width - 1) - area_max_x;
/* Draw relief if not yet drawn. */
@@ -5252,21 +5320,18 @@ x_detect_focus_change (struct x_display_info *dpyinfo, struct frame *frame,
int focus_state
= focus_frame ? focus_frame->output_data.x->focus_state : 0;
-#ifdef USE_GTK
if (xi_event->evtype == XI_FocusIn
|| xi_event->evtype == XI_FocusOut)
x_focus_changed ((xi_event->evtype == XI_FocusIn
? FocusIn : FocusOut),
FOCUS_EXPLICIT,
dpyinfo, frame, bufp);
- else
-#endif
- if ((xi_event->evtype == XI_Enter
- || xi_event->evtype == XI_Leave)
- && (((XIEnterEvent *) xi_event)->detail
- != XINotifyInferior)
- && ((XIEnterEvent *) xi_event)->focus
- && !(focus_state & FOCUS_EXPLICIT))
+ else if ((xi_event->evtype == XI_Enter
+ || xi_event->evtype == XI_Leave)
+ && (((XIEnterEvent *) xi_event)->detail
+ != XINotifyInferior)
+ && ((XIEnterEvent *) xi_event)->focus
+ && !(focus_state & FOCUS_EXPLICIT))
x_focus_changed ((xi_event->evtype == XI_Enter
? FocusIn : FocusOut),
FOCUS_IMPLICIT,
@@ -5386,8 +5451,6 @@ x_find_modifier_meanings (struct x_display_info *dpyinfo)
dpyinfo->super_mod_mask = 0;
dpyinfo->hyper_mod_mask = 0;
- XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
-
#ifdef HAVE_XKB
if (dpyinfo->xkb_desc)
{
@@ -5432,6 +5495,8 @@ x_find_modifier_meanings (struct x_display_info *dpyinfo)
}
#endif
+ XDisplayKeycodes (dpyinfo->display, &min_code, &max_code);
+
syms = XGetKeyboardMapping (dpyinfo->display,
min_code, max_code - min_code + 1,
&syms_per_code);
@@ -5924,7 +5989,7 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
if (!f1 && insist > 0)
f1 = SELECTED_FRAME ();
- if (f1)
+ if (f1 && FRAME_X_P (f1))
{
/* Ok, we found a frame. Store all the values.
last_mouse_glyph is a rectangle used to reduce the
@@ -5934,7 +5999,6 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
on it, i.e. into the same rectangles that matrices on
the frame are divided into. */
- /* FIXME: what if F1 is not an X frame? */
dpyinfo = FRAME_DISPLAY_INFO (f1);
remember_mouse_glyph (f1, win_x, win_y, &dpyinfo->last_mouse_glyph);
dpyinfo->last_mouse_glyph_frame = f1;
@@ -8285,8 +8349,10 @@ x_filter_event (struct x_display_info *dpyinfo, XEvent *event)
&& event->type == GenericEvent
&& (event->xgeneric.extension
== dpyinfo->xi2_opcode)
- && (event->xgeneric.evtype
- == XI_KeyPress))
+ && ((event->xgeneric.evtype
+ == XI_KeyPress)
+ || (event->xgeneric.evtype
+ == XI_KeyRelease)))
{
f1 = x_any_window_to_frame (dpyinfo,
((XIDeviceEvent *)
@@ -9458,7 +9524,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
case EnterNotify:
x_display_set_last_user_time (dpyinfo, event->xcrossing.time);
- x_detect_focus_change (dpyinfo, any, event, &inev.ie);
+
+ if (x_top_window_to_frame (dpyinfo, event->xcrossing.window))
+ x_detect_focus_change (dpyinfo, any, event, &inev.ie);
#ifdef HAVE_XWIDGETS
{
@@ -9540,7 +9608,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
}
#endif
x_display_set_last_user_time (dpyinfo, event->xcrossing.time);
- x_detect_focus_change (dpyinfo, any, event, &inev.ie);
+
+ if (x_top_window_to_frame (dpyinfo, event->xcrossing.window))
+ x_detect_focus_change (dpyinfo, any, event, &inev.ie);
f = x_top_window_to_frame (dpyinfo, event->xcrossing.window);
#if defined HAVE_X_TOOLKIT && defined HAVE_XINPUT2
@@ -10151,13 +10221,23 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_detect_focus_change (dpyinfo, any, event, &inev.ie);
goto XI_OTHER;
case XI_Enter:
- any = x_any_window_to_frame (dpyinfo, enter->event);
+
+ any = x_top_window_to_frame (dpyinfo, enter->event);
ev.x = lrint (enter->event_x);
ev.y = lrint (enter->event_y);
- ev.window = leave->event;
-
+ ev.window = enter->event;
x_display_set_last_user_time (dpyinfo, xi_event->time);
- x_detect_focus_change (dpyinfo, any, event, &inev.ie);
+
+ /* There is no need to handle entry/exit events for
+ passive focus from non-top windows at all, since they
+ are an inferiors of the frame's top window, which will
+ get virtual events. */
+ if (any)
+ x_detect_focus_change (dpyinfo, any, event, &inev.ie);
+
+ if (!any)
+ any = x_any_window_to_frame (dpyinfo, enter->event);
+
{
#ifdef HAVE_XWIDGETS
struct xwidget_view *xwidget_view = xwidget_view_from_window (enter->event);
@@ -10221,11 +10301,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_note_mouse_movement (dpyinfo->last_mouse_glyph_frame, &ev);
#endif
goto XI_OTHER;
+
case XI_Leave:
ev.x = lrint (leave->event_x);
ev.y = lrint (leave->event_y);
ev.window = leave->event;
- any = x_any_window_to_frame (dpyinfo, leave->event);
+ any = x_top_window_to_frame (dpyinfo, leave->event);
#ifdef HAVE_XWIDGETS
{
@@ -10243,7 +10324,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
#endif
x_display_set_last_user_time (dpyinfo, xi_event->time);
- x_detect_focus_change (dpyinfo, any, event, &inev.ie);
+
+ if (any)
+ x_detect_focus_change (dpyinfo, any, event, &inev.ie);
+
+ if (!any)
+ any = x_any_window_to_frame (dpyinfo, leave->event);
#ifndef USE_X_TOOLKIT
f = x_top_window_to_frame (dpyinfo, leave->event);
@@ -11167,6 +11253,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
case XI_PropertyEvent:
case XI_HierarchyChanged:
case XI_DeviceChanged:
+
+#ifdef XISlaveSwitch
+ if (xi_event->evtype == XI_DeviceChanged
+ && (((XIDeviceChangedEvent *) xi_event)->reason
+ == XISlaveSwitch))
+ goto XI_OTHER;
+#endif
x_init_master_valuators (dpyinfo);
goto XI_OTHER;
#ifdef XI_TouchBegin
@@ -11433,6 +11526,22 @@ handle_one_xevent (struct x_display_info *dpyinfo,
x_find_modifier_meanings (dpyinfo);
}
+ else
+ {
+ dpyinfo->xkb_desc = XkbGetMap (dpyinfo->display,
+ (XkbKeySymsMask
+ | XkbKeyTypesMask
+ | XkbModifierMapMask
+ | XkbVirtualModsMask),
+ XkbUseCoreKbd);
+
+ if (dpyinfo->xkb_desc)
+ XkbGetNames (dpyinfo->display,
+ XkbGroupNamesMask | XkbVirtualModNamesMask,
+ dpyinfo->xkb_desc);
+ }
+
+ XkbRefreshKeyboardMapping (&xkbevent->map);
}
}
#endif
diff --git a/src/xwidget.c b/src/xwidget.c
index 7d6d256a191..45879b15cbe 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -1447,8 +1447,8 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
#ifdef HAVE_XINPUT2
else if (event->type == GenericEvent)
{
- xg_event->crossing.x = (gdouble) xev->event_x;
- xg_event->crossing.y = (gdouble) xev->event_y;
+ xg_event->crossing.x = x;
+ xg_event->crossing.y = y;
xg_event->crossing.x_root = (gdouble) xev->root_x;
xg_event->crossing.y_root = (gdouble) xev->root_y;
xg_event->crossing.time = xev->time;
diff --git a/test/Makefile.in b/test/Makefile.in
index d6ab7b244d2..9ad994e1101 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -75,7 +75,7 @@ EMACS_EXTRAOPT =
EMACSOPT = --no-init-file --no-site-file --no-site-lisp -L "$(SEPCHAR)$(srcdir)" $(elpa_opts) $(EMACS_EXTRAOPT)
# Prevent any settings in the user environment causing problems.
-unexport EMACSDATA EMACSDOC EMACSPATH GREP_OPTIONS XDG_CONFIG_HOME
+unexport EMACSDATA EMACSDOC EMACSLOADPATH EMACSPATH GREP_OPTIONS XDG_CONFIG_HOME
# To run tests under a debugger, set this to eg: "gdb --args".
GDB =
@@ -118,10 +118,8 @@ MODULES_EMACSOPT :=
endif
# The actual Emacs command run in the targets below.
-# Prevent any setting of EMACSLOADPATH in user environment causing problems,
-# and prevent locals to influence the text of the errors we expect to receive.
-emacs = LANG=C EMACSLOADPATH= \
- EMACS_TEST_DIRECTORY=$(abspath $(srcdir)) \
+# Prevent locales influencing the text of the errors we expect to receive.
+emacs = LANG=C EMACS_TEST_DIRECTORY=$(abspath $(srcdir)) \
$(GDB) $(TEST_TIMEOUT) "$(EMACS)" $(MODULES_EMACSOPT) $(EMACSOPT)
# Set HOME to a nonexistent directory to prevent tests from accessing
diff --git a/test/lisp/emacs-lisp/edebug-tests.el b/test/lisp/emacs-lisp/edebug-tests.el
index d238bffdaa1..35259a796a0 100644
--- a/test/lisp/emacs-lisp/edebug-tests.el
+++ b/test/lisp/emacs-lisp/edebug-tests.el
@@ -1094,5 +1094,15 @@ This avoids potential duplicate definitions (Bug#41988)."
(edebug-new-definition name))))
(should-error (eval-buffer) :type 'invalid-read-syntax))))
+(ert-deftest edebug-tests-inline ()
+ "Check that Edebug can instrument inline functions (Bug#53068)."
+ (with-temp-buffer
+ (print '(define-inline edebug-tests-inline (arg)
+ (inline-quote ,arg))
+ (current-buffer))
+ (let ((edebug-all-defs t)
+ (edebug-initial-mode 'Go-nonstop))
+ (eval-buffer))))
+
(provide 'edebug-tests)
;;; edebug-tests.el ends here
diff --git a/test/lisp/emacs-lisp/ert-tests.el b/test/lisp/emacs-lisp/ert-tests.el
index ac130644743..270cca1c2e7 100644
--- a/test/lisp/emacs-lisp/ert-tests.el
+++ b/test/lisp/emacs-lisp/ert-tests.el
@@ -881,6 +881,9 @@ This macro is used to test if macroexpansion in `should' works."
"Check that `lexical-binding' in `ert-deftest' has the file value."
(should (equal lexical-binding t)))
+(ert-deftest ert-test-get-explainer ()
+ (should (eq (ert--get-explainer 'string-equal) 'ert--explain-string-equal))
+ (should (eq (ert--get-explainer 'string=) 'ert--explain-string-equal)))
(provide 'ert-tests)
diff --git a/test/lisp/eshell/esh-opt-tests.el b/test/lisp/eshell/esh-opt-tests.el
index 532adfb733a..255768635b1 100644
--- a/test/lisp/eshell/esh-opt-tests.el
+++ b/test/lisp/eshell/esh-opt-tests.el
@@ -57,7 +57,7 @@
'((?u "user" t user "execute a command as another USER")
:parse-leading-options-only))))
(should
- (equal '("world" "emerge")
+ (equal '("DN" "emerge" "world")
(eshell--process-args
"sudo"
'("-u" "root" "emerge" "-uDN" "world")
@@ -65,59 +65,132 @@
(ert-deftest test-eshell-eval-using-options ()
"Tests for `eshell-eval-using-options'."
+ ;; Test short options.
(eshell-eval-using-options
- "sudo" '("-u" "root" "whoami")
- '((?u "user" t user "execute a command as another USER")
- :parse-leading-options-only)
- (should (equal user "root")))
+ "ls" '("-a" "/some/path")
+ '((?a "all" nil show-all
+ "do not ignore entries starting with ."))
+ (should (eq show-all t))
+ (should (equal args '("/some/path"))))
(eshell-eval-using-options
- "sudo" '("--user" "root" "whoami")
- '((?u "user" t user "execute a command as another USER")
- :parse-leading-options-only)
- (should (equal user "root")))
+ "ls" '("/some/path")
+ '((?a "all" nil show-all
+ "do not ignore entries starting with ."))
+ (should (eq show-all nil))
+ (should (equal args '("/some/path"))))
+ ;; Test long options.
(eshell-eval-using-options
- "sudo" '("emerge" "-uDN" "world")
- '((?u "user" t user "execute a command as another USER"))
- (should (equal user "world")))
+ "ls" '("--all" "/some/path")
+ '((?a "all" nil show-all
+ "do not ignore entries starting with ."))
+ (should (eq show-all t))
+ (should (equal args '("/some/path"))))
+
+ ;; Test options with constant values.
(eshell-eval-using-options
- "sudo" '("emerge" "-uDN" "world")
- '((?u "user" t user "execute a command as another USER")
- :parse-leading-options-only)
- (should (eq user nil)))
+ "ls" '("/some/path" "-h")
+ '((?h "human-readable" 1024 human-readable
+ "print sizes in human readable format"))
+ (should (eql human-readable 1024))
+ (should (equal args '("/some/path"))))
+ (eshell-eval-using-options
+ "ls" '("/some/path" "--human-readable")
+ '((?h "human-readable" 1024 human-readable
+ "print sizes in human readable format"))
+ (should (eql human-readable 1024))
+ (should (equal args '("/some/path"))))
+ (eshell-eval-using-options
+ "ls" '("/some/path")
+ '((?h "human-readable" 1024 human-readable
+ "print sizes in human readable format"))
+ (should (eq human-readable nil))
+ (should (equal args '("/some/path"))))
+ ;; Test options with user-specified values.
+ (eshell-eval-using-options
+ "ls" '("-I" "*.txt" "/some/path")
+ '((?I "ignore" t ignore-pattern
+ "do not list implied entries matching pattern"))
+ (should (equal ignore-pattern "*.txt"))
+ (should (equal args '("/some/path"))))
+ (eshell-eval-using-options
+ "ls" '("-I*.txt" "/some/path")
+ '((?I "ignore" t ignore-pattern
+ "do not list implied entries matching pattern"))
+ (should (equal ignore-pattern "*.txt"))
+ (should (equal args '("/some/path"))))
(eshell-eval-using-options
- "ls" '("-I" "*.txt" "/dev/null")
+ "ls" '("--ignore" "*.txt" "/some/path")
'((?I "ignore" t ignore-pattern
- "do not list implied entries matching pattern"))
- (should (equal ignore-pattern "*.txt")))
+ "do not list implied entries matching pattern"))
+ (should (equal ignore-pattern "*.txt"))
+ (should (equal args '("/some/path"))))
+ (eshell-eval-using-options
+ "ls" '("--ignore=*.txt" "/some/path")
+ '((?I "ignore" t ignore-pattern
+ "do not list implied entries matching pattern"))
+ (should (equal ignore-pattern "*.txt"))
+ (should (equal args '("/some/path"))))
+ ;; Test multiple short options in a single token.
(eshell-eval-using-options
- "ls" '("-l" "/dev/null")
- '((?l nil long-listing listing-style
- "use a long listing format"))
- (should (eql listing-style 'long-listing)))
+ "ls" '("-al" "/some/path")
+ '((?a "all" nil show-all
+ "do not ignore entries starting with .")
+ (?l nil long-listing listing-style
+ "use a long listing format"))
+ (should (eq t show-all))
+ (should (eql listing-style 'long-listing))
+ (should (equal args '("/some/path"))))
(eshell-eval-using-options
- "ls" '("/dev/null")
- '((?l nil long-listing listing-style
- "use a long listing format"))
- (should (eq listing-style nil)))
+ "ls" '("-aI*.txt" "/some/path")
+ '((?a "all" nil show-all
+ "do not ignore entries starting with .")
+ (?I "ignore" t ignore-pattern
+ "do not list implied entries matching pattern"))
+ (should (eq t show-all))
+ (should (equal ignore-pattern "*.txt"))
+ (should (equal args '("/some/path"))))
+ ;; Test that "--" terminates options.
(eshell-eval-using-options
- "ls" '("/dev/null" "-h")
- '((?h "human-readable" 1024 human-readable
- "print sizes in human readable format"))
- (should (eql human-readable 1024)))
+ "ls" '("--" "-a")
+ '((?a "all" nil show-all
+ "do not ignore entries starting with ."))
+ (should (eq show-all nil))
+ (should (equal args '("-a"))))
(eshell-eval-using-options
- "ls" '("/dev/null" "--human-readable")
- '((?h "human-readable" 1024 human-readable
- "print sizes in human readable format"))
- (should (eql human-readable 1024)))
+ "ls" '("--" "--all")
+ '((?a "all" nil show-all
+ "do not ignore entries starting with ."))
+ (should (eq show-all nil))
+ (should (equal args '("--all"))))
+
+ ;; Test :parse-leading-options-only.
(eshell-eval-using-options
- "ls" '("/dev/null")
- '((?h "human-readable" 1024 human-readable
- "print sizes in human readable format"))
- (should (eq human-readable nil))))
+ "sudo" '("-u" "root" "whoami")
+ '((?u "user" t user "execute a command as another USER")
+ :parse-leading-options-only)
+ (should (equal user "root"))
+ (should (equal args '("whoami"))))
+ (eshell-eval-using-options
+ "sudo" '("--user" "root" "whoami")
+ '((?u "user" t user "execute a command as another USER")
+ :parse-leading-options-only)
+ (should (equal user "root"))
+ (should (equal args '("whoami"))))
+ (eshell-eval-using-options
+ "sudo" '("emerge" "-uDN" "world")
+ '((?u "user" t user "execute a command as another USER"))
+ (should (equal user "DN"))
+ (should (equal args '("emerge" "world"))))
+ (eshell-eval-using-options
+ "sudo" '("emerge" "-uDN" "world")
+ '((?u "user" t user "execute a command as another USER")
+ :parse-leading-options-only)
+ (should (eq user nil))
+ (should (equal args '("emerge" "-uDN" "world")))))
(provide 'esh-opt-tests)
diff --git a/test/lisp/ffap-tests.el b/test/lisp/ffap-tests.el
index aebc9b6dbb9..0fdc31e8b61 100644
--- a/test/lisp/ffap-tests.el
+++ b/test/lisp/ffap-tests.el
@@ -141,6 +141,23 @@ left alone when opening a URL in an external browser."
(let (kill-buffer-query-functions)
(kill-buffer (call-interactively #'find-file-at-point)))))))
+(ert-deftest ffap-test-path ()
+ (skip-unless (file-exists-p "/bin"))
+ (skip-unless (file-exists-p "/usr/bin"))
+ (with-temp-buffer
+ (insert "/usr/bin:/bin")
+ (goto-char (point-min))
+ (should (equal (ffap-file-at-point) "/usr/bin")))
+ (with-temp-buffer
+ (insert "/usr/bin:/bin")
+ (goto-char (point-min))
+ (search-forward ":")
+ (should (equal (ffap-file-at-point) "/bin")))
+ (with-temp-buffer
+ (insert ":/bin")
+ (goto-char (point-min))
+ (should (equal (ffap-file-at-point) nil))))
+
(provide 'ffap-tests)
;;; ffap-tests.el ends here
diff --git a/test/lisp/help-fns-tests.el b/test/lisp/help-fns-tests.el
index 6ee7b4f3eb1..4df8e3c9ef6 100644
--- a/test/lisp/help-fns-tests.el
+++ b/test/lisp/help-fns-tests.el
@@ -177,4 +177,13 @@ Return first line of the output of (describe-function-1 FUNC)."
(should-not (find-lisp-object-file-name help-fns--test-var 'defface))
(should-not (find-lisp-object-file-name help-fns--test-var 1))))
+(ert-deftest help-fns--analyze-function-recursive ()
+ (defalias 'help-fns--a 'help-fns--b)
+ (should (equal (help-fns--analyze-function 'help-fns--a)
+ '(help-fns--a help-fns--b t help-fns--b)))
+ ;; Make a loop and see that it doesn't infloop.
+ (defalias 'help-fns--b 'help-fns--a)
+ (should (equal (help-fns--analyze-function 'help-fns--a)
+ '(help-fns--a help-fns--b t help-fns--b))))
+
;;; help-fns-tests.el ends here
diff --git a/test/lisp/so-long-tests/spelling-tests.el b/test/lisp/so-long-tests/spelling-tests.el
index 317513e9a91..ce4b0844c99 100644
--- a/test/lisp/so-long-tests/spelling-tests.el
+++ b/test/lisp/so-long-tests/spelling-tests.el
@@ -36,12 +36,11 @@
;; make lisp/so-long-tests/spelling-tests SELECTOR=t
;; Only define the test if spell-checking is possible.
-(when (and ispell-program-name
- (executable-find ispell-program-name)
- (condition-case ()
- (progn (ispell-check-version) t)
- (error nil))
- (member "british" (ispell-valid-dictionary-list)))
+(when (ignore-errors
+ (and ispell-program-name
+ (executable-find ispell-program-name)
+ (progn (ispell-check-version) t)
+ (member "british" (ispell-valid-dictionary-list))))
(ert-deftest so-long-spelling ()
"Check the spelling in the source code."
:tags '(:unstable) ;; It works for me, but I'm not sure about others.
@@ -51,8 +50,9 @@
;; The Emacs test Makefile's use of HOME=/nonexistent triggers an error
;; when starting the inferior ispell process, so we set HOME to a valid
;; (but empty) temporary directory for this test.
- (ert-with-temp-file tmpdir
- :suffix "so-long.ispell"
+ (ert-with-temp-directory tmpdir
+ :prefix "so-long."
+ :suffix ".ispell"
(let* ((process-environment (cons (format "HOME=%s" tmpdir)
process-environment))
(find-spelling-mistake
diff --git a/test/lisp/subr-tests.el b/test/lisp/subr-tests.el
index 9be7511bdc9..512b6545355 100644
--- a/test/lisp/subr-tests.el
+++ b/test/lisp/subr-tests.el
@@ -1007,5 +1007,22 @@ final or penultimate step during initialization."))
(should (equal (ensure-list :foo) '(:foo)))
(should (equal (ensure-list '(1 2 3)) '(1 2 3))))
+(ert-deftest test-alias-p ()
+ (should-not (function-alias-p 1))
+
+ (defun subr-tests--fun ())
+ (should-not (function-alias-p 'subr-tests--fun))
+
+ (defalias 'subr-tests--a 'subr-tests--b)
+ (defalias 'subr-tests--b 'subr-tests--c)
+ (should (equal (function-alias-p 'subr-tests--a)
+ '(subr-tests--b subr-tests--c)))
+
+ (defalias 'subr-tests--d 'subr-tests--e)
+ (defalias 'subr-tests--e 'subr-tests--d)
+ (should-error (function-alias-p 'subr-tests--d))
+ (should (equal (function-alias-p 'subr-tests--d t)
+ '(subr-tests--e))))
+
(provide 'subr-tests)
;;; subr-tests.el ends here