diff --git a/admin/notes/unicode b/admin/notes/unicode index 21233ac2819..c41b9a6d26d 100644 --- a/admin/notes/unicode +++ b/admin/notes/unicode @@ -116,8 +116,12 @@ FONT-NAME-REGEXP is checked using `string-match'." Visit "emoji-zwj-sequences.txt" and "emoji-sequences.txt" with the rebuilt Emacs, and check that the sample sequences are composed -properly. Note that your emoji font might not have glyphs for the -newest codepoints yet. +properly. Also check the Unicode style chart file available at +https://unicode.org/emoji/charts/emoji-style.txt for any issues +involving VS-15 and VS-16, if so you may need to update the value +generated for auto-composition-emoji-eligible-codepoints by +admin/unidata/emoji-zwj.awk. Note that your emoji font might not have +glyphs for the newest codepoints yet. Finally, etc/NEWS should be updated to announce the support for the new Unicode version. diff --git a/admin/unidata/blocks.awk b/admin/unidata/blocks.awk index 96b0413875d..314ac3e9394 100755 --- a/admin/unidata/blocks.awk +++ b/admin/unidata/blocks.awk @@ -221,31 +221,9 @@ FILENAME ~ "emoji-data.txt" && /^[0-9A-F].*; Emoji_Presentation / { } END { - ## These codepoints have Emoji_Presentation = No, but they are - ## used in emoji-sequences.txt and emoji-zwj-sequences.txt (with a - ## Variation Selector), so force them into the emoji script so - ## they will get composed correctly. FIXME: delete this when we - ## can change the font used for a codepoint based on whether it's - ## followed by a VS (usually VS-16) idx = 0 - override_start[idx] = "1F3CB" - override_end[idx] = "1F3CC" - idx++ - override_start[idx] = "1F3F3" - override_end[idx] = "1F3F4" - idx++ - override_start[idx] = "1F441" - override_end[idx] = "1F441" - idx++ - override_start[idx] = "1F574" - override_end[idx] = "1F575" - idx++ - override_start[idx] = "1F590" - override_end[idx] = "1F590" - - ## These are here so that font_range can choose Emoji presentation - ## for the preceding codepoint when it encounters a VS - idx++ + # ## These are here so that font_range can choose Emoji presentation + # ## for the preceding codepoint when it encounters a VS override_start[idx] = "FE00" override_end[idx] = "FE0F" diff --git a/admin/unidata/emoji-zwj.awk b/admin/unidata/emoji-zwj.awk index 5aca157cbd4..d4e2944ca34 100644 --- a/admin/unidata/emoji-zwj.awk +++ b/admin/unidata/emoji-zwj.awk @@ -64,6 +64,44 @@ END { print ";;; emoji-zwj.el --- emoji zwj character composition table -*- lexical-binding:t -*-" print ";;; Automatically generated from admin/unidata/emoji-{zwj-,}sequences.txt" print "(eval-when-compile (require 'regexp-opt))" + + # The following codepoints are not emoji, but they are part of + # emoji sequences. We have code in font.c:font_range that will + # try to display them with the emoji font anyway. + + trigger_codepoints[1] = "261D" + trigger_codepoints[2] = "26F9" + trigger_codepoints[3] = "270C" + trigger_codepoints[4] = "270D" + trigger_codepoints[5] = "2764" + trigger_codepoints[6] = "1F3CB" + trigger_codepoints[7] = "1F3CC" + trigger_codepoints[8] = "1F3F3" + trigger_codepoints[9] = "1F3F4" + trigger_codepoints[10] = "1F441" + trigger_codepoints[11] = "1F574" + trigger_codepoints[12] = "1F575" + trigger_codepoints[13] = "1F590" + + printf "(setq auto-composition-emoji-eligible-codepoints\n" + printf "'(" + + for (trig in trigger_codepoints) + { + printf("\n?\\N{U+%s}", trigger_codepoints[trig]) + } + printf "\n))\n\n" + + # We add entries for 'codepoint U+FE0F' here to ensure that the + # code in font_range is triggered. + + for (trig in trigger_codepoints) + { + codepoint = trigger_codepoints[trig] + c = sprintf("\\N{U+%s}", codepoint) + vec[codepoint] = vec[codepoint] "\n\"" c "\\N{U+FE0F}\"" + } + print "(dolist (elt `(" for (elt in ch) @@ -98,6 +136,5 @@ END { print " 0" print " 'compose-gstring-for-graphic))))" - print "\n" - print "(provide 'emoji-zwj)" + printf "\n(provide 'emoji-zwj)" } diff --git a/doc/emacs/windows.texi b/doc/emacs/windows.texi index facbc7f3ed8..8cb88a20954 100644 --- a/doc/emacs/windows.texi +++ b/doc/emacs/windows.texi @@ -444,7 +444,7 @@ selected window write: @group (customize-set-variable 'display-buffer-alist - '("\\*scratch\\*" (display-buffer-same-window))) + '(("\\*scratch\\*" (display-buffer-same-window)))) @end group @end example diff --git a/doc/lispintro/emacs-lisp-intro.texi b/doc/lispintro/emacs-lisp-intro.texi index 81ae2536339..2a990ca9ce8 100644 --- a/doc/lispintro/emacs-lisp-intro.texi +++ b/doc/lispintro/emacs-lisp-intro.texi @@ -1177,7 +1177,7 @@ are different from the meaning the letters make as a word. For example, the word for the South American sloth, the @samp{ai}, is completely different from the two words, @samp{a}, and @samp{i}. -There are many kinds of atom in nature but only a few in Lisp: for +There are many kinds of atoms in nature but only a few in Lisp: for example, @dfn{numbers}, such as 37, 511, or 1729, and @dfn{symbols}, such as @samp{+}, @samp{foo}, or @samp{forward-line}. The words we have listed in the examples above are all symbols. In everyday Lisp diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi index f851d12c080..56ac7118135 100644 --- a/doc/lispref/frames.texi +++ b/doc/lispref/frames.texi @@ -642,7 +642,7 @@ automatically increase the outer width of a frame in order to accommodate an overlong tool bar. @item Tab Bar -@cindex internal tab bar +@cindex tab bar The tab bar (@pxref{Tab Bars,,,emacs, The GNU Emacs Manual}) is always drawn by Emacs itself. The tab bar appears above the tool bar in Emacs built with an internal tool bar, and below the tool bar in @@ -1218,10 +1218,10 @@ width of one scroll bar provided this option is @code{nil} and keep it unchanged if this option is @code{t} or a list containing @code{vertical-scroll-bars}. -The default value is @code{'(tab-bar-lines tool-bar-lines)} for Lucid, +The default value is @code{(tab-bar-lines tool-bar-lines)} for Lucid, Motif and MS-Windows (which means that adding/removing a tool or tab bar there does not change the outer frame height), -@code{'(tab-bar-lines)} on all other window systems including GTK+ +@code{(tab-bar-lines)} on all other window systems including GTK+ (which means that changing any of the parameters listed above with the exception of @code{tab-bar-lines} may change the size of the outer frame), and @code{t} otherwise (which means the outer frame size never diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index fb72b8f7005..262516054ab 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -213,7 +213,8 @@ window} which is used for displaying a tooltip in a tooltip frame Each window belongs to exactly one frame (@pxref{Frames}). For all windows belonging to a specific frame, we sometimes also say that these -windows are @dfn{owned} by that frame or simply that they are on that frame. +windows are @dfn{owned} by that frame or simply that they are on that +frame. @defun window-frame &optional window This function returns the specified @var{window}'s frame---the frame @@ -233,12 +234,6 @@ minibuffer window (@pxref{Minibuffer Windows}) in that list. If active. If @var{minibuffer} is neither @code{nil} nor @code{t}, the minibuffer window is never included. -Note that the window returned by @code{minibuffer-window} called with -the argument @var{frame} is returned by @code{window-list} called with -the same argument if and only if that window actually belongs to -@var{frame}. If the minibuffer window is owned by another frame, it is -not returned by this invocation. - The optional argument @var{window}, if non-@code{nil}, must be a live window on the specified frame; then @var{window} will be the first element in the returned list. If @var{window} is omitted or @code{nil}, diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi index 8cc3eafc874..4e95b1211fa 100644 --- a/doc/misc/tramp.texi +++ b/doc/misc/tramp.texi @@ -1071,7 +1071,7 @@ capable of servicing requests from @value{tramp}. This non-native @value{tramp} method connects via the Server Message Block (SMB) networking protocol to hosts running file servers that are -typically based on @url{https://www.samba.org/,,Samba} or MS Windows. +typically based on @uref{https://www.samba.org/,,Samba} or MS Windows. Using @command{smbclient} requires a few tweaks when working with @value{tramp}: @@ -1323,7 +1323,7 @@ possible, @value{tramp} emulates those operations otherwise. @vindex tramp-rclone-program The program @command{rclone} allows to access different system -storages in the cloud, see @url{https://rclone.org/} for a list of +storages in the cloud, see @uref{https://rclone.org/} for a list of supported systems. If the @command{rclone} program isn't found in your @env{PATH} environment variable, you can tell @value{tramp} its absolute path via the user option @code{tramp-rclone-program}. @@ -1362,7 +1362,7 @@ for accessing the system storage, you should use it. On local hosts which have installed the @command{sshfs} client for mounting a file system based on @command{sftp}, this method can be used, see -@url{https://github.com/libfuse/sshfs/blob/master/README.rst/}. If +@uref{https://github.com/libfuse/sshfs/blob/master/README.rst/}. If the @command{sshfs} program isn't found in your @env{PATH} environment variable, you can tell @value{tramp} its absolute path via the user option @code{tramp-sshfs-program}. @@ -5192,13 +5192,14 @@ tramp-compat-with-mutex} @value{tramp} comes with compatibility code for different Emacs versions. When you see such a message (the text might differ), you -don't use the Emacs built-in version of @value{tramp}. In case you -have installed @value{tramp} from GNU ELPA, +don't use the Emacs built-in version of @value{tramp}, and you must +recompile it. In case you have installed @value{tramp} from GNU ELPA, @ifset installchapter -@xref{ELPA Installation}. +@xref{ELPA Installation}. Otherwise, @xref{Recompilation}. @end ifset @ifclear installchapter -see the package README file for instructions how to recompile it. +see @uref{@value{trampurl}#ELPA-Installation}. Otherwise, see +@uref{@value{trampurl}#Recompilation}. @end ifclear diff --git a/etc/NEWS.28 b/etc/NEWS.28 index b7c4346db97..b410ef77cfa 100644 --- a/etc/NEWS.28 +++ b/etc/NEWS.28 @@ -2567,7 +2567,7 @@ that prompt for a project directory. +++ *** New prefix keymap 'project-prefix-map'. Key sequences that invoke project-related commands start with the -prefix 'C-x p'. Type "C-x p C-h" to show the full list. +prefix 'C-x p'. Type 'C-x p C-h' to show the full list. +++ *** New commands 'project-dired', 'project-vc-dir', 'project-shell', @@ -3220,19 +3220,20 @@ batch mode. +++ ** New transient mode 'repeat-mode' to allow shorter key sequences. -You can type 'C-x u u' instead of 'C-x u C-x u' to undo many changes, -'C-x o o' instead of 'C-x o C-x o' to switch several windows, -'C-x { { } } ^ ^ v v' to resize the selected window interactively, -'M-g n n p p' to navigate next-error matches. Any other key exits -transient mode and then is executed normally. 'repeat-exit-key' -defines an additional key to exit mode like 'isearch-exit' ('RET'). -The user option 'repeat-exit-timeout' specifies the number of -seconds of idle time to break the repetition chain automatically. -With 'repeat-keep-prefix' you can keep the prefix arg of the previous -command. For example, this can help to reverse the window navigation -direction with e.g. 'C-x o M-- o o'. Also it can help to set a new -step with e.g. 'C-x { C-5 { { {', which will set the window resizing -step to 5 columns. +Type 'M-x repeat-mode RET' to enable this mode. You can then type +'C-x u u' instead of 'C-x u C-x u' to undo many changes, 'C-x o o' +instead of 'C-x o C-x o' to switch windows, 'C-x { { } } ^ ^ v v' to +resize the selected window interactively, 'M-g n n p p' to navigate +next-error matches. Any other key exits transient mode and then is +executed normally. 'repeat-exit-key' defines an additional key to +exit mode like 'isearch-exit' ('RET'). The user option +'repeat-exit-timeout' specifies the number of seconds of idle time to +break the repetition chain automatically. With 'repeat-keep-prefix' +you can keep the prefix arg of the previous command. For example, +this can help to reverse the window navigation direction with +e.g. 'C-x o M-- o o'. Also it can help to set a new step with +e.g. 'C-x { C-5 { { {', which will set the window resizing step to 5 +columns. --- ** New themes 'modus-vivendi' and 'modus-operandi'. diff --git a/lisp/composite.el b/lisp/composite.el index 859253ec7e2..99f528a0779 100644 --- a/lisp/composite.el +++ b/lisp/composite.el @@ -834,8 +834,15 @@ and the second is a glyph for a variation selector." (lgstring-set-glyph gstring 1 nil) (throw 'tag gstring))))))) +;; We explicitly don't handle #xFE0F (VS-16) here, because that's +;; taken care of by font_range in font.c, which will check for an +;; emoji font for codepoints used in compositions even if they're not +;; emoji themselves, and thus choose the Emoji presentation for them +;; when followed by VS-16. VS-15 *is* handled here, because if it's +;; handled in font_range, we end up choosing the Emoji presentation +;; rather than the Text presentation. (let ((elt '([".." 1 compose-gstring-for-variation-glyph]))) - (set-char-table-range composition-function-table '(#xFE00 . #xFE0F) elt) + (set-char-table-range composition-function-table '(#xFE00 . #xFE0E) elt) (set-char-table-range composition-function-table '(#xE0100 . #xE01EF) elt)) (defun auto-compose-chars (func from to font-object string direction) diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el index 6d8bed1d786..362a258f43d 100644 --- a/lisp/net/tramp-adb.el +++ b/lisp/net/tramp-adb.el @@ -128,8 +128,7 @@ It is used for TCP/IP devices." (file-attributes . tramp-adb-handle-file-attributes) (file-directory-p . tramp-handle-file-directory-p) (file-equal-p . tramp-handle-file-equal-p) - ;; FIXME: This is too sloppy. - (file-executable-p . tramp-handle-file-exists-p) + (file-executable-p . tramp-adb-handle-file-executable-p) (file-exists-p . tramp-handle-file-exists-p) (file-in-directory-p . tramp-handle-file-in-directory-p) (file-local-copy . tramp-adb-handle-file-local-copy) @@ -147,7 +146,7 @@ It is used for TCP/IP devices." (file-notify-rm-watch . tramp-handle-file-notify-rm-watch) (file-notify-valid-p . tramp-handle-file-notify-valid-p) (file-ownership-preserved-p . ignore) - (file-readable-p . tramp-handle-file-exists-p) + (file-readable-p . tramp-adb-handle-file-readable-p) (file-regular-p . tramp-handle-file-regular-p) (file-remote-p . tramp-handle-file-remote-p) (file-selinux-context . tramp-handle-file-selinux-context) @@ -515,28 +514,31 @@ Emacs dired can't find files." (set-file-modes tmpfile (logior (or (file-modes filename) 0) #o0400))) tmpfile))) +(defun tramp-adb-handle-file-executable-p (filename) + "Like `file-executable-p' for Tramp files." + (with-parsed-tramp-file-name filename nil + (with-tramp-file-property v localname "file-executable-p" + (tramp-adb-send-command-and-check + v (format "test -x %s" (tramp-shell-quote-argument localname)))))) + +(defun tramp-adb-handle-file-readable-p (filename) + "Like `file-readable-p' for Tramp files." + (with-parsed-tramp-file-name filename nil + (with-tramp-file-property v localname "file-readable-p" + (or (tramp-handle-file-readable-p filename) + (tramp-adb-send-command-and-check + v (format "test -r %s" (tramp-shell-quote-argument localname))))))) + (defun tramp-adb-handle-file-writable-p (filename) - "Like `file-writable-p' for Tramp files. -But handle the case, if the \"test\" command is not available." + "Like `file-writable-p' for Tramp files." (with-parsed-tramp-file-name filename nil (with-tramp-file-property v localname "file-writable-p" - (if (tramp-adb-find-test-command v) - (if (file-exists-p filename) - (tramp-adb-send-command-and-check - v (format "test -w %s" (tramp-shell-quote-argument localname))) - (and - (file-directory-p (file-name-directory filename)) - (file-writable-p (file-name-directory filename)))) - - ;; Missing "test" command on Android < 4. - (let ((rw-path "/data/data")) - (tramp-message - v 5 - "Not implemented yet (assuming \"/data/data\" is writable): %s" - localname) - (and (>= (length localname) (length rw-path)) - (string= (substring localname 0 (length rw-path)) - rw-path))))))) + (if (file-exists-p filename) + (tramp-adb-send-command-and-check + v (format "test -w %s" (tramp-shell-quote-argument localname))) + (and + (file-directory-p (file-name-directory filename)) + (file-writable-p (file-name-directory filename))))))) (defun tramp-adb-handle-write-region (start end filename &optional append visit lockname mustbenew) @@ -1043,12 +1045,13 @@ implementation will be used." (rename-file remote-tmpstderr stderr)))) ;; Read initial output. Remove the first ;; line, which is the command echo. - (while - (progn - (goto-char (point-min)) - (not (re-search-forward "[\n]" nil t))) - (tramp-accept-process-output p 0)) - (delete-region (point-min) (point)) + (unless (eq filter t) + (while + (progn + (goto-char (point-min)) + (not (re-search-forward "[\n]" nil t))) + (tramp-accept-process-output p 0)) + (delete-region (point-min) (point))) ;; Provide error buffer. This shows only ;; initial error messages; messages arriving ;; later on will be inserted when the @@ -1141,12 +1144,6 @@ error and non-nil on success." (let ((inhibit-read-only t)) (delete-region (point-min) (point-max))) (zerop (apply #'tramp-call-process vec tramp-adb-program nil t nil args)))) -(defun tramp-adb-find-test-command (vec) - "Check whether the ash has a builtin \"test\" command. -This happens for Android >= 4.0." - (with-tramp-connection-property vec "test" - (tramp-adb-send-command-and-check vec "type test"))) - ;; Connection functions (defun tramp-adb-send-command (vec command &optional neveropen nooutput) diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el index 115d005c0ca..ebe57a8bcec 100644 --- a/lisp/net/tramp-gvfs.el +++ b/lisp/net/tramp-gvfs.el @@ -788,7 +788,7 @@ It has been changed in GVFS 1.14.") (file-notify-rm-watch . tramp-handle-file-notify-rm-watch) (file-notify-valid-p . tramp-handle-file-notify-valid-p) (file-ownership-preserved-p . ignore) - (file-readable-p . tramp-gvfs-handle-file-readable-p) + (file-readable-p . tramp-handle-file-readable-p) (file-regular-p . tramp-handle-file-regular-p) (file-remote-p . tramp-handle-file-remote-p) (file-selinux-context . tramp-handle-file-selinux-context) @@ -1396,8 +1396,7 @@ If FILE-SYSTEM is non-nil, return file system attributes." "Like `file-executable-p' for Tramp files." (with-parsed-tramp-file-name filename nil (with-tramp-file-property v localname "file-executable-p" - (and (file-exists-p filename) - (tramp-check-cached-permissions v ?x))))) + (tramp-check-cached-permissions v ?x)))) (defun tramp-gvfs-handle-file-name-all-completions (filename directory) "Like `file-name-all-completions' for Tramp files." @@ -1519,31 +1518,6 @@ If FILE-SYSTEM is non-nil, return file system attributes." (when string (tramp-message proc 10 "Rest string:\n%s" string)) (process-put proc 'rest-string string))) -(defun tramp-gvfs-handle-file-readable-p (filename) - "Like `file-readable-p' for Tramp files." - (with-parsed-tramp-file-name filename nil - (with-tramp-file-property v localname "file-readable-p" - (and (file-exists-p filename) - (or (tramp-check-cached-permissions v ?r) - ;; `tramp-check-cached-permissions' doesn't handle - ;; symbolic links. - (and (stringp (file-symlink-p filename)) - (file-readable-p - (concat - (file-remote-p filename) (file-symlink-p filename)))) - ;; If the user is different from what we guess to be - ;; the user, we don't know. Let's check, whether - ;; access is restricted explicitly. - (and (/= (tramp-get-remote-uid v 'integer) - (tramp-compat-file-attribute-user-id - (file-attributes filename 'integer))) - (not - (string-equal - "FALSE" - (cdr (assoc - "access::can-read" - (tramp-gvfs-get-file-attributes filename))))))))))) - (defun tramp-gvfs-handle-file-system-info (filename) "Like `file-system-info' for Tramp files." (setq filename (directory-file-name (expand-file-name filename))) diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index 6984dd8b429..6f3b3245225 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -1580,9 +1580,7 @@ ID-FORMAT valid values are `string' and `integer'." "Like `file-readable-p' for Tramp files." (with-parsed-tramp-file-name filename nil (with-tramp-file-property v localname "file-readable-p" - ;; Examine `file-attributes' cache to see if request can be - ;; satisfied without remote operation. - (or (tramp-check-cached-permissions v ?r) + (or (tramp-handle-file-readable-p filename) (tramp-run-test "-r" filename))))) ;; Functions implemented using the basic functions above. diff --git a/lisp/net/tramp-sudoedit.el b/lisp/net/tramp-sudoedit.el index 516d46da37d..845f31d09b1 100644 --- a/lisp/net/tramp-sudoedit.el +++ b/lisp/net/tramp-sudoedit.el @@ -464,8 +464,9 @@ the result will be a local, non-Tramp, file name." "Like `file-readable-p' for Tramp files." (with-parsed-tramp-file-name filename nil (with-tramp-file-property v localname "file-readable-p" - (tramp-sudoedit-send-command - v "test" "-r" (tramp-compat-file-name-unquote localname))))) + (or (tramp-handle-file-readable-p filename) + (tramp-sudoedit-send-command + v "test" "-r" (tramp-compat-file-name-unquote localname)))))) (defun tramp-sudoedit-handle-set-file-modes (filename mode &optional flag) "Like `set-file-modes' for Tramp files." diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 318b4e454da..372e0a2cb73 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -2087,8 +2087,7 @@ VEC-OR-PROC identifies the connection to use, SIGNAL is the signal identifier to be raised, remaining arguments passed to `tramp-message'. Finally, signal SIGNAL is raised with FMT-STRING and ARGUMENTS." - (let ((inhibit-message t) - signal-hook-function) + (let (signal-hook-function) (tramp-backtrace vec-or-proc) (unless arguments ;; FMT-STRING could be just a file name, as in @@ -2198,9 +2197,10 @@ the resulting error message." ;; `custom-initialize-*' functions provoke `void-variable' errors. ;; We don't want to see them in the backtrace. (unless (eq error-symbol 'void-variable) - (tramp-error - (car tramp-current-connection) error-symbol - (mapconcat (lambda (x) (format "%s" x)) data " ")))) + (let ((inhibit-message t)) + (tramp-error + (car tramp-current-connection) error-symbol + (mapconcat (lambda (x) (format "%s" x)) data " "))))) (put #'tramp-signal-hook-function 'tramp-suppress-trace t) @@ -3275,10 +3275,18 @@ User is always nil." (defun tramp-handle-access-file (filename string) "Like `access-file' for Tramp files." - (unless (file-readable-p (file-truename filename)) - (tramp-compat-file-missing - (tramp-dissect-file-name filename) - (format "%s: %s" string filename)))) + (setq filename (file-truename filename)) + (with-parsed-tramp-file-name filename v + (if (file-exists-p filename) + (unless + (funcall + (if (file-directory-p filename) + #'file-accessible-directory-p #'file-readable-p) + filename) + (tramp-error + v 'file-error (format "%s: Permission denied, %s" string filename))) + (tramp-compat-file-missing + v (format "%s: No such file or directory, %s" string filename))))) (defun tramp-handle-add-name-to-file (filename newname &optional ok-if-already-exists) @@ -3568,6 +3576,17 @@ User is always nil." (tramp-compat-file-attribute-modification-time (file-attributes file1)))))) +(defun tramp-handle-file-readable-p (filename) + "Like `file-readable-p' for Tramp files." + (with-parsed-tramp-file-name filename nil + (with-tramp-file-property v localname "file-readable-p" + (or (tramp-check-cached-permissions v ?r) + ;; `tramp-check-cached-permissions' doesn't handle symbolic + ;; links. + (when-let ((symlink (file-symlink-p filename))) + (and (stringp symlink) + (file-readable-p (concat (file-remote-p filename) symlink)))))))) + (defun tramp-handle-file-regular-p (filename) "Like `file-regular-p' for Tramp files." (and (file-exists-p filename) @@ -4220,7 +4239,12 @@ substitution. SPEC-LIST is a list of char/value pairs used for :name name :buffer buffer :command (append `(,login-program) login-args command) :coding coding :noquery noquery :connection-type connection-type - :filter filter :sentinel sentinel :stderr stderr)) + :sentinel sentinel :stderr stderr)) + ;; Set filter. Prior Emacs 29.1, it doesn't work reliable + ;; to provide it as `make-process' argument when filter is + ;; t. See Bug#51177. + (when filter + (set-process-filter p filter)) (tramp-message v 6 "%s" (string-join (process-command p) " ")) p)))))) diff --git a/lisp/progmodes/bug-reference.el b/lisp/progmodes/bug-reference.el index c6327c1a3f3..63850571c53 100644 --- a/lisp/progmodes/bug-reference.el +++ b/lisp/progmodes/bug-reference.el @@ -72,7 +72,7 @@ so that it is considered safe, see `enable-local-variables'.") (get s 'bug-reference-url-format))))) (defcustom bug-reference-bug-regexp - "\\(\\(?:[Bb]ug ?#?\\|[Pp]atch ?#\\|RFE ?#\\|PR [a-z+-]+/\\)\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)" + "\\(\\b\\(?:[Bb]ug ?#?\\|[Pp]atch ?#\\|RFE ?#\\|PR [a-z+-]+/\\)\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)" "Regular expression matching bug references. The first subexpression defines the region of the bug-reference overlay, i.e., the region being fontified and made clickable in @@ -350,7 +350,7 @@ generated from `bug-reference-forge-alist'." ;; `bug-reference-url-format' and ;; `bug-reference-bug-regexp' aren't set already. ("git\\.\\(?:sv\\|savannah\\)\\.gnu\\.org:" - "\\<\\(\\(?:[Bb]ug ?#?\\)\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)\\>" + "\\(\\b\\(?:[Bb]ug ?#?\\)\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)\\>" ,(lambda (_) "https://debbugs.gnu.org/%s")) ;; Entries for the software forges of @@ -395,7 +395,7 @@ applicable." ,(regexp-opt '("@debbugs.gnu.org" "-devel@gnu.org" ;; List-Id of Gnus devel mailing list. "ding.gnus.org")) - "\\([Bb]ug ?#?\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)" + "\\(\\b[Bb]ug ?#?\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)" "https://debbugs.gnu.org/%s")) "An alist for setting up `bug-reference-mode' in mail modes. @@ -526,7 +526,7 @@ From, and Cc against HEADER-REGEXP in `((,(concat "#" (regexp-opt '("emacs" "gnus" "org-mode" "rcirc" "erc") 'words)) "Libera.Chat" - "\\([Bb]ug ?#?\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)" + "\\(\\b[Bb]ug ?#?\\([0-9]+\\(?:#[0-9]+\\)?\\)\\)" "https://debbugs.gnu.org/%s")) "An alist for setting up `bug-reference-mode' in IRC modes. diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index 20cdb72ccf1..c42c95764a2 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -10409,6 +10409,7 @@ This function might do hidden buffer changes." ;; are directly inside a class (etc.) called "bar". (save-excursion (and + type-start (progn (goto-char name-start) (not (memq (c-forward-type) '(nil maybe)))) diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index 10a37942571..9522055670d 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el @@ -877,17 +877,17 @@ namespace but with lower confidence." ;; ^ index K ^ index J ^ index I (let* ((i (elisp--xref-list-index)) (i-head (looking-at-sym)) - (i-paren (and i-head (eq (char-before) ?\() + (i-paren (and i (eq (char-before) ?\() (progn (backward-char) t))) (i-quoted (and i-paren (memq (char-before) '(?\' ?`)))) (j (and i-paren (elisp--xref-list-index))) (j-head (and j (looking-at-sym))) - (j-paren (and j-head (eq (char-before) ?\() + (j-paren (and j (eq (char-before) ?\() (progn (backward-char) t))) (j-quoted (and j-paren (memq (char-before) '(?\' ?`)))) (k (and j-paren (elisp--xref-list-index))) (k-head (and k (looking-at-sym))) - (k-paren (and k-head (eq (char-before) ?\() + (k-paren (and k (eq (char-before) ?\() (progn (backward-char) t))) (k-quoted (and k-paren (memq (char-before) '(?\' ?`))))) (cond diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index 3dc95c91691..03556919b20 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el @@ -239,7 +239,7 @@ For any other value of KEY, the value is t." (string-to-number (string-replace "tab-" "" key-name))))) (t t))) -(defvar tab-bar-drag-maybe) +(defvar tab-bar--dragging-in-progress) (defun tab-bar--event-to-item (posn) "This function extracts extra info from the mouse event at position POSN. @@ -248,7 +248,7 @@ It returns a list of the form (KEY KEY-BINDING CLOSE-P), where: KEY-BINDING is the binding of KEY; CLOSE-P is non-nil if the mouse event was a click on the close button \"x\", nil otherwise." - (setq tab-bar-drag-maybe nil) + (setq tab-bar--dragging-in-progress nil) (if (posn-window posn) (let ((caption (car (posn-string posn)))) (when caption @@ -280,7 +280,7 @@ existing tab." (interactive "e") (let* ((item (tab-bar--event-to-item (event-start event))) (tab-number (tab-bar--key-to-number (nth 0 item)))) - (setq tab-bar-drag-maybe t) + (setq tab-bar--dragging-in-progress t) ;; Don't close the tab when clicked on the close button. Also ;; don't add new tab on down-mouse. Let `tab-bar-mouse-1' do this. (unless (or (eq (car item) 'add-tab) (nth 2 item)) @@ -357,7 +357,7 @@ only when you click on its \"x\" close button." This command should be bound to a drag event. It moves the tab at the mouse-down event to the position at mouse-up event." (interactive "e") - (setq tab-bar-drag-maybe nil) + (setq tab-bar--dragging-in-progress nil) (let ((from (tab-bar--key-to-number (nth 0 (tab-bar--event-to-item (event-start event))))) diff --git a/src/composite.c b/src/composite.c index f456e7a835d..c170805d9dd 100644 --- a/src/composite.c +++ b/src/composite.c @@ -2124,6 +2124,17 @@ GSTRING, or modify GSTRING itself and return it. See also the documentation of `auto-composition-mode'. */); Vcomposition_function_table = Fmake_char_table (Qnil, Qnil); + DEFVAR_LISP ("auto-composition-emoji-eligible-codepoints", Vauto_composition_emoji_eligible_codepoints, + doc: /* List of codepoints for which auto-composition will check for an emoji font. + +These are codepoints which have Emoji_Presentation = No, and thus by +default are not displayed as emoji. In certain circumstances, such as +when followed by U+FE0F (VS-16) the emoji font should be used for +them anyway. + +This list is auto-generated, you should not need to modify it. */); + Vauto_composition_emoji_eligible_codepoints = Qnil; + defsubr (&Scompose_region_internal); defsubr (&Scompose_string_internal); defsubr (&Sfind_composition_internal); diff --git a/src/font.c b/src/font.c index 83f0f8296ad..6cd4a6b5c11 100644 --- a/src/font.c +++ b/src/font.c @@ -3860,6 +3860,23 @@ font_at (int c, ptrdiff_t pos, struct face *face, struct window *w, #ifdef HAVE_WINDOW_SYSTEM +/* Check if CH is a codepoint for which we should attempt to use the + emoji font, even if the codepoint itself has Emoji_Presentation = + No. Vauto_composition_emoji_eligible_codepoints is filled in for + us by admin/unidata/emoji-zwj.awk. */ +static bool +codepoint_is_emoji_eligible (int ch) +{ + if (EQ (CHAR_TABLE_REF (Vchar_script_table, ch), Qemoji)) + return true; + + if (! NILP (Fmemq (make_fixnum (ch), + Vauto_composition_emoji_eligible_codepoints))) + return true; + + return false; +} + /* Check how many characters after character/byte position POS/POS_BYTE (at most to *LIMIT) can be displayed by the same font in the window W. FACE, if non-NULL, is the face selected for the character at POS. @@ -3907,8 +3924,7 @@ font_range (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t *limit, /* If the composition was triggered by an emoji, use a character from 'script-representative-chars', rather than the first character in the string, to determine the font to use. */ - if (EQ (CHAR_TABLE_REF (Vchar_script_table, ch), - Qemoji)) + if (codepoint_is_emoji_eligible (ch)) { Lisp_Object val = assq_no_quit (Qemoji, Vscript_representative_chars); if (CONSP (val)) diff --git a/src/xdisp.c b/src/xdisp.c index 578458bd248..738f22abedd 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -33780,7 +33780,7 @@ note_mouse_highlight (struct frame *f, int x, int y) if (EQ (window, f->tab_bar_window)) { note_tab_bar_highlight (f, x, y); - if (tab_bar_drag_maybe) + if (tab_bar__dragging_in_progress) { cursor = FRAME_OUTPUT_DATA (f)->hand_cursor; goto set_cursor; @@ -35916,9 +35916,9 @@ When nil, mouse-movement events will not be generated as long as the mouse stays within the extent of a single glyph (except for images). */); mouse_fine_grained_tracking = false; - DEFVAR_BOOL ("tab-bar-drag-maybe", tab_bar_drag_maybe, + DEFVAR_BOOL ("tab-bar--dragging-in-progress", tab_bar__dragging_in_progress, doc: /* Non-nil when maybe dragging tab bar item. */); - tab_bar_drag_maybe = false; + tab_bar__dragging_in_progress = false; DEFVAR_BOOL ("redisplay-skip-initial-frame", redisplay_skip_initial_frame, doc: /* Non-nil to skip redisplay in initial frame. diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el index da15401be05..8c7fc48848b 100644 --- a/test/lisp/net/tramp-tests.el +++ b/test/lisp/net/tramp-tests.el @@ -3159,7 +3159,20 @@ This tests also `file-directory-p' and `file-accessible-directory-p'." (regexp-opt (directory-files tmp-name1)) (length (directory-files tmp-name1))))))) - ;; Check error case. + ;; Check error cases. + (when (and (tramp--test-supports-file-modes-p) + ;; With "sshfs", directories with zero file + ;; modes are still "accessible". + (not (tramp--test-sshfs-p)) + ;; A directory is always accessible for user "root". + (not (zerop (tramp-compat-file-attribute-user-id + (file-attributes tmp-name1))))) + (set-file-modes tmp-name1 0) + (with-temp-buffer + (should-error + (insert-directory tmp-name1 nil) + :type 'file-error)) + (set-file-modes tmp-name1 #o777)) (delete-directory tmp-name1 'recursive) (with-temp-buffer (should-error @@ -3372,9 +3385,22 @@ This tests also `access-file', `file-readable-p', (tramp-get-remote-gid tramp-test-vec 'integer))) (delete-file tmp-name1)) + (when (and (tramp--test-supports-file-modes-p) + ;; A file is always accessible for user "root". + (not (zerop (tramp-compat-file-attribute-user-id + (file-attributes + tramp-test-temporary-file-directory))))) + (write-region "foo" nil tmp-name1) + (set-file-modes tmp-name1 0) + (should-error + (access-file tmp-name1 "error") + :type 'file-error) + (set-file-modes tmp-name1 #o777) + (delete-file tmp-name1)) (should-error (access-file tmp-name1 "error") :type tramp-file-missing) + ;; `file-ownership-preserved-p' should return t for ;; non-existing files. (when test-file-ownership-preserved-p diff --git a/test/lisp/progmodes/elisp-mode-tests.el b/test/lisp/progmodes/elisp-mode-tests.el index 6bc4fefb28a..8a3669c4272 100644 --- a/test/lisp/progmodes/elisp-mode-tests.el +++ b/test/lisp/progmodes/elisp-mode-tests.el @@ -965,6 +965,17 @@ evaluation of BODY." (should (equal (elisp--xref-infer-namespace p6) 'maybe-variable)) (should (equal (elisp--xref-infer-namespace p7) 'variable))) + (elisp-mode-test--with-buffer + (concat "(let (({p1}alpha {p2}beta)\n" + " ({p3}gamma ({p4}delta {p5}epsilon)))\n" + " ({p6}zeta))\n") + (should (equal (elisp--xref-infer-namespace p1) 'variable)) + (should (equal (elisp--xref-infer-namespace p2) 'variable)) + (should (equal (elisp--xref-infer-namespace p3) 'variable)) + (should (equal (elisp--xref-infer-namespace p4) 'function)) + (should (equal (elisp--xref-infer-namespace p5) 'maybe-variable)) + (should (equal (elisp--xref-infer-namespace p6) 'function))) + (elisp-mode-test--with-buffer (concat "(defun {p1}alpha () {p2}beta)\n" "(defface {p3}gamma ...)\n"