diff options
author | Alan Mackenzie <acm@muc.de> | 2022-01-14 19:28:07 +0000 |
---|---|---|
committer | Alan Mackenzie <acm@muc.de> | 2022-01-14 19:28:07 +0000 |
commit | d87a34597c9f0be967f75ff8cfd0ace4392da63f (patch) | |
tree | c9474eb0156af143ce61a0c5bcec659546b56300 | |
parent | 57b698f15913385aec7bc9745016b961c0aa5c55 (diff) | |
parent | d29291d665e808307126bf52c3e748fef78f0f9c (diff) | |
download | emacs-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
73 files changed, 3247 insertions, 310 deletions
@@ -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. @@ -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 |