diff options
328 files changed, 23345 insertions, 20106 deletions
@@ -2,7 +2,7 @@ Copyright (C) 2001-2023 Free Software Foundation, Inc. See the end of the file for license conditions. -This directory tree holds version 29.0.60 of GNU Emacs, the extensible, +This directory tree holds version 30.0.50 of GNU Emacs, the extensible, customizable, self-documenting real-time display editor. The file INSTALL in this directory says how to build and install GNU diff --git a/admin/admin.el b/admin/admin.el index 735d426b09b..90f810b79c6 100644 --- a/admin/admin.el +++ b/admin/admin.el @@ -110,7 +110,7 @@ Root must be the root of an Emacs source tree." (submatch (1+ (in "0-9.")))))) (set-version-in-file root "configure.ac" version (rx (and "AC_INIT" (1+ (not (in ?,))) - ?, (0+ space) ?\[ + ?, (0+ space) (submatch (1+ (in "0-9.")))))) (set-version-in-file root "nt/README.W32" version (rx (and "version" (1+ space) @@ -843,8 +843,11 @@ $Date: %s $ (package-install pkg) (require pkg nil t)))) +(declare-function org-html-export-as-html "ox-html.el") (defvar org-html-postamble) (defvar org-html-mathjax-template) +(defvar htmlize-output-type) + (defun make-news-html-file (root version) "Convert the NEWS file into an HTML file." (interactive (let ((root diff --git a/admin/find-gc.el b/admin/find-gc.el index cce4a8402a7..7cb319d867a 100644 --- a/admin/find-gc.el +++ b/admin/find-gc.el @@ -100,7 +100,7 @@ Also store it in `find-gc-unsafe-list'." -(defun trace-call-tree (&optional ignored) +(defun trace-call-tree (&optional _ignored) (message "Setting up directories...") (setq find-gc-subrs-called nil) (let ((case-fold-search nil) diff --git a/admin/gitmerge.el b/admin/gitmerge.el index a172fa2bc9b..396d2fe2ac5 100644 --- a/admin/gitmerge.el +++ b/admin/gitmerge.el @@ -293,7 +293,7 @@ should not be skipped." "Try to resolve conflicts in FILE with smerge. Returns non-nil if conflicts remain." (unless (file-exists-p file) (error "Gitmerge-resolve: Can't find %s" file)) - (with-demoted-errors + (with-demoted-errors "Error: %S" (let ((exists (find-buffer-visiting file))) (with-current-buffer (let ((enable-local-variables :safe) (enable-local-eval nil)) diff --git a/admin/merge-gnulib b/admin/merge-gnulib index 6aa52bc7539..f47c5e6e8d4 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib @@ -33,13 +33,14 @@ GNULIB_MODULES=' crypto/md5 crypto/md5-buffer crypto/sha1-buffer crypto/sha256-buffer crypto/sha512-buffer d-type diffseq double-slash-root dtoastr dtotimespec dup2 - environ execinfo explicit_bzero faccessat + environ execinfo faccessat fchmodat fcntl fcntl-h fdopendir file-has-acl filemode filename filevercmp flexmember fpieee free-posix fstatat fsusage fsync futimens getloadavg getopt-gnu getrandom gettime gettimeofday gitlog-to-changelog ieee754-h ignore-value intprops largefile libgmp lstat - manywarnings memmem-simple mempcpy memrchr minmax mkostemp mktime + manywarnings memmem-simple mempcpy memrchr memset_explicit + minmax mkostemp mktime nanosleep nproc nstrftime pathmax pipe2 pselect pthread_sigmask qcopy-acl readlink readlinkat regex diff --git a/admin/notes/git-workflow b/admin/notes/git-workflow index 717fc550776..d33f49a1aca 100644 --- a/admin/notes/git-workflow +++ b/admin/notes/git-workflow @@ -16,14 +16,14 @@ Initial setup Then we want to clone the repository. We normally want to have both the current master and (if there is one) the active release branch -(eg emacs-28). +(eg emacs-29). mkdir ~/emacs cd ~/emacs git clone <membername>@git.sv.gnu.org:/srv/git/emacs.git master cd master git config push.default current -git worktree add ../emacs-28 emacs-28 +git worktree add ../emacs-29 emacs-29 You now have both branches conveniently accessible, and you can do "git pull" in them once in a while to keep updated. @@ -67,10 +67,10 @@ which will look like commit 958b768a6534ae6e77a8547a56fc31b46b63710b -cd ~/emacs/emacs-28 +cd ~/emacs/emacs-29 git cherry-pick -xe 958b768a6534ae6e77a8547a56fc31b46b63710b -and optionally add "Backport:" to the commit string. Then +and add "Backport:" to the commit string. Then git push @@ -109,7 +109,7 @@ up-to-date by doing a pull. Then start Emacs with emacs -l admin/gitmerge.el -f gitmerge You'll be asked for the branch to merge, which will default to -(eg) 'origin/emacs-28', which you should accept. Merging a local tracking +(eg) 'origin/emacs-29', which you should accept. Merging a local tracking branch is discouraged, since it might not be up-to-date, or worse, contain commits from you which are not yet pushed upstream. diff --git a/build-aux/config.guess b/build-aux/config.guess index b30b9fdc8ef..980b0208381 100755 --- a/build-aux/config.guess +++ b/build-aux/config.guess @@ -1,6 +1,6 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2023 Free Software Foundation, Inc. +# Copyright 1992-2022 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale diff --git a/build-aux/config.sub b/build-aux/config.sub index 9e118bdee3c..baf1512b3c0 100755 --- a/build-aux/config.sub +++ b/build-aux/config.sub @@ -1,6 +1,6 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2023 Free Software Foundation, Inc. +# Copyright 1992-2022 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale diff --git a/build-aux/update-copyright b/build-aux/update-copyright index ce919bac727..99196fceef6 100755 --- a/build-aux/update-copyright +++ b/build-aux/update-copyright @@ -137,7 +137,7 @@ eval 'exec perl -wSx -0777 -pi "$0" "$@"' if 0; -my $VERSION = '2020-04-04.15:07'; # UTC +my $VERSION = '2023-01-11.04:24'; # UTC # The definition above must lie within the first 8 lines in order # for the Emacs time-stamp write hook (at end) to update it. # If you change this file with Emacs, please let the write hook @@ -280,7 +280,7 @@ if (defined $stmt_re) } # Replace the old copyright statement. - s/$stmt_re/$stmt_wrapped/; + s/$stmt_re/$stmt_wrapped/g; } } else diff --git a/configure.ac b/configure.ac index 645082c9746..fc17dbd8318 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,7 @@ dnl along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. AC_PREREQ([2.65]) dnl Note this is parsed by (at least) make-dist and lisp/cedet/ede/emacs.el. -AC_INIT([GNU Emacs], [29.0.60], [bug-gnu-emacs@gnu.org], [], +AC_INIT([GNU Emacs], [30.0.50], [bug-gnu-emacs@gnu.org], [], [https://www.gnu.org/software/emacs/]) dnl Set emacs_config_options to the options of 'configure', quoted for the shell, @@ -1139,6 +1139,7 @@ AS_IF([test $gl_gcc_warnings = no], # clang is unduly picky about some things. if test "$emacs_cv_clang" = yes; then + gl_WARN_ADD([-Wno-bitwise-instead-of-logical]) gl_WARN_ADD([-Wno-missing-braces]) gl_WARN_ADD([-Wno-null-pointer-arithmetic]) gl_WARN_ADD([-Wno-implicit-const-int-float-conversion]) @@ -1841,7 +1842,9 @@ AC_CHECK_HEADERS_ONCE( coff.h pty.h sys/resource.h sys/utsname.h pwd.h utmp.h util.h - sanitizer/lsan_interface.h]) + sanitizer/lsan_interface.h + sanitizer/asan_interface.h + sanitizer/common_interface_defs.h]) AC_CACHE_CHECK([for ADDR_NO_RANDOMIZE], [emacs_cv_personality_addr_no_randomize], @@ -2693,39 +2696,6 @@ if test "${HAVE_X11}" = "yes"; then export LD_RUN_PATH fi - if test "${opsys}" = "gnu-linux"; then - AC_CACHE_CHECK([whether X on GNU/Linux needs -b to link], [emacs_cv_b_link], - [AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], - [[XOpenDisplay ("foo");]])], - [xgnu_linux_first_failure=no], - [xgnu_linux_first_failure=yes]) - if test "${xgnu_linux_first_failure}" = "yes"; then - OLD_CPPFLAGS="$CPPFLAGS" - OLD_LIBS="$LIBS" - CPPFLAGS="$CPPFLAGS -b i486-linuxaout" - LIBS="$LIBS -b i486-linuxaout" - AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], - [[XOpenDisplay ("foo");]])], - [xgnu_linux_second_failure=no], - [xgnu_linux_second_failure=yes]) - if test "${xgnu_linux_second_failure}" = "yes"; then - # If we get the same failure with -b, there is no use adding -b. - # So leave it out. This plays safe. - emacs_cv_b_link=no - else - emacs_cv_b_link=yes - fi - CPPFLAGS=$OLD_CPPFLAGS - LIBS=$OLD_LIBS - else - emacs_cv_b_link=no - fi]) - if test "x$emacs_cv_b_link" = xyes ; then - LD_SWITCH_X_SITE="$LD_SWITCH_X_SITE -b i486-linuxaout" - C_SWITCH_X_SITE="$C_SWITCH_X_SITE -b i486-linuxaout" - fi - fi - # Reportedly, some broken Solaris systems have XKBlib.h but are missing # header files included from there. AC_CACHE_CHECK([for Xkb], [emacs_cv_xkb], @@ -3935,21 +3905,10 @@ if test "${HAVE_X11}" = "yes"; then if test "${HAVE_XCB}" = "yes"; then AC_CHECK_LIB([X11-xcb], [XGetXCBConnection], [HAVE_X11_XCB=yes]) if test "${HAVE_X11_XCB}" = "yes"; then - AC_CHECK_LIB([xcb-util], [xcb_aux_sync], [HAVE_XCB_UTIL=yes]) - if test "${HAVE_XCB_UTIL}" = "yes"; then - AC_DEFINE([USE_XCB], [1], -[Define to 1 if you have the XCB library and X11-XCB library for mixed - X11/XCB programming.]) - XCB_LIBS="-lX11-xcb -lxcb -lxcb-util" - else - AC_CHECK_LIB([xcb-aux], [xcb_aux_sync], [HAVE_XCB_AUX=yes]) - if test "${HAVE_XCB_AUX}" = "yes"; then - AC_DEFINE([USE_XCB], [1], + AC_DEFINE([USE_XCB], [1], [Define to 1 if you have the XCB library and X11-XCB library for mixed - X11/XCB programming.]) - XCB_LIBS="-lX11-xcb -lxcb -lxcb-aux" - fi - fi +X11/XCB programming.]) + XCB_LIBS="-lX11-xcb -lxcb" fi fi fi @@ -4217,11 +4176,13 @@ AC_SUBST_FILE([module_env_snippet_26]) AC_SUBST_FILE([module_env_snippet_27]) AC_SUBST_FILE([module_env_snippet_28]) AC_SUBST_FILE([module_env_snippet_29]) +AC_SUBST_FILE([module_env_snippet_30]) module_env_snippet_25="$srcdir/src/module-env-25.h" module_env_snippet_26="$srcdir/src/module-env-26.h" module_env_snippet_27="$srcdir/src/module-env-27.h" module_env_snippet_28="$srcdir/src/module-env-28.h" module_env_snippet_29="$srcdir/src/module-env-29.h" +module_env_snippet_30="$srcdir/src/module-env-30.h" emacs_major_version="${PACKAGE_VERSION%%.*}" AC_SUBST([emacs_major_version]) @@ -4703,7 +4664,7 @@ AC_SUBST([XINERAMA_LIBS]) ### Use Xfixes (-lXfixes) if available HAVE_XFIXES=no if test "${HAVE_X11}" = "yes"; then - XFIXES_REQUIRED=4.0.0 + XFIXES_REQUIRED=1.0.0 XFIXES_MODULES="xfixes >= $XFIXES_REQUIRED" EMACS_CHECK_MODULES([XFIXES], [$XFIXES_MODULES]) if test $HAVE_XFIXES = no; then @@ -5007,6 +4968,7 @@ pthread_sigmask strsignal setitimer \ sendto recvfrom getsockname getifaddrs freeifaddrs \ gai_strerror sync \ getpwent endpwent getgrent endgrent \ +renameat2 \ cfmakeraw cfsetspeed __executable_start log2 pthread_setname_np \ pthread_set_name_np]) LIBS=$OLD_LIBS @@ -6400,7 +6362,7 @@ fi # it temporarily reverts them to their pre-pkg-config values, # because gnulib needs to work with both src (which uses the # pkg-config stuff) and lib-src (which does not). For example, gnulib -# may need to determine whether LIB_CLOCK_GETTIME should contain -lrt, +# may need to determine whether CLOCK_TIME_LIB should contain -lrt, # and it therefore needs to run in an environment where LIBS does not # already contain -lrt merely because 'pkg-config --libs' printed '-lrt' # for some package unrelated to lib-src. @@ -6592,7 +6554,9 @@ if test "${HAVE_GTK}" = "yes"; then fi if test $USE_ACL -ne 0; then - ACL_SUMMARY="yes $LIB_ACL" + ACL_SUMMARY="yes" + test "$LIB_ACL" && ACL_SUMMARY="$ACL_SUMMARY $LIB_ACL" + test "$LIB_XATTR" && ACL_SUMMARY="$ACL_SUMMARY $LIB_XATTR" else ACL_SUMMARY=no fi diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi index c0e702da947..664b9d5d9a3 100644 --- a/doc/emacs/files.texi +++ b/doc/emacs/files.texi @@ -812,22 +812,21 @@ in these cases, customize the variable @vindex write-region-inhibit-fsync Normally, when a program writes a file, the operating system briefly caches the file's data in main memory before committing the data to -disk. This can greatly improve performance; for example, when running -on laptops, it can avoid a disk spin-up each time a file is written. -However, it risks data loss if the operating system crashes before -committing the cache to disk. +secondary storage. Although this can greatly improve performance, it +risks data loss if the system loses power before committing the cache, +and on some platforms other processes might not immediately notice the +file's change. To lessen this risk, Emacs can invoke the @code{fsync} system call after saving a file. Using @code{fsync} does not eliminate the risk -of data loss, partly because many systems do not implement +of data loss or slow notification, partly because many systems do not support @code{fsync} properly, and partly because Emacs's file-saving procedure typically relies also on directory updates that might not survive a crash even if @code{fsync} works properly. The @code{write-region-inhibit-fsync} variable controls whether Emacs invokes @code{fsync} after saving a file. The variable's -default value is @code{nil} when Emacs is interactive, and @code{t} -when Emacs runs in batch mode (@pxref{Initial Options, Batch Mode}). +default value is @code{t}. Emacs never uses @code{fsync} when writing auto-save files, as these files might lose data anyway. @@ -1900,6 +1899,11 @@ following in the Trash directory: liable to also delete this @code{.dir-locals.el} file, so this should only be done if you delete files from the Trash directory manually. +@vindex remote-file-name-inhibit-delete-by-moving-to-trash + If the variable @code{remote-file-name-inhibit-delete-by-moving-to-trash} +is non-@code{nil}, remote files are never moved to the Trash. They +are deleted instead. + @ifnottex If a file is under version control (@pxref{Version Control}), you should delete it using @kbd{M-x vc-delete-file} instead of @kbd{M-x diff --git a/doc/emacs/mini.texi b/doc/emacs/mini.texi index 6fb312ec321..898d9e904f6 100644 --- a/doc/emacs/mini.texi +++ b/doc/emacs/mini.texi @@ -953,12 +953,14 @@ File ‘foo.el’ exists; overwrite? (y or n) @end smallexample @cindex yes or no prompt +@vindex yes-or-no-prompt The second type of yes-or-no query is typically employed if giving the wrong answer would have serious consequences; it thus features a -longer prompt ending with @samp{(yes or no)}. For example, if you -invoke @kbd{C-x k} (@code{kill-buffer}) on a file-visiting buffer with -unsaved changes, Emacs activates the minibuffer with a prompt like -this: +longer prompt ending with @samp{(yes or no)} (or the value of +@code{yes-or-no-prompt} if you've customized that). For example, if +you invoke @kbd{C-x k} (@code{kill-buffer}) on a file-visiting buffer +with unsaved changes, Emacs activates the minibuffer with a prompt +like this: @smallexample Buffer foo.el modified; kill anyway? (yes or no) diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi index acabce57223..a5e1689b6c7 100644 --- a/doc/emacs/misc.texi +++ b/doc/emacs/misc.texi @@ -1810,31 +1810,28 @@ you can give each daemon its own server name like this: emacs --daemon=foo @end example -@findex server-stop-automatically +@vindex server-stop-automatically The Emacs server can optionally be stopped automatically when -certain conditions are met. To do this, call the function -@code{server-stop-automatically} in your init file (@pxref{Init -File}), with one of the following arguments: +certain conditions are met. To do this, set the option +@code{server-stop-automatically} to one of the following values: -@itemize -@item -With the argument @code{empty}, the server is stopped when it has no -clients, no unsaved file-visiting buffers and no running processes -anymore. - -@item -With the argument @code{delete-frame}, when the last client frame is -being closed, you are asked whether each unsaved file-visiting buffer -must be saved and each unfinished process can be stopped, and if so, -the server is stopped. - -@item -With the argument @code{kill-terminal}, when the last client frame is -being closed with @kbd{C-x C-c} (@code{save-buffers-kill-terminal}), -you are asked whether each unsaved file-visiting buffer must be saved -and each unfinished process can be stopped, and if so, the server is +@table @code +@item empty +This value causes the server to be stopped when it has no clients, no +unsaved file-visiting buffers and no running processes anymore. + +@item delete-frame +This value means that when the last client frame is being closed, you +are asked whether each unsaved file-visiting buffer must be saved and +each unfinished process can be stopped, and if so, the server is stopped. -@end itemize + +@item kill-terminal +This value means that when the last client frame is being closed with +@kbd{C-x C-c} (@code{save-buffers-kill-terminal}), you are asked +whether each unsaved file-visiting buffer must be saved and each +unfinished process can be stopped, and if so, the server is stopped. +@end table @findex server-eval-at If you have defined a server by a unique server name, it is possible diff --git a/doc/emacs/programs.texi b/doc/emacs/programs.texi index e9268ff2a0d..d983c2b59c6 100644 --- a/doc/emacs/programs.texi +++ b/doc/emacs/programs.texi @@ -163,6 +163,7 @@ Emacs we use it for all languages. * Left Margin Paren:: An open-paren or similar opening delimiter starts a defun if it is at the left margin. * Moving by Defuns:: Commands to move over or mark a major definition. +* Moving by Sentences:: Commands to move over certain code units. * Imenu:: Making buffer indexes as menus. * Which Function:: Which Function mode shows which function you are in. @end menu @@ -265,6 +266,66 @@ tree-sitter library provide control of this behavior: if the variable @code{treesit-defun-tactic} is set to the value @code{top-level}, the defun commands will find the @emph{outermost} defuns instead. +@node Moving by Sentences +@subsection Moving by Sentences +@cindex sentences, in programming languages + + These commands move point or set up the region based on units of +code, also called @dfn{sentences}. Even though sentences are usually +considered when writing human languages, Emacs can use the same +commands to move over certain constructs in programming languages +(@pxref{Sentences}, @pxref{Moving by Defuns}). In a programming +language a sentence is usually a complete language construct smaller +than defuns, but larger than sexps (@pxref{List Motion,,, elisp, The +Emacs Lisp Reference Manual}). What exactly is a sentence in this +case depends on the programming language, but usually it is a complete +statement, such as a variable definition and initialization, or a +conditional statement. An example of a sentence in the C language +could be + +@example +int x = 5; +@end example + +@noindent +or in the JavaScript language it could look like + +@example +@group +const thing = () => console.log("Hi"); +@end group +@group +const foo = [1] == '1' + ? "No way" + : "..."; +@end group + +@end example + +@table @kbd +@item M-a +Move to beginning of current or preceding sentence +(@code{backward-sentence}). +@item M-e +Move to end of current or following sentence (@code{forward-sentence}). +@end table + +@cindex move to beginning or end of sentence +@cindex sentence, move to beginning or end +@kindex M-a @r{(programming modes)} +@kindex M-e @r{(programming modes)} +@findex backward-sentence @r{(programming modes)} +@findex forward-sentence @r{(programming modes)} + The commands to move to the beginning and end of the current +sentence are @kbd{M-a} (@code{backward-sentence}) and @kbd{M-e} +(@code{forward-sentence}). If you repeat one of these commands, or +use a positive numeric argument, each repetition moves to the next +sentence in the direction of motion. + + @kbd{M-a} with a negative argument @minus{}@var{n} moves forward +@var{n} times to the next end of a sentence. Likewise, @kbd{M-e} with +a negative argument moves back to the start of a sentence. + @node Imenu @subsection Imenu @cindex index of buffer definitions @@ -431,6 +492,9 @@ large chunks of code: @table @kbd @item C-M-q Reindent all the lines within one parenthetical grouping. +@item M-q +Fill a single paragraph in a defun, or reindent all the lines within +that defun. @item C-u @key{TAB} Shift an entire parenthetical grouping rigidly sideways so that its first line is properly indented. @@ -451,6 +515,21 @@ indentation of the line where the grouping starts). The function that etc. To correct the overall indentation as well, type @kbd{@key{TAB}} first. +@kindex M-q +@findex prog-fill-reindent-defun +@vindex beginning-of-defun-function +@vindex end-of-defun-function +@vindex fill-paragraph-function + To reindent the entire defun around point, type @kbd{M-q} +(@code{prog-fill-reindent-defun}). If point is in a comment or a +string, this command fills and indents the comment or string instead. +What exactly constitutes a comment, a string, or a defun depends on +the major mode: the bounds of a defun are decided by the variables +@code{beginning-of-defun-function} and @code{end-of-defun-function} +(@pxref{List Motion,,, elisp, The Emacs Lisp Reference Manual}), +and the filling mechanism is decided by @code{fill-paragraph-function} +(@pxref{Filling,,, elisp, The Emacs Lisp Reference Manual}). + @kindex C-u TAB If you like the relative indentation within a grouping but not the indentation of its first line, move point to that first line and type diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi index 3cc5f10582a..18f2274cfa6 100644 --- a/doc/emacs/text.texi +++ b/doc/emacs/text.texi @@ -253,6 +253,10 @@ value of @code{sentence-end-double-space}. of a sentence. Set the variable @code{sentence-end-without-period} to @code{t} in such cases. + Even though the above mentioned sentence movement commands are based +on human languages, other Emacs modes can set these command to get +similar functionality (@pxref{Moving by Sentences}). + @node Paragraphs @section Paragraphs @cindex paragraphs diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index 707af6ee64c..ad01e0f2886 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -692,11 +692,9 @@ files that the user does not need to know about. @defvar write-region-inhibit-fsync If this variable's value is @code{nil}, @code{write-region} uses the -@code{fsync} system call after writing a file. Although this slows -Emacs down, it lessens the risk of data loss after power failure. If -the value is @code{t}, Emacs does not use @code{fsync}. The default -value is @code{nil} when Emacs is interactive, and @code{t} when Emacs -runs in batch mode. @xref{Files and Storage}. +@code{fsync} system call after writing a file. If the value is +@code{t}, Emacs does not use @code{fsync}. The default value is +@code{t}. @xref{Files and Storage}. @end defvar @defmac with-temp-file file body@dots{} @@ -1873,6 +1871,11 @@ no prefix argument is given, and @code{nil} otherwise. See also @code{delete-directory} in @ref{Create/Delete Dirs}. @end deffn +@defopt remote-file-name-inhibit-delete-by-moving-to-trash +If this variable is non-@code{nil}, remote files are never moved to +the Trash. They are deleted instead. +@end defopt + @cindex file permissions, setting @cindex permissions, file @cindex file modes, setting @@ -2038,17 +2041,28 @@ data already stored elsewhere on secondary storage until one file or the other is later modified; this will lose both files if the only copy on secondary storage is lost due to media failure. Second, the operating system might not write data to secondary storage -immediately, which will lose the data if power is lost. +immediately, which will lose the data if power is lost +or if there is a media failure. @findex write-region Although both sorts of failures can largely be avoided by a suitably -configured file system, such systems are typically more expensive or -less efficient. In more-typical systems, to survive media failure you +configured system, such systems are typically more expensive or +less efficient. In lower-end systems, to survive media failure you can copy the file to a different device, and to survive a power -failure you can use the @code{write-region} function with the +failure (or be immediately notified of a media failure) you can use +the @code{write-region} function with the @code{write-region-inhibit-fsync} variable set to @code{nil}. +Although this variable is ordinarily @code{t} because that can +significantly improve performance, it may make sense to temporarily +bind it to @code{nil} if using Emacs to implement database-like +transactions that survive power failure on lower-end systems. @xref{Writing to Files}. +On some platforms when Emacs changes a file other processes might not +be notified of the change immediately. Setting +@code{write-region-inhibit-fsync} to @code{nil} may improve +notification speed in this case, though there are no guarantees. + @node File Names @section File Names @cindex file names @@ -3376,7 +3390,8 @@ first, before handlers for jobs such as remote file access. @code{file-readable-p}, @code{file-regular-p}, @code{file-remote-p}, @code{file-selinux-context}, @code{file-symlink-p}, @code{file-system-info}, -@code{file-truename}, @code{file-writable-p}, +@code{file-truename}, @code{file-user-uid}, +@code{file-writable-p}, @code{find-backup-file-name},@* @code{get-file-buffer}, @code{insert-directory}, @@ -3437,7 +3452,8 @@ first, before handlers for jobs such as remote file access. @code{file-readable-p}, @code{file-regular-p}, @code{file-remote-p}, @code{file-selinux-context}, @code{file-symlink-p}, @code{file-system-info}, -@code{file-truename}, @code{file-writable-p}, +@code{file-truename}, @code{file-user-uid}, +@code{file-writable-p}, @code{find-backup-file-name}, @code{get-file-buffer}, @code{insert-directory}, diff --git a/doc/lispref/minibuf.texi b/doc/lispref/minibuf.texi index 114e5d38a80..4b957a68401 100644 --- a/doc/lispref/minibuf.texi +++ b/doc/lispref/minibuf.texi @@ -2233,10 +2233,12 @@ minibuffer. It returns @code{t} if the user enters @samp{yes}, @code{nil} if the user types @samp{no}. The user must type @key{RET} to finalize the response. Upper and lower case are equivalent. -@code{yes-or-no-p} starts by displaying @var{prompt} in the minibuffer, -followed by @w{@samp{(yes or no) }}. The user must type one of the -expected responses; otherwise, the function responds @samp{Please answer -yes or no.}, waits about two seconds and repeats the request. +@vindex yes-or-no-prompt +@code{yes-or-no-p} starts by displaying @var{prompt} in the +minibuffer, followed by the value of @code{yes-or-no-prompt} @w{(default +@samp{(yes or no) })}. The user must type one of the expected +responses; otherwise, the function responds @w{@samp{Please answer yes or +no.}}, waits about two seconds and repeats the request. @code{yes-or-no-p} requires more work from the user than @code{y-or-n-p} and is appropriate for more crucial decisions. diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi index 3be7036f637..bca62a7a8de 100644 --- a/doc/lispref/os.texi +++ b/doc/lispref/os.texi @@ -1277,6 +1277,16 @@ This function returns the real @acronym{UID} of the user. This function returns the effective @acronym{UID} of the user. @end defun +@defun file-user-uid +This function returns the connection-local value for the user's +effective @acronym{UID}. If @code{default-directory} is local, this +is equivalent to @code{user-uid}, but for remote files (@pxref{Remote +Files, , , emacs, The GNU Emacs Manual}), it will return the +@acronym{UID} for the user associated with that remote connection; if +the remote connection has no associated user, it will instead return +-1. +@end defun + @cindex GID @defun group-gid This function returns the effective @acronym{GID} of the Emacs process. diff --git a/doc/lispref/positions.texi b/doc/lispref/positions.texi index f3824436246..838877b6282 100644 --- a/doc/lispref/positions.texi +++ b/doc/lispref/positions.texi @@ -858,6 +858,40 @@ top-level defuns, if the value is @code{nested}, navigation functions recognize nested defuns. @end defvar +@defvar treesit-sentence-type-regexp +The value of this variable is a regexp matching the node type of sentence +nodes. (For ``node'' and ``node type'', @pxref{Parsing Program Source}.) +@end defvar + +@findex treesit-forward-sentence +@findex forward-sentence +@findex backward-sentence +If Emacs is compiled with tree-sitter, it can use the tree-sitter +parser information to move across syntax constructs. Since what +exactly is considered a sentence varies between languages, a major +mode should set @code{treesit-sentence-type-regexp} to determine that. +Then the mode can get navigation-by-sentence functionality for free, +by using @code{forward-sentence} and +@code{backward-sentence}(@pxref{Moving by Sentences,,, emacs, The +extensible self-documenting text editor}). + +@defvar treesit-sexp-type-regexp +The value of this variable is a regexp matching the node type of sexp +nodes. (For ``node'' and ``node type'', @pxref{Parsing Program +Source}.) +@end defvar + +@findex treesit-forward-sexp +@findex forward-sexp@r{, and tree-sitter} +@findex backward-sexp@r{, and tree-sitter} +If Emacs is compiled with tree-sitter, it can use the tree-sitter +parser information to move across syntax constructs. Since what +exactly is considered a sexp varies between languages, a major mode +should set @code{treesit-sexp-type-regexp} to determine that. Then +the mode can get navigation-by-sexp functionality for free, by using +@code{forward-sexp} and @code{backward-sexp}(@pxref{Moving by +Sentences,,, emacs, The extensible self-documenting text editor}). + @node Skipping Characters @subsection Skipping Characters @cindex skipping characters diff --git a/doc/misc/calc.texi b/doc/misc/calc.texi index c3e32433fc4..5424995534e 100644 --- a/doc/misc/calc.texi +++ b/doc/misc/calc.texi @@ -11040,7 +11040,8 @@ the year even for older dates. The customizable variable have Calc's date forms switch from the Julian to Gregorian calendar at any specified date. -Today's timekeepers introduce an occasional ``leap second''. +A few platforms support leap seconds, such as the time stamp +1972-06-30 23:59:60 UTC, an extra second appended to June 1972. These do not occur regularly and Calc does not take these minor effects into account. (If it did, it would have to report a non-integer number of days between, say, @@ -17340,8 +17341,12 @@ it can be a variable which is a time zone name in upper- or lower-case. For example @samp{tzone(PST) = tzone(8)} and @samp{tzone(pdt) = tzone(7)} (for Pacific standard and daylight saving times, respectively). -North American and European time zone names are defined as follows; -note that for each time zone there is one name for standard time, +North American and European time zone names are defined as follows. +These names are obsolescent and new code should not rely on them: +the @samp{YST}-related names have disagreed with time in Yukon since 1973, +and other names could well become confusing or wrong in the future +as countries change their time zone rules. +For each time zone there is one name for standard time, another for daylight saving time, and a third for ``generalized'' time in which the daylight saving adjustment is computed from context. @@ -17363,7 +17368,7 @@ To define time zone names that do not appear in the above table, you must modify the Lisp variable @code{math-tzone-names}. This is a list of lists describing the different time zone names; its structure is best explained by an example. The three entries for -Pacific Time look like this: +circa-2022 US Pacific Time look like this: @smallexample @group diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi index 1789cded9d3..e51e2cf799b 100644 --- a/doc/misc/eshell.texi +++ b/doc/misc/eshell.texi @@ -418,9 +418,9 @@ alias (@pxref{Aliases}). Example: @example ~ $ which sudo eshell/sudo is a compiled Lisp function in `em-tramp.el'. -~ $ alias sudo '*sudo $*' +~ $ alias sudo '*sudo $@@*' ~ $ which sudo -sudo is an alias, defined as "*sudo $*" +sudo is an alias, defined as "*sudo $@@*" @end example Some of the built-in commands have different behavior from their @@ -540,7 +540,7 @@ Manual}. If @code{eshell-plain-diff-behavior} is non-@code{nil}, then this command does not use Emacs's internal @code{diff}. This is the same -as using @samp{alias diff '*diff $*'}. +as using @samp{alias diff '*diff $@@*'}. @item dirname @cmindex dirname @@ -610,9 +610,9 @@ but use Emacs's internal @code{grep} instead. If @code{eshell-plain-grep-behavior} is non-@code{nil}, then these commands do not use Emacs's internal @code{grep}. This is the same as -using @samp{alias grep '*grep $*'}, though this setting applies to all -of the built-in commands for which you would need to create a separate -alias. +using @samp{alias grep '*grep $@@*'}, though this setting applies to +all of the built-in commands for which you would need to create a +separate alias. @item history @cmindex history @@ -668,7 +668,7 @@ Alias to Emacs's @code{locate} function, which simply runs the external If @code{eshell-plain-locate-behavior} is non-@code{nil}, then Emacs's internal @code{locate} is not used. This is the same as using -@samp{alias locate '*locate $*'}. +@samp{alias locate '*locate $@@*'}. @item ls @cmindex ls @@ -1047,12 +1047,21 @@ whenever you change the current directory to a different host the value will automatically update to reflect the search path on that host. +@vindex $UID +@item $UID +This returns the effective @acronym{UID} for the current user. This +variable is connection-aware, so when the current directory is remote, +its value will be @acronym{UID} for the user associated with that +remote connection. + @vindex $_ @item $_ This refers to the last argument of the last command. With a subscript, you can access any argument of the last command. For example, @samp{$_[1]} refers to the second argument of the last -command (excluding the command name itself). +command (excluding the command name itself). To get all arguments of +the last command, you can use an index range like @samp{$_[..]} +(@pxref{Dollars Expansion}). @vindex $$ @item $$ @@ -1078,6 +1087,7 @@ that are currently visible in the Eshell window. They are both copied to the environment, so external commands invoked from Eshell can consult them to do the right thing. +@vindex $INSIDE_EMACS @item $INSIDE_EMACS This variable indicates to external commands that they are being invoked from within Emacs so they can adjust their behavior if @@ -1091,24 +1101,47 @@ necessary. Its value is @code{@var{emacs-version},eshell}. @node Aliases @section Aliases -@vindex $* +@findex eshell-read-aliases-list Aliases are commands that expand to a longer input line. For example, -@command{ll} is a common alias for @code{ls -l}, and would be defined -with the command invocation @kbd{alias ll 'ls -l $*'}; with this defined, -running @samp{ll foo} in Eshell will actually run @samp{ls -l foo}. -Aliases defined (or deleted) by the @command{alias} command are -automatically written to the file named by @code{eshell-aliases-file}, -which you can also edit directly (although you will have to manually -reload it). - -@vindex $1, $2, @dots{} +@command{ll} is a common alias for @code{ls -l}. To define this alias +in Eshell, you can use the command invocation @kbd{alias ll 'ls -l +$@@*'}; with this defined, running @samp{ll foo} in Eshell will +actually run @samp{ls -l foo}. Aliases defined (or deleted) by the +@command{alias} command are automatically written to the file named by +@code{eshell-aliases-file}, which you can also edit directly. After +doing so, use @w{@kbd{M-x eshell-read-aliases-list}} to load the +edited aliases. + Note that unlike aliases in Bash, arguments must be handled -explicitly. Typically the alias definition would end in @samp{$*} to -pass all arguments along. More selective use of arguments via -@samp{$1}, @samp{$2}, etc., is also possible. For example, +explicitly. Within aliases, you can use the special variables +@samp{$*}, @samp{$0}, @samp{$1}, @samp{$2}, etc. to refer to the +arguments passed to the alias. + +@table @code + +@vindex $* +@item $* +This expands to the list of arguments passed to the alias. For +example, if you run @code{my-alias 1 2 3}, then @samp{$*} would be the +list @code{(1 2 3)}. Note that since this variable is a list, using +@samp{$*} in an alias will pass this list as a single argument to the +aliased command. Therefore, when defining an alias, you should +usually use @samp{$@@*} to pass all arguments along, splicing them +into your argument list (@pxref{Dollars Expansion}). + +@vindex $0 +@item $0 +This expands to the name of the alias currently being executed. + +@vindex $1, $2, @dots{}, $9 +@item $1, $2, @dots{}, $9 +These variables expand to the nth argument (starting at 1) passed to +the alias. This lets you selectively use an alias's arguments, so @kbd{alias mcd 'mkdir $1 && cd $1'} would cause @kbd{mcd foo} to create and switch to a directory called @samp{foo}. +@end table + @node History @section History @cmindex history @@ -1339,11 +1372,24 @@ index. The exact behavior depends on the type of @var{expr}'s value: @item a sequence Expands to the element at the (zero-based) index @var{i} of the sequence (@pxref{Sequences Arrays Vectors, Sequences, , elisp, The -Emacs Lisp Reference Manual}). +Emacs Lisp Reference Manual}). If @var{i} is negative, @var{i} counts +from the end, so -1 refers to the last element of the sequence. + +If @var{i} is a range like @code{@var{start}..@var{end}}, this expands +to a subsequence from the indices @var{start} to @var{end}, where +@var{end} is excluded@footnote{This behavior is different from ranges +in Bash (where both the start and end are included in the range), but +matches the behavior of similar Emacs Lisp functions, like +@code{substring} (@pxref{Creating Strings, , , elisp, The Emacs Lisp +Reference Manual}).}. @var{start} and/or @var{end} can also be +omitted, which is equivalent to the start and/or end of the entire +list. For example, @samp{$@var{expr}[-2..]} expands to the last two +values of @var{expr}. @item a string Split the string at whitespace, and then expand to the @var{i}th -element of the resulting sequence. +element of the resulting sequence. As above, @var{i} can be a range +like @code{@var{start}..@var{end}}. @item an alist If @var{i} is a non-numeric value, expand to the value associated with @@ -1370,12 +1416,36 @@ to split the string. @var{regexp} can be any form other than a number. For example, @samp{$@var{var}[: 0]} will return the first element of a colon-delimited string. +@cindex length operator, in variable expansion @item $#@var{expr} -Expands to the length of the result of @var{expr}, an expression in -one of the above forms. For example, @samp{$#@var{var}} returns the -length of the variable @var{var} and @samp{$#@var{var}[0]} returns the -length of the first element of @var{var}. Again, signals an error if -the result of @var{expr} is not a string or a sequence. +This is the @dfn{length operator}. It expands to the length of the +result of @var{expr}, an expression in one of the above forms. For +example, @samp{$#@var{var}} returns the length of the variable +@var{var} and @samp{$#@var{var}[0]} returns the length of the first +element of @var{var}. Again, signals an error if the result of +@var{expr} is not a string or a sequence. + +@cindex splice operator, in variable expansion +@item $@@@var{expr} +This is the @dfn{splice operator}. It ``splices'' the elements of +@var{expr} (an expression of one of the above forms) into the +resulting list of arguments, much like the @samp{,@@} marker in Emacs +Lisp (@pxref{Backquote, , , elisp, The Emacs Lisp Reference Manual}). +The elements of @var{expr} become arguments at the same level as the +other arguments around it. For example, if @var{numbers} is the list +@code{(1 2 3)}, then: + +@example +@group +~ $ echo 0 $numbers +(0 + (1 2 3)) +@end group +@group +~ $ echo 0 $@@numbers +(0 1 2 3) +@end group +@end example @end table @@ -2094,7 +2164,7 @@ Allow for a Bash-compatible syntax, such as: @example alias arg=blah -function arg () @{ blah $* @} +function arg () @{ blah $@@* @} @end example @item Pcomplete sometimes gets stuck @@ -2179,11 +2249,6 @@ So that @kbd{M-@key{DEL}} acts in a predictable manner, etc. @item Allow all Eshell buffers to share the same history and list-dir -@item There is a problem with script commands that output to @file{/dev/null} - -If a script file, somewhere in the middle, uses @samp{> /dev/null}, -output from all subsequent commands is swallowed. - @item Split up parsing of text after @samp{$} in @file{esh-var.el} Make it similar to the way that @file{esh-arg.el} is structured. @@ -2392,13 +2457,6 @@ current being used. This way, the user could change it to use rc syntax: @samp{>[2=1]}. -@item Allow @samp{$_[-1]}, which would indicate the last element of the array - -@item Make @samp{$x[*]} equal to listing out the full contents of @samp{x} - -Return them as a list, so that @samp{$_[*]} is all the arguments of the -last command. - @item Copy ANSI code handling from @file{term.el} into @file{em-term.el} Make it possible for the user to send char-by-char to the underlying diff --git a/doc/misc/eww.texi b/doc/misc/eww.texi index bc556ed88e2..836eb38503e 100644 --- a/doc/misc/eww.texi +++ b/doc/misc/eww.texi @@ -92,9 +92,10 @@ searched via @code{eww-search-prefix}. The default search engine is either prefix the file name with @code{file://} or use the command @kbd{M-x eww-open-file}. - If you invoke @code{eww} with a prefix argument, as in @w{@kbd{C-u -M-x eww}}, it will create a new EWW buffer instead of reusing the -default one, which is normally called @file{*eww*}. + If you invoke @code{eww} or @code{eww-open-file} with a prefix +argument, as in @w{@kbd{C-u M-x eww}}, they will create a new EWW +buffer instead of reusing the default one, which is normally called +@file{*eww*}. @findex eww-quit @findex eww-reload diff --git a/doc/misc/mh-e.texi b/doc/misc/mh-e.texi index 575a086e2c5..caee0ed2c70 100644 --- a/doc/misc/mh-e.texi +++ b/doc/misc/mh-e.texi @@ -793,7 +793,7 @@ You should see the scan line for your message, and perhaps others. Use @cartouche @smallexample - 3 t08/24 root received fax files on Wed Aug 24 11:00:13 PDT 1 + 3 t08/24 root received fax files on Wed Aug 24 11:00:13 -0700 1 # 4+t08/24 To:wohler Test<<This is a test message to get the wheels -:%% @{+inbox/select@} 4 msgs (1-4) Bot L4 (MH-Folder Show)--------- diff --git a/doc/misc/modus-themes.org b/doc/misc/modus-themes.org index 4bf78379c10..1273fd8a3ad 100644 --- a/doc/misc/modus-themes.org +++ b/doc/misc/modus-themes.org @@ -4,9 +4,9 @@ #+language: en #+options: ':t toc:nil author:t email:t num:t #+startup: content -#+macro: stable-version 3.0.0 -#+macro: release-date 2022-10-28 -#+macro: development-version 3.1.0-dev +#+macro: stable-version 4.0.0 +#+macro: release-date 2023-01-01 +#+macro: development-version 4.1.0-dev #+macro: file @@texinfo:@file{@@$1@@texinfo:}@@ #+macro: space @@texinfo:@: @@ #+macro: kbd @@texinfo:@kbd{@@$1@@texinfo:}@@ @@ -21,20 +21,27 @@ #+texinfo: @insertcopying -This manual, written by Protesilaos Stavrou, describes the customization -options for the ~modus-operandi~ and ~modus-vivendi~ themes, and provides -every other piece of information pertinent to them. +This manual, written by Protesilaos Stavrou, describes the +customization options for the Modus themes, and provides every other +piece of information pertinent to them. The documentation furnished herein corresponds to stable version -{{{stable-version}}}, released on {{{release-date}}}. Any reference to a newer -feature which does not yet form part of the latest tagged commit, is -explicitly marked as such. +{{{stable-version}}}, released on {{{release-date}}}. Any reference +to a newer feature which does not yet form part of the latest tagged +commit, is explicitly marked as such. Current development target is {{{development-version}}}. -+ Homepage: https://protesilaos.com/emacs/modus-themes. -+ Git repository: https://git.sr.ht/~protesilaos/modus-themes. -+ Mailing list: https://lists.sr.ht/~protesilaos/modus-themes. ++ Package name (GNU ELPA): ~modus-themes~ ++ Official manual: <https://protesilaos.com/emacs/modus-themes> ++ Change log: <https://protesilaos.com/emacs/modus-themes-changelog> ++ Color palette: <https://protesilaos.com/emacs/modus-themes-colors> ++ Sample pictures: <https://protesilaos.com/emacs/modus-themes-pictures> ++ Git repo on SourceHut: <https://git.sr.ht/~protesilaos/modus-themes> + - Mirrors: + + GitHub: <https://github.com/protesilaos/modus-themes> + + GitLab: <https://gitlab.com/protesilaos/modus-themes> ++ Mailing list: <https://lists.sr.ht/~protesilaos/modus-themes> + Backronym: My Old Display Unexpectedly Sharpened ... themes #+toc: headlines 8 insert TOC here, with eight headline levels @@ -45,7 +52,7 @@ Current development target is {{{development-version}}}. :custom_id: h:b14c3fcb-13dd-4144-9d92-2c58b3ed16d3 :end: -Copyright (C) 2020-2023 Free Software Foundation, Inc. +Copyright (C) 2020-2023 Free Software Foundation, Inc. #+begin_quote Permission is granted to copy, distribute and/or modify this document @@ -64,44 +71,46 @@ modify this GNU manual.” :custom_id: h:f0f3dbcb-602d-40cf-b918-8f929c441baf :end: -The Modus themes are designed for accessible readability. They conform -with the highest standard for color contrast between any given -combination of background and foreground values. This corresponds to -the WCAG AAA standard, which specifies a minimum rate of distance in -relative luminance of 7:1. +The Modus themes are designed for accessible readability. They +conform with the highest standard for color contrast between +combinations of background and foreground values. For small sized +text, this corresponds to the WCAG AAA standard, which specifies a +minimum rate of distance in relative luminance of 7:1. + +The Modus themes consist of six themes, divided into three subgroups. + +- Main themes :: ~modus-operandi~ is the project's main light theme, + while ~modus-vivendi~ is its dark counterpart. These two themes are + part of the project since its inception. They are designed to cover + a broad range of needs and are, in the opinion of the author, the + reference for what a highly legible "default" theme should look + like. + +- Tinted themes :: ~modus-operandi-tinted~ and ~modus-vivendi-tinted~ + are variants of the two main themes. They slightly tone down the + intensity of the background and provide a bit more color variety. + ~modus-operandi-tinted~ has a set of base tones that are shades of + light ochre (earthly colors), while ~modus-vivendi-tinted~ gives a + night sky impression. + +- Deuteranopia themes :: ~modus-operandi-deuteranopia~ and its + companion ~modus-vivendi-deuteranopia~ are optimized for users with + red-green color deficiency. This means that they do not use red and + green hues for color-coding purposes, such as for diff removed and + added lines. Instead, they implement colors that are discernible by + users with deueteranopia or deuteranomaly (mostly yellow and blue + hues). -Modus Operandi (~modus-operandi~) is a light theme, while Modus Vivendi -(~modus-vivendi~) is dark. Each theme's color palette is designed to meet -the needs of the numerous interfaces that are possible in the Emacs -computing environment. +To ensure that users have a consistently accessible experience, the +themes strive to achieve as close to full face coverage as possible, +while still targeting a curated list of well-maintained packages +([[#h:a9c8f29d-7f72-4b54-b74b-ddefe15d6a19][Face coverage]]). The overarching objective of this project is to always offer accessible color combinations. There shall never be a compromise on this principle. If there arises an inescapable trade-off between readability and stylistic considerations, we will always opt for the former. -To ensure that users have a consistently accessible experience, the -themes strive to achieve as close to full face coverage as possible -([[#h:a9c8f29d-7f72-4b54-b74b-ddefe15d6a19][Face coverage]]). - -Furthermore, the themes are designed to empower users with red-green -color deficiency (deuteranopia). This is achieved in three ways: - -1. The conformance with the highest legibility standard means that text - is always readable no matter the perception of its hue. - -2. Most contexts use colors on the blue-cyan-magenta-purple side of the - spectrum. Put differently, green and/or red are seldom used, thus - minimizing the potential for confusion. - - [[#h:0b26cb47-9733-4cb1-87d9-50850cb0386e][Why are colors mostly variants of blue, magenta, cyan?]]. - -3. In contexts where a red/green color-coding is unavoidable, we provide - a universal toggle to customize the themes so that a red/blue scheme - is used instead. - - [[#h:3ed03a48-20d8-4ce7-b214-0eb7e4c79abe][Option for red-green color deficiency or deuteranopia]]. - Starting with version 0.12.0 and onwards, the themes are built into GNU Emacs. @@ -111,12 +120,8 @@ Emacs. :end: #+cindex: Screenshots -Check the web page with [[https://protesilaos.com/emacs/modus-themes-pictures/][the screen shots]]. There are lots of scenarios -on display that draw attention to details and important aspects in the -design of the themes. They also showcase the numerous customization -options. - -[[#h:bf1c82f2-46c7-4eb2-ad00-dd11fdd8b53f][Customization options]]. +Check the web page with [[https://protesilaos.com/emacs/modus-themes-pictures/][the screen shots]]. Note that the themes are +highly customizable ([[#h:bf1c82f2-46c7-4eb2-ad00-dd11fdd8b53f][Customization options]]). ** Learn about the latest changes :properties: @@ -137,6 +142,13 @@ On older versions of Emacs, they can be installed using Emacs' package manager or manually from their code repository. There also exist packages for distributions of GNU/Linux. +Emacs 28 ships with ~modus-themes~ version =1.6.0=. Emacs 29 includes +version =3.0.0=. Emacs 30 provides a newer, refactored version that +thoroughly refashions how the themes are implemented and customized. +Such major versions are not backward-compatible due to the limited +resources at the maintainer's disposal to support multiple versions of +Emacs and of the themes across the years. + ** Install manually from source :properties: :custom_id: h:da3414b7-1426-46b8-8e76-47b845b76fd0 @@ -245,102 +257,82 @@ wrong. :properties: :custom_id: h:3f3c3728-1b34-437d-9d0c-b110f5b161a9 :end: -#+findex: modus-themes-load-themes #+findex: modus-themes-toggle -#+findex: modus-themes-load-operandi -#+findex: modus-themes-load-vivendi -#+cindex: Essential configuration +#+findex: modus-themes-load-theme #+vindex: modus-themes-after-load-theme-hook +#+cindex: Essential configuration + +NOTE that Emacs can load multiple themes, which typically produces +undesirable results and undoes the work of the designer. Use the +~disable-theme~ command if you are trying other themes beside the +Modus collection. Users of the built-in themes cannot ~require~ the package as usual -because there is no package to speak of. Instead, things are simpler as -all one needs is to load the theme of their preference by adding either -form to their init file: +because there is no package to speak of. Instead, things are simpler +as built-in themes are considered safe. All one needs is to load the +theme of their preference by adding either form to their init file: #+begin_src emacs-lisp (load-theme 'modus-operandi) ; Light theme (load-theme 'modus-vivendi) ; Dark theme #+end_src +Remember that the Modus themes are six themes ([[#h:f0f3dbcb-602d-40cf-b918-8f929c441baf][Overview]]). Adapt the +above snippet accordingly. + Users of packaged variants of the themes must add a few more lines to ensure that everything works as intended. First, one has to require the -main library before loading either theme: +main library before loading one of the themes: #+begin_src emacs-lisp (require 'modus-themes) #+end_src -Then it is recommended to load the individual theme files with the -helper function ~modus-themes-load-themes~: +One can activate a theme with something like the following expression, +replacing ~modus-operandi~ with their preferred Modus theme: #+begin_src emacs-lisp -;; Load the theme files before enabling a theme (else you get an error). -(modus-themes-load-themes) -#+end_src - -Once the libraries that define the themes are enabled, one can activate -a theme with either of the following expressions: - -#+begin_src emacs-lisp -(modus-themes-load-operandi) ; Light theme -;; OR -(modus-themes-load-vivendi) ; Dark theme +(load-theme 'modus-operandi :no-confim) #+end_src Changes to the available customization options must always be evaluated -before loading a theme ([[#h:bf1c82f2-46c7-4eb2-ad00-dd11fdd8b53f][Customization Options]]). An exception to this -norm is when using the various Custom interfaces or with commands like -{{{kbd(M-x customize-set-variable)}}}, which can optionally -automatically reload the theme ([[#h:9001527a-4e2c-43e0-98e8-3ef72d770639][Option for inhibiting theme reload]]). +before loading a theme ([[#h:bf1c82f2-46c7-4eb2-ad00-dd11fdd8b53f][Customization Options]]). Reload a theme for +new changes to take effect. This is how a basic setup could look like: #+begin_src emacs-lisp -;;; For the built-in themes which cannot use `require': -;; Add all your customizations prior to loading the themes +;;; For the built-in themes which cannot use `require'. + +;; Add all your customizations prior to loading the themes. (setq modus-themes-italic-constructs t - modus-themes-bold-constructs nil - modus-themes-region '(bg-only no-extend)) + modus-themes-bold-constructs nil) -;; Load the theme of your choice: -(load-theme 'modus-operandi) ;; OR (load-theme 'modus-vivendi) +;; Load the theme of your choice. +(load-theme 'modus-operandi) +;; Optionally define a key to switch between Modus themes. Also check +;; the user option `modus-themes-to-toggle'. (define-key global-map (kbd "<f5>") #'modus-themes-toggle) -;;; For packaged versions which must use `require': +;;; For packaged versions which must use `require'. + (require 'modus-themes) ;; Add all your customizations prior to loading the themes (setq modus-themes-italic-constructs t - modus-themes-bold-constructs nil - modus-themes-region '(bg-only no-extend)) + modus-themes-bold-constructs nil) -;; Load the theme files before enabling a theme -(modus-themes-load-themes) - -;; Load the theme of your choice: -(modus-themes-load-operandi) ;; OR (modus-themes-load-vivendi) +;; Load the theme of your choice. +(load-theme 'modus-operandi :no-confim) (define-key global-map (kbd "<f5>") #'modus-themes-toggle) #+end_src [[#h:e979734c-a9e1-4373-9365-0f2cd36107b8][Sample configuration with and without use-package]]. -With those granted, bear in mind a couple of technical points on -~modus-themes-load-operandi~ and ~modus-themes-load-vivendi~, as well as -~modus-themes-toggle~ which relies on them: - -1. Those functions call ~load-theme~. Some users prefer to opt for - ~enable-theme~ instead ([[#h:e68560b3-7fb0-42bc-a151-e015948f8a35][Differences between loading and enabling]]). - -2. The functions will run the ~modus-themes-after-load-theme-hook~ as - their final step. This can be employed for bespoke configurations - ([[#h:f4651d55-8c07-46aa-b52b-bed1e53463bb][Advanced customization]]). Experienced users may not wish to rely on - such a hook and the functions that run it: they may prefer a custom - solution ([[#h:86f6906b-f090-46cc-9816-1fe8aeb38776][A theme-agnostic hook for theme loading]]). - ** Sample configuration with and without use-package :properties: :custom_id: h:e979734c-a9e1-4373-9365-0f2cd36107b8 @@ -348,38 +340,36 @@ With those granted, bear in mind a couple of technical points on #+cindex: use-package configuration #+cindex: sample configuration +What follows is a variant of what we demonstrate in the previous +section ([[#h:3f3c3728-1b34-437d-9d0c-b110f5b161a9][Enable and load]]). + It is common for Emacs users to rely on ~use-package~ for declaring package configurations in their setup. We use this as an example: #+begin_src emacs-lisp -;;; For the built-in themes which cannot use `require': +;;; For the built-in themes which cannot use `require'. (use-package emacs :init ;; Add all your customizations prior to loading the themes (setq modus-themes-italic-constructs t - modus-themes-bold-constructs nil - modus-themes-region '(bg-only no-extend)) + modus-themes-bold-constructs nil) :config - ;; Load the theme of your choice: - (load-theme 'modus-operandi) ;; OR (load-theme 'modus-vivendi) + ;; Load the theme of your choice. + (load-theme 'modus-operandi) :bind ("<f5>" . modus-themes-toggle)) -;;; For packaged versions which must use `require': +;;; For packaged versions which must use `require'. (use-package modus-themes :ensure :init ;; Add all your customizations prior to loading the themes (setq modus-themes-italic-constructs t - modus-themes-bold-constructs nil - modus-themes-region '(bg-only no-extend)) - - ;; Load the theme files before enabling a theme - (modus-themes-load-themes) + modus-themes-bold-constructs nil) :config - ;; Load the theme of your choice: - (modus-themes-load-operandi) ;; OR (modus-themes-load-vivendi) + ;; Load the theme of your choice. + (load-theme 'modus-operandi :no-confim) :bind ("<f5>" . modus-themes-toggle)) #+end_src @@ -389,8 +379,7 @@ The same without ~use-package~: ;;; For the built-in themes which cannot use `require': ;; Add all your customizations prior to loading the themes (setq modus-themes-italic-constructs t - modus-themes-bold-constructs nil - modus-themes-region '(bg-only no-extend)) + modus-themes-bold-constructs nil) ;; Load the theme of your choice: (load-theme 'modus-operandi) ;; OR (load-theme 'modus-vivendi) @@ -404,14 +393,10 @@ The same without ~use-package~: ;; Add all your customizations prior to loading the themes (setq modus-themes-italic-constructs t - modus-themes-bold-constructs nil - modus-themes-region '(bg-only no-extend)) - -;; Load the theme files before enabling a theme -(modus-themes-load-themes) + modus-themes-bold-constructs nil) ;; Load the theme of your choice: -(modus-themes-load-operandi) ;; OR (modus-themes-load-vivendi) +(load-theme 'modus-operandi :no-confim) ;; OR (load-theme 'modus-vivendi :no-confim) (define-key global-map (kbd "<f5>") #'modus-themes-toggle) #+end_src @@ -433,8 +418,8 @@ package declaration of the themes. The reason we recommend ~load-theme~ instead of the other option of ~enable-theme~ is that the former does a kind of "reset" on the face specs. It quite literally loads (or reloads) the theme. Whereas the -latter simply puts an already loaded theme at the top of the list of -enabled items, re-using whatever state was last loaded. +~enable-theme~ function simply puts an already loaded theme to the top +of the list of enabled items, re-using whatever state was last loaded. As such, ~load-theme~ reads all customizations that may happen during any given Emacs session: even after the initial setup of a theme. @@ -453,10 +438,13 @@ session, are better off using something like this: #+begin_src emacs-lisp (require 'modus-themes) + +;; Activate your desired themes here (load-theme 'modus-operandi t t) (load-theme 'modus-vivendi t t) -(enable-theme 'modus-operandi) ;; OR (enable-theme 'modus-vivendi) +;; Enable the preferred one +(enable-theme 'modus-operandi) #+end_src [[#h:b40aca50-a3b2-4c43-be58-2c26fcd14237][Toggle themes without reloading them]]. @@ -467,198 +455,95 @@ With the above granted, other sections of the manual discuss how to configure custom faces, where ~load-theme~ is expected, though ~enable-theme~ could still apply in stable setups: -[[#h:1487c631-f4fe-490d-8d58-d72ffa3bd474][Case-by-case face specs using the themes' palette]]. - -[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Face specs at scale using the themes' palette]]. +[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Use theme colors in code with modus-themes-with-colors]]. -* Customization Options +* Customization options :properties: :custom_id: h:bf1c82f2-46c7-4eb2-ad00-dd11fdd8b53f :end: The Modus themes are highly configurable, though they should work well -without any further tweaks. By default, all customization options are -set to nil, unless otherwise noted in this manual. +without any further tweaks. We provide a variety of user options. +The following code block provides an overview. In addition to those +variables, the themes support a comprehensive system of overrides: it +can be used to make thoroughgoing changes to the looks of the themes +([[#h:34c7a691-19bb-4037-8d2f-67a07edab150][Option for palette overrides]]). We document everything at length in +the pages of this manual and also provide ready-to-use code samples. Remember that all customization options must be evaluated before loading a theme ([[#h:3f3c3728-1b34-437d-9d0c-b110f5b161a9][Enable and load]]). If the theme is already active, it must be -reloaded for changes in user options to come into force. - -Below is a summary of what you will learn in the subsequent sections of -this manual. +reloaded for changes to take effect. #+begin_src emacs-lisp +;; In all of the following, WEIGHT is a symbol such as `semibold', +;; `light', `bold', or anything mentioned in `modus-themes-weights'. (setq modus-themes-italic-constructs t modus-themes-bold-constructs nil - modus-themes-mixed-fonts nil - modus-themes-subtle-line-numbers nil - modus-themes-intense-mouseovers nil - modus-themes-deuteranopia t - modus-themes-tabs-accented t + modus-themes-mixed-fonts t modus-themes-variable-pitch-ui nil - modus-themes-inhibit-reload t ; only applies to `customize-set-variable' and related - - modus-themes-fringes nil ; {nil,'subtle,'intense} - - ;; Options for `modus-themes-lang-checkers' are either nil (the - ;; default), or a list of properties that may include any of those - ;; symbols: `straight-underline', `text-also', `background', - ;; `intense' OR `faint'. - modus-themes-lang-checkers nil - - ;; Options for `modus-themes-mode-line' are either nil, or a list - ;; that can combine any of `3d' OR `moody', `borderless', - ;; `accented', a natural number for extra padding (or a cons cell - ;; of padding and NATNUM), and a floating point for the height of - ;; the text relative to the base font size (or a cons cell of - ;; height and FLOAT) - modus-themes-mode-line '(accented borderless (padding . 4) (height . 0.9)) - - ;; Same as above: - ;; modus-themes-mode-line '(accented borderless 4 0.9) - - ;; Options for `modus-themes-markup' are either nil, or a list - ;; that can combine any of `bold', `italic', `background', - ;; `intense'. - modus-themes-markup '(background italic) - - ;; Options for `modus-themes-syntax' are either nil (the default), - ;; or a list of properties that may include any of those symbols: - ;; `faint', `yellow-comments', `green-strings', `alt-syntax' - modus-themes-syntax nil - - ;; Options for `modus-themes-hl-line' are either nil (the default), - ;; or a list of properties that may include any of those symbols: - ;; `accented', `underline', `intense' - modus-themes-hl-line '(underline accented) - - ;; Options for `modus-themes-paren-match' are either nil (the - ;; default), or a list of properties that may include any of those - ;; symbols: `bold', `intense', `underline' - modus-themes-paren-match '(bold intense) - - ;; Options for `modus-themes-links' are either nil (the default), - ;; or a list of properties that may include any of those symbols: - ;; `neutral-underline' OR `no-underline', `faint' OR `no-color', - ;; `bold', `italic', `background' - modus-themes-links '(neutral-underline background) - - ;; Options for `modus-themes-box-buttons' are either nil (the - ;; default), or a list that can combine any of `flat', `accented', - ;; `faint', `variable-pitch', `underline', `all-buttons', the - ;; symbol of any font weight as listed in `modus-themes-weights', - ;; and a floating point number (e.g. 0.9) for the height of the - ;; button's text. - modus-themes-box-buttons '(variable-pitch flat faint 0.9) + modus-themes-custom-auto-reload t ;; Options for `modus-themes-prompts' are either nil (the ;; default), or a list of properties that may include any of those - ;; symbols: `background', `bold', `gray', `intense', `italic' - modus-themes-prompts '(intense bold) + ;; symbols: `italic', `WEIGHT' + modus-themes-prompts '(italic bold) - ;; The `modus-themes-completions' is an alist that reads three - ;; keys: `matches', `selection', `popup'. Each accepts a nil - ;; value (or empty list) or a list of properties that can include - ;; any of the following (for WEIGHT read further below): - ;; - ;; `matches' - `background', `intense', `underline', `italic', WEIGHT - ;; `selection' - `accented', `intense', `underline', `italic', `text-also' WEIGHT - ;; `popup' - same as `selected' - ;; `t' - applies to any key not explicitly referenced (check docs) + ;; The `modus-themes-completions' is an alist that reads two + ;; keys: `matches', `selection'. Each accepts a nil value (or + ;; empty list) or a list of properties that can include any of + ;; the following (for WEIGHT read further below): ;; - ;; WEIGHT is a symbol such as `semibold', `light', or anything - ;; covered in `modus-themes-weights'. Bold is used in the absence - ;; of an explicit WEIGHT. - modus-themes-completions '((matches . (extrabold)) - (selection . (semibold accented)) - (popup . (accented intense))) - - modus-themes-mail-citations nil ; {nil,'intense,'faint,'monochrome} - - ;; Options for `modus-themes-region' are either nil (the default), - ;; or a list of properties that may include any of those symbols: - ;; `no-extend', `bg-only', `accented' - modus-themes-region '(bg-only no-extend) - - ;; Options for `modus-themes-diffs': nil, 'desaturated, 'bg-only - modus-themes-diffs 'desaturated + ;; `matches' :: `underline', `italic', `WEIGHT' + ;; `selection' :: `underline', `italic', `WEIGHT' + modus-themes-completions + '((matches . (extrabold)) + (selection . (semibold italic text-also))) modus-themes-org-blocks 'gray-background ; {nil,'gray-background,'tinted-background} - modus-themes-org-agenda ; this is an alist: read the manual or its doc string - '((header-block . (variable-pitch 1.3)) - (header-date . (grayscale workaholic bold-today 1.1)) - (event . (accented varied)) - (scheduled . uniform) - (habit . traffic-light)) - - modus-themes-headings ; this is an alist: read the manual or its doc string - '((1 . (overline background variable-pitch 1.3)) - (2 . (rainbow overline 1.1)) - (t . (semibold)))) + ;; The `modus-themes-headings' is an alist: read the manual's + ;; node about it or its doc string. Basically, it supports + ;; per-level configurations for the optional use of + ;; `variable-pitch' typography, a height value as a multiple of + ;; the base font size (e.g. 1.5), and a `WEIGHT'. + modus-themes-headings + '((1 . (variable-pitch 1.5)) + (2 . (1.3)) + (agenda-date . (1.3)) + (agenda-structure . (variable-pitch light 1.8)) + (t . (1.1)))) + +;; Remember that more (MUCH MORE) can be done with overrides, which we +;; document extensively in this manual. #+end_src -** Option for inhibiting theme reload +** Option for reloading the theme on custom change :properties: :alt_title: Custom reload theme :description: Toggle auto-reload of the theme when setting custom variables :custom_id: h:9001527a-4e2c-43e0-98e8-3ef72d770639 :end: -#+vindex: modus-themes-inhibit-reload +#+vindex: modus-themes-custom-auto-reload Brief: Toggle reloading of the active theme when an option is changed -through the Customize UI. +through the Custom UI. -Symbol: ~modus-themes-inhibit-reload~ (=boolean= type) +Symbol: ~modus-themes-custom-auto-reload~ (=boolean= type) Possible values: 1. ~nil~ 2. ~t~ (default) -By default, customizing a theme-related user option through the Custom -interfaces or with {{{kbd(M-x customize-set-variable)}}} will not reload the -currently active Modus theme. - -Enable this behavior by setting this variable to ~nil~. - -Regardless of this option, the active theme must be reloaded for changes -to user options to take effect ([[#h:3f3c3728-1b34-437d-9d0c-b110f5b161a9][Enable and load]]). - -** Option for red-green color deficiency or deuteranopia -:properties: -:alt_title: Deuteranopia style -:description: Toggle red/blue color-coding instead of red/green -:custom_id: h:3ed03a48-20d8-4ce7-b214-0eb7e4c79abe -:end: -#+vindex: modus-themes-deuteranopia - -Brief: When non-~nil~ use red/blue color-coding instead of red/green, -where appropriate. - -Symbol: ~modus-themes-deuteranopia~ (=boolean= type) - -Possible values: - -1. ~nil~ (default) -2. ~t~ - -This is to account for red-green color deficiency, also know as -deuteranopia and variants. It applies to all contexts where there can -be a color-coded distinction between failure or success, a to-do or done -state, a mark for deletion versus a mark for selection (e.g. in Dired), -current and lazily highlighted search matches, removed lines in diffs as -opposed to added ones, and so on. +All theme user options take effect when a theme is loaded. Any +subsequent changes require the theme to be reloaded. -Note that this does not change all colors throughout the active theme, -but only applies to cases that have color-coding significance. For -example, regular code syntax highlighting is not affected. There is no -such need because of the themes' overarching commitment to the highest -legibility standard, which ensures that text is readable regardless of -hue, as well as the predominance of colors on the -blue-cyan-magenta-purple side of the spectrum. +When this variable has a non-nil value, any change made via the Custom +UI or related functions such as ~customize-set-variable~ and ~setopt~ +(Emacs 29), will trigger a reload automatically. -[[#h:0b26cb47-9733-4cb1-87d9-50850cb0386e][Why are colors mostly variants of blue, magenta, cyan?]]. +With a nil value, changes to user options have no further consequences: +the user must manually reload the theme ([[#h:3f3c3728-1b34-437d-9d0c-b110f5b161a9][Enable and load]]). ** Option for more bold constructs :properties: @@ -680,9 +565,9 @@ Possible values: The default is to use a bold typographic weight only when it is required. -With a non-~nil~ value (~t~) display several syntactic constructs in bold -weight. This concerns keywords and other important aspects of code -syntax. It also affects certain mode line indicators and command-line +With a non-~nil~ value (~t~) display several syntactic constructs in +bold weight. This concerns keywords and other important aspects of +code syntax. It also affects certain mode line indicators and command prompts. Advanced users may also want to configure the exact attributes of the @@ -718,70 +603,6 @@ Advanced users may also want to configure the exact attributes of the [[#h:2793a224-2109-4f61-a106-721c57c01375][Configure bold and italic faces]]. -** Option for syntax highlighting -:properties: -:alt_title: Syntax styles -:description: Choose the overall aesthetic of code syntax -:custom_id: h:c119d7b2-fcd4-4e44-890e-5e25733d5e52 -:end: -#+vindex: modus-themes-syntax - -Brief: Set the overall style of code syntax highlighting. - -Symbol: ~modus-themes-syntax~ (=choice= type, list of properties) - -Possible values are expressed as a list of properties (default is ~nil~ or -an empty list). The list can include any of the following symbols: - -+ ~faint~ -+ ~yellow-comments~ -+ ~green-strings~ -+ ~alt-syntax~ - -The default (a ~nil~ value or an empty list) is to use a balanced -combination of colors on the cyan-blue-magenta side of the spectrum. -There is little to no use of greens, yellows, and reds. Comments are -gray, strings are blue colored, doc strings are a shade of cyan, while -color combinations are designed to avoid exaggerations. - -The property ~faint~ fades the saturation of all applicable colors, where -that is possible or appropriate. - -The property ~yellow-comments~ applies a yellow color to comments. - -The property ~green-strings~ applies a green color to strings and a green -tint to doc strings. - -The property ~alt-syntax~ changes the combination of colors beyond strings -and comments, so that the effective palette is broadened to provide -greater variety relative to the default. - -Combinations of any of those properties are expressed as a list, like in -these examples: - -#+begin_src emacs-lisp -(faint) -(green-strings yellow-comments) -(alt-syntax green-strings yellow-comments) -(faint alt-syntax green-strings yellow-comments) -#+end_src - -The order in which the properties are set is not significant. - -In user configuration files the form may look like this: - -#+begin_src emacs-lisp -(setq modus-themes-syntax '(faint alt-syntax)) -#+end_src - -Independent of this variable, users may also control the use of a bold -weight or italic text: ~modus-themes-bold-constructs~ and -~modus-themes-italic-constructs~. - -[[#h:b25714f6-0fbe-41f6-89b5-6912d304091e][Option for more bold constructs]]. - -[[#h:977c900d-0d6d-4dbb-82d9-c2aae69543d6][Option for more italic constructs]]. - ** Option for font mixing :properties: :alt_title: Mixed fonts @@ -805,111 +626,31 @@ tables and code blocks to always inherit from the ~fixed-pitch~ face. This is to ensure that certain constructs like code blocks and tables remain monospaced even when users opt for a mode that remaps typeface families, such as the built-in {{{kbd(M-x variable-pitch-mode)}}}. Otherwise -the layout would appear broken, due to how spacing is done. +the layout can appear broken, due to how spacing is done. For a consistent experience, user may need to specify the font family of the ~fixed-pitch~ face. [[#h:defcf4fc-8fa8-4c29-b12e-7119582cc929][Font configurations for Org and others]]. -Furthermore, users may prefer to use another package for handling mixed -typeface configurations, rather than letting the theme do it, perhaps -because a purpose-specific package has extra functionality. Two -possible options are ~org-variable-pitch~ and ~mixed-pitch~. - -** Option for links +** Option for command prompt styles :properties: -:alt_title: Link styles -:description: Choose among several styles, with or without underline -:custom_id: h:5808be52-361a-4d18-88fd-90129d206f9b +:alt_title: Command prompts +:description: Control the style of command prompts +:custom_id: h:db5a9a7c-2928-4a28-b0f0-6f2b9bd52ba1 :end: -#+vindex: modus-themes-links +#+vindex: modus-themes-prompts -Brief: Control the style of links to web pages, files, buffers... +Brief: Control the style of command prompts (e.g. minibuffer, shell, IRC +clients). -Symbol: ~modus-themes-links~ (=choice= type, list of properties) +Symbol: ~modus-themes-prompts~ (=choice= type, list of properties) Possible values are expressed as a list of properties (default is ~nil~ or an empty list). The list can include any of the following symbols: -+ Underline style: - - ~neutral-underline~ - - ~no-underline~ -+ Text coloration: - - ~faint~ - - ~no-color~ -+ ~bold~ + ~italic~ -+ ~background~ - -The default (a ~nil~ value or an empty list) is a prominent text color, -typically blue, with an underline of the same color. - -For the style of the underline, a ~neutral-underline~ property turns the -color of the line into a subtle gray, while the ~no-underline~ property -removes the line altogether. If both of those are set, the latter takes -precedence. - -For text coloration, a ~faint~ property desaturates the color of the text -and the underline, unless the underline is affected by the -aforementioned properties. While a ~no-color~ property removes the color -from the text. If both of those are set, the latter takes precedence. - -A ~bold~ property applies a heavy typographic weight to the text of the -link. - -An ~italic~ property adds a slant to the link's text (italic or oblique -forms, depending on the typeface). - -A ~background~ property applies a subtle tinted background color. - -In case both ~no-underline~ and ~no-color~ are set, then a subtle gray -background is applied to all links. This can still be combined with the -~bold~ and ~italic~ properties. - -Combinations of any of those properties are expressed as a list, -like in these examples: - -#+begin_src emacs-lisp -(faint) -(no-underline faint) -(no-color no-underline bold) -(italic bold background no-color no-underline) -#+end_src - -The order in which the properties are set is not significant. - -In user configuration files the form may look like this: - -#+begin_src emacs-lisp -(setq modus-themes-links '(neutral-underline background)) -#+end_src - -The placement of the underline, meaning its proximity to the text, is -controlled by ~x-use-underline-position-properties~, -~x-underline-at-descent-line~, ~underline-minimum-offset~. Please refer to -their documentation strings. - -** Option for box buttons -:properties: -:alt_title: Box buttons -:description: Choose among several styles for buttons -:custom_id: h:8b85f711-ff40-45b0-b7fc-4727503cd2ec -:end: -#+vindex: modus-themes-box-buttons - -Brief: Control the style of buttons in the Custom UI and related. - -Symbol: ~modus-themes-box-buttons~ (=choice= type, list of properties) - -Possible values are expressed as a list of properties (default is ~nil~ or -an empty list). The list can include any of the following symbols: - -+ ~flat~ -+ ~accented~ -+ ~faint~ -+ ~variable-pitch~ -+ ~underline~ ++ ~italic~ + A font weight, which must be supported by the underlying typeface: - ~thin~ - ~ultralight~ @@ -923,213 +664,24 @@ an empty list). The list can include any of the following symbols: - ~heavy~ - ~extrabold~ - ~ultrabold~ -+ A floating point as a height multiple of the default or a cons cell in - the form of =(height . FLOAT)= -+ ~all-buttons~ - -The default (a ~nil~ value or an empty list) is a gray background -combined with a pseudo three-dimensional effect. - -The ~flat~ property makes the button two dimensional. - -The ~accented~ property changes the background from gray to an accent -color. - -The ~faint~ property reduces the overall coloration. - -The ~variable-pitch~ property applies a proportionately spaced typeface -to the button~s text. - -[[#h:defcf4fc-8fa8-4c29-b12e-7119582cc929][Font configurations for Org and others]]. - -The ~underline~ property draws a line below the affected text and -removes whatever box effect. This is optimal when Emacs runs inside a -terminal emulator ([[#h:fbb5e254-afd6-4313-bb05-93b3b4f67358][More accurate colors in terminal emulators]]). If -~flat~ and ~underline~ are defined together, the latter takes -precedence. - -The symbol of a weight attribute adjusts the font of the button -accordingly, such as ~light~, ~semibold~, etc. Valid symbols are -defined in the variable ~modus-themes-weights~. - -[[#h:2793a224-2109-4f61-a106-721c57c01375][Configure bold and italic faces]]. - -A number, expressed as a floating point (e.g. =0.9=), adjusts the height -of the button's text to that many times the base font size. The default -height is the same as =1.0=, though it need not be explicitly stated. -Instead of a floating point, an acceptable value can be in the form of a -cons cell like =(height . FLOAT)= or =(height FLOAT)=, where FLOAT is -the given number. - -The ~all-buttons~ property extends the box button effect (or the -aforementioned properties) to the faces of the generic widget library. -By default, those do not look like the buttons of the Custom UI as they -are ordinary text wrapped in square brackets. - -Combinations of any of those properties are expressed as a list, -like in these examples: - -#+begin_src emacs-lisp -(flat) -(variable-pitch flat) -(variable-pitch flat semibold 0.9) -(variable-pitch flat semibold (height 0.9)) ; same as above -(variable-pitch flat semibold (height . 0.9)) ; same as above -#+end_src - -The order in which the properties are set is not significant. - -In user configuration files the form may look like this: - -#+begin_src emacs-lisp -(setq modus-themes-box-buttons '(variable-pitch flat 0.9)) -#+end_src - -** Option for command prompt styles -:properties: -:alt_title: Command prompts -:description: Choose among plain, subtle, or intense prompts -:custom_id: h:db5a9a7c-2928-4a28-b0f0-6f2b9bd52ba1 -:end: -#+vindex: modus-themes-prompts - -Brief: Control the style of command prompts (e.g. minibuffer, shell, IRC -clients). - -Symbol: ~modus-themes-prompts~ (=choice= type, list of properties) - -Possible values are expressed as a list of properties (default is ~nil~ or -an empty list). The list can include any of the following symbols: - -+ ~background~ -+ ~bold~ -+ ~gray~ -+ ~intense~ -+ ~italic~ The default (a ~nil~ value or an empty list) means to only use a subtle -accented foreground color. - -The property ~background~ applies a background color to the prompt's text. -By default, this is a subtle accented value. - -The property ~intense~ makes the foreground color more prominent. If the -~background~ property is also set, it amplifies the value of the -background as well. - -The property ~gray~ changes the prompt's colors to grayscale. This -affects the foreground and, if the ~background~ property is also set, the -background. Its effect is subtle, unless it is combined with the -~intense~ property. - -The property ~bold~ makes the text use a bold typographic weight. -Similarly, ~italic~ adds a slant to the font's forms (italic or oblique -forms, depending on the typeface). - -Combinations of any of those properties are expressed as a list, like in -these examples: - -#+begin_src emacs-lisp -(intense) -(bold intense) -(intense bold gray) -(intense background gray bold) -#+end_src - -The order in which the properties are set is not significant. +colored foreground color. -In user configuration files the form may look like this: - -#+begin_src emacs-lisp -(setq modus-themes-prompts '(background gray)) -#+end_src +The ~italic~ property adds a slant to the font's forms (italic or +oblique forms, depending on the typeface). -** Option for mode line presentation -:properties: -:alt_title: Mode line -:description: Choose among several styles, with or without borders -:custom_id: h:27943af6-d950-42d0-bc23-106e43f50a24 -:end: -#+vindex: modus-themes-mode-line - -Brief: Control the style of the mode lines. - -Symbol: ~modus-themes-mode-line~ (=choice= type, list of properties) - -Possible values, which can be expressed as a list of combinations of box -effect, color, and border visibility: - -+ Overall style: - - ~3d~ - - ~moody~ -+ ~accented~ -+ ~borderless~ -+ A natural number > 1 for extra padding or a cons cell in the form of - ~(padding . NATNUM)~. -+ A floating point to set the height of the mode line's text. It can - also be a cons cell in the form of ~(height . FLOAT)~. - -The default (a ~nil~ value or an empty list) is a two-dimensional -rectangle with a border around it. The active and the inactive mode -lines use different shades of grayscale values for the background, -foreground, border. - -The ~3d~ property applies a three-dimensional effect to the active mode -line. The inactive mode lines remain two-dimensional and are toned down -a bit, relative to the default style. - -The ~moody~ property optimizes the mode line for use with the library of -the same name (hereinafter referred to as 'Moody'). In practice, it -removes the box effect and replaces it with underline and overline -properties. It also tones down the inactive mode lines. Despite its -intended purpose, this option can also be used without the Moody library -(please consult the themes' manual on this point for more details). If -both ~3d~ and ~moody~ properties are set, the latter takes precedence. - -The ~borderless~ property removes the color of the borders. It does not -actually remove the borders, but only makes their color the same as the -background, effectively creating some padding. - -The ~accented~ property ensures that the active mode line uses a colored -background instead of the standard shade of gray. - -A positive integer (natural number or natnum) applies a padding effect -of NATNUM pixels at the boundaries of the mode lines. The default value -is 1 and does not need to be specified explicitly. The padding has no -effect when the ~moody~ property is also used, because Moody already -applies its own tweaks. To ensure that the underline is placed at the -bottom of the mode line, set ~x-underline-at-descent-line~ to non-~nil~ -(this is not needed when the ~borderless~ property is also set). For -users on Emacs 29, the ~x-use-underline-position-properties~ variable must -also be set to nil. - -The padding can also be expressed as a cons cell in the form of -=(padding . NATNUM)= or =(padding NATNUM)= where the key is constant and -NATNUM is the desired natural number. - -A floating point applies an adjusted height to the mode line's text as a -multiple of the main font size. The default rate is 1.0 and does not -need to be specified. Apart from a floating point, the height may also -be expressed as a cons cell in the form of =(height . FLOAT)= or -=(height FLOAT)= where the key is constant and the FLOAT is the desired -number. +The symbol of a font weight attribute such as ~light~, ~semibold~, et +cetera, adds the given weight to links. Valid symbols are defined in +the variable ~modus-themes-weights~. The absence of a weight means +that the one of the underlying text will be used. Combinations of any of those properties are expressed as a list, like in these examples: #+begin_src emacs-lisp -(accented) -(borderless 3d) -(moody accented borderless) -#+end_src - -Same as above, using the padding and height as an example (these -all yield the same result): - -#+begin_src emacs-lisp -(accented borderless 4 0.9) -(accented borderless (padding . 4) (height . 0.9)) -(accented borderless (padding 4) (height 0.9)) +(bold italic) +(italic semibold) #+end_src The order in which the properties are set is not significant. @@ -1137,57 +689,10 @@ The order in which the properties are set is not significant. In user configuration files the form may look like this: #+begin_src emacs-lisp -(setq modus-themes-mode-line '(borderless accented)) +(setq modus-themes-prompts '(extrabold italic)) #+end_src -Note that Moody does not expose any faces that the themes could style -directly. Instead it re-purposes existing ones to render its tabs and -ribbons. As such, there may be cases where the contrast ratio falls -below the 7:1 target that the themes conform with (WCAG AAA). To hedge -against this, we configure a fallback foreground for the ~moody~ property, -which will come into effect when the background of the mode line changes -to something less accessible, such as Moody ribbons (read the doc string -of ~set-face-attribute~, specifically ~:distant-foreground~). This fallback -is activated when Emacs determines that the background and foreground of -the given construct are too close to each other in terms of color -distance. In practice, users will need to experiment with the variable -~face-near-same-color-threshold~ to trigger the effect. We find that a -value of =45000= shall suffice, contrary to the default =30000=. Though for -the combinations that involve the ~accented~ and ~moody~ properties, as -mentioned above, that should be raised up to =70000=. Do not set it too -high, because it has the adverse effect of always overriding the default -colors (which have been carefully designed to be highly accessible). - -Furthermore, because Moody expects an underline and overline instead of -a box style, it is strongly advised to set ~x-underline-at-descent-line~ -to a non-~nil~ value. - -Finally, note that various packages which heavily modify the mode line, -such as =doom-modeline=, =nano-modeline=, =powerline=, =spaceline= may not look -as intended with all possible combinations of this user option. - -** Option for accented background in tab interfaces -:properties: -:alt_title: Tab style -:description: Toggle accented background for tabs -:custom_id: h:27cef8f5-dc4e-4c93-ba41-b899e650d936 -:end: -#+vindex: modus-themes-tabs-accented - -Brief: Toggle accent colors for tabbed interfaces. - -Symbol: ~modus-themes-tabs-accented~ (=boolean= type) - -Possible values: - -+ ~nil~ (default) -+ ~t~ - -By default, all tab interfaces use backgrounds which are shades of gray. -When this option is set to non-~nil~, the backgrounds become colorful. - -This affects the built-in ~tab-bar-mode~ and ~tab-line-mode~, as well as the -Centaur tabs package. +[[#h:bd75b43a-0bf1-45e7-b8b4-20944ca8b7f8][Make prompts more or less colorful]]. ** Option for completion framework aesthetics :properties: @@ -1201,204 +706,194 @@ Brief: Set the overall style of completion framework interfaces. Symbol: ~modus-themes-completions~ (=alist= type properties) -This affects Company, Corfu, Flx, Helm, Icomplete/Fido, Ido, Ivy, -Orderless, Selectrum, Vertico. The value is an alist that takes the -form of a =(KEY . PROPERTIES)= combination. =KEY= is a symbol, while +This affects Company, Corfu, Flx, Icomplete/Fido, Ido, Ivy, Orderless, +Vertico. The value is an alist of expressions, each of which takes +the form of =(KEY . LIST-OF-PROPERTIES)=. =KEY= is a symbol, while =PROPERTIES= is a list. Here is a sample, followed by a description of the particularities: #+begin_src emacs-lisp (setq modus-themes-completions - '((matches . (extrabold background intense)) - (selection . (semibold accented intense)) - (popup . (accented)))) + '((matches . (extrabold background)) + (selection . (semibold italic)))) #+end_src The ~matches~ key refers to the highlighted characters that correspond -to the user's input. When its properties are ~nil~ or an empty list, +to the user's input. When its properties are nil or an empty list, matching characters in the user interface will have a bold weight and a colored foreground. The list of properties may include any of the following symbols regardless of the order they may appear in: -- ~background~ to add a background color; - -- ~intense~ to increase the overall coloration (also amplifies - the ~background~, if present); - - ~underline~ to draw a line below the characters; - ~italic~ to use a slanted font (italic or oblique forms); -- The symbol of a font weight attribute such as ~light~, ~semibold~, et - cetera. Valid symbols are defined in the ~modus-themes-weights~ - variable. The absence of a weight means that bold will be used. +- The symbol of a font weight attribute such as ~light~, + ~semibold~, et cetera. Valid symbols are defined in the + variable ~modus-themes-weights~. The absence of a weight means + that bold will be used. The ~selection~ key applies to the current line or currently matched candidate, depending on the specifics of the user interface. When its -properties are ~nil~ or an empty list, it has a subtle gray background, +properties are nil or an empty list, it has a subtle gray background, a bold weight, and the base foreground value for the text. The list of properties it accepts is as follows (order is not significant): -- ~accented~ to make the background colorful instead of gray; - -- ~text-also~ to apply extra color to the text of the selected line; - -- ~intense~ to increase the overall coloration; - - ~underline~ to draw a line below the characters; - ~italic~ to use a slanted font (italic or oblique forms); -- The symbol of a font weight attribute such as ~light~, ~semibold~, et - cetera. Valid symbols are defined in the ~modus-themes-weights~ - variable. The absence of a weight means that bold will be used. +- The symbol of a font weight attribute such as ~light~, + ~semibold~, et cetera. Valid symbols are defined in the + variable ~modus-themes-weights~. The absence of a weight means + that bold will be used. -The ~popup~ key takes the same values as ~selection~. The only -difference is that it applies specifically to user interfaces that -display an inline popup and thus have slightly different styling -requirements than the minibuffer. The two prominent packages are -=company= and =corfu=. - -Apart from specifying each key separately, a fallback list is accepted. -This is only useful when the desired aesthetic is the same across all -keys that are not explicitly referenced. For example, this: +Apart from specifying each key separately, a catch-all list is +accepted. This is only useful when the desired aesthetic is the same +across all keys that are not explicitly referenced. For example, +this: #+begin_src emacs-lisp (setq modus-themes-completions - '((t . (extrabold intense)))) + '((t . (extrabold underline)))) #+end_src Is the same as: #+begin_src emacs-lisp (setq modus-themes-completions - '((matches . (extrabold intense)) - (selection . (extrabold intense)) - (popup . (extrabold intense)))) + '((matches . (extrabold underline)) + (selection . (extrabold underline)))) #+end_src -In the case of the fallback, any property that does not apply to the -corresponding key is simply ignored (~matches~ does not have ~accented~ -and ~text-also~, while ~selection~ and ~popup~ do not have -~background~). +[[#h:d959f789-0517-4636-8780-18123f936f91][Make completion matches more or less colorful]]. -[[#h:2793a224-2109-4f61-a106-721c57c01375][Configure bold and italic faces]]. - -Also refer to the documentation of the ~orderless~ package for its -intersection with ~company~ (if you choose to use those in tandem). - -** Option for mail citations +** Option for org-mode block styles :properties: -:alt_title: Mail citations -:description: Choose among colorful, desaturated, monochrome citations -:custom_id: h:5a12765d-0ba0-4a75-ab11-e35d3bbb317d +:alt_title: Org mode blocks +:description: Choose among plain, gray, or tinted backgrounds +:custom_id: h:b7e328c0-3034-4db7-9cdf-d5ba12081ca2 :end: -#+vindex: modus-themes-mail-citations +#+vindex: modus-themes-org-blocks -Brief: Set the overall style of citations/quotes when composing -emails. +Brief: Set the overall style of Org code blocks, quotes, and the like. -Symbol: ~modus-themes-mail-citations~ (=choice= type) +Symbol: ~modus-themes-org-blocks~ (=choice= type) Possible values: 1. ~nil~ (default) -2. ~intense~ -3. ~faint~ -4. ~monochrome~ - -By default (a ~nil~ value) citations are styled with contrasting hues to -denote their depth. Colors are easy to tell apart because they -complement each other, but they otherwise are not very prominent. +2. ~gray-background~ +3. ~tinted-background~ -Option ~intense~ is similar to the default in terms of using contrasting -and complementary hues, but applies more saturated colors. - -Option ~faint~ maintains the same color-based distinction between citation -levels though the colors it uses have subtle differences between them. +Nil (the default) means that the block has no background of its own: +it uses the one that applies to the rest of the buffer. In this case, +the delimiter lines have a gray color for their text, making them look +exactly like all other Org properties. -Option ~monochrome~ turns all quotes into a shade of gray. +Option ~gray-background~ applies a subtle gray background to the +block's contents. It also affects the begin and end lines of the +block as they get another shade of gray as their background, which +differentiates them from the contents of the block. All background +colors extend to the edge of the window, giving the area a +rectangular, "blocky" presentation. If the begin/end lines do not +extend in this way, check the value of the Org user option +~org-fontify-whole-block-delimiter-line~. + +Option ~tinted-background~ uses a colored background for the contents +of the block. The exact color value will depend on the programming +language and is controlled by the variable ~org-src-block-faces~ +(refer to the theme's source code for the current association list). +For this to take effect, the Org buffer needs to be restarted with +~org-mode-restart~. + +Code blocks use their major mode's fontification (syntax highlighting) +only when the variable ~org-src-fontify-natively~ is non-nil. While +quote/verse blocks require setting +~org-fontify-quote-and-verse-blocks~ to a non-nil value. -Whatever the value assigned to this variable, citations in emails are -controlled by typographic elements or indentation, which the themes do -not touch. +[[#h:f44cc6e3-b0f1-4a5e-8a90-9e48fa557b50][Update Org block delimiter fontification]]. -** Option for fringe visibility +** Option for the headings' overall style :properties: -:alt_title: Fringes -:description: Choose among invisible, subtle, or intense fringe styles -:custom_id: h:1983c3fc-74f6-44f3-b917-967c403bebae +:alt_title: Heading styles +:description: Choose among several styles, also per heading level +:custom_id: h:271eff19-97aa-4090-9415-a6463c2f9ae1 :end: -#+vindex: modus-themes-fringes - -Brief: Control the overall coloration of the fringes. - -Symbol: ~modus-themes-fringes~ (=choice= type) - -Possible values: - -1. ~nil~ -2. ~subtle~ -3. ~intense~ +#+vindex: modus-themes-headings -When the value is nil, do not apply a distinct background color. +Brief: Heading styles with optional list of values per heading level. -With a value of ~subtle~ use a gray background color that is -visible yet close to the main background color. +Symbol: ~modus-themes-headings~ (=alist= type, multiple properties) -With ~intense~ use a more pronounced gray background color. +This is an alist that accepts a =(KEY . LIST-OF-VALUES)= combination. +The =KEY= is either a number, representing the heading's level (0 +through 8) or ~t~, which pertains to the fallback style. The named +keys =agenda-date= and =agenda-structure= apply to the Org agenda. -** Option for language checkers -:properties: -:alt_title: Language checkers -:description: Control the style of language checkers/linters -:custom_id: h:4b13743a-8ebf-4d2c-a043-cceba10b1eb4 -:end: -#+vindex: modus-themes-lang-checkers - -Brief: Control the style of in-buffer warnings and errors produced by -spell checkers, code linters, and the like. +Level 0 is a special heading: it is used for what counts as a document +title or equivalent, such as the =#+title= construct we find in Org +files. Levels 1-8 are regular headings. -Symbol: ~modus-themes-lang-checkers~ (=choice= type, list of properties) +The =LIST-OF-VALUES= covers symbols that refer to properties, as +described below. Here is a complete sample with various stylistic +combinations, followed by a presentation of all available properties: -Possible values are expressed as a list of properties (default is ~nil~ or -an empty list). The list can include any of the following symbols: +#+begin_src emacs-lisp +(setq modus-themes-headings + '((1 . (variable-pitch 1.5)) + (2 . (1.3)) + (agenda-date . (1.3)) + (agenda-structure . (variable-pitch light 1.8)) + (t . (1.1)))) +#+end_src -+ ~straight-underline~ -+ ~text-also~ -+ ~background~ -+ Overall coloration: - - ~intense~ - - ~faint~ +Properties: -The default (a ~nil~ value or an empty list) applies a color-coded -underline to the affected text, while it leaves the original foreground -intact. If the display spec of Emacs has support for it, the -underline's style is that of a wave, otherwise it is a straight line. ++ A font weight, which must be supported by the underlying typeface: + - ~thin~ + - ~ultralight~ + - ~extralight~ + - ~light~ + - ~semilight~ + - ~regular~ + - ~medium~ + - ~semibold~ + - ~bold~ (default) + - ~heavy~ + - ~extrabold~ + - ~ultrabold~ ++ A floating point as a height multiple of the default or a cons cell in + the form of =(height . FLOAT)=. -The property ~straight-underline~ ensures that the underline under the -affected text is always drawn as a straight line. +By default (a ~nil~ value for this variable), all headings have a bold +typographic weight and use a desaturated text color. -The property ~text-also~ applies the same color of the underline to the -affected text. +A ~variable-pitch~ property changes the font family of the heading to that +of the ~variable-pitch~ face (normally a proportionately spaced typeface). -The property ~background~ adds a color-coded background. +The symbol of a weight attribute adjusts the font of the heading +accordingly, such as ~light~, ~semibold~, etc. Valid symbols are +defined in the variable ~modus-themes-weights~. The absence of a weight +means that bold will be used by virtue of inheriting the ~bold~ face. -The property ~intense~ amplifies the applicable colors if ~background~ -and/or ~text-also~ are set. If ~intense~ is set on its own, then it implies -~text-also~. +[[#h:2793a224-2109-4f61-a106-721c57c01375][Configure bold and italic faces]]. -The property ~faint~ uses nuanced colors for the underline and for the -foreground when ~text-also~ is included. If both ~faint~ and ~intense~ are -specified, the former takes precedence. +A number, expressed as a floating point (e.g. 1.5), adjusts the height +of the heading to that many times the base font size. The default +height is the same as 1.0, though it need not be explicitly stated. +Instead of a floating point, an acceptable value can be in the form of a +cons cell like =(height . FLOAT)= or =(height FLOAT)=, where FLOAT is +the given number. -Combinations of any of those properties can be expressed in a list, as -in those examples: +Combinations of any of those properties are expressed as a list, like in +these examples: #+begin_src emacs-lisp -(background) -(straight-underline intense) -(background text-also straight-underline) +(semibold) +(variable-pitch semibold 1.3) +(variable-pitch semibold (height 1.3)) ; same as above +(variable-pitch semibold (height . 1.3)) ; same as above #+end_src The order in which the properties are set is not significant. @@ -1406,752 +901,1230 @@ The order in which the properties are set is not significant. In user configuration files the form may look like this: #+begin_src emacs-lisp -(setq modus-themes-lang-checkers '(text-also background)) +(setq modus-themes-headings + '((1 . (variable-pitch 1.5)) + (2 . (1.3)) + (agenda-date . (1.3)) + (agenda-structure . (variable-pitch light 1.8)) + (t . (1.1)))) #+end_src -NOTE: The placement of the straight underline, though not the wave -style, is controlled by the built-in variables ~underline-minimum-offset~, -~x-underline-at-descent-line~, ~x-use-underline-position-properties~. - -To disable fringe indicators for Flymake or Flycheck, refer to variables -~flymake-fringe-indicator-position~ and ~flycheck-indication-mode~, -respectively. - -** Option for line highlighting -:properties: -:alt_title: Line highlighting -:description: Choose style of current line (hl-line-mode) -:custom_id: h:1dba1cfe-d079-4c13-a810-f768e8789177 -:end: -#+vindex: modus-themes-hl-line - -Brief: Control the style of the current line of ~hl-line-mode~. - -Symbol: ~modus-themes-hl-line~ (=choice= type, list of properties) - -The value is a list of properties, each designated by a symbol. With -a ~nil~ value, or an empty list, the style is a subtle gray background -color. - -Possible properties are the following symbols: - -+ ~accented~ -+ ~intense~ -+ ~underline~ - -The property ~accented~ changes the background to a colored variant. - -An ~underline~ property draws a line below the highlighted area. Its -color is similar to the background, so gray by default or an accent -color when ~accented~ is also set. - -An ~intense~ property amplifies the colors in use, which may be both the -background and the underline. - -Combinations of any of those properties are expressed as a list, like in -these examples: +When defining the styles per heading level, it is possible to pass a +non-~nil~ value (~t~) instead of a list of properties. This will retain the +original aesthetic for that level. For example: #+begin_src emacs-lisp -(intense) -(underline intense) -(accented intense underline) -#+end_src - -The order in which the properties are set is not significant. - -In user configuration files the form may look like this: +(setq modus-themes-headings + '((1 . t) ; keep the default style + (2 . (semibold 1.2)) + (t . (rainbow)))) ; style for all other headings -#+begin_src emacs-lisp -(setq modus-themes-hl-line '(underline accented)) +(setq modus-themes-headings + '((1 . (variable-pitch 1.5)) + (2 . (semibold)) + (t . t))) ; default style for all other levels #+end_src -Set ~x-underline-at-descent-line~ to a non-~nil~ value so that the -placement of the underline coincides with the lower boundary of the -colored background. +Note that the text color of headings, of their background, and +overline can all be set via the overrides. It is possible to have any +color combination for any heading level (something that could not be +done in older versions of the themes). -This style affects several packages that enable ~hl-line-mode~, such as -=elfeed=, =notmuch=, and =mu4e=. +[[#h:34c7a691-19bb-4037-8d2f-67a07edab150][Option for palette overrides]]. -[ Also check the =lin= package on GNU ELPA (by the author of the - modus-themes) for a stylistic enhancement to ~hl-line-mode~. ] +[[#h:11297984-85ea-4678-abe9-a73aeab4676a][Make headings more or less colorful]]. -** Option for line numbers +** Option for variable-pitch font in UI elements :properties: -:alt_title: Line numbers -:description: Toggle subtle style for line numbers -:custom_id: h:8c4a6230-2e43-4aa2-a631-3b7179392e09 +:alt_title: UI typeface +:description: Toggle the use of variable-pitch across the User Interface +:custom_id: h:16cf666c-5e65-424c-a855-7ea8a4a1fcac :end: -#+vindex: modus-themes-subtle-line-numbers +#+vindex: modus-themes-variable-pitch-ui -Brief: Toggle subtle line numbers. +Brief: Toggle the use of proportionately spaced (~variable-pitch~) fonts +in the User Interface. -Symbol: ~modus-themes-subtle-line-numbers~ (=boolean= type) +Symbol: ~modus-themes-variable-pitch-ui~ (=boolean= type) -Possible value: +Possible values: 1. ~nil~ (default) 2. ~t~ -The default style for ~display-line-numbers-mode~ and its global variant -is to apply a subtle gray background to the line numbers. The current -line has a more pronounced background and foreground combination to -bring more attention to itself. +This option concerns User Interface elements that are under the direct +control of Emacs. In particular: the mode line, header line, tab bar, +and tab line. + +The default is to use the same font as the rest of Emacs, which usually +is a monospaced family. -Similarly, the faces for ~display-line-numbers-major-tick~ and its -counterpart ~display-line-numbers-minor-tick~ use appropriate styles that -involve a bespoke background and foreground combination. +With a non-~nil~ value (~t~) apply a proportionately spaced typeface. This +is done by assigning the ~variable-pitch~ face to the relevant items. -With a non-~nil~ value (~t~), line numbers have no background of their own. -Instead they retain the primary background of the theme, blending with -the rest of the buffer. Foreground values for all relevant faces are -updated to accommodate this aesthetic. +[[#h:defcf4fc-8fa8-4c29-b12e-7119582cc929][Font configurations for Org and others]]. -** Option for mouseover effects +** Option for palette overrides :properties: -:alt_title: Mouse hover effects -:description: Toggle intense style for mouseover highlights -:custom_id: h:9b869620-fcc5-4b5f-9ab8-225d73b7f22f +:alt_title: Palette overrides +:description: Refashion color values and/or semantic color mappings +:custom_id: h:34c7a691-19bb-4037-8d2f-67a07edab150 :end: -#+vindex: modus-themes-intense-mouseovers -Brief: Toggle intense mouse hover effects. +This section describes palette overrides in detail. For a simpler +alternative, use the presets we provide ([[#h:b0bc811c-227e-42ec-bf67-15e1f41eb7bc][Palette override presets]]). -Symbol: ~modus-themes-intense-mouseovers~ (=boolean= type) +Each Modus theme specifies a color palette that declares named color +values and semantic color mappings: -Possible value: ++ Named colors consist of a symbol and a string that specifies a + hexadecimal RGB value. For example: =(blue-warmer "#354fcf")=. -1. ~nil~ (default) -2. ~t~ ++ The semantic color mappings associate an abstract construct with a + given named color from the palette, like =(heading-2 yellow-faint)=. + Both elements of the list are symbols, though the ~cadr~ (value) can + be a string that specifies a color, such as =(heading-2 "#354fcf")=. + Semantic color mappings cannot be recursive: their value must be + either a named color or a hexadecimal RGB value. -By default all mouseover effects apply a highlight with a subtle colored -background. When non-~nil~, these have a more pronounced effect. +#+vindex: modus-themes-common-palette-overrides +Both of those subsets can be overridden, thus refashioning the theme. +Overrides are either shared, by being stored in the user option +~modus-themes-common-palette-overrides~, or they are specific to the +theme they name. In the latter case, the naming scheme of each +palette variable is =THEME-NAME-palette-overrides=, thus yielding: -Note that this affects the generic ~highlight~ which, strictly speaking, -is not limited to mouse usage. +#+vindex: modus-operandi-palette-overrides ++ ~modus-operandi-palette-overrides~ -** Option for markup style in Org and others -:properties: -:alt_title: Markup -:description: Choose style for markup in Org and others -:custom_id: h:9d9a4e64-99ac-4018-8f66-3051b9c43fd7 -:end: -#+vindex: modus-themes-markup +#+vindex: modus-operandi-deuteranopia-palette-overrides ++ ~modus-operandi-deuteranopia-palette-overrides~ -Brief: Choose style of markup in Org, Markdown, and others (affects -constructs such as Org's ==verbatim== and =~code~=). +#+vindex: modus-operandi-tinted-palette-overrides ++ ~modus-operandi-tinted-palette-overrides~ -Symbol: ~modus-themes-markup~ (=boolean= type) +#+vindex: modus-vivendi-palette-overrides ++ ~modus-vivendi-palette-overrides~ -Possible values are expressed as a list of properties (default is ~nil~ or -an empty list). The list can include any of the following symbols: +#+vindex: modus-vivendi-deuteranopia-palette-overrides ++ ~modus-vivendi-deuteranopia-palette-overrides~ -1. ~bold~ -2. ~italic~ -3. ~background~ -4. ~intense~ +#+vindex: modus-vivendi-tinted-palette-overrides ++ ~modus-vivendi-tinted-palette-overrides~ -The ~italic~ property applies a typographic slant (italics). +Theme-specific overrides take precedence over the shared ones. It is +strongly advised that shared overrides do NOT alter color values, as +those will not be appropriate for both dark and light themes. Common +overrides are best limited to the semantic color mappings as those use +the color value that corresponds to the active theme (e.g. make the +cursor =blue-warmer= in all themes, whatever the value of +=blue-warmer= is in each theme). -The ~bold~ property applies a heavier typographic weight. +The value of any overrides' variable must mirror a theme's palette. +Palette variables are named after their theme as =THEME-NAME-palette=. +For example, the ~modus-operandi-palette~ is like this: -[[#h:2793a224-2109-4f61-a106-721c57c01375][Configure bold and italic faces]]. +#+begin_src emacs-lisp +(defconst modus-operandi-palette + '( +;;; Basic values -The ~background~ property adds a background color. The background is a -shade of gray, unless the ~intense~ property is also set. + (bg-main "#ffffff") + (bg-dim "#f0f0f0") + (fg-main "#000000") -The ~intense~ property amplifies the existing coloration. When -~background~ is used, the background color is enhanced as well and -becomes tinted instead of being gray. + ;; ... -Combinations of any of those properties are expressed as a list, -like in these examples: + (red "#a60000") + (red-warmer "#972500") + (red-cooler "#a0132f") + (red-faint "#7f0000") + (red-intense "#d00000") -#+begin_src emacs-lisp -(bold) -(bold italic) -(bold italic intense) -(bold italic intense background) -#+end_src + ;; ... -The order in which the properties are set is not significant. +;;;; Mappings -In user configuration files the form may look like this: + ;; ... -#+begin_src emacs-lisp -(setq modus-themes-markup '(bold italic)) -#+end_src + (cursor fg-main) + (builtin magenta-warmer) + (comment fg-dim) + (constant blue-cooler) + (docstring green-faint) + (fnname magenta) + (keyword magenta-cooler) -Also check the variables ~org-hide-emphasis-markers~, -~org-hide-macro-markers~. + ;; ... + )) +#+end_src -** Option for parenthesis matching -:properties: -:alt_title: Matching parentheses -:description: Choose between various styles for matching delimiters/parentheses -:custom_id: h:e66a7e4d-a512-4bc7-9f86-fbbb5923bf37 -:end: -#+vindex: modus-themes-paren-match +The ~modus-operandi-palette-overrides~ targets the entries that need +to be changed. For example, to make the main foreground colour a dark +gray instead of pure black, use a shade of red for comments, and apply +a cyan hue to keywords: -Brief: Control the style of matching delimiters produced by -~show-paren-mode~. +#+begin_src emacs-lisp +(setq modus-operandi-palette-overrides + '((fg-main "#333333") + (comment red-faint) + (keyword cyan-cooler))) +#+end_src -Symbol: ~modus-themes-paren-match~ (=choice= type, list of properties) +Changes take effect upon theme reload ([[#h:9001527a-4e2c-43e0-98e8-3ef72d770639][Custom reload theme]]). +Overrides are removed by setting their variable to a ~nil~ value. -Possible values are expressed as a list of properties (default is ~nil~ or -an empty list). The list can include any of the following symbols: +The common accented foregrounds in each palette follow a predictable +naming scheme: =HUE{,-warmer,-cooler,-faint,-intense}=. =HUE= is one +of the six basic colors: red, green, blue, yellow, magenta, cyan. -+ ~bold~ -+ ~intense~ -+ ~underline~ +Named colors that are meant to be used as backgrounds contain =bg= in +their name, such as =bg-red-intense=. While special purpose +foregrounds that are meant to be combined with such backgrounds, +contain =fg= in their name, such as =fg-removed= which complements +=bg-removed=. -The default (a ~nil~ value or an empty list) is a subtle background color. +Named colors can be previewed, such as with the command +~modus-themes-list-colors~ ([[#h:f4d4b71b-2ca5-4c3d-b0b4-9bfd7aa7fb4d][Preview theme colors]]). -The ~bold~ property adds a bold weight to the characters of the matching -delimiters. +For a video tutorial that users of all skill levels can approach, +watch: https://protesilaos.com/codelog/2022-12-17-modus-themes-v4-demo/. -The ~intense~ property applies a more prominent background color to the -delimiters. +*** Palette override presets +:PROPERTIES: +:CUSTOM_ID: h:b0bc811c-227e-42ec-bf67-15e1f41eb7bc +:END: -The ~underline~ property draws a straight line under the affected text. +This section shows how to refashion the themes by opting in to the +stylistic presets we provide. Those presets override the default +color mappings to amplify or tone down the overall coloration of the +them. -Combinations of any of those properties are expressed as a list, like in -these examples: +To make almost all aspects of the themes less intense, use this: #+begin_src emacs-lisp -(bold) -(underline intense) -(bold intense underline) +;; Always remember to reload the theme for changes to take effect! +(setq modus-themes-common-palette-overrides modus-themes-preset-overrides-faint) #+end_src -The order in which the properties are set is not significant. +#+vindex: modus-themes-preset-overrides-faint +With ~modus-themes-preset-overrides-faint~ the grays are toned down, +gray backgrounds are removed from some contexts, and almost all accent +colors are desaturated. It makes the themes less attention-grabbing. -In user configuration files the form may look like this: +On the opposite end of the stylistic spectrum, we have this #+begin_src emacs-lisp -(setq modus-themes-paren-match '(bold intense)) +;; Always remember to reload the theme for changes to take effect! +(setq modus-themes-common-palette-overrides modus-themes-preset-overrides-intense) #+end_src -This customization variable affects the built-in ~show-paren-mode~ and the -=smartparens= package. - -** Option for active region -:properties: -:alt_title: Active region -:description: Choose between various styles for the active region -:custom_id: h:60798063-b4ad-45ea-b9a7-ff7b5c0ab74c -:end: -#+vindex: modus-themes-region +#+vindex: modus-themes-preset-overrides-intense +The ~modus-themes-preset-overrides-intense~ makes many background +colors accented instead of gray and increases coloration in a number +of places. Colors stand out more and are made easier to spot. -Brief: Control the style of the region. +Note that the user is not limited to those presets. The system of +overrides we provide makes it possible to tweak the value of each +individual named color and to change how values are assigned to +semantic color mappings ([[#h:34c7a691-19bb-4037-8d2f-67a07edab150][Option for palette overrides]]). Subsequent +sections provide examples ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). -Symbol: ~modus-themes-region~ (=choice= type, list of properties) - -Possible values are expressed as a list of properties (default is ~nil~ or -an empty list). The list can include any of the following symbols: +It is also possible to use those presets as a basis and, for example, +add to them code from the subsequent sections of this manual. This is +the general idea (extra space for didactic purposes): -+ ~no-extend~ -+ ~bg-only~ -+ ~accented~ +#+begin_src emacs-lisp +(setq modus-themes-common-palette-overrides + `( + ;; From the section "Make the mode line borderless" + (border-mode-line-active unspecified) + (border-mode-line-inactive unspecified) -The default (a ~nil~ value or an empty list) is a prominent gray -background that overrides all foreground colors in the area it -encompasses. Its reach extends to the edge of the window. + ;; From the section "Make matching parenthesis more or less intense" + (bg-paren-match bg-magenta-intense) + (underline-paren-match fg-main) -The ~no-extend~ property limits the region to the end of the line, so that -it does not reach the edge of the window. + ;; And expand the preset here. Note that the ,@ works because + ;; we use the backtick for this list, instead of a straight + ;; quote. + ,@modus-themes-preset-overrides-intense)) +#+end_src -The ~bg-only~ property makes the region's background color more subtle to -allow the underlying text to retain its foreground colors. +*** Stylistic variants using palette overrides +:PROPERTIES: +:CUSTOM_ID: h:df1199d8-eaba-47db-805d-6b568a577bf3 +:END: -The ~accented~ property applies a more colorful background to the region. +This section contains practical examples of overriding the palette of +the themes ([[#h:34c7a691-19bb-4037-8d2f-67a07edab150][Option for palette overrides]]). Users can copy the code to +their init file, evaluate it, and then re-load the theme for changes +to take effect. To apply overrides at startup simply define them +before the call that loads the theme. Remember that we also provide +presets that are easier to apply ([[#h:b0bc811c-227e-42ec-bf67-15e1f41eb7bc][Palette override presets]]). -Combinations of any of those properties are expressed as a list, like in -these examples: +**** Make the mode line borderless +:PROPERTIES: +:CUSTOM_ID: h:80ddba52-e188-411f-8cc0-480ebd75befe +:END: -#+begin_src emacs-lisp -(no-extend) -(bg-only accented) -(accented bg-only no-extend) -#+end_src +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). To +hide the border around the active and inactive mode lines, we need to +set their color to that of the underlying background. -The order in which the properties are set is not significant. +[[#h:e8d781be-eefc-4a81-ac4e-5ed156190df7][Make the active mode line colorful]]. -In user configuration files the form may look like this: +[[#h:5a0c58cc-f97f-429c-be08-927b9fbb0a9c][Add padding to mode line]]. #+begin_src emacs-lisp -(setq modus-themes-region '(bg-only no-extend)) -#+end_src +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. -** Option for diff buffer looks -:properties: -:alt_title: Diffs -:description: Choose among intense, desaturated, or background-only diffs -:custom_id: h:ea7ac54f-5827-49bd-b09f-62424b3b6427 -:end: -#+vindex: modus-themes-diffs +(setq modus-themes-common-palette-overrides + '((border-mode-line-active unspecified) + (border-mode-line-inactive unspecified))) +#+end_src -Brief: Set the overall style of diffs. +**** Make the active mode line colorful +:PROPERTIES: +:CUSTOM_ID: h:e8d781be-eefc-4a81-ac4e-5ed156190df7 +:END: -Symbol: ~modus-themes-diffs~ (=choice= type) +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). +Here we show some snippets that apply different stylistic variants. +Of course, it is possible to use theme-specific overrides to, say, +have a blue mode line for ~modus-operandi~ and a red one for +~modus-vivendi~. -Possible values: +[[#h:80ddba52-e188-411f-8cc0-480ebd75befe][Make the mode line borderless]]. -1. ~nil~ (default) -2. ~desaturated~ -3. ~bg-only~ +[[#h:5a0c58cc-f97f-429c-be08-927b9fbb0a9c][Add padding to mode line]]. -The default (~nil~) uses fairly intense color combinations for diffs, by -applying prominently colored backgrounds, with appropriately tinted -foregrounds. - -Option ~desaturated~ follows the same principles as with the default -(~nil~), though it tones down all relevant colors. +#+begin_src emacs-lisp +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. -Option ~bg-only~ applies a background but does not override the text's -foreground. This makes it suitable for a non-~nil~ value passed to -~diff-font-lock-syntax~ (note: Magit does not support syntax highlighting -in diffs---last checked on 2021-12-02). +;; Blue background, neutral foreground, intense blue border +(setq modus-themes-common-palette-overrides + '((bg-mode-line-active bg-blue) + (fg-mode-line-active fg-main) + (border-mode-line-active blue-intense))) -When the user option ~modus-themes-deuteranopia~ is non-~nil~, all diffs -will use a red/blue color-coding system instead of the standard -red/green. Other stylistic changes are made in the interest of -optimizing for such a use-case. +;; Subtle blue background, neutral foreground, intense blue border +(setq modus-themes-common-palette-overrides + '((bg-mode-line-active bg-blue-subtle) + (fg-mode-line-active fg-main) + (border-mode-line-active blue-intense))) -[[#h:3ed03a48-20d8-4ce7-b214-0eb7e4c79abe][Option for red-green color deficiency or deuteranopia]]. +;; Subtle red background, red foreground, invisible border +(setq modus-themes-common-palette-overrides + '((bg-mode-line-active bg-red-subtle) + (fg-mode-line-active red-warmer) + (border-mode-line-active bg-red-subtle))) +#+end_src -In versions before =2.0.0= there was an option for foreground-only diffs. -This is no longer supported at the theme level because there are cases -where the perceived contrast and overall contextuality were not good -enough although the applied colors were technically above the 7:1 -contrast threshold. +**** Make the fringe invisible or another color +:PROPERTIES: +:CUSTOM_ID: h:c312dcac-36b6-4a1f-b1f5-ab1c9abe27b0 +:END: -[[#h:e2aed9eb-5e1e-45ec-bbd7-bc4faeab3236][Diffs with only the foreground]]. +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). +Here we show how to make the fringe invisible or how to assign to it a +different color. The "fringe" is a small area to the right and left +side of the Emacs window which shows indicators such as for truncation +or continuation lines. -[[#h:b0b31802-0216-427e-b071-1a47adcfe608][Ediff without diff color-coding]]. +#+begin_src emacs-lisp +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. -** Option for org-mode block styles -:properties: -:alt_title: Org mode blocks -:description: Choose among plain, gray, or tinted backgrounds -:custom_id: h:b7e328c0-3034-4db7-9cdf-d5ba12081ca2 -:end: -#+vindex: modus-themes-org-blocks +;; Make the fringe invisible +(setq modus-themes-common-palette-overrides + '((fringe unspecified))) -Brief: Set the overall style of Org code blocks, quotes, and the like. +;; Make the fringe more intense +(setq modus-themes-common-palette-overrides + '((fringe bg-active))) -Symbol: ~modus-themes-org-blocks~ (=choice= type) +;; Make the fringe colorful, but nuanced +(setq modus-themes-common-palette-overrides + '((fringe bg-blue-nuanced))) +#+end_src -Possible values: +**** Make links use subtle or no underlines +:PROPERTIES: +:CUSTOM_ID: h:6c1d1dea-5cbf-4d92-b7bb-570a7a23ffe9 +:END: -1. ~nil~ (default) -2. ~gray-background~ (value ~grayscale~ exists for backward compatibility) -3. ~tinted-background~ (value ~rainbow~ exists for backward compatibility) +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). In +this example, we showcase the special use of the ~unspecified~ symbol +that underline mappings can read correctly. -Nil (the default) means that the block has no background of its own: it -uses the one that applies to the rest of the buffer. In this case, the -delimiter lines have a gray color for their text, making them look -exactly like all other Org properties. +#+begin_src emacs-lisp +;; Subtle underlines +(setq modus-themes-common-palette-overrides + '((underline-link border) + (underline-link-visited border) + (underline-link-symbolic border))) -Option ~gray-background~ applies a subtle gray background to the block's -contents. It also affects the begin and end lines of the block as they -get another shade of gray as their background, which differentiates them -from the contents of the block. All background colors extend to the -edge of the window, giving the area a rectangular, "blocky" -presentation. - -Option ~tinted-background~ uses a slightly colored background for the -contents of the block. The exact color will depend on the programming -language and is controlled by the variable ~org-src-block-faces~ (refer to -the theme's source code for the current association list). For this to -take effect, the Org buffer needs to be restarted with ~org-mode-restart~. -In this scenario, it may be better to inhibit the extension of the -delimiter lines' background to the edge of the window because Org does -not provide a mechanism to update their colors depending on the contents -of the block. Disable the extension of such backgrounds by setting -~org-fontify-whole-block-delimiter-line~ to nil. - -Code blocks use their major mode's colors only when the variable -~org-src-fontify-natively~ is non-~nil~. While quote/verse blocks require -setting ~org-fontify-quote-and-verse-blocks~ to a non-~nil~ value. +;; No underlines +(setq modus-themes-common-palette-overrides + '((underline-link unspecified) + (underline-link-visited unspecified) + (underline-link-symbolic unspecified))) +#+end_src -[[#h:f44cc6e3-b0f1-4a5e-8a90-9e48fa557b50][Update Org block delimiter fontification]]. +**** Make prompts more or less colorful +:PROPERTIES: +:CUSTOM_ID: h:bd75b43a-0bf1-45e7-b8b4-20944ca8b7f8 +:END: -Older versions of the themes provided options ~grayscale~ (or ~greyscale~) -and ~rainbow~. Those will continue to work as they are aliases for -~gray-background~ and ~tinted-background~, respectively. +This section contains practical examples of overriding the palette of +the themes ([[#h:34c7a691-19bb-4037-8d2f-67a07edab150][Option for palette overrides]]). In the following code +block we show how to add or remove color from prompts. -** Option for Org agenda constructs -:properties: -:alt_title: Org agenda -:description: Control each element in the presentation of the agenda -:custom_id: h:68f481bc-5904-4725-a3e6-d7ecfa7c3dbc -:end: -#+vindex: modus-themes-org-agenda +[[#h:db5a9a7c-2928-4a28-b0f0-6f2b9bd52ba1][Option for command prompt styles]]. -Brief: Control the style of the Org agenda. Multiple parameters are -available, each with its own options. +#+begin_src emacs-lisp +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. -Symbol: ~modus-themes-org-agenda~ (=alist= type, multiple styles) +;; Keep the background unspecified (like the default), but use a faint +;; foreground color. +(setq modus-themes-common-palette-overrides + '((fg-prompt cyan-faint) + (bg-prompt unspecified))) -This is an alist that accepts a =(key . value)= combination. Some values -are specified as a list. Here is a sample, followed by a description of -all possible combinations: +;; Add a nuanced background to prompts that complements their foreground. +(setq modus-themes-common-palette-overrides + '((fg-prompt cyan) + (bg-prompt bg-cyan-nuanced))) -#+begin_src emacs-lisp -(setq modus-themes-org-agenda - '((header-block . (variable-pitch 1.5)) - (header-date . (grayscale workaholic bold-today 1.2)) - (event . (accented italic varied)) - (scheduled . uniform) - (habit . traffic-light))) +;; Add a yellow background and adjust the foreground accordingly. +(setq modus-themes-common-palette-overrides + '((fg-prompt fg-main) + (bg-prompt bg-yellow-subtle))) ; try to replace "subtle" with "intense" #+end_src -A ~header-block~ key applies to elements that concern the headings which -demarcate blocks in the structure of the agenda. By default (a ~nil~ -value) those are rendered in a bold typographic weight, plus a height -that is slightly taller than the default font size. Acceptable values -come in the form of a list that can include either or both of those -properties: +**** Make completion matches more or less colorful +:PROPERTIES: +:CUSTOM_ID: h:d959f789-0517-4636-8780-18123f936f91 +:END: -- ~variable-pitch~ to use a proportionately spaced typeface; +This section contains practical examples of overriding the palette of +the themes ([[#h:34c7a691-19bb-4037-8d2f-67a07edab150][Option for palette overrides]]). Here we demonstrate how +to activate background coloration for completion matches. We show +three different degrees of intensity. + +[[#h:f1c20c02-7b34-4c35-9c65-99170efb2882][Option for completion framework aesthetics]]. + +#+begin_src emacs-lisp +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. + +;; Add a nuanced background color to completion matches, while keeping +;; their foreground intact. +(setq modus-themes-common-palette-overrides + '((fg-completion-match-0 blue) + (fg-completion-match-1 magenta-warmer) + (fg-completion-match-2 cyan) + (fg-completion-match-3 red) + (bg-completion-match-0 bg-blue-nuanced) + (bg-completion-match-1 bg-magenta-nuanced) + (bg-completion-match-2 bg-cyan-nuanced) + (bg-completion-match-3 bg-red-nuanced))) + +;; Add intense background colors to completion matches and adjust the +;; foregrounds accordingly. +(setq modus-themes-common-palette-overrides + '((fg-completion-match-0 fg-main) + (fg-completion-match-1 fg-main) + (fg-completion-match-2 fg-main) + (fg-completion-match-3 fg-main) + (bg-completion-match-0 bg-blue-intense) + (bg-completion-match-1 bg-yellow-intense) + (bg-completion-match-2 bg-cyan-intense) + (bg-completion-match-3 bg-red-intense))) + +;; Like the above, but with subtle backgrounds. +(setq modus-themes-common-palette-overrides + '((fg-completion-match-0 fg-main) + (fg-completion-match-1 fg-main) + (fg-completion-match-2 fg-main) + (fg-completion-match-3 fg-main) + (bg-completion-match-0 bg-blue-subtle) + (bg-completion-match-1 bg-yellow-subtle) + (bg-completion-match-2 bg-cyan-subtle) + (bg-completion-match-3 bg-red-subtle))) +#+end_src + +Adding to the above, it is possible to, say, reduce the number of +colors to two: + +#+begin_src emacs-lisp +;; No backgrounds (like the default) and just use two colors. +(setq modus-themes-common-palette-overrides + '((fg-completion-match-0 blue) + (fg-completion-match-1 yellow) + (fg-completion-match-2 blue) + (fg-completion-match-3 yellow) + (bg-completion-match-0 unspecified) + (bg-completion-match-1 unspecified) + (bg-completion-match-2 unspecified) + (bg-completion-match-3 unspecified))) + +;; Again, a two-color style but this time with backgrounds +(setq modus-themes-common-palette-overrides + '((fg-completion-match-0 blue) + (fg-completion-match-1 yellow) + (fg-completion-match-2 blue) + (fg-completion-match-3 yellow) + (bg-completion-match-0 bg-blue-nuanced) + (bg-completion-match-1 bg-yellow-nuanced) + (bg-completion-match-2 bg-blue-nuanced) + (bg-completion-match-3 bg-yellow-nuanced))) +#+end_src + +The user can mix and match to their liking. + +**** Make comments yellow and strings green +:PROPERTIES: +:CUSTOM_ID: h:26f53daa-0065-48dc-88ab-6a718d16cd95 +:END: -- A number as a floating point (e.g. 1.5) to set the height of the text - to that many times the default font height. A float of 1.0 or the - symbol ~no-scale~ have the same effect of making the font the same - height as the rest of the buffer. When neither a number nor - `no-scale' are present, the default is a small increase in height (a - value of 1.15). +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). In +previous versions of the themes, we provided an option for yellow-ish +comments and green-ish strings. For some users, those were still not +good enough, as the exact values were hardcoded. Here we show how to +reproduce the effect, but also how to tweak it to one's liking. - Instead of a floating point, an acceptable value can be in the form of - a cons cell like =(height . FLOAT)= or =(height FLOAT)=, where FLOAT - is the given number. +[[#h:c8767172-bf11-4c96-81dc-e736c464fc9c][Make code syntax use the old alt-syntax style]]. -- The symbol of a weight attribute adjusts the font of the heading - accordingly, such as ~light~, ~semibold~, etc. Valid symbols are - defined in the variable ~modus-themes-weights~. The absence of a - weight means that bold will be used by virtue of inheriting the ~bold~ - face. +[[#h:943063da-7b27-4ba4-9afe-f8fe77652fd1][Make use of alternative styles for code syntax]]. -[[#h:2793a224-2109-4f61-a106-721c57c01375][Configure bold and italic faces]]. +#+begin_src emacs-lisp +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. -In case both a number and ~no-scale~ are in the list, the latter takes -precedence. If two numbers are specified, the first one is applied. +;; Yellow comments and green strings like older versions of the Modus +;; themes +(setq modus-themes-common-palette-overrides + '((comment yellow-cooler) + (string green-cooler))) -Example usage: +;; Faint yellow comments and a different shade of green for strings +(setq modus-themes-common-palette-overrides + '((comment yellow-faint) + (string green-warmer))) -#+begin_src emacs-lisp -(header-block . nil) -(header-block . (1.5)) -(header-block . (no-scale)) -(header-block . (variable-pitch 1.5)) -(header-block . (variable-pitch 1.5 semibold)) +;; Green comments and yellow strings, because now the user has the +;; freedom to do it +(setq modus-themes-common-palette-overrides + '((comment green) + (string yellow-cooler))) #+end_src -A ~header-date~ key covers date headings. Dates use only a foreground -color by default (a ~nil~ value), with weekdays and weekends having a -slight difference in hueness. The current date has an added gray -background. This key accepts a list of values that can include any of -the following properties: - -- ~grayscale~ to make weekdays use the main foreground color and - weekends a more subtle gray; - -- ~workaholic~ to make weekdays and weekends look the same in - terms of color; +**** Make code syntax use the old alt-syntax style +:PROPERTIES: +:CUSTOM_ID: h:c8767172-bf11-4c96-81dc-e736c464fc9c +:END: -- ~bold-today~ to apply a bold typographic weight to the current - date; +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). In +this section we show how to reproduce what previous versions of the +Modus themes provided as a stylistic alternative for code syntax. The +upside of using overrides for this purpose is that we can tweak the +style to our liking, but first let's start with its recreation: + +#+begin_src emacs-lisp +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. + + +;; The old "alt-syntax" +(setq modus-themes-common-palette-overrides + '((builtin magenta) + (comment fg-dim) + (constant magenta-cooler) + (docstring magenta-faint) + (docmarkup green-faint) + (fnname magenta-warmer) + (keyword cyan) + (preprocessor cyan-cooler) + (string red-cooler) + (type magenta-cooler) + (variable blue-warmer) + (rx-construct magenta-warmer) + (rx-backslash blue-cooler))) +#+end_src + +The "alt-syntax" could optionally use green strings and yellow +comments ([[#h:26f53daa-0065-48dc-88ab-6a718d16cd95][Make comments yellow and strings green]]): + +#+begin_src emacs-lisp +;; Same as above, but with yellow comments and green strings +(setq modus-themes-common-palette-overrides + '((builtin magenta) + (comment yellow-faint) + (constant magenta-cooler) + (docstring green-faint) + (docmarkup magenta-faint) + (fnname magenta-warmer) + (keyword cyan) + (preprocessor cyan-cooler) + (string green-cooler) + (type magenta-cooler) + (variable blue-warmer) + (rx-construct magenta-warmer) + (rx-backslash blue-cooler))) +#+end_src + +The standard "alt-syntax" has red strings. As such, it is interesting +to experiment with faintly red colored comments: + +#+begin_src emacs-lisp +;; Like the old "alt-syntax" but with faint red comments +(setq modus-themes-common-palette-overrides + '((builtin magenta) + (comment red-faint) + (constant magenta-cooler) + (docstring magenta-faint) + (docmarkup green-faint) + (fnname magenta-warmer) + (keyword cyan) + (preprocessor cyan-cooler) + (string red-cooler) + (type magenta-cooler) + (variable blue-warmer) + (rx-construct magenta-warmer) + (rx-backslash blue-cooler))) +#+end_src + +The user can always mix and match styles to their liking. + +[[#h:943063da-7b27-4ba4-9afe-f8fe77652fd1][Make use of alternative styles for code syntax]]. + +**** Make use of alternative styles for code syntax +:PROPERTIES: +:CUSTOM_ID: h:943063da-7b27-4ba4-9afe-f8fe77652fd1 +:END: -- ~bold-all~ to render all date headings in a bold weight; +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). The +idea here is to change how named colors are mapped to code syntax. +Each of the following snippets give the ~modus-themes~ a different +feel while editing code. + +Note that my ~modus-themes~ and ~ef-themes~ do not use the same +palettes, so some things are different. If you copy from the latter +to the former, double-check that the entries exist in the given Modus +theme palette. + +[[#h:26f53daa-0065-48dc-88ab-6a718d16cd95][Make comments yellow and strings green]]. + +[[*Make code syntax use the old alt-syntax style][Make code syntax use the old alt-syntax style]]. + +#+begin_src emacs-lisp +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. + + +;; Mimic `ef-night' theme (from my `ef-themes') for code syntax +;; highlighting, while still using the Modus colors (and other +;; mappings). +(setq modus-themes-common-palette-overrides + '((builtin green-cooler) + (comment yellow-faint) + (constant magenta-cooler) + (fnname cyan-cooler) + (keyword blue-warmer) + (preprocessor red-warmer) + (docstring cyan-faint) + (string blue-cooler) + (type magenta-cooler) + (variable cyan))) + +;; Mimic `ef-summer' theme (from my `ef-themes') for code syntax +;; highlighting, while still using the Modus colors (and other +;; mappings). +(setq modus-themes-common-palette-overrides + '((builtin magenta) + (comment yellow-faint) + (constant red-cooler) + (fnname magenta-warmer) + (keyword magenta-cooler) + (preprocessor green-warmer) + (docstring cyan-faint) + (string yellow-warmer) + (type cyan-warmer) + (variable blue-warmer))) + +;; Mimic `ef-bio' theme (from my `ef-themes') for code syntax +;; highlighting, while still using the Modus colors (and other +;; mappings). +(setq modus-themes-common-palette-overrides + '((builtin green) + (comment yellow-faint) + (constant blue) + (fnname green-warmer) + (keyword green-cooler) + (preprocessor green) + (docstring green-faint) + (string magenta-cooler) + (type cyan-warmer) + (variable blue-warmer))) + +;; Mimic `ef-trio-light' theme (from my `ef-themes') for code syntax +;; highlighting, while still using the Modus colors (and other +;; mappings). +(setq modus-themes-common-palette-overrides + '((builtin magenta-cooler) + (comment yellow-faint) + (constant magenta-warmer) + (fnname blue-warmer) + (keyword magenta) + (preprocessor red-cooler) + (docstring magenta-faint) + (string green-cooler) + (type cyan-cooler) + (variable cyan-warmer))) +#+end_src + +**** Make matching parenthesis more or less intense +:PROPERTIES: +:CUSTOM_ID: h:259cf8f5-48ec-4b13-8a69-5d6387094468 +:END: -- ~underline-today~ applies an underline to the current date while - removing the background it has by default; +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). In +this code block we show how to change the background of matching +delimiters when ~show-paren-mode~ is enabled. We also demonstrate how +to enable underlines for those highlights. -- A number as a floating point (e.g. 1.2) to set the height of the text - to that many times the default font height. The default is the same - as the base font height (the equivalent of 1.0). Instead of a - floating point, an acceptable value can be in the form of a cons cell - like =(height . FLOAT)= or =(height FLOAT)=, where FLOAT is the given - number. +#+begin_src emacs-lisp +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. -For example: +;; Change the background to a shade of magenta +(setq modus-themes-common-palette-overrides + '((bg-paren-match bg-magenta-intense))) -#+begin_src emacs-lisp -(header-date . nil) -(header-date . (workaholic)) -(header-date . (grayscale bold-all)) -(header-date . (grayscale workaholic)) -(header-date . (grayscale workaholic bold-today)) -(header-date . (grayscale workaholic bold-today scale-heading)) +;; Enable underlines by applying a color to them +(setq modus-themes-common-palette-overrides + '((bg-paren-match bg-magenta-intense) + (underline-paren-match fg-main))) #+end_src -An ~event~ key covers (i) headings with a plain time stamp that are -shown on the agenda, also known as events, (ii) entries imported from -the diary, and (iii) other items that derive from a symbolic expression -or sexp (phases of the moon, holidays, etc.). By default all those look -the same and have a subtle foreground color (the default is a ~nil~ value -or an empty list). This key accepts a list of properties. Those are: - -- ~accented~ applies an accent value to the event's foreground, - replacing the original gray. It makes all entries stand out more. -- ~italic~ adds a slant to the font's forms (italic or oblique forms, - depending on the typeface). -- ~varied~ differentiates between events with a plain time stamp and - entries that are generated from either the diary or a symbolic - expression. It generally puts more emphasis on events. When ~varied~ - is combined with ~accented~, it makes only events use an accent color, - while diary/sexp entries retain their original subtle foreground. - When ~varied~ is used in tandem with ~italic~, it applies a slant only - to diary and sexp entries, not events. And when ~varied~ is the sole - property passed to the ~event~ key, it has the same meaning as the - list (italic varied). The combination of ~varied~, ~accented~, - ~italic~ covers all of the aforementioned cases. +**** Make box buttons more or less gray +:PROPERTIES: +:CUSTOM_ID: h:4f6b6ca3-f5bb-4830-8312-baa232305360 +:END: -For example: +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). By +default, the boxed buttons that appear in {{{kbd(M-x customize)}}} and +related are distinct shades of gray. The following set of overrides +removes the gray from the active buttons and amplifies it for the +inactive ones. #+begin_src emacs-lisp -(event . nil) -(event . (italic)) -(event . (accented italic)) -(event . (accented italic varied)) +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. + +(setq modus-themes-common-palette-overrides + '((bg-button-active bg-main) + (fg-button-active fg-main) + (bg-button-inactive bg-inactive) + (fg-button-inactive "gray50"))) #+end_src -A ~scheduled~ key applies to tasks with a scheduled date. By default (a -~nil~ value), those use varying shades of yellow to denote (i) a past or -current date and (ii) a future date. Valid values are symbols: +**** Make TODO and DONE more or less intense +:PROPERTIES: +:CUSTOM_ID: h:b57bb50b-a863-4ea8-bb38-6de2275fa868 +:END: -- ~nil~ (default); -- ~uniform~ to make all scheduled dates the same color; -- ~rainbow~ to use contrasting colors for past, present, future - scheduled dates. +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). +Here we show how to affect just the =TODO= and =DONE= keywords that we +encounter in Org buffers. The idea is to make those pop out more or +to subdue them. -For example: +[[#h:11297984-85ea-4678-abe9-a73aeab4676a][Make headings more or less colorful]]. + +[[#h:bb5b396f-5532-4d52-ab13-149ca24854f1][Make inline code in prose use alternative styles]]. #+begin_src emacs-lisp -(scheduled . nil) -(scheduled . uniform) -(scheduled . rainbow) -#+end_src +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. -A ~habit~ key applies to the ~org-habit~ graph. All possible value are -passed as a symbol. Those are: - -- The default (~nil~) is meant to conform with the original aesthetic of - ~org-habit~. It employs all four color codes that correspond to the - org-habit states---clear, ready, alert, and overdue---while - distinguishing between their present and future variants. This - results in a total of eight colors in use: red, yellow, green, blue, - in tinted and shaded versions. They cover the full set of information - provided by the ~org-habit~ consistency graph. -- ~simplified~ is like the default except that it removes the dichotomy - between current and future variants by applying uniform color-coded - values. It applies a total of four colors: red, yellow, green, blue. - They produce a simplified consistency graph that is more legible (or - less busy) than the default. The intent is to shift focus towards the - distinction between the four states of a habit task, rather than each - state's present/future outlook. -- ~traffic-light~ further reduces the available colors to red, yellow, and - green. As in ~simplified~, present and future variants appear - uniformly, but differently from it, the ~clear~ state is rendered in a - green hue, instead of the original blue. This is meant to capture the - use-case where a habit task being too early is less important than it - being too late. The difference between ready and clear states is - attenuated by painting both of them using shades of green. This - option thus highlights the alert and overdue states. -- When ~modus-themes-deuteranopia~ is non-~nil~ the exact style of the habit - graph adapts to the needs of users with red-green color deficiency by - substituting every instance of green with blue or cyan (depending on - the specifics). - -[[#h:3ed03a48-20d8-4ce7-b214-0eb7e4c79abe][Option for red-green color deficiency or deuteranopia]]. +;; Increase intensity +(setq modus-themes-common-palette-overrides + '((prose-done green-intense) + (prose-todo red-intense))) -For example: +;; Tone down intensity +(setq modus-themes-common-palette-overrides + '((prose-done green-faint) ; OR replace `green-faint' with `olive' + (prose-todo red-faint))) ; OR replace `red-faint' with `rust' -#+begin_src emacs-lisp -(habit . nil) -(habit . simplified) -(habit . traffic-light) +;; Keep TODO at its default (so no override for it), but make DONE +;; gray. +(setq modus-themes-common-palette-overrides + '((prose-done fg-dim))) #+end_src -Putting it all together, the alist can look like this: - -#+begin_src emacs-lisp -'((header-block . (1.5 variable-pitch)) - (header-date . (grayscale workaholic bold-today)) - (event . (accented varied)) - (scheduled . uniform) - (habit . traffic-light)) - -;; Or else: -(setq modus-themes-org-agenda - '((header-block . (1.5 variable-pitch)) - (header-date . (grayscale workaholic bold-today)) - (event . (accented varied)) - (scheduled . uniform) - (habit . traffic-light))) -#+end_src +**** Make headings more or less colorful +:PROPERTIES: +:CUSTOM_ID: h:11297984-85ea-4678-abe9-a73aeab4676a +:END: -** Option for the headings' overall style -:properties: -:alt_title: Heading styles -:description: Choose among several styles, also per heading level -:custom_id: h:271eff19-97aa-4090-9415-a6463c2f9ae1 -:end: -#+vindex: modus-themes-headings +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). +Here we show how to alter the looks of headings, such as in Org mode. +Using overrides here offers far more flexibility than what we could +achieve with previous versions of the themes: the user can mix and +match styles at will. + +[[#h:b57bb50b-a863-4ea8-bb38-6de2275fa868][Make TODO and DONE more intense]]. + +#+begin_src emacs-lisp +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. + + +;; Apply more colorful foreground to some headings (headings 0-8). +;; Level 0 is for Org #+title and related. +(setq modus-themes-common-palette-overrides + '((fg-heading-1 blue-warmer) + (fg-heading-2 yellow-cooler) + (fg-heading-3 cyan-cooler))) + +;; Like the above, but with gradient colors +(setq modus-themes-common-palette-overrides + '((fg-heading-1 blue) + (fg-heading-2 cyan) + (fg-heading-3 green))) + +;; Add color to level 1 heading, but use the main foreground for +;; others +(setq modus-themes-common-palette-overrides + '((fg-heading-1 blue) + (fg-heading-2 fg-main) + (fg-heading-3 fg-main))) + +;; Apply colorful foreground, background, and overline (headings 0-8) +(setq modus-themes-common-palette-overrides + '((fg-heading-1 blue-warmer) + (bg-heading-1 bg-blue-nuanced) + (overline-heading-1 blue))) + +;; Apply gray scale foreground, background, and overline (headings 0-8) +(setq modus-themes-common-palette-overrides + '((fg-heading-1 fg-main) + (bg-heading-1 bg-dim) + (overline-heading-1 border))) +#+end_src + +**** Make Org agenda more or less colorful +:PROPERTIES: +:CUSTOM_ID: h:a5af0452-a50f-481d-bf60-d8143f98105f +:END: -Brief: Heading styles with optional list of values for levels 0-8. +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). +Here we provide three distinct code blocks. The first adds +alternative and more varied colors to the Org agenda (and related). +The second uses faint coloration. The third makes the agenda use +various shades of blue. Mix and match at will, while also combining +these styles with what we show in the other chapters with practical +stylistic variants. + +#+begin_src emacs-lisp +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. + +;; Make the Org agenda use alternative and varied colors. +(setq modus-themes-common-palette-overrides + '((date-common cyan) ; default value (for timestamps and more) + (date-deadline red-warmer) + (date-event magenta-warmer) + (date-holiday blue) ; for M-x calendar + (date-now yellow-warmer) + (date-scheduled magenta-cooler) + (date-weekday cyan-cooler) + (date-weekend blue-faint))) +#+end_src + +An example with faint coloration: + +#+begin_src emacs-lisp +;; Make the Org agenda use faint colors. +(setq modus-themes-common-palette-overrides + '((date-common cyan-faint) ; for timestamps and more + (date-deadline red-faint) + (date-event fg-alt) ; default + (date-holiday magenta) ; default (for M-x calendar) + (date-now fg-main) ; default + (date-scheduled yellow-faint) + (date-weekday fg-dim) + (date-weekend fg-dim))) +#+end_src + +A third example that makes the agenda more blue: + +#+begin_src emacs-lisp +;; Make the Org agenda use more blue instead of yellow and red. +(setq modus-themes-common-palette-overrides + '((date-common cyan) ; default value (for timestamps and more) + (date-deadline blue-cooler) + (date-event blue-faint) + (date-holiday blue) ; for M-x calendar + (date-now blue-faint) + (date-scheduled blue) + (date-weekday fg-main) + (date-weekend fg-dim))) +#+end_src + +**** Make inline code in prose use alternative styles +:PROPERTIES: +:CUSTOM_ID: h:bb5b396f-5532-4d52-ab13-149ca24854f1 +:END: -Symbol: ~modus-themes-headings~ (=alist= type, multiple properties) +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). In +the following code block we show how to affect constructs such as +Org's verbatim, code, and macro entries. We also provide mappings for +tables, property drawers, tags, and code block delimiters, though we +do not show every possible permutation. + +[[#h:b57bb50b-a863-4ea8-bb38-6de2275fa868][Make TODO and DONE more or less intense]]. + +#+begin_src emacs-lisp +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. + + +;; These are all the mappings at their default values for didactic +;; purposes +(setq modus-themes-common-palette-overrides + '((prose-block fg-dim) + (prose-code green-cooler) + (prose-done green) + (prose-macro magenta-cooler) + (prose-metadata fg-dim) + (prose-metadata-value fg-alt) + (prose-table fg-alt) + (prose-tag magenta-faint) + (prose-todo red) + (prose-verbatim magenta-warmer))) + +;; Make code block delimiters use a shade of red, tone down +;; =verbatim=, ~code~, and {{{macro}}}, and amplify the style of +;; property drawers +(setq modus-themes-common-palette-overrides + '((prose-block red-faint) + (prose-code fg-dim) + (prose-macro magenta-faint) + (prose-metadata cyan) + (prose-metadata-value green-warmer) + (prose-verbatim fg-dim))) + +;; Like the above but with more color variety for the inline code +;; elements +(setq modus-themes-common-palette-overrides + '((prose-block red-faint) + (prose-code blue-cooler) + (prose-macro yellow-warmer) + (prose-metadata cyan) + (prose-metadata-value green-warmer) + (prose-verbatim red-warmer))) +#+end_src + +**** Make mail citations and headers more or less colorful +:PROPERTIES: +:CUSTOM_ID: h:7da7a4ad-5d3a-4f11-9796-5a1abed0f0c4 +:END: -This is an alist that accepts a =(key . list-of-values)= combination. -The key is either a number, representing the heading's level (0-8) or t, -which pertains to the fallback style. +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). In +this section we show how to change the coloration of email message +headers and citations. Before we show the code, this is the anatomy +of a message: + +#+begin_example message +From: Protesilaos <info@protesilaos.com> +To: Modus-Themes Development <~protesilaos/modus-themes@lists.sr.ht> +Subject: Test subject +--- Headers above this line; message and citations below --- +This is some sample text + +> > Older quote +> Newer quote +#+end_example -Level 0 is a special heading: it is used for what counts as a document -title or equivalent, such as the =#+title= construct we find in Org -files. Levels 1-8 are regular headings. +We thus have the following: + +#+begin_src emacs-lisp +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. + + +;; Reduce the intensity of mail citations and headers +(setq modus-themes-common-palette-overrides + '((mail-cite-0 cyan-faint) + (mail-cite-1 yellow-faint) + (mail-cite-2 green-faint) + (mail-cite-3 red-faint) + (mail-part olive) + (mail-recipient indigo) + (mail-subject maroon) + (mail-other slate))) + +;; Make mail citations more intense; adjust the headers accordingly +(setq modus-themes-common-palette-overrides + '((mail-cite-0 blue) + (mail-cite-1 yellow) + (mail-cite-2 green) + (mail-cite-3 magenta) + (mail-part magenta-cooler) + (mail-recipient cyan) + (mail-subject red-warmer) + (mail-other cyan-cooler))) + +;; Make all citations faint and neutral; make most headers green but +;; use red for the subject lie so that it stands out +(setq modus-themes-common-palette-overrides + '((mail-cite-0 fg-dim) + (mail-cite-1 fg-alt) + (mail-cite-2 fg-dim) + (mail-cite-3 fg-alt) + (mail-part yellow-cooler) + (mail-recipient green-cooler) + (mail-subject red-cooler) + (mail-other green))) +#+end_src + +**** Make the region preserve text colors, plus other styles +:PROPERTIES: +:CUSTOM_ID: h:c8605d37-66e1-42aa-986e-d7514c3af6fe +:END: -The list of values covers symbols that refer to properties, as described -below. Here is a complete sample, followed by a presentation of all -available properties: +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). +Here we show how to make the region respect the underlying text colors +or how to make the background more/less intense while combining it +with an appropriate foreground value. #+begin_src emacs-lisp -(setq modus-themes-headings - '((1 . (background overline variable-pitch 1.5)) - (2 . (overline rainbow 1.3)) - (3 . (overline 1.1)) - (t . (monochrome)))) -#+end_src - -Properties: - -+ ~rainbow~ -+ ~overline~ -+ ~background~ -+ ~monochrome~ -+ A font weight, which must be supported by the underlying typeface: - - ~thin~ - - ~ultralight~ - - ~extralight~ - - ~light~ - - ~semilight~ - - ~regular~ - - ~medium~ - - ~semibold~ - - ~bold~ - - ~heavy~ - - ~extrabold~ - - ~ultrabold~ -+ ~no-bold~ (deprecated alias of a ~regular~ weight) -+ A floating point as a height multiple of the default or a cons cell in - the form of =(height . FLOAT)=. +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. -By default (a ~nil~ value for this variable), all headings have a bold -typographic weight and use a desaturated text color. - -A ~rainbow~ property makes the text color more saturated. -An ~overline~ property draws a line above the area of the heading. +;; A background with no specific foreground (use foreground of +;; underlying text) +(setq modus-themes-common-palette-overrides + '((bg-region bg-ochre) ; try to replace `bg-ochre' with `bg-lavender', `bg-sage' + (fg-region unspecified))) -A ~background~ property adds a subtle tinted color to the background of -the heading. +;; Subtle gray with a prominent blue foreground +(setq modus-themes-common-palette-overrides + '((bg-region bg-dim) + (fg-region blue-cooler))) -A ~monochrome~ property makes the heading the same as the base color, -which is that of the ~default~ face's foreground. When ~background~ is also -set, ~monochrome~ changes its color to gray. If both ~monochrome~ and -~rainbow~ are set, the former takes precedence. +;; Intense magenta background combined with the main foreground +(setq modus-themes-common-palette-overrides + '((bg-region bg-magenta-intense) + (fg-region fg-main))) +#+end_src -A ~variable-pitch~ property changes the font family of the heading to that -of the ~variable-pitch~ face (normally a proportionately spaced typeface). +**** Make mouse highlights more or less colorful +:PROPERTIES: +:CUSTOM_ID: h:b5cab69d-d7cb-451c-8ff9-1f545ceb6caf +:END: -The symbol of a weight attribute adjusts the font of the heading -accordingly, such as ~light~, ~semibold~, etc. Valid symbols are -defined in the variable ~modus-themes-weights~. The absence of a weight -means that bold will be used by virtue of inheriting the ~bold~ face. -For backward compatibility, the ~no-bold~ value is accepted, though -users are encouraged to specify a ~regular~ weight instead. +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). In +the following code block we show how to affect the semantic color +mapping that covers mouse hover effects and related highlights: -[[#h:2793a224-2109-4f61-a106-721c57c01375][Configure bold and italic faces]]. +#+begin_src emacs-lisp +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. -A number, expressed as a floating point (e.g. 1.5), adjusts the height -of the heading to that many times the base font size. The default -height is the same as 1.0, though it need not be explicitly stated. -Instead of a floating point, an acceptable value can be in the form of a -cons cell like =(height . FLOAT)= or =(height FLOAT)=, where FLOAT is -the given number. -Combinations of any of those properties are expressed as a list, like in -these examples: +;; Make the background an intense yellow +(setq modus-themes-common-palette-overrides + '((bg-hover bg-yellow-intense))) -#+begin_src emacs-lisp -(semibold) -(rainbow background) -(overline monochrome semibold 1.3) -(overline monochrome semibold (height 1.3)) ; same as above -(overline monochrome semibold (height . 1.3)) ; same as above +;; Make the background subtle green +(setq modus-themes-common-palette-overrides + '((bg-hover bg-green-subtle))) #+end_src -The order in which the properties are set is not significant. +**** Make language underlines less colorful +:PROPERTIES: +:CUSTOM_ID: h:03dbd5af-6bae-475e-85a2-cec189f69598 +:END: -In user configuration files the form may look like this: +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). +Here we show how to affect the color of the underlines that are used +by code linters and prose spell checkers. #+begin_src emacs-lisp -(setq modus-themes-headings - '((1 . (background overline rainbow 1.5)) - (2 . (background overline 1.3)) - (t . (overline semibold)))) -#+end_src +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. -When defining the styles per heading level, it is possible to pass a -non-~nil~ value (~t~) instead of a list of properties. This will retain the -original aesthetic for that level. For example: -#+begin_src emacs-lisp -(setq modus-themes-headings - '((1 . t) ; keep the default style - (2 . (background overline)) - (t . (rainbow)))) ; style for all other headings +;; Make the underlines less intense +(setq modus-themes-common-palette-overrides + '((underline-err red-faint) + (underline-warning yellow-faint) + (underline-note cyan-faint))) -(setq modus-themes-headings - '((1 . (background overline)) - (2 . (rainbow semibold)) - (t . t))) ; default style for all other levels +;; Change the color-coding of the underlines +(setq modus-themes-common-palette-overrides + '((underline-err yellow-intense) + (underline-warning magenta-intense) + (underline-note green-intense))) #+end_src -For Org users, the extent of the heading depends on the variable -~org-fontify-whole-heading-line~. This affects the ~overline~ and -~background~ properties. Depending on the version of Org, there may be -others, such as ~org-fontify-done-headline~. - -** Option for variable-pitch font in UI elements -:properties: -:alt_title: UI typeface -:description: Toggle the use of variable-pitch across the User Interface -:custom_id: h:16cf666c-5e65-424c-a855-7ea8a4a1fcac -:end: -#+vindex: modus-themes-variable-pitch-ui - -Brief: Toggle the use of proportionately spaced (~variable-pitch~) fonts -in the User Interface. +**** Make line numbers use alternative styles +:PROPERTIES: +:CUSTOM_ID: h:b6466f51-cb58-4007-9ebe-53a27af655c7 +:END: -Symbol: ~modus-themes-variable-pitch-ui~ (=boolean= type) +This is one of our practical examples to override the semantic colors +of the Modus themes ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][Stylistic variants using palette overrides]]). In +this section we show how to affect the ~display-line-numbers-mode~. -Possible values: +#+begin_src emacs-lisp +;; These overrides are common to all Modus themes. We also provide +;; theme-specific options, such as `modus-operandi-palette-overrides'. +;; +;; In general, the theme-specific overrides are better for overriding +;; color values, such as redefining what `blue-faint' looks like. The +;; common overrides are best used for changes to semantic color +;; mappings, as we show below. -1. ~nil~ (default) -2. ~t~ -This option concerns User Interface elements that are under the direct -control of Emacs. In particular: the mode line, header line, tab bar, -and tab line. +;; Make line numbers less intense +(setq modus-themes-common-palette-overrides + '((fg-line-number-inactive "gray50") + (fg-line-number-active fg-main) + (bg-line-number-inactive unspecified) + (bg-line-number-active unspecified))) -The default is to use the same font as the rest of Emacs, which usually -is a monospaced family. - -With a non-~nil~ value (~t~) apply a proportionately spaced typeface. This -is done by assigning the ~variable-pitch~ face to the relevant items. +;; Like the above, but use a shade of red for the current line number +(setq modus-themes-common-palette-overrides + '((fg-line-number-inactive "gray50") + (fg-line-number-active red-cooler) + (bg-line-number-inactive unspecified) + (bg-line-number-active unspecified))) -[[#h:defcf4fc-8fa8-4c29-b12e-7119582cc929][Font configurations for Org and others]]. +;; Make all numbers more intense, use a more pronounce gray +;; background, and make the current line have a colored background +(setq modus-themes-common-palette-overrides + '((fg-line-number-inactive fg-main) + (fg-line-number-active fg-main) + (bg-line-number-inactive bg-inactive) + (bg-line-number-active bg-cyan-intense))) +#+end_src * Advanced customization :properties: @@ -2220,7 +2193,7 @@ the background). It thus falls back to the closest approximation, which seldom is appropriate for the purposes of the Modus themes. In such a case, the user is expected to update their terminal's color -palette such as by adapting these resources: +palette such as by adapting these resources ([[#h:f4d4b71b-2ca5-4c3d-b0b4-9bfd7aa7fb4d][Preview theme colors]]): #+begin_src emacs-lisp ! Theme: modus-operandi @@ -2268,27 +2241,43 @@ xterm*color14: #6ae4b9 xterm*color15: #ffffff #+end_src -** Visualize the active Modus theme's palette +** Preview theme colors :properties: :custom_id: h:f4d4b71b-2ca5-4c3d-b0b4-9bfd7aa7fb4d :end: +#+cindex: Preview named colors or semantic color mappings + #+findex: modus-themes-list-colors #+findex: modus-themes-list-colors-current -#+cindex: Preview color values - The command ~modus-themes-list-colors~ prompts for a choice between -=modus-operandi= and =modus-vivendi= to produce a help buffer that shows a -preview of each variable in the given theme's color palette. The +=modus-operandi= and =modus-vivendi= to produce a help buffer that +shows a preview of the named colors in the given theme's palette. The command ~modus-themes-list-colors-current~ skips the prompt, using the current Modus theme. +When called with a prefix argument (=C-u= with the default key +bindings), these commands will show a preview of the palette's +semantic color mappings instead of the named colors. + +In this context, "named colors" are entries that associate a symbol to +a string color value, such as =(blue-warmer "#354fcf")=. Whereas +"semantic color mappings" associate a named color to a symbol, like +=(string blue-warmer)=, thus making the theme render all string +constructs in the =blue-warmer= color value ([[#h:34c7a691-19bb-4037-8d2f-67a07edab150][Option for palette overrides]]). + +#+findex: modus-themes-preview-colors +#+findex: modus-themes-preview-colors-current +Aliases for those commands are ~modus-themes-preview-colors~ and +~modus-themes-preview-colors-current~. + Each row shows a foreground and background coloration using the underlying value it references. For example a line with =#a60000= (a shade of red) will show red text followed by a stripe with that same color as a backdrop. -The name of the buffer describes the given Modus theme. It is thus -called =*modus-operandi-list-colors*= or =*modus-vivendi-list-colors*=. +The name of the buffer describes the given Modus theme and what the +contents are, such as =*modus-operandi-list-colors*= for named colors +and ==*modus-operandi-list-mappings*= for the semantic color mappings. ** Per-theme customization settings :properties: @@ -2306,12 +2295,12 @@ other). (defun my-demo-modus-operandi () (interactive) (setq modus-themes-bold-constructs t) ; ENABLE bold - (modus-themes-load-operandi)) + (modus-themes-load-theme 'modus-operandi)) (defun my-demo-modus-vivendi () (interactive) (setq modus-themes-bold-constructs nil) ; DISABLE bold - (modus-themes-load-vivendi)) + (modus-themes-load-theme 'modus-vivendi)) (defun my-demo-modus-themes-toggle () (if (eq (car custom-enabled-themes) 'modus-operandi) @@ -2325,231 +2314,103 @@ equivalent the themes provide. For a more elaborate design, it is better to inspect the source code of ~modus-themes-toggle~ and relevant functions. -** Case-by-case face specs using the themes' palette +** Use theme colors in code with modus-themes-with-colors :properties: -:custom_id: h:1487c631-f4fe-490d-8d58-d72ffa3bd474 +:custom_id: h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae :end: -#+findex: modus-themes-color -#+findex: modus-themes-color-alts -#+cindex: Extracting individual colors +#+cindex: Use colors from the palette anywhere -This section is about tweaking individual faces. If you plan to do -things at scale, consult the next section: [[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Set multiple faces]]. +Note that users most probably do not need the following. Just rely on +the comprehensive overrides we provide ([[#h:34c7a691-19bb-4037-8d2f-67a07edab150][Option for palette overrides]]). -We already covered in previous sections how to toggle between the themes -and how to configure options prior to loading. We also explained that -some of the functions made available to users will fire up a hook that -can be used to pass tweaks in the post-theme-load phase. - -Now assume you wish to change a single face, say, the ~cursor~. And you -would like to get the standard "blue" color value of the active Modus -theme, whether it is Modus Operandi or Modus Vivendi. To do that, you -can use the ~modus-themes-color~ function. It accepts a symbol that is -associated with a color in ~modus-themes-operandi-colors~ and -~modus-themes-vivendi-colors~. Like this: +#+findex: modus-themes-with-colors +Advanced users may want to apply colors from the palette of the active +Modus theme in their custom code. The ~modus-themes-with-colors~ +macro supplies those to any form called inside of it. For example: #+begin_src emacs-lisp -(modus-themes-color 'blue) +(modus-themes-with-colors + (list blue-warmer magenta-cooler fg-added warning variable fg-heading-4)) +;; => ("#354fcf" "#531ab6" "#005000" "#884900" "#005e8b" "#721045") #+end_src -The function always extracts the color value of the active Modus theme. +The above return value is for ~modus-operandi~ when that is the active +theme. Switching to another theme and evaluating this code anew will +give us the relevant results for that theme (remember that since +version 4, the Modus themes consist of six items ([[#h:f0f3dbcb-602d-40cf-b918-8f929c441baf][Overview]])). The +same with ~modus-vivendi~ as the active theme: #+begin_src emacs-lisp -(progn - (load-theme 'modus-operandi t) - (modus-themes-color 'blue)) ; "#0031a9" for `modus-operandi' - -(progn - (load-theme 'modus-vivendi t) - (modus-themes-color 'blue)) ; "#2fafff" for `modus-vivendi' +(modus-themes-with-colors + (list blue-warmer magenta-cooler fg-added warning variable fg-heading-4)) +;; => ("#79a8ff" "#b6a0ff" "#a0e0a0" "#fec43f" "#00d3d0" "#feacd0") #+end_src -Do {{{kbd(C-h v)}}} on the aforementioned variables to check all the available -symbols that can be passed to this function. Or simply invoke the -command ~modus-themes-list-colors~ to produce a buffer with a preview of -each entry in the palette. +The ~modus-themes-with-colors~ has access to the whole palette of the +active theme, meaning that it can instantiate both (i) named colors +like =blue-warmer= and (ii) semantic color mappings like =warning=. +We provide commands to inspect those ([[#h:f4d4b71b-2ca5-4c3d-b0b4-9bfd7aa7fb4d][Preview theme colors]]). -[[#h:f4d4b71b-2ca5-4c3d-b0b4-9bfd7aa7fb4d][Visualize the active Modus theme's palette]]. - -With that granted, let us expand the example to actually change the -~cursor~ face's background property. We employ the built-in function of -~set-face-attribute~: +Others sections in this manual show how to use the aforementioned +macro ([[#h:f4651d55-8c07-46aa-b52b-bed1e53463bb][Advanced customization]]). -#+begin_src emacs-lisp -(set-face-attribute 'cursor nil :background (modus-themes-color 'blue)) -#+end_src +** Add padding to mode line +:PROPERTIES: +:CUSTOM_ID: h:5a0c58cc-f97f-429c-be08-927b9fbb0a9c +:END: -If you evaluate this form, your cursor will become blue. But if you -change themes, such as with ~modus-themes-toggle~, your edits will be -lost, because the newly loaded theme will override the ~:background~ -attribute you had assigned to that face. +Emacs faces do not have a concept of "padding" for the space between +the text and its box boundaries. We can approximate the effect by +adding a =:box= attribute, making its border several pixels thick, and +using the mode line's background color for it. This way the thick +border will not stand out and will appear as a continuation of the +mode line. -For such changes to persist, we need to make them after loading the -theme. So we rely on ~modus-themes-after-load-theme-hook~, which gets -called from ~modus-themes-load-operandi~, ~modus-themes-load-vivendi~, as -well as the command ~modus-themes-toggle~. Here is a sample function that -tweaks two faces and then gets added to the hook: +[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Use theme colors in code with modus-themes-with-colors]]. #+begin_src emacs-lisp (defun my-modus-themes-custom-faces () - (set-face-attribute 'cursor nil :background (modus-themes-color 'blue)) - (set-face-attribute 'font-lock-type-face nil :foreground (modus-themes-color 'magenta-alt))) + (modus-themes-with-colors + (custom-set-faces + ;; Add "padding" to the mode lines + `(mode-line ((,c :box (:line-width 10 :color ,bg-mode-line-active)))) + `(mode-line-inactive ((,c :box (:line-width 10 :color ,bg-mode-line-inactive))))))) (add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-custom-faces) #+end_src -[[#h:86f6906b-f090-46cc-9816-1fe8aeb38776][A theme-agnostic hook for theme loading]]. - -Using this principle, it is possible to override the styles of faces -without having to find color values for each case. - -Another application is to control the precise weight for bold -constructs. This is particularly useful if your typeface has several -variants such as "heavy", "extrabold", "semibold". All you have to do -is edit the ~bold~ face. For example: - -#+begin_src emacs-lisp -(set-face-attribute 'bold nil :weight 'semibold) -#+end_src - -Remember to use the custom function and hook combo we demonstrated -above. Because the themes do not hard-wire a specific weight, this -simple form is enough to change the weight of all bold constructs -throughout the interface. - -Finally, there are cases where you want to tweak colors though wish to -apply different ones to each theme, say, a blue hue for Modus Operandi -and a shade of red for Modus Vivendi. To this end, we provide -~modus-themes-color-alts~ as a convenience function to save you from the -trouble of writing separate wrappers for each theme. It still returns a -single value by querying either of ~modus-themes-operandi-colors~ and -~modus-themes-vivendi-colors~, only here you pass the two keys you want, -first for ~modus-operandi~ then ~modus-vivendi~. - -Take the previous example with the ~cursor~ face: - -#+begin_src emacs-lisp -;; Blue for `modus-operandi' and red for `modus-vivendi' -(set-face-attribute 'cursor nil :background (modus-themes-color-alts 'blue 'red)) -#+end_src - -** Face specs at scale using the themes' palette -:properties: -:custom_id: h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae -:end: -#+findex: modus-themes-with-colors -#+cindex: Extracting colors en masse - -The examples here are for large scale operations. For simple, one-off -tweaks, you may prefer the approach documented in the previous section -([[#h:1487c631-f4fe-490d-8d58-d72ffa3bd474][Case-by-case face specs using the themes' palette]]). - -The ~modus-themes-with-colors~ macro lets you retrieve multiple color -values by employing the backquote/backtick and comma notation. The -values are stored in the alists ~modus-themes-operandi-colors~ and -~modus-themes-vivendi-colors~, while the macro always queries that of the -active Modus theme (preview the current palette with the command -~modus-themes-list-colors~). - -[[#h:f4d4b71b-2ca5-4c3d-b0b4-9bfd7aa7fb4d][Visualize the active Modus theme's palette]]. - -Here is an abstract example that just returns a list of color values -while ~modus-operandi~ is enabled: - -#+begin_src emacs-lisp -(modus-themes-with-colors - (list fg-main - blue-faint - magenta - magenta-alt-other - cyan-alt-other - fg-special-cold - blue-alt - magenta-faint - cyan - fg-main - green-faint - red-alt-faint - blue-alt-faint - fg-special-warm - cyan-alt - blue)) -;; => -;; ("#000000" "#002f88" "#721045" "#5317ac" -;; "#005a5f" "#093060" "#2544bb" "#752f50" -;; "#00538b" "#000000" "#104410" "#702f00" -;; "#003f78" "#5d3026" "#30517f" "#0031a9") -#+end_src - -Getting a list of colors may have its applications, though what you are -most likely interested in is how to use those variables to configure -several faces at once. To do so we can rely on the built-in -~custom-set-faces~ function, which sets face specifications for the -special ~user~ theme. That "theme" gets applied on top of regular themes -like ~modus-operandi~ and ~modus-vivendi~. - -This is how it works: - -#+begin_src emacs-lisp -(modus-themes-with-colors - (custom-set-faces - `(cursor ((,class :background ,blue))) - `(mode-line ((,class :background ,yellow-nuanced-bg - :foreground ,yellow-nuanced-fg))) - `(mode-line-inactive ((,class :background ,blue-nuanced-bg - :foreground ,blue-nuanced-fg))))) -#+end_src - -The above snippet will immediately refashion the faces it names once it -is evaluated. However, if you switch between the Modus themes, say, -from ~modus-operandi~ to ~modus-vivendi~, the colors will not get updated to -match those of the new theme. To make things work across the themes, we -need to employ the same technique we discussed in the previous section, -namely, to pass our changes at the post-theme-load phase via a hook. - -The themes provide the ~modus-themes-after-load-theme-hook~, which gets -called from ~modus-themes-load-operandi~, ~modus-themes-load-vivendi~, as -well as the command ~modus-themes-toggle~. With this knowledge, you can -wrap the macro in a function and then assign that function to the hook. -Thus: +The above has the effect of removing the border around the mode lines. +In older versions of the themes, we provided the option for a padded +mode line which could also have borders around it. Those were not +real border, however, but an underline and an overline. Adjusting the +above: #+begin_src emacs-lisp (defun my-modus-themes-custom-faces () (modus-themes-with-colors (custom-set-faces - `(cursor ((,class :background ,blue))) - `(mode-line ((,class :background ,yellow-nuanced-bg - :foreground ,yellow-nuanced-fg))) - `(mode-line-inactive ((,class :background ,blue-nuanced-bg - :foreground ,blue-nuanced-fg)))))) + ;; Add "padding" to the mode lines + `(mode-line ((,c :underline ,border-mode-line-active + :overline ,border-mode-line-active + :box (:line-width 10 :color ,bg-mode-line-active)))) + `(mode-line-inactive ((,c :underline ,border-mode-line-inactive + :overline ,border-mode-line-inactive + :box (:line-width 10 :color ,bg-mode-line-inactive))))))) + +;; ESSENTIAL to make the underline move to the bottom of the box: +(setq x-underline-at-descent-line t) (add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-custom-faces) #+end_src -[[#h:86f6906b-f090-46cc-9816-1fe8aeb38776][A theme-agnostic hook for theme loading]]. - -To discover the faces defined by all loaded libraries, you may do -{{{kbd(M-x list-faces-display)}}}. Be warned that when you ~:inherit~ a face -you are introducing an implicit dependency, so try to avoid doing so for -libraries other than the built-in {{{file(faces.el)}}} (or at least understand -that things may break if you inherit from a yet-to-be-loaded face). +The reason we no longer provide this option is because it depends on a +non-nil value for ~x-underline-at-descent-line~. That variable +affects ALL underlines, including those of links. The effect is +intrusive and looks awkard in prose. -Also bear in mind that these examples are meant to work with the Modus -themes. If you are cycling between multiple themes you may encounter -unforeseen issues, such as the colors of the Modus themes being applied -to a non-Modus item. - -Finally, note that you can still use other functions where those make -sense. For example, the ~modus-themes-color-alts~ that was discussed in -the previous section. Adapt the above example like this: - -#+begin_src emacs-lisp -... -(modus-themes-with-colors - (custom-set-faces - `(cursor ((,class :background ,(modus-themes-color-alts 'blue 'green)))) - ...)) -#+end_src +As such, the Modus themes no longer provide that option but instead +offer this piece of documentation to make the user fully aware of the +state of affairs. ** Remap face with local value :properties: @@ -2564,7 +2425,7 @@ activates ~hl-line-mode~, but we wish to keep it distinct from other buffers. This is where ~face-remap-add-relative~ can be applied and may be combined with ~modus-themes-with-colors~ to deliver consistent results. -[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Face specs at scale using the themes' palette]]. +[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Use theme colors in code with modus-themes-with-colors]]. In this example we will write a simple interactive function that adjusts the background color of the ~region~ face. This is the sample code: @@ -2572,12 +2433,12 @@ the background color of the ~region~ face. This is the sample code: #+begin_src emacs-lisp (defvar my-rainbow-region-colors (modus-themes-with-colors - `((red . ,red-subtle-bg) - (green . ,green-subtle-bg) - (yellow . ,yellow-subtle-bg) - (blue . ,blue-subtle-bg) - (magenta . ,magenta-subtle-bg) - (cyan . ,cyan-subtle-bg))) + `((red . ,bg-red-subtle) + (green . ,bg-green-subtle) + (yellow . ,bg-yellow-subtle) + (blue . ,bg-blue-subtle) + (magenta . ,bg-magenta-subtle) + (cyan . ,bg-cyan-subtle))) "Sample list of color values for `my-rainbow-region'.") (defun my-rainbow-region (color) @@ -2613,768 +2474,6 @@ Perhaps you may wish to generalize those findings in to a set of functions that also accept an arbitrary face. We shall leave the experimentation up to you. -** Cycle through arbitrary colors -:properties: -:custom_id: h:77dc4a30-b96a-4849-85a8-fee3c2995305 -:end: -#+cindex: Cycle colors - -Users may opt to customize individual faces of the themes to accommodate -their particular needs. One such case is with the color intensity of -comments, specifically the foreground of ~font-lock-comment-face~. The -Modus themes set that to a readable value, in accordance with their -accessibility objective, though users may prefer to lower the overall -contrast on an on-demand basis. - -One way to achieve this is to design a command that cycles through three -distinct levels of intensity, though the following can be adapted to any -kind of cyclic behavior, such as to switch between red, green, and blue. - -In the following example, we employ the ~modus-themes-color~ function -which reads a symbol that represents an entry in the active theme's -color palette ([[#h:1487c631-f4fe-490d-8d58-d72ffa3bd474][Case-by-case face specs using the themes' palette]]). -Those are stored in ~my-modus-themes-comment-colors~. - -#+begin_src emacs-lisp -(defvar my-modus-themes-comment-colors - ;; We are abusing the palette here, as those colors have their own - ;; purpose in the palette, so please ignore the semantics of their - ;; names. - '((low . bg-region) - (medium . bg-tab-inactive-alt) - (high . fg-alt)) - "Alist of levels of intensity mapped to color palette entries. -The entries are found in `modus-themes-operandi-colors' or -`modus-themes-vivendi-colors'.") - -(defvar my-modus-themes--adjust-comment-color-state nil - "The cyclic state of `my-modus-themes-adjust-comment-color'. -For internal use.") - -(defun my-modus-themes--comment-foreground (degree state) - "Set `font-lock-comment-face' foreground. -Use `my-modus-themes-comment-colors' to extract the color value -for each level of intensity. - -This is complementary to `my-modus-themes-adjust-comment-color'." - (let ((palette-colors my-modus-themes-comment-colors)) - (set-face-foreground - 'font-lock-comment-face - (modus-themes-color (alist-get degree palette-colors))) - (setq my-modus-themes--adjust-comment-color-state state) - (message "Comments are set to %s contrast" degree))) - -(defun my-modus-themes-adjust-comment-color () - "Cycle through levels of intensity for comments. -The levels are determined by `my-modus-themes-comment-colors'." - (interactive) - (pcase my-modus-themes--adjust-comment-color-state - ('nil - (my-modus-themes--comment-foreground 'low 1)) - (1 - (my-modus-themes--comment-foreground 'medium 2)) - (_ - (my-modus-themes--comment-foreground 'high nil)))) -#+end_src - -With the above, {{{kbd(M-x my-modus-themes-adjust-comment-color)}}} will cycle -through the three levels of intensity that have been specified. - -Another approach is to not read from the active theme's color palette -and instead provide explicit color values, either in hexadecimal RGB -notation (like =#123456=) or as the names that are displayed in the output -of {{{kbd(M-x list-colors-display)}}}. In this case, the alist with the -colors will have to account for the active theme, so as to set the -appropriate colors. While this introduces a bit more complexity, it -ultimately offers greater flexibility on the choice of colors for such a -niche functionality (so there is no need to abuse the palette of the -active Modus theme): - -#+begin_src emacs-lisp -(defvar my-modus-themes-comment-colors - '((light . ((low . "gray75") - (medium . "gray50") - (high . "#505050"))) ; the default for `modus-operandi' - - (dark . ((low . "gray25") - (medium . "gray50") - (high . "#a8a8a8")))) ; the default for `modus-vivendi' - "Alist of levels of intensity mapped to color values. -For such colors, consult the command `list-colors-display'. Pass -the name of a color or its hex value.") - -(defvar my-modus-themes--adjust-comment-color-state nil - "The cyclic state of `my-modus-themes-adjust-comment-color'. -For internal use.") - -(defun my-modus-themes--comment-foreground (degree state) - "Set `font-lock-comment-face' foreground. -Use `my-modus-themes-comment-colors' to extract the color value -for each level of intensity. - -This is complementary to `my-modus-themes-adjust-comment-color'." - (let* ((colors my-modus-themes-comment-colors) - (levels (pcase (car custom-enabled-themes) - ('modus-operandi (alist-get 'light colors)) - ('modus-vivendi (alist-get 'dark colors))))) - (set-face-foreground - 'font-lock-comment-face - (alist-get degree levels)) - (setq my-modus-themes--adjust-comment-color-state state) - (message "Comments are set to %s contrast" degree))) - -(defun my-modus-themes-adjust-comment-color () - "Cycle through levels of intensity for comments. -The levels are determined by `my-modus-themes-comment-colors'." - (interactive) - (pcase my-modus-themes--adjust-comment-color-state - ('nil - (my-modus-themes--comment-foreground 'low 1)) - (1 - (my-modus-themes--comment-foreground 'medium 2)) - (_ - (my-modus-themes--comment-foreground 'high nil)))) -#+end_src - -The effect of the above configurations on ~font-lock-comment-face~ is -global. To make it buffer-local, one must tweak the code to employ the -function ~face-remap-add-relative~ ([[#h:7a93cb6f-4eca-4d56-a85c-9dcd813d6b0f][Remap face with local value]]). - -So this form in ~my-modus-themes--comment-foreground~: - -#+begin_src emacs-lisp -;; example 1 -(... - (set-face-foreground - 'font-lock-comment-face - (modus-themes-color (alist-get degree palette-colors))) - ...) - -;; example 2 -(... - (set-face-foreground - 'font-lock-comment-face - (alist-get degree levels)) - ...) -#+end_src - -Must become this: - -#+begin_src emacs-lisp -;; example 1 -(... - (face-remap-add-relative - 'font-lock-comment-face - `(:foreground ,(modus-themes-color (alist-get degree palette-colors)))) - ...) - -;; example 2 -(... - (face-remap-add-relative - 'font-lock-comment-face - `(:foreground ,(alist-get degree levels))) - ...) -#+end_src - -** Override colors -:properties: -:custom_id: h:307d95dd-8dbd-4ece-a543-10ae86f155a6 -:end: -#+vindex: modus-themes-operandi-color-overrides -#+vindex: modus-themes-vivendi-color-overrides -#+cindex: Change a theme's colors - -The themes provide a mechanism for overriding their color values. This -is controlled by the variables ~modus-themes-operandi-color-overrides~ and -~modus-themes-vivendi-color-overrides~, which are alists that should -mirror a subset of the associations in ~modus-themes-operandi-colors~ and -~modus-themes-vivendi-colors~ respectively. As with all customizations, -overriding must be done before loading the affected theme. - -[[#h:f4d4b71b-2ca5-4c3d-b0b4-9bfd7aa7fb4d][Visualize the active Modus theme's palette]]. - -Let us approach the present topic one step at a time. Here is a -simplified excerpt of the default palette for Modus Operandi with some -basic background values that apply to buffers and the mode line -(remember to inspect the actual value to find out all the associations -that can be overridden): - -#+begin_src emacs-lisp -(defconst modus-themes-operandi-colors - '((bg-main . "#ffffff") - (bg-dim . "#f8f8f8") - (bg-alt . "#f0f0f0") - (bg-active . "#d7d7d7") - (bg-inactive . "#efefef"))) -#+end_src - -As one can tell, we bind a key to a hexadecimal RGB color value. Now -say we wish to override those specific values and have our changes -propagate to all faces that use those keys. We could write something -like this, which adds a subtle ocher tint: - -#+begin_src emacs-lisp -(setq modus-themes-operandi-color-overrides - '((bg-main . "#fefcf4") - (bg-dim . "#faf6ef") - (bg-alt . "#f7efe5") - (bg-active . "#e8dfd1") - (bg-inactive . "#f6ece5"))) -#+end_src - -Once this is evaluated, any subsequent loading of ~modus-operandi~ will -use those values instead of the defaults. No further intervention is -required. - -To reset the changes, we apply this and reload the theme: - -#+begin_src emacs-lisp -(setq modus-themes-operandi-color-overrides nil) -#+end_src - -Users who wish to leverage such a mechanism can opt to implement it -on-demand by means of a global minor mode. The following snippet covers -both themes and expands to some more associations in the palette: - -#+begin_src emacs-lisp -(define-minor-mode my-modus-themes-tinted - "Tweak some Modus themes colors." - :init-value nil - :global t - (if my-modus-themes-tinted - (setq modus-themes-operandi-color-overrides - '((bg-main . "#fefcf4") - (bg-dim . "#faf6ef") - (bg-alt . "#f7efe5") - (bg-hl-line . "#f4f0e3") - (bg-active . "#e8dfd1") - (bg-inactive . "#f6ece5") - (bg-region . "#c6bab1") - (bg-header . "#ede3e0") - (bg-tab-active . "#fdf6eb") - (bg-tab-inactive . "#c8bab8")) - modus-themes-vivendi-color-overrides - '((bg-main . "#100b17") - (bg-dim . "#161129") - (bg-alt . "#181732") - (bg-hl-line . "#191628") - (bg-active . "#282e46") - (bg-inactive . "#1a1e39") - (bg-region . "#393a53") - (bg-header . "#202037") - (bg-tab-active . "#120f18") - (bg-tab-inactive . "#3a3a5a"))) - (setq modus-themes-operandi-color-overrides nil - modus-themes-vivendi-color-overrides nil))) -#+end_src - -A more neutral style for ~modus-themes-operandi-color-overrides~ can -look like this: - -#+begin_src emacs-lisp -'((bg-main . "#f7f7f7") - (bg-dim . "#f2f2f2") - (bg-alt . "#e8e8e8") - (bg-hl-line . "#eaeaef") - (bg-active . "#e0e0e0") - (bg-inactive . "#e6e6e6") - (bg-region . "#b5b5b5") - (bg-header . "#e4e4e4") - (bg-tab-active . "#f5f5f5") - (bg-tab-inactive . "#c0c0c0")) -#+end_src - -With those in place, one can use {{{kbd(M-x my-modus-themes-tinted)}}} -and then load the Modus theme of their choice. The new palette subset -will come into effect: subtle ocher tints (or shades of gray) for Modus -Operandi and night sky blue shades for Modus Vivendi. Switching between -the two themes, such as with {{{kbd(M-x modus-themes-toggle)}}} will -also use the overrides. - -Given that this is a user-level customization, one is free to implement -whatever color values they desire, even if the possible combinations -fall below the minimum 7:1 contrast ratio that governs the design of the -themes (the WCAG AAA legibility standard). Alternatively, this can also -be done programmatically ([[#h:4589acdc-2505-41fc-9f5e-699cfc45ab00][Override color saturation]]). - -The above are expanded into a fully fledged derivative elsewhere in this -document ([[#h:736c0ff5-8c9c-4565-82cf-989e57d07d4a][Override colors completely]]). - -For manual interventions it is advised to inspect the source code of -~modus-themes-operandi-colors~ and ~modus-themes-vivendi-colors~ for the -inline commentary: it explains what the intended use of each palette -subset is. - -Furthermore, users may benefit from the ~modus-themes-contrast~ function -that we provide: [[#h:02e25930-e71a-493d-828a-8907fc80f874][test color combinations]]. It measures the contrast -ratio between two color values, so it can help in overriding the palette -(or a subset thereof) without making the end result inaccessible. - -** Override color saturation -:properties: -:custom_id: h:4589acdc-2505-41fc-9f5e-699cfc45ab00 -:end: -#+cindex: Change a theme's color saturation - -In the previous section we documented how one can override color values -manually ([[#h:307d95dd-8dbd-4ece-a543-10ae86f155a6][Override colors]]). Here we use a programmatic approach which -leverages the built-in ~color-saturate-name~ function to adjust the -saturation of all color values used by the active Modus theme. Our goal -is to prepare a counterpart of the active theme's palette that holds -modified color values, adjusted for a percent change in saturation. A -positive number amplifies the effect, while a negative one will move -towards a grayscale spectrum. - -We start with a function that can be either called from Lisp or invoked -interactively. In the former scenario, we pass to it the rate of change -we want. While in the latter, a minibuffer prompt asks for a number to -apply the desired effect. In either case, we intend to assign anew the -value of ~modus-themes-operandi-color-overrides~ (light theme) and the -same for ~modus-themes-vivendi-color-overrides~ (dark theme). - -#+begin_src emacs-lisp -(defun my-modus-themes-saturate (percent) - "Saturate current Modus theme palette overrides by PERCENT." - (interactive - (list (read-number "Saturation by percent: "))) - (let* ((theme (modus-themes--current-theme)) - (palette (pcase theme - ('modus-operandi modus-themes-operandi-colors) - ('modus-vivendi modus-themes-vivendi-colors) - (_ (error "No Modus theme is active")))) - (overrides (pcase theme - ('modus-operandi 'modus-themes-operandi-color-overrides) - ('modus-vivendi 'modus-themes-vivendi-color-overrides) - (_ (error "No Modus theme is active"))))) - (let (name cons colors) - (dolist (cons palette) - (setq name (color-saturate-name (cdr cons) percent)) - (setq name (format "%s" name)) - (setq cons `(,(car cons) . ,name)) - (push cons colors)) - (set overrides colors)) - (pcase theme - ('modus-operandi (modus-themes-load-operandi)) - ('modus-vivendi (modus-themes-load-vivendi))))) - -;; sample Elisp calls (or call `my-modus-themes-saturate' interactively) -(my-modus-themes-saturate 50) -(my-modus-themes-saturate -75) -#+end_src - -Using the above has an immediate effect, as it reloads the active Modus -theme. - -The =my-modus-themes-saturate= function stores new color values in the -variables ~modus-themes-operandi-color-overrides~ and -~modus-themes-vivendi-color-overrides~, meaning that it undoes changes -implemented by the user on individual colors. To have both automatic -saturation adjustment across the board and retain per-case edits to the -palette, some tweaks to the above function are required. For example: - -#+begin_src emacs-lisp -(defvar my-modus-themes-vivendi-extra-color-overrides - '((fg-main . "#ead0c0") - (bg-main . "#050515")) - "My bespoke colors for `modus-vivendi'.") - -(defvar my-modus-themes-operandi-extra-color-overrides - '((fg-main . "#1a1a1a") - (bg-main . "#fefcf4")) - "My bespoke colors for `modus-operandi'.") - -(defun my-modus-themes-saturate (percent) - "Saturate current Modus theme palette overrides by PERCENT. -Preserve the color values stored in -`my-modus-themes-operandi-extra-color-overrides', -`my-modus-themes-vivendi-extra-color-overrides'." - (interactive - (list (read-number "Saturation by percent: "))) - (let* ((theme (modus-themes--current-theme)) - (palette (pcase theme - ('modus-operandi modus-themes-operandi-colors) - ('modus-vivendi modus-themes-vivendi-colors) - (_ (error "No Modus theme is active")))) - (overrides (pcase theme - ('modus-operandi 'modus-themes-operandi-color-overrides) - ('modus-vivendi 'modus-themes-vivendi-color-overrides) - (_ (error "No Modus theme is active")))) - (extra-overrides (pcase theme - ('modus-operandi my-modus-themes-operandi-extra-color-overrides) - ('modus-vivendi my-modus-themes-vivendi-extra-color-overrides) - (_ (error "No Modus theme is active"))))) - (let (name cons colors) - (dolist (cons palette) - (setq name (color-saturate-name (cdr cons) percent)) - (setq name (format "%s" name)) - (setq cons `(,(car cons) . ,name)) - (push cons colors)) - (set overrides (append extra-overrides colors))) - (pcase theme - ('modus-operandi (modus-themes-load-operandi)) - ('modus-vivendi (modus-themes-load-vivendi))))) -#+end_src - -To disable the effect, one must reset the aforementioned variables of -the themes to ~nil~. Or specify a command for it, such as by taking -inspiration from the ~modus-themes-toggle~ we already provide: - -#+begin_src emacs-lisp -(defun my-modus-themes-revert-overrides () - "Reset palette overrides and reload active Modus theme." - (interactive) - (setq modus-themes-operandi-color-overrides nil - modus-themes-vivendi-color-overrides nil) - (pcase (modus-themes--current-theme) - ('modus-operandi (modus-themes-load-operandi)) - ('modus-vivendi (modus-themes-load-vivendi)))) -#+end_src - -** Override colors through blending -:properties: -:custom_id: h:80c326bf-fe32-47b2-8c59-58022256fd6e -:end: -#+cindex: Change theme colors through blending - -This is yet another method of overriding color values. - -[[#h:307d95dd-8dbd-4ece-a543-10ae86f155a6][Override colors]]. - -[[#h:4589acdc-2505-41fc-9f5e-699cfc45ab00][Override color saturation]]. - -Building on ideas and concepts from the previous sections, this method -blends the entire palette at once with the chosen colors. The function -~my-modus-themes-interpolate~ blends two colors, taking a value from the -themes and mixing it with a user-defined color to arrive at a midpoint. -This scales to all background and foreground colors with the help of the -~my-modus-themes-tint-palette~ function. - -#+begin_src emacs-lisp -(setq my-modus-operandi-bg-blend "#fbf1c7" - my-modus-operandi-fg-blend "#3a6084" - my-modus-vivendi-bg-blend "#3a4042" - my-modus-vivendi-fg-blend "#d7b765") - -;; Adapted from the `kurecolor-interpolate' function of kurecolor.el -(defun my-modus-themes-interpolate (color1 color2) - (cl-destructuring-bind (r g b) - (mapcar #'(lambda (n) (* (/ n 2) 255.0)) - (cl-mapcar '+ (color-name-to-rgb color1) (color-name-to-rgb color2))) - (format "#%02X%02X%02X" r g b))) - -(defun my-modus-themes-tint-palette (palette bg-blend fg-blend) - "Modify Modus PALETTE programmatically and return a new palette. -Blend background colors with BG-BLEND and foreground colors with FG-BLEND." - (let (name cons colors) - (dolist (cons palette) - (let ((blend (if (string-match "bg" (symbol-name (car cons))) - bg-blend - fg-blend))) - (setq name (my-modus-themes-interpolate (cdr cons) blend))) - (setq name (format "%s" name)) - (setq cons `(,(car cons) . ,name)) - (push cons colors)) - colors)) - -(define-minor-mode modus-themes-tinted-mode - "Tweak some Modus themes colors." - :init-value nil - :global t - (if modus-themes-tinted-mode - (setq modus-themes-operandi-color-overrides - (my-modus-themes-tint-palette modus-themes-operandi-colors - my-modus-operandi-bg-blend - my-modus-operandi-fg-blend) - modus-themes-vivendi-color-overrides - (my-modus-themes-tint-palette modus-themes-vivendi-colors - my-modus-vivendi-bg-blend - my-modus-vivendi-fg-blend)) - (setq modus-themes-operandi-color-overrides nil - modus-themes-vivendi-color-overrides nil))) - -(modus-themes-tinted-mode 1) -#+end_src - -** Override colors completely -:PROPERTIES: -:CUSTOM_ID: h:736c0ff5-8c9c-4565-82cf-989e57d07d4a -:END: - -Based on the ideas we have already covered in these sections, the -following code block provides a complete, bespoke pair of color palettes -which override the defaults. They are implemented as a minor mode, as -explained before ([[#h:307d95dd-8dbd-4ece-a543-10ae86f155a6][Override colors]]). We call them "Summertime" for -convenience. - -#+begin_src emacs-lisp -;; Read the relevant blog post: -;; <https://protesilaos.com/codelog/2022-07-26-modus-themes-color-override-demo/> -(define-minor-mode modus-themes-summertime - "Refashion the Modus themes by overriding their colors. - -This is a complete technology demonstration to show how to -manually override the colors of the Modus themes. I have taken -good care of those overrides to make them work as a fully fledged -color scheme that is compatible with all user options of the -Modus themes. - -These overrides are usable by those who (i) like something more -fancy than the comparatively austere looks of the Modus themes, -and (ii) can cope with a lower contrast ratio. - -The overrides are set up as a minor mode, so that the user can -activate the effect on demand. Those who want to load the -overrides at all times can either add them directly to their -configuration or enable `modus-themes-summertime' BEFORE loading -either of the Modus themes (if the overrides are evaluated after -the theme, the theme must be reloaded). - -Remember that all changes to theme-related variables require a -reload of the theme to take effect (the Modus themes have lots of -user options, apart from those overrides). - -The `modus-themes-summertime' IS NOT an official extension to the -Modus themes and DOES NOT comply with its lofty accessibility -standards. It is included in the official manual as guidance for -those who want to make use of the color overriding facility we -provide." - :init-value nil - :global t - (if modus-themes-summertime - (setq modus-themes-operandi-color-overrides - '((bg-main . "#fff0f2") - (bg-dim . "#fbe6ef") - (bg-alt . "#f5dae6") - (bg-hl-line . "#fad8e3") - (bg-active . "#efcadf") - (bg-inactive . "#f3ddef") - (bg-active-accent . "#ffbbef") - (bg-region . "#dfc5d1") - (bg-region-accent . "#efbfef") - (bg-region-accent-subtle . "#ffd6ef") - (bg-header . "#edd3e0") - (bg-tab-active . "#ffeff2") - (bg-tab-inactive . "#f8d3ef") - (bg-tab-inactive-accent . "#ffd9f5") - (bg-tab-inactive-alt . "#e5c0d5") - (bg-tab-inactive-alt-accent . "#f3cce0") - (fg-main . "#543f78") - (fg-dim . "#5f476f") - (fg-alt . "#7f6f99") - (fg-unfocused . "#8f6f9f") - (fg-active . "#563068") - (fg-inactive . "#8a5698") - (fg-docstring . "#5f5fa7") - (fg-comment-yellow . "#a9534f") - (fg-escape-char-construct . "#8b207f") - (fg-escape-char-backslash . "#a06d00") - (bg-special-cold . "#d3e0f4") - (bg-special-faint-cold . "#e0efff") - (bg-special-mild . "#c4ede0") - (bg-special-faint-mild . "#e0f0ea") - (bg-special-warm . "#efd0c4") - (bg-special-faint-warm . "#ffe4da") - (bg-special-calm . "#f0d3ea") - (bg-special-faint-calm . "#fadff9") - (fg-special-cold . "#405fb8") - (fg-special-mild . "#407f74") - (fg-special-warm . "#9d6f4f") - (fg-special-calm . "#af509f") - (bg-completion . "#ffc5e5") - (bg-completion-subtle . "#f7cfef") - (red . "#ed2f44") - (red-alt . "#e0403d") - (red-alt-other . "#e04059") - (red-faint . "#ed4f44") - (red-alt-faint . "#e0603d") - (red-alt-other-faint . "#e06059") - (green . "#217a3c") - (green-alt . "#417a1c") - (green-alt-other . "#006f3c") - (green-faint . "#318a4c") - (green-alt-faint . "#518a2c") - (green-alt-other-faint . "#20885c") - (yellow . "#b06202") - (yellow-alt . "#a95642") - (yellow-alt-other . "#a06f42") - (yellow-faint . "#b07232") - (yellow-alt-faint . "#a96642") - (yellow-alt-other-faint . "#a08042") - (blue . "#275ccf") - (blue-alt . "#475cc0") - (blue-alt-other . "#3340ef") - (blue-faint . "#476ce0") - (blue-alt-faint . "#575ccf") - (blue-alt-other-faint . "#3f60d7") - (magenta . "#bf317f") - (magenta-alt . "#d033c0") - (magenta-alt-other . "#844fe4") - (magenta-faint . "#bf517f") - (magenta-alt-faint . "#d053c0") - (magenta-alt-other-faint . "#846fe4") - (cyan . "#007a9f") - (cyan-alt . "#3f709f") - (cyan-alt-other . "#107f7f") - (cyan-faint . "#108aaf") - (cyan-alt-faint . "#3f80af") - (cyan-alt-other-faint . "#3088af") - (red-active . "#cd2f44") - (green-active . "#116a6c") - (yellow-active . "#993602") - (blue-active . "#475ccf") - (magenta-active . "#7f2ccf") - (cyan-active . "#007a8f") - (red-nuanced-bg . "#ffdbd0") - (red-nuanced-fg . "#ed6f74") - (green-nuanced-bg . "#dcf0dd") - (green-nuanced-fg . "#3f9a4c") - (yellow-nuanced-bg . "#fff3aa") - (yellow-nuanced-fg . "#b47232") - (blue-nuanced-bg . "#e3e3ff") - (blue-nuanced-fg . "#201f6f") - (magenta-nuanced-bg . "#fdd0ff") - (magenta-nuanced-fg . "#c0527f") - (cyan-nuanced-bg . "#dbefff") - (cyan-nuanced-fg . "#0f3f60") - (bg-diff-heading . "#b7cfe0") - (fg-diff-heading . "#041645") - (bg-diff-added . "#d6f0d6") - (fg-diff-added . "#004520") - (bg-diff-changed . "#fcefcf") - (fg-diff-changed . "#524200") - (bg-diff-removed . "#ffe0ef") - (fg-diff-removed . "#891626") - (bg-diff-refine-added . "#84cfa4") - (fg-diff-refine-added . "#002a00") - (bg-diff-refine-changed . "#cccf8f") - (fg-diff-refine-changed . "#302010") - (bg-diff-refine-removed . "#da92b0") - (fg-diff-refine-removed . "#500010") - (bg-diff-focus-added . "#a6e5c6") - (fg-diff-focus-added . "#002c00") - (bg-diff-focus-changed . "#ecdfbf") - (fg-diff-focus-changed . "#392900") - (bg-diff-focus-removed . "#efbbcf") - (fg-diff-focus-removed . "#5a0010")) - modus-themes-vivendi-color-overrides - '((bg-main . "#25152a") - (bg-dim . "#2a1930") - (bg-alt . "#382443") - (bg-hl-line . "#332650") - (bg-active . "#463358") - (bg-inactive . "#2d1f3a") - (bg-active-accent . "#50308f") - (bg-region . "#5d4a67") - (bg-region-accent . "#60509f") - (bg-region-accent-subtle . "#3f285f") - (bg-header . "#3a2543") - (bg-tab-active . "#26162f") - (bg-tab-inactive . "#362647") - (bg-tab-inactive-accent . "#36265a") - (bg-tab-inactive-alt . "#3e2f5a") - (bg-tab-inactive-alt-accent . "#3e2f6f") - (fg-main . "#debfe0") - (fg-dim . "#d0b0da") - (fg-alt . "#ae85af") - (fg-unfocused . "#8e7f9f") - (fg-active . "#cfbfef") - (fg-inactive . "#b0a0c0") - (fg-docstring . "#c8d9f7") - (fg-comment-yellow . "#cf9a70") - (fg-escape-char-construct . "#ff75aa") - (fg-escape-char-backslash . "#dbab40") - (bg-special-cold . "#2a3f58") - (bg-special-faint-cold . "#1e283f") - (bg-special-mild . "#0f3f31") - (bg-special-faint-mild . "#0f281f") - (bg-special-warm . "#44331f") - (bg-special-faint-warm . "#372213") - (bg-special-calm . "#4a314f") - (bg-special-faint-calm . "#3a223f") - (fg-special-cold . "#c0b0ff") - (fg-special-mild . "#bfe0cf") - (fg-special-warm . "#edc0a6") - (fg-special-calm . "#ff9fdf") - (bg-completion . "#502d70") - (bg-completion-subtle . "#451d65") - (red . "#ff5f6f") - (red-alt . "#ff8f6d") - (red-alt-other . "#ff6f9d") - (red-faint . "#ffa0a0") - (red-alt-faint . "#f5aa80") - (red-alt-other-faint . "#ff9fbf") - (green . "#51ca5c") - (green-alt . "#71ca3c") - (green-alt-other . "#51ca9c") - (green-faint . "#78bf78") - (green-alt-faint . "#99b56f") - (green-alt-other-faint . "#88bf99") - (yellow . "#f0b262") - (yellow-alt . "#f0e242") - (yellow-alt-other . "#d0a272") - (yellow-faint . "#d2b580") - (yellow-alt-faint . "#cabf77") - (yellow-alt-other-faint . "#d0ba95") - (blue . "#778cff") - (blue-alt . "#8f90ff") - (blue-alt-other . "#8380ff") - (blue-faint . "#82b0ec") - (blue-alt-faint . "#a0acef") - (blue-alt-other-faint . "#80b2f0") - (magenta . "#ff70cf") - (magenta-alt . "#ff77f0") - (magenta-alt-other . "#ca7fff") - (magenta-faint . "#e0b2d6") - (magenta-alt-faint . "#ef9fe4") - (magenta-alt-other-faint . "#cfa6ff") - (cyan . "#30cacf") - (cyan-alt . "#60caff") - (cyan-alt-other . "#40b79f") - (cyan-faint . "#90c4ed") - (cyan-alt-faint . "#a0bfdf") - (cyan-alt-other-faint . "#a4d0bb") - (red-active . "#ff6059") - (green-active . "#64dc64") - (yellow-active . "#ffac80") - (blue-active . "#4fafff") - (magenta-active . "#cf88ff") - (cyan-active . "#50d3d0") - (red-nuanced-bg . "#440a1f") - (red-nuanced-fg . "#ffcccc") - (green-nuanced-bg . "#002904") - (green-nuanced-fg . "#b8e2b8") - (yellow-nuanced-bg . "#422000") - (yellow-nuanced-fg . "#dfdfb0") - (blue-nuanced-bg . "#1f1f5f") - (blue-nuanced-fg . "#bfd9ff") - (magenta-nuanced-bg . "#431641") - (magenta-nuanced-fg . "#e5cfef") - (cyan-nuanced-bg . "#042f49") - (cyan-nuanced-fg . "#a8e5e5") - (bg-diff-heading . "#304466") - (fg-diff-heading . "#dae7ff") - (bg-diff-added . "#0a383a") - (fg-diff-added . "#94ba94") - (bg-diff-changed . "#2a2000") - (fg-diff-changed . "#b0ba9f") - (bg-diff-removed . "#50163f") - (fg-diff-removed . "#c6adaa") - (bg-diff-refine-added . "#006a46") - (fg-diff-refine-added . "#e0f6e0") - (bg-diff-refine-changed . "#585800") - (fg-diff-refine-changed . "#ffffcc") - (bg-diff-refine-removed . "#952838") - (fg-diff-refine-removed . "#ffd9eb") - (bg-diff-focus-added . "#1d4c3f") - (fg-diff-focus-added . "#b4dfb4") - (bg-diff-focus-changed . "#424200") - (fg-diff-focus-changed . "#d0daaf") - (bg-diff-focus-removed . "#6f0f39") - (fg-diff-focus-removed . "#eebdba"))) - (setq modus-themes-operandi-color-overrides nil - modus-themes-vivendi-color-overrides nil))) -#+end_src - ** Font configurations for Org and others :properties: :custom_id: h:defcf4fc-8fa8-4c29-b12e-7119582cc929 @@ -3400,8 +2499,8 @@ the ~variable-pitch~ (proportional spacing) and ~fixed-pitch~ (monospaced) faces respectively. It may also be convenient to set your main typeface by configuring the ~default~ face the same way. -[ The =fontaine= package on GNU ELPA (by the author of the modus-themes) - is designed to handle this case. ] +[ The ~fontaine~ package on GNU ELPA (by Protesilaos) is designed to + handle this case. ] Put something like this in your initialization file (also consider reading the doc string of ~set-face-attribute~): @@ -3537,7 +2636,7 @@ of the themes, which can make it easier to redefine faces in bulk). (add-hook 'modus-themes-after-load-theme-hook #'my-modes-themes-bold-italic-faces) #+end_src -[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Face specs at scale using the themes' palette]]. +[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Use theme colors in code with modus-themes-with-colors]]. ** Custom Org todo keyword and priority faces :properties: @@ -3623,8 +2722,6 @@ Their documentation strings will offer you further guidance. Recall that the themes let you retrieve a color from their palette. Do it if you plan to control face attributes. -[[#h:1487c631-f4fe-490d-8d58-d72ffa3bd474][Custom face specs using the themes' palette]]. - [[#h:02e25930-e71a-493d-828a-8907fc80f874][Check color combinations]]. ** Custom Org emphasis faces @@ -3649,7 +2746,7 @@ specification of that variable looks like this: With the exception of ~org-verbatim~ and ~org-code~ faces, everything else uses the corresponding type of emphasis: a bold typographic weight, or -italicized, underlined, and struck through text. +italicised, underlined, and struck through text. The best way for users to add some extra attributes, such as a foreground color, is to define their own faces and assign them to the @@ -3872,8 +2969,8 @@ palette in large part because certain colors are only meant to be used in combination with some others. Consult the source code for the minutia and relevant commentary. -Such knowledge may prove valuable while attempting to override some of -the themes' colors: [[#h:307d95dd-8dbd-4ece-a543-10ae86f155a6][Override colors]]. +Such knowledge may prove valuable while attempting to customize the +theme's color palette. ** Load theme depending on time of day :properties: @@ -3972,101 +3069,6 @@ With those in place, PDFs have a distinct backdrop for their page, while buffers with major-mode as ~pdf-view-mode~ automatically switches to dark mode when ~modus-themes-toggle~ is called. -** Decrease mode line height -:properties: -:custom_id: h:03be4438-dae1-4961-9596-60a307c070b5 -:end: -#+cindex: Decrease mode line height - -By default, the mode line of the Modus themes is set to 1 pixel width -for its =:box= attribute. In contrast, the mode line of stock Emacs is -1 -pixel. This small difference is considered necessary for the purposes -of accessibility as our out-of-the-box design has a prominent color -around the mode line (a border) to make its boundaries clear. With a -negative width the border and the text on the mode line can feel a bit -more difficult to read under certain scenaria. - -Furthermore, the user option ~modus-themes-mode-line~ ([[#h:27943af6-d950-42d0-bc23-106e43f50a24][Mode line]]) does not -allow for such a negative value because there are many edge cases that -simply make for a counter-intuitive set of possibilities, such as a =0= -value not being acceptable by the underlying face infrastructure, and -negative values greater than =-2= not being particularly usable. - -For these reasons, users who wish to decrease the overall height of the -mode line must handle things on their own by implementing the methods -for face customization documented herein. - -[[#h:1487c631-f4fe-490d-8d58-d72ffa3bd474][Basic face customization]]. - -One such method is to create a function that configures the desired -faces and hook it to ~modus-themes-after-load-theme-hook~ so that it -persists while switching between the Modus themes with the command -~modus-themes-toggle~. - -This one simply disables the box altogether, which will reduce the -height of the mode lines, but also remove their border: - -#+begin_src emacs-lisp -(defun my-modus-themes-custom-faces () - (set-face-attribute 'mode-line nil :box nil) - (set-face-attribute 'mode-line-inactive nil :box nil)) - -(add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-custom-faces) -#+end_src - -The above relies on the ~set-face-attribute~ function, though users who -plan to re-use colors from the theme and do so at scale are better off -with the more streamlined combination of the ~modus-themes-with-colors~ -macro and ~custom-set-faces~. - -[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Face customization at scale]]. - -As explained before in this document, this approach has a syntax that is -consistent with the source code of the themes, so it probably is easier -to re-use parts of the design. - -The following emulates the stock Emacs style, while still using the -colors of the Modus themes (whichever attribute is not explicitly stated -is inherited from the underlying theme): - -#+begin_src emacs-lisp -(defun my-modus-themes-custom-faces () - (modus-themes-with-colors - (custom-set-faces - `(mode-line ((,class :box (:line-width -1 :style released-button)))) - `(mode-line-inactive ((,class :box (:line-width -1 :color ,bg-region))))))) - -(add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-custom-faces) -#+end_src - -And this one is like the out-of-the-box style of the Modus themes, but -with the -1 height instead of 1: - -#+begin_src emacs-lisp -(defun my-modus-themes-custom-faces () - (modus-themes-with-colors - (custom-set-faces - `(mode-line ((,class :box (:line-width -1 :color ,fg-alt)))) - `(mode-line-inactive ((,class :box (:line-width -1 :color ,bg-region))))))) - -(add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-custom-faces) -#+end_src - -Finally, to also change the background color of the active mode line, -such as that it looks like the "accented" variant which is possible via -the user option ~modus-themes-mode-line~, the =:background= attribute needs -to be specified as well: - -#+begin_src emacs-lisp -(defun my-modus-themes-custom-faces () - (modus-themes-with-colors - (custom-set-faces - `(mode-line ((,class :box (:line-width -1 :color ,fg-alt) :background ,bg-active-accent))) - `(mode-line-inactive ((,class :box (:line-width -1 :color ,bg-region))))))) - -(add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-custom-faces) -#+end_src - ** Toggle themes without reloading them :properties: :custom_id: h:b40aca50-a3b2-4c43-be58-2c26fcd14237 @@ -4106,13 +3108,13 @@ varying skill levels, from beginners to experts. This means that we try to make things easier by not expecting anyone reading this document to be proficient in Emacs Lisp or programming in general. -Such a case is with the use of the ~modus-themes-after-load-theme-hook~, -which runs after ~modus-themes-toggle~, ~modus-themes-load-operandi~, or -~modus-themes-load-vivendi~ is evaluated. We recommend using that hook -for advanced customizations, because (1) we know for sure that it is +Such a case is with the use of ~modus-themes-after-load-theme-hook~, +which runs after the ~modus-themes-load-theme~ function (used by the +command ~modus-themes-toggle~). We recommend using that hook for +advanced customizations, because (1) we know for sure that it is available once the themes are loaded, and (2) anyone consulting this -manual, especially the sections on enabling and loading the themes, will -be in a good position to benefit from that hook. +manual, especially the sections on enabling and loading the themes, +will be in a good position to benefit from that hook. Advanced users who have a need to switch between the Modus themes and other items will find that such a hook does not meet their requirements: @@ -4138,235 +3140,14 @@ also has the benefit that it does not depend on functions such as ~modus-themes-toggle~ and the others mentioned above. ~enable-theme~ is called internally by ~load-theme~, so the hook works everywhere. -Now this specific piece of Elisp may be simple for experienced users, -but it is not easy to read for newcomers, including the author of the -Modus themes for the first several months of their time as an Emacs -user. Hence our hesitation to recommend it as part of the standard -setup of the Modus themes (it is generally a good idea to understand -what the implications are of advising a function). - -** Diffs with only the foreground -:properties: -:custom_id: h:e2aed9eb-5e1e-45ec-bbd7-bc4faeab3236 -:end: -#+cindex: Foreground-only diffs - -Buffers that show differences between versions of a file or buffer, such -as in ~diff-mode~ and ~ediff~ always use color-coded background and -foreground combinations. - -[[#h:ea7ac54f-5827-49bd-b09f-62424b3b6427][Option for diff buffer looks]]. - -User may, however, prefer a style that removes the color-coded -backgrounds from regular changes while keeping them for word-wise (aka -"refined") changes---backgrounds for word-wise diffs are helpful in -context. To make this happen, one can use the ~modus-themes-with-colors~ -macro ([[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Face specs at scale using the themes' palette]]): - -#+begin_src emacs-lisp -(defun my-modus-themes-custom-faces () - (modus-themes-with-colors - (custom-set-faces - `(modus-themes-diff-added ((,class :background unspecified :foreground ,green))) ; OR ,blue for deuteranopia - `(modus-themes-diff-changed ((,class :background unspecified :foreground ,yellow))) - `(modus-themes-diff-removed ((,class :background unspecified :foreground ,red))) - - `(modus-themes-diff-refine-added ((,class :background ,bg-diff-added :foreground ,fg-diff-added))) - ;; `(modus-themes-diff-refine-added ((,class :background ,bg-diff-added-deuteran :foreground ,fg-diff-added-deuteran))) - `(modus-themes-diff-refine-changed ((,class :background ,bg-diff-changed :foreground ,fg-diff-changed))) - `(modus-themes-diff-refine-removed ((,class :background ,bg-diff-removed :foreground ,fg-diff-removed))) - - `(modus-themes-diff-focus-added ((,class :background ,bg-dim :foreground ,green))) ; OR ,blue for deuteranopia - `(modus-themes-diff-focus-changed ((,class :background ,bg-dim :foreground ,yellow))) - `(modus-themes-diff-focus-removed ((,class :background ,bg-dim :foreground ,red))) - - `(modus-themes-diff-heading ((,class :background ,bg-alt :foreground ,fg-main))) - - `(diff-indicator-added ((,class :foreground ,green))) ; OR ,blue for deuteranopia - `(diff-indicator-changed ((,class :foreground ,yellow))) - `(diff-indicator-removed ((,class :foreground ,red))) - - `(magit-diff-added ((,class :background unspecified :foreground ,green-faint))) - `(magit-diff-changed ((,class :background unspecified :foreground ,yellow-faint))) - `(magit-diff-removed ((,class :background unspecified :foreground ,red-faint))) - `(magit-diff-context-highlight ((,class :background ,bg-dim :foreground ,fg-dim)))))) - -;; This is so that the changes persist when switching between -;; `modus-operandi' and `modus-vivendi'. -(add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-custom-faces) -#+end_src - -This used to be an optional style of ~modus-themes-diffs~, but has been -removed since version =2.0.0= to ensure that the accessibility standard -and aesthetic quality of the themes is not compromised. - -** Ediff without diff color-coding -:properties: -:custom_id: h:b0b31802-0216-427e-b071-1a47adcfe608 -:end: - -Ediff uses the same color-coding as ordinary diffs in ~diff-mode~, Magit, -etc. ([[#h:ea7ac54f-5827-49bd-b09f-62424b3b6427][Option for diff buffer looks]]). This is consistent with the -principle of least surprise. - -Users may, however, prefer to treat Ediff differently on the premise -that it does not need any particular color-coding to show added or -removed lines/words: it does not use the =+= or =-= markers, after all. - -This can be achieved by customizing the Ediff faces with color -combinations that do not carry the same connotations as those of diffs. -Consider this example, which leverages the ~modus-themes-with-colors~ -macro ([[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Face specs at scale using the themes' palette]]): - -#+begin_src emacs-lisp -(defun my-modus-themes-custom-faces () - (modus-themes-with-colors - (custom-set-faces - `(ediff-current-diff-A ((,class :inherit unspecified :background ,bg-special-faint-cold :foreground ,fg-special-cold))) - `(ediff-current-diff-B ((,class :inherit unspecified :background ,bg-special-faint-warm :foreground ,fg-special-warm))) - `(ediff-current-diff-C ((,class :inherit unspecified :background ,bg-special-faint-calm :foreground ,fg-special-calm))) - `(ediff-fine-diff-A ((,class :inherit unspecified :background ,bg-special-cold :foreground ,fg-special-cold))) - `(ediff-fine-diff-B ((,class :inherit unspecified :background ,bg-special-warm :foreground ,fg-special-warm))) - `(ediff-fine-diff-C ((,class :inherit unspecified :background ,bg-special-calm :foreground ,fg-special-calm)))))) - -;; This is so that the changes persist when switching between -;; `modus-operandi' and `modus-vivendi'. -(add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-custom-faces) -#+end_src - -Remove the =:foreground= and its value to preserve the underlying -coloration. +The downside of the theme-agnostic hook is that any functions added to +it will likely not be able to benefit from macro calls that read the +active theme, such as ~modus-themes-with-colors~. Not all Emacs +themes have the same capabilities. -[[#h:f4d4b71b-2ca5-4c3d-b0b4-9bfd7aa7fb4d][Visualize the active Modus theme's palette]]. - -** Near-monochrome syntax highlighting -:properties: -:custom_id: h:c1f3fa8e-7a63-4a6f-baf3-a7febc0661f0 -:end: -#+cindex: Monochrome code syntax - -While the Modus themes do provide a user option to control the overall -style of syntax highlighting in programming major modes, they do not -cover the possibility of a monochromatic or near-monochromatic design -([[#h:c119d7b2-fcd4-4e44-890e-5e25733d5e52][Option for syntax highlighting]]). This is due to the multitude of -preferences involved: one may like comments to be styled with an accent -value, another may want certain constructs to be bold, a third may apply -italics to doc strings but not comments... The possibilities are -virtually endless. As such, this sort of design is best handled at the -user level in accordance with the information furnished elsewhere in -this manual. - -[[#h:1487c631-f4fe-490d-8d58-d72ffa3bd474][Case-by-case face specs using the themes' palette]]. - -[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Face specs at scale using the themes' palette]]. - -The gist is that we want to override the font-lock faces. For our -changes to persist while switching between ~modus-operandi~ and -~modus-vivendi~ we wrap our face overrides in a function that we hook to -~modus-themes-after-load-theme-hook~. - -Users who want to replicate the structure of the themes' source code are -advised to use the examples with ~custom-set-faces~. Those who prefer a -different approach can use the snippets which call ~set-face-attribute~. -Below are the code blocks. - -The following uses a yellow accent value for comments and green hues for -strings. Regexp grouping constructs have color values that work in the -context of a green string. All other elements use the main foreground -color, except warnings such as the ~user-error~ function in Elisp -buffers which gets a subtle red tint (not to be confused with the -~warning~ face which is used for genuine warnings). Furthermore, notice -the ~modus-themes-bold~ and ~modus-themes-slant~ which apply the -preference set in the user options ~modus-themes-bold-constructs~ and -~modus-themes-italic-constructs~, respectively. Users who do not want -this conditionally must replace these faces with ~bold~ and ~italic~ -respectively (or ~unspecified~ to disable the effect altogether). - -#+begin_src emacs-lisp -;; This is the hook. It will not be replicated across all code samples. -(add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-subtle-syntax) - -(defun my-modus-themes-subtle-syntax () - (modus-themes-with-colors - (custom-set-faces - `(font-lock-builtin-face ((,class :inherit modus-themes-bold :foreground unspecified))) - `(font-lock-comment-delimiter-face ((,class :inherit font-lock-comment-face))) - `(font-lock-comment-face ((,class :inherit unspecified :foreground ,fg-comment-yellow))) - `(font-lock-constant-face ((,class :foreground unspecified))) - `(font-lock-doc-face ((,class :inherit modus-themes-slant :foreground ,fg-special-mild))) - `(font-lock-function-name-face ((,class :foreground unspecified))) - `(font-lock-keyword-face ((,class :inherit modus-themes-bold :foreground unspecified))) - `(font-lock-negation-char-face ((,class :inherit modus-themes-bold :foreground unspecified))) - `(font-lock-preprocessor-face ((,class :foreground unspecified))) - `(font-lock-regexp-grouping-backslash ((,class :inherit bold :foreground ,yellow))) - `(font-lock-regexp-grouping-construct ((,class :inherit bold :foreground ,blue-alt-other))) - `(font-lock-string-face ((,class :foreground ,green-alt-other))) - `(font-lock-type-face ((,class :inherit modus-themes-bold :foreground unspecified))) - `(font-lock-variable-name-face ((,class :foreground unspecified))) - `(font-lock-warning-face ((,class :inherit modus-themes-bold :foreground ,red-nuanced-fg)))))) - -;; Same as above with `set-face-attribute' instead of `custom-set-faces' -(defun my-modus-themes-subtle-syntax () - (modus-themes-with-colors - (set-face-attribute 'font-lock-builtin-face nil :inherit 'modus-themes-bold :foreground 'unspecified) - (set-face-attribute 'font-lock-comment-delimiter-face nil :inherit 'font-lock-comment-face) - (set-face-attribute 'font-lock-comment-face nil :inherit 'unspecified :foreground fg-comment-yellow) - (set-face-attribute 'font-lock-constant-face nil :foreground 'unspecified) - (set-face-attribute 'font-lock-doc-face nil :inherit 'modus-themes-slant :foreground fg-special-mild) - (set-face-attribute 'font-lock-function-name-face nil :foreground 'unspecified) - (set-face-attribute 'font-lock-keyword-face nil :inherit 'modus-themes-bold :foreground 'unspecified) - (set-face-attribute 'font-lock-negation-char-face nil :inherit 'modus-themes-bold :foreground 'unspecified) - (set-face-attribute 'font-lock-preprocessor-face nil :foreground 'unspecified) - (set-face-attribute 'font-lock-regexp-grouping-backslash nil :inherit 'bold :foreground yellow) - (set-face-attribute 'font-lock-regexp-grouping-construct nil :inherit 'bold :foreground blue-alt-other) - (set-face-attribute 'font-lock-string-face nil :foreground green-alt-other) - (set-face-attribute 'font-lock-type-face nil :inherit 'modus-themes-bold :foreground 'unspecified) - (set-face-attribute 'font-lock-variable-name-face nil :foreground 'unspecified) - (set-face-attribute 'font-lock-warning-face nil :inherit 'modus-themes-bold :foreground red-nuanced-fg))) -#+end_src - -The following sample is the same as above, except strings are blue and -comments are gray. Regexp constructs are adapted accordingly. - -#+begin_src emacs-lisp -(defun my-modus-themes-subtle-syntax () - (modus-themes-with-colors - (custom-set-faces - `(font-lock-builtin-face ((,class :inherit modus-themes-bold :foreground unspecified))) - `(font-lock-comment-delimiter-face ((,class :inherit font-lock-comment-face))) - `(font-lock-comment-face ((,class :inherit unspecified :foreground ,fg-alt))) - `(font-lock-constant-face ((,class :foreground unspecified))) - `(font-lock-doc-face ((,class :inherit modus-themes-slant :foreground ,fg-docstring))) - `(font-lock-function-name-face ((,class :foreground unspecified))) - `(font-lock-keyword-face ((,class :inherit modus-themes-bold :foreground unspecified))) - `(font-lock-negation-char-face ((,class :inherit modus-themes-bold :foreground unspecified))) - `(font-lock-preprocessor-face ((,class :foreground unspecified))) - `(font-lock-regexp-grouping-backslash ((,class :inherit bold :foreground ,fg-escape-char-backslash))) - `(font-lock-regexp-grouping-construct ((,class :inherit bold :foreground ,fg-escape-char-construct))) - `(font-lock-string-face ((,class :foreground ,blue-alt))) - `(font-lock-type-face ((,class :inherit modus-themes-bold :foreground unspecified))) - `(font-lock-variable-name-face ((,class :foreground unspecified))) - `(font-lock-warning-face ((,class :inherit modus-themes-bold :foreground ,red-nuanced-fg)))))) - -;; Same as above with `set-face-attribute' instead of `custom-set-faces' -(defun my-modus-themes-subtle-syntax () - (modus-themes-with-colors - (set-face-attribute 'font-lock-builtin-face nil :inherit 'modus-themes-bold :foreground 'unspecified) - (set-face-attribute 'font-lock-comment-delimiter-face nil :inherit 'font-lock-comment-face) - (set-face-attribute 'font-lock-comment-face nil :inherit 'unspecified :foreground fg-alt) - (set-face-attribute 'font-lock-constant-face nil :foreground 'unspecified) - (set-face-attribute 'font-lock-doc-face nil :inherit 'modus-themes-slant :foreground fg-docstring) - (set-face-attribute 'font-lock-function-name-face nil :foreground 'unspecified) - (set-face-attribute 'font-lock-keyword-face nil :inherit 'modus-themes-bold :foreground 'unspecified) - (set-face-attribute 'font-lock-negation-char-face nil :inherit 'modus-themes-bold :foreground 'unspecified) - (set-face-attribute 'font-lock-preprocessor-face nil :foreground 'unspecified) - (set-face-attribute 'font-lock-regexp-grouping-backslash nil :inherit 'bold :foreground fg-escape-char-backslash) - (set-face-attribute 'font-lock-regexp-grouping-construct nil :inherit 'bold :foreground fg-escape-char-construct) - (set-face-attribute 'font-lock-string-face nil :foreground blue-alt) - (set-face-attribute 'font-lock-type-face nil :inherit 'modus-themes-bold :foreground 'unspecified) - (set-face-attribute 'font-lock-variable-name-face nil :foreground 'unspecified) - (set-face-attribute 'font-lock-warning-face nil :inherit 'modus-themes-bold :foreground red-nuanced-fg))) -#+end_src +In this document, we cover ~modus-themes-after-load-theme-hook~ though +the user can replace it with ~after-enable-theme-hook~ should they +need to (provided they understand the implications). ** Custom hl-todo colors :PROPERTIES: @@ -4448,16 +3229,16 @@ on what we cover at length elsewhere in this manual: [[#h:f4651d55-8c07-46aa-b52b-bed1e53463bb][Advanced customization]]. -[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Face specs at scale using the themes' palette]]. +[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Use theme colors in code with modus-themes-with-colors]]. #+begin_src emacs-lisp (defun my-modus-themes-custom-faces () (modus-themes-with-colors (custom-set-faces - `(solaire-default-face ((,class :inherit default :background ,bg-alt :foreground ,fg-dim))) - `(solaire-line-number-face ((,class :inherit solaire-default-face :foreground ,fg-unfocused))) - `(solaire-hl-line-face ((,class :background ,bg-active))) - `(solaire-org-hide-face ((,class :background ,bg-alt :foreground ,bg-alt)))))) + `(solaire-default-face ((,c :inherit default :background ,bg-dim :foreground ,fg-dim))) + `(solaire-line-number-face ((,c :inherit solaire-default-face :foreground ,fg-unfocused))) + `(solaire-hl-line-face ((,c :background ,bg-active))) + `(solaire-org-hide-face ((,c :background ,bg-dim :foreground ,bg-dim)))))) (add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-custom-faces) #+end_src @@ -4487,65 +3268,50 @@ affected face groups. The items with an appended asterisk =*= tend to have lots of extensions, so the "full support" may not be 100% true… + ace-window -+ alert ++ agda2-mode + all-the-icons + all-the-icons-dired + all-the-icons-ibuffer + annotate + ansi-color + anzu -+ apropos -+ artbollocks-mode + auctex and TeX + auto-dim-other-buffers + avy -+ awesome-tray + bbdb + binder -+ bm + bongo + boon + bookmark -+ breakpoint (provided by the built-in {{{file(gdb-mi.el)}}} library) + calendar and diary -+ calfw -+ calibredb + centaur-tabs -+ cfrs + change-log and log-view (such as ~vc-print-log~, ~vc-print-root-log~) + chart + cider + circe + citar -+ color-rg ++ clojure-mode + column-enforce-mode + company-mode* -+ company-posframe + compilation-mode + completions + consult + corfu + corfu-quick + counsel* -+ counsel-css -+ cov + cperl-mode + crontab-mode + css-mode + csv-mode + ctrlf + custom (what you get with {{{kbd(M-x customize)}}}) -+ dap-mode + deadgrep -+ debbugs + deft -+ denote + devdocs + dictionary + diff-hl + diff-mode + dim-autoload -+ dir-treeview + dired + dired-async + dired-git @@ -4553,11 +3319,8 @@ have lots of extensions, so the "full support" may not be 100% true… + dired-narrow + dired-subtree + diredfl -+ diredp (dired+) + display-fill-column-indicator-mode + doom-modeline -+ easy-jekyll -+ ebdb + ediff + ein (Emacs IPython Notebook) + eglot @@ -4571,36 +3334,23 @@ have lots of extensions, so the "full support" may not be 100% true… + emms + enh-ruby-mode (enhanced-ruby-mode) + epa -+ equake + erc -+ eros + ert + eshell + eshell-fringe-status -+ eshell-git-prompt -+ eshell-prompt-extras (epe) -+ eshell-syntax-highlighting + evil* (evil-mode) -+ evil-goggles -+ evil-snipe -+ evil-visual-mark-mode + eww + exwm + eyebrowse -+ fancy-dabbrev + flycheck + flycheck-color-mode-line + flycheck-indicator -+ flycheck-posframe + flymake + flyspell + flx -+ freeze-it + focus + fold-this + font-lock (generic syntax highlighting) -+ forge -+ fountain (fountain-mode) + geiser + git-commit + git-gutter (and variants) @@ -4609,23 +3359,16 @@ have lots of extensions, so the "full support" may not be 100% true… + gnus + gotest + golden-ratio-scroll-screen -+ helm* -+ helm-ls-git -+ helm-switch-shell -+ helm-xref + helpful -+ highlight-indentation + highlight-numbers + highlight-parentheses ([[#h:24bab397-dcb2-421d-aa6e-ec5bd622b913][Note on highlight-parentheses.el]]) + highlight-thing -+ hl-defined + hl-fill-column + hl-line-mode + hl-todo + hydra + ibuffer + icomplete -+ icomplete-vertical + ido-mode + iedit + iflipb @@ -4635,7 +3378,6 @@ have lots of extensions, so the "full support" may not be 100% true… + info + info+ (info-plus) + info-colors -+ interaction-log + ioccur + isearch, occur, etc. + ivy* @@ -4644,34 +3386,25 @@ have lots of extensions, so the "full support" may not be 100% true… + journalctl-mode + js2-mode + julia -+ jupyter + kaocha-runner + keycast + ledger-mode + leerzeichen + line numbers (~display-line-numbers-mode~ and global variant) -+ lsp-mode -+ lsp-ui -+ macrostep + magit -+ magit-imerge + make-mode + man + marginalia + markdown-mode + markup-faces (~adoc-mode~) -+ mentor + messages -+ mini-modeline + minimap -+ mmm-mode + mode-line + mood-line + moody + mpdel + mu4e + multiple-cursors -+ nano-modeline + neotree + notmuch + num3-mode @@ -4698,11 +3431,8 @@ have lots of extensions, so the "full support" may not be 100% true… + pdf-tools + persp-mode + perspective -+ phi-grep -+ pomidor + popup + powerline -+ powerline-evil + prism ([[#h:a94272e0-99da-4149-9e80-11a7e67a2cf2][Note for prism.el]]) + prescient + proced @@ -4710,19 +3440,15 @@ have lots of extensions, so the "full support" may not be 100% true… + pulse + pyim + quick-peek -+ racket-mode -+ rainbow-blocks + rainbow-delimiters + rcirc ++ rcirc-color + recursion-indicator + regexp-builder (also known as ~re-builder~) + rg (rg.el) + ripgrep + rmail + ruler-mode -+ selectrum -+ selectrum-prescient -+ semantic + sesman + shell-script-mode + shortdoc @@ -4734,9 +3460,7 @@ have lots of extensions, so the "full support" may not be 100% true… + slime (slbd) + sly + smart-mode-line -+ smartparens + smerge -+ spaceline + speedbar + spell-fu + stripes @@ -4746,20 +3470,16 @@ have lots of extensions, so the "full support" may not be 100% true… + sx + symbol-overlay + syslog-mode -+ tab-bar-groups + tab-bar-mode + tab-line-mode + table (built-in {{{file(table.el)}}}) + telega -+ telephone-line + terraform-mode + term + textsec -+ tomatinho + transient (pop-up windows such as Magit's) + trashed + tree-sitter -+ treemacs + tty-menu + tuareg + typescript @@ -4779,15 +3499,12 @@ have lots of extensions, so the "full support" may not be 100% true… + which-key + whitespace-mode + window-divider-mode -+ winum + writegood-mode + woman + xah-elisp-mode -+ xref + xterm-color (and ansi-colors) + yaml-mode + yasnippet -+ ztree Plus many other miscellaneous faces that are provided by Emacs. @@ -4802,34 +3519,45 @@ inherit from some basic faces or their dependencies which are directly supported by the themes. + ag ++ apropos + apt-sources-list ++ bbdb ++ bm ++ breakpoint (provided by the built-in {{{file(gdb-mi.el)}}} library) + buffer-expose + bufler + counsel-notmuch + counsel-org-capture-string + dashboard (emacs-dashboard) + define-word ++ denote + disk-usage + dtache + dynamic-ruler + easy-kill ++ ebdb + edit-indirect + egerrit + elfeed-summary + evil-owl + flyspell-correct + fortran-mode ++ freeze-it ++ forge + git-walktree + goggles + highlight-defined + highlight-escape-sequences (~hes-mode~) ++ icomplete-vertical + i3wm-config-mode ++ lin + minibuffer-line + no-emoji + org-remark + parrot + perl-mode + php-mode ++ pulsar + rjsx-mode + side-hustle + spell-fu @@ -4840,6 +3568,7 @@ supported by the themes. + vdiff + vertico-indexed + vertico-mouse ++ xref * Notes on individual packages :properties: @@ -4895,16 +3624,21 @@ length elsewhere in this manual: [[#h:f4651d55-8c07-46aa-b52b-bed1e53463bb][Advanced customization]]. -[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Face specs at scale using the themes' palette]]. +[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Use theme colors in code with modus-themes-with-colors]]. #+begin_src emacs-lisp (defun my-modus-themes-custom-faces () (modus-themes-with-colors (custom-set-faces - ;; Replace green with blue if you use `modus-themes-deuteranopia'. - `(git-gutter-fr:added ((,class :foreground ,green-fringe-bg))) - `(git-gutter-fr:deleted ((,class :foreground ,red-fringe-bg))) - `(git-gutter-fr:modified ((,class :foreground ,yellow-fringe-bg)))))) + ;; Make foreground the same as background for a uniform bar on + ;; Doom Emacs. + ;; + ;; Doom should not be implementing such hacks because themes + ;; cannot support them: + ;; <https://protesilaos.com/codelog/2022-08-04-doom-git-gutter-modus-themes/>. + `(git-gutter-fr:added ((,c :foreground ,bg-added-intense))) + `(git-gutter-fr:deleted ((,c :foreground ,bg-removed-intense))) + `(git-gutter-fr:modified ((,c :foreground ,bg-changed-intense)))))) (add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-custom-faces) #+end_src @@ -4917,17 +3651,17 @@ If the above does not work, try this instead: (after! modus-themes (modus-themes-with-colors (custom-set-faces - ;; Replace green with blue if you use `modus-themes-deuteranopia'. - `(git-gutter-fr:added ((,class :foreground ,green-fringe-bg))) - `(git-gutter-fr:deleted ((,class :foreground ,red-fringe-bg))) - `(git-gutter-fr:modified ((,class :foreground ,yellow-fringe-bg)))))) + ;; Make foreground the same as background for a uniform bar on + ;; Doom Emacs. + ;; + ;; Doom should not be implementing such hacks because themes + ;; cannot support them: + ;; <https://protesilaos.com/codelog/2022-08-04-doom-git-gutter-modus-themes/>. + `(git-gutter-fr:added ((,c :foreground ,bg-added-intense))) + `(git-gutter-fr:deleted ((,c :foreground ,bg-removed-intense))) + `(git-gutter-fr:modified ((,c :foreground ,bg-changed-intense)))))) #+end_src -Replace ~green-fringe-bg~ with ~blue-fringe-bg~ if you want to optimize -for red-green color deficiency. - -[[#h:3ed03a48-20d8-4ce7-b214-0eb7e4c79abe][Option for red-green color deficiency or deuteranopia]]. - ** Note on php-mode multiline comments :PROPERTIES: :CUSTOM_ID: h:d0a3157b-9c04-46e8-8742-5fb2a7ae8798 @@ -5042,10 +3776,10 @@ elsewhere in this document. For example: #+begin_src emacs-lisp (modus-themes-with-colors (custom-set-faces - `(fill-column-indicator ((,class :foreground ,bg-active))))) + `(fill-column-indicator ((,c :foreground ,bg-active))))) #+end_src -[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Face specs at scale using the themes' palette]]. +[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Use theme colors in code with modus-themes-with-colors]]. To make the line thicker, set the height to be equal to the base font size instead of the one pixel we use. This is done by specifying a rate @@ -5055,7 +3789,7 @@ For example: #+begin_src emacs-lisp (modus-themes-with-colors (custom-set-faces - `(fill-column-indicator ((,class :height 1.0 :background ,bg-inactive :foreground ,bg-inactive))))) + `(fill-column-indicator ((,c :height 1.0 :background ,bg-inactive :foreground ,bg-inactive))))) #+end_src ** Note on highlight-parentheses.el @@ -5113,14 +3847,14 @@ found): ;; Here we set color combinations that involve both a background ;; and a foreground value. - (setq highlight-parentheses-background-colors (list cyan-refine-bg - magenta-refine-bg - green-refine-bg - yellow-refine-bg) - highlight-parentheses-colors (list cyan-refine-fg - magenta-refine-fg - green-refine-fg - yellow-refine-fg)) + (setq highlight-parentheses-background-colors (list bg-cyan-intense + bg-magenta-intense + bg-green-intense + bg-yellow-intense) + highlight-parentheses-colors (list cyan + magenta + green + yellow)) ;; And here we pass only foreground colors while disabling any ;; backgrounds. @@ -5160,14 +3894,14 @@ implementation: ;; Here we set color combinations that involve both a background ;; and a foreground value. - (setq highlight-parentheses-background-colors (list cyan-refine-bg - magenta-refine-bg - green-refine-bg - yellow-refine-bg) - highlight-parentheses-colors (list cyan-refine-fg - magenta-refine-fg - green-refine-fg - yellow-refine-fg)) + (setq highlight-parentheses-background-colors (list bg-cyan-intense + bg-magenta-intense + bg-green-intense + bg-yellow-intense) + highlight-parentheses-colors (list cyan + magenta + green + yellow)) ;; And here we pass only foreground colors while disabling any ;; backgrounds. @@ -5221,7 +3955,7 @@ Users who might prefer to fall below the minimum 7:1 contrast ratio in relative luminance (the accessibility target we conform with), can opt to configure the relevant faces on their own. -[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Face specs at scale using the themes' palette]]. +[[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Use theme colors in code with modus-themes-with-colors]]. This example uses more vivid background colors, though it comes at the very high cost of degraded legibility. @@ -5229,14 +3963,14 @@ very high cost of degraded legibility. #+begin_src emacs-lisp (modus-themes-with-colors (custom-set-faces - `(mmm-cleanup-submode-face ((,class :background ,yellow-refine-bg))) - `(mmm-code-submode-face ((,class :background ,bg-active))) - `(mmm-comment-submode-face ((,class :background ,blue-refine-bg))) - `(mmm-declaration-submode-face ((,class :background ,cyan-refine-bg))) - `(mmm-default-submode-face ((,class :background ,bg-alt))) - `(mmm-init-submode-face ((,class :background ,magenta-refine-bg))) - `(mmm-output-submode-face ((,class :background ,red-refine-bg))) - `(mmm-special-submode-face ((,class :background ,green-refine-bg))))) + `(mmm-cleanup-submode-face ((,c :background ,bg-yellow-intense))) + `(mmm-code-submode-face ((,c :background ,bg-inactive))) + `(mmm-comment-submode-face ((,c :background ,bg-blue-intense))) + `(mmm-declaration-submode-face ((,c :background ,bg-cyan-intense))) + `(mmm-default-submode-face ((,c :background ,bg-dim))) + `(mmm-init-submode-face ((,c :background ,bg-magenta-intense))) + `(mmm-output-submode-face ((,c :background ,bg-red-intense))) + `(mmm-special-submode-face ((,c :background ,bg-green-intense))))) #+end_src ** Note on prism.el @@ -5250,13 +3984,13 @@ implements an alternative to the typical coloration of code. Instead of highlighting the syntactic constructs, it applies color to different levels of depth in the code structure. -As {{{file(prism.el)}}} offers a broad range of customizations, we cannot -style it directly at the theme level: that would run contrary to the -spirit of the package. Instead, we may offer preset color schemes. -Those should offer a starting point for users to adapt to their needs. +As =prism.el= offers a broad range of customizations, we cannot style +it directly at the theme level: that would run contrary to the spirit +of the package. Instead, we may offer preset color schemes. Those +should offer a starting point for users to adapt to their needs. In the following code snippets, we employ the ~modus-themes-with-colors~ -macro: [[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Face specs at scale using the themes' palette]]. +macro: [[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Use theme colors in code with modus-themes-with-colors]]. These are the minimum recommended settings with 16 colors: @@ -5269,20 +4003,20 @@ These are the minimum recommended settings with 16 colors: :colors (modus-themes-with-colors (list fg-main magenta - cyan-alt-other - magenta-alt-other + cyan-cooler + magenta-cooler blue - magenta-alt - cyan-alt - red-alt-other + magenta-warmer + cyan-warmer + red-cooler green fg-main cyan yellow - blue-alt - red-alt - green-alt-other - fg-special-warm))) + blue-warmer + red-warmer + green-cooler + yellow-faint))) #+end_src With 8 colors: @@ -5296,11 +4030,11 @@ With 8 colors: :colors (modus-themes-with-colors (list blue magenta - magenta-alt-other - cyan-alt-other + magenta-cooler + cyan-cooler fg-main - blue-alt - red-alt-other + blue-warmer + red-cooler cyan))) #+end_src @@ -5316,8 +4050,8 @@ to the themes' default aesthetic: :colors (modus-themes-with-colors (list blue magenta - magenta-alt-other - green-alt))) + magenta-cooler + green-warmer))) #+end_src If you need to apply desaturation and lightening, you can use what the @@ -5330,47 +4064,11 @@ examples with the 4, 8, 16 colors): :lightens (cl-loop for i from 0 below 16 collect (* i 2.5)) :colors (modus-themes-with-colors (list fg-main - cyan-alt-other - magenta-alt-other + cyan-cooler + magenta-cooler magenta))) #+end_src -** Note on god-mode.el -:properties: -:alt_title: Note for god-mode -:custom_id: h:4da1d515-3e05-47ef-9e45-8251fc7e986a -:end: - -The ~god-mode~ library does not provide faces that could be configured by -the Modus themes. Users who would like to get some visual feedback on -the status of {{{kbd(M-x god-mode)}}} are instead encouraged by upstream to -set up their own configurations, such as by changing the ~mode-line~ face -([[#h:f4651d55-8c07-46aa-b52b-bed1e53463bb][Advanced customization]]). This is an adaptation of the approach -followed in the upstream README: - -#+begin_src emacs-lisp -(defun my-god-mode-update-mode-line () - "Make `mode-line' blue if God local mode is active." - (modus-themes-with-colors - (if god-local-mode - (set-face-attribute 'mode-line nil - :foreground blue-active - :background bg-active-accent - :box blue) - (set-face-attribute 'mode-line nil - :foreground fg-active - :background bg-active - :box fg-alt)))) - -(add-hook 'post-command-hook 'my-god-mode-update-mode-line) -#+end_src - -We employ the ~modus-themes-with-colors~ which provides access to color -variables defined by the active theme. Its use is covered elsewhere in -this manual ([[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Face specs at scale using the themes' palette]]). As for the -attributes that can be passed to each face, start by consulting the -documentation string of ~set-face-attribute~. - ** Note on company-mode overlay pop-up :properties: :custom_id: h:20cef8c4-d11f-4053-8b2c-2872925780b1 @@ -5387,6 +4085,8 @@ instead of overlays.[fn:: https://github.com/company-mode/company-mode/issues/1010][fn:: https://github.com/tumashu/company-posframe/] +Also consider the ~corfu~ package. + ** Note on ERC escaped color sequences :properties: :custom_id: h:98bdf319-1e32-4469-8a01-771200fba65c @@ -5500,38 +4200,6 @@ would be a good baseline for many themes and/or user configurations. Our target is the highest of the sort, though we do not demand that everyone conforms with it. -** Note on Helm grep -:properties: -:custom_id: h:d28879a2-8e4b-4525-986e-14c0f873d229 -:end: - -There is one face from the Helm package that is meant to highlight the -matches of a grep or grep-like command (=ag= or =ripgrep=). It is -~helm-grep-match~. However, this face can only apply when the user does -not pass =--color=always= as a command-line option for their command. - -Here is the docstring for that face, which is defined in the -{{{file(helm-grep.el)}}} library (you can always visit the source code with -{{{kbd(M-x find-library)}}}). - -#+begin_quote -Face used to highlight grep matches. Have no effect when grep backend -use "--color=" -#+end_quote - -The user must either remove =--color= from the flags passed to the grep -function, or explicitly use =--color=never= (or equivalent). Helm -provides user-facing customization options for controlling the grep -function's parameters, such as ~helm-grep-default-command~ and -~helm-grep-git-grep-command~. - -When =--color=always= is in effect, the grep output will use red text in -bold letter forms to present the matching part in the list of -candidates. That style still meets the contrast ratio target of >= 7:1 -(accessibility standard WCAG AAA), because it draws the reference to -ANSI color number 1 (red) from the already-supported array of -~ansi-color-names-vector~. - ** Note on pdf-tools link hints :properties: :custom_id: h:2659d13e-b1a5-416c-9a89-7c3ce3a76574 @@ -5849,15 +4517,15 @@ A good theme is one that does so with consistency, though not uniformity. In practical terms, a color scheme is what one uses when, for example, -they edit the first sixteen escape sequences of a terminal emulator to -the hues of their preference. The terminal offers the option to choose, -say, the exact value of what counts as "red", but does not provide the -means to control where that is mapped to and whether it should also have -other qualities such as a bold weight for the underlying text or an -added background color. In contradistinction, Emacs uses constructs -known as "faces" which allow the user/developer to specify where a given -color will be used and whether it should be accompanied by other -typographic or stylistic attributes. +they replace the first sixteen escape sequences of a terminal emulator +with color values of their preference. The terminal offers the option +to choose, say, the exact value of what counts as "red", but does not +provide the means to control where that is mapped to and whether it +should also have other qualities such as a bold weight for the +underlying text or an added background color. In contradistinction, +Emacs uses constructs known as "faces" which allow the user/developer +to specify where a given color will be used and whether it should be +accompanied by other typographic or stylistic attributes. By configuring the multitude of faces on offer we thus control both which colors are applied and how they appear in their context. When a @@ -5876,9 +4544,7 @@ it is already understood that one must follow the indicator or headline to view its contents and (ii) underlining everything would make the interface virtually unusable. -[[#h:5808be52-361a-4d18-88fd-90129d206f9b][Option for links]]. - -Again, one must exercise judgment in order to avoid discrimination, +Again, one must exercise judgement in order to avoid discrimination, where "discrimination" refers to: + The treatment of substantially different magnitudes as if they were of @@ -5888,9 +4554,9 @@ where "discrimination" refers to: (To treat similar things differently; to treat dissimilar things alike.) -If, in other words, one was to enforce uniformity without accounting for -the particular requirements of each case---the contextual demands for -usability beyond matters of color---they would be making a +If, in other words, one is to enforce uniformity without accounting +for the particular requirements of each case---the contextual demands +for usability beyond matters of color---they are making a not-so-obvious error of treating different cases as if they were the same. @@ -5923,13 +4589,13 @@ doing so would run contrary to how this project is maintained where details matter greatly. Each program has its own requirements so it won't always be -possible---or indeed desirable---to have 1:1 correspondence between what -applies to Emacs and what should be done elsewhere. No port should ever -strive to be a faithful copy of the Emacs implementation, as no other -program is an Emacs equivalent, but instead try to follow the spirit of -the design. For example, some of the customization options accept a -list as their value, or an alist, which may not be possible to reproduce -on other platforms. +possible---or indeed desirable---to have 1:1 correspondence between +what applies to Emacs and what should be done elsewhere. No port +should ever strive to be a copy of the Emacs implementation, as no +other program is an Emacs equivalent, but instead try to follow the +spirit of the design. For example, some of the customization options +accept a list as their value, or an alist, which may not be possible +to reproduce on other platforms. [[#h:bf1c82f2-46c7-4eb2-ad00-dd11fdd8b53f][Customization options]]. @@ -5939,10 +4605,10 @@ standards are not compromised and (ii) the overall character of the themes remains consistent. The former criterion should be crystal clear as it pertains to the -scientific foundations of the themes: high legibility and taking care of -the needs of users with red-green color deficiency (deuteranopia) by -avoiding red+green color coding paradigms and/or by providing red+blue -variants. +scientific foundations of the themes: high legibility and taking care +of the needs of users with red-green color deficiency (deuteranopia) +by avoiding red+green color coding paradigms and/or by providing +yellow+blue variants ([[#h:f0f3dbcb-602d-40cf-b918-8f929c441baf][Overview]]). The latter criterion is the "je ne sais quoi" of the artistic aspect of the themes, which is partially fleshed out in this manual. @@ -5951,7 +4617,7 @@ the themes, which is partially fleshed out in this manual. With regard to the artistic aspect (where "art" qua skill may amount to an imprecise science), there is no hard-and-fast rule in effect as it -requires one to exercise discretion and make decisions based on +requires one to exercize discretion and make decisions based on context-dependent information or constraints. As is true with most things in life, when in doubt, do not cling on to the letter of the law but try to understand its spirit. @@ -5980,13 +4646,17 @@ in which you can contribute to their ongoing development. :end: #+cindex: Sources of the themes -The ~modus-operandi~ and ~modus-vivendi~ themes are built into Emacs 28. - -The source code of the themes is [[https://git.sr.ht/~protesilaos/modus-themes][available on SourceHut]]. Or check the -[[https://gitlab.com/protesilaos/modus-themes/][GitLab mirror (former main source)]] and the [[https://github.com/protesilaos/modus-themes/][GitHub mirror]]. - -An HTML version of this manual is provided as an extension of the -[[https://protesilaos.com/emacs/modus-themes/][author's personal website]] (does not rely on any non-free code). ++ Package name (GNU ELPA): ~modus-themes~ ++ Official manual: <https://protesilaos.com/emacs/modus-themes> ++ Change log: <https://protesilaos.com/emacs/modus-themes-changelog> ++ Color palette: <https://protesilaos.com/emacs/modus-themes-colors> ++ Sample pictures: <https://protesilaos.com/emacs/modus-themes-pictures> ++ Git repo on SourceHut: <https://git.sr.ht/~protesilaos/modus-themes> + - Mirrors: + + GitHub: <https://github.com/protesilaos/modus-themes> + + GitLab: <https://gitlab.com/protesilaos/modus-themes> ++ Mailing list: <https://lists.sr.ht/~protesilaos/modus-themes> ++ Backronym: My Old Display Unexpectedly Sharpened ... themes ** Issues you can help with :properties: @@ -5994,10 +4664,8 @@ An HTML version of this manual is provided as an extension of the :end: #+cindex: Contributing -#+findex: modus-themes-report-bug A few tasks you can help with by sending an email to the general -[[https://lists.sr.ht/~protesilaos/modus-themes][modus-themes public mailing list]] (or use the command -~modus-themes-report-bug~). +[[https://lists.sr.ht/~protesilaos/modus-themes][modus-themes public mailing list]]. + Suggest refinements to packages that are covered. + Report packages not covered thus far. @@ -6014,10 +4682,6 @@ It is preferable that your feedback includes some screenshots, GIFs, or short videos, as well as further instructions to reproduce a given setup. Though this is not a requirement. -#+findex: modus-themes-version -Also consider mentioning the version of the themes you are using, such -as by invoking the command ~modus-themes-version~. - Whatever you do, bear in mind the overarching objective of the Modus themes: to keep a contrast ratio that is greater or equal to 7:1 between background and foreground colors. If a compromise is ever necessary @@ -6097,45 +4761,48 @@ The Modus themes are a collective effort. Every bit of work matters. + Author/maintainer :: Protesilaos Stavrou. -+ Contributions to code or documentation :: Alex Griffin, Anders - Johansson, Antonio Ruiz, Basil L.{{{space()}}} Contovounesios, Björn - Lindström, Carlo Zancanaro, Christian Tietze, Daniel Mendler, Eli - Zaretskii, Fritz Grabo, Illia Ostapyshyn, Kévin Le Gouguec, Koen van - Greevenbroek, Kostadin Ninev, Madhavan Krishnan, Manuel Giraud, - Markus Beppler, Matthew Stevenson, Mauro Aranda, Nicolas De - Jaeghere, Paul David, Philip Kaludercic, Pierre Téchoueyres, Rudolf - Adamkovič, Stephen Gildea, Shreyas Ragavan, Stefan Kangas, Utkarsh - Singh, Vincent Murphy, Xinglu Chen, Yuanchen Xie, okamsn. ++ Contributions to code or documentation :: Aleksei Gusev, Alex + Griffin, Anders Johansson, Antonio Ruiz, Basil L.{{{space()}}} + Contovounesios, Björn Lindström, Carlo Zancanaro, Christian Tietze, + Daniel Mendler, Eli Zaretskii, Fritz Grabo, Illia Ostapyshyn, Kévin + Le Gouguec, Koen van Greevenbroek, Kostadin Ninev, Madhavan + Krishnan, Manuel Giraud, Markus Beppler, Matthew Stevenson, Mauro + Aranda, Nicolas De Jaeghere, Paul David, Philip Kaludercic, Pierre + Téchoueyres, Rudolf Adamkovič, Stephen Gildea, Shreyas Ragavan, + Stefan Kangas, Utkarsh Singh, Vincent Murphy, Xinglu Chen, Yuanchen + Xie, okamsn. + Ideas and user feedback :: Aaron Jensen, Adam Porter, Adam Spiers, - Adrian Manea, Alex Griffin, Alex Koen, Alex Peitsinis, Alexey - Shmalko, Alok Singh, Anders Johansson, André Alexandre Gomes, Andrew - Tropin, Antonio Hernández Blas, Arif Rezai, Augusto Stoffel, Basil - L.{{{space()}}} Contovounesios, Burgess Chang, Christian Tietze, - Christopher Dimech, Christopher League, Damien Cassou, Daniel - Mendler, Dario Gjorgjevski, David Edmondson, Davor Rotim, Divan - Santana, Eliraz Kedmi, Emanuele Michele Alberto Monterosso, Farasha - Euker, Feng Shu, Gautier Ponsinet, Gerry Agbobada, Gianluca Recchia, - Gonçalo Marrafa, Guilherme Semente, Gustavo Barros, Hörmetjan - Yiltiz, Ilja Kocken, Iris Garcia, Ivan Popovych, Jeremy Friesen, - Jerry Zhang, Johannes Grødem, John Haman, Jonas Collberg, Jorge - Morais, Joshua O'Connor, Julio C. Villasante, Kenta Usami, Kevin - Fleming, Kévin Le Gouguec, Kevin Kainan Li, Kostadin Ninev, Len + Adrian Manea, Aleksei Pirogov, Alex Griffin, Alex Koen, Alex + Peitsinis, Alexey Shmalko, Alok Singh, Anders Johansson, André + Alexandre Gomes, Andrew Tropin, Antonio Hernández Blas, Arif Rezai, + Augusto Stoffel, Basil L.{{{space()}}} Contovounesios, Burgess + Chang, Charlotte Van Petegem, Christian Tietze, Christopher Dimech, + Christopher League, Damien Cassou, Daniel Mendler, Dario + Gjorgjevski, David Edmondson, Davor Rotim, Divan Santana, Eliraz + Kedmi, Emanuele Michele Alberto Monterosso, Farasha Euker, Feng Shu, + Gautier Ponsinet, Gerry Agbobada, Gianluca Recchia, Gonçalo Marrafa, + Guilherme Semente, Gustavo Barros, Hörmetjan Yiltiz, Ilja Kocken, + Iris Garcia, Ivan Popovych, James Ferguson, Jeremy Friesen, Jerry + Zhang, Johannes Grødem, John Haman, Jonas Collberg, Jorge Morais, + Joshua O'Connor, Julio C. Villasante, Kenta Usami, Kevin Fleming, + Kévin Le Gouguec, Kevin Kainan Li, Kostadin Ninev, Laith Bahodi, Len Trigg, Lennart C. Karssen, Luis Miguel Castañeda, Magne Hov, Manuel Uberti, Mark Bestley, Mark Burton, Mark Simpson, Markus Beppler, - Matt Armstrong, Matthias Fuchs, Mauro Aranda, Maxime Tréca, Michael - Goldenberg, Morgan Smith, Morgan Willcock, Murilo Pereira, Nicky van - Foreest, Nicolas De Jaeghere, Pablo Stafforini, Paul Poloskov, - Pengji Zhang, Pete Kazmier, Peter Wu, Philip Kaludercic, Pierre - Téchoueyres, Przemysław Kryger, Robert Hepple, Roman Rudakov, Ryan - Phillips, Rytis Paškauskas, Rudolf Adamkovič, Sam Kleinman, Samuel - Culpepper, Saša Janiška, Shreyas Ragavan, Simon Pugnet, Tassilo - Horn, Thibaut Verron, Thomas Heartman, Togan Muftuoglu, Tony Zorman, - Trey Merkley, Tomasz Hołubowicz, Toon Claes, Uri Sharf, Utkarsh - Singh, Vincent Foley. As well as users: Ben, CsBigDataHub1, Emacs - Contrib, Eugene, Fourchaux, Fredrik, Moesasji, Nick, Summer Emacs, - TheBlob42, Trey, bepolymathe, bit9tream, derek-upham, doolio, - fleimgruber, gitrj95, iSeeU, jixiuf, okamsn, pRot0ta1p. + Matt Armstrong, Matthias Fuchs, Mattias Engdegård, Mauro Aranda, + Maxime Tréca, Michael Goldenberg, Morgan Smith, Morgan Willcock, + Murilo Pereira, Nicky van Foreest, Nicolas De Jaeghere, Pablo + Stafforini, Paul Poloskov, Pengji Zhang, Pete Kazmier, Peter Wu, + Philip Kaludercic, Pierre Téchoueyres, Przemysław Kryger, Robert + Hepple, Roman Rudakov, Ryan Phillips, Rytis Paškauskas, Rudolf + Adamkovič, Sam Kleinman, Samuel Culpepper, Saša Janiška, Shreyas + Ragavan, Simon Pugnet, Tassilo Horn, Thibaut Verron, Thomas + Heartman, Togan Muftuoglu, Tony Zorman, Trey Merkley, Tomasz + Hołubowicz, Toon Claes, Uri Sharf, Utkarsh Singh, Vincent Foley. As + well as users: Ben, CsBigDataHub1, Emacs Contrib, Eugene, Fourchaux, + Fredrik, Moesasji, Nick, Summer Emacs, TheBlob42, Trey, bepolymathe, + bit9tream, derek-upham, doolio, fleimgruber, gitrj95, iSeeU, jixiuf, + okamsn, pRot0ta1p, soaringbird, tumashu, wakamenod. + Packaging :: Basil L.{{{space()}}} Contovounesios, Eli Zaretskii, Glenn Morris, Mauro Aranda, Richard Stallman, Stefan Kangas (core @@ -6153,42 +4820,6 @@ themes' design and/or aspects of their functionality. All errors are my own. -* Other notes about the project -:properties: -:custom_id: h:13752581-4378-478c-af17-165b6e76bc1b -:end: -#+cindex: Development notes - -If you are curious about the principles that govern the development of -this project read the essay [[https://protesilaos.com/codelog/2020-03-17-design-modus-themes-emacs/][On the design of the Modus themes]] -(2020-03-17). - -Here are some more publications for those interested in the kind of work -that goes into this project (sometimes the commits also include details -of this sort): - -+ [[https://protesilaos.com/codelog/2020-05-10-modus-operandi-palette-review/][Modus Operandi theme subtle palette review]] (2020-05-10) -+ [[https://protesilaos.com/codelog/2020-06-13-modus-vivendi-palette-review/][Modus Vivendi theme subtle palette review]] (2020-06-13) -+ [[https://protesilaos.com/codelog/2020-07-04-modus-themes-faint-colours/][Modus themes: new "faint syntax" option]] (2020-07-04) -+ [[https://protesilaos.com/codelog/2020-07-08-modus-themes-nuanced-colours/][Modus themes: major review of "nuanced" colours]] (2020-07-08) -+ [[https://protesilaos.com/codelog/2020-09-14-modus-themes-review-blues/][Modus themes: review of blue colours]] (2020-09-14) -+ [[https://protesilaos.com/codelog/2020-12-27-modus-themes-review-rainbow-delimiters/][Modus themes: review rainbow-delimiters faces]] (2020-12-27) -+ [[https://protesilaos.com/codelog/2021-01-11-modus-themes-review-select-faint-colours/][Modus themes: review of select "faint" colours]] (2021-01-11) -+ [[https://protesilaos.com/codelog/2021-02-25-modus-themes-diffs-deuteranopia/][The Modus themes now cover deuteranopia in diffs]] (2021-02-25) -+ [[https://protesilaos.com/codelog/2021-06-02-modus-themes-org-agenda/][Introducing the variable modus-themes-org-agenda]] (2021-06-02) -+ [[https://protesilaos.com/codelog/2022-01-02-review-modus-themes-org-habit-colours/][Modus themes: review of the org-habit graph colours]] (2022-01-02) -+ [[https://protesilaos.com/codelog/2022-01-03-modus-themes-port-faq/][Re: VSCode or Vim ports of the Emacs modus-themes?]] (2022-01-03) -+ [[https://protesilaos.com/codelog/2022-04-20-modus-themes-case-study-avy/][Modus themes: case study on Avy faces and colour combinations]] (2022-04-20) -+ [[https://protesilaos.com/codelog/2022-04-21-modus-themes-colour-theory/][Emacs: colour theory and techniques used in the Modus themes]] (2022-04-21) - -And here are the canonical sources of this project: - -+ Manual :: <https://protesilaos.com/emacs/modus-themes> -+ Change Log :: <https://protesilaos.com/emacs/modus-themes-changelog> -+ Screenshots :: <https://protesilaos.com/emacs/modus-themes-pictures> -+ Git repository :: https://git.sr.ht/~protesilaos/modus-themes -+ Mailing list :: https://lists.sr.ht/~protesilaos/modus-themes - * GNU Free Documentation License :properties: :appendix: t diff --git a/doc/misc/newsticker.texi b/doc/misc/newsticker.texi index d71895da5db..4a0311cad42 100644 --- a/doc/misc/newsticker.texi +++ b/doc/misc/newsticker.texi @@ -307,11 +307,16 @@ news ticker. @findex newsticker-start-ticker @findex newsticker-stop-ticker +@vindex newsticker-ticker-period Headlines can be displayed in the echo area, either scrolling like messages in a stock-quote ticker, or just changing. This can be started with the command @code{newsticker-start-ticker}. It can be stopped with @code{newsticker-stop-ticker}. +The ticker by default runs continuously. To only run it once, at a +specific time interval, set the @code{newsticker-ticker-period} +variable. + @node Navigation @section Navigation @@ -542,8 +547,10 @@ are shown in the echo area, i.e., the ``ticker''. @itemize @item @vindex newsticker-display-interval +@vindex newsticker-ticker-period @vindex newsticker-scroll-smoothly -@code{newsticker-ticker-interval} and +@code{newsticker-ticker-interval}, +@code{newsticker-ticker-period}, and @code{newsticker-scroll-smoothly} define how headlines are shown in the echo area. @end itemize diff --git a/doc/misc/rcirc.texi b/doc/misc/rcirc.texi index 41930f154c2..6b10d1ab2a4 100644 --- a/doc/misc/rcirc.texi +++ b/doc/misc/rcirc.texi @@ -691,11 +691,11 @@ window is showing them), the mode line will now show you the abbreviated channel or nick name. Use @kbd{C-c C-@key{SPC}} to switch to these buffers. -@cindex rcirc-track-abbrevate-flag +@cindex rcirc-track-abbreviate-flag By default the channel names are abbreviated, set -@code{rcirc-track-abbrevate-flag} to a non-@code{nil} value. This might be -interesting if the IRC activities are not tracked in the mode line, -but somewhere else. +@code{rcirc-track-abbreviate-flag} to a non-@code{nil} value. This +might be interesting if the IRC activities are not tracked in the mode +line, but somewhere else. @vindex rcirc-mode-hook If you prefer not to load @code{rcirc} immediately, you can delay the diff --git a/doc/misc/sc.texi b/doc/misc/sc.texi index d4b39d4ee39..9bf7c36b481 100644 --- a/doc/misc/sc.texi +++ b/doc/misc/sc.texi @@ -404,7 +404,7 @@ from the alist with the @code{sc-mail-field} function. Thus, if the following fields were present in the original article: @example -Date:@: 08 April 1991, 17:32:09 EST +Date:@: 08 Apr 1991 17:32:09 -0500 Subject:@: Better get out your asbestos suit @end example @@ -415,7 +415,7 @@ then, the following lisp constructs return: @example (sc-mail-field "date") -==> "08 April 1991, 17:32:09 EST" +==> "08 Apr 1991 17:32:09 -0500" (sc-mail-field "subject") ==> "Better get out your asbestos suit" diff --git a/doc/misc/texinfo.tex b/doc/misc/texinfo.tex index 7858bf152c3..3cccf01d958 100644 --- a/doc/misc/texinfo.tex +++ b/doc/misc/texinfo.tex @@ -3,9 +3,9 @@ % Load plain if necessary, i.e., if running under initex. \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi % -\def\texinfoversion{2022-11-12.22} +\def\texinfoversion{2023-01-02.21} % -% Copyright 1985--1986, 1988, 1990--2023 Free Software Foundation, Inc. +% Copyright 1985, 1986, 1988, 1990-2023 Free Software Foundation, Inc. % % This texinfo.tex file is free software: you can redistribute it and/or % modify it under the terms of the GNU General Public License as @@ -58,12 +58,6 @@ \message{Loading texinfo [version \texinfoversion]:} -% If in a .fmt file, print the version number -% and turn on active characters that we couldn't do earlier because -% they might have appeared in the input file name. -\everyjob{\message{[Texinfo version \texinfoversion]}% - \catcode`+=\active \catcode`\_=\active} - % LaTeX's \typeout. This ensures that the messages it is used for % are identical in format to the corresponding ones from latex/pdflatex. \def\typeout{\immediate\write17}% @@ -530,7 +524,7 @@ % ... but they get defined via ``\envdef\foo{...}'': \long\def\envdef#1#2{\def#1{\startenvironment#1#2}} -\def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}} +\long\def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}} % Check whether we're in the right environment: \def\checkenv#1{% @@ -591,6 +585,9 @@ % @/ allows a line break. \let\/=\allowbreak +% @- allows explicit insertion of hyphenation points +\def\-{\discretionary{\normaldash}{}{}}% + % @. is an end-of-sentence period. \def\.{.\spacefactor=\endofsentencespacefactor\space} @@ -1197,13 +1194,17 @@ output) for that.)} % % Set color, and create a mark which defines \thiscolor accordingly, % so that \makeheadline knows which color to restore. + \def\curcolor{0 0 0}% \def\setcolor#1{% - \xdef\currentcolordefs{\gdef\noexpand\thiscolor{#1}}% - \domark - \pdfsetcolor{#1}% + \ifx#1\curcolor\else + \xdef\currentcolordefs{\gdef\noexpand\thiscolor{#1}}% + \domark + \pdfsetcolor{#1}% + \xdef\curcolor{#1}% + \fi } % - \def\maincolor{\rgbBlack} + \let\maincolor\rgbBlack \pdfsetcolor{\maincolor} \edef\thiscolor{\maincolor} \def\currentcolordefs{} @@ -1359,7 +1360,7 @@ output) for that.)} % % by default, use black for everything. \def\urlcolor{\rgbBlack} - \def\linkcolor{\rgbBlack} + \let\linkcolor\rgbBlack \def\endlink{\setcolor{\maincolor}\pdfendlink} % % Adding outlines to PDF; macros for calculating structure of outlines @@ -1537,9 +1538,10 @@ output) for that.)} \next} \def\makelink{\addtokens{\toksB}% {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} - \def\pdflink#1{% + \def\pdflink#1{\pdflinkpage{#1}{#1}}% + \def\pdflinkpage#1#2{% \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}} - \setcolor{\linkcolor}#1\endlink} + \setcolor{\linkcolor}#2\endlink} \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} \else % non-pdf mode @@ -1786,10 +1788,11 @@ output) for that.)} \next} \def\makelink{\addtokens{\toksB}% {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} - \def\pdflink#1{% + \def\pdflink#1{\pdflinkpage{#1}{#1}}% + \def\pdflinkpage#1#2{% \special{pdf:bann << /Border [0 0 0] /Type /Annot /Subtype /Link /A << /S /GoTo /D (#1) >> >>}% - \setcolor{\linkcolor}#1\endlink} + \setcolor{\linkcolor}#2\endlink} \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} % % @@ -2134,6 +2137,11 @@ end \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% \fi\fi +% +% This is what gets called when #5 of \setfont is empty. +\let\cmap\gobble +% +% (end of cmaps) % Set the font macro #1 to the font named \fontprefix#2. @@ -2149,11 +2157,10 @@ end \def\setfont#1#2#3#4#5{% \font#1=\fontprefix#2#3 scaled #4 \csname cmap#5\endcsname#1% + \ifx#2\ttshape\hyphenchar#1=-1 \fi + \ifx#2\ttbshape\hyphenchar#1=-1 \fi + \ifx#2\ttslshape\hyphenchar#1=-1 \fi } -% This is what gets called when #5 of \setfont is empty. -\let\cmap\gobble -% -% (end of cmaps) % Use cm as the default font prefix. % To specify the font prefix, you must define \fontprefix @@ -2674,6 +2681,7 @@ end \gdef\setcodequotes{\let`\codequoteleft \let'\codequoteright} \gdef\setregularquotes{\let`\lq \let'\rq} } +\setregularquotes % Allow an option to not use regular directed right quote/apostrophe % (char 0x27), but instead the undirected quote from cmtt (char 0x0d). @@ -2815,13 +2823,6 @@ end % @sansserif, explicit sans. \def\sansserif#1{{\sf #1}} -% We can't just use \exhyphenpenalty, because that only has effect at -% the end of a paragraph. Restore normal hyphenation at the end of the -% group within which \nohyphenation is presumably called. -% -\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} -\def\restorehyphenation{\hyphenchar\font = `- } - \newif\iffrenchspacing \frenchspacingfalse @@ -2890,27 +2891,29 @@ end % Switch to typewriter. \tt % - % But `\ ' produces the large typewriter interword space. + % `\ ' produces the large typewriter interword space. \def\ {{\spaceskip = 0pt{} }}% % - % Turn off hyphenation. - \nohyphenation - % \plainfrenchspacing #1% }% \null % reset spacefactor to 1000 } -% We *must* turn on hyphenation at `-' and `_' in @code. -% (But see \codedashfinish below.) +% This is for LuaTeX: It is not sufficient to disable hyphenation at +% explicit dashes by setting `\hyphenchar` to -1. +\def\dashnobreak{% + \normaldash + \penalty 10000 } + +% We must turn on hyphenation at `-' and `_' in @code. % Otherwise, it is too hard to avoid overfull hboxes % in the Emacs manual, the Library manual, etc. +% We explicitly allow hyphenation at these characters +% using \discretionary. % -% Unfortunately, TeX uses one parameter (\hyphenchar) to control -% both hyphenation at - and hyphenation within words. -% We must therefore turn them both off (\tclose does that) -% and arrange explicitly to hyphenate at a dash. -- rms. +% Hyphenation at - and hyphenation within words was turned off +% by default for the tt fonts using the \hyphenchar parameter of TeX. { \catcode`\-=\active \catcode`\_=\active \catcode`\'=\active \catcode`\`=\active @@ -2923,7 +2926,7 @@ end \let-\codedash \let_\codeunder \else - \let-\normaldash + \let-\dashnobreak \let_\realunder \fi % Given -foo (with a single dash), we do not want to allow a break @@ -3200,7 +3203,7 @@ end % definition of @key with no lozenge. % -\def\key#1{{\setregularquotes \nohyphenation \tt #1}\null} +\def\key#1{{\setregularquotes \tt #1}\null} % @clicksequence{File @click{} Open ...} \def\clicksequence#1{\begingroup #1\endgroup} @@ -3740,13 +3743,14 @@ $$% want the contents after the title page.}}% \parseargdef\shorttitlepage{% - \begingroup \hbox{}\vskip 1.5in \chaprm \centerline{#1}% - \endgroup\page\hbox{}\page} + {\headingsoff \begingroup \hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page}\pageone} \envdef\titlepage{% % Open one extra group, as we want to close it in the middle of \Etitlepage. \begingroup \parindent=0pt \textfonts + \headingsoff % Leave some space at the very top of the page. \vglue\titlepagetopglue % No rule at page bottom unless we print one at the top with @title. @@ -3774,11 +3778,9 @@ $$% % If we use the new definition of \page, we always get a blank page % after the title page, which we certainly don't want. \oldpage + \pageone \endgroup % - % Need this before the \...aftertitlepage checks so that if they are - % in effect the toc pages will come out with page numbers. - \HEADINGSon } \def\finishtitlepage{% @@ -3947,7 +3949,6 @@ $$% } \def\HEADINGSoff{{\globaldefs=1 \headingsoff}} % global setting -\HEADINGSoff % it's the default % When we turn headings on, set the page number to 1. \def\pageone{ @@ -3971,7 +3972,7 @@ $$% \pageone \HEADINGSsinglex } -\def\HEADINGSon{\HEADINGSdouble} +% \def\HEADINGSon{\HEADINGSdouble} % defined by \CHAPPAGon \def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} \let\HEADINGSdoubleafter=\HEADINGSafter @@ -4793,21 +4794,6 @@ $$% \def\docodeindexxxx #1{\docind{\indexname}{#1}} -% Used for the aux, toc and index files to prevent expansion of Texinfo -% commands. -% -\def\atdummies{% - \definedummyletter\@% - \definedummyletter\ % - \definedummyletter\{% - \definedummyletter\}% - \definedummyletter\&% - % - % Do the redefinitions. - \definedummies - \otherbackslash -} - % \definedummyword defines \#1 as \string\#1\space, thus effectively % preventing its expansion. This is used only for control words, % not control letters, because the \space would be incorrect for @@ -4823,110 +4809,91 @@ $$% % \def\definedummyword #1{\def#1{\string#1\space}}% \def\definedummyletter#1{\def#1{\string#1}}% -\let\definedummyaccent\definedummyletter -% Called from \atdummies to prevent the expansion of commands. +% Used for the aux, toc and index files to prevent expansion of Texinfo +% commands. Most of the commands are controlled through the +% \ifdummies conditional. % -\def\definedummies{% +\def\atdummies{% + \dummiestrue % - \let\commondummyword\definedummyword - \let\commondummyletter\definedummyletter - \let\commondummyaccent\definedummyaccent - \commondummiesnofonts + \definedummyletter\@% + \definedummyletter\ % + \definedummyletter\{% + \definedummyletter\}% + \definedummyletter\&% % \definedummyletter\_% \definedummyletter\-% % - % Non-English letters. - \definedummyword\AA - \definedummyword\AE - \definedummyword\DH - \definedummyword\L - \definedummyword\O - \definedummyword\OE - \definedummyword\TH - \definedummyword\aa - \definedummyword\ae - \definedummyword\dh - \definedummyword\exclamdown - \definedummyword\l - \definedummyword\o - \definedummyword\oe - \definedummyword\ordf - \definedummyword\ordm - \definedummyword\questiondown - \definedummyword\ss - \definedummyword\th - % - % Although these internal commands shouldn't show up, sometimes they do. - \definedummyword\bf - \definedummyword\gtr - \definedummyword\hat - \definedummyword\less - \definedummyword\sf - \definedummyword\sl - \definedummyword\tclose - \definedummyword\tt - % - \definedummyword\LaTeX - \definedummyword\TeX - % - % Assorted special characters. - \definedummyword\ampchar - \definedummyword\atchar - \definedummyword\arrow - \definedummyword\backslashchar - \definedummyword\bullet - \definedummyword\comma - \definedummyword\copyright - \definedummyword\registeredsymbol - \definedummyword\dots - \definedummyword\enddots - \definedummyword\entrybreak - \definedummyword\equiv - \definedummyword\error - \definedummyword\euro - \definedummyword\expansion - \definedummyword\geq - \definedummyword\guillemetleft - \definedummyword\guillemetright - \definedummyword\guilsinglleft - \definedummyword\guilsinglright - \definedummyword\lbracechar - \definedummyword\leq - \definedummyword\mathopsup - \definedummyword\minus - \definedummyword\ogonek - \definedummyword\pounds - \definedummyword\point - \definedummyword\print - \definedummyword\quotedblbase - \definedummyword\quotedblleft - \definedummyword\quotedblright - \definedummyword\quoteleft - \definedummyword\quoteright - \definedummyword\quotesinglbase - \definedummyword\rbracechar - \definedummyword\result - \definedummyword\sub - \definedummyword\sup - \definedummyword\textdegree - % \definedummyword\subentry % % We want to disable all macros so that they are not expanded by \write. + \let\commondummyword\definedummyword \macrolist \let\value\dummyvalue % - \normalturnoffactive -} - -% \commondummiesnofonts: common to \definedummies and \indexnofonts. -% Define \commondummyletter, \commondummyaccent and \commondummyword before -% using. Used for accents, font commands, and various control letters. -% -\def\commondummiesnofonts{% - % Control letters and accents. + \turnoffactive +} + +\newif\ifdummies +\newif\ifindexnofonts + +\def\commondummyletter#1{% + \expandafter\let\csname\string#1:impl\endcsname#1% + \edef#1{% + \noexpand\ifindexnofonts + % empty expansion + \noexpand\else + \noexpand\ifdummies\string#1% + \noexpand\else + \noexpand\jumptwofi % dispose of the \fi + \expandafter\noexpand\csname\string#1:impl\endcsname + \noexpand\fi + \noexpand\fi}% +} + +\def\commondummyaccent#1{% + \expandafter\let\csname\string#1:impl\endcsname#1% + \edef#1{% + \noexpand\ifindexnofonts + \noexpand\expandafter % dispose of \else ... \fi + \noexpand\asis + \noexpand\else + \noexpand\ifdummies\string#1% + \noexpand\else + \noexpand\jumptwofi % dispose of the \fi + \expandafter\noexpand\csname\string#1:impl\endcsname + \noexpand\fi + \noexpand\fi}% +} + +% Like \commondummyaccent but add a \space at the end of the dummy expansion +% #2 is the expansion used for \indexnofonts. #2 is always followed by +% \asis to remove a pair of following braces. +\def\commondummyword#1#2{% + \expandafter\let\csname\string#1:impl\endcsname#1% + \expandafter\def\csname\string#1:ixnf\endcsname{#2\asis}% + \edef#1{% + \noexpand\ifindexnofonts + \noexpand\expandafter % dispose of \else ... \fi + \expandafter\noexpand\csname\string#1:ixnf\endcsname + \noexpand\else + \noexpand\ifdummies\string#1\space + \noexpand\else + \noexpand\jumptwofi % dispose of the \fi \fi + \expandafter\noexpand\csname\string#1:impl\endcsname + \noexpand\fi + \noexpand\fi}% +} +\def\jumptwofi#1\fi\fi{\fi\fi#1} + +% For \atdummies and \indexnofonts. \atdummies sets +% \dummiestrue and \indexnofonts sets \indexnofontstrue. +\def\definedummies{ + % @-sign is always an escape character when reading auxiliary files + \escapechar = `\@ + % \commondummyletter\!% \commondummyaccent\"% \commondummyaccent\'% @@ -4940,58 +4907,123 @@ $$% \commondummyaccent\^% \commondummyaccent\`% \commondummyaccent\~% - \commondummyword\u - \commondummyword\v - \commondummyword\H - \commondummyword\dotaccent - \commondummyword\ogonek - \commondummyword\ringaccent - \commondummyword\tieaccent - \commondummyword\ubaraccent - \commondummyword\udotaccent - \commondummyword\dotless + % + % Control letters and accents. + \commondummyword\u {}% + \commondummyword\v {}% + \commondummyword\H {}% + \commondummyword\dotaccent {}% + \commondummyword\ogonek {}% + \commondummyword\ringaccent {}% + \commondummyword\tieaccent {}% + \commondummyword\ubaraccent {}% + \commondummyword\udotaccent {}% + \commondummyword\dotless {}% % % Texinfo font commands. - \commondummyword\b - \commondummyword\i - \commondummyword\r - \commondummyword\sansserif - \commondummyword\sc - \commondummyword\slanted - \commondummyword\t + \commondummyword\b {}% + \commondummyword\i {}% + \commondummyword\r {}% + \commondummyword\sansserif {}% + \commondummyword\sc {}% + \commondummyword\slanted {}% + \commondummyword\t {}% % % Commands that take arguments. - \commondummyword\abbr - \commondummyword\acronym - \commondummyword\anchor - \commondummyword\cite - \commondummyword\code - \commondummyword\command - \commondummyword\dfn - \commondummyword\dmn - \commondummyword\email - \commondummyword\emph - \commondummyword\env - \commondummyword\file - \commondummyword\image - \commondummyword\indicateurl - \commondummyword\inforef - \commondummyword\kbd - \commondummyword\key - \commondummyword\math - \commondummyword\option - \commondummyword\pxref - \commondummyword\ref - \commondummyword\samp - \commondummyword\strong - \commondummyword\tie - \commondummyword\U - \commondummyword\uref - \commondummyword\url - \commondummyword\var - \commondummyword\verb - \commondummyword\w - \commondummyword\xref + \commondummyword\abbr {}% + \commondummyword\acronym {}% + \commondummyword\anchor {}% + \commondummyword\cite {}% + \commondummyword\code {}% + \commondummyword\command {}% + \commondummyword\dfn {}% + \commondummyword\dmn {}% + \commondummyword\email {}% + \commondummyword\emph {}% + \commondummyword\env {}% + \commondummyword\file {}% + \commondummyword\image {}% + \commondummyword\indicateurl{}% + \commondummyword\inforef {}% + \commondummyword\kbd {}% + \commondummyword\key {}% + \commondummyword\math {}% + \commondummyword\option {}% + \commondummyword\pxref {}% + \commondummyword\ref {}% + \commondummyword\samp {}% + \commondummyword\strong {}% + \commondummyword\tie {}% + \commondummyword\U {}% + \commondummyword\uref {}% + \commondummyword\url {}% + \commondummyword\var {}% + \commondummyword\verb {}% + \commondummyword\w {}% + \commondummyword\xref {}% + % + \commondummyword\AA {AA}% + \commondummyword\AE {AE}% + \commondummyword\DH {DZZ}% + \commondummyword\L {L}% + \commondummyword\O {O}% + \commondummyword\OE {OE}% + \commondummyword\TH {TH}% + \commondummyword\aa {aa}% + \commondummyword\ae {ae}% + \commondummyword\dh {dzz}% + \commondummyword\exclamdown {!}% + \commondummyword\l {l}% + \commondummyword\o {o}% + \commondummyword\oe {oe}% + \commondummyword\ordf {a}% + \commondummyword\ordm {o}% + \commondummyword\questiondown {?}% + \commondummyword\ss {ss}% + \commondummyword\th {th}% + % + \commondummyword\LaTeX {LaTeX}% + \commondummyword\TeX {TeX}% + % + % Assorted special characters. + \commondummyword\ampchar {\normalamp}% + \commondummyword\atchar {\@}% + \commondummyword\arrow {->}% + \commondummyword\backslashchar {}% + \commondummyword\bullet {bullet}% + \commondummyword\comma {,}% + \commondummyword\copyright {copyright}% + \commondummyword\dots {...}% + \commondummyword\enddots {...}% + \commondummyword\entrybreak {}% + \commondummyword\equiv {===}% + \commondummyword\error {error}% + \commondummyword\euro {euro}% + \commondummyword\expansion {==>}% + \commondummyword\geq {>=}% + \commondummyword\guillemetleft {<<}% + \commondummyword\guillemetright {>>}% + \commondummyword\guilsinglleft {<}% + \commondummyword\guilsinglright {>}% + \commondummyword\lbracechar {\{}% + \commondummyword\leq {<=}% + \commondummyword\mathopsup {sup}% + \commondummyword\minus {-}% + \commondummyword\pounds {pounds}% + \commondummyword\point {.}% + \commondummyword\print {-|}% + \commondummyword\quotedblbase {"}% + \commondummyword\quotedblleft {"}% + \commondummyword\quotedblright {"}% + \commondummyword\quoteleft {`}% + \commondummyword\quoteright {'}% + \commondummyword\quotesinglbase {,}% + \commondummyword\rbracechar {\}}% + \commondummyword\registeredsymbol {R}% + \commondummyword\result {=>}% + \commondummyword\sub {}% + \commondummyword\sup {}% + \commondummyword\textdegree {o}% } \let\indexlbrace\relax @@ -5042,18 +5074,7 @@ $$% % would be for a given command (usually its argument). % \def\indexnofonts{% - % Accent commands should become @asis. - \def\commondummyaccent##1{\let##1\asis}% - % We can just ignore other control letters. - \def\commondummyletter##1{\let##1\empty}% - % All control words become @asis by default; overrides below. - \let\commondummyword\commondummyaccent - \commondummiesnofonts - % - % Don't no-op \tt, since it isn't a user-level command - % and is used in the definitions of the active chars like <, >, |, etc. - % Likewise with the other plain tex font commands. - %\let\tt=\asis + \indexnofontstrue % \def\ { }% \def\@{@}% @@ -5065,65 +5086,6 @@ $$% \let\lbracechar\{% \let\rbracechar\}% % - % Non-English letters. - \def\AA{AA}% - \def\AE{AE}% - \def\DH{DZZ}% - \def\L{L}% - \def\OE{OE}% - \def\O{O}% - \def\TH{TH}% - \def\aa{aa}% - \def\ae{ae}% - \def\dh{dzz}% - \def\exclamdown{!}% - \def\l{l}% - \def\oe{oe}% - \def\ordf{a}% - \def\ordm{o}% - \def\o{o}% - \def\questiondown{?}% - \def\ss{ss}% - \def\th{th}% - % - \let\do\indexnofontsdef - % - \do\LaTeX{LaTeX}% - \do\TeX{TeX}% - % - % Assorted special characters. - \do\atchar{@}% - \do\arrow{->}% - \do\bullet{bullet}% - \do\comma{,}% - \do\copyright{copyright}% - \do\dots{...}% - \do\enddots{...}% - \do\equiv{==}% - \do\error{error}% - \do\euro{euro}% - \do\expansion{==>}% - \do\geq{>=}% - \do\guillemetleft{<<}% - \do\guillemetright{>>}% - \do\guilsinglleft{<}% - \do\guilsinglright{>}% - \do\leq{<=}% - \do\lbracechar{\{}% - \do\minus{-}% - \do\point{.}% - \do\pounds{pounds}% - \do\print{-|}% - \do\quotedblbase{"}% - \do\quotedblleft{"}% - \do\quotedblright{"}% - \do\quoteleft{`}% - \do\quoteright{'}% - \do\quotesinglbase{,}% - \do\rbracechar{\}}% - \do\registeredsymbol{R}% - \do\result{=>}% - \do\textdegree{o}% % % We need to get rid of all macros, leaving only the arguments (if present). % Of course this is not nearly correct, but it is the best we can do for now. @@ -5135,14 +5097,11 @@ $$% % to take a single TeX argument. The case of a macro invocation that % goes to end-of-line is not handled. % + \def\commondummyword##1{\let##1\asis}% \macrolist \let\value\indexnofontsvalue } -% Give the control sequence a definition that removes the {} that follows -% its use, e.g. @AA{} -> AA -\def\indexnofontsdef#1#2{\def#1##1{#2}}% - @@ -5616,6 +5575,11 @@ might help (with 'rm \jobname.?? \jobname.??s')% \newdimen\entryrightmargin \entryrightmargin=0pt +% for PDF output, whether to make the text of the entry a link to the page +% number. set for @contents and @shortcontents where there is only one +% page number. +\newif\iflinkentrytext + % \entry typesets a paragraph consisting of the text (#1), dot leaders, and % then page number (#2) flushed to the right margin. It is used for index % and table of contents entries. The paragraph is indented by \leftskip. @@ -5642,7 +5606,7 @@ might help (with 'rm \jobname.?? \jobname.??s')% } \def\entrybreak{\unskip\space\ignorespaces}% \def\doentry{% - % Save the text of the entry + % Save the text of the entry in \boxA \global\setbox\boxA=\hbox\bgroup \bgroup % Instead of the swallowed brace. \noindent @@ -5652,12 +5616,21 @@ might help (with 'rm \jobname.?? \jobname.??s')% % with catcodes occurring. } {\catcode`\@=11 +% #1 is the page number \gdef\finishentry#1{% - \egroup % end box A + \egroup % end \boxA \dimen@ = \wd\boxA % Length of text of entry + % add any leaders and page number to \boxA. \global\setbox\boxA=\hbox\bgroup - \unhbox\boxA - % #1 is the page number. + \ifpdforxetex + \iflinkentrytext + \pdflinkpage{#1}{\unhbox\boxA}% + \else + \unhbox\boxA + \fi + \else + \unhbox\boxA + \fi % % Get the width of the page numbers, and only use % leaders if they are present. @@ -5676,6 +5649,8 @@ might help (with 'rm \jobname.?? \jobname.??s')% \fi \fi \egroup % end \boxA + % + % now output \ifdim\wd\boxB = 0pt \noindent\unhbox\boxA\par \nobreak @@ -6375,7 +6350,7 @@ might help (with 'rm \jobname.?? \jobname.??s')% \fi } -\parseargdef\setchapternewpage{\csname CHAPPAG#1\endcsname} +\parseargdef\setchapternewpage{\csname CHAPPAG#1\endcsname\HEADINGSon} \def\CHAPPAGoff{% \global\let\contentsalignmacro = \chappager @@ -6392,7 +6367,7 @@ might help (with 'rm \jobname.?? \jobname.??s')% \global\let\pchapsepmacro=\chapoddpage \global\def\HEADINGSon{\HEADINGSdouble}} -\CHAPPAGon +\setchapternewpage on % \chapmacro - Chapter opening. % @@ -6772,6 +6747,7 @@ might help (with 'rm \jobname.?? \jobname.??s')% \def\thistitle{}% no title in double-sided headings % Record where the Roman numerals started. \ifnum\romancount=0 \global\romancount=\pagecount \fi + \linkentrytexttrue } % \raggedbottom in plain.tex hardcodes \topskip so override it @@ -6899,7 +6875,7 @@ might help (with 'rm \jobname.?? \jobname.??s')% % Chapters, in the short toc. % See comments in \dochapentry re vbox and related settings. \def\shortchapentry#1#2#3#4{% - \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}% + \tocentry{\shortchaplabel{#2}\labelspace #1}{#4}% } % Appendices, in the main contents. @@ -6914,7 +6890,7 @@ might help (with 'rm \jobname.?? \jobname.??s')% % Unnumbered chapters. \def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}} -\def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}} +\def\shortunnchapentry#1#2#3#4{\tocentry{#1}{#4}} % Sections. \def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}} @@ -6946,24 +6922,24 @@ might help (with 'rm \jobname.?? \jobname.??s')% % Move the page numbers slightly to the right \advance\entryrightmargin by -0.05em \chapentryfonts - \tocentry{#1}{\dopageno\bgroup#2\egroup}% + \tocentry{#1}{#2}% \endgroup \nobreak\vskip .25\baselineskip plus.1\baselineskip } \def\dosecentry#1#2{\begingroup \secentryfonts \leftskip=\tocindent - \tocentry{#1}{\dopageno\bgroup#2\egroup}% + \tocentry{#1}{#2}% \endgroup} \def\dosubsecentry#1#2{\begingroup \subsecentryfonts \leftskip=2\tocindent - \tocentry{#1}{\dopageno\bgroup#2\egroup}% + \tocentry{#1}{#2}% \endgroup} \def\dosubsubsecentry#1#2{\begingroup \subsubsecentryfonts \leftskip=3\tocindent - \tocentry{#1}{\dopageno\bgroup#2\egroup}% + \tocentry{#1}{#2}% \endgroup} % We use the same \entry macro as for the index entries. @@ -6972,9 +6948,6 @@ might help (with 'rm \jobname.?? \jobname.??s')% % Space between chapter (or whatever) number and the title. \def\labelspace{\hskip1em \relax} -\def\dopageno#1{{\rm #1}} -\def\doshortpageno#1{{\rm #1}} - \def\chapentryfonts{\secfonts \rm} \def\secentryfonts{\textfonts} \def\subsecentryfonts{\textfonts} @@ -7119,8 +7092,7 @@ might help (with 'rm \jobname.?? \jobname.??s')% \newdimen\cartouter\newdimen\cartinner \newskip\normbskip\newskip\normpskip\newskip\normlskip - -\envdef\cartouche{% +\envparseargdef\cartouche{% \cartouchefontdefs \ifhmode\par\fi % can't be in the midst of a paragraph. \startsavinginserts @@ -7150,16 +7122,19 @@ might help (with 'rm \jobname.?? \jobname.??s')% \baselineskip=0pt\parskip=0pt\lineskip=0pt \carttop \hbox\bgroup - \hskip\lskip - \vrule\kern3pt - \vbox\bgroup - \kern3pt - \hsize=\cartinner - \baselineskip=\normbskip - \lineskip=\normlskip - \parskip=\normpskip - \vskip -\parskip - \comment % For explanation, see the end of def\group. + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \hsize=\cartinner + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \def\arg{#1}% + \ifx\arg\empty\else + \centerV{\hfil \bf #1 \hfil}% + \fi + \kern3pt + \vskip -\parskip } \def\Ecartouche{% \ifhmode\par\fi @@ -7410,7 +7385,7 @@ might help (with 'rm \jobname.?? \jobname.??s')% \endgroup % \def\setupverb{% - \tt % easiest (and conventionally used) font for verbatim + \tt \def\par{\leavevmode\endgraf}% \setcodequotes \tabeightspaces @@ -7587,32 +7562,28 @@ might help (with 'rm \jobname.?? \jobname.??s')% \exdentamount=\defbodyindent } -\def\dodefunx#1{% - % First, check whether we are in the right environment: - \checkenv#1% - % - % As above, allow line break if we have multiple x headers in a row. - % It's not a great place, though. - \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi - % - % And now, it's time to reuse the body of the original defun: - \expandafter\gobbledefun#1% -} -\def\gobbledefun#1\startdefun{} +\newtoks\defidx +\newtoks\deftext + +\def\useindex#1{\defidx={#1}\ignorespaces} -% \printdefunline \deffnheader{text} +% Called as \printdefunline \deffooheader{text} % \def\printdefunline#1#2{% \begingroup \plainfrenchspacing - % call \deffnheader: + % call \deffooheader: #1#2 \endheader + % create the index entry + \defcharsdefault + \edef\temp{\noexpand\doind{\the\defidx}{\the\deftext}}% + \temp % common ending: \interlinepenalty = 10000 \advance\rightskip by 0pt plus 1fil\relax \endgraf \nobreak\vskip -\parskip - \penalty\defunpenalty % signal to \startdefun and \dodefunx + \penalty\defunpenalty % signal to \startdefun and \deffoox % Some of the @defun-type tags do not enable magic parentheses, % rendering the following check redundant. But we don't optimize. \checkparencounts @@ -7621,7 +7592,7 @@ might help (with 'rm \jobname.?? \jobname.??s')% \def\Edefun{\endgraf\medbreak} -% \makedefun{deffoo}{ (definition of \deffooheader) } +% \makedefun{deffoo} (\deffooheader parameters) { (\deffooheader expansion) } % % Define \deffoo, \deffoox \Edeffoo and \deffooheader. \def\makedefun#1{% @@ -7636,8 +7607,18 @@ might help (with 'rm \jobname.?? \jobname.??s')% \doingtypefnfalse % distinguish typed functions from all else \parseargusing\activeparens{\printdefunline#3}% }% - \def#2{\dodefunx#1}% - \def#3% + \def#2{% + % First, check whether we are in the right environment: + \checkenv#1% + % + % As in \startdefun, allow line break if we have multiple x headers + % in a row. It's not a great place, though. + \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi + % + \doingtypefnfalse % distinguish typed functions from all else + \parseargusing\activeparens{\printdefunline#3}% + }% + \def#3% definition of \deffooheader follows } \newif\ifdoingtypefn % doing typed function? @@ -7662,18 +7643,23 @@ might help (with 'rm \jobname.?? \jobname.??s')% \fi\fi } +\def\defind#1#2{ + \defidx={#1}% + \deftext={#2}% +} + % Untyped functions: % @deffn category name args \makedefun{deffn}#1 #2 #3\endheader{% - \doind{fn}{\code{#2}}% + \defind{fn}{\code{#2}}% \defname{#1}{}{#2}\magicamp\defunargs{#3\unskip}% } % @defop category class name args \makedefun{defop}#1 {\defopheaderx{#1\ \putwordon}} \def\defopheaderx#1#2 #3 #4\endheader{% - \doind{fn}{\code{#3}\space\putwordon\ \code{#2}}% + \defind{fn}{\code{#3}\space\putwordon\ \code{#2}}% \defname{#1\ \code{#2}}{}{#3}\magicamp\defunargs{#4\unskip}% } @@ -7681,7 +7667,7 @@ might help (with 'rm \jobname.?? \jobname.??s')% % @deftypefn category type name args \makedefun{deftypefn}#1 #2 #3 #4\endheader{% - \doind{fn}{\code{#3}}% + \defind{fn}{\code{#3}}% \doingtypefntrue \defname{#1}{#2}{#3}\defunargs{#4\unskip}% } @@ -7689,7 +7675,7 @@ might help (with 'rm \jobname.?? \jobname.??s')% % @deftypeop category class type name args \makedefun{deftypeop}#1 {\deftypeopheaderx{#1\ \putwordon}} \def\deftypeopheaderx#1#2 #3 #4 #5\endheader{% - \doind{fn}{\code{#4}\space\putwordon\ \code{#1\ \code{#2}}}% + \defind{fn}{\code{#4}\space\putwordon\ \code{#1\ \code{#2}}}% \doingtypefntrue \defname{#1\ \code{#2}}{#3}{#4}\defunargs{#5\unskip}% } @@ -7698,14 +7684,14 @@ might help (with 'rm \jobname.?? \jobname.??s')% % @deftypevr category type var args \makedefun{deftypevr}#1 #2 #3 #4\endheader{% - \doind{vr}{\code{#3}}% + \defind{vr}{\code{#3}}% \defname{#1}{#2}{#3}\defunargs{#4\unskip}% } % @deftypecv category class type var args \makedefun{deftypecv}#1 {\deftypecvheaderx{#1\ \putwordof}} \def\deftypecvheaderx#1#2 #3 #4 #5\endheader{% - \doind{vr}{\code{#4}\space\putwordof\ \code{#2}}% + \defind{vr}{\code{#4}\space\putwordof\ \code{#2}}% \defname{#1\ \code{#2}}{#3}{#4}\defunargs{#5\unskip}% } @@ -7722,7 +7708,7 @@ might help (with 'rm \jobname.?? \jobname.??s')% % @deftp category name args \makedefun{deftp}#1 #2 #3\endheader{% - \doind{tp}{\code{#2}}% + \defind{tp}{\code{#2}}% \defname{#1}{}{#2}\defunargs{#3\unskip}% } @@ -7831,10 +7817,12 @@ might help (with 'rm \jobname.?? \jobname.??s')% % Print arguments. Use slanted for @def*, typewriter for @deftype*. \def\defunargs#1{% - \df \ifdoingtypefn \tt \else \sl \fi - \ifflagclear{txicodevaristt}{}% - {\def\var##1{{\setregularquotes \ttsl ##1}}}% - #1% + \bgroup + \df \ifdoingtypefn \tt \else \sl \fi + \ifflagclear{txicodevaristt}{}% + {\def\var##1{{\setregularquotes \ttsl ##1}}}% + #1% + \egroup } % We want ()&[] to print specially on the defun line. @@ -9873,12 +9861,10 @@ directory should work if nowhere else does.} % For native Unicode handling (XeTeX and LuaTeX) \nativeunicodechardefs \else - % For treating UTF-8 as byte sequences (TeX, eTeX and pdfTeX) + % For treating UTF-8 as byte sequences (TeX, eTeX and pdfTeX). + % Since we already invoke \utfeightchardefs at the top level, + % making non-ascii chars active is sufficient. \setnonasciicharscatcode\active - % since we already invoked \utfeightchardefs at the top level - % (below), do not re-invoke it, otherwise our check for duplicated - % definitions gets triggered. Making non-ascii chars active is - % sufficient. \fi % \else @@ -9903,7 +9889,6 @@ directory should work if nowhere else does.} \fi } -% emacs-page % A message to be logged when using a character that isn't available % the default font encoding (OT1). % @@ -9912,12 +9897,6 @@ directory should work if nowhere else does.} % Take account of \c (plain) vs. \, (Texinfo) difference. \def\cedilla#1{\ifx\c\ptexc\c{#1}\else\,{#1}\fi} -% First, make active non-ASCII characters in order for them to be -% correctly categorized when TeX reads the replacement text of -% macros containing the character definitions. -\setnonasciicharscatcode\active -% - \def\gdefchar#1#2{% \gdef#1{% \ifpassthroughchars @@ -9927,8 +9906,14 @@ directory should work if nowhere else does.} \fi }} +\begingroup + +% Make non-ASCII characters active for defining the character definition +% macros. +\setnonasciicharscatcode\active + % Latin1 (ISO-8859-1) character definitions. -\def\latonechardefs{% +\gdef\latonechardefs{% \gdefchar^^a0{\tie} \gdefchar^^a1{\exclamdown} \gdefchar^^a2{{\tcfont \char162}} % cent @@ -10033,7 +10018,7 @@ directory should work if nowhere else does.} } % Latin9 (ISO-8859-15) encoding character definitions. -\def\latninechardefs{% +\gdef\latninechardefs{% % Encoding is almost identical to Latin1. \latonechardefs % @@ -10048,7 +10033,7 @@ directory should work if nowhere else does.} } % Latin2 (ISO-8859-2) character definitions. -\def\lattwochardefs{% +\gdef\lattwochardefs{% \gdefchar^^a0{\tie} \gdefchar^^a1{\ogonek{A}} \gdefchar^^a2{\u{}} @@ -10152,6 +10137,8 @@ directory should work if nowhere else does.} \gdefchar^^ff{\dotaccent{}} } +\endgroup % active chars + % UTF-8 character definitions. % % This code to support UTF-8 is based on LaTeX's utf8.def, with some @@ -10489,7 +10476,7 @@ directory should work if nowhere else does.} \DeclareUnicodeCharacter{00AE}{\registeredsymbol{}}% \DeclareUnicodeCharacter{00AF}{\={ }}% % - \DeclareUnicodeCharacter{00B0}{\textdegree} + \DeclareUnicodeCharacter{00B0}{\textdegree}% \DeclareUnicodeCharacter{00B1}{\ensuremath\pm}% \DeclareUnicodeCharacter{00B2}{$^2$}% \DeclareUnicodeCharacter{00B3}{$^3$}% @@ -11204,14 +11191,14 @@ directory should work if nowhere else does.} \relax } -% Define all Unicode characters we know about. This makes UTF-8 the default -% input encoding and allows @U to work. +% Define all Unicode characters we know about \iftxinativeunicodecapable \nativeunicodechardefsatu \else \utfeightchardefs \fi + \message{formatting,} \newdimen\defaultparindent \defaultparindent = 15pt @@ -11539,7 +11526,7 @@ directory should work if nowhere else does.} \fi } -\microtypeON +\microtypeOFF \parseargdef\microtype{% \def\txiarg{#1}% @@ -11556,6 +11543,9 @@ directory should work if nowhere else does.} \message{and turning on texinfo input format.} +% Make UTF-8 the default encoding. +\documentencodingzzz{UTF-8} + \def^^L{\par} % remove \outer, so ^L can appear in an @comment \catcode`\^^K = 10 % treat vertical tab as whitespace @@ -11618,23 +11608,32 @@ directory should work if nowhere else does.} % Used sometimes to turn off (effectively) the active characters even after % parsing them. \def\turnoffactive{% - \normalturnoffactive + \passthroughcharstrue + \let-=\normaldash + \let"=\normaldoublequote + \let$=\normaldollar %$ font-lock fix + \let+=\normalplus + \let<=\normalless + \let>=\normalgreater + \let^=\normalcaret + \let_=\normalunderscore + \let|=\normalverticalbar + \let~=\normaltilde \otherbackslash + \setregularquotes + \unsepspaces } -\catcode`\@=0 +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \loadconf turn them back on. +\catcode`+=\other \catcode`\_=\other + % \backslashcurfont outputs one backslash character in current font, % as in \char`\\. \global\chardef\backslashcurfont=`\\ -% \realbackslash is an actual character `\' with catcode other. -{\catcode`\\=\other @gdef@realbackslash{\}} - -% In Texinfo, backslash is an active character; it prints the backslash -% in fixed width font. -\catcode`\\=\active % @ for escape char from now on. - % Print a typewriter backslash. For math mode, we can't simply use % \backslashcurfont: the story here is that in math mode, the \char % of \backslashcurfont ends up printing the roman \ from the math symbol @@ -11644,109 +11643,120 @@ directory should work if nowhere else does.} % ignored family value; char position "5C). We can't use " for the % usual hex value because it has already been made active. -@def@ttbackslash{{@tt @ifmmode @mathchar29020 @else @backslashcurfont @fi}} -@let@backslashchar = @ttbackslash % @backslashchar{} is for user documents. +\def\ttbackslash{{\tt \ifmmode \mathchar29020 \else \backslashcurfont \fi}} +\let\backslashchar = \ttbackslash % \backslashchar{} is for user documents. -% \otherbackslash defines an active \ to be a literal `\' character with -% catcode other. -@gdef@otherbackslash{@let\=@realbackslash} - -% Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of -% the literal character `\'. -% -{@catcode`- = @active - @gdef@normalturnoffactive{% - @passthroughcharstrue - @let-=@normaldash - @let"=@normaldoublequote - @let$=@normaldollar %$ font-lock fix - @let+=@normalplus - @let<=@normalless - @let>=@normalgreater - @let^=@normalcaret - @let_=@normalunderscore - @let|=@normalverticalbar - @let~=@normaltilde - @let\=@ttbackslash - @setregularquotes - @unsepspaces - } -} - -% If a .fmt file is being used, characters that might appear in a file -% name cannot be active until we have parsed the command line. -% So turn them off again, and have @fixbackslash turn them back on. -@catcode`+=@other @catcode`@_=@other - -% \enablebackslashhack - allow file to begin `\input texinfo' -% -% If a .fmt file is being used, we don't want the `\input texinfo' to show up. -% That is what \eatinput is for; after that, the `\' should revert to printing -% a backslash. -% If the file did not have a `\input texinfo', then it is turned off after -% the first line; otherwise the first `\' in the file would cause an error. -% This is used on the very last line of this file, texinfo.tex. -% We also use @c to call @fixbackslash, in case ends of lines are hidden. -{ -@catcode`@^=7 -@catcode`@^^M=13@gdef@enablebackslashhack{% - @global@let\ = @eatinput% - @catcode`@^^M=13% - @def@c{@fixbackslash@c}% - % Definition for the newline at the end of this file. - @def ^^M{@let^^M@secondlinenl}% - % Definition for a newline in the main Texinfo file. - @gdef @secondlinenl{@fixbackslash}% +% These are made active for url-breaking, so need +% active definitions as the normal characters. +\def\normaldot{.} +\def\normalquest{?} +\def\normalslash{/} + +% \newlinesloadsconf - call \loadconf as soon as possible in the +% file, e.g. at the first newline. +% +{\catcode`\^=7 +\catcode`\^^M=13 +\gdef\newlineloadsconf{% + \catcode`\^^M=13 % + \newlineloadsconfzz% +} +\gdef\newlineloadsconfzz#1^^M{% + \def\c{\loadconf\c}% + % Definition for the first newline read in the file + \def ^^M{\loadconf}% % In case the first line has a whole-line command on it - @let@originalparsearg@parsearg - @def@parsearg{@fixbackslash@originalparsearg} + \let\originalparsearg\parsearg% + \def\parsearg{\loadconf\originalparsearg}% }} -{@catcode`@^=7 @catcode`@^^M=13% -@gdef@eatinput input texinfo#1^^M{@fixbackslash}} % Emergency active definition of newline, in case an active newline token % appears by mistake. -{@catcode`@^=7 @catcode13=13% -@gdef@enableemergencynewline{% - @gdef^^M{% - @par% - %<warning: active newline>@par% +{\catcode`\^=7 \catcode13=13% +\gdef\enableemergencynewline{% + \gdef^^M{% + \par% + %<warning: active newline>\par% }}} -@gdef@fixbackslash{% - @ifx\@eatinput @let\ = @ttbackslash @fi - @catcode13=5 % regular end of line - @enableemergencynewline - @let@c=@comment - @let@parsearg@originalparsearg +% \loadconf gets called at the beginning of every Texinfo file. +% If texinfo.cnf is present on the system, read it. Useful for site-wide +% @afourpaper, etc. Not opening texinfo.cnf directly in texinfo.tex +% makes it possible to make a format file for Texinfo. +% +\gdef\loadconf{% + \relax % Terminate the filename if running as "tex '&texinfo' FILE.texi". + % + % Turn off the definitions that trigger \loadconf + \everyjobreset + \catcode13=5 % regular end of line + \enableemergencynewline + \let\c=\comment + \let\parsearg\originalparsearg + % % Also turn back on active characters that might appear in the input % file name, in case not using a pre-dumped format. - @catcode`+=@active - @catcode`@_=@active - % - % If texinfo.cnf is present on the system, read it. - % Useful for site-wide @afourpaper, etc. This macro, @fixbackslash, gets - % called at the beginning of every Texinfo file. Not opening texinfo.cnf - % directly in this file, texinfo.tex, makes it possible to make a format - % file for Texinfo. + \catcode`+=\active + \catcode`\_=\active % - @openin 1 texinfo.cnf - @ifeof 1 @else @input texinfo.cnf @fi - @closein 1 + \openin 1 texinfo.cnf + \ifeof 1 \else \input texinfo.cnf \fi + \closein 1 } +% Redefine some control sequences to be controlled by the \ifdummies +% and \ifindexnofonts switches. Do this at the end so that the control +% sequences are all defined. +\definedummies + + + + +\catcode`\@=0 + +% \realbackslash is an actual character `\' with catcode other. +{\catcode`\\=\other @gdef@realbackslash{\}} + +% In Texinfo, backslash is an active character; it prints the backslash +% in fixed width font. +\catcode`\\=\active % @ for escape char from now on. + +@let\ = @ttbackslash + +% If in a .fmt file, print the version number. +% \eatinput stops the `\input texinfo' from showing up. +% After that, `\' should revert to printing a backslash. +% Turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +% +@everyjob{@message{[Texinfo version @texinfoversion]}% + @global@let\ = @eatinput + @catcode`+=@active @catcode`@_=@active} + +{@catcode`@^=7 @catcode`@^^M=13% +@gdef@eatinput input texinfo#1^^M{@loadconf}} + +@def@everyjobreset{@ifx\@eatinput @let\ = @ttbackslash @fi} + +% \otherbackslash defines an active \ to be a literal `\' character with +% catcode other. +@gdef@otherbackslash{@let\=@realbackslash} + +% Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of +% the literal character `\'. +% +{@catcode`- = @active + @gdef@normalturnoffactive{% + @turnoffactive + @let\=@ttbackslash + } +} % Say @foo, not \foo, in error messages. @escapechar = `@@ -% These (along with & and #) are made active for url-breaking, so need -% active definitions as the normal characters. -@def@normaldot{.} -@def@normalquest{?} -@def@normalslash{/} - % These look ok in all fonts, so just make them not special. % @hashchar{} gets its own user-level command, because of #line. @catcode`@& = @other @def@normalamp{&} @@ -11761,15 +11771,11 @@ directory should work if nowhere else does.} @c Do this last of all since we use ` in the previous @catcode assignments. @catcode`@'=@active @catcode`@`=@active -@setregularquotes @c Local variables: @c eval: (add-hook 'before-save-hook 'time-stamp nil t) @c time-stamp-pattern: "texinfoversion{%Y-%02m-%02d.%02H}" -@c page-delimiter: "^\\\\message\\|emacs-page" +@c page-delimiter: "^\\\\message" @c End: -@c vim:sw=2: - -@enablebackslashhack - +@newlineloadsconf diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi index 56436d32970..a8a59f982fc 100644 --- a/doc/misc/tramp.texi +++ b/doc/misc/tramp.texi @@ -1,5 +1,5 @@ \input texinfo @c -*- mode: texinfo; coding: utf-8 -*- -@setfilename ../info/tramp +@setfilename ../../info/tramp.info @c %**start of header @include docstyle.texi @c In the Tramp GIT, the version number and the bug report address @@ -927,6 +927,17 @@ pod is used. This method does not support user names. +@item @option{toolbox} +@cindex method @option{toolbox} +@cindex @option{toolbox} method + +Integration of Toolbox system containers. The host name may be either +a container's name or ID, as returned by @samp{toolbox list -c}. +Without a host name, the default Toolbox container for the host will +be used. + +This method does not support user names. + @end table @@ -3928,12 +3939,12 @@ connection-local variables. @vindex async-shell-command-width @vindex COLUMNS@r{, environment variable} -If Emacs supports the user option @code{async-shell-command-width} -(since @w{Emacs 27}), @value{tramp} cares about its value for -asynchronous shell commands. It specifies the number of display -columns for command output. For synchronous shell commands, a similar -effect can be achieved by adding the environment variable -@env{COLUMNS} to @code{tramp-remote-process-environment}. +@value{tramp} cares about the user option +@code{async-shell-command-width} for asynchronous shell commands. It +specifies the number of display columns for command output. For +synchronous shell commands, a similar effect can be achieved by adding +the environment variable @env{COLUMNS} to +@code{tramp-remote-process-environment}. @subsection Running @code{eshell} on a remote host @@ -4824,8 +4835,8 @@ Where is the latest @value{tramp}? @item Which systems does it work on? -The package works successfully on @w{Emacs 26}, @w{Emacs 27}, @w{Emacs -28}, and @w{Emacs 29}. +The package works successfully on @w{Emacs 27}, @w{Emacs 28}, @w{Emacs +29}, and @w{Emacs 30}. While Unix and Unix-like systems are the primary remote targets, @value{tramp} has equal success connecting to other platforms, such as @@ -5204,9 +5215,10 @@ them, @ref{Misc File Ops, Trashing , , emacs}. @ifnotinfo them. @end ifnotinfo -Remote files are always trashed to the local trash, except remote -encrypted files (@pxref{Keeping files encrypted}), which are deleted -anyway. +Remote files are always trashed to the local trash, except the user +option @code{remote-file-name-inhibit-delete-by-moving-to-trash} is +non-@code{nil}, or it is a remote encrypted file (@pxref{Keeping files +encrypted}), which are deleted anyway. If Emacs is configured to use the XDG conventions for the trash directory, remote files cannot be restored with the respective tools, diff --git a/doc/misc/trampver.texi b/doc/misc/trampver.texi index 299fb3fcb31..2f505c6acea 100644 --- a/doc/misc/trampver.texi +++ b/doc/misc/trampver.texi @@ -7,10 +7,10 @@ @c In the Tramp GIT, the version number and the bug report address @c are auto-frobbed from configure.ac. -@set trampver 2.6.0.29.1 +@set trampver 2.7.0-pre @set trampurl https://www.gnu.org/software/tramp/ @set tramp-bug-report-address tramp-devel@@gnu.org -@set emacsver 26.1 +@set emacsver 27.1 @c Other flags from configuration. @set instprefix /usr/local diff --git a/etc/DEBUG b/etc/DEBUG index cfa033d6c0c..c4f0852abb3 100644 --- a/etc/DEBUG +++ b/etc/DEBUG @@ -1007,6 +1007,28 @@ Address sanitization is incompatible with undefined-behavior sanitization, unfortunately. Address sanitization is also incompatible with the --with-dumping=unexec option of 'configure'. +*** Address poisoning/unpoisoning + +When compiled with address sanitization, Emacs will also try to mark +dead/free lisp objects as poisoned, forbidding them from being +accessed without being unpoisoned first. This adds an extra layer +of checking with objects in internal free lists, which may otherwise +evade traditional use-after-free checks. To disable this, add +'allow_user_poisoning=0' to ASAN_OPTIONS, or build Emacs with +'-DGC_ASAN_POISON_OBJECTS=0' in CFLAGS. + +While using GDB, memory addresses can be inspected by using helper +functions additionally provided by the ASan library: + + (gdb) call __asan_describe_address(ptr) + +To check whether an address range is poisoned or not, use: + + (gdb) call __asan_region_is_poisoned(ptr, 8) + +Additional functions can be found in the header +'sanitizer/asan_interface.h' in your compiler's headers directory. + ** Running Emacs under Valgrind Valgrind <https://valgrind.org/> is free software that can be useful @@ -1,15 +1,15 @@ GNU Emacs NEWS -- history of user-visible changes. -Copyright (C) 2021-2023 Free Software Foundation, Inc. +Copyright (C) 2022-2023 Free Software Foundation, Inc. See the end of the file for license conditions. Please send Emacs bug reports to 'bug-gnu-emacs@gnu.org'. If possible, use 'M-x report-emacs-bug'. -This file is about changes in Emacs version 29. +This file is about changes in Emacs version 30. See file HISTORY for a list of GNU Emacs versions and release dates. -See files NEWS.28, NEWS.27, ..., NEWS.18, and NEWS.1-17 for changes +See files NEWS.29, NEWS.28, ..., NEWS.18, and NEWS.1-17 for changes in older Emacs versions. You can narrow news to a specific version by calling 'view-emacs-news' @@ -22,4776 +22,271 @@ When you add a new item, use the appropriate mark if you are sure it applies, and please also update docstrings as needed. -* Installation Changes in Emacs 29.1 - ---- -** Ahead-of-time native compilation can now be requested via configure. -Use '--with-native-compilation=aot' to request that all the Lisp files -in the Emacs tree should be natively compiled ahead of time. (This is -slow on most machines.) - -This feature existed in Emacs 28.1, but was less easy to request. - -+++ -** Emacs can be built with the tree-sitter parsing library. -This library, together with separate grammar libraries for each -language, provides incremental parsing capabilities for several -popular programming languages and other formatted files. Emacs built -with this library offers major modes, described elsewhere in this -file, that are based on the tree-sitter's parsers. If you have the -tree-sitter library installed, the configure script will automatically -include it in the build; use '--without-tree-sitter' at configure time -to disable that. - -Emacs modes based on the tree-sitter library require an additional -grammar library for each mode. These grammar libraries provide the -tree-sitter library with language-specific lexical analysis and -parsing capabilities, and are developed separately from the -tree-sitter library itself. If you don't have a grammar library -required by some Emacs major mode, and your distro doesn't provide it -as an installable package, you can compile and install such a library -yourself. Many libraries can be downloaded from the tree-sitter site: - - https://github.com/tree-sitter - -Emacs provides a user command, 'treesit-install-language-grammar', -that automates the download and build process of a grammar library. -It prompts for the language, the URL of the language grammar's VCS -repository, and then uses the installed C/C++ compiler to build the -library and install it. - -You can also do this manually. To compile such a library after -cloning its Git repository, compile the files "scanner.c" and -"parser.c" (sometimes named "scanner.cc" and "parser.cc") in the "src" -subdirectory of the library's source tree using the C or C++ compiler, -then link these two files into a shared library named -"libtree-sitter-LANG.so", where LANG is the name of the language -supported by the grammar as it is expected by the Emacs major mode -(for example, "c" for 'c-ts-mode', "cpp" for 'c++-ts-mode', "python" -for 'python-ts-mode', etc.). Then place the shared library you've -built in the same directory where you keep the other shared libraries -used by Emacs, or in the "tree-sitter" subdirectory of your -'user-emacs-directory', or in a directory mentioned in the variable -'treesit-extra-load-path'. - -You only need to install language grammar libraries required by the -Emacs modes you will use, as Emacs loads these libraries only when the -corresponding mode is turned on in some buffer for the first time in -an Emacs session. - -+++ -** Emacs can be built with built-in support for accessing SQLite databases. -This uses the popular sqlite3 library, and can be disabled by using -the '--without-sqlite3' option to the 'configure' script. - -+++ -** Support for the WebP image format. -This support is built by default when the libwebp library is -available, and includes support for animated WebP images. To disable -WebP support, use the '--without-webp' configure flag. Image -specifiers can now use ':type webp'. - -+++ -** Emacs has been ported to the Haiku operating system. -The configuration process should automatically detect and build for -Haiku. There is also an optional window-system port to Haiku, which -can be enabled by configuring Emacs with the option '--with-be-app', -which will require the Haiku Application Kit development headers and a -C++ compiler to be present on your system. If Emacs is not built with -the option '--with-be-app', the resulting Emacs will only run in -text-mode terminals. - -To enable Cairo support, ensure that the Cairo and FreeType -development files are present on your system, and configure Emacs with -'--with-be-cairo'. - -Unlike X, there is no compile-time option to enable or disable -double-buffering; it is always enabled. To disable it, change the -frame parameter 'inhibit-double-buffering' instead. - ---- -** Emacs now installs the ".pdmp" file using a unique fingerprint in the name. -The file is typically installed using a file name akin to -"...dir/libexec/emacs/29.1/x86_64-pc-linux-gnu/emacs-<fingerprint>.pdmp". -If a constant file name is required, the file can be renamed to -"emacs.pdmp", and Emacs will find it during startup anyway. - ---- -** Emacs on X now uses XInput 2 for input events. -If your X server has support and you have the XInput 2 development -headers installed, Emacs will use the X Input Extension for handling -input. If this causes problems, you can configure Emacs with the -option '--without-xinput2' to disable this support. - -'(featurep 'xinput2)' can be used to test for the presence of XInput 2 -support from Lisp programs. - -+++ -** Emacs now supports being built with pure GTK. -To use this option, make sure the GTK 3 (version 3.22.23 or later) and -Cairo development files are installed, and configure Emacs with the -option '--with-pgtk'. Unlike the default X and GTK build, the -resulting Emacs binary will work on any underlying window system -supported by GDK, such as Wayland and Broadway. We recommend that you -use this configuration only if you are running a window system other -than X that's supported by GDK. Running this configuration on X is -known to have problems, such as undesirable frame positioning and -various issues with keyboard input of sequences such as 'C-;' and -'C-S-u'. - ---- -** Emacs no longer reduces the size of the Japanese dictionary. -Building Emacs includes generation of a Japanese dictionary, which is -used by Japanese input methods. Previously, the build included a step -of reducing the size of this dictionary's vocabulary. This vocabulary -reduction is now optional, by default off. If you need the Emacs -build to include the vocabulary reduction, configure Emacs with the -option '--with-small-ja-dic'. In an Emacs source tree already -configured without that option, you can force the vocabulary reduction -by saying - - make -C leim generate-ja-dic JA_DIC_NO_REDUCTION_OPTION='' - -after deleting "lisp/leim/ja-dic/ja-dic.el". - ---- -** The docstrings of preloaded files are not in "etc/DOC" any more. -Instead, they're fetched as needed from the corresponding ".elc" -files, as was already the case for all the non-preloaded files. +* Installation Changes in Emacs 30.1 -* Startup Changes in Emacs 29.1 - -+++ -** '--batch' and '--script' now adjust the garbage collection levels. -These switches now set 'gc-cons-percentage' to 1.0 (up from the -default of 0.1). This means that batch processes will typically use -more memory than before, but use less time doing garbage collection. -Batch jobs that are supposed to run for a long time should adjust the -limit back down again. - -+++ -** Emacs can now be used more easily in an executable script. -If you start an executable script with - - #!/usr/bin/emacs -x - -Emacs will start without reading any init files (like with '--quick'), -and then execute the rest of the script file as Emacs Lisp. When it -reaches the end of the script, Emacs will exit with an exit code from -the value of the final form. - -+++ -** Emacs now supports setting 'user-emacs-directory' via '--init-directory'. -Use the '--init-directory' command-line option to set -'user-emacs-directory'. - -+++ -** Emacs now has a '--fingerprint' option. -This will output a string identifying the current Emacs build, and exit. - -+++ -** New hook 'after-pdump-load-hook'. -This is run at the end of the Emacs startup process, and is meant to -be used to reinitialize data structures that would normally be done at -load time. - -** Native Compilation - -+++ -*** New variable 'inhibit-automatic-native-compilation'. -If set, Emacs will inhibit native compilation (and won't write -anything to the eln cache automatically). The variable is initialized -during Emacs startup from the environment variable -'EMACS_INHIBIT_AUTOMATIC_NATIVE_COMPILATION'. - ---- -*** New command 'native-compile-prune-cache'. -This command deletes old subdirectories of the eln cache (but not the -ones for the current Emacs version). Note that subdirectories of the -system directory where the "*.eln" files are installed (usually, the -last entry in 'native-comp-eln-load-path') are not deleted. - ---- -*** New function 'startup-redirect-eln-cache'. -This function can be called in your init files to change the -user-specific directory where Emacs stores the "*.eln" files produced -by native compilation of Lisp packages Emacs loads. The default -eln cache directory is unchanged: it is the "eln-cache" subdirectory -of 'user-emacs-directory'. - - -* Incompatible changes in Emacs 29.1 - -+++ -** The image commands have changed key bindings. -In previous Emacs versions, images have had the '+', '-' and 'r' keys -bound when point is over an image. In Emacs 29.1, additional commands -were added, and this made it more likely that users would trigger the -image commands by mistake. To avoid this, all image commands have -moved to the 'i' keymap, so '+' is now 'i +', '-' is now 'i -', and -'r' is now 'i r'. In addition, these commands are now repeating, so -you can rotate an image twice by saying 'i r r', for instance. - -+++ -** Emacs now picks the correct coding-system for X input methods. -Previously, Emacs would use 'locale-coding-system' for input -methods, which could in some circumstances be incorrect, especially -when the input method chose to fall back to some other coding system. - -Emacs now automatically detects the coding-system used by input -methods, and uses that to decode input in preference to the value of -'locale-coding-system'. This unfortunately means that users who have -changed the coding system used to decode X keyboard input must adjust -their customizations to 'locale-coding-system' to the variable -'x-input-coding-system' instead. - -+++ -** Bookmarks no longer include context for encrypted files. -If you're visiting an encrypted file, setting a bookmark no longer -includes excerpts from that buffer in the bookmarks file. This is -implemented by the new hook 'bookmark-inhibit-context-functions', -where packages can register a function which returns non-nil for file -names to be excluded from adding such excerpts. - ---- -** 'show-paren-mode' is now disabled in 'special-mode' buffers. -In Emacs versions previous to Emacs 28.1, 'show-paren-mode' defaulted -off. In Emacs 28.1, the mode was switched on in all buffers. In -Emacs 29.1, this was changed to be switched on in all editing-related -buffers, but not in buffers that inherit from 'special-mode'. To go -back to how things worked in Emacs 28.1, put the following in your -init file: - - (setopt show-paren-predicate t) - -+++ -** Explicitly-set read-only state is preserved when reverting a buffer. -If you use the 'C-x C-q' command to change the read-only state of the -buffer and then revert it, Emacs would previously use the file -permission bits to determine whether the buffer should be read-only -after reverting the buffer. Emacs now remembers the decision made in -'C-x C-q'. - ---- -** The Gtk selection face is no longer used for the region. -The combination of a Gtk-controlled background and a foreground color -controlled by the internal Emacs machinery led to low-contrast faces -in common default setups. Emacs now uses the same 'region' face on -Gtk and non-Gtk setups. - ---- -** 'C-h f' and 'C-h x' may now require confirmation when you press 'RET'. -If the text in the minibuffer cannot be completed to a single function -or command, typing 'RET' will not automatically complete to the shortest -candidate, but will instead ask for confirmation. Typing 'TAB' will -complete as much as possible, and another 'TAB' will show all the -possible completions. This allows you to insist on the functions name -even if Help doesn't appear to know about it, by confirming with a -second 'RET'. - -** Dired - ---- -*** 'w' ('dired-copy-filename-as-kill') has changed behavior. -If there are several files marked, file names containing space and -quote characters will be quoted "like this". - ---- -*** The 'd' command now more consistently skips dot files. -In previous Emacs versions, commands like 'C-u 10 d' would put the "D" -mark on the next ten files, no matter whether they were dot files -(i.e., "." and "..") or not, while marking the next ten lines with the -mouse (in 'transient-mark-mode') and then hitting 'd' would skip dot -files. These now work equivalently. - -+++ -** Warning about "eager macro-expansion failure" is now an error. - ---- -** Previously, the X "reverseVideo" value at startup was heeded for all frames. -This meant that if you had a "reverseVideo" resource on the initial -display, and then opened up a new frame on a display without any -explicit "reverseVideo" setting, it would get heeded there, too. (This -included terminal frames.) In Emacs 29, the "reverseVideo" X resource -is handled like all the other X resources, and set on a per-frame basis. - -+++ -** 'E' in 'query-replace' now edits the replacement with exact case. -Previously, this command did the same as 'e'. - ---- -** '/ a' in "*Packages*" buffer now limits by archive name(s) instead of regexp. - -+++ -** Setting the goal columns now also affects '<prior>' and '<next>'. -Previously, 'C-x C-n' only affected 'next-line' and 'previous-line', -but it now also affects 'scroll-up-command' and 'scroll-down-command'. - ---- -** Isearch in "*Help*" and "*info*" now char-folds quote characters by default. -This means that you can say 'C-s `foo' (GRAVE ACCENT) if the buffer -contains "‘foo" (LEFT SINGLE QUOTATION MARK) and the like. These -quotation characters look somewhat similar in some fonts. To switch -this off, disable the new 'isearch-fold-quotes-mode' minor mode. - ---- -** Sorting commands no longer necessarily change modification status. -In earlier Emacs versions, commands like 'sort-lines' would always -change buffer modification status to "modified", whether they changed -something in the buffer or not. This has been changed: the buffer is -marked as modified only if the sorting ended up actually changing the -contents of the buffer. - ---- -** 'string-lines' handles trailing newlines differently. -It no longer returns an empty final string if the string ends with a -newline. - ---- -** 'TAB' and '<backtab>' are now bound in 'button-map'. -This means that if point is on a button, 'TAB' will take you to the -next button, even if the mode has bound it to something else. This -also means that 'TAB' on a button in an 'outline-minor-mode' heading -will move point instead of collapsing the outline. - ---- -** 'outline-minor-mode-cycle-map' is now parent of 'outline-minor-mode'. -Instead of adding text property 'keymap' with 'outline-minor-mode-cycle' -on outline headings in 'outline-minor-mode', the keymap -'outline-minor-mode-cycle' is now active in the whole buffer. -But keybindings in 'outline-minor-mode-cycle' still take effect -only on outline headings because they are bound with the help of -'outline-minor-mode-cycle--bind' that checks if point is on a heading. - ---- -** 'Info-default-directory-list' is no longer populated at Emacs startup. -If you have code in your init file that removes directories from -'Info-default-directory-list', this will no longer work. - ---- -** 'C-k' no longer deletes files in 'ido-mode'. -To get the previous action back, put something like the following in -your Init file: - - (require 'ido) - (keymap-set ido-file-completion-map "C-k" #'ido-delete-file-at-head) - ---- -** New user option 'term-clear-full-screen-programs'. -By default, term.el will now work like most terminals when displaying -full-screen programs: When they exit, the output is cleared, leaving -what was displayed in the window before the programs started. Set -this user option to nil to revert back to the old behavior. - ---- -** Support for old EIEIO functions is not autoloaded any more. -You need an explicit '(require 'eieio-compat)' to use 'defmethod' -and 'defgeneric' (which have been made obsolete in Emacs 25.1 with -'cl-defmethod' and 'cl-defgeneric'). -Similarly you might need to '(require 'eieio-compat)' before loading -files that were compiled with an old EIEIO (Emacs<25). - ---- -** 'C-x 8 .' has been moved to 'C-x 8 . .'. -This is to open up the 'C-x 8 .' map to bind further characters there. - ---- -** 'C-x 8 =' has been moved to 'C-x 8 = ='. -You can now use 'C-x 8 =' to insert several characters with macron; -for example, 'C-x 8 = a' will insert U+0101 LATIN SMALL LETTER A WITH -MACRON. To insert a lone macron, type 'C-x 8 = =' instead of the -previous 'C-x ='. - -** Eshell - -*** Eshell's PATH is now derived from 'exec-path'. -For consistency with remote connections, Eshell now uses 'exec-path' -to determine the execution path on the local or remote system, instead -of using the PATH environment variable directly. - ---- -*** 'source' and '.' no longer accept the '--help' option. -This is for compatibility with the shell versions of these commands, -which don't handle options like '--help' in any special way. - -+++ -*** String delimiters in argument predicates/modifiers are more restricted. -Previously, some argument predicates/modifiers allowed arbitrary -characters as string delimiters. To provide more unified behavior -across all predicates/modifiers, the list of allowed delimiters has -been restricted to "...", '...', /.../, |...|, (...), [...], <...>, -and {...}. See the "(eshell) Argument Predication and Modification" -node in the Eshell manual for more details. - -+++ -*** Eshell pipelines now only pipe stdout by default. -To pipe both stdout and stderr, use the '|&' operator instead of '|'. - ---- -** The 'delete-forward-char' command now deletes by grapheme clusters. -This command is by default bound to the '<Delete>' function key -(a.k.a. '<deletechar>'). When invoked without a prefix argument or -with a positive prefix numeric argument, the command will now delete -complete grapheme clusters produced by character composition. For -example, if point is before an Emoji sequence, pressing '<Delete>' -will delete the entire sequence, not just a single character at its -beginning. - -+++ -** 'load-history' does not treat autoloads specially any more. -An autoload definition appears just as a '(defun . NAME)' and the -'(t . NAME)' entries are not generated any more. - ---- -** The Tamil input methods no longer insert Tamil digits. -The input methods 'tamil-itrans' and 'tamil-inscript' no longer insert -the Tamil digits, as those digit characters are not used nowadays by -speakers of the Tamil language. To get back the previous behavior, -use the new 'tamil-itrans-digits' and 'tamil-inscript-digits' input -methods instead. - -+++ -** New variable 'current-time-list' governing default timestamp form. -Functions like 'current-time' now yield '(TICKS . HZ)' timestamps if -this new variable is nil. The variable defaults to t, which means -these functions default to timestamps of the forms '(HI LO US PS)', -'(HI LO US)' or '(HI LO)', which are less regular and less efficient. -This is part of a long-planned change first documented in Emacs 27. -Developers are encouraged to test timestamp-related code with this -variable set to nil, as it will default to nil in a future Emacs -version and will be removed some time after that. - -+++ -** Functions that recreate the "*scratch*" buffer now also initialize it. -When functions like 'other-buffer' and 'server-execute' recreate -"*scratch*", they now also insert 'initial-scratch-message' and set -the major mode according to 'initial-major-mode', like at Emacs -startup. Previously, these functions ignored -'initial-scratch-message' and left "*scratch*" in 'fundamental-mode'. - ---- -** Naming of Image-Dired thumbnail files has changed. -Names of thumbnail files generated when 'image-dired-thumbnail-storage' -is 'image-dired' now always end in ".jpg". This fixes various issues -on different platforms, but means that thumbnails generated in Emacs 28 -will not be used in Emacs 29, and vice-versa. If disk space is an -issue, consider deleting the 'image-dired-dir' directory (usually -"~/.emacs.d/image-dired/") after upgrading to Emacs 29. - ---- -** The 'rlogin' method in the URL library is now obsolete. -Emacs will now display a warning if you request a URL like -"rlogin://foo@example.org". - ---- -** Setting 'url-gateway-method' to 'rlogin' is now obsolete. -Emacs will now display a warning when setting it to that value. -The user options 'url-gateway-rlogin-host', -'url-gateway-rlogin-parameters', and 'url-gateway-rlogin-user-name' -are also obsolete. - ---- -** The user function 'url-irc-function' now takes a SCHEME argument. -The user option 'url-irc-function' is now called with a sixth argument -corresponding to the scheme portion of the target URL. For example, -this would be "ircs" for a URL like "ircs://irc.libera.chat". - ---- -** The linum.el library is now obsolete. -We recommend using either the built-in 'display-line-numbers-mode', or -the 'nlinum' package from GNU ELPA instead. The former has better -performance, but the latter is closer to a drop-in replacement. - -1. To use 'display-line-numbers-mode', add something like this to your - Init file: - - (global-display-line-numbers-mode 1) - ;; Alternatively, to use it only in programming modes: - (add-hook 'prog-mode-hook #'display-line-numbers-mode) - -2. To use 'nlinum', add this to your Init file: - - (package-install 'nlinum) - (global-nlinum-mode 1) - ;; Alternatively, to use it only in programming modes: - (add-hook 'prog-mode-hook #'nlinum-mode) - -3. To continue using the obsolete package 'linum', add this line to - your Init file, in addition to any existing customizations: - - (require 'linum) - ---- -** The thumbs.el library is now obsolete. -We recommend using command 'image-dired' instead. - ---- -** The autoarg.el library is now marked obsolete. -This library provides the 'autoarg-mode' and 'autoarg-kp-mode' minor -modes to emulate the behavior of the historical editor Twenex Emacs. -We believe it is no longer useful. - ---- -** The quickurl.el library is now obsolete. -Use 'abbrev', 'skeleton' or 'tempo' instead. - ---- -** The rlogin.el library, and the 'rsh' command are now obsolete. -Use something like 'M-x shell RET ssh <host> RET' instead. - ---- -** The url-about.el library is now obsolete. - ---- -** The autoload.el library is now obsolete. -It is superseded by the new loaddefs-gen.el library. - ---- -** The netrc.el library is now obsolete. -Use the 'auth-source-netrc-parse-all' function in auth-source.el -instead. - ---- -** The url-dired.el library is now obsolete. - ---- -** The fast-lock.el and lazy-lock.el libraries have been removed. -They have been obsolete since Emacs 22.1. - -The variable 'font-lock-support-mode' is occasionally useful for -debugging purposes. It is now a regular variable (instead of a user -option) and can be set to nil to disable Just-in-time Lock mode. +* Startup Changes in Emacs 30.1 -* Changes in Emacs 29.1 - -+++ -** New user option 'major-mode-remap-alist' to specify favorite major modes. -This user option lets you remap the default modes (e.g. 'perl-mode' or -'latex-mode') to your favorite ones (e.g. 'cperl-mode' or -'LaTeX-mode') without having to use 'defalias', which can have -undesirable side effects. -This applies to all modes specified via 'auto-mode-alist', file-local -variables, etc. - ---- -** Emacs now supports Unicode Standard version 15.0. - ---- -** New user option 'electric-quote-replace-consecutive'. - ---- -** Emacs is now capable of editing files with very long lines. -The display of long lines has been optimized, and Emacs should no -longer choke when a buffer on display contains long lines. The -variable 'long-line-threshold' controls whether and when these display -optimizations are in effect. - -A companion variable 'large-hscroll-threshold' controls when another -set of display optimizations are in effect, which are aimed -specifically at speeding up display of long lines that are truncated -on display. - -If you still experience slowdowns while editing files with long lines, -this may be due to line truncation, or to one of the enabled minor -modes, or to the current major mode. Try turning off line truncation -with 'C-x x t', or try disabling all known slow minor modes with -'M-x so-long-minor-mode', or try disabling both known slow minor modes -and the major mode with 'M-x so-long-mode', or visit the file with -'M-x find-file-literally' instead of the usual 'C-x C-f'. - -Note that the display optimizations in these cases may cause the -buffer to be occasionally mis-fontified. - -The new function 'long-line-optimizations-p' returns non-nil when -these optimizations are in effect in the current buffer. - -+++ -** New command to change the font size globally. -To increase the font size, type 'C-x C-M-+' or 'C-x C-M-='; to -decrease it, type 'C-x C-M--'; to restore the font size, type 'C-x -C-M-0'. The final key in these commands may be repeated without the -leading 'C-x' and without the modifiers, e.g. 'C-x C-M-+ C-M-+ C-M-+' -and 'C-x C-M-+ + +' increase the font size by three steps. When -'mouse-wheel-mode' is enabled, 'C-M-wheel-up' and 'C-M-wheel-down' also -increase and decrease the font size globally. Additionally, the -user option 'global-text-scale-adjust-resizes-frames' controls whether -the frames are resized when the font size is changed. - ---- -** New config variable 'syntax-wholeline-max' to reduce the cost of long lines. -This variable is used by some operations (mostly syntax-propertization -and font-locking) to treat lines longer than this variable as if they -were made up of various smaller lines. This can help reduce the -slowdowns seen in buffers made of a single long line, but can also -cause misbehavior in the presence of such long lines (though most of -that misbehavior should usually be limited to mis-highlighting). You -can recover the previous behavior with: - - (setq syntax-wholeline-max most-positive-fixnum) - ---- -** New bindings in 'find-function-setup-keys' for 'find-library'. -When 'find-function-setup-keys' is enabled, 'C-x L' is now bound to -'find-library', 'C-x 4 L' is now bound to 'find-library-other-window' -and 'C-x 5 L' is now bound to 'find-library-other-frame'. - -+++ -** New key binding after 'M-x' or 'M-X': 'M-X'. -Emacs allows different completion predicates to be used with 'M-x' -(i.e., 'execute-extended-command') via the -'read-extended-command-predicate' user option. Emacs also has the -'M-X' (note upper case X) command, which only displays commands -especially relevant to the current buffer. Emacs now allows toggling -between these modes while the user is inputting a command by hitting -'M-X' while in the minibuffer. - ---- -** Interactively, 'kill-buffer' will now offer to save the buffer if unsaved. - ---- -** New commands 'duplicate-line' and 'duplicate-dwim'. -'duplicate-line' duplicates the current line the specified number of times. -'duplicate-dwim' duplicates the region if it is active. If not, it -works like 'duplicate-line'. An active rectangular region is -duplicated on its right-hand side. - ---- -** Files with the ".eld" extension are now visited in 'lisp-data-mode'. - -+++ -** 'network-lookup-address-info' can now check numeric IP address validity. -Specifying 'numeric' as the new optional HINTS argument makes it -check if the passed address is a valid IPv4/IPv6 address (without DNS -traffic). - - (network-lookup-address-info "127.1" 'ipv4 'numeric) - => ([127 0 0 1 0]) - -+++ -** New command 'find-sibling-file'. -This command jumps to a file considered a "sibling file", which is -determined according to the new user option 'find-sibling-rules'. - -+++ -** New user option 'delete-selection-temporary-region'. -When non-nil, 'delete-selection-mode' will only delete the temporary -regions (usually set by mouse-dragging or shift-selection). +* Changes in Emacs 30.1 -+++ -** New user option 'switch-to-prev-buffer-skip-regexp'. -This should be a regexp or a list of regexps; buffers whose names -match those regexps will be ignored by 'switch-to-prev-buffer' and -'switch-to-next-buffer'. - -+++ -** New command 'rename-visited-file'. -This command renames the file visited by the current buffer by moving -it to a new name or location, and also makes the buffer visit this new -file. - -** Menus - ---- -*** The entries following the buffers in the "Buffers" menu can now be altered. -Change the 'menu-bar-buffers-menu-command-entries' variable to alter -the entries that follow the buffer list. - ---- -** 'delete-process' is now a command. -When called interactively, it will kill the process running in the -current buffer (if any). This can be useful if you have runaway -output in the current buffer (from a process or a network connection), -and want to stop it. - -+++ -** New command 'restart-emacs'. -This is like 'save-buffers-kill-emacs', but instead of just killing -the current Emacs process at the end, it starts a new Emacs process -(using the same command line arguments as the running Emacs process). -'kill-emacs' and 'save-buffers-kill-emacs' have also gained new -optional arguments to restart instead of just killing the current -process. - -** Drag and Drop - -+++ -*** New user option 'mouse-drag-mode-line-buffer'. -If non-nil, dragging on the buffer name part of the mode-line will -drag the buffer's associated file to other programs. This option is -currently only available on X, Haiku and Nextstep (GNUstep or macOS). - -+++ -*** New user option 'mouse-drag-and-drop-region-cross-program'. -If non-nil, this option allows dragging text in the region from Emacs -to another program. - ---- -*** New user option 'mouse-drag-and-drop-region-scroll-margin'. -If non-nil, this option allows scrolling a window while dragging text -around without a scroll wheel. - -+++ -*** The value of 'mouse-drag-copy-region' can now be the symbol 'non-empty'. -This prevents mouse drag gestures from putting empty strings onto the -kill ring. - -+++ -*** New user options 'dnd-indicate-insertion-point' and 'dnd-scroll-margin'. -These options allow adjusting point and scrolling a window when -dragging items from another program. - -+++ -*** The X Direct Save (XDS) protocol is now supported. -This means dropping an image or file link from programs such as -Firefox will no longer create a temporary file in a random directory, -instead asking you where to save the file first. - -+++ -** New user option 'record-all-keys'. -If non-nil, this option will force recording of all input keys, -including those typed in response to passwords prompt (this was the -previous behavior). The default is nil, which inhibits recording of -passwords. - -+++ -** New function 'command-query'. -This function makes its argument command prompt the user for -confirmation before executing. - -+++ -** The 'disabled' property of a command's symbol can now be a list. -The first element of the list should be the symbol 'query', which will -cause the command disabled this way prompt the user with a y/n or a -yes/no question before executing. The new function 'command-query' is -a convenient method of making commands disabled in this way. - ---- -** 'count-words' will now report buffer totals if given a prefix. -Without a prefix, it will only report the word count for the narrowed -part of the buffer. - -+++ -** 'count-words' will now report sentence count when used interactively. - -+++ -** New user option 'set-message-functions'. -It allows selecting more functions for 'set-message-function' -in addition to the default function that handles messages -in the active minibuffer. The most useful are 'inhibit-message' -that allows specifying a list of messages to inhibit via -'inhibit-message-regexps', and 'set-multi-message' that -accumulates recent messages and displays them stacked -in the echo area. - ---- -** New user option 'find-library-include-other-files'. -If set to nil, commands like 'find-library' will only include library -files in the completion candidates. The default is t, which preserves -previous behavior, whereby non-library files could also be included. - -+++ -** New command 'sqlite-mode-open-file' for examining an sqlite3 file. -This uses the new 'sqlite-mode' which allows listing the tables in a -DB file, and examining and modifying the columns and the contents of -those tables. - ---- -** 'write-file' will now copy some file mode bits. -If the current buffer is visiting a file that is executable, the -'C-x C-w' command will now make the new file executable, too. - -+++ -** New user option 'process-error-pause-time'. -This determines how long to pause Emacs after a process -filter/sentinel error has been handled. - -+++ -** New faces for font-lock. -These faces are primarily meant for use with tree-sitter. They are: -'font-lock-bracket-face', 'font-lock-delimiter-face', -'font-lock-escape-face', 'font-lock-misc-punctuation-face', -'font-lock-number-face', 'font-lock-operator-face', -'font-lock-property-face', and 'font-lock-punctuation-face', -'font-lock-regexp-face'. - -+++ -** New face 'variable-pitch-text'. -This face is like 'variable-pitch' (from which it inherits), but is -slightly larger, which should help with the visual size differences -between the default, non-proportional font and proportional fonts when -mixed. - -+++ -** New face 'mode-line-active'. -This inherits from the 'mode-line' face, but is the face actually used -on the mode lines (along with 'mode-line-inactive'). - -+++ -** New face attribute pseudo-value 'reset'. -This value stands for the value of the corresponding attribute of the -'default' face. It can be used to reset attribute values produced by -inheriting from other faces. - -+++ -** New X resource: "borderThickness". -This controls the thickness of the external borders of the menu bars -and pop-up menus. - -+++ -** New X resource: "inputStyle". -This controls the style of the pre-edit and status areas of X input -methods. - -+++ -** New X resources: "highlightForeground" and "highlightBackground". -Only in the Lucid build, this controls colors used for highlighted -menu item widgets. - -+++ -** On X, Emacs now tries to synchronize window resize with the window manager. -This leads to less flicker and empty areas of a frame being displayed -when a frame is being resized. Unfortunately, it does not work on -some ancient buggy window managers, so if Emacs appears to freeze, but -is still responsive to input, you can turn it off by setting the X -resource "synchronizeResize" to "off". - -+++ -** On X, Emacs can optionally synchronize display with the graphics hardware. -When this is enabled by setting the X resource "synchronizeResize" to -"extended", frame content "tearing" is drastically reduced. This is -only supported on the Motif, Lucid, and no-toolkit builds, and -requires an X compositing manager supporting the extended frame -synchronization protocol (see -https://fishsoup.net/misc/wm-spec-synchronization.html). - -This behavior can be toggled on and off via the frame parameter -'use-frame-synchronization'. - -+++ -** New frame parameter 'alpha-background' and X resource "alphaBackground". -This controls the opacity of the text background when running on a -composited display. - -+++ -** New frame parameter 'shaded'. -With window managers which support this, it controls whether or not a -frame's contents will be hidden, leaving only the title bar on display. - ---- -** New user option 'x-gtk-use-native-input'. -This controls whether or not GTK input methods are used by Emacs, -instead of XIM input methods. - -+++ -** New user option 'use-system-tooltips'. -This controls whether to use the toolkit tooltips, or Emacs's own -native implementation of tooltips as small frames. This option is -only meaningful if Emacs was built with GTK+, Nextstep, or Haiku -support, and defaults to t, which makes Emacs use the toolkit -tooltips. The existing GTK-specific option -'x-gtk-use-system-tooltips' is now an alias of this new option. - -+++ -** Non-native tooltips are now supported on Nextstep. -This means Emacs built with GNUstep or built on macOS is now able to -display different faces and images inside tooltips when the -'use-system-tooltips' user option is nil. - ---- -** New minor mode 'pixel-scroll-precision-mode'. -When enabled, and if your mouse supports it, you can scroll the -display up or down at pixel resolution, according to what your mouse -wheel reports. Unlike 'pixel-scroll-mode', this mode scrolls the -display pixel-by-pixel, as opposed to only animating line-by-line -scrolls. - -** Terminal Emacs - ---- -*** Emacs will now use 24-bit colors on terminals that support "Tc" capability. -This is in addition to previously-supported ways of discovering 24-bit -color support: either via the "RGB" or "setf24" capabilities, or if -the 'COLORTERM' environment variable is set to the value "truecolor". - ---- -*** Select active regions with xterm selection support. -On terminals with xterm "setSelection" support, the active region may be -saved to the X primary selection, following the -'select-active-regions' variable. This support is enabled when -'tty-select-active-regions' is non-nil. - ---- -*** New command to set up display of unsupported characters. -The new command 'standard-display-by-replacement-char' produces Lisp -code that sets up the 'standard-display-table' to use a replacement -character for display of characters that the text-mode terminal -doesn't support. This code is intended to be used in your init files. -This feature is most useful with the Linux console and similar -terminals, where Emacs has a reliable way of determining which -characters have glyphs in the font loaded into the terminal's memory. - ---- -*** New functions to set terminal output buffer size. -The new functions 'tty--set-output-buffer-size' and -'tty--output-buffer-size' allow setting and retrieving the output -buffer size of a terminal device. The default buffer size is and has -always been BUFSIZ, which is defined in your system's stdio.h. When -you set a buffer size with 'tty--set-output-buffer-size', this also -prevents Emacs from explicitly flushing the tty output stream, except -at the end of display update. - -** ERT - -+++ -*** New ERT variables 'ert-batch-print-length' and 'ert-batch-print-level'. -These variables will override 'print-length' and 'print-level' when -printing Lisp values in ERT batch test results. - ---- -*** Redefining an ERT test in batch mode now signals an error. -Executing 'ert-deftest' with the same name as an existing test causes -the previous definition to be discarded, which was probably not -intended when this occurs in batch mode. To remedy the error, rename -tests so that they all have unique names. - -+++ -*** ERT can generate JUnit test reports. -When environment variable 'EMACS_TEST_JUNIT_REPORT' is set, ERT -generates a JUnit test report under this file name. This is useful -for Emacs integration into CI/CD test environments. - ---- -*** Unbound test symbols now signal an 'ert-test-unbound' error. -This affects the 'ert-select-tests' function and its callers. - -** Emoji - -+++ -*** Emacs now has several new methods for inserting Emoji. -The Emoji commands are under the new 'C-x 8 e' prefix. - -+++ -*** New command 'emoji-insert' (bound to 'C-x 8 e e' and 'C-x 8 e i'). -This command guides you through various Emoji categories and -combinations in a graphical menu system. +** X selection requests are now handled much faster and asynchronously. +This means it should be less necessary to disable the likes of +'select-active-regions' when Emacs is running over a slow network +connection. -+++ -*** New command 'emoji-search' (bound to 'C-x 8 e s'). -This command lets you search for Emoji based on names. +** Emacs now updates invisible frames that are made visible by a compositor. +If an invisible or an iconified frame is shown to the user by the +compositing manager, Emacs will now redisplay such a frame even though +'frame-visible-p' returns nil or 'icon' for it. This can happen, for +example, as part of preview for iconified frames. +++ -*** New command 'emoji-list' (bound to 'C-x 8 e l'). -This command lists all Emoji (categorized by themes) in a special -buffer and lets you choose one of them. - ---- -*** New command 'emoji-recent' (bound to 'C-x 8 e r'). -This command lets you choose among the Emoji you have recently -inserted. - -+++ -*** New command 'emoji-describe' (bound to 'C-x 8 e d'). -This command will tell you the name of the Emoji at point. (It also -works for non-Emoji characters.) - ---- -*** New commands 'emoji-zoom-increase' and 'emoji-zoom-decrease'. -These are bound to 'C-x 8 e +' and 'C-x 8 e -', respectively. They -can be used on any character, but are mainly useful for Emoji. - ---- -*** New input method 'emoji'. -This allows you to enter Emoji using short strings, eg ':face_palm:' -or ':scream:'. - -** Help - ---- -*** Variable values displayed by 'C-h v' in "*Help*" are now fontified. - -+++ -*** New user option 'help-clean-buttons'. -If non-nil, link buttons in "*Help*" buffers will have any surrounding -quotes removed. - ---- -*** 'M-x apropos-variable' output now includes values of variables. -Such apropos buffer is more easily viewed with outlining after -enabling 'outline-minor-mode' in 'apropos-mode'. - -+++ -*** New docstring syntax to indicate that symbols shouldn't be links. -When displaying docstrings in "*Help*" buffers, strings that are -"`like-this'" are made into links (if they point to a bound -function/variable). This can lead to false positives when talking -about values that are symbols that happen to have the same names as -functions/variables. To inhibit this buttonification, use the new -"\\+`like-this'" syntax. - -+++ -*** New user option 'help-window-keep-selected'. -If non-nil, commands to show the info manual and the source will reuse -the same window in which the "*Help*" buffer is shown. - ---- -*** Commands like 'C-h f' have changed how they describe menu bindings. -For instance, previously a command might be described as having the -following bindings: - - It is bound to <open>, C-x C-f, <menu-bar> <file> <new-file>. - -This has been changed to: - - It is bound to <open> and C-x C-f. - It can also be invoked from the menu: File → Visit New File... - -+++ -*** The 'C-h .' command now accepts a prefix argument. -'C-u C-h .' would previously inhibit displaying a warning message if -there's no local help at point. This has been changed to call -'button-describe'/'widget-describe' and display button/widget help -instead. - ---- -*** New user option 'help-enable-variable-value-editing'. -If enabled, 'e' on a value in "*Help*" will pop you to a new buffer -where you can edit the value. This is not enabled by default, because -it is easy to make an edit that yields an invalid result. - ---- -*** 'C-h b' uses outlining by default. -Set 'describe-bindings-outline' to nil to get back the old behavior. - ---- -*** Jumping to function/variable source now saves mark before moving point. -Jumping to source from a "*Help*" buffer moves point when the source -buffer is already open. Now, the old point is pushed onto mark ring. - -+++ -*** New key bindings in "*Help*" buffers: 'n' and 'p'. -These will take you (respectively) to the next and previous "page". - ---- -*** 'describe-char' now also outputs the name of Emoji sequences. - -+++ -*** New key binding in "*Help*" buffer: 'I'. -This will take you to the Emacs Lisp manual entry for the item -displayed, if any. - ---- -*** The 'C-h m' ('describe-mode') "*Help*" buffer has been reformatted. -It now only includes local minor modes at the start, and the global -minor modes are listed after the major mode. - -+++ -*** The user option 'help-window-select' now affects apropos commands. -The apropos commands will now select the apropos window if -'help-window-select' is non-nil. - ---- -*** 'describe-keymap' now considers the symbol at point. -If the symbol at point is a keymap, 'describe-keymap' suggests it as -the default candidate. - ---- -*** New command 'help-quick' displays an overview of common commands. -The command pops up a buffer at the bottom of the screen with a few -helpful commands for various tasks. You can toggle the display using -'C-h C-q'. - -** Emacs now comes with Org v9.6. -See the file "ORG-NEWS" for user-visible changes in Org. - -** Outline Mode +** 'write-region-inhibit-fsync' now defaults to t in interactive mode, +as it has in batch mode since Emacs 24. +++ -*** Support for customizing the default visibility state of headings. -Customize the user option 'outline-default-state' to define what -headings will be visible initially, after Outline mode is turned on. -When the value is a number, the user option 'outline-default-rules' -determines the visibility of the subtree starting at the corresponding -level. Values are provided to control showing a heading subtree -depending on whether the heading matches a regexp, or on whether its -subtree has long lines or is itself too long. - -** Outline Minor Mode - -+++ -*** New user option 'outline-minor-mode-use-buttons'. -If non-nil, Outline Minor Mode will use buttons to hide/show outlines -in addition to the ellipsis. The default is nil, but in 'help-mode' -it has the value 'insert' that inserts the buttons directly into the -buffer, and you can use 'RET' to cycle outline visibility. When -the value is 'in-margins', Outline Minor Mode uses the window margins -for buttons that hide/show outlines. - -+++ -*** Buttons and headings now have their own keymaps. -'outline-button-icon-map', 'outline-overlay-button-map', and -'outline-inserted-button-map' are now available as defined keymaps -instead of being anonymous keymaps. - -** Windows - -+++ -*** New commands 'split-root-window-below' and 'split-root-window-right'. -These commands split the root window in two, and are bound to 'C-x w 2' -and 'C-x w 3', respectively. A number of other useful window-related -commands are now available with key sequences that start with the -'C-x w' prefix. - -+++ -*** New user option 'display-buffer-avoid-small-windows'. -If non-nil, this should be a window height in lines, a number. -Windows smaller than this will be avoided by 'display-buffer', if -possible. - -+++ -*** New display action 'display-buffer-full-frame'. -This action removes other windows from the frame when displaying a -buffer on that frame. - -+++ -*** 'display-buffer' now can set up the body size of the chosen window. -For example, a 'display-buffer-alist' entry of - - (window-width . (body-columns . 40)) - -will make the body of the chosen window 40 columns wide. For the -height use 'window-height' and 'body-lines', respectively. - ---- -*** You can customize on which window 'scroll-other-window' operates. -This is controlled by the new 'other-window-scroll-default' variable. - -** Frames - -+++ -*** 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 - ---- -*** New user option 'tab-bar-auto-width' to automatically determine tab width. -This option is non-nil by default, which resizes tab-bar tabs so that -their width is evenly distributed across the tab bar. A companion -option 'tab-bar-auto-width-max' controls the maximum width of a tab -before its name on display is truncated. - ---- -*** 'C-x t RET' creates a new tab when the provided tab name doesn't exist. -It prompts for the name of a tab and switches to it, creating a new -tab if no tab exists by that name. - ---- -*** New keymap 'tab-bar-history-mode-map'. -By default, it contains 'C-c <left>' and 'C-c <right>' to browse -the history of tab window configurations back and forward. - ---- -** Better detection of text suspiciously reordered on display. -The function 'bidi-find-overridden-directionality' has been extended -to detect reordering effects produced by embeddings and isolates -(started by directional formatting control characters such as RLO and -LRI). The new command 'highlight-confusing-reorderings' finds and -highlights segments of buffer text whose reordering for display is -suspicious and could be malicious. - -** Emacs Server and Client - -+++ -*** New command-line option '-r'/'--reuse-frame' for emacsclient. -With this command-line option, Emacs reuses an existing graphical client -frame if one exists; otherwise it creates a new frame. - -+++ -*** New command-line option '-w N'/'--timeout=N' for emacsclient. -With this command-line option, emacsclient will exit if Emacs does not -respond within N seconds. The default is to wait forever. - -+++ -*** 'server-stop-automatically' can be used to automatically stop the server. -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'. - -+++ -*** New user option 'rcirc-cycle-completion-flag'. -Rcirc will use the default 'completion-at-point' mechanism. The -conventional IRC behavior of completing by cycling through the -available options can be restored by enabling this option. - -+++ -*** New user option 'rcirc-bridge-bot-alist'. -If you are in a channel where a bot is responsible for bridging -between networks, you can use this variable to make these messages -appear more native. For example, you might set the option to: - - (setopt rcirc-bridge-bot-alist '(("bridge" . "{\\(.+?\\)}[[:space:]]+"))) - -for messages like - - 09:47 <bridge> {john} I am not on IRC - -to be reformatted into - - 09:47 <john> I am not on IRC - ---- -*** New formatting commands. -Most IRC clients (including rcirc) support basic formatting using -control codes. Under the 'C-c C-f' prefix a few commands have been -added to insert these automatically. For example, if a region is -active and 'C-c C-f C-b' is invoked, markup is inserted for the region -to be highlighted in bold. - -** Imenu +** New user option 'remote-file-name-inhibit-delete-by-moving-to-trash'. +When non-nil, this option suppresses moving remote files to the local +trash when deleting. Default is nil. +++ -*** 'imenu' is now bound to 'M-g i' globally. - ---- -*** New function 'imenu-flush-cache'. -Use it if you want Imenu to forget the buffer's index alist and -recreate it anew next time 'imenu' is invoked. - ---- -** Emacs is now capable of abandoning a window's redisplay that takes too long. -This is controlled by the new variable 'max-redisplay-ticks'. If that -variable is set to a non-zero value, display of a window will be -aborted after that many low-level redisplay operations, thus -preventing Emacs from becoming wedged when visiting files with very -long lines. The default is zero, which disables the feature: Emacs -will wait forever for redisplay to finish. (We believe you won't need -this feature, given the ability to display buffers with very long -lines.) +** New user option 'yes-or-no-prompt'. +This allows the user to customize the prompt that is appended by +'yes-or-no-p' when asking questions. The default value is +"(yes or no) ". -* Editing Changes in Emacs 29.1 - -+++ -** 'M-SPC' is now bound to 'cycle-spacing'. -Formerly it invoked 'just-one-space'. The actions performed by -'cycle-spacing' and their order can now be customized via the user -option 'cycle-spacing-actions'. +* Editing Changes in Emacs 30.1 --- -** 'zap-to-char' and 'zap-up-to-char' are case-sensitive for upper-case chars. -These commands now behave as case-sensitive for interactive calls when -they are invoked with an uppercase character, regardless of the value -of 'case-fold-search'. - ---- -** 'scroll-other-window' and 'scroll-other-window-down' now respect remapping. -These commands (bound to 'C-M-v' and 'C-M-V') used to scroll the other -windows without looking at customizations in that other window. These -functions now check whether they have been rebound in the buffer shown -in that other window, and then call the remapped function instead. In -addition, these commands now also respect the -'scroll-error-top-bottom' user option. - ---- -** Indentation of 'cl-flet' and 'cl-labels' has changed. -These forms now indent like this: - - (cl-flet ((bla (x) - (* x x))) - (bla 42)) - -This change also affects 'cl-macrolet', 'cl-flet*' and -'cl-symbol-macrolet'. - -+++ -** New user option 'translate-upper-case-key-bindings'. -Set this option to nil to inhibit the default translation of upper -case keys to their lower case variants. - -+++ -** New command 'ensure-empty-lines'. -This command increases (or decreases) the number of empty lines before -point. - ---- -** Improved mouse behavior with auto-scrolling modes. -When clicking inside the 'scroll-margin' or 'hscroll-margin' region, -point is now moved only when releasing the mouse button. This no -longer results in a bogus selection, unless the mouse has also been -dragged. +** New command 'kill-matching-buffers-no-ask'. +This works like 'kill-matching-buffers', but without asking for +confirmation. +++ -** 'kill-ring-max' now defaults to 120. - ---- -** New user option 'yank-menu-max-items'. -Customize this option to limit the number of entries in the menu -"Edit → Paste from Kill Menu". The default is 60. +** New helper variable 'transpose-sexps-function'. +Emacs now can set this variable to customize the behavior of the +'transpose-sexps' function. +++ -** Performing a pinch gesture on a touchpad now increases the text scale. - -** Show Paren Mode - -+++ -*** New user option 'show-paren-context-when-offscreen'. -When non-nil, if the point is in a closing delimiter and the opening -delimiter is offscreen, shows some context around the opening -delimiter in the echo area. The default is nil. - -This option can also be set to the symbols 'overlay' or 'child-frame', -in which case the context is shown in an overlay or child-frame at the -top-left of the current window. The latter option requires a -graphical frame. On non-graphical frames, the context is shown in the -echo area. - -** Comint - -+++ -*** 'comint-term-environment' is now aware of connection-local variables. -The user option 'comint-terminfo-terminal' and the variable -'system-uses-terminfo' can now be set as connection-local variables to -change the terminal used on a remote host. - ---- -*** New user option 'comint-delete-old-input'. -When nil, this prevents comint from deleting the current input when -inserting previous input using '<mouse-2>'. The default is t, to -preserve previous behavior. - ---- -*** New minor mode 'comint-fontify-input-mode'. -This minor mode is enabled by default in "*shell*" and "*ielm*" -buffers. It fontifies input text according to 'shell-mode' or -'emacs-lisp-mode' font-lock rules. Customize the user options -'shell-fontify-input-enable' and 'ielm-fontify-input-enable' to nil if -you don't want to enable input fontification by default. - -** Mwheel - ---- -*** New user options for alternate wheel events. -The user options 'mouse-wheel-down-alternate-event' and -'mouse-wheel-up-alternate-event' as well as the variables -'mouse-wheel-left-alternate-event' and -'mouse-wheel-right-alternate-event' have been added to better support -systems where two kinds of wheel events can be received. - -** Internationalization - ---- -*** The '<Delete>' function key now allows deleting the entire composed sequence. -For the details, see the item about the 'delete-forward-char' command -above. - ---- -*** New user option 'composition-break-at-point'. -Setting it to a non-nil value temporarily disables automatic -composition of character sequences at point, and thus makes it easier -to edit such sequences by allowing point to "enter" the composed -sequence. - ---- -*** Support for many old scripts and writing systems. -Emacs now supports, and has language-environments and input methods, -for several dozens of old scripts that were used in the past for -various languages. For each such script Emacs now has font-selection -and character composition rules, a language environment, and an input -method. The newly-added scripts and the corresponding language -environments are: - - Tai Tham script and the Northern Thai language environment - - Brahmi script and language environment - - Kaithi script and language environment - - Tirhuta script and language environment +** New function 'transpose-sexps-default-function'. +The previous implementation is moved into its own function, to be +bound by 'transpose-sexps-function'. - Sharada script and language environment +** New function 'treesit-transpose-sexps'. +Tree-sitter now unconditionally sets 'transpose-sexps-function' for all +tree-sitter enabled modes. This functionality utilizes the new +'transpose-sexps-function'. - Siddham script and language environment +** Commands and variables to move by program statements - Syloti Nagri script and language environment +*** New variable 'forward-sentence-function'. +Major modes can now set this variable to customize the behavior of the +'forward-sentence' command. - Modi script and language environment +*** New function 'forward-sentence-default-function'. +The previous implementation of 'forward-sentence' is moved into its +own function, to be bound by 'forward-sentence-function'. - Baybayin script and Tagalog language environment +*** New buffer-local variable 'treesit-sentence-type-regexp'. +Similarly to 'treesit-defun-type-regexp', this variable is used to +define "sentences" in tree-sitter enabled modes. - Hanunoo script and language environment +*** New function 'treesit-forward-sentence'. +All tree-sitter enabled modes that define 'treesit-sentence-type-regexp' +now set 'forward-sentence-function' to call 'treesit-forward-sentence'. - Buhid script and language environment +*** New buffer-local variable 'treesit-sexp-type-regexp'. +Similarly to 'treesit-defun-type-regexp', this variable is used to +define "sexps" in tree-sitter enabled modes. - Tagbanwa script and language environment - - Limbu script and language environment - - Balinese script and language environment - - Javanese script and language environment - - Sundanese script and language environment - - Batak script and language environment - - Rejang script and language environment - - Makasar script and language environment - - Lontara script and language environment - - Hanifi Rohingya script and language environment - - Grantha script and language environment - - Kharoshthi script and language environment - - Lepcha script and language environment - - Meetei Mayek script and language environment - - Adlam script and language environment - - Mende Kikakui script and language environment - - Wancho script and language environment - - Toto script and language environment - - Gothic script and language environment - - Coptic script and language environment - ---- -*** The "Oriya" language environment was renamed to "Odia". -This is to follow the change in the official name of the script. The -'oriya' input method was also renamed to 'odia'. However, the old -name of the language environment and the input method are still -supported. - ---- -*** New Greek translation of the Emacs tutorial. -Type 'C-u C-h t' to select it in case your language setup does not do -so automatically. - ---- -*** New Ukrainian translation of the Emacs Tutorial. - ---- -*** New default phonetic input method for the Tamil language environment. -The default input method for the Tamil language environment is now -"tamil-phonetic" which is a customizable phonetic input method. To -change the input method's translation rules, customize the user option -'tamil-translation-rules'. - ---- -*** New 'tamil99' input method for the Tamil language. -This supports the keyboard layout specifically designed for the Tamil -language. - ---- -*** New input method 'slovak-qwerty'. -This is a variant of the 'slovak' input method, which corresponds to -the QWERTY Slovak keyboards. - ---- -*** New input method 'cyrillic-chuvash'. -This input method is based on the russian-computer input method, and -is intended for typing in the Chuvash language written in the Cyrillic -script. +*** New function 'treesit-forward-sexp'. +Tree-sitter conditionally sets 'forward-sexp-function' for major modes +that have defined 'treesit-sexp-type-regexp' to enable sexp-related +motion commands. -* Changes in Specialized Modes and Packages in Emacs 29.1 - -** Ecomplete - ---- -*** New commands 'ecomplete-edit' and 'ecomplete-remove'. -These allow you to (respectively) edit and bulk-remove entries from -the ecomplete database. - ---- -*** New user option 'ecomplete-auto-select'. -If non-nil and there's only one matching option, auto-select that. - ---- -*** New user option 'ecomplete-filter-regexp'. -If non-nil, this user option describes what entries not to add to the -database stored on disk. - -** Auth Source - -+++ -*** New user option 'auth-source-pass-extra-query-keywords'. -Whether to recognize additional keyword params, like ':max' and -':require', as well as accept lists of query terms paired with -applicable keywords. This disables most known behavioral quirks -unique to auth-source-pass, such as wildcard subdomain matching. - -** Dired - -+++ -*** 'dired-guess-shell-command' moved from dired-x to dired. -This means that 'dired-do-shell-command' will now provide smarter -defaults without first having to require 'dired-x'. See the node -"(emacs) Shell Command Guessing" in the Emacs manual for more details. - ---- -*** 'dired-clean-up-buffers-too' moved from dired-x to dired. -This means that Dired now offers to kill buffers visiting files and -dirs when they are deleted in Dired. Before, you had to require -'dired-x' to enable this behavior. To disable this behavior, -customize the user option 'dired-clean-up-buffers-too' to nil. The -related user option 'dired-clean-confirm-killing-deleted-buffers' -(which see) has also been moved to 'dired'. - -+++ -*** 'dired-do-relsymlink' moved from dired-x to dired. -The corresponding key 'Y' is now bound by default in Dired. - -+++ -*** 'dired-do-relsymlink-regexp' moved from dired-x to dired. -The corresponding key sequence '% Y' is now bound by default in Dired. - ---- -*** 'M-G' is now bound to 'dired-goto-subdir'. -Before, that binding was only available if the dired-x package was -loaded. - -+++ -*** 'dired-info' and 'dired-man' moved from dired-x to dired. -The 'dired-info' and 'dired-man' commands have been moved from the -dired-x package to dired. They have also been renamed to -'dired-do-info' and 'dired-do-man'; the old command names are obsolete -aliases. - -The keys 'I' ('dired-do-info') and 'N' ('dired-do-man') are now bound -in Dired mode by default. The user options 'dired-bind-man' and -'dired-bind-info' no longer have any effect and are obsolete. - -To get the old behavior back and unbind these keys in Dired mode, add -the following to your Init file: - - (with-eval-after-load 'dired - (keymap-set dired-mode-map "N" nil) - (keymap-set dired-mode-map "I" nil)) - ---- -*** New command 'dired-do-eww'. -This command visits the file on the current line with EWW. - ---- -*** New user option 'dired-omit-lines'. -This is used by 'dired-omit-mode', and now allows you to hide based on -other things than just the file names. - -+++ -*** New user option 'dired-mouse-drag-files'. -If non-nil, dragging file names with the mouse in a Dired buffer will -initiate a drag-and-drop session allowing them to be opened in other -programs. - -+++ -*** New user option 'dired-free-space'. -Dired will now, by default, include the free space in the first line -instead of having it on a separate line. To get the previous behavior -back, say: - - (setopt dired-free-space 'separate) - ---- -*** New user option 'dired-make-directory-clickable'. -If non-nil (which is the default), hitting 'RET' or 'mouse-1' on -the directory components at the directory displayed at the start of -the buffer will take you to that directory. - ---- -*** Search and replace in Dired/Wdired supports more regexps. -For example, the regexp ".*" will match only characters that are part -of the file name. Also "^.*$" can be used to match at the beginning -of the file name and at the end of the file name. This is used only -when searching on file names. In Wdired this can be used when the new -user option 'wdired-search-replace-filenames' is non-nil (which is the -default). - -** Elisp - ---- -*** New command 'elisp-eval-region-or-buffer' (bound to 'C-c C-e'). -This command evals the forms in the active region or in the whole buffer. - ---- -*** New commands 'elisp-byte-compile-file' and 'elisp-byte-compile-buffer'. -These commands (bound to 'C-c C-f' and 'C-c C-b', respectively) -byte-compile the visited file and the current buffer, respectively. - -** Games - ---- -*** New user option 'tetris-allow-repetitions'. -This controls how randomness is implemented (whether to use pure -randomness as before, or to use a bag). - -** Battery - -+++ -*** New user option 'battery-update-functions'. -This can be used to trigger actions based on the battery status. - -** DocView - ---- -*** doc-view can now generate SVG images when viewing PDF files. -If Emacs is built with SVG support, doc-view can generate SVG files -when using MuPDF as the converter for PDF files, which generally leads -to sharper images (especially when zooming), and allows customization -of background and foreground color of the page via the new user -options 'doc-view-svg-background' and 'doc-view-svg-foreground'. To -activate this behavior, set 'doc-view-mupdf-use-svg' to non-nil if -your Emacs has SVG support. Note that, with some versions of MuPDF, -SVG generation is known to sometimes produce SVG files that are buggy -or can take a long time to render. - -** Enriched Mode - -+++ -*** New command 'enriched-toggle-markup'. -This allows you to see the markup in 'enriched-mode' buffers (e.g., -the "HELLO" file). - -** Shell Script Mode - ---- -*** New user option 'sh-indent-statement-after-and'. -This controls how statements like the following are indented: - - foo && - bar - -*** New Flymake backend using the ShellCheck program. -It is enabled by default, but requires that the external "shellcheck" -command is installed. - -** CC Mode - ---- -*** C++ Mode now supports most of the new features in the C++20 Standard. - ---- -*** In Objective-C Mode, no extra types are recognized by default. -The default value of 'objc-font-lock-extra-types' has been changed to -nil, since too many identifiers were getting misfontified as types. -This may cause some actual types not to get fontified. To get the old -behavior back, customize the user option to the value suggested in its -doc string. - -** Cperl Mode - ---- -*** New user option 'cperl-file-style'. -This option determines the indentation style to be used. It can also -be used as a file-local variable. - -** Gud - ---- -*** 'gud-go' is now bound to 'C-c C-v'. -If given a prefix, it will prompt for an argument to use for the -run/continue command. - ---- -*** 'perldb' now recognizes '-E'. -As of Perl 5.10, 'perl -E 0' behaves like 'perl -e 0' but also activates -all optional features of the Perl version in use. 'perldb' now uses -this invocation as its default. - -** Customize - ---- -*** New command 'custom-toggle-hide-all-widgets'. -This is bound to 'H' and toggles whether to hide or show the widget -contents. - -** Diff Mode - ---- -*** New user option 'diff-whitespace-style'. -Sets the value of the buffer-local variable 'whitespace-style' in -'diff-mode' buffers. By default, this variable is '(face trailing)', -which preserves behavior of previous Emacs versions. - -+++ -*** New user option 'diff-add-log-use-relative-names'. -If non-nil insert file names in ChangeLog skeletons relative to the -VC root directory. - -** Ispell - ---- -*** 'ispell-region' and 'ispell-buffer' now push the mark. -These commands push onto the mark ring the location of the last -misspelled word where corrections were offered, so that you can then -skip back to that location with 'C-x C-x'. - -** Dabbrev - ---- -*** New function 'dabbrev-capf' for use on 'completion-at-point-functions'. - -+++ -*** New user option 'dabbrev-ignored-buffer-modes'. -Buffers with major modes in this list will be ignored. By default, -this includes "binary" buffers like 'archive-mode' and 'image-mode'. - -** Package - -+++ -*** New command 'package-update'. -This command allows you to upgrade packages without using 'M-x -list-packages'. - -+++ -*** New command 'package-update-all'. -This command allows updating all packages without any queries. - -+++ -*** New commands 'package-recompile' and 'package-recompile-all'. -These commands can be useful if the ".elc" files are out of date -(invalid byte code and macros). - -+++ -*** New DWIM action on 'x' in "*Packages*" buffer. -If no packages are marked, 'x' will install the package under point if -it isn't already, and remove it if it is installed. - -+++ -*** New command 'package-vc-install'. -Packages can now be installed directly from source by cloning from -their repository. - -+++ -*** New command 'package-vc-install-from-checkout'. -An existing checkout can now be loaded via package.el, by creating a -symbolic link from the usual package directory to the checkout. - -+++ -*** New command 'package-vc-checkout'. -Used to fetch the source of a package by cloning a repository without -activating the package. - -+++ -*** New command 'package-vc-prepare-patch'. -This command allows you to send patches to package maintainers, for -packages checked out using 'package-vc-install'. - -+++ -*** New command 'package-report-bug'. -This command helps you compose an email for sending bug reports to -package maintainers. - -+++ -*** New user option 'package-vc-selected-packages'. -By customizing this user option you can specify specific packages to -install. - -** Emacs Sessions (Desktop) - -+++ -*** New user option to load a locked desktop if locking Emacs is not running. -The option 'desktop-load-locked-desktop' can now be set to the value -'check-pid', which means to allow loading a locked ".emacs.desktop" -file if the Emacs process which locked it is no longer running on the -local machine. This allows avoiding questions about locked desktop -files when the Emacs session which locked it crashes, or was otherwise -interrupted and didn't exit gracefully. See the "(emacs) Saving -Emacs Sessions" node in the Emacs manual for more details. - -** Miscellaneous - -+++ -*** New command 'scratch-buffer'. -This command switches to the "*scratch*" buffer. If "*scratch*" doesn't -exist, the command creates it first. You can use this command if you -inadvertently delete the "*scratch*" buffer. - -** Debugging - +* Changes in Specialized Modes and Packages in Emacs 30.1 --- -*** 'q' in a "*Backtrace*" buffer no longer clears the buffer. -Instead it just buries the buffer and switches the mode from -'debugger-mode' to 'backtrace-mode', since commands like 'e' are no -longer available after exiting the recursive edit. +** Variable order and truncation can now be configured in 'gdb-many-windows'. +The new user option 'gdb-locals-table-row-config' allows users to +configure the order and max length of various properties in the local +variables buffer when using 'gdb-many-windows'. -+++ -*** New user option 'debug-allow-recursive-debug'. -This user option controls whether the 'e' (in a "*Backtrace*" -buffer or while edebugging) and 'C-x C-e' (while edebugging) commands -lead to a (further) backtrace. By default, this variable is nil, -which is a change in behavior from previous Emacs versions. - -+++ -*** 'e' in edebug can now take a prefix arg to pretty-print the results. -When invoked with a prefix argument, as in 'C-u e', this command will -pop up a new buffer and show the full pretty-printed value there. +By default, this user option is set to write the properties in the order: +name, type and value, where the name and type are truncated to 20 +characters, and the value is truncated according to the value of +'gdb-locals-value-limit'. -+++ -*** 'C-x C-e' now interprets a non-zero prefix arg to pretty-print the results. -When invoked with a non-zero prefix argument, as in 'C-u C-x C-e', -this command will pop up a new buffer and show the full pretty-printed -value there. - -+++ -*** You can now generate a backtrace from Lisp errors in redisplay. -To do this, set the new variable 'backtrace-on-redisplay-error' to a -non-nil value. The backtrace will be written to a special buffer -named "*Redisplay-trace*". This buffer will not be automatically -displayed in a window. - -** Compile - -+++ -*** New user option 'compilation-hidden-output'. -This can be used to make specific parts of compilation output -invisible. - -+++ -*** The 'compilation-auto-jump-to-first-error' user option has been extended. -It can now have the additional values 'if-location-known' (which will -only jump if the location of the first error is known), and -'first-known' (which will jump to the first known error location). - -+++ -*** New user option 'compilation-max-output-line-length'. -Lines longer than the value of this option will have their ends -hidden, with a button to reveal the hidden text. This speeds up -operations like grepping on files that have few newlines. The default -value is 400; set to nil to disable hiding. - -** Flymake - -+++ -*** New user option 'flymake-mode-line-lighter'. - -+++ -** New minor mode 'word-wrap-whitespace-mode' for extending 'word-wrap'. -This mode switches 'word-wrap' on, and breaks on all the whitespace -characters instead of just 'SPC' and 'TAB'. +If you want to get back the old behavior, set the user option to the value ---- -** New mode, 'emacs-news-mode', for editing the NEWS file. -This mode adds some highlighting, makes the 'M-q' command aware of the -format of NEWS entries, and has special commands for doing maintenance -of the Emacs NEWS files. In addition, this mode turns on -'outline-minor-mode', and thus displays customizable icons (see -'icon-preference') in the margins. To disable these icons, set -'outline-minor-mode-use-buttons' to a nil value. - ---- -** Kmacro -Kmacros are now OClosures and have a new constructor 'kmacro' which -uses the 'key-parse' syntax. It replaces the old 'kmacro-lambda-form' -(which is now declared obsolete). - ---- -** savehist.el can now truncate variables that are too long. -An element of user option 'savehist-additional-variables' can now be -of the form '(VARIABLE . MAX-ELTS)', which means to truncate the -VARIABLE's value to at most MAX-ELTS elements (if the value is a list) -before saving the value. - -** Minibuffer and Completions - -+++ -*** New commands for navigating completions from the minibuffer. -When the minibuffer is the current buffer, typing 'M-<up>' or -'M-<down>' selects a previous/next completion candidate from the -"*Completions*" buffer and inserts it to the minibuffer. -When the user option 'minibuffer-completion-auto-choose' is nil, -'M-<up>' and 'M-<down>' do the same, but without inserting -a completion candidate to the minibuffer, then 'M-RET' can be used -to choose the currently active candidate from the "*Completions*" -buffer and exit the minibuffer. With a prefix argument, 'C-u M-RET' -inserts the currently active candidate to the minibuffer, but doesn't -exit the minibuffer. These keys are also available for in-buffer -completion, but they don't insert candidates automatically, you need -to type 'M-RET' to insert the selected candidate to the buffer. - -+++ -*** Choosing a completion with a prefix argument doesn't exit the minibuffer. -This means that typing 'C-u RET' on a completion candidate in the -"*Completions*" buffer inserts the completion into the minibuffer, -but doesn't exit the minibuffer. - -+++ -*** The "*Completions*" buffer can now be automatically selected. -To enable this behavior, customize the user option -'completion-auto-select' to t, then pressing 'TAB' will switch to the -"*Completions*" buffer when it pops up that buffer. If the value is -'second-tab', then the first 'TAB' will display "*Completions*", and -the second one will switch to the "*Completions*" buffer. - ---- -*** New user option 'completion-auto-wrap'. -When non-nil, the commands 'next-completion' and 'previous-completion' -automatically wrap around on reaching the beginning or the end of -the "*Completions*" buffer. - -+++ -*** New values for the 'completion-auto-help' user option. -There are two new values to control the way the "*Completions*" buffer -behaves after pressing a 'TAB' if completion is not unique. The value -'always' updates or shows the "*Completions*" buffer after any attempt -to complete. The value 'visual' is like 'always', but only updates -the completions if they are already visible. The default value t -always hides the completion buffer after some completion is made. - ---- -*** New commands to complete the minibuffer history. -'minibuffer-complete-history' ('C-x <up>') is like 'minibuffer-complete' -but completes on the history items instead of the default completion -table. 'minibuffer-complete-defaults' ('C-x <down>') completes -on the list of default items. - -+++ -*** User option 'minibuffer-eldef-shorten-default' is now obsolete. -Customize the user option 'minibuffer-default-prompt-format' instead. - -+++ -*** New user option 'completions-sort'. -This option controls the sorting of the completion candidates in -the "*Completions*" buffer. Available styles are no sorting, -alphabetical (the default), or a custom sort function. - -+++ -*** New user option 'completions-max-height'. -This option limits the height of the "*Completions*" buffer. - -+++ -*** New user option 'completions-header-format'. -This is a string to control the header line to show in the -"*Completions*" buffer before the list of completions. -If it contains "%s", that is replaced with the number of completions. -If nil, the header line is not shown. - -+++ -*** New user option 'completions-highlight-face'. -When this user option names a face, the current -candidate in the "*Completions*" buffer is highlighted with that face. -The nil value disables this highlighting. The default is to highlight -using the 'completions-highlight' face. - -+++ -*** You can now define abbrevs for the minibuffer modes. -'minibuffer-mode-abbrev-table' and -'minibuffer-inactive-mode-abbrev-table' are now defined. - -** Isearch and Replace - -+++ -*** Changes in how Isearch responds to 'mouse-yank-at-point'. -If a user does 'C-s' and then uses '<mouse-2>' ('mouse-yank-primary') -outside the echo area, Emacs will, by default, end the Isearch and -yank the text at mouse cursor. But if 'mouse-yank-at-point' is -non-nil, the text will now be added to the Isearch instead. - -+++ -*** Changes for values 'no' and 'no-ding' of 'isearch-wrap-pause'. -Now with these values the search will wrap around not only on repeating -with 'C-s C-s', but also after typing a character. - -+++ -*** New user option 'char-fold-override'. -Non-nil means that the default definitions of equivalent characters -are overridden. - -*** New command 'describe-char-fold-equivalences'. -It displays character equivalences used by 'char-fold-to-regexp'. - -+++ -*** 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. - -** Glyphless Characters - -+++ -*** New minor mode 'glyphless-display-mode'. -This allows an easy way to toggle seeing all glyphless characters in -the current buffer. - ---- -*** The extra slot of 'glyphless-char-display' can now have cons values. -The extra slot of the 'glyphless-char-display' char-table can now have -values that are cons cells, specifying separate values for text-mode -and GUI terminals. - -+++ -*** "Replacement character" feature for undisplayable characters on TTYs. -The 'acronym' method of displaying glyphless characters on text-mode -frames treats single-character acronyms specially: they are displayed -without the surrounding '[..]' "box", thus in effect treating such -"acronyms" as replacement characters. - -** Registers - -+++ -*** Buffer names can now be stored in registers. -For instance, to enable jumping to the "*Messages*" buffer with -'C-x r j m': - - (set-register ?m '(buffer . "*Messages*")) - -** Pixel Fill - -+++ -*** This is a new package that deals with filling variable-pitch text. - -+++ -*** New function 'pixel-fill-region'. -This fills the region to be no wider than a specified pixel width. - -** Info - -+++ -*** Command 'info-apropos' now takes a prefix argument to search for regexps. - ---- -*** New command 'Info-goto-node-web' and key binding 'G'. -This will take you to the "gnu.org" web server's version of the current -info node. This command only works for the Emacs and Emacs Lisp manuals. - -** Shortdoc - ---- -*** New command 'shortdoc-copy-function-as-kill' bound to 'w'. -It copies the name of the function near point into the kill ring. - ---- -*** 'N' and 'P' are now bound to 'shortdoc-{next,previous}-section'. -This is in addition to the old keybindings 'C-c C-n' and 'C-c C-p'. + (setopt gdb-locals-table-row-config + `((type . 0) (name . 0) (value . ,gdb-locals-value-limit))) ** VC --- -*** New command 'vc-pull-and-push'. -This commands first does a "pull" command, and if that is successful, -does a "push" command afterwards. Currently supported in Git and Bzr. - -+++ -*** 'C-x v b' prefix key is used now for branch commands. -'vc-print-branch-log' is bound to 'C-x v b l', and new commands are -'vc-create-branch' ('C-x v b c') and 'vc-switch-branch' ('C-x v b s'). -The VC Directory buffer now uses the prefix 'b' for these branch-related -commands. - -+++ -*** New command 'vc-dir-mark-by-regexp' bound to '% m' and '* %'. -This command marks files based on a regexp. If given a prefix -argument, unmark instead. - -+++ -*** New command 'C-x v !' ('vc-edit-next-command'). -This prefix command requests editing of the next VC shell command -before execution. For example, in a Git repository, you can produce a -log of more than one branch by typing 'C-x v ! C-x v b l' and then -appending additional branch names to the 'git log' command. - ---- -*** 'C-x v v' in a diffs buffer allows to commit only some of the changes. -This command is intended to allow you to commit only some of the -changes you have in your working tree. Begin by creating a buffer -with the changes against the last commit, e.g. with 'C-x v D' -('vc-root-diff'). Then edit the diffs to remove the hunks you don't -want to commit. Finally, type 'C-x v v' in that diff buffer to commit -only part of your changes, those whose hunks were left in the buffer. - ---- -*** 'C-x v v' on an unregistered file will now use the most specific backend. -Previously, if you had an SVN-covered "~/" directory, and a Git-covered -directory in "~/foo/bar", using 'C-x v v' on a new, unregistered file -"~/foo/bar/zot" would register it in the SVN repository in "~/" instead of -in the Git repository in "~/foo/bar". This makes this command -consistent with 'vc-responsible-backend'. +*** New user option 'vc-git-shortlog-switches'. +This is a string or a list of strings that specifies the Git log +switches for shortlogs, such as the one produced by 'C-x v L'. +'vc-git-log-switches' is no longer used for shortlogs. ---- -*** Log Edit now fontifies long Git commit summary lines. -Writing shorter summary lines avoids truncation in contexts in which -Git commands display summary lines. See the two new user options -'vc-git-log-edit-summary-target-len' and 'vc-git-log-edit-summary-max-len'. - ---- -*** New 'log-edit-headers-separator' face. -It is used to style the line that separates the 'log-edit' headers -from the 'log-edit' summary. +** Buffer Selection --- -*** The function 'vc-read-revision' accepts a new MULTIPLE argument. -If non-nil, multiple revisions can be queried. This is done using -'completing-read-multiple'. - ---- -*** New function 'vc-read-multiple-revisions'. -This function invokes 'vc-read-revision' with a non-nil value for -MULTIPLE. - -+++ -*** New command 'vc-prepare-patch'. -Patches for any version control system can be prepared using VC. The -command will query what commits to send and will compose messages for -your mail user agent. The behavior of 'vc-prepare-patch' can be -modified by the user options 'vc-prepare-patches-separately' and -'vc-default-patch-addressee'. - -** Message - ---- -*** New user option 'mml-attach-file-at-the-end'. -If non-nil, 'C-c C-a' will put attached files at the end of the message. - ---- -*** Message Mode now supports image yanking. - -+++ -*** New user option 'message-server-alist'. -This controls automatic insertion of the "X-Message-SMTP-Method" -header before sending a message. - -** HTML Mode - ---- -*** HTML Mode now supports "text/html" and "image/*" yanking. - -** Texinfo Mode - ---- -*** 'texinfo-mode' now has a specialized 'narrow-to-defun' definition. -It narrows to the current node. - -** EUDC - -+++ -*** Deprecations planned for next release. -After Emacs 29.1, some aspects of EUDC will be deprecated. The goal -of these deprecations is to simplify EUDC server configuration by -making 'eudc-server-hotlist' the only place to add servers. There -will not be a need to set the server using the 'eudc-set-server' -command. Instead, the 'eudc-server-hotlist' user option should be -customized to have an entry for the server. The plan is to obsolete -the 'eudc-hotlist' package since Customize is sufficient for changing -'eudc-server-hotlist'. How the 'eudc-server' user option works in this -context is to-be-determined; it can't be removed, because that would -break compatibility, but it may become synchronized with -'eudc-server-hotlist' so that 'eudc-server' is always equal to '(car -eudc-server-hotlist)'. The first entry in 'eudc-server-hotlist' is the -first server tried by 'eudc-expand-try-all'. The hotlist -simplification will allow 'eudc-query-form' to show a drop down of -possible servers, instead of requiring a call to 'eudc-set-server' -like it does in this release. The default value of -'eudc-ignore-options-file' will be changed from nil to t. - -+++ -*** New user option 'eudc-ignore-options-file' that defaults to nil. -The 'eudc-ignore-options-file' user option can be configured to ignore -the 'eudc-options-file' (typically "~/.emacs.d/eudc-options"). Most -users should configure this to t and put EUDC configuration in the -main Emacs initialization file ("~/.emacs" or "~/.emacs.d/init.el"). - -+++ -*** 'eudc-expansion-overwrites-query' to 'eudc-expansion-save-query-as-kill'. -The user option 'eudc-expansion-overwrites-query' is renamed to -'eudc-expansion-save-query-as-kill' to reflect the actual behavior of -the user option. The former is kept as alias. - -+++ -*** New command 'eudc-expand-try-all'. -This command can be used in place of 'eudc-expand-inline'. It takes a -prefix argument that causes 'eudc-expand-try-all' to return matches -from all servers instead of just the matches from the first server to -return any. This is useful for example, if one wants to search LDAP -for a name that happens to match a contact in one's BBDB. - -+++ -*** New behavior and default for user option 'eudc-inline-expansion-format'. -EUDC inline expansion result formatting defaulted to - - ("%s %s <%s>" firstname name email) - -Since email address specifications need to comply with RFC 5322 in -order to be useful in messages, there was a risk to produce syntax -which was standard with RFC 822, but is marked as obsolete syntax by -its successor RFC 5322. Also, the first and last name part was never -enclosed in double quotes, potentially producing invalid address -specifications, which may be rejected by a receiving MTA. Thus, this -variable can now additionally be set to nil (the new default), or a -function. In both cases, the formatted result will be in compliance -with RFC 5322. When set to nil, a default format very similar to the -old default will be produced. When set to a function, that function -is called, and the returned values are used to populate the phrase and -comment parts (see RFC 5322 for definitions). In both cases, the -phrase part will be automatically quoted if necessary. - -+++ -*** New function 'eudc-capf-complete' with 'message-mode' integration. -EUDC can now contribute email addresses to 'completion-at-point' by -adding the new function 'eudc-capf-complete' to -'completion-at-point-functions' in 'message-mode'. - -+++ -*** Additional attributes of query and results in eudcb-macos-contacts.el. -The EUDC back-end for the macOS Contacts app now provides a wider set -of attributes to use for queries, and delivers more attributes in -query results. - -+++ -*** New back-end for ecomplete. -A new back-end for ecomplete allows information from that database to -be queried by EUDC, too. The attributes present in the EUDC query are -used to select the entry type in the ecomplete database. - -+++ -*** New back-end for mailabbrev. -A new back-end for mailabbrev allows information from that database to -be queried by EUDC, too. The attributes 'email', 'name', and 'firstname' -are supported only. - -** EWW/SHR - -+++ -*** New user option to automatically rename EWW buffers. -The 'eww-auto-rename-buffer' user option can be configured to rename -rendered web pages by using their title, URL, or a user-defined -function which returns a string. For the first two cases, the length -of the resulting name is controlled by the user option -'eww-buffer-name-length'. By default, no automatic renaming is -performed. - -+++ -*** New user option 'shr-allowed-images'. -This complements 'shr-blocked-images', but allows specifying just the -allowed images. - -+++ -*** New user option 'shr-use-xwidgets-for-media'. -If non-nil (and Emacs has been built with support for xwidgets), -display <video> elements with an xwidget. Note that this is -experimental; it is known to crash Emacs on some systems, and just -doesn't work on other systems. Also see etc/PROBLEMS. - -+++ -*** New user option 'eww-url-transformers'. -These are used to alter an URL before using it. By default it removes -the common "utm_" trackers from URLs. - -** Find Dired - ---- -*** New command 'find-dired-with-command'. -This enables users to run 'find-dired' with an arbitrary command, -enabling running commands previously unsupported and also enabling new -commands to be built on top. - -** Gnus - -+++ -*** Tool bar changes in Gnus/Message. -There were previously two styles of tool bars available in Gnus and -Message, referred to as 'gnus-summary-tool-bar-retro', -'gnus-group-tool-bar-retro' and 'message-tool-bar-retro', and -'gnus-summary-tool-bar-gnome', 'gnus-group-tool-bar-gnome' and -'message-tool-bar-gnome'. The "retro" tool bars have been removed (as -well as the icons used), and the "gnome" tool bars are now the only -pre-defined toolbars. - ---- -*** 'gnus-summary-up-thread' and 'gnus-summary-down-thread' bindings removed. -The 'gnus-summary-down-thread' binding to 'M-C-d' was shadowed by -'gnus-summary-read-document', and these commands are also available on -'T u' and 'T d' respectively. - ---- -*** Gnus now uses a variable-pitch font in the headers by default. -To get the monospace font back, you can put something like the -following in your ".gnus" file: - - (set-face-attribute 'gnus-header nil :inherit 'unspecified) - ---- -*** The default value of 'gnus-treat-fold-headers' is now 'head'. - ---- -*** New face 'gnus-header'. -All other 'gnus-header-*' faces inherit from this face now. - -+++ -*** New user option 'gnus-treat-emojize-symbols'. -If non-nil, symbols that have an Emoji representation will be -displayed as emojis. The default is nil. - -+++ -*** New command 'gnus-article-emojize-symbols'. -This is bound to 'W D e' and will display symbols that have Emoji -representation as Emoji. - -+++ -*** New mu backend for gnus-search. -Configuration is very similar to the notmuch and namazu backends. It -supports the unified search syntax. - ---- -*** 'gnus-html-image-cache-ttl' is now a seconds count. -Formerly it was a pair of numbers '(A B)' that represented 65536*A + B, -to cater to older Emacs implementations that lacked bignums. -The older form still works but is undocumented. - -** Rmail - ---- -*** Rmail partial summaries can now be applied one on top of the other. -You can now narrow the set of messages selected by Rmail summary's -criteria (recipients, topic, senders, etc.) by making a summary of the -already summarized messages. For example, invoking -'rmail-summary-by-senders', followed by 'rmail-summary-by-topic' will -produce a summary where both the senders and the topic are according -to your selection. The new user option -'rmail-summary-progressively-narrow' controls whether the stacking of -the filters is in effect; customize it to a non-nil value to enable -this feature. - ---- -*** New Rmail summary: by thread. -The new command 'rmail-summary-by-thread' produces a summary of -messages that belong to a single thread of discussion. - -** EIEIO - -+++ -*** 'slot-value' can now be used to access slots of 'cl-defstruct' objects. - -** Align - ---- -*** Alignment in 'text-mode' has changed. -Previously, 'M-x align' didn't do anything, and you had to say 'C-u -M-x align' for it to work. This has now been changed. The default -regexp for 'C-u M-x align-regexp' has also been changed to be easier -for inexperienced users to use. - -** Help - ---- -*** New mode, 'emacs-news-view-mode', for viewing the NEWS file. -This mode is used by the 'C-h N' command, and adds buttons to manual -entries and symbol references. - ---- -*** New user option 'help-link-key-to-documentation'. -When this option is non-nil (which is the default), key bindings -displayed in the "*Help*" buffer will be linked to the documentation -for the command they are bound to. This does not affect listings of -key bindings and functions (such as 'C-h b'). - -** Info Look - ---- -*** info-look specs can now be expanded at run time instead of a load time. -The new ':doc-spec-function' element can be used to compute the -':doc-spec' element when the user asks for info on that particular -mode (instead of at load time). - -** Ansi Color - ---- -*** Support for ANSI 256-color and 24-bit colors. -256-color and 24-bit color codes are now handled by ANSI color -filters and displayed with the specified color. - -** Term Mode - ---- -*** New user option 'term-bind-function-keys'. -If non-nil, 'term-mode' will pass the function keys on to the -underlying shell instead of using the normal Emacs bindings. - ---- -*** Support for ANSI 256-color and 24-bit colors, italic and other fonts. -'term-mode' can now display 256-color and 24-bit color codes. It can -also handle ANSI codes for faint, italic and blinking text, displaying -it with new 'term-{faint,italic,slow-blink,fast-blink}' faces. - -** Project - -+++ -*** 'project-find-file' and 'project-or-external-find-file' can include all. -The commands 'project-find-file' and 'project-or-external-find-file' -now accept a prefix argument, which is interpreted to mean "include -all files". - -+++ -*** New command 'project-list-buffers' bound to 'C-x p C-b'. -This command displays a list of buffers from the current project. - -+++ -*** 'project-kill-buffers' can display the list of buffers to kill. -Customize the user option 'project-kill-buffers-display-buffer-list' -to enable the display of the buffer list. - -*** New user option 'project-vc-extra-root-markers'. -Use it to add detection of nested projects (inside a VCS repository), -or projects outside of VCS repositories. - -As a consequence, the 'VC project backend' is formally renamed to -'VC-aware project backend'. - -+++ -*** New user option 'project-vc-include-untracked'. -If non-nil, files untracked by a VCS are considered to be part of -the project by a VC project based on that VCS. - -** Xref - -+++ -*** New command 'xref-go-forward'. -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' prompting change. -This command no longer prompts for FROM when called without prefix -argument. This makes the most common case faster: replacing entire -matches. - -+++ -*** New command 'xref-find-references-and-replace' to rename one identifier. - ---- -*** New variable 'xref-current-item' (renamed from a private version). - ---- -*** New function 'xref-show-xrefs'. - -*** 'outline-minor-mode' is supported in Xref buffers. -You can enable outlining by adding 'outline-minor-mode' to -'xref-after-update-hook'. - -** File Notifications - -+++ -*** The new command 'file-notify-rm-all-watches' removes all file notifications. - -** Sql - ---- -*** Sql now supports sending of passwords in-process. -To improve security, if an sql product has ':password-in-comint' set -to t, a password supplied via the minibuffer will be sent in-process, -as opposed to via the command-line. - -** Image Mode - -+++ -*** New command 'image-transform-fit-to-window'. -This command fits the image to the current window by scaling down or -up as necessary. Unlike 'image-transform-fit-both', this does not -only scale the image down, but up as well. It is bound to 's w' in -Image Mode by default. - ---- -*** New command 'image-mode-wallpaper-set'. -This command sets the desktop background to the current image. It is -bound to 'W' by default. - -+++ -*** 'image-transform-fit-to-{height,width}' are now obsolete. -Use the new command 'image-transform-fit-to-window' instead. -The keybinding for 'image-transform-fit-to-width' is now 's i'. - ---- -*** User option 'image-auto-resize' can now be set to 'fit-window'. -This works like 'image-transform-fit-to-window'. - ---- -*** New user option 'image-auto-resize-max-scale-percent'. -The new 'fit-window' option will never scale an image more than this -much (in percent). It is nil by default, which means no limit. - ---- -*** New user option 'image-text-based-formats'. -This controls whether or not to show a message when opening certain -image formats saying how to edit it as text. The default is to show -this message for SVG and XPM. - -+++ -*** New commands: 'image-flip-horizontally' and 'image-flip-vertically'. -These commands horizontally and vertically flip the image under point, -and are bound to 'i h' and 'i v', respectively. - -+++ -*** New command 'image-transform-set-percent'. -It allows setting the image size to a percentage of its original size, -and is bound to 's p' in Image mode. - -+++ -*** 'image-transform-original' renamed to 'image-transform-reset-to-original'. -The old name was confusing, and is now an obsolete function alias. - -+++ -*** 'image-transform-reset' renamed to 'image-transform-reset-to-initial'. -The old name was confusing, and is now an obsolete function alias. - -** Images - -+++ -*** Users can now add special image conversion functions. -This is done via 'image-converter-add-handler'. - -** Image Dired - -+++ -*** 'image-dired-image-mode' is now based on 'image-mode'. -This avoids converting images in the background, and makes Image-Dired -noticeably faster. New keybindings from 'image-mode' are now -available in the "*image-dired-display-image*" buffer; press '?' or -'h' in that buffer to see the full list. - ---- -*** Navigation and marking commands now work in image display buffer. -The following new bindings have been added: -- 'n', 'SPC' => 'image-dired-display-next' -- 'p', 'DEL' => 'image-dired-display-previous' -- 'm' => 'image-dired-mark-thumb-original-file' -- 'd' => 'image-dired-flag-thumb-original-file' -- 'u' => 'image-dired-unmark-thumb-original-file' - ---- -*** New command 'image-dired-unmark-all-marks'. -It removes all marks from all files in the thumbnail and the -associated Dired buffer, and is bound to 'U' in the thumbnail and -display buffer. - ---- -*** New command 'image-dired-do-flagged-delete'. -It deletes all flagged files, and is bound to 'x' in the thumbnail -buffer. It replaces the command 'image-dired-delete-marked', which is -now an obsolete alias. - ---- -*** New command 'image-dired-copy-filename-as-kill'. -It copies the name of the marked or current image to the kill ring, -and is bound to 'w' in the thumbnail buffer. - ---- -*** New command 'image-dired-wallpaper-set'. -This command sets the desktop background to the image at point in the -thumbnail buffer. It is bound to 'W' by default. - ---- -*** 'image-dired-slideshow-start' is now bound to 'S'. -It is bound in both the thumbnail and display buffer, and no longer -prompts for a timeout; use a numerical prefix (e.g. 'C-u 8 S') to set -the timeout. - ---- -*** New user option 'image-dired-marking-shows-next'. -If this option is non-nil (the default), marking, unmarking or -flagging an image in either the thumbnail or display buffer shows the -next image. - ---- -*** New face 'image-dired-thumb-flagged'. -If 'image-dired-thumb-mark' is non-nil (the default), this face is -used for images that are flagged for deletion in the Dired buffer -associated with Image-Dired. - ---- -*** Image information is now shown in the header line of the thumbnail buffer. -This replaces the message that most navigation commands in the -thumbnail buffer used to show at the bottom of the screen. - ---- -*** New specifiers for 'image-dired-display-properties-format'. -This is used to format the new header line. The new specifiers are: -"%d" for the name of the directory that the file is in, "%n" for -file's number in the thumbnail buffer, and "%s" for the file size. - -The default format has been updated to use this. If you prefer the -old format, add this to your Init file: - - (setopt image-dired-display-properties-format "%b: %f (%t): %c") - ---- -*** New faces for the header line of the thumbnail buffer. -These faces correspond to different parts of the header line, as -specified in 'image-dired-display-properties-format': -- 'image-dired-thumb-header-directory-name' -- 'image-dired-thumb-header-file-name' -- 'image-dired-thumb-header-file-size' -- 'image-dired-thumb-header-image-count' - ---- -*** PDF support. -Image-Dired now displays thumbnails for PDF files. Type 'RET' on a -PDF file in the thumbnail buffer to visit the corresponding PDF. - ---- -*** Support GraphicsMagick command line tools. -Support for the GraphicsMagick command line tool ("gm") has been -added, and is used when it is available instead of ImageMagick. - ---- -*** Support Thumbnail Managing Standard v0.9.0 (Dec 2020). -This standard allows sharing generated thumbnails across different -programs. Version 0.9.0 adds two larger thumbnail sizes: 512x512 and -1024x1024 pixels. See the user option 'image-dired-thumbnail-storage' -to use it; it is not enabled by default. - ---- -*** Reduce dependency on external "exiftool" program. -The 'image-dired-copy-with-exif-file-name' command no longer requires -an external "exiftool" program to be available. The user options -'image-dired-cmd-read-exif-data-program' and -'image-dired-cmd-read-exif-data-options' are now obsolete. - ---- -*** Support for bookmark.el. -The command 'bookmark-set' (bound to 'C-x r m') is now supported in -the thumbnail view, and will create a bookmark that opens the current -directory in Image-Dired. - ---- -*** The 'image-dired-slideshow-start' command no longer prompts. -It no longer inconveniently prompts for a number of images and a -delay: it runs indefinitely, but stops automatically on any command. -You can set the delay with a prefix argument, or a negative prefix -argument to prompt for a delay. Customize the user option -'image-dired-slideshow-delay' to change the default from 5 seconds. - -+++ -*** 'image-dired-show-all-from-dir-max-files' increased to 1000. -This user option controls asking for confirmation when starting -Image-Dired in a directory with many files. Since Image-Dired creates -thumbnails in the background in recent versions, this is not as -important as it used to be. You can now also customize this option to -nil to disable this confirmation completely. - ---- -*** 'image-dired-thumb-size' increased to 128. - -+++ -*** 'image-dired-db-file' renamed to 'image-dired-tags-db-file'. - ---- -*** 'image-dired-display-image-mode' renamed to 'image-dired-image-mode'. -The corresponding keymap is now named 'image-dired-image-mode-map'. - -+++ -*** Some commands have been renamed to be shorter. -- 'image-dired-display-thumbnail-original-image' has been renamed to - 'image-dired-display-this'. -- 'image-dired-display-next-thumbnail-original' has been renamed to - 'image-dired-display-next'. -- 'image-dired-display-previous-thumbnail-original' has been renamed - to 'image-dired-display-previous'. -The old names are now obsolete aliases. - ---- -*** 'image-dired-thumb-{height,width}' are now obsolete. -Customize 'image-dired-thumb-size' instead, which will set both the -height and width. - ---- -*** HTML image gallery generation is now obsolete. -The 'image-dired-gallery-generate' command and these user options are -now obsolete: 'image-dired-gallery-thumb-image-root-url', -'image-dired-gallery-hidden-tags', 'image-dired-gallery-dir', -'image-dired-gallery-image-root-url'. - ---- -*** 'image-dired-rotate-thumbnail-{left,right}' are now obsolete. -Instead, use commands 'image-dired-refresh-thumb' to generate a new -thumbnail, or 'image-rotate' to rotate the thumbnail without updating -the thumbnail file. - -+++ -*** Some commands and user options are now obsolete. -Since 'image-dired-display-image-mode' is now based on 'image-mode', -some commands and user options are no longer needed and are now obsolete: -'image-dired-cmd-create-temp-image-options', -'image-dired-cmd-create-temp-image-program', -'image-dired-display-current-image-full', -'image-dired-display-current-image-sized', -'image-dired-display-window-height-correction', -'image-dired-display-window-width-correction', -'image-dired-temp-image-file'. - -** Exif - ---- -*** New function 'exif-field'. -This is a convenience function to extract the field data from -'exif-parse-file' and 'exif-parse-buffer'. - -** Bookmarks - ---- -*** 'list-bookmarks' now includes a type column. -Types are registered via a 'bookmark-handler-type' symbol property on -the jumping function. - -+++ -*** 'bookmark-sort-flag' can now be set to 'last-modified'. -This will display bookmark list from most recently set to least -recently set. - ---- -*** When editing a bookmark annotation, 'C-c C-k' will now cancel. -It is bound to the new command 'bookmark-edit-annotation-cancel'. - ---- -*** New user option 'bookmark-fringe-mark'. -This option controls the bitmap used to indicate bookmarks in the -fringe (or nil to disable showing this marker). - -** Xwidget - ---- -*** New user option 'xwidget-webkit-buffer-name-format'. -This option controls how xwidget-webkit buffers are named. - ---- -*** New user option 'xwidget-webkit-cookie-file'. -This option controls whether the xwidget-webkit buffers save cookies -set by web pages, and if so, in which file to save them. - -+++ -*** New minor mode 'xwidget-webkit-edit-mode'. -When this mode is enabled, self-inserting characters and other common -web browser shortcut keys are redefined to send themselves to the -WebKit widget. - -+++ -*** New minor mode 'xwidget-webkit-isearch-mode'. -This mode acts similarly to incremental search, and allows searching -the contents of a WebKit widget. In xwidget-webkit mode, it is bound -to 'C-s' and 'C-r'. - -+++ -*** New command 'xwidget-webkit-browse-history'. -This command displays a buffer containing the page load history of -the current WebKit widget, and allows you to navigate it. - ---- -*** On X, the WebKit inspector is now available inside xwidgets. -To access the inspector, right click on the widget and select "Inspect -Element". - ---- -*** "Open in New Window" in a WebKit widget's context menu now works. -The newly created buffer will be displayed via 'display-buffer', which -can be customized through the usual mechanism of 'display-buffer-alist' -and friends. - -** Tramp - -+++ -*** New connection methods "docker", "podman" and "kubernetes". -They allow accessing containers provided by Docker and similar -programs. - ---- -*** Tramp supports abbreviating remote home directories now. -When calling 'abbreviate-file-name' on a Tramp file name, the result -will abbreviate the user's home directory, for example by abbreviating -"/ssh:user@host:/home/user" to "/ssh:user@host:~". - -+++ -*** New user option 'tramp-use-scp-direct-remote-copying'. -When set to non-nil, Tramp does not copy files between two remote -hosts via a local copy in its temporary directory, but lets the 'scp' -command do this job. - -+++ -*** Proper password prompts for methods "doas", "sudo" and "sudoedit". -The password prompts for these methods reflect now the credentials of -the user requesting such a connection, and not of the user who is the -target. This has always been needed, just the password prompt and the -related 'auth-sources' entry were wrong. - -+++ -*** New user option 'tramp-completion-use-cache'. -During user and host name completion in the minibuffer, results from -Tramp's connection cache are taken into account. This can be disabled -by setting the user option 'tramp-completion-use-cache' to nil. - -** Browse URL - ---- -*** New user option 'browse-url-default-scheme'. -This user option decides which URL scheme that 'browse-url' and -related functions will use by default. For example, you could -customize this to "https" to always prefer HTTPS URLs. - ---- -*** New user option 'browse-url-irc-function'. -This option specifies a function for opening "irc://" links. It -defaults to the new function 'browse-url-irc'. - ---- -*** New function 'browse-url-irc'. -This multipurpose autoloaded function can be used for opening "irc://" -and "ircs://" URLS by any caller that passes a URL string as an initial -arg. - ---- -*** Support for the Netscape web browser has been removed. -This support has been obsolete since Emacs 25.1. The final version of -the Netscape web browser was released in February, 2008. - ---- -*** Support for the Galeon web browser has been removed. -This support has been obsolete since Emacs 25.1. The final version of -the Galeon web browser was released in September, 2008. - ---- -*** Support for the Mozilla web browser is now obsolete. -Note that this historical web browser is different from Mozilla -Firefox; it is its predecessor. - -** Python Mode - -+++ -*** Project shells and a new user option 'python-shell-dedicated'. -When called with a prefix argument, 'run-python' now offers the choice -of creating a shell dedicated to the current project. This shell runs -in the project root directory and is shared among all project buffers. - -Without a prefix argument, the kind of shell (buffer-dedicated, -project-dedicated or global) is specified by the new -'python-shell-dedicated' user option. - -** Ruby Mode - ---- -*** New user option 'ruby-toggle-block-space-before-parameters'. - ---- -*** Support for endless methods. - ---- -*** New user options that determine indentation logic. -'ruby-method-params-indent', 'ruby-block-indent', -'ruby-after-operator-indent', 'ruby-method-call-indent', -'ruby-parenless-call-arguments-indent'. See the docstrings for -explanations and examples. +*** New user option 'bs-default-action-list'. +You can now configure how to display the "*buffer-selection*" buffer +using this new option. (Or set 'display-buffer-alist' directly.) ** Eshell +++ -*** New feature to easily bypass Eshell's own pipelining. -Prefixing '|', '<' or '>' with an asterisk, i.e. '*|', '*<' or '*>', -will cause the whole command to be passed to the operating system -shell. This is particularly useful to bypass Eshell's own pipelining -support for pipelines which will move a lot of data. See section -"Running Shell Pipelines Natively" in the Eshell manual, node -"(eshell) Pipelines". - -+++ -*** New module to help supplying absolute file names to remote commands. -After enabling the new 'eshell-elecslash' module, typing a forward -slash as the first character of a command line argument will -automatically insert the Tramp prefix. The automatic insertion -applies only when 'default-directory' is remote and the command is a -Lisp function. This frees you from having to keep track of whether -commands are Lisp function or external when supplying absolute file -name arguments. See the "(eshell) Electric forward slash" node in the -Eshell manual for details. +*** New splice operator for Eshell dollar expansions. +Dollar expansions in Eshell now let you splice the elements of the +expansion in-place using '$@expr'. This makes it easier to fill lists +of arguments into a command, such as when defining aliases. For more +information, see the "(eshell) Dollars Expansion" node in the Eshell +manual. +++ -*** Improved support for redirection operators in Eshell. -Eshell now supports a wider variety of redirection operators. For -example, you can now redirect both stdout and stderr via '&>' or -duplicate one output handle to another via 'NEW-FD>&OLD-FD'. For more -information, see the "(eshell) Redirection" node in the Eshell manual. - -+++ -*** New eshell built-in command 'doas'. -The privilege-escalation program 'doas' has been added to the existing -'su' and 'sudo' commands from the 'eshell-tramp' module. The external -command may still be accessed by using '*doas'. - -+++ -*** Double-quoting an Eshell expansion now treats the result as a single string. -If an Eshell expansion like '$FOO' is surrounded by double quotes, the -result will always be a single string, no matter the type that would -otherwise be returned. - -+++ -*** Concatenating Eshell expansions now works more similarly to other shells. -When concatenating an Eshell expansion that returns a list, "adjacent" -elements of each operand are now concatenated together, -e.g. '$(list "a" "b")c' returns '("a" "bc")'. See the "(eshell) -Expansion" node in the Eshell manual for more details. - -+++ -*** Eshell subcommands with multiline numeric output return lists of numbers. -If every line of the output of an Eshell subcommand like '${COMMAND}' -is numeric, the result will be a list of numbers (or a single number -if only one line of output). Previously, this only converted numbers -when there was a single line of output. +*** Eshell now supports negative numbers and ranges for indices. +Now, you can retrieve the last element of a list with '$my-list[-1]' +or get a sublist of elements 2 through 4 with '$my-list[2..5]'. For +more information, see the "(eshell) Dollars Expansion" node in the +Eshell manual. --- -*** Built-in Eshell commands now follow 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'. New commands can take advantage of this with the -'eshell-eval-using-options' macro. See "Defining new built-in -commands" in the "(eshell) Built-ins" node of the Eshell manual. +*** Eshell now uses 'field' properties in its output. +In particular, this means that pressing the '<home>' key moves the +point to the beginning of your input, not the beginning of the whole +line. If you want to go back to the old behavior, add something like +this to your configuration: ---- -*** Eshell globs ending with "/" now match only directories. -Additionally, globs ending with "**/" or "***/" no longer raise an -error, and now expand to all directories recursively (following -symlinks in the latter case). + (keymap-set eshell-mode-map "<home>" #'eshell-bol-ignoring-prompt) +++ -*** Lisp forms in Eshell now treat a nil result as a failed exit status. -When executing a command that looks like '(lisp form)' and returns -nil, Eshell will set the exit status (available in the '$?' -variable) to 2. This allows commands like that to be used in -conditionals. To change this behavior, customize the new -'eshell-lisp-form-nil-is-failure' user option. - -** Shell - ---- -*** New user option 'shell-kill-buffer-on-exit'. -Enabling this will automatically kill a "*shell*" buffer as soon as -the shell session terminates. +*** 'eshell-read-aliases-list' is now an interactive command. +After manually editing 'eshell-aliases-file', you can use this command +to load the edited aliases. ---- -*** New minor mode 'shell-highlight-undef-mode'. -Customize 'shell-highlight-undef-enable' to t if you want to enable -this minor mode in "*shell*" buffers. It will highlight undefined -commands with a warning face as you type. - -** Calc +** Prog Mode +++ -*** New user option 'calc-kill-line-numbering'. -Set it to nil to exclude line numbering from kills and copies. +*** New command 'prog-fill-reindent-defun'. +This command either fills a single paragraph in a defun, such as a +docstring, or a comment, or (re)indents the surrounding defun if +point is not in a comment or a string. It is by default bound to +'M-q' in 'prog-mode' and all its descendants. -** Hierarchy +** Tramp +++ -*** Tree Display can delay computation of children. -'hierarchy-add-tree' and 'hierarchy-add-trees' have an optional -argument which allows tree-widget display to be activated and computed -only when the user expands the node. - -** Proced +*** New connection method "toolbox". +This allows accessing system containers provided by Toolbox. ---- -*** proced.el shows system processes of remote hosts. -When 'default-directory' is remote, and 'proced' is invoked with a -negative argument like 'C-u - proced', the system processes of that -remote host are shown. Alternatively, the user option -'proced-show-remote-processes' can be set to non-nil. -'proced-signal-function' has been marked obsolete. - ---- -*** Proced can now optionally show process details in color. -New user option 'proced-enable-color-flag' enables coloring of Proced -buffers. This option is disabled by default; customize it to a -non-nil value to enable colors. - -** Miscellaneous - ---- -*** New user option 'webjump-use-internal-browser'. -When non-nil, WebJump will use an internal browser to open web pages, -instead of the default external browser. +** EWW +++ -*** New user option 'font-lock-ignore'. -This option provides a mechanism to selectively disable font-lock -keyword-driven fontifications. +*** 'eww-open-file' can now display the file in a new buffer. +By default, the command reuses the "*eww*" buffer, but if called with +the new argument NEW-BUFFER non-nil, it will use a new buffer instead. +Interactively, invoke 'eww-open-file' with a prefix argument to +activate this behavior. ---- -*** New user option 'auto-save-visited-predicate'. -This user option is a predicate function which is called by -'auto-save-visited-mode' to decide whether or not to save a buffer. -You can use it to automatically save only specific buffers, for -example buffers using a particular mode or in some directory. - ---- -*** New user option 'remote-file-name-inhibit-auto-save-visited'. -If this user option is non-nil, 'auto-save-visited-mode' will not -auto-save remote buffers. The default is nil. +** go-ts-mode +++ -*** New package vtable.el for formatting tabular data. -This package allows formatting data using variable-pitch fonts. -The resulting tables can display text in variable pitch fonts, text -using fonts of different sizes, and images. See the "(vtable) Top" -manual for more details. - ---- -*** New minor mode 'elide-head-mode'. -Enabling this minor mode turns on hiding header material, like -'elide-head' does; disabling it shows the header. The commands -'elide-head' and 'elide-head-show' are now obsolete. - -*** New package ansi-osc.el. -Support for OSC ("Operating System Command") escape sequences has been -extracted from comint.el in order to provide interpretation of OSC -sequences in compilation buffers. - -Adding the new function 'ansi-osc-compilation-filter' to -'compilation-filter-hook' enables interpretation of OSC escape -sequences in compilation buffers. By default, all sequences are -filtered out. - -The list of handlers (already covering OSC 7 and 8) has been extended -with a handler for OSC 2, the command to set a window title. - ---- -*** 'recentf-mode' now uses abbreviated file names by default. -This means that e.g. "/home/foo/bar" is now displayed as "~/bar". -Customize the user option 'recentf-filename-handlers' to nil to get -back the old behavior. - ---- -*** New command 'recentf-open'. -This command prompts for a recently opened file in the minibuffer, and -visits it. - ---- -*** 'ffap-machine-at-point' no longer pings hosts by default. -It will now simply look at a hostname to determine if it is valid, -instead of also trying to ping it. Customize the user option -'ffap-machine-p-known' to 'ping' to get the old behavior back. - ---- -*** The 'run-dig' command is now obsolete; use 'dig' instead. - ---- -*** Some 'bib-mode' commands and variables have been renamed. -To respect Emacs naming conventions, the variable 'unread-bib-file' -has been renamed to 'bib-unread-file'. The following commands have -also been renamed: - 'addbib' to 'bib-add' - 'return-key-bib' to 'bib-return-key' - 'mark-bib' to 'bib-mark' - 'unread-bib' to 'bib-unread' - ---- -*** 'outlineify-sticky' command is renamed to 'allout-outlinify-sticky'. -The old name is still available as an obsolete function alias. - ---- -*** The url-irc library now understands "ircs://" links. - ---- -*** New command 'world-clock-copy-time-as-kill' for 'world-clock-mode'. -It copies the current line into the kill ring. - ---- -*** 'edit-abbrevs' now uses font-locking. -The new face 'abbrev-table-name' is used to display the abbrev table -name. - ---- -*** New key binding 'O' in "*Buffer List*". -This key is now bound to 'Buffer-menu-view-other-window', which will -view this line's buffer in View mode in another window. - -** Scheme Mode - ---- -*** Auto-detection of Scheme library files. -Emacs now automatically enables the Scheme mode when opening R6RS -Scheme Library Source (".sls") files and R7RS Scheme Library -Definition (".sld") files. - ---- -*** Imenu members for R6RS and R7RS library members. -Imenu now lists the members directly nested in R6RS Scheme libraries -('library') and R7RS libraries ('define-library'). +*** New command 'go-ts-mode-docstring'. +This command adds a docstring comment to the current defun. If a +comment already exists, point is only moved to the comment. It is +bound to 'C-c C-d' in 'go-ts-mode'. -* New Modes and Packages in Emacs 29.1 - -+++ -** Eglot: Emacs Client for the Language Server Protocol. -Emacs now comes with the Eglot package, which enhances various Emacs -features, such as completion, documentation, error detection, etc., -based on data provided by language servers using the Language Server -Protocol (LSP). See the new Info manual "(eglot) Top" for more. - -+++ -** use-package: Declarative package configuration. -use-package is now shipped with Emacs. It provides the 'use-package' -macro, which allows you to isolate package configuration in your init -file in a way that is declarative, tidy, and performance-oriented. -See the new Info manual "(use-package) Top" for more. - -+++ -** New commands 'image-crop' and 'image-cut'. -These commands allow interactively cropping/cutting the image at -point. The commands are bound to keys 'i c' and 'i x' (respectively) -in the local keymap over images. They rely on external programs, by -default "convert" from ImageMagick, to do the actual cropping/eliding -of the image file. +* New Modes and Packages in Emacs 30.1 ---- -** New package 'wallpaper'. -This package provides the command 'wallpaper-set', which sets the -desktop background image. Depending on the system and the desktop, -this may require an external program (such as "swaybg", "gm", -"display" or "xloadimage"). If so, a suitable command should be -detected automatically in most cases. It can also be customized -manually if needed, using the new user options 'wallpaper-command' and -'wallpaper-command-args'. - -+++ -** New package 'oclosure'. -This allows the creation of "functions with slots" or "function -objects" via the macros 'oclosure-define' and 'oclosure-lambda'. - -+++ -*** New generic function 'oclosure-interactive-form'. -Used by 'interactive-form' when called on an OClosure. -This allows specific OClosure types to compute their interactive specs -on demand rather than precompute them when created. - ---- -** New theme 'leuven-dark'. -This is a dark version of the 'leuven' theme. - -+++ -** New mode 'erts-mode'. -This mode is used to edit files geared towards testing actions in -Emacs buffers, like indentation and the like. The new ert function -'ert-test-erts-file' is used to parse these files. - ---- -** New major mode 'js-json-mode'. -This is a lightweight variant of 'js-mode' that is used by default -when visiting JSON files. - -+++ -** New major mode 'csharp-mode'. -A major mode based on CC Mode for editing programs in the C# language. -This mode is auto-enabled for files with the ".cs" extension. - -+++ ** New major modes based on the tree-sitter library. -These new major modes are available if Emacs was built with the -tree-sitter library. They provide support for font-locking, -indentation, and navigation by defuns based on parsing the buffer text -by a tree-sitter parser. Some major modes also offer support for -Imenu and 'which-func'. - -The new modes based on tree-sitter are for now entirely optional, and -you must turn them on manually, or load them in your init file, or -customize 'auto-mode-alist' to turn them on automatically for certain -files. You can also customize 'major-mode-remap-alist' to -automatically turn on some tree-sitter based modes for the same files -for which a "built-in" mode would be turned on. For example: - - (add-to-list 'major-mode-remap-alist '(ruby-mode . ruby-ts-mode)) - -If you try these modes and don't like them, you can go back to the -"built-in" modes by restarting Emacs. But please tell us why you -didn't like the tree-sitter based modes, so that we could try -improving them. - -Each major mode based on tree-sitter needs a language grammar library, -usually named "libtree-sitter-LANG.so" ("libtree-sitter-LANG.dll" on -MS-Windows), where LANG is the corresponding language name. Emacs -looks for these libraries in the following places: - - . in the directories mentioned in the list 'treesit-extra-load-path' - . in the "tree-sitter" subdirectory of your 'user-emacs-directory' - (by default, "~/.emacs.d/tree-sitter") - . in the standard system directories where other shared libraries are - usually installed - -We recommend to install these libraries in one of the standard system -locations (the last place in the above list). - -If a language grammar library required by a mode is not found in any -of the above places, the mode will display a warning when you try to -turn it on. - -+++ -*** New major mode 'typescript-ts-mode'. -A major mode based on the tree-sitter library for editing programs -in the TypeScript language. - -+++ -*** New major mode 'tsx-ts-mode'. -A major mode based on the tree-sitter library for editing programs -in the TypeScript language, with support for TSX. - -+++ -*** New major mode 'c-ts-mode'. -An optional major mode based on the tree-sitter library for editing -programs in the C language. - -+++ -*** New major mode 'c++-ts-mode'. -An optional major mode based on the tree-sitter library for editing -programs in the C++ language. - -+++ -*** New command 'c-or-c++-ts-mode'. -A command that automatically guesses the language of a header file, -and enables either 'c-ts-mode' or 'c++-ts-mode' accordingly. - -+++ -*** New major mode 'java-ts-mode'. -An optional major mode based on the tree-sitter library for editing -programs in the Java language. - -+++ -*** New major mode 'python-ts-mode'. -An optional major mode based on the tree-sitter library for editing -programs in the Python language. - -+++ -*** New major mode 'css-ts-mode'. -An optional major mode based on the tree-sitter library for editing -CSS (Cascading Style Sheets). - -+++ -*** New major mode 'json-ts-mode'. -An optional major mode based on the tree-sitter library for editing -programs in the JSON language. - -+++ -*** New major mode 'csharp-ts-mode'. -An optional major mode based on the tree-sitter library for editing -programs in the C# language. - -+++ -*** New major mode 'bash-ts-mode'. -Am optional major mode based on the tree-sitter library for editing -Bash shell scripts. - -+++ -*** New major mode 'dockerfile-ts-mode'. -A major mode based on the tree-sitter library for editing -Dockerfiles. - -+++ -*** New major mode 'cmake-ts-mode'. -A major mode based on the tree-sitter library for editing CMake files. +++ -*** New major mode 'toml-ts-mode'. +*** New major mode 'html-ts-mode'. An optional major mode based on the tree-sitter library for editing -files written in TOML, a format for writing configuration files. - -+++ -*** New major mode 'go-ts-mode'. -A major mode based on the tree-sitter library for editing programs in -the Go language. - -+++ -*** New major mode 'go-mod-ts-mode'. -A major mode based on the tree-sitter library for editing "go.mod" -files. - -+++ -*** New major mode 'yaml-ts-mode'. -A major mode based on the tree-sitter library for editing files -written in YAML. - -+++ -*** New major mode 'rust-ts-mode'. -A major mode based on the tree-sitter library for editing programs in -the Rust language. +HTML files. --- -*** New major mode 'ruby-ts-mode'. -An optional major mode based on the tree-sitter library for editing -programs in the Ruby language. +** The highly accessible Modus themes collection has six items. +The 'modus-operandi' and 'modus-vivendi' are the main themes that have +been part of Emacs since version 28. The former is light, the latter +dark. In addition to these, we now have 'modus-operandi-tinted' and +'modus-vivendi-tinted' for easier legibility, as well as +'modus-operandi-deuteranopia' and 'modus-vivendi-deuteranopia' to +cover the needs of users with red-green color deficiency. The Info +manual "(modus-themes) Top" describes the details and showcases all +their customization options. -* Incompatible Lisp Changes in Emacs 29.1 - -+++ -** The implementation of overlays has changed. -Emacs now uses an implementation of overlays that is much more -efficient than the original one, and should speed up all the -operations that involve overlays, especially when there are lots of -them in a buffer. - -As result of this, some minor incompatibilities in behavior could be -observed, as described below. Except those minor incompatibilities, -no other changes in behavior of overlays should be visible on the Lisp -or user level, with the exception of better performance and the order -of overlays returned by functions that don't promise any particular -order. - ---- -*** The function 'overlay-recenter' is now a no-op. -This function does nothing, and in particular has no effect on the -value returned by 'overlay-lists'. The purpose of 'overlay-recenter' -was to allow more efficient lookup of overlays around a certain buffer -position; however with the new implementation the lookup of overlays -is efficient regardless of their position, and there's no longer any -need to "optimize" the lookup, nor any notion of a "center" of the -overlays. - ---- -*** The function 'overlay-lists' returns one unified list of overlays. -This function used to return a cons of two lists, one with overlays -before the "center" position, the other after that "center". It now -returns a list whose 'car' is the list of all the buffer overlays, and -whose 'cdr' is always nil. - -+++ -** 'format-prompt' now uses 'substitute-command-keys'. -This means that both the prompt and 'minibuffer-default-prompt-format' -will have key definitions and single quotes handled specially. +* Incompatible Lisp Changes in Emacs 30.1 -+++ -** New function 'substitute-quotes'. -This function works like 'substitute-command-keys' but only -substitutes quote characters. - ---- -** 'find-image' now uses 'create-image'. -This means that images found through 'find-image' also have -auto-scaling applied. (This only makes a difference on HiDPI -displays.) - -+++ -** Changes in how "raw" in-memory XBM images are specified. -Some years back Emacs gained the ability to scale images, and you -could then specify ':width' and ':height' when using 'create-image' on all -image types -- except XBM images, because this format already used the -':width' and ':height' arguments to specify the width/height of the "raw" -in-memory format. This meant that if you used these specifications -on, for instance, XBM files, Emacs would refuse to display them. This -has been changed, and ':width'/':height' now works as with all other image -formats, and the way to specify the width/height of the "raw" -in-memory format is now by using ':data-width' and ':data-height'. - -+++ -** "loaddefs.el" generation has been reimplemented. -The various "loaddefs.el" files in the Emacs tree (which contain -information about autoloads, built-in packages and package prefixes) -used to be generated by functions in autoloads.el. These are now -generated by loaddefs-gen.el instead. This leads to functionally -equivalent "loaddefs.el" files, but they do not use exactly the same -syntax, so using 'M-x update-file-autoloads' no longer works. (This -didn't work well in most files in the past, either, but it will now -signal an error in any file.) - -In addition, files are scanned in a slightly different way. -Previously, ';;;###' specs inside a top-level form (i.e., something -like '(when ... ;;;### ...)' would be ignored. They are now parsed as -usual. - ---- -** Themes have special autoload cookies. -All built-in themes are scraped for ';;;###theme-autoload' cookies -that are loaded along with the regular auto-loaded code. - -+++ -** 'buffer-modified-p' has been extended. -This function was previously documented to return only nil or t. This -has been changed to nil/'autosaved'/non-nil. The new 'autosaved' -value means that the buffer is modified, but that it hasn't been -modified since the time of last auto-save. - ---- -** 'with-silent-modifications' also restores buffer autosave status. -'with-silent-modifications' is a macro meant to be used by the font -locking machinery to allow applying text properties without changing -the modification status of the buffer. However, it didn't restore the -buffer autosave status, so applying font locking to a modified buffer -that had already been auto-saved would trigger another auto-saving. -This is no longer the case. - ---- -** 'prin1' doesn't always escape "." and "?" in symbols any more. -Previously, symbols like 'foo.bar' would be printed by 'prin1' as -"foo\.bar". This now prints as "foo.bar" instead. The Emacs Lisp -reader interprets these strings as referring to the same symbol, so -this is virtually always backwards-compatible, but there may -theoretically be code out there that expects a specific printed -representation. - -The same is the case with the "?" character: The 'foo?' symbol is now -printed as "foo?" instead of "foo\?". - -If the "." and "?" characters are the first character in the symbol, -they will still be escaped, so the '.foo' symbol is still printed as -"\.foo" and the '?bar' symbol is still printed as "\?bar". - -+++ -** Remapping 'mode-line' face no longer works as expected. -'mode-line' is now the parent face of the new 'mode-line-active' face, -and remapping parent of basic faces does not work reliably. -Instead of remapping 'mode-line', you have to remap 'mode-line-active'. - -+++ -** 'make-process' has been extended to support ptys when ':stderr' is set. -Previously, setting ':stderr' to a non-nil value would force the -process's connection to use pipes. Now, Emacs will use a pty for -stdin and stdout if requested no matter the value of ':stderr'. - ---- -** User option 'mail-source-ignore-errors' is now obsolete. -The whole mechanism for prompting users to continue in case of -mail-source errors has been removed, so this option is no longer -needed. - -** Fonts - ---- -*** Emacs now supports 'medium' fonts. -Emacs previously didn't distinguish between the 'regular'/'normal' -weight and the 'medium' weight, but it now also supports the (heavier) -'medium' weight. However, this means that if you specify a weight of -'normal' and the font doesn't have this weight, Emacs won't find the -font spec. In these cases, replacing ":weight 'normal" with ":weight -'medium" should fix the issue. - ---- -** Keymap descriptions have changed. -'help--describe-command', 'C-h b' and associated functions that output -keymap descriptions have changed. In particular, prefix commands are -not output at all, and instead of "??" for closures/functions, -"[closure]"/"[lambda]" is output. - ---- -** 'downcase' details have changed slightly. -In certain locales, changing the case of an ASCII-range character may -turn it into a multibyte character, most notably with "I" in Turkish -(the lowercase is "ı", 0x0131). Previously, 'downcase' on a unibyte -string was buggy, and would mistakenly just return the lower byte of -this, 0x31 (the digit "1"). 'downcase' on a unibyte string has now -been changed to downcase such characters as if they were ASCII. To -get proper locale-dependent downcasing, the string has to be converted -to multibyte first. (This goes for the other case-changing functions, -too.) - ---- -** Functions in 'tramp-foreign-file-name-handler-alist' have changed. -Functions to determine which Tramp file name handler to use are now -passed a file name in dissected form (via 'tramp-dissect-file-name') -instead of in string form. - ---- -** 'def' indentation changes. -In 'emacs-lisp-mode', forms with a symbol with a name that start with -"def" have been automatically indented as if they were 'defun'-like -forms, for instance: - - (defzot 1 - 2 3) - -This heuristic has now been removed, and all functions/macros that -want to be indented this way have to be marked with - - (declare (indent defun)) - -or the like. If the function/macro definition itself can't be -changed, the indentation can also be adjusted by saying something -like: - - (put 'defzot 'lisp-indent-function 'defun) - ---- -** The 'inhibit-changing-match-data' variable is now obsolete. -Instead, functions like 'string-match' and 'looking-at' now take an -optional INHIBIT-MODIFY argument. - ---- -** 'gnus-define-keys' is now obsolete. -Use 'define-keymap' instead. - ---- -** MozRepl has been removed from js.el. -MozRepl was removed from Firefox in 2017, so this code doesn't work -with recent versions of Firefox. - ---- -** The function 'image-dired-get-exif-data' is now obsolete. -Use 'exif-parse-file' and 'exif-field' instead. - ---- -** 'insert-directory' alternatives should not change the free disk space line. -This change is now applied in 'dired-insert-directory'. - ---- -** 'compilation-last-buffer' is (finally) declared obsolete. -It has been obsolete since Emacs 22.1, actually. - ---- -** Calling 'lsh' now elicits a byte-compiler warning. -'lsh' behaves in somewhat surprising and platform-dependent ways for -negative arguments, and is generally slower than 'ash', which should be -used instead. This warning can be suppressed by surrounding calls to -'lsh' with the construct '(with-suppressed-warnings ((suspicious lsh)) ...)', -but switching to 'ash' is generally much preferable. - ---- -** Some functions and variables obsolete since Emacs 24 have been removed: -'Buffer-menu-buffer+size-width', 'Electric-buffer-menu-mode', -'Info-edit-map', 'allout-abbreviate-flattened-numbering', -'allout-exposure-change-hook', 'allout-mode-deactivate-hook', -'allout-structure-added-hook', 'allout-structure-deleted-hook', -'allout-structure-shifted-hook', 'ansi-color-unfontify-region', -'archive-extract-hooks', 'auth-source-forget-user-or-password', -'auth-source-hide-passwords', 'auth-source-user-or-password', -'automatic-hscrolling', 'automount-dir-prefix', 'bibtex-complete', -'bibtex-entry-field-alist', 'buffer-has-markers-at', -'buffer-substring-filters', 'byte-compile-disable-print-circle', -'c-prepare-bug-report-hooks', 'cfengine-mode-abbrevs', -'change-log-acknowledgement', 'chart-map', -'checkdoc-comment-style-hooks', 'comint--unquote&expand-filename', -'comint-dynamic-complete', 'comint-dynamic-complete-as-filename', -'comint-dynamic-simple-complete', 'comint-unquote-filename', -'command-history-map', 'compilation-parse-errors-function', -'completion-annotate-function', 'condition-case-no-debug', -'count-lines-region', 'crisp-mode-modeline-string', -'custom-print-functions', 'cvs-string-prefix-p', 'data-debug-map', -'deferred-action-function', 'deferred-action-list', -'dired-pop-to-buffer', 'dired-shrink-to-fit', -'dired-sort-set-modeline', 'dired-x-submit-report', -'display-buffer-function', -'ediff-choose-window-setup-function-automatically', -'eieio-defgeneric', 'eieio-defmethod', 'emacs-lock-from-exiting', -'erc-complete-word', 'erc-dcc-chat-filter-hook', -'eshell-add-to-window-buffer-names', 'eshell-cmpl-suffix-list', -'eshell-for', 'eshell-remove-from-window-buffer-names', -'eshell-status-in-modeline', 'filesets-cache-fill-content-hooks', -'font-list-limit', 'font-lock-maximum-size', -'font-lock-reference-face', 'gnus-carpal', -'gnus-debug-exclude-variables', 'gnus-debug-files', -'gnus-local-domain', 'gnus-outgoing-message-group', -'gnus-registry-user-format-function-M', 'gnus-secondary-servers', -'gnus-subscribe-newsgroup-hooks', 'gud-inhibit-global-bindings', -'hangul-input-method-inactivate', 'hfy-post-html-hooks', -'image-extension-data', 'image-library-alist', -'inactivate-current-input-method-function', 'inactivate-input-method', -'inhibit-first-line-modes-regexps', -'inhibit-first-line-modes-suffixes', 'input-method-inactivate-hook', -'intdos', 'javascript-generic-mode', 'javascript-generic-mode-hook', -'latex-string-prefix-p', 'macro-declaration-function' (function), -'macro-declaration-function' (variable), 'mail-complete', -'mail-complete-function', 'mail-mailer-swallows-blank-line', -'mail-sent-via', 'make-register', 'makefile-complete', -'menu-bar-kill-ring-save', 'meta-complete-symbol', 'meta-mode-map', -'mh-kill-folder-suppress-prompt-hooks', -'minibuffer-completing-symbol', -'minibuffer-local-filename-must-match-map', 'mode25', 'mode4350', -'mpc-string-prefix-p', 'msb-after-load-hooks', -'nndiary-request-accept-article-hooks', -'nndiary-request-create-group-hooks', -'nndiary-request-update-info-hooks', 'nnimap-split-rule', -'nntp-authinfo-file', 'ns-alternatives-map', -'ns-store-cut-buffer-internal', 'package-menu-view-commentary', -'pascal-last-completions', 'pascal-show-completions', -'pascal-toggle-completions', 'pcomplete-arg-quote-list', -'pcomplete-quote-argument', 'prolog-char-quote-workaround', -'python-buffer', 'python-guess-indent', 'python-indent', -'python-info-ppss-comment-or-string-p', 'python-info-ppss-context', -'python-info-ppss-context-type', 'python-preoutput-result', -'python-proc', 'python-send-receive', 'python-send-string', -'python-use-skeletons', 'quail-inactivate', 'quail-inactivate-hook', -'query-replace-interactive', 'rcirc-activity-hooks', -'rcirc-print-hooks', 'rcirc-receive-message-hooks', -'rcirc-sentinel-hooks', 'read-filename-at-point', 'redraw-modeline', -'reftex-index-map', 'reftex-index-phrases-map', -'reftex-select-bib-map', 'reftex-select-label-map', 'reftex-toc-map', -'register-name-alist', 'register-value', 'report-emacs-bug-info', -'report-emacs-bug-pretest-address', -'rmail-default-dont-reply-to-names', 'rmail-dont-reply-to', -'rmail-dont-reply-to-names', 'robin-inactivate', -'robin-inactivate-hook', 'rst-block-face', 'rst-comment-face', -'rst-definition-face', 'rst-directive-face', 'rst-emphasis1-face', -'rst-emphasis2-face', 'rst-external-face', 'rst-literal-face', -'rst-reference-face', 'semantic-change-hooks', -'semantic-edits-delete-change-hooks', -'semantic-edits-new-change-hooks', -'semantic-edits-reparse-change-hooks', 'semantic-grammar-map', -'semantic-grammar-syntax-table', 'semantic-lex-reset-hooks', -'semanticdb-elisp-sym-function-arglist', -'semanticdb-save-database-hooks', 'set-face-underline-p', -'set-register-value', 'sh-maybe-here-document', 'speedbar-key-map', -'speedbar-syntax-table', 'starttls-any-program-available', -'strokes-modeline-string', 'strokes-report-bug', -'term-default-bg-color', 'term-default-fg-color', -'tex-string-prefix-p', 'timeclock-modeline-display', -'timeclock-modeline-display', 'timeclock-update-modeline', -'toggle-emacs-lock', 'tooltip-use-echo-area', 'turn-on-cwarn-mode', -'turn-on-iimage-mode', 'ucs-input-inactivate', 'ucs-insert', -'url-recreate-url-attributes', 'user-variable-p', -'vc-string-prefix-p', 'vc-toggle-read-only', 'view-return-to-alist', -'view-return-to-alist-update', 'w32-default-color-map' (function), -'which-func-mode' (function), 'window-system-version', -'winner-mode-leave-hook', 'x-cut-buffer-or-selection-value'. - ---- -** Some functions and variables obsolete since Emacs 23 have been removed: -'find-emacs-lisp-shadows', 'newsticker-cache-filename', -'process-filter-multibyte-p', 'redisplay-end-trigger-functions', -'set-process-filter-multibyte', 'set-window-redisplay-end-trigger', -'unify-8859-on-decoding-mode', 'unify-8859-on-encoding-mode', -'vc-arch-command', 'window-redisplay-end-trigger', 'x-selection'. - ---- -** Some functions and variables obsolete since Emacs 21 or 22 have been removed: -'c-toggle-auto-state', 'find-file-not-found-hooks', -'ls-lisp-dired-ignore-case', 'query-replace-regexp-eval'. - -+++ -** New generic function 'function-documentation'. -It can dynamically generate a raw docstring depending on the type of a -function. Used mainly for docstrings of OClosures. - -+++ -** Base64 encoding no longer tolerates latin-1 input. -The functions 'base64-encode-string', 'base64url-encode-string', -'base64-encode-region' and 'base64url-encode-region' no longer accept -characters in the range U+0080..U+00FF as substitutes for single bytes -in the range 128..255, but signal an error for all multibyte characters. -The input must be unibyte encoded text. - -+++ -** The 'clone-indirect-buffer-hook' is now run by 'make-indirect-buffer'. -It was previously only run by 'clone-indirect-buffer' and -'clone-indirect-buffer-other-window'. Since 'make-indirect-buffer' is -called by both of these, the hook is now run by all 3 of these -functions. - ---- -** '?\' at the end of a line now signals an error. -Previously, it produced a nonsense value, -1, that was never intended. - ---- -** Some libraries obsolete since Emacs 24.1 and 24.3 have been removed: -abbrevlist.el, assoc.el, complete.el, cust-print.el, -erc-hecomplete.el, mailpost.el, mouse-sel.el, old-emacs-lock.el, -patcomp.el, pc-mode.el, pc-select.el, s-region.el, and sregex.el. - -+++ -** Many seldom-used generalized variables have been made obsolete. -Emacs has a number of rather obscure generalized variables defined, -that, for instance, allowed you to say things like: - - (setf (point-min) 4) - -These never caught on and have been made obsolete. The form above, -for instance, is the same as saying - - (narrow-to-region 4 (point-max)) - -The following generalized variables have been made obsolete: -'buffer-file-name', 'buffer-local-value', 'buffer-modified-p', -'buffer-name', 'buffer-string', 'buffer-substring', 'current-buffer', -'current-column', 'current-global-map', 'current-input-mode', -'current-local-map', 'current-window-configuration', -'default-file-modes', 'documentation-property', 'eq', 'frame-height', -'frame-width', 'frame-visible-p', 'global-key-binding', -'local-key-binding', 'mark', 'mark-marker', 'marker-position', -'mouse-position', 'point', 'point-marker', 'point-max', 'point-min', -'read-mouse-position', 'screen-height', 'screen-width', -'selected-frame', 'selected-screen', 'selected-window', -'standard-case-table', 'syntax-table', 'visited-file-modtime', -'window-height', 'window-width', and 'x-get-secondary-selection'. +** User option 'tramp-completion-reread-directory-timeout' has been removed. +This user option has been obsoleted in Emacs 27, use +'remote-file-name-inhibit-cache' instead. -* Lisp Changes in Emacs 29.1 - -+++ -** Interpreted closures are "safe for space". -As was already the case for byte-compiled closures, instead of capturing -the whole current lexical environment, interpreted closures now only -capture the part of the environment that they need. -The previous behavior could occasionally lead to memory leaks or -to problems where a printed closure would not be 'read'able because -of an un'read'able value in an unrelated lexical variable. - -+++ -** New accessor function 'file-attribute-file-identifier'. -It returns the list of the inode number and device identifier -retrieved by 'file-attributes'. This value can be used to identify a -file uniquely. The device identifier can be a single number or (for -remote files) a cons of 2 numbers. - -+++ -** New macro 'while-let'. -This is like 'when-let', but repeats until a binding form is nil. - -+++ -** New function 'make-obsolete-generalized-variable'. -This can be used to mark setters used by 'setf' as obsolete, and the -byte-compiler will then warn about using them. - -+++ -** New functions 'pos-eol' and 'pos-bol'. -These are like 'line-end-position' and 'line-beginning-position' -(respectively), but ignore fields (and are more efficient). - -+++ -** New function 'compiled-function-p'. -This returns non-nil if its argument is either a built-in, or a -byte-compiled, or a natively-compiled function object, or a function -loaded from a dynamic module. - ---- -** 'deactivate-mark' can have new value 'dont-save'. -This value means that Emacs should deactivate the mark as usual, but -without setting the primary selection, if 'select-active-regions' is -enabled. - -+++ -** New 'declare' form 'interactive-args'. -This can be used to specify what forms to put into 'command-history' -when executing commands interactively. - -+++ -** The FORM argument of 'time-convert' is mandatory. -'time-convert' can still be called without it, as before, but the -compiler now emits a warning about this deprecated usage. - -+++ -** Emacs now supports user-customizable and themable icons. -These can be used for buttons in buffers and the like. See the -"(elisp) Icons" and "(emacs) Icons" nodes in the manuals for details. - -+++ -** New arguments MESSAGE and TIMEOUT of 'set-transient-map'. -MESSAGE specifies a message to display after activating the transient -map, including a special formatting spec to list available keys. -TIMEOUT is the idle time after which to deactivate the transient map. -The default timeout value can be defined by the new variable -'set-transient-map-timeout'. - -** Connection Local Variables - -+++ -*** Some connection-local variables are now user options. -The variables 'connection-local-profile-alist' and -'connection-local-criteria-alist' are now user options, in order to -make it more convenient to inspect and modify them. - -+++ -*** New function 'connection-local-update-profile-variables'. -This function allows to modify the settings of an existing -connection-local profile. - -+++ -*** New macro 'with-connection-local-application-variables'. -This macro works like 'with-connection-local-variables', but it allows -to use another application but 'tramp'. This is useful when running -code in a buffer where Tramp has already set some connection-local -variables. - -+++ -*** New macro 'setq-connection-local'. -This allows dynamically setting variable values for a particular -connection within the body of 'with-connection-local-{application-}variables'. -See the "(elisp) Connection Local Variables" node in the Lisp -Reference manual for more information. - -+++ -** 'plist-get', 'plist-put' and 'plist-member' are no longer limited to 'eq'. -These function now take an optional comparison PREDICATE argument. - -+++ -** 'read-multiple-choice' can now use long-form answers. - -+++ -** 'M-s c' in 'read-regexp' now toggles case folding. - -+++ -** 'completing-read' now allows a function as its REQUIRE-MATCH argument. -This function is called to see whether what the user has typed is a -match. This is also available from functions that call -'completing-read', like 'read-file-name'. - -+++ -** 'posn-col-row' can now give position data based on windows. -Previously, it reported data only based on the frame. - -+++ -** 'file-expand-wildcards' can now also take a regexp as PATTERN argument. - ---- -** vc-mtn (the VC backend for Monotone) has been made obsolete. - -+++ -** 'gui-set-selection' can specify different values for different data types. -If DATA is a string, then its text properties are searched for values -for each specific data type while the selection is being converted. - ---- -** New eldoc function 'elisp-eldoc-var-docstring-with-value'. -This function includes the current value of the variable in eldoc display -and can be used as a more detailed alternative to 'elisp-eldoc-var-docstring'. - -+++ -** 'save-some-buffers' can now be extended to save other things. -Traditionally, 'save-some-buffers' saved buffers, and also saved -abbrevs. This has been generalized via the -'save-some-buffers-functions' variable, and packages can now register -things to be saved. - -+++ -** New function 'string-equal-ignore-case'. -This compares strings ignoring case differences. - -+++ -** 'symbol-file' can now report natively-compiled ".eln" files. -If Emacs was built with native-compilation enabled, Lisp programs can -now call 'symbol-file' with the new optional 3rd argument non-nil to -request the name of the ".eln" file which defined a given symbol. - -+++ -** New macro 'with-memoization' provides a very primitive form of memoization. - -+++ -** 'max-char' can now report the maximum codepoint according to Unicode. -When called with a new optional argument UNICODE non-nil, 'max-char' -will now report the maximum valid codepoint defined by the Unicode -Standard. - -** Seq - -+++ -*** New function 'seq-split'. -This returns a list of sub-sequences of the specified sequence. - -+++ -*** New function 'seq-remove-at-position'. -This function returns a copy of the specified sequence where the -element at a given (zero-based) index got removed. - -+++ -*** New function 'seq-positions'. -This returns a list of the (zero-based) indices of elements matching a -given predicate in the specified sequence. - -+++ -*** New function 'seq-keep'. -This is like 'seq-map', but removes all nil results from the returned -list. - -** Themes - ---- -*** New hooks 'enable-theme-functions' and 'disable-theme-functions'. -These are run after enabling and disabling a theme, respectively. - ---- -*** Themes can now be made obsolete. -Using 'make-obsolete' on a theme is now supported. This will make -'load-theme' issue a warning when loading the theme. - -+++ -** New hook 'display-monitors-changed-functions'. -It is called whenever the configuration of different monitors on a -display changes. - -+++ -** 'prin1' and 'prin1-to-string' now take an optional OVERRIDES argument. -This argument can be used to override values of print-related settings. - -+++ -** New minor mode 'header-line-indent-mode'. -This is meant to be used in modes that have a header line that should -be kept aligned with the buffer contents when the user switches -'display-line-numbers-mode' on or off. - -+++ -** New global minor mode 'lost-selection-mode'. -This global minor mode makes Emacs deactivate the mark in all buffers -when the primary selection is obtained by another program. - ---- -** On X, Emacs will try to preserve selection ownership when a frame is deleted. -This means that if you make Emacs the owner of a selection, such as by -selecting some text into the clipboard or primary selection, and then -delete the current frame, you will still be able to insert the -contents of that selection into other programs as long as another -frame is open on the same display. This behavior can be disabled by -setting the user option 'x-auto-preserve-selections' to nil. - -+++ -** New predicate 'char-uppercase-p'. -This returns non-nil if its argument its an uppercase character. - -** Byte Compilation - ---- -*** Byte compilation will now warn about some quoting mistakes in docstrings. -When writing code snippets that contains the "'" character (APOSTROPHE), -that quote character has to be escaped to avoid Emacs displaying it as -"’" (LEFT SINGLE QUOTATION MARK), which would make code examples like - - (setq foo '(1 2 3)) - -invalid. Emacs will now warn during byte compilation if it seems -something like that, and also warn about when using RIGHT/LEFT SINGLE -QUOTATION MARK directly. In both these cases, if these characters -should really be present in the docstring, they should be quoted with -"\=". - ---- -*** Byte compilation will now warn about some malformed 'defcustom' types. -It is very common to write 'defcustom' types on the form: - - :type '(choice (const :tag "foo" 'bar)) +* Lisp Changes in Emacs 30.1 -I.e., double-quoting the 'bar', which is almost never the correct -value. The byte compiler will now issue a warning if it encounters -these forms. - -+++ -** 'restore-buffer-modified-p' can now alter buffer auto-save state. -With a FLAG value of 'autosaved', it will mark the buffer as having -been auto-saved since the time of last modification. +** New or changed byte-compilation warnings --- -** New minor mode 'isearch-fold-quotes-mode'. -This sets up 'search-default-mode' so that quote characters are -char-folded into each other. It is used, by default, in "*Help*" and -"*info*" buffers. +*** Warn about empty bodies for more special forms and macros. +The compiler now warns about an empty body argument to 'when', +'unless', 'ignore-error' and 'with-suppressed-warnings' in addition to +the existing warnings for 'let' and 'let*'. Example: -+++ -** New macro 'buffer-local-set-state'. -This is a helper macro to be used by minor modes that wish to restore -buffer-local variables back to their original states when the mode is -switched off. + (when (> x 2)) ---- -** New macro 'with-buffer-unmodified-if-unchanged'. -If the buffer is marked as unmodified, and code does modifications -that, in total, means that the buffer is identical to the buffer -before, mark the buffer as unmodified again. +This warning can be suppressed using 'with-suppressed-warnings' with +the warning name 'empty-body'. --- -** New function 'malloc-trim'. -This function allows returning unused memory back to the operating -system, and is mainly meant as a debugging tool. It is currently -available only when Emacs was built with glibc as the C library. +*** Warn about quoted error names in 'condition-case' and 'ignore-error'. +The compiler now warns about quoted condition (error) names +in 'condition-case' and 'ignore-error'. Example: ---- -** 'x-show-tip' no longer hard-codes a timeout default. -The new variable 'x-show-tooltip-timeout' allows the user to alter -this for packages that don't use 'tooltip-show', but instead call the -lower level function directly. + (condition-case nil + (/ x y) + ('arith-error "division by zero")) ---- -** New function 'current-cpu-time'. -It gives access to the CPU time used by the Emacs process, for -example for benchmarking purposes. +Quoting them adds the error name 'quote' to those handled or ignored +respectively, which was probably not intended. --- -** New function 'string-edit'. -This is meant to be used when the user has to edit a (potentially) -long string. It pops up a new buffer where you can edit the string, -and a callback is called when the user types 'C-c C-c'. +*** Warn about comparison with literal constants without defined identity. +The compiler now warns about comparisons by identity with a literal +string, cons, vector, record, function, large integer or float as this +may not match any value at all. Example: -+++ -** New function 'read-string-from-buffer'. -This is a modal version of 'string-edit', and can be used as an -alternative to 'read-string'. + (eq x "hello") -+++ -** The return value of 'clear-message-function' is not ignored anymore. -If the function returns 'dont-clear-message', then the message is not -cleared, with the assumption that the function cleared it itself. - -+++ -** The local variables section now supports defining fallback modes. -This was previously only available when using a property line (i.e., -putting the modes on the first line of a file). +Only literals for symbols and small integers (fixnums), including +characters, are guaranteed to have a consistent (unique) identity. +This warning applies to 'eq', 'eql', 'memq', 'memql', 'assq', 'rassq', +'remq' and 'delq'. -+++ -** New function 'flush-standard-output'. -This enables display of lines that don't end in a newline from -batch-based Emacs scripts. +To compare by (structural) value, use 'equal', 'member', 'assoc', +'rassoc', 'remove' or 'delete' instead. Floats and bignums can also +be compared using 'eql', '=' and 'memql'. Function literals cannot be +compared reliably at all. -+++ -** New convenience function 'buttonize-region'. -This works like 'buttonize', but for a region instead of a string. +This warning can be suppressed using 'with-suppressed-warnings' with +the warning name 'suspicious'. +++ -** 'macroexp-let2*' can omit TEST argument and use single-var bindings. - -+++ -** New macro-writing macros, 'cl-with-gensyms' and 'cl-once-only'. -See the "(cl) Macro-Writing Macros" manual section for descriptions. - -+++ -** New variable 'last-event-device' and new function 'device-class'. -On X Windows, 'last-event-device' specifies the input extension device -from which the last input event originated, and 'device-class' can be -used to determine the type of an input device. - -+++ -** Variable 'track-mouse' can have a new value 'drag-source'. -This means the same as 'dropping', but modifies the mouse position -list in reported motion events if there is no frame underneath the -mouse pointer. - -+++ -** New functions for dragging items from Emacs to other programs. -The new functions 'x-begin-drag', 'dnd-begin-file-drag', -'dnd-begin-drag-files', and 'dnd-direct-save' allow dragging contents -(such as files and text) from Emacs to other programs. - ---- -** New function 'ietf-drums-parse-date-string'. -This function parses RFC5322 (and RFC822) date strings, and should be -used instead of 'parse-time-string' when parsing data that's standards -compliant. - -+++ -** New macro 'setopt'. -This is like 'setq', but is meant to be used for user options instead -of plain variables, and uses 'custom-set'/'set-default' to set them. - -+++ -** New utility predicate 'mode-line-window-selected-p'. -This is meant to be used from ':eval' mode line constructs to create -different mode line looks for selected and unselected windows. - -+++ -** New variable 'messages-buffer-name'. -This variable (defaulting to "*Messages*") allows packages to override -where messages are logged. - -+++ -** New function 'readablep'. -This function says whether an object can be written out and then -read back by the Emacs Lisp reader. - -+++ -** New variable 'print-unreadable-function'. -This variable allows changing how Emacs prints unreadable objects. - ---- -** The user option 'polling-period' now accepts floating point values. -This means Emacs can now poll for input during Lisp execution more -frequently than once in a second. - ---- -** New function 'bidi-string-strip-control-characters'. -This utility function is meant for displaying strings when it is -essential that there's no bidirectional context. It removes all the -bidirectional formatting control characters (such as RLM, LRO, PDF, -etc.) from its argument string. The characters it removes are listed -in the value of 'bidi-control-characters'. - ---- -** The Gnus range functions have been moved to a new library, range.el. -All the old names have been made obsolete. - -+++ -** 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. - -+++ -** New facility for handling session state: 'multisession-value'. -This can be used as a convenient way to store (simple) application -state, and the command 'list-multisession-values' allows users to list -(and edit) this data. - -+++ -** New function 'get-display-property'. -This is like 'get-text-property', but works on the 'display' text -property. - -+++ -** New function 'add-display-text-property'. -This is like 'put-text-property', but works on the 'display' text -property. - -+++ -** New 'min-width' 'display' property. -This allows setting a minimum display width for a region of text. - -+++ -** New 'cursor-face' text property. -This uses 'cursor-face' instead of the default face when cursor is on or -near the character and 'cursor-face-highlight-mode' is enabled. The -user option 'cursor-face-highlight-nonselected-window' is similar to -'highlight-nonselected-windows', but for this property. - -+++ -** New event type 'touch-end'. -This event is sent whenever the user's finger moves off the mouse -wheel on some mice, or when the user's finger moves off the touchpad. - -+++ -** New event type 'pinch'. -This event is sent when a user performs a pinch gesture on a touchpad, -which is comprised of placing two fingers on the touchpad and moving -them towards or away from each other. - -+++ -** New hook 'x-pre-popup-menu-hook'. -This hook, run before 'x-popup-menu', is about to display a -deck-of-cards menu on screen. - ---- -** New hook 'post-select-region-hook'. -This hook is run immediately after 'select-active-regions'. It causes -the region to be set as the primary selection. - -+++ -** New function 'buffer-match-p'. -Check if a buffer satisfies some condition. Some examples for -conditions can be regular expressions that match a buffer name, a -cons-cell like '(major-mode . shell-mode)' that matches any buffer -where 'major-mode' is 'shell-mode' or a combination with a condition -like '(and "\\`\\*.+\\*\\'" (major-mode . special-mode))'. - -+++ -** New function 'match-buffers'. -It uses 'buffer-match-p' to gather a list of buffers that match a -condition. - ---- -** New optional arguments TEXT-FACE and DEFAULT-FACE for 'tooltip-show'. -They allow changing the faces used for the tooltip text and frame -colors of the resulting tooltip frame from the default 'tooltip' face. - -** Text Security and Suspiciousness - -+++ -*** New library textsec.el. -This library contains a number of checks for whether a string is -"suspicious". This usually means that the string contains characters -that have glyphs that can be confused with other, more commonly used -glyphs, or contains bidirectional (or other) formatting characters -that may be used to confuse a user. - -+++ -*** New user option 'textsec-check'. -If non-nil (which is the default), Emacs packages that are vulnerable -to attackers trying to confuse the users will use the textsec library -to mark suspicious text. For instance shr/eww will mark suspicious -URLs and links, Gnus will mark suspicious From addresses, and -Message mode will query the user if the user is sending mail to a -suspicious address. If this variable is nil, these checks are -disabled. - -+++ -*** New function 'textsec-suspicious-p'. -This is the main function Emacs applications should be using to check -whether a string is suspicious. It heeds the 'textsec-check' user -option. - -** Keymaps and Key Definitions - -+++ -*** 'where-is-internal' can now filter events marked as non key events. -If a command maps to a key binding like '[some-event]', and 'some-event' -has a symbol plist containing a non-nil 'non-key-event' property, then -that binding is ignored by 'where-is-internal'. - -+++ -*** New functions for defining and manipulating keystrokes. -These all take the syntax defined by 'key-valid-p'. None of the older -functions have been deprecated or altered, but they are now -de-emphasized in the documentation. - -+++ -*** Use 'keymap-set' instead of 'define-key'. - -+++ -*** Use 'keymap-global-set' instead of 'global-set-key'. - -+++ -*** Use 'keymap-local-set' instead of 'local-set-key'. - -+++ -*** Use 'keymap-global-unset' instead of 'global-unset-key'. - -+++ -*** Use 'keymap-local-unset' instead of 'local-unset-key'. - -+++ -*** Use 'keymap-substitute' instead of 'substitute-key-definition'. - -+++ -*** Use 'keymap-set-after' instead of 'define-key-after'. - -+++ -*** Use 'keymap-lookup' instead of 'lookup-key' and 'key-binding'. - -+++ -*** Use 'keymap-local-lookup' instead of 'local-key-binding'. - -+++ -*** Use 'keymap-global-lookup' instead of 'global-key-binding'. - -+++ -*** 'define-key' now takes an optional REMOVE argument. -If non-nil, remove the definition from the keymap. This is subtly -different from setting a definition to nil (when the keymap has a -parent). - -+++ -*** 'read-multiple-choice' now takes an optional SHOW-HELP argument. -If non-nil, show the help buffer immediately, before any user input. - -+++ -*** New function 'key-valid-p'. -The 'kbd' function is quite permissive, and will try to return -something usable even if the syntax of the argument isn't completely -correct. The 'key-valid-p' predicate does a stricter check of the -syntax. - ---- -*** New function 'key-parse'. -This is like 'kbd', but only returns vectors instead of a mix of -vectors and strings. - -+++ -*** New ':type' for 'defcustom' for keys. -The new 'key' type can be used for options that should be a valid key -according to 'key-valid-p'. The type 'key-sequence' is now obsolete. - -+++ -** New function 'define-keymap'. -This function allows defining a number of keystrokes with one form. - -+++ -** New macro 'defvar-keymap'. -This macro allows defining keymap variables more conveniently. - -** 'defvar-keymap' can specify 'repeat-mode' behavior for the keymap. -Use ':repeat t' to have all bindings be repeatable or for more -advanced usage: - - :repeat (:enter (commands ...) :exit (commands ...)) - ---- -** 'kbd' can now be used in built-in, preloaded libraries. -It no longer depends on edmacro.el and cl-lib.el. - -+++ -** New substitution in docstrings and 'substitute-command-keys'. -Use \\`KEYSEQ' to insert a literal key sequence "KEYSEQ" (for example -\\`C-k') in a docstring or when calling 'substitute-command-keys', -which will use the same face as a command substitution. This should -be used only when a key sequence has no corresponding command, for -example when it is read directly with 'read-key-sequence'. It must be -a valid key sequence according to 'key-valid-p'. - ---- -** 'lookup-key' is more permissive when searching for extended menu items. -In Emacs 28.1, the behavior of 'lookup-key' was changed: when looking -for a menu item '[menu-bar Foo-Bar]', first try to find an exact -match, then look for the lowercased '[menu-bar foo-bar]'. - -This has been extended, so that when looking for a menu item with a -symbol containing spaces, as in '[menu-bar Foo\ Bar]', first look for -an exact match, then the lowercased '[menu-bar foo\ bar]' and finally -'[menu-bar foo-bar]'. This further improves backwards-compatibility -when converting menus to use 'easy-menu-define'. - -+++ -** New function 'file-name-split'. -This returns a list of all the components of a file name. - -+++ -** New function 'file-name-parent-directory'. -This returns the parent directory of a file name. - -+++ -** New macro 'with-undo-amalgamate'. -It records a particular sequence of operations as a single undo step. - -+++ -** New command 'yank-media'. -This command supports yanking non-plain-text media like images and -HTML from other applications into Emacs. It is only supported in -modes that have registered support for it, and only on capable -platforms. - -+++ -** New command 'yank-media-types'. -This command lets you examine all data in the current selection and -the clipboard, and insert it into the buffer. - -+++ -** New variable 'yank-transform-functions'. -This variable allows the user to alter the string to be inserted. - ---- -** New command 'yank-in-context'. -This command tries to preserve string/comment syntax when yanking. - ---- -** New function 'minibuffer-lazy-highlight-setup'. -This function allows setting up the minibuffer so that lazy -highlighting of its content is applied in the original window. - -+++ -** New text property 'inhibit-isearch'. -If set, 'isearch' will skip these areas, which can be useful (for -instance) when covering huge amounts of data (that has no meaningful -searchable data, like image data) with a 'display' text property. - -+++ -** 'insert-image' now takes an INHIBIT-ISEARCH optional argument. -It marks the image with the 'inhibit-isearch' text property, which -inhibits 'isearch' matching the STRING argument. - ---- -** New variable 'replace-regexp-function'. -Function to call to convert the entered FROM string to an Emacs -regexp in 'query-replace' and similar commands. It can be used to -implement a different regexp syntax for search/replace. - ---- -** New variables to customize defaults of FROM for 'query-replace*' commands. -The new variable 'query-replace-read-from-default' can be set to a -function that returns the default value of FROM when 'query-replace' -prompts for a string to be replaced. An example of such a function is -'find-tag-default'. - -The new variable 'query-replace-read-from-regexp-default' can be set -to a function (such as 'find-tag-default-as-regexp') that returns the -default value of FROM when 'query-replace-regexp' prompts for a regexp -whose matches are to be replaced. If these variables are nil (which -is the default), 'query-replace' and 'query-replace-regexp' take the -default value from the previous FROM-TO pair. - -** Lisp pretty-printer ('pp') - ---- -*** New function 'pp-emacs-lisp-code'. -'pp' formats general Lisp sexps. This function does much the same, -but applies formatting rules appropriate for Emacs Lisp code. Note -that this could currently be quite slow, and is thus appropriate only -for relatively small code fragments. - ---- -*** New user option 'pp-use-max-width'. -If non-nil, 'pp' and all 'pp-*' commands that format the results, will -attempt to limit the line length when formatting long lists and -vectors. This uses 'pp-emacs-lisp-code', and thus could be slow for -large lists. - -+++ -** New function 'file-has-changed-p'. -This convenience function is useful when writing code that parses -files at run-time, and allows Lisp programs to re-parse files only -when they have changed. - -+++ -** 'abbreviate-file-name' now respects magic file name handlers. - ---- -** New function 'font-has-char-p'. -This can be used to check whether a specific font has a glyph for a -character. - -+++ -** 'window-text-pixel-size' now accepts a new argument IGNORE-LINE-AT-END. -This controls whether or not the last screen line of the text being -measured will be counted for the purpose of calculating the text -dimensions. - -+++ -** 'window-text-pixel-size' understands a new meaning of FROM. -Specifying a cons as the FROM argument allows to start measuring text -from a specified amount of pixels above or below a position. - -+++ -** 'window-body-width' and 'window-body-height' can use remapped faces. -Specifying 'remap' as the PIXELWISE argument now checks if the default -face was remapped, and if so, uses the remapped face to determine the -character width/height. - -+++ -** 'set-window-vscroll' now accepts a new argument PRESERVE-VSCROLL-P. -This means the vscroll will not be reset when set on a window that is -"frozen" due to a mini-window being resized. - -** XDG Support - ---- -*** New function 'xdg-state-home'. -It returns the new 'XDG_STATE_HOME' environment variable. It should -point to a file name that "contains state data that should persist -between (application) restarts, but that is not important or portable -enough to the user that it should be stored in $XDG_DATA_HOME". -(This variable was introduced in the XDG Base Directory Specification -version 0.8 released on May 8, 2021.) - ---- -*** New function 'xdg-current-desktop'. -It returns a list of strings, corresponding to the colon-separated -list of names in the 'XDG_CURRENT_DESKTOP' environment variable, which -identify the current desktop environment. -(This variable was introduced in XDG Desktop Entry Specification -version 1.2.) - ---- -*** New function 'xdg-session-type'. -It returns the 'XDG_SESSION_TYPE' environment variable. (This is not -part of any official standard; see the man page pam_systemd(8) for -more information.) - -+++ -** New macro 'with-delayed-message'. -This macro is like 'progn', but will output the specified message if -the body takes longer to execute than the specified timeout. - ---- -** New function 'funcall-with-delayed-message'. -This function is like 'funcall', but will output the specified message -if the function takes longer to execute than the specified timeout. - -** Locale - ---- -*** New variable 'current-locale-environment'. -This holds the value of the previous call to 'set-locale-environment'. - ---- -*** New macro 'with-locale-environment'. -This macro can be used to change the locale temporarily while -executing code. - -** Table - ---- -*** New user option 'table-latex-environment'. -This allows switching between "table" and "tabular". - -** Tabulated List Mode - -+++ -*** A column can now be set to an image descriptor. -The 'tabulated-list-entries' variable now supports using an image -descriptor, which means to insert an image in that column instead of -text. See the documentation string of that variable for details. - -+++ -** ':keys' in 'menu-item' can now be a function. -If so, it is called whenever the menu is computed, and can be used to -calculate the keys dynamically. - -+++ -** New major mode 'clean-mode'. -This is a new major mode meant for debugging. It kills absolutely all -local variables and removes overlays and text properties. - -+++ -** 'kill-all-local-variables' can now kill all local variables. -If given the new optional KILL-PERMANENT argument, it also kills -permanent local variables. - -+++ -** Third 'mapconcat' argument SEPARATOR is now optional. -An explicit nil always meant the empty string, now it can be left out. - -+++ -** New function 'image-at-point-p'. -This function returns t if point is on a valid image, and nil -otherwise. - -+++ -** New function 'buffer-text-pixel-size'. -This is similar to 'window-text-pixel-size', but can be used when the -buffer isn't displayed. - -+++ -** New function 'string-pixel-width'. -This returns the width of a string in pixels. This can be useful when -dealing with variable pitch fonts and glyphs that have widths that -aren't integer multiples of the default font. - -+++ -** New function 'string-glyph-split'. -This function splits a string into a list of strings representing -separate glyphs. This takes into account combining characters and -grapheme clusters, by treating each sequence of characters composed on -display as a single unit. - -** Xwidget - -+++ -*** The function 'make-xwidget' now accepts an optional RELATED argument. -This argument is used as another widget for the newly created WebKit -widget to share settings and subprocesses with. It must be another -WebKit widget. - -+++ -*** New function 'xwidget-perform-lispy-event'. -This function allows you to send events to xwidgets. Usually, some -equivalent of the event will be sent, but there is no guarantee of -what the widget will actually receive. - -On GTK+, only key and function key events are implemented. - -+++ -*** New function 'xwidget-webkit-load-html'. -This function is used to load HTML text into WebKit xwidgets -directly, in contrast to creating a temporary file to hold the -markup, and passing the URI of the file as an argument to -'xwidget-webkit-goto-uri'. - -+++ -*** New functions for performing searches on WebKit xwidgets. -Some new functions, such as 'xwidget-webkit-search', have been added -for performing searches on WebKit xwidgets. - -+++ -*** New function 'xwidget-webkit-back-forward-list'. -This function returns the history of page-loads in a WebKit xwidget. - -+++ -*** New function 'xwidget-webkit-estimated-load-progress'. -This function returns the estimated progress of page loading in a -WebKit xwidget. - -+++ -*** New function 'xwidget-webkit-stop-loading'. -This function terminates all data transfer during page loads in a -WebKit xwidget. - -+++ -*** 'load-changed' xwidget events are now more detailed. -In particular, they can now have different arguments based on the -state of the WebKit widget. 'load-finished' is sent when a load has -completed, 'load-started' when a load first starts, 'load-redirected' -after a redirect, and 'load-committed' when the WebKit widget first -commits to the load. - -+++ -*** New event type 'xwidget-display-event'. -These events are sent whenever an xwidget requests that Emacs displays -another xwidget. The only arguments to this event are the xwidget -that should be displayed, and the xwidget that asked to display it. - -+++ -*** New function 'xwidget-webkit-set-cookie-storage-file'. -This function is used to control where and if an xwidget stores -cookies set by web pages on disk. - ---- -** New variable 'help-buffer-under-preparation'. -This variable is bound to t during the preparation of a "*Help*" buffer. - -+++ -** Timestamps like '(1 . 1000)' now work without warnings being generated. -For example, '(time-add nil '(1 . 1000))' no longer warns that the -'(1 . 1000)' acts like '(1000 . 1000000)'. This warning, which was a -temporary transition aid for Emacs 27, has served its purpose. - -+++ -** 'encode-time' now also accepts a 6-element list with just time and date. -'(encode-time (list SECOND MINUTE HOUR DAY MONTH YEAR))' is now short for -'(encode-time (list SECOND MINUTE HOUR DAY MONTH YEAR nil -1 nil))'. - -+++ -** 'date-to-time' now accepts arguments that lack month, day, or time. -The function now assumes the earliest possible values if its argument -lacks month, day, or time. For example, (date-to-time "2021-12-04") -now assumes a time of "00:00" instead of signaling an error. - -+++ -** 'format-seconds' now allows suppressing zero-value trailing elements. -The new "%x" non-printing control character will suppress zero-value -elements that appear after "%x". - -+++ -** New events for taking advantage of touchscreen devices. -The events 'touchscreen-begin', 'touchscreen-update', and -'touchscreen-end' have been added to take better advantage of -touch-capable display panels. - -+++ -** New error symbol 'permission-denied'. -This is a subcategory of 'file-error', and is signaled when some file -operation fails because the OS doesn't allow Emacs to access a file or -a directory. - -+++ -** The ':underline' face attribute now accepts a new property. -The property ':position' now specifies the position of the underline -when used as part of a property list specification for the -':underline' attribute. - -+++ -** 'defalias' records a more precise history of definitions. -This is recorded in the 'function-history' symbol property. - ---- -** New hook 'save-place-after-find-file-hook'. -This is called at the end of 'save-place-find-file-hook'. - ---- -** 'indian-tml-base-table' no longer translates digits. -Use 'indian-tml-base-digits-table' if you want digits translation. - ---- -** 'indian-tml-itrans-v5-hash' no longer translates digits. -Use 'indian-tml-itrans-digits-v5-hash' if you want digits -translation. - -+++ -** 'shell-quote-argument' has a new optional argument POSIX. -This is useful when quoting shell arguments for a remote shell -invocation. Such shells are POSIX conformant by default. - -+++ -** 'make-process' can set connection type independently for input and output. -When calling 'make-process', communication via pty can be enabled -selectively for just input or output by passing a cons cell for -':connection-type', e.g. '(pipe . pty)'. When examining a process -later, you can determine whether a particular stream for a process -uses a pty by passing one of 'stdin', 'stdout', or 'stderr' as the -second argument to 'process-tty-name'. - -+++ -** 'signal-process' now consults the list 'signal-process-functions'. -This is to determine which function has to be called in order to -deliver the signal. This allows Tramp to send the signal to remote -asynchronous processes. The hitherto existing implementation has been -moved to 'internal-default-signal-process'. - -+++ -** Some system information functions honor remote systems now. -'list-system-processes' returns remote process IDs. -'memory-info' returns memory information of remote systems. -'process-attributes' expects a remote process ID. -This happens only when the current buffer's 'default-directory' is -remote. In order to preserve the old behavior, bind -'default-directory' to a local directory, like - - (let ((default-directory temporary-file-directory)) - (list-system-processes)) - -+++ -** New functions 'take' and 'ntake'. -'(take N LIST)' returns the first N elements of LIST; 'ntake' does -the same but works by modifying LIST destructively. - ---- -** 'string-split' is now an alias for 'split-string'. - -+++ -** 'format-spec' now accepts functions in the replacement. -The function is called only when used in the format string. This is -useful to avoid side-effects such as prompting, when the value is not -actually being used for anything. - -+++ -** The variable 'max-specpdl-size' has been made obsolete. -Now 'max-lisp-eval-depth' alone is used for limiting Lisp recursion -and stack usage. 'max-specpdl-size' is still present as a plain -variable for compatibility but its limiting powers have been taken away. - -** New function 'external-completion-table'. -This function returns a completion table designed to ease -communication between Emacs's completion facilities and external tools -offering completion services, particularly tools whose full working -set is too big to transfer to Emacs every time a completion is -needed. The table uses new 'external' completion style exclusively -and cannot work with regular styles such as 'basic' or 'flex'. - -+++ -** Magic file name handlers for 'make-directory-internal' are no longer needed. -Instead, Emacs uses the already-existing 'make-directory' handlers. - -+++ -** '(make-directory DIR t)' returns non-nil if DIR already exists. -This can let a caller know whether it created DIR. Formerly, -'make-directory's return value was unspecified. +** New function 'file-user-uid'. +This function is like 'user-uid', but is aware of file name handlers, +so it will return the remote UID for remote files (or -1 if the +connection has no associated user). -* Changes in Emacs 29.1 on Non-Free Operating Systems - -** MS-Windows - ---- -*** Emacs now supports double-buffering on MS-Windows to reduce display flicker. -(This was supported on Free systems since Emacs 26.1.) - -To disable double-buffering (e.g., if it causes display problems), set -the frame parameter 'inhibit-double-buffering' to a non-nil value. -You can do that either by adding - - '(inhibit-double-buffering . t) - -to 'default-frame-alist', or by modifying the frame parameters of the -selected frame by evaluating - - (modify-frame-parameters nil '((inhibit-double-buffering . t))) - -+++ -*** Emacs now supports system dark mode. -On Windows 10 (version 1809 and higher) and Windows 11, Emacs will now -follow the system's dark mode: GUI frames use the appropriate light or -dark title bar and scroll bars, based on the user's Windows-wide color -settings. - ---- -*** Emacs now uses native image APIs to display some image formats. -On Windows 2000 and later, Emacs now defaults to using the native -image APIs for displaying the BMP, GIF, JPEG, PNG, and TIFF images. -This means Emacs on MS-Windows needs no longer use external image -support libraries to display those images. Other image types -- XPM, -SVG, and WEBP -- still need support libraries for Emacs to be able to -display them. - -The use of native image APIs is controlled by the variable -'w32-use-native-image-API', whose value now defaults to t on systems -where those APIs are available. - -+++ -*** Emacs now supports display of BMP images using native image APIs. -When 'w32-use-native-image-API' is non-nil, Emacs on MS-Windows now -has built-in support for displaying BMP images. - ---- -*** GUI Yes/No dialogs now include a "Cancel" button. -The "Cancel" button is in addition to "Yes" and "No", and is intended -to allow users to quit the dialog, as an equivalent of 'C-g' when Emacs -asks a yes/no question via the echo area. This is controlled by the -new variable 'w32-yes-no-dialog-show-cancel', by default t. Set it to -nil to get back the old behavior of showing a modal dialog with only -two buttons: "Yes" and "No". - -** Cygwin - ---- -*** 'process-attributes' is now implemented. +* Changes in Emacs 30.1 on Non-Free Operating Systems ---------------------------------------------------------------------- diff --git a/etc/NEWS.29 b/etc/NEWS.29 new file mode 100644 index 00000000000..fb211f9b7d0 --- /dev/null +++ b/etc/NEWS.29 @@ -0,0 +1,4819 @@ +GNU Emacs NEWS -- history of user-visible changes. + +Copyright (C) 2021-2023 Free Software Foundation, Inc. +See the end of the file for license conditions. + +Please send Emacs bug reports to 'bug-gnu-emacs@gnu.org'. +If possible, use 'M-x report-emacs-bug'. + +This file is about changes in Emacs version 29. + +See file HISTORY for a list of GNU Emacs versions and release dates. +See files NEWS.28, NEWS.27, ..., NEWS.18, and NEWS.1-17 for changes +in older Emacs versions. + +You can narrow news to a specific version by calling 'view-emacs-news' +with a prefix argument or by typing 'C-u C-h C-n'. + +Temporary note: ++++ indicates that all relevant manuals in doc/ have been updated. +--- means no change in the manuals is needed. +When you add a new item, use the appropriate mark if you are sure it +applies, and please also update docstrings as needed. + + +* Installation Changes in Emacs 29.1 + +--- +** Ahead-of-time native compilation can now be requested via configure. +Use '--with-native-compilation=aot' to request that all the Lisp files +in the Emacs tree should be natively compiled ahead of time. (This is +slow on most machines.) + +This feature existed in Emacs 28.1, but was less easy to request. + ++++ +** Emacs can be built with the tree-sitter parsing library. +This library, together with separate grammar libraries for each +language, provides incremental parsing capabilities for several +popular programming languages and other formatted files. Emacs built +with this library offers major modes, described elsewhere in this +file, that are based on the tree-sitter's parsers. If you have the +tree-sitter library installed, the configure script will automatically +include it in the build; use '--without-tree-sitter' at configure time +to disable that. + +Emacs modes based on the tree-sitter library require an additional +grammar library for each mode. These grammar libraries provide the +tree-sitter library with language-specific lexical analysis and +parsing capabilities, and are developed separately from the +tree-sitter library itself. If you don't have a grammar library +required by some Emacs major mode, and your distro doesn't provide it +as an installable package, you can compile and install such a library +yourself. Many libraries can be downloaded from the tree-sitter site: + + https://github.com/tree-sitter + +Emacs provides a user command, 'treesit-install-language-grammar', +that automates the download and build process of a grammar library. +It prompts for the language, the URL of the language grammar's VCS +repository, and then uses the installed C/C++ compiler to build the +library and install it. + +You can also do this manually. To compile such a library after +cloning its Git repository, compile the files "scanner.c" and +"parser.c" (sometimes named "scanner.cc" and "parser.cc") in the "src" +subdirectory of the library's source tree using the C or C++ compiler, +then link these two files into a shared library named +"libtree-sitter-LANG.so", where LANG is the name of the language +supported by the grammar as it is expected by the Emacs major mode +(for example, "c" for 'c-ts-mode', "cpp" for 'c++-ts-mode', "python" +for 'python-ts-mode', etc.). Then place the shared library you've +built in the same directory where you keep the other shared libraries +used by Emacs, or in the "tree-sitter" subdirectory of your +'user-emacs-directory', or in a directory mentioned in the variable +'treesit-extra-load-path'. + +You only need to install language grammar libraries required by the +Emacs modes you will use, as Emacs loads these libraries only when the +corresponding mode is turned on in some buffer for the first time in +an Emacs session. + ++++ +** Emacs can be built with built-in support for accessing SQLite databases. +This uses the popular sqlite3 library, and can be disabled by using +the '--without-sqlite3' option to the 'configure' script. + ++++ +** Support for the WebP image format. +This support is built by default when the libwebp library is +available, and includes support for animated WebP images. To disable +WebP support, use the '--without-webp' configure flag. Image +specifiers can now use ':type webp'. + ++++ +** Emacs has been ported to the Haiku operating system. +The configuration process should automatically detect and build for +Haiku. There is also an optional window-system port to Haiku, which +can be enabled by configuring Emacs with the option '--with-be-app', +which will require the Haiku Application Kit development headers and a +C++ compiler to be present on your system. If Emacs is not built with +the option '--with-be-app', the resulting Emacs will only run in +text-mode terminals. + +To enable Cairo support, ensure that the Cairo and FreeType +development files are present on your system, and configure Emacs with +'--with-be-cairo'. + +Unlike X, there is no compile-time option to enable or disable +double-buffering; it is always enabled. To disable it, change the +frame parameter 'inhibit-double-buffering' instead. + +--- +** Emacs now installs the ".pdmp" file using a unique fingerprint in the name. +The file is typically installed using a file name akin to +"...dir/libexec/emacs/29.1/x86_64-pc-linux-gnu/emacs-<fingerprint>.pdmp". +If a constant file name is required, the file can be renamed to +"emacs.pdmp", and Emacs will find it during startup anyway. + +--- +** Emacs on X now uses XInput 2 for input events. +If your X server has support and you have the XInput 2 development +headers installed, Emacs will use the X Input Extension for handling +input. If this causes problems, you can configure Emacs with the +option '--without-xinput2' to disable this support. + +'(featurep 'xinput2)' can be used to test for the presence of XInput 2 +support from Lisp programs. + ++++ +** Emacs now supports being built with pure GTK. +To use this option, make sure the GTK 3 (version 3.22.23 or later) and +Cairo development files are installed, and configure Emacs with the +option '--with-pgtk'. Unlike the default X and GTK build, the +resulting Emacs binary will work on any underlying window system +supported by GDK, such as Wayland and Broadway. We recommend that you +use this configuration only if you are running a window system other +than X that's supported by GDK. Running this configuration on X is +known to have problems, such as undesirable frame positioning and +various issues with keyboard input of sequences such as 'C-;' and +'C-S-u'. + +--- +** Emacs no longer reduces the size of the Japanese dictionary. +Building Emacs includes generation of a Japanese dictionary, which is +used by Japanese input methods. Previously, the build included a step +of reducing the size of this dictionary's vocabulary. This vocabulary +reduction is now optional, by default off. If you need the Emacs +build to include the vocabulary reduction, configure Emacs with the +option '--with-small-ja-dic'. In an Emacs source tree already +configured without that option, you can force the vocabulary reduction +by saying + + make -C leim generate-ja-dic JA_DIC_NO_REDUCTION_OPTION='' + +after deleting "lisp/leim/ja-dic/ja-dic.el". + +--- +** The docstrings of preloaded files are not in "etc/DOC" any more. +Instead, they're fetched as needed from the corresponding ".elc" +files, as was already the case for all the non-preloaded files. + + +* Startup Changes in Emacs 29.1 + ++++ +** '--batch' and '--script' now adjust the garbage collection levels. +These switches now set 'gc-cons-percentage' to 1.0 (up from the +default of 0.1). This means that batch processes will typically use +more memory than before, but use less time doing garbage collection. +Batch jobs that are supposed to run for a long time should adjust the +limit back down again. + ++++ +** Emacs can now be used more easily in an executable script. +If you start an executable script with + + #!/usr/bin/emacs -x + +Emacs will start without reading any init files (like with '--quick'), +and then execute the rest of the script file as Emacs Lisp. When it +reaches the end of the script, Emacs will exit with an exit code from +the value of the final form. + ++++ +** Emacs now supports setting 'user-emacs-directory' via '--init-directory'. +Use the '--init-directory' command-line option to set +'user-emacs-directory'. + ++++ +** Emacs now has a '--fingerprint' option. +This will output a string identifying the current Emacs build, and exit. + ++++ +** New hook 'after-pdump-load-hook'. +This is run at the end of the Emacs startup process, and is meant to +be used to reinitialize data structures that would normally be done at +load time. + +** Native Compilation + ++++ +*** New variable 'inhibit-automatic-native-compilation'. +If set, Emacs will inhibit native compilation (and won't write +anything to the eln cache automatically). The variable is initialized +during Emacs startup from the environment variable +'EMACS_INHIBIT_AUTOMATIC_NATIVE_COMPILATION'. + +--- +*** New command 'native-compile-prune-cache'. +This command deletes old subdirectories of the eln cache (but not the +ones for the current Emacs version). Note that subdirectories of the +system directory where the "*.eln" files are installed (usually, the +last entry in 'native-comp-eln-load-path') are not deleted. + +--- +*** New function 'startup-redirect-eln-cache'. +This function can be called in your init files to change the +user-specific directory where Emacs stores the "*.eln" files produced +by native compilation of Lisp packages Emacs loads. The default +eln cache directory is unchanged: it is the "eln-cache" subdirectory +of 'user-emacs-directory'. + + +* Incompatible changes in Emacs 29.1 + ++++ +** The image commands have changed key bindings. +In previous Emacs versions, images have had the '+', '-' and 'r' keys +bound when point is over an image. In Emacs 29.1, additional commands +were added, and this made it more likely that users would trigger the +image commands by mistake. To avoid this, all image commands have +moved to the 'i' keymap, so '+' is now 'i +', '-' is now 'i -', and +'r' is now 'i r'. In addition, these commands are now repeating, so +you can rotate an image twice by saying 'i r r', for instance. + ++++ +** Emacs now picks the correct coding-system for X input methods. +Previously, Emacs would use 'locale-coding-system' for input +methods, which could in some circumstances be incorrect, especially +when the input method chose to fall back to some other coding system. + +Emacs now automatically detects the coding-system used by input +methods, and uses that to decode input in preference to the value of +'locale-coding-system'. This unfortunately means that users who have +changed the coding system used to decode X keyboard input must adjust +their customizations to 'locale-coding-system' to the variable +'x-input-coding-system' instead. + ++++ +** Bookmarks no longer include context for encrypted files. +If you're visiting an encrypted file, setting a bookmark no longer +includes excerpts from that buffer in the bookmarks file. This is +implemented by the new hook 'bookmark-inhibit-context-functions', +where packages can register a function which returns non-nil for file +names to be excluded from adding such excerpts. + +--- +** 'show-paren-mode' is now disabled in 'special-mode' buffers. +In Emacs versions previous to Emacs 28.1, 'show-paren-mode' defaulted +off. In Emacs 28.1, the mode was switched on in all buffers. In +Emacs 29.1, this was changed to be switched on in all editing-related +buffers, but not in buffers that inherit from 'special-mode'. To go +back to how things worked in Emacs 28.1, put the following in your +init file: + + (setopt show-paren-predicate t) + ++++ +** Explicitly-set read-only state is preserved when reverting a buffer. +If you use the 'C-x C-q' command to change the read-only state of the +buffer and then revert it, Emacs would previously use the file +permission bits to determine whether the buffer should be read-only +after reverting the buffer. Emacs now remembers the decision made in +'C-x C-q'. + +--- +** The Gtk selection face is no longer used for the region. +The combination of a Gtk-controlled background and a foreground color +controlled by the internal Emacs machinery led to low-contrast faces +in common default setups. Emacs now uses the same 'region' face on +Gtk and non-Gtk setups. + +--- +** 'C-h f' and 'C-h x' may now require confirmation when you press 'RET'. +If the text in the minibuffer cannot be completed to a single function +or command, typing 'RET' will not automatically complete to the shortest +candidate, but will instead ask for confirmation. Typing 'TAB' will +complete as much as possible, and another 'TAB' will show all the +possible completions. This allows you to insist on the functions name +even if Help doesn't appear to know about it, by confirming with a +second 'RET'. + +** Dired + +--- +*** 'w' ('dired-copy-filename-as-kill') has changed behavior. +If there are several files marked, file names containing space and +quote characters will be quoted "like this". + +--- +*** The 'd' command now more consistently skips dot files. +In previous Emacs versions, commands like 'C-u 10 d' would put the "D" +mark on the next ten files, no matter whether they were dot files +(i.e., "." and "..") or not, while marking the next ten lines with the +mouse (in 'transient-mark-mode') and then hitting 'd' would skip dot +files. These now work equivalently. + ++++ +** Warning about "eager macro-expansion failure" is now an error. + +--- +** Previously, the X "reverseVideo" value at startup was heeded for all frames. +This meant that if you had a "reverseVideo" resource on the initial +display, and then opened up a new frame on a display without any +explicit "reverseVideo" setting, it would get heeded there, too. (This +included terminal frames.) In Emacs 29, the "reverseVideo" X resource +is handled like all the other X resources, and set on a per-frame basis. + ++++ +** 'E' in 'query-replace' now edits the replacement with exact case. +Previously, this command did the same as 'e'. + +--- +** '/ a' in "*Packages*" buffer now limits by archive name(s) instead of regexp. + ++++ +** Setting the goal columns now also affects '<prior>' and '<next>'. +Previously, 'C-x C-n' only affected 'next-line' and 'previous-line', +but it now also affects 'scroll-up-command' and 'scroll-down-command'. + +--- +** Isearch in "*Help*" and "*info*" now char-folds quote characters by default. +This means that you can say 'C-s `foo' (GRAVE ACCENT) if the buffer +contains "‘foo" (LEFT SINGLE QUOTATION MARK) and the like. These +quotation characters look somewhat similar in some fonts. To switch +this off, disable the new 'isearch-fold-quotes-mode' minor mode. + +--- +** Sorting commands no longer necessarily change modification status. +In earlier Emacs versions, commands like 'sort-lines' would always +change buffer modification status to "modified", whether they changed +something in the buffer or not. This has been changed: the buffer is +marked as modified only if the sorting ended up actually changing the +contents of the buffer. + +--- +** 'string-lines' handles trailing newlines differently. +It no longer returns an empty final string if the string ends with a +newline. + +--- +** 'TAB' and '<backtab>' are now bound in 'button-map'. +This means that if point is on a button, 'TAB' will take you to the +next button, even if the mode has bound it to something else. This +also means that 'TAB' on a button in an 'outline-minor-mode' heading +will move point instead of collapsing the outline. + +--- +** 'outline-minor-mode-cycle-map' is now parent of 'outline-minor-mode'. +Instead of adding text property 'keymap' with 'outline-minor-mode-cycle' +on outline headings in 'outline-minor-mode', the keymap +'outline-minor-mode-cycle' is now active in the whole buffer. +But keybindings in 'outline-minor-mode-cycle' still take effect +only on outline headings because they are bound with the help of +'outline-minor-mode-cycle--bind' that checks if point is on a heading. + +--- +** 'Info-default-directory-list' is no longer populated at Emacs startup. +If you have code in your init file that removes directories from +'Info-default-directory-list', this will no longer work. + +--- +** 'C-k' no longer deletes files in 'ido-mode'. +To get the previous action back, put something like the following in +your Init file: + + (require 'ido) + (keymap-set ido-file-completion-map "C-k" #'ido-delete-file-at-head) + +--- +** New user option 'term-clear-full-screen-programs'. +By default, term.el will now work like most terminals when displaying +full-screen programs: When they exit, the output is cleared, leaving +what was displayed in the window before the programs started. Set +this user option to nil to revert back to the old behavior. + +--- +** Support for old EIEIO functions is not autoloaded any more. +You need an explicit '(require 'eieio-compat)' to use 'defmethod' +and 'defgeneric' (which have been made obsolete in Emacs 25.1 with +'cl-defmethod' and 'cl-defgeneric'). +Similarly you might need to '(require 'eieio-compat)' before loading +files that were compiled with an old EIEIO (Emacs<25). + +--- +** 'C-x 8 .' has been moved to 'C-x 8 . .'. +This is to open up the 'C-x 8 .' map to bind further characters there. + +--- +** 'C-x 8 =' has been moved to 'C-x 8 = ='. +You can now use 'C-x 8 =' to insert several characters with macron; +for example, 'C-x 8 = a' will insert U+0101 LATIN SMALL LETTER A WITH +MACRON. To insert a lone macron, type 'C-x 8 = =' instead of the +previous 'C-x ='. + +** Eshell + +*** Eshell's PATH is now derived from 'exec-path'. +For consistency with remote connections, Eshell now uses 'exec-path' +to determine the execution path on the local or remote system, instead +of using the PATH environment variable directly. + +--- +*** 'source' and '.' no longer accept the '--help' option. +This is for compatibility with the shell versions of these commands, +which don't handle options like '--help' in any special way. + ++++ +*** String delimiters in argument predicates/modifiers are more restricted. +Previously, some argument predicates/modifiers allowed arbitrary +characters as string delimiters. To provide more unified behavior +across all predicates/modifiers, the list of allowed delimiters has +been restricted to "...", '...', /.../, |...|, (...), [...], <...>, +and {...}. See the "(eshell) Argument Predication and Modification" +node in the Eshell manual for more details. + ++++ +*** Eshell pipelines now only pipe stdout by default. +To pipe both stdout and stderr, use the '|&' operator instead of '|'. + +--- +** The 'delete-forward-char' command now deletes by grapheme clusters. +This command is by default bound to the '<Delete>' function key +(a.k.a. '<deletechar>'). When invoked without a prefix argument or +with a positive prefix numeric argument, the command will now delete +complete grapheme clusters produced by character composition. For +example, if point is before an Emoji sequence, pressing '<Delete>' +will delete the entire sequence, not just a single character at its +beginning. + ++++ +** 'load-history' does not treat autoloads specially any more. +An autoload definition appears just as a '(defun . NAME)' and the +'(t . NAME)' entries are not generated any more. + +--- +** The Tamil input methods no longer insert Tamil digits. +The input methods 'tamil-itrans' and 'tamil-inscript' no longer insert +the Tamil digits, as those digit characters are not used nowadays by +speakers of the Tamil language. To get back the previous behavior, +use the new 'tamil-itrans-digits' and 'tamil-inscript-digits' input +methods instead. + ++++ +** New variable 'current-time-list' governing default timestamp form. +Functions like 'current-time' now yield '(TICKS . HZ)' timestamps if +this new variable is nil. The variable defaults to t, which means +these functions default to timestamps of the forms '(HI LO US PS)', +'(HI LO US)' or '(HI LO)', which are less regular and less efficient. +This is part of a long-planned change first documented in Emacs 27. +Developers are encouraged to test timestamp-related code with this +variable set to nil, as it will default to nil in a future Emacs +version and will be removed some time after that. + ++++ +** Functions that recreate the "*scratch*" buffer now also initialize it. +When functions like 'other-buffer' and 'server-execute' recreate +"*scratch*", they now also insert 'initial-scratch-message' and set +the major mode according to 'initial-major-mode', like at Emacs +startup. Previously, these functions ignored +'initial-scratch-message' and left "*scratch*" in 'fundamental-mode'. + +--- +** Naming of Image-Dired thumbnail files has changed. +Names of thumbnail files generated when 'image-dired-thumbnail-storage' +is 'image-dired' now always end in ".jpg". This fixes various issues +on different platforms, but means that thumbnails generated in Emacs 28 +will not be used in Emacs 29, and vice-versa. If disk space is an +issue, consider deleting the 'image-dired-dir' directory (usually +"~/.emacs.d/image-dired/") after upgrading to Emacs 29. + +--- +** The 'rlogin' method in the URL library is now obsolete. +Emacs will now display a warning if you request a URL like +"rlogin://foo@example.org". + +--- +** Setting 'url-gateway-method' to 'rlogin' is now obsolete. +Emacs will now display a warning when setting it to that value. +The user options 'url-gateway-rlogin-host', +'url-gateway-rlogin-parameters', and 'url-gateway-rlogin-user-name' +are also obsolete. + +--- +** The user function 'url-irc-function' now takes a SCHEME argument. +The user option 'url-irc-function' is now called with a sixth argument +corresponding to the scheme portion of the target URL. For example, +this would be "ircs" for a URL like "ircs://irc.libera.chat". + +--- +** The linum.el library is now obsolete. +We recommend using either the built-in 'display-line-numbers-mode', or +the 'nlinum' package from GNU ELPA instead. The former has better +performance, but the latter is closer to a drop-in replacement. + +1. To use 'display-line-numbers-mode', add something like this to your + Init file: + + (global-display-line-numbers-mode 1) + ;; Alternatively, to use it only in programming modes: + (add-hook 'prog-mode-hook #'display-line-numbers-mode) + +2. To use 'nlinum', add this to your Init file: + + (package-install 'nlinum) + (global-nlinum-mode 1) + ;; Alternatively, to use it only in programming modes: + (add-hook 'prog-mode-hook #'nlinum-mode) + +3. To continue using the obsolete package 'linum', add this line to + your Init file, in addition to any existing customizations: + + (require 'linum) + +--- +** The thumbs.el library is now obsolete. +We recommend using command 'image-dired' instead. + +--- +** The autoarg.el library is now marked obsolete. +This library provides the 'autoarg-mode' and 'autoarg-kp-mode' minor +modes to emulate the behavior of the historical editor Twenex Emacs. +We believe it is no longer useful. + +--- +** The quickurl.el library is now obsolete. +Use 'abbrev', 'skeleton' or 'tempo' instead. + +--- +** The rlogin.el library, and the 'rsh' command are now obsolete. +Use something like 'M-x shell RET ssh <host> RET' instead. + +--- +** The url-about.el library is now obsolete. + +--- +** The autoload.el library is now obsolete. +It is superseded by the new loaddefs-gen.el library. + +--- +** The netrc.el library is now obsolete. +Use the 'auth-source-netrc-parse-all' function in auth-source.el +instead. + +--- +** The url-dired.el library is now obsolete. + +--- +** The fast-lock.el and lazy-lock.el libraries have been removed. +They have been obsolete since Emacs 22.1. + +The variable 'font-lock-support-mode' is occasionally useful for +debugging purposes. It is now a regular variable (instead of a user +option) and can be set to nil to disable Just-in-time Lock mode. + + +* Changes in Emacs 29.1 + ++++ +** New user option 'major-mode-remap-alist' to specify favorite major modes. +This user option lets you remap the default modes (e.g. 'perl-mode' or +'latex-mode') to your favorite ones (e.g. 'cperl-mode' or +'LaTeX-mode') without having to use 'defalias', which can have +undesirable side effects. +This applies to all modes specified via 'auto-mode-alist', file-local +variables, etc. + +--- +** Emacs now supports Unicode Standard version 15.0. + +--- +** New user option 'electric-quote-replace-consecutive'. + +--- +** Emacs is now capable of editing files with very long lines. +The display of long lines has been optimized, and Emacs should no +longer choke when a buffer on display contains long lines. The +variable 'long-line-threshold' controls whether and when these display +optimizations are in effect. + +A companion variable 'large-hscroll-threshold' controls when another +set of display optimizations are in effect, which are aimed +specifically at speeding up display of long lines that are truncated +on display. + +If you still experience slowdowns while editing files with long lines, +this may be due to line truncation, or to one of the enabled minor +modes, or to the current major mode. Try turning off line truncation +with 'C-x x t', or try disabling all known slow minor modes with +'M-x so-long-minor-mode', or try disabling both known slow minor modes +and the major mode with 'M-x so-long-mode', or visit the file with +'M-x find-file-literally' instead of the usual 'C-x C-f'. + +Note that the display optimizations in these cases may cause the +buffer to be occasionally mis-fontified. + +The new function 'long-line-optimizations-p' returns non-nil when +these optimizations are in effect in the current buffer. + ++++ +** New command to change the font size globally. +To increase the font size, type 'C-x C-M-+' or 'C-x C-M-='; to +decrease it, type 'C-x C-M--'; to restore the font size, type 'C-x +C-M-0'. The final key in these commands may be repeated without the +leading 'C-x' and without the modifiers, e.g. 'C-x C-M-+ C-M-+ C-M-+' +and 'C-x C-M-+ + +' increase the font size by three steps. When +'mouse-wheel-mode' is enabled, 'C-M-wheel-up' and 'C-M-wheel-down' also +increase and decrease the font size globally. Additionally, the +user option 'global-text-scale-adjust-resizes-frames' controls whether +the frames are resized when the font size is changed. + +--- +** New config variable 'syntax-wholeline-max' to reduce the cost of long lines. +This variable is used by some operations (mostly syntax-propertization +and font-locking) to treat lines longer than this variable as if they +were made up of various smaller lines. This can help reduce the +slowdowns seen in buffers made of a single long line, but can also +cause misbehavior in the presence of such long lines (though most of +that misbehavior should usually be limited to mis-highlighting). You +can recover the previous behavior with: + + (setq syntax-wholeline-max most-positive-fixnum) + +--- +** New bindings in 'find-function-setup-keys' for 'find-library'. +When 'find-function-setup-keys' is enabled, 'C-x L' is now bound to +'find-library', 'C-x 4 L' is now bound to 'find-library-other-window' +and 'C-x 5 L' is now bound to 'find-library-other-frame'. + ++++ +** New key binding after 'M-x' or 'M-X': 'M-X'. +Emacs allows different completion predicates to be used with 'M-x' +(i.e., 'execute-extended-command') via the +'read-extended-command-predicate' user option. Emacs also has the +'M-X' (note upper case X) command, which only displays commands +especially relevant to the current buffer. Emacs now allows toggling +between these modes while the user is inputting a command by hitting +'M-X' while in the minibuffer. + +--- +** Interactively, 'kill-buffer' will now offer to save the buffer if unsaved. + +--- +** New commands 'duplicate-line' and 'duplicate-dwim'. +'duplicate-line' duplicates the current line the specified number of times. +'duplicate-dwim' duplicates the region if it is active. If not, it +works like 'duplicate-line'. An active rectangular region is +duplicated on its right-hand side. + +--- +** Files with the ".eld" extension are now visited in 'lisp-data-mode'. + ++++ +** 'network-lookup-address-info' can now check numeric IP address validity. +Specifying 'numeric' as the new optional HINTS argument makes it +check if the passed address is a valid IPv4/IPv6 address (without DNS +traffic). + + (network-lookup-address-info "127.1" 'ipv4 'numeric) + => ([127 0 0 1 0]) + ++++ +** New command 'find-sibling-file'. +This command jumps to a file considered a "sibling file", which is +determined according to the new user option 'find-sibling-rules'. + ++++ +** New user option 'delete-selection-temporary-region'. +When non-nil, 'delete-selection-mode' will only delete the temporary +regions (usually set by mouse-dragging or shift-selection). + ++++ +** New user option 'switch-to-prev-buffer-skip-regexp'. +This should be a regexp or a list of regexps; buffers whose names +match those regexps will be ignored by 'switch-to-prev-buffer' and +'switch-to-next-buffer'. + ++++ +** New command 'rename-visited-file'. +This command renames the file visited by the current buffer by moving +it to a new name or location, and also makes the buffer visit this new +file. + +** Menus + +--- +*** The entries following the buffers in the "Buffers" menu can now be altered. +Change the 'menu-bar-buffers-menu-command-entries' variable to alter +the entries that follow the buffer list. + +--- +** 'delete-process' is now a command. +When called interactively, it will kill the process running in the +current buffer (if any). This can be useful if you have runaway +output in the current buffer (from a process or a network connection), +and want to stop it. + ++++ +** New command 'restart-emacs'. +This is like 'save-buffers-kill-emacs', but instead of just killing +the current Emacs process at the end, it starts a new Emacs process +(using the same command line arguments as the running Emacs process). +'kill-emacs' and 'save-buffers-kill-emacs' have also gained new +optional arguments to restart instead of just killing the current +process. + +** Drag and Drop + ++++ +*** New user option 'mouse-drag-mode-line-buffer'. +If non-nil, dragging on the buffer name part of the mode-line will +drag the buffer's associated file to other programs. This option is +currently only available on X, Haiku and Nextstep (GNUstep or macOS). + ++++ +*** New user option 'mouse-drag-and-drop-region-cross-program'. +If non-nil, this option allows dragging text in the region from Emacs +to another program. + +--- +*** New user option 'mouse-drag-and-drop-region-scroll-margin'. +If non-nil, this option allows scrolling a window while dragging text +around without a scroll wheel. + ++++ +*** The value of 'mouse-drag-copy-region' can now be the symbol 'non-empty'. +This prevents mouse drag gestures from putting empty strings onto the +kill ring. + ++++ +*** New user options 'dnd-indicate-insertion-point' and 'dnd-scroll-margin'. +These options allow adjusting point and scrolling a window when +dragging items from another program. + ++++ +*** The X Direct Save (XDS) protocol is now supported. +This means dropping an image or file link from programs such as +Firefox will no longer create a temporary file in a random directory, +instead asking you where to save the file first. + ++++ +** New user option 'record-all-keys'. +If non-nil, this option will force recording of all input keys, +including those typed in response to passwords prompt (this was the +previous behavior). The default is nil, which inhibits recording of +passwords. + ++++ +** New function 'command-query'. +This function makes its argument command prompt the user for +confirmation before executing. + ++++ +** The 'disabled' property of a command's symbol can now be a list. +The first element of the list should be the symbol 'query', which will +cause the command disabled this way prompt the user with a y/n or a +yes/no question before executing. The new function 'command-query' is +a convenient method of making commands disabled in this way. + +--- +** 'count-words' will now report buffer totals if given a prefix. +Without a prefix, it will only report the word count for the narrowed +part of the buffer. + ++++ +** 'count-words' will now report sentence count when used interactively. + ++++ +** New user option 'set-message-functions'. +It allows selecting more functions for 'set-message-function' +in addition to the default function that handles messages +in the active minibuffer. The most useful are 'inhibit-message' +that allows specifying a list of messages to inhibit via +'inhibit-message-regexps', and 'set-multi-message' that +accumulates recent messages and displays them stacked +in the echo area. + +--- +** New user option 'find-library-include-other-files'. +If set to nil, commands like 'find-library' will only include library +files in the completion candidates. The default is t, which preserves +previous behavior, whereby non-library files could also be included. + ++++ +** New command 'sqlite-mode-open-file' for examining an sqlite3 file. +This uses the new 'sqlite-mode' which allows listing the tables in a +DB file, and examining and modifying the columns and the contents of +those tables. + +--- +** 'write-file' will now copy some file mode bits. +If the current buffer is visiting a file that is executable, the +'C-x C-w' command will now make the new file executable, too. + ++++ +** New user option 'process-error-pause-time'. +This determines how long to pause Emacs after a process +filter/sentinel error has been handled. + ++++ +** New faces for font-lock. +These faces are primarily meant for use with tree-sitter. They are: +'font-lock-bracket-face', 'font-lock-delimiter-face', +'font-lock-escape-face', 'font-lock-misc-punctuation-face', +'font-lock-number-face', 'font-lock-operator-face', +'font-lock-property-face', and 'font-lock-punctuation-face', +'font-lock-regexp-face'. + ++++ +** New face 'variable-pitch-text'. +This face is like 'variable-pitch' (from which it inherits), but is +slightly larger, which should help with the visual size differences +between the default, non-proportional font and proportional fonts when +mixed. + ++++ +** New face 'mode-line-active'. +This inherits from the 'mode-line' face, but is the face actually used +on the mode lines (along with 'mode-line-inactive'). + ++++ +** New face attribute pseudo-value 'reset'. +This value stands for the value of the corresponding attribute of the +'default' face. It can be used to reset attribute values produced by +inheriting from other faces. + ++++ +** New X resource: "borderThickness". +This controls the thickness of the external borders of the menu bars +and pop-up menus. + ++++ +** New X resource: "inputStyle". +This controls the style of the pre-edit and status areas of X input +methods. + ++++ +** New X resources: "highlightForeground" and "highlightBackground". +Only in the Lucid build, this controls colors used for highlighted +menu item widgets. + ++++ +** On X, Emacs now tries to synchronize window resize with the window manager. +This leads to less flicker and empty areas of a frame being displayed +when a frame is being resized. Unfortunately, it does not work on +some ancient buggy window managers, so if Emacs appears to freeze, but +is still responsive to input, you can turn it off by setting the X +resource "synchronizeResize" to "off". + ++++ +** On X, Emacs can optionally synchronize display with the graphics hardware. +When this is enabled by setting the X resource "synchronizeResize" to +"extended", frame content "tearing" is drastically reduced. This is +only supported on the Motif, Lucid, and no-toolkit builds, and +requires an X compositing manager supporting the extended frame +synchronization protocol (see +https://fishsoup.net/misc/wm-spec-synchronization.html). + +This behavior can be toggled on and off via the frame parameter +'use-frame-synchronization'. + ++++ +** New frame parameter 'alpha-background' and X resource "alphaBackground". +This controls the opacity of the text background when running on a +composited display. + ++++ +** New frame parameter 'shaded'. +With window managers which support this, it controls whether or not a +frame's contents will be hidden, leaving only the title bar on display. + +--- +** New user option 'x-gtk-use-native-input'. +This controls whether or not GTK input methods are used by Emacs, +instead of XIM input methods. + ++++ +** New user option 'use-system-tooltips'. +This controls whether to use the toolkit tooltips, or Emacs's own +native implementation of tooltips as small frames. This option is +only meaningful if Emacs was built with GTK+, Nextstep, or Haiku +support, and defaults to t, which makes Emacs use the toolkit +tooltips. The existing GTK-specific option +'x-gtk-use-system-tooltips' is now an alias of this new option. + ++++ +** Non-native tooltips are now supported on Nextstep. +This means Emacs built with GNUstep or built on macOS is now able to +display different faces and images inside tooltips when the +'use-system-tooltips' user option is nil. + +--- +** New minor mode 'pixel-scroll-precision-mode'. +When enabled, and if your mouse supports it, you can scroll the +display up or down at pixel resolution, according to what your mouse +wheel reports. Unlike 'pixel-scroll-mode', this mode scrolls the +display pixel-by-pixel, as opposed to only animating line-by-line +scrolls. + +** Terminal Emacs + +--- +*** Emacs will now use 24-bit colors on terminals that support "Tc" capability. +This is in addition to previously-supported ways of discovering 24-bit +color support: either via the "RGB" or "setf24" capabilities, or if +the 'COLORTERM' environment variable is set to the value "truecolor". + +--- +*** Select active regions with xterm selection support. +On terminals with xterm "setSelection" support, the active region may be +saved to the X primary selection, following the +'select-active-regions' variable. This support is enabled when +'tty-select-active-regions' is non-nil. + +--- +*** New command to set up display of unsupported characters. +The new command 'standard-display-by-replacement-char' produces Lisp +code that sets up the 'standard-display-table' to use a replacement +character for display of characters that the text-mode terminal +doesn't support. This code is intended to be used in your init files. +This feature is most useful with the Linux console and similar +terminals, where Emacs has a reliable way of determining which +characters have glyphs in the font loaded into the terminal's memory. + +--- +*** New functions to set terminal output buffer size. +The new functions 'tty--set-output-buffer-size' and +'tty--output-buffer-size' allow setting and retrieving the output +buffer size of a terminal device. The default buffer size is and has +always been BUFSIZ, which is defined in your system's stdio.h. When +you set a buffer size with 'tty--set-output-buffer-size', this also +prevents Emacs from explicitly flushing the tty output stream, except +at the end of display update. + +** ERT + ++++ +*** New ERT variables 'ert-batch-print-length' and 'ert-batch-print-level'. +These variables will override 'print-length' and 'print-level' when +printing Lisp values in ERT batch test results. + +--- +*** Redefining an ERT test in batch mode now signals an error. +Executing 'ert-deftest' with the same name as an existing test causes +the previous definition to be discarded, which was probably not +intended when this occurs in batch mode. To remedy the error, rename +tests so that they all have unique names. + ++++ +*** ERT can generate JUnit test reports. +When environment variable 'EMACS_TEST_JUNIT_REPORT' is set, ERT +generates a JUnit test report under this file name. This is useful +for Emacs integration into CI/CD test environments. + +--- +*** Unbound test symbols now signal an 'ert-test-unbound' error. +This affects the 'ert-select-tests' function and its callers. + +** Emoji + ++++ +*** Emacs now has several new methods for inserting Emoji. +The Emoji commands are under the new 'C-x 8 e' prefix. + ++++ +*** New command 'emoji-insert' (bound to 'C-x 8 e e' and 'C-x 8 e i'). +This command guides you through various Emoji categories and +combinations in a graphical menu system. + ++++ +*** New command 'emoji-search' (bound to 'C-x 8 e s'). +This command lets you search for Emoji based on names. + ++++ +*** New command 'emoji-list' (bound to 'C-x 8 e l'). +This command lists all Emoji (categorized by themes) in a special +buffer and lets you choose one of them. + +--- +*** New command 'emoji-recent' (bound to 'C-x 8 e r'). +This command lets you choose among the Emoji you have recently +inserted. + ++++ +*** New command 'emoji-describe' (bound to 'C-x 8 e d'). +This command will tell you the name of the Emoji at point. (It also +works for non-Emoji characters.) + +--- +*** New commands 'emoji-zoom-increase' and 'emoji-zoom-decrease'. +These are bound to 'C-x 8 e +' and 'C-x 8 e -', respectively. They +can be used on any character, but are mainly useful for Emoji. + +--- +*** New input method 'emoji'. +This allows you to enter Emoji using short strings, eg ':face_palm:' +or ':scream:'. + +** Help + +--- +*** Variable values displayed by 'C-h v' in "*Help*" are now fontified. + ++++ +*** New user option 'help-clean-buttons'. +If non-nil, link buttons in "*Help*" buffers will have any surrounding +quotes removed. + +--- +*** 'M-x apropos-variable' output now includes values of variables. +Such apropos buffer is more easily viewed with outlining after +enabling 'outline-minor-mode' in 'apropos-mode'. + ++++ +*** New docstring syntax to indicate that symbols shouldn't be links. +When displaying docstrings in "*Help*" buffers, strings that are +"`like-this'" are made into links (if they point to a bound +function/variable). This can lead to false positives when talking +about values that are symbols that happen to have the same names as +functions/variables. To inhibit this buttonification, use the new +"\\+`like-this'" syntax. + ++++ +*** New user option 'help-window-keep-selected'. +If non-nil, commands to show the info manual and the source will reuse +the same window in which the "*Help*" buffer is shown. + +--- +*** Commands like 'C-h f' have changed how they describe menu bindings. +For instance, previously a command might be described as having the +following bindings: + + It is bound to <open>, C-x C-f, <menu-bar> <file> <new-file>. + +This has been changed to: + + It is bound to <open> and C-x C-f. + It can also be invoked from the menu: File → Visit New File... + ++++ +*** The 'C-h .' command now accepts a prefix argument. +'C-u C-h .' would previously inhibit displaying a warning message if +there's no local help at point. This has been changed to call +'button-describe'/'widget-describe' and display button/widget help +instead. + +--- +*** New user option 'help-enable-variable-value-editing'. +If enabled, 'e' on a value in "*Help*" will pop you to a new buffer +where you can edit the value. This is not enabled by default, because +it is easy to make an edit that yields an invalid result. + +--- +*** 'C-h b' uses outlining by default. +Set 'describe-bindings-outline' to nil to get back the old behavior. + +--- +*** Jumping to function/variable source now saves mark before moving point. +Jumping to source from a "*Help*" buffer moves point when the source +buffer is already open. Now, the old point is pushed onto mark ring. + ++++ +*** New key bindings in "*Help*" buffers: 'n' and 'p'. +These will take you (respectively) to the next and previous "page". + +--- +*** 'describe-char' now also outputs the name of Emoji sequences. + ++++ +*** New key binding in "*Help*" buffer: 'I'. +This will take you to the Emacs Lisp manual entry for the item +displayed, if any. + +--- +*** The 'C-h m' ('describe-mode') "*Help*" buffer has been reformatted. +It now only includes local minor modes at the start, and the global +minor modes are listed after the major mode. + ++++ +*** The user option 'help-window-select' now affects apropos commands. +The apropos commands will now select the apropos window if +'help-window-select' is non-nil. + +--- +*** 'describe-keymap' now considers the symbol at point. +If the symbol at point is a keymap, 'describe-keymap' suggests it as +the default candidate. + +--- +*** New command 'help-quick' displays an overview of common commands. +The command pops up a buffer at the bottom of the screen with a few +helpful commands for various tasks. You can toggle the display using +'C-h C-q'. + +** Emacs now comes with Org v9.6. +See the file "ORG-NEWS" for user-visible changes in Org. + +** Outline Mode + ++++ +*** Support for customizing the default visibility state of headings. +Customize the user option 'outline-default-state' to define what +headings will be visible initially, after Outline mode is turned on. +When the value is a number, the user option 'outline-default-rules' +determines the visibility of the subtree starting at the corresponding +level. Values are provided to control showing a heading subtree +depending on whether the heading matches a regexp, or on whether its +subtree has long lines or is itself too long. + +** Outline Minor Mode + ++++ +*** New user option 'outline-minor-mode-use-buttons'. +If non-nil, Outline Minor Mode will use buttons to hide/show outlines +in addition to the ellipsis. The default is nil, but in 'help-mode' +it has the value 'insert' that inserts the buttons directly into the +buffer, and you can use 'RET' to cycle outline visibility. When +the value is 'in-margins', Outline Minor Mode uses the window margins +for buttons that hide/show outlines. + ++++ +*** Buttons and headings now have their own keymaps. +'outline-button-icon-map', 'outline-overlay-button-map', and +'outline-inserted-button-map' are now available as defined keymaps +instead of being anonymous keymaps. + +** Windows + ++++ +*** New commands 'split-root-window-below' and 'split-root-window-right'. +These commands split the root window in two, and are bound to 'C-x w 2' +and 'C-x w 3', respectively. A number of other useful window-related +commands are now available with key sequences that start with the +'C-x w' prefix. + ++++ +*** New user option 'display-buffer-avoid-small-windows'. +If non-nil, this should be a window height in lines, a number. +Windows smaller than this will be avoided by 'display-buffer', if +possible. + ++++ +*** New display action 'display-buffer-full-frame'. +This action removes other windows from the frame when displaying a +buffer on that frame. + ++++ +*** 'display-buffer' now can set up the body size of the chosen window. +For example, a 'display-buffer-alist' entry of + + (window-width . (body-columns . 40)) + +will make the body of the chosen window 40 columns wide. For the +height use 'window-height' and 'body-lines', respectively. + +--- +*** You can customize on which window 'scroll-other-window' operates. +This is controlled by the new 'other-window-scroll-default' variable. + +** Frames + ++++ +*** 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 + +--- +*** New user option 'tab-bar-auto-width' to automatically determine tab width. +This option is non-nil by default, which resizes tab-bar tabs so that +their width is evenly distributed across the tab bar. A companion +option 'tab-bar-auto-width-max' controls the maximum width of a tab +before its name on display is truncated. + +--- +*** 'C-x t RET' creates a new tab when the provided tab name doesn't exist. +It prompts for the name of a tab and switches to it, creating a new +tab if no tab exists by that name. + +--- +*** New keymap 'tab-bar-history-mode-map'. +By default, it contains 'C-c <left>' and 'C-c <right>' to browse +the history of tab window configurations back and forward. + +--- +** Better detection of text suspiciously reordered on display. +The function 'bidi-find-overridden-directionality' has been extended +to detect reordering effects produced by embeddings and isolates +(started by directional formatting control characters such as RLO and +LRI). The new command 'highlight-confusing-reorderings' finds and +highlights segments of buffer text whose reordering for display is +suspicious and could be malicious. + +** Emacs Server and Client + ++++ +*** New command-line option '-r'/'--reuse-frame' for emacsclient. +With this command-line option, Emacs reuses an existing graphical client +frame if one exists; otherwise it creates a new frame. + ++++ +*** New command-line option '-w N'/'--timeout=N' for emacsclient. +With this command-line option, emacsclient will exit if Emacs does not +respond within N seconds. The default is to wait forever. + ++++ +*** 'server-stop-automatically' can be used to automatically stop the server. +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'. + ++++ +*** New user option 'rcirc-cycle-completion-flag'. +Rcirc will use the default 'completion-at-point' mechanism. The +conventional IRC behavior of completing by cycling through the +available options can be restored by enabling this option. + ++++ +*** New user option 'rcirc-bridge-bot-alist'. +If you are in a channel where a bot is responsible for bridging +between networks, you can use this variable to make these messages +appear more native. For example, you might set the option to: + + (setopt rcirc-bridge-bot-alist '(("bridge" . "{\\(.+?\\)}[[:space:]]+"))) + +for messages like + + 09:47 <bridge> {john} I am not on IRC + +to be reformatted into + + 09:47 <john> I am not on IRC + +--- +*** New formatting commands. +Most IRC clients (including rcirc) support basic formatting using +control codes. Under the 'C-c C-f' prefix a few commands have been +added to insert these automatically. For example, if a region is +active and 'C-c C-f C-b' is invoked, markup is inserted for the region +to be highlighted in bold. + +** Imenu + ++++ +*** 'imenu' is now bound to 'M-g i' globally. + +--- +*** New function 'imenu-flush-cache'. +Use it if you want Imenu to forget the buffer's index alist and +recreate it anew next time 'imenu' is invoked. + +--- +** Emacs is now capable of abandoning a window's redisplay that takes too long. +This is controlled by the new variable 'max-redisplay-ticks'. If that +variable is set to a non-zero value, display of a window will be +aborted after that many low-level redisplay operations, thus +preventing Emacs from becoming wedged when visiting files with very +long lines. The default is zero, which disables the feature: Emacs +will wait forever for redisplay to finish. (We believe you won't need +this feature, given the ability to display buffers with very long +lines.) + + +* Editing Changes in Emacs 29.1 + ++++ +** 'M-SPC' is now bound to 'cycle-spacing'. +Formerly it invoked 'just-one-space'. The actions performed by +'cycle-spacing' and their order can now be customized via the user +option 'cycle-spacing-actions'. + +--- +** 'zap-to-char' and 'zap-up-to-char' are case-sensitive for upper-case chars. +These commands now behave as case-sensitive for interactive calls when +they are invoked with an uppercase character, regardless of the value +of 'case-fold-search'. + +--- +** 'scroll-other-window' and 'scroll-other-window-down' now respect remapping. +These commands (bound to 'C-M-v' and 'C-M-V') used to scroll the other +windows without looking at customizations in that other window. These +functions now check whether they have been rebound in the buffer shown +in that other window, and then call the remapped function instead. In +addition, these commands now also respect the +'scroll-error-top-bottom' user option. + +--- +** Indentation of 'cl-flet' and 'cl-labels' has changed. +These forms now indent like this: + + (cl-flet ((bla (x) + (* x x))) + (bla 42)) + +This change also affects 'cl-macrolet', 'cl-flet*' and +'cl-symbol-macrolet'. + ++++ +** New user option 'translate-upper-case-key-bindings'. +Set this option to nil to inhibit the default translation of upper +case keys to their lower case variants. + ++++ +** New command 'ensure-empty-lines'. +This command increases (or decreases) the number of empty lines before +point. + +--- +** Improved mouse behavior with auto-scrolling modes. +When clicking inside the 'scroll-margin' or 'hscroll-margin' region, +point is now moved only when releasing the mouse button. This no +longer results in a bogus selection, unless the mouse has also been +dragged. + ++++ +** 'kill-ring-max' now defaults to 120. + +--- +** New user option 'yank-menu-max-items'. +Customize this option to limit the number of entries in the menu +"Edit → Paste from Kill Menu". The default is 60. + ++++ +** Performing a pinch gesture on a touchpad now increases the text scale. + +** Show Paren Mode + ++++ +*** New user option 'show-paren-context-when-offscreen'. +When non-nil, if the point is in a closing delimiter and the opening +delimiter is offscreen, shows some context around the opening +delimiter in the echo area. The default is nil. + +This option can also be set to the symbols 'overlay' or 'child-frame', +in which case the context is shown in an overlay or child-frame at the +top-left of the current window. The latter option requires a +graphical frame. On non-graphical frames, the context is shown in the +echo area. + +** Comint + ++++ +*** 'comint-term-environment' is now aware of connection-local variables. +The user option 'comint-terminfo-terminal' and the variable +'system-uses-terminfo' can now be set as connection-local variables to +change the terminal used on a remote host. + +--- +*** New user option 'comint-delete-old-input'. +When nil, this prevents comint from deleting the current input when +inserting previous input using '<mouse-2>'. The default is t, to +preserve previous behavior. + +--- +*** New minor mode 'comint-fontify-input-mode'. +This minor mode is enabled by default in "*shell*" and "*ielm*" +buffers. It fontifies input text according to 'shell-mode' or +'emacs-lisp-mode' font-lock rules. Customize the user options +'shell-fontify-input-enable' and 'ielm-fontify-input-enable' to nil if +you don't want to enable input fontification by default. + +** Mwheel + +--- +*** New user options for alternate wheel events. +The user options 'mouse-wheel-down-alternate-event' and +'mouse-wheel-up-alternate-event' as well as the variables +'mouse-wheel-left-alternate-event' and +'mouse-wheel-right-alternate-event' have been added to better support +systems where two kinds of wheel events can be received. + +** Internationalization + +--- +*** The '<Delete>' function key now allows deleting the entire composed sequence. +For the details, see the item about the 'delete-forward-char' command +above. + +--- +*** New user option 'composition-break-at-point'. +Setting it to a non-nil value temporarily disables automatic +composition of character sequences at point, and thus makes it easier +to edit such sequences by allowing point to "enter" the composed +sequence. + +--- +*** Support for many old scripts and writing systems. +Emacs now supports, and has language-environments and input methods, +for several dozens of old scripts that were used in the past for +various languages. For each such script Emacs now has font-selection +and character composition rules, a language environment, and an input +method. The newly-added scripts and the corresponding language +environments are: + + Tai Tham script and the Northern Thai language environment + + Brahmi script and language environment + + Kaithi script and language environment + + Tirhuta script and language environment + + Sharada script and language environment + + Siddham script and language environment + + Syloti Nagri script and language environment + + Modi script and language environment + + Baybayin script and Tagalog language environment + + Hanunoo script and language environment + + Buhid script and language environment + + Tagbanwa script and language environment + + Limbu script and language environment + + Balinese script and language environment + + Javanese script and language environment + + Sundanese script and language environment + + Batak script and language environment + + Rejang script and language environment + + Makasar script and language environment + + Lontara script and language environment + + Hanifi Rohingya script and language environment + + Grantha script and language environment + + Kharoshthi script and language environment + + Lepcha script and language environment + + Meetei Mayek script and language environment + + Adlam script and language environment + + Mende Kikakui script and language environment + + Wancho script and language environment + + Toto script and language environment + + Gothic script and language environment + + Coptic script and language environment + +--- +*** The "Oriya" language environment was renamed to "Odia". +This is to follow the change in the official name of the script. The +'oriya' input method was also renamed to 'odia'. However, the old +name of the language environment and the input method are still +supported. + +--- +*** New Greek translation of the Emacs tutorial. +Type 'C-u C-h t' to select it in case your language setup does not do +so automatically. + +--- +*** New Ukrainian translation of the Emacs Tutorial. + +--- +*** New default phonetic input method for the Tamil language environment. +The default input method for the Tamil language environment is now +"tamil-phonetic" which is a customizable phonetic input method. To +change the input method's translation rules, customize the user option +'tamil-translation-rules'. + +--- +*** New 'tamil99' input method for the Tamil language. +This supports the keyboard layout specifically designed for the Tamil +language. + +--- +*** New input method 'slovak-qwerty'. +This is a variant of the 'slovak' input method, which corresponds to +the QWERTY Slovak keyboards. + +--- +*** New input method 'cyrillic-chuvash'. +This input method is based on the russian-computer input method, and +is intended for typing in the Chuvash language written in the Cyrillic +script. + + +* Changes in Specialized Modes and Packages in Emacs 29.1 + +** Ecomplete + +--- +*** New commands 'ecomplete-edit' and 'ecomplete-remove'. +These allow you to (respectively) edit and bulk-remove entries from +the ecomplete database. + +--- +*** New user option 'ecomplete-auto-select'. +If non-nil and there's only one matching option, auto-select that. + +--- +*** New user option 'ecomplete-filter-regexp'. +If non-nil, this user option describes what entries not to add to the +database stored on disk. + +** Auth Source + ++++ +*** New user option 'auth-source-pass-extra-query-keywords'. +Whether to recognize additional keyword params, like ':max' and +':require', as well as accept lists of query terms paired with +applicable keywords. This disables most known behavioral quirks +unique to auth-source-pass, such as wildcard subdomain matching. + +** Dired + ++++ +*** 'dired-guess-shell-command' moved from dired-x to dired. +This means that 'dired-do-shell-command' will now provide smarter +defaults without first having to require 'dired-x'. See the node +"(emacs) Shell Command Guessing" in the Emacs manual for more details. + +--- +*** 'dired-clean-up-buffers-too' moved from dired-x to dired. +This means that Dired now offers to kill buffers visiting files and +dirs when they are deleted in Dired. Before, you had to require +'dired-x' to enable this behavior. To disable this behavior, +customize the user option 'dired-clean-up-buffers-too' to nil. The +related user option 'dired-clean-confirm-killing-deleted-buffers' +(which see) has also been moved to 'dired'. + ++++ +*** 'dired-do-relsymlink' moved from dired-x to dired. +The corresponding key 'Y' is now bound by default in Dired. + ++++ +*** 'dired-do-relsymlink-regexp' moved from dired-x to dired. +The corresponding key sequence '% Y' is now bound by default in Dired. + +--- +*** 'M-G' is now bound to 'dired-goto-subdir'. +Before, that binding was only available if the dired-x package was +loaded. + ++++ +*** 'dired-info' and 'dired-man' moved from dired-x to dired. +The 'dired-info' and 'dired-man' commands have been moved from the +dired-x package to dired. They have also been renamed to +'dired-do-info' and 'dired-do-man'; the old command names are obsolete +aliases. + +The keys 'I' ('dired-do-info') and 'N' ('dired-do-man') are now bound +in Dired mode by default. The user options 'dired-bind-man' and +'dired-bind-info' no longer have any effect and are obsolete. + +To get the old behavior back and unbind these keys in Dired mode, add +the following to your Init file: + + (with-eval-after-load 'dired + (keymap-set dired-mode-map "N" nil) + (keymap-set dired-mode-map "I" nil)) + +--- +*** New command 'dired-do-eww'. +This command visits the file on the current line with EWW. + +--- +*** New user option 'dired-omit-lines'. +This is used by 'dired-omit-mode', and now allows you to hide based on +other things than just the file names. + ++++ +*** New user option 'dired-mouse-drag-files'. +If non-nil, dragging file names with the mouse in a Dired buffer will +initiate a drag-and-drop session allowing them to be opened in other +programs. + ++++ +*** New user option 'dired-free-space'. +Dired will now, by default, include the free space in the first line +instead of having it on a separate line. To get the previous behavior +back, say: + + (setopt dired-free-space 'separate) + +--- +*** New user option 'dired-make-directory-clickable'. +If non-nil (which is the default), hitting 'RET' or 'mouse-1' on +the directory components at the directory displayed at the start of +the buffer will take you to that directory. + +--- +*** Search and replace in Dired/Wdired supports more regexps. +For example, the regexp ".*" will match only characters that are part +of the file name. Also "^.*$" can be used to match at the beginning +of the file name and at the end of the file name. This is used only +when searching on file names. In Wdired this can be used when the new +user option 'wdired-search-replace-filenames' is non-nil (which is the +default). + +** Elisp + +--- +*** New command 'elisp-eval-region-or-buffer' (bound to 'C-c C-e'). +This command evals the forms in the active region or in the whole buffer. + +--- +*** New commands 'elisp-byte-compile-file' and 'elisp-byte-compile-buffer'. +These commands (bound to 'C-c C-f' and 'C-c C-b', respectively) +byte-compile the visited file and the current buffer, respectively. + +** Games + +--- +*** New user option 'tetris-allow-repetitions'. +This controls how randomness is implemented (whether to use pure +randomness as before, or to use a bag). + +** Battery + ++++ +*** New user option 'battery-update-functions'. +This can be used to trigger actions based on the battery status. + +** DocView + +--- +*** doc-view can now generate SVG images when viewing PDF files. +If Emacs is built with SVG support, doc-view can generate SVG files +when using MuPDF as the converter for PDF files, which generally leads +to sharper images (especially when zooming), and allows customization +of background and foreground color of the page via the new user +options 'doc-view-svg-background' and 'doc-view-svg-foreground'. To +activate this behavior, set 'doc-view-mupdf-use-svg' to non-nil if +your Emacs has SVG support. Note that, with some versions of MuPDF, +SVG generation is known to sometimes produce SVG files that are buggy +or can take a long time to render. + +** Enriched Mode + ++++ +*** New command 'enriched-toggle-markup'. +This allows you to see the markup in 'enriched-mode' buffers (e.g., +the "HELLO" file). + +** Shell Script Mode + +--- +*** New user option 'sh-indent-statement-after-and'. +This controls how statements like the following are indented: + + foo && + bar + +*** New Flymake backend using the ShellCheck program. +It is enabled by default, but requires that the external "shellcheck" +command is installed. + +** CC Mode + +--- +*** C++ Mode now supports most of the new features in the C++20 Standard. + +--- +*** In Objective-C Mode, no extra types are recognized by default. +The default value of 'objc-font-lock-extra-types' has been changed to +nil, since too many identifiers were getting misfontified as types. +This may cause some actual types not to get fontified. To get the old +behavior back, customize the user option to the value suggested in its +doc string. + +** Cperl Mode + +--- +*** New user option 'cperl-file-style'. +This option determines the indentation style to be used. It can also +be used as a file-local variable. + +** Gud + +--- +*** 'gud-go' is now bound to 'C-c C-v'. +If given a prefix, it will prompt for an argument to use for the +run/continue command. + +--- +*** 'perldb' now recognizes '-E'. +As of Perl 5.10, 'perl -E 0' behaves like 'perl -e 0' but also activates +all optional features of the Perl version in use. 'perldb' now uses +this invocation as its default. + +** Customize + +--- +*** New command 'custom-toggle-hide-all-widgets'. +This is bound to 'H' and toggles whether to hide or show the widget +contents. + +** Diff Mode + +--- +*** New user option 'diff-whitespace-style'. +Sets the value of the buffer-local variable 'whitespace-style' in +'diff-mode' buffers. By default, this variable is '(face trailing)', +which preserves behavior of previous Emacs versions. + ++++ +*** New user option 'diff-add-log-use-relative-names'. +If non-nil insert file names in ChangeLog skeletons relative to the +VC root directory. + +** Ispell + +--- +*** 'ispell-region' and 'ispell-buffer' now push the mark. +These commands push onto the mark ring the location of the last +misspelled word where corrections were offered, so that you can then +skip back to that location with 'C-x C-x'. + +** Dabbrev + +--- +*** New function 'dabbrev-capf' for use on 'completion-at-point-functions'. + ++++ +*** New user option 'dabbrev-ignored-buffer-modes'. +Buffers with major modes in this list will be ignored. By default, +this includes "binary" buffers like 'archive-mode' and 'image-mode'. + +** Package + ++++ +*** New command 'package-update'. +This command allows you to upgrade packages without using 'M-x +list-packages'. + ++++ +*** New command 'package-update-all'. +This command allows updating all packages without any queries. + ++++ +*** New commands 'package-recompile' and 'package-recompile-all'. +These commands can be useful if the ".elc" files are out of date +(invalid byte code and macros). + ++++ +*** New DWIM action on 'x' in "*Packages*" buffer. +If no packages are marked, 'x' will install the package under point if +it isn't already, and remove it if it is installed. + ++++ +*** New command 'package-vc-install'. +Packages can now be installed directly from source by cloning from +their repository. + ++++ +*** New command 'package-vc-install-from-checkout'. +An existing checkout can now be loaded via package.el, by creating a +symbolic link from the usual package directory to the checkout. + ++++ +*** New command 'package-vc-checkout'. +Used to fetch the source of a package by cloning a repository without +activating the package. + ++++ +*** New command 'package-vc-prepare-patch'. +This command allows you to send patches to package maintainers, for +packages checked out using 'package-vc-install'. + ++++ +*** New command 'package-report-bug'. +This command helps you compose an email for sending bug reports to +package maintainers. + ++++ +*** New user option 'package-vc-selected-packages'. +By customizing this user option you can specify specific packages to +install. + +** Emacs Sessions (Desktop) + ++++ +*** New user option to load a locked desktop if locking Emacs is not running. +The option 'desktop-load-locked-desktop' can now be set to the value +'check-pid', which means to allow loading a locked ".emacs.desktop" +file if the Emacs process which locked it is no longer running on the +local machine. This allows avoiding questions about locked desktop +files when the Emacs session which locked it crashes, or was otherwise +interrupted and didn't exit gracefully. See the "(emacs) Saving +Emacs Sessions" node in the Emacs manual for more details. + +** Miscellaneous + ++++ +*** New command 'scratch-buffer'. +This command switches to the "*scratch*" buffer. If "*scratch*" doesn't +exist, the command creates it first. You can use this command if you +inadvertently delete the "*scratch*" buffer. + +** Debugging + +--- +*** 'q' in a "*Backtrace*" buffer no longer clears the buffer. +Instead it just buries the buffer and switches the mode from +'debugger-mode' to 'backtrace-mode', since commands like 'e' are no +longer available after exiting the recursive edit. + ++++ +*** New user option 'debug-allow-recursive-debug'. +This user option controls whether the 'e' (in a "*Backtrace*" +buffer or while edebugging) and 'C-x C-e' (while edebugging) commands +lead to a (further) backtrace. By default, this variable is nil, +which is a change in behavior from previous Emacs versions. + ++++ +*** 'e' in edebug can now take a prefix arg to pretty-print the results. +When invoked with a prefix argument, as in 'C-u e', this command will +pop up a new buffer and show the full pretty-printed value there. + ++++ +*** 'C-x C-e' now interprets a non-zero prefix arg to pretty-print the results. +When invoked with a non-zero prefix argument, as in 'C-u C-x C-e', +this command will pop up a new buffer and show the full pretty-printed +value there. + ++++ +*** You can now generate a backtrace from Lisp errors in redisplay. +To do this, set the new variable 'backtrace-on-redisplay-error' to a +non-nil value. The backtrace will be written to a special buffer +named "*Redisplay-trace*". This buffer will not be automatically +displayed in a window. + +** Compile + ++++ +*** New user option 'compilation-hidden-output'. +This can be used to make specific parts of compilation output +invisible. + ++++ +*** The 'compilation-auto-jump-to-first-error' user option has been extended. +It can now have the additional values 'if-location-known' (which will +only jump if the location of the first error is known), and +'first-known' (which will jump to the first known error location). + ++++ +*** New user option 'compilation-max-output-line-length'. +Lines longer than the value of this option will have their ends +hidden, with a button to reveal the hidden text. This speeds up +operations like grepping on files that have few newlines. The default +value is 400; set to nil to disable hiding. + +** Flymake + ++++ +*** New user option 'flymake-mode-line-lighter'. + ++++ +** New minor mode 'word-wrap-whitespace-mode' for extending 'word-wrap'. +This mode switches 'word-wrap' on, and breaks on all the whitespace +characters instead of just 'SPC' and 'TAB'. + +--- +** New mode, 'emacs-news-mode', for editing the NEWS file. +This mode adds some highlighting, makes the 'M-q' command aware of the +format of NEWS entries, and has special commands for doing maintenance +of the Emacs NEWS files. In addition, this mode turns on +'outline-minor-mode', and thus displays customizable icons (see +'icon-preference') in the margins. To disable these icons, set +'outline-minor-mode-use-buttons' to a nil value. + +--- +** Kmacro +Kmacros are now OClosures and have a new constructor 'kmacro' which +uses the 'key-parse' syntax. It replaces the old 'kmacro-lambda-form' +(which is now declared obsolete). + +--- +** savehist.el can now truncate variables that are too long. +An element of user option 'savehist-additional-variables' can now be +of the form '(VARIABLE . MAX-ELTS)', which means to truncate the +VARIABLE's value to at most MAX-ELTS elements (if the value is a list) +before saving the value. + +** Minibuffer and Completions + ++++ +*** New commands for navigating completions from the minibuffer. +When the minibuffer is the current buffer, typing 'M-<up>' or +'M-<down>' selects a previous/next completion candidate from the +"*Completions*" buffer and inserts it to the minibuffer. +When the user option 'minibuffer-completion-auto-choose' is nil, +'M-<up>' and 'M-<down>' do the same, but without inserting +a completion candidate to the minibuffer, then 'M-RET' can be used +to choose the currently active candidate from the "*Completions*" +buffer and exit the minibuffer. With a prefix argument, 'C-u M-RET' +inserts the currently active candidate to the minibuffer, but doesn't +exit the minibuffer. These keys are also available for in-buffer +completion, but they don't insert candidates automatically, you need +to type 'M-RET' to insert the selected candidate to the buffer. + ++++ +*** Choosing a completion with a prefix argument doesn't exit the minibuffer. +This means that typing 'C-u RET' on a completion candidate in the +"*Completions*" buffer inserts the completion into the minibuffer, +but doesn't exit the minibuffer. + ++++ +*** The "*Completions*" buffer can now be automatically selected. +To enable this behavior, customize the user option +'completion-auto-select' to t, then pressing 'TAB' will switch to the +"*Completions*" buffer when it pops up that buffer. If the value is +'second-tab', then the first 'TAB' will display "*Completions*", and +the second one will switch to the "*Completions*" buffer. + +--- +*** New user option 'completion-auto-wrap'. +When non-nil, the commands 'next-completion' and 'previous-completion' +automatically wrap around on reaching the beginning or the end of +the "*Completions*" buffer. + ++++ +*** New values for the 'completion-auto-help' user option. +There are two new values to control the way the "*Completions*" buffer +behaves after pressing a 'TAB' if completion is not unique. The value +'always' updates or shows the "*Completions*" buffer after any attempt +to complete. The value 'visual' is like 'always', but only updates +the completions if they are already visible. The default value t +always hides the completion buffer after some completion is made. + +--- +*** New commands to complete the minibuffer history. +'minibuffer-complete-history' ('C-x <up>') is like 'minibuffer-complete' +but completes on the history items instead of the default completion +table. 'minibuffer-complete-defaults' ('C-x <down>') completes +on the list of default items. + ++++ +*** User option 'minibuffer-eldef-shorten-default' is now obsolete. +Customize the user option 'minibuffer-default-prompt-format' instead. + ++++ +*** New user option 'completions-sort'. +This option controls the sorting of the completion candidates in +the "*Completions*" buffer. Available styles are no sorting, +alphabetical (the default), or a custom sort function. + ++++ +*** New user option 'completions-max-height'. +This option limits the height of the "*Completions*" buffer. + ++++ +*** New user option 'completions-header-format'. +This is a string to control the header line to show in the +"*Completions*" buffer before the list of completions. +If it contains "%s", that is replaced with the number of completions. +If nil, the header line is not shown. + ++++ +*** New user option 'completions-highlight-face'. +When this user option names a face, the current +candidate in the "*Completions*" buffer is highlighted with that face. +The nil value disables this highlighting. The default is to highlight +using the 'completions-highlight' face. + ++++ +*** You can now define abbrevs for the minibuffer modes. +'minibuffer-mode-abbrev-table' and +'minibuffer-inactive-mode-abbrev-table' are now defined. + +** Isearch and Replace + ++++ +*** Changes in how Isearch responds to 'mouse-yank-at-point'. +If a user does 'C-s' and then uses '<mouse-2>' ('mouse-yank-primary') +outside the echo area, Emacs will, by default, end the Isearch and +yank the text at mouse cursor. But if 'mouse-yank-at-point' is +non-nil, the text will now be added to the Isearch instead. + ++++ +*** Changes for values 'no' and 'no-ding' of 'isearch-wrap-pause'. +Now with these values the search will wrap around not only on repeating +with 'C-s C-s', but also after typing a character. + ++++ +*** New user option 'char-fold-override'. +Non-nil means that the default definitions of equivalent characters +are overridden. + +*** New command 'describe-char-fold-equivalences'. +It displays character equivalences used by 'char-fold-to-regexp'. + ++++ +*** 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. + +** Glyphless Characters + ++++ +*** New minor mode 'glyphless-display-mode'. +This allows an easy way to toggle seeing all glyphless characters in +the current buffer. + +--- +*** The extra slot of 'glyphless-char-display' can now have cons values. +The extra slot of the 'glyphless-char-display' char-table can now have +values that are cons cells, specifying separate values for text-mode +and GUI terminals. + ++++ +*** "Replacement character" feature for undisplayable characters on TTYs. +The 'acronym' method of displaying glyphless characters on text-mode +frames treats single-character acronyms specially: they are displayed +without the surrounding '[..]' "box", thus in effect treating such +"acronyms" as replacement characters. + +** Registers + ++++ +*** Buffer names can now be stored in registers. +For instance, to enable jumping to the "*Messages*" buffer with +'C-x r j m': + + (set-register ?m '(buffer . "*Messages*")) + +** Pixel Fill + ++++ +*** This is a new package that deals with filling variable-pitch text. + ++++ +*** New function 'pixel-fill-region'. +This fills the region to be no wider than a specified pixel width. + +** Info + ++++ +*** Command 'info-apropos' now takes a prefix argument to search for regexps. + +--- +*** New command 'Info-goto-node-web' and key binding 'G'. +This will take you to the "gnu.org" web server's version of the current +info node. This command only works for the Emacs and Emacs Lisp manuals. + +** Shortdoc + +--- +*** New command 'shortdoc-copy-function-as-kill' bound to 'w'. +It copies the name of the function near point into the kill ring. + +--- +*** 'N' and 'P' are now bound to 'shortdoc-{next,previous}-section'. +This is in addition to the old keybindings 'C-c C-n' and 'C-c C-p'. + +** VC + +--- +*** New command 'vc-pull-and-push'. +This commands first does a "pull" command, and if that is successful, +does a "push" command afterwards. Currently supported in Git and Bzr. + ++++ +*** 'C-x v b' prefix key is used now for branch commands. +'vc-print-branch-log' is bound to 'C-x v b l', and new commands are +'vc-create-branch' ('C-x v b c') and 'vc-switch-branch' ('C-x v b s'). +The VC Directory buffer now uses the prefix 'b' for these branch-related +commands. + ++++ +*** New command 'vc-dir-mark-by-regexp' bound to '% m' and '* %'. +This command marks files based on a regexp. If given a prefix +argument, unmark instead. + ++++ +*** New command 'C-x v !' ('vc-edit-next-command'). +This prefix command requests editing of the next VC shell command +before execution. For example, in a Git repository, you can produce a +log of more than one branch by typing 'C-x v ! C-x v b l' and then +appending additional branch names to the 'git log' command. + +--- +*** 'C-x v v' in a diffs buffer allows to commit only some of the changes. +This command is intended to allow you to commit only some of the +changes you have in your working tree. Begin by creating a buffer +with the changes against the last commit, e.g. with 'C-x v D' +('vc-root-diff'). Then edit the diffs to remove the hunks you don't +want to commit. Finally, type 'C-x v v' in that diff buffer to commit +only part of your changes, those whose hunks were left in the buffer. + +--- +*** 'C-x v v' on an unregistered file will now use the most specific backend. +Previously, if you had an SVN-covered "~/" directory, and a Git-covered +directory in "~/foo/bar", using 'C-x v v' on a new, unregistered file +"~/foo/bar/zot" would register it in the SVN repository in "~/" instead of +in the Git repository in "~/foo/bar". This makes this command +consistent with 'vc-responsible-backend'. + +--- +*** Log Edit now fontifies long Git commit summary lines. +Writing shorter summary lines avoids truncation in contexts in which +Git commands display summary lines. See the two new user options +'vc-git-log-edit-summary-target-len' and 'vc-git-log-edit-summary-max-len'. + +--- +*** New 'log-edit-headers-separator' face. +It is used to style the line that separates the 'log-edit' headers +from the 'log-edit' summary. + +--- +*** The function 'vc-read-revision' accepts a new MULTIPLE argument. +If non-nil, multiple revisions can be queried. This is done using +'completing-read-multiple'. + +--- +*** New function 'vc-read-multiple-revisions'. +This function invokes 'vc-read-revision' with a non-nil value for +MULTIPLE. + ++++ +*** New command 'vc-prepare-patch'. +Patches for any version control system can be prepared using VC. The +command will query what commits to send and will compose messages for +your mail user agent. The behavior of 'vc-prepare-patch' can be +modified by the user options 'vc-prepare-patches-separately' and +'vc-default-patch-addressee'. + +** Message + +--- +*** New user option 'mml-attach-file-at-the-end'. +If non-nil, 'C-c C-a' will put attached files at the end of the message. + +--- +*** Message Mode now supports image yanking. + ++++ +*** New user option 'message-server-alist'. +This controls automatic insertion of the "X-Message-SMTP-Method" +header before sending a message. + +** HTML Mode + +--- +*** HTML Mode now supports "text/html" and "image/*" yanking. + +** Texinfo Mode + +--- +*** 'texinfo-mode' now has a specialized 'narrow-to-defun' definition. +It narrows to the current node. + +** EUDC + ++++ +*** Deprecations planned for next release. +After Emacs 29.1, some aspects of EUDC will be deprecated. The goal +of these deprecations is to simplify EUDC server configuration by +making 'eudc-server-hotlist' the only place to add servers. There +will not be a need to set the server using the 'eudc-set-server' +command. Instead, the 'eudc-server-hotlist' user option should be +customized to have an entry for the server. The plan is to obsolete +the 'eudc-hotlist' package since Customize is sufficient for changing +'eudc-server-hotlist'. How the 'eudc-server' user option works in this +context is to-be-determined; it can't be removed, because that would +break compatibility, but it may become synchronized with +'eudc-server-hotlist' so that 'eudc-server' is always equal to '(car +eudc-server-hotlist)'. The first entry in 'eudc-server-hotlist' is the +first server tried by 'eudc-expand-try-all'. The hotlist +simplification will allow 'eudc-query-form' to show a drop down of +possible servers, instead of requiring a call to 'eudc-set-server' +like it does in this release. The default value of +'eudc-ignore-options-file' will be changed from nil to t. + ++++ +*** New user option 'eudc-ignore-options-file' that defaults to nil. +The 'eudc-ignore-options-file' user option can be configured to ignore +the 'eudc-options-file' (typically "~/.emacs.d/eudc-options"). Most +users should configure this to t and put EUDC configuration in the +main Emacs initialization file ("~/.emacs" or "~/.emacs.d/init.el"). + ++++ +*** 'eudc-expansion-overwrites-query' to 'eudc-expansion-save-query-as-kill'. +The user option 'eudc-expansion-overwrites-query' is renamed to +'eudc-expansion-save-query-as-kill' to reflect the actual behavior of +the user option. The former is kept as alias. + ++++ +*** New command 'eudc-expand-try-all'. +This command can be used in place of 'eudc-expand-inline'. It takes a +prefix argument that causes 'eudc-expand-try-all' to return matches +from all servers instead of just the matches from the first server to +return any. This is useful for example, if one wants to search LDAP +for a name that happens to match a contact in one's BBDB. + ++++ +*** New behavior and default for user option 'eudc-inline-expansion-format'. +EUDC inline expansion result formatting defaulted to + + ("%s %s <%s>" firstname name email) + +Since email address specifications need to comply with RFC 5322 in +order to be useful in messages, there was a risk to produce syntax +which was standard with RFC 822, but is marked as obsolete syntax by +its successor RFC 5322. Also, the first and last name part was never +enclosed in double quotes, potentially producing invalid address +specifications, which may be rejected by a receiving MTA. Thus, this +variable can now additionally be set to nil (the new default), or a +function. In both cases, the formatted result will be in compliance +with RFC 5322. When set to nil, a default format very similar to the +old default will be produced. When set to a function, that function +is called, and the returned values are used to populate the phrase and +comment parts (see RFC 5322 for definitions). In both cases, the +phrase part will be automatically quoted if necessary. + ++++ +*** New function 'eudc-capf-complete' with 'message-mode' integration. +EUDC can now contribute email addresses to 'completion-at-point' by +adding the new function 'eudc-capf-complete' to +'completion-at-point-functions' in 'message-mode'. + ++++ +*** Additional attributes of query and results in eudcb-macos-contacts.el. +The EUDC back-end for the macOS Contacts app now provides a wider set +of attributes to use for queries, and delivers more attributes in +query results. + ++++ +*** New back-end for ecomplete. +A new back-end for ecomplete allows information from that database to +be queried by EUDC, too. The attributes present in the EUDC query are +used to select the entry type in the ecomplete database. + ++++ +*** New back-end for mailabbrev. +A new back-end for mailabbrev allows information from that database to +be queried by EUDC, too. The attributes 'email', 'name', and 'firstname' +are supported only. + +** EWW/SHR + ++++ +*** New user option to automatically rename EWW buffers. +The 'eww-auto-rename-buffer' user option can be configured to rename +rendered web pages by using their title, URL, or a user-defined +function which returns a string. For the first two cases, the length +of the resulting name is controlled by the user option +'eww-buffer-name-length'. By default, no automatic renaming is +performed. + ++++ +*** New user option 'shr-allowed-images'. +This complements 'shr-blocked-images', but allows specifying just the +allowed images. + ++++ +*** New user option 'shr-use-xwidgets-for-media'. +If non-nil (and Emacs has been built with support for xwidgets), +display <video> elements with an xwidget. Note that this is +experimental; it is known to crash Emacs on some systems, and just +doesn't work on other systems. Also see etc/PROBLEMS. + ++++ +*** New user option 'eww-url-transformers'. +These are used to alter an URL before using it. By default it removes +the common "utm_" trackers from URLs. + +** Find Dired + +--- +*** New command 'find-dired-with-command'. +This enables users to run 'find-dired' with an arbitrary command, +enabling running commands previously unsupported and also enabling new +commands to be built on top. + +** Gnus + ++++ +*** Tool bar changes in Gnus/Message. +There were previously two styles of tool bars available in Gnus and +Message, referred to as 'gnus-summary-tool-bar-retro', +'gnus-group-tool-bar-retro' and 'message-tool-bar-retro', and +'gnus-summary-tool-bar-gnome', 'gnus-group-tool-bar-gnome' and +'message-tool-bar-gnome'. The "retro" tool bars have been removed (as +well as the icons used), and the "gnome" tool bars are now the only +pre-defined toolbars. + +--- +*** 'gnus-summary-up-thread' and 'gnus-summary-down-thread' bindings removed. +The 'gnus-summary-down-thread' binding to 'M-C-d' was shadowed by +'gnus-summary-read-document', and these commands are also available on +'T u' and 'T d' respectively. + +--- +*** Gnus now uses a variable-pitch font in the headers by default. +To get the monospace font back, you can put something like the +following in your ".gnus" file: + + (set-face-attribute 'gnus-header nil :inherit 'unspecified) + +--- +*** The default value of 'gnus-treat-fold-headers' is now 'head'. + +--- +*** New face 'gnus-header'. +All other 'gnus-header-*' faces inherit from this face now. + ++++ +*** New user option 'gnus-treat-emojize-symbols'. +If non-nil, symbols that have an Emoji representation will be +displayed as emojis. The default is nil. + ++++ +*** New command 'gnus-article-emojize-symbols'. +This is bound to 'W D e' and will display symbols that have Emoji +representation as Emoji. + ++++ +*** New mu backend for gnus-search. +Configuration is very similar to the notmuch and namazu backends. It +supports the unified search syntax. + +--- +*** 'gnus-html-image-cache-ttl' is now a seconds count. +Formerly it was a pair of numbers '(A B)' that represented 65536*A + B, +to cater to older Emacs implementations that lacked bignums. +The older form still works but is undocumented. + +** Rmail + +--- +*** Rmail partial summaries can now be applied one on top of the other. +You can now narrow the set of messages selected by Rmail summary's +criteria (recipients, topic, senders, etc.) by making a summary of the +already summarized messages. For example, invoking +'rmail-summary-by-senders', followed by 'rmail-summary-by-topic' will +produce a summary where both the senders and the topic are according +to your selection. The new user option +'rmail-summary-progressively-narrow' controls whether the stacking of +the filters is in effect; customize it to a non-nil value to enable +this feature. + +--- +*** New Rmail summary: by thread. +The new command 'rmail-summary-by-thread' produces a summary of +messages that belong to a single thread of discussion. + +** EIEIO + ++++ +*** 'slot-value' can now be used to access slots of 'cl-defstruct' objects. + +** Align + +--- +*** Alignment in 'text-mode' has changed. +Previously, 'M-x align' didn't do anything, and you had to say 'C-u +M-x align' for it to work. This has now been changed. The default +regexp for 'C-u M-x align-regexp' has also been changed to be easier +for inexperienced users to use. + +** Help + +--- +*** New mode, 'emacs-news-view-mode', for viewing the NEWS file. +This mode is used by the 'C-h N' command, and adds buttons to manual +entries and symbol references. + +--- +*** New user option 'help-link-key-to-documentation'. +When this option is non-nil (which is the default), key bindings +displayed in the "*Help*" buffer will be linked to the documentation +for the command they are bound to. This does not affect listings of +key bindings and functions (such as 'C-h b'). + +** Info Look + +--- +*** info-look specs can now be expanded at run time instead of a load time. +The new ':doc-spec-function' element can be used to compute the +':doc-spec' element when the user asks for info on that particular +mode (instead of at load time). + +** Ansi Color + +--- +*** Support for ANSI 256-color and 24-bit colors. +256-color and 24-bit color codes are now handled by ANSI color +filters and displayed with the specified color. + +** Term Mode + +--- +*** New user option 'term-bind-function-keys'. +If non-nil, 'term-mode' will pass the function keys on to the +underlying shell instead of using the normal Emacs bindings. + +--- +*** Support for ANSI 256-color and 24-bit colors, italic and other fonts. +'term-mode' can now display 256-color and 24-bit color codes. It can +also handle ANSI codes for faint, italic and blinking text, displaying +it with new 'term-{faint,italic,slow-blink,fast-blink}' faces. + +** Project + ++++ +*** 'project-find-file' and 'project-or-external-find-file' can include all. +The commands 'project-find-file' and 'project-or-external-find-file' +now accept a prefix argument, which is interpreted to mean "include +all files". + ++++ +*** New command 'project-list-buffers' bound to 'C-x p C-b'. +This command displays a list of buffers from the current project. + ++++ +*** 'project-kill-buffers' can display the list of buffers to kill. +Customize the user option 'project-kill-buffers-display-buffer-list' +to enable the display of the buffer list. + +*** New user option 'project-vc-extra-root-markers'. +Use it to add detection of nested projects (inside a VCS repository), +or projects outside of VCS repositories. + +As a consequence, the 'VC project backend' is formally renamed to +'VC-aware project backend'. + ++++ +*** New user option 'project-vc-include-untracked'. +If non-nil, files untracked by a VCS are considered to be part of +the project by a VC project based on that VCS. + +** Xref + ++++ +*** New command 'xref-go-forward'. +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' prompting change. +This command no longer prompts for FROM when called without prefix +argument. This makes the most common case faster: replacing entire +matches. + ++++ +*** New command 'xref-find-references-and-replace' to rename one identifier. + +--- +*** New variable 'xref-current-item' (renamed from a private version). + +--- +*** New function 'xref-show-xrefs'. + +*** 'outline-minor-mode' is supported in Xref buffers. +You can enable outlining by adding 'outline-minor-mode' to +'xref-after-update-hook'. + +** File Notifications + ++++ +*** The new command 'file-notify-rm-all-watches' removes all file notifications. + +** Sql + +--- +*** Sql now supports sending of passwords in-process. +To improve security, if an sql product has ':password-in-comint' set +to t, a password supplied via the minibuffer will be sent in-process, +as opposed to via the command-line. + +** Image Mode + ++++ +*** New command 'image-transform-fit-to-window'. +This command fits the image to the current window by scaling down or +up as necessary. Unlike 'image-transform-fit-both', this does not +only scale the image down, but up as well. It is bound to 's w' in +Image Mode by default. + +--- +*** New command 'image-mode-wallpaper-set'. +This command sets the desktop background to the current image. It is +bound to 'W' by default. + ++++ +*** 'image-transform-fit-to-{height,width}' are now obsolete. +Use the new command 'image-transform-fit-to-window' instead. +The keybinding for 'image-transform-fit-to-width' is now 's i'. + +--- +*** User option 'image-auto-resize' can now be set to 'fit-window'. +This works like 'image-transform-fit-to-window'. + +--- +*** New user option 'image-auto-resize-max-scale-percent'. +The new 'fit-window' option will never scale an image more than this +much (in percent). It is nil by default, which means no limit. + +--- +*** New user option 'image-text-based-formats'. +This controls whether or not to show a message when opening certain +image formats saying how to edit it as text. The default is to show +this message for SVG and XPM. + ++++ +*** New commands: 'image-flip-horizontally' and 'image-flip-vertically'. +These commands horizontally and vertically flip the image under point, +and are bound to 'i h' and 'i v', respectively. + ++++ +*** New command 'image-transform-set-percent'. +It allows setting the image size to a percentage of its original size, +and is bound to 's p' in Image mode. + ++++ +*** 'image-transform-original' renamed to 'image-transform-reset-to-original'. +The old name was confusing, and is now an obsolete function alias. + ++++ +*** 'image-transform-reset' renamed to 'image-transform-reset-to-initial'. +The old name was confusing, and is now an obsolete function alias. + +** Images + ++++ +*** Users can now add special image conversion functions. +This is done via 'image-converter-add-handler'. + +** Image Dired + ++++ +*** 'image-dired-image-mode' is now based on 'image-mode'. +This avoids converting images in the background, and makes Image-Dired +noticeably faster. New keybindings from 'image-mode' are now +available in the "*image-dired-display-image*" buffer; press '?' or +'h' in that buffer to see the full list. + +--- +*** Navigation and marking commands now work in image display buffer. +The following new bindings have been added: +- 'n', 'SPC' => 'image-dired-display-next' +- 'p', 'DEL' => 'image-dired-display-previous' +- 'm' => 'image-dired-mark-thumb-original-file' +- 'd' => 'image-dired-flag-thumb-original-file' +- 'u' => 'image-dired-unmark-thumb-original-file' + +--- +*** New command 'image-dired-unmark-all-marks'. +It removes all marks from all files in the thumbnail and the +associated Dired buffer, and is bound to 'U' in the thumbnail and +display buffer. + +--- +*** New command 'image-dired-do-flagged-delete'. +It deletes all flagged files, and is bound to 'x' in the thumbnail +buffer. It replaces the command 'image-dired-delete-marked', which is +now an obsolete alias. + +--- +*** New command 'image-dired-copy-filename-as-kill'. +It copies the name of the marked or current image to the kill ring, +and is bound to 'w' in the thumbnail buffer. + +--- +*** New command 'image-dired-wallpaper-set'. +This command sets the desktop background to the image at point in the +thumbnail buffer. It is bound to 'W' by default. + +--- +*** 'image-dired-slideshow-start' is now bound to 'S'. +It is bound in both the thumbnail and display buffer, and no longer +prompts for a timeout; use a numerical prefix (e.g. 'C-u 8 S') to set +the timeout. + +--- +*** New user option 'image-dired-marking-shows-next'. +If this option is non-nil (the default), marking, unmarking or +flagging an image in either the thumbnail or display buffer shows the +next image. + +--- +*** New face 'image-dired-thumb-flagged'. +If 'image-dired-thumb-mark' is non-nil (the default), this face is +used for images that are flagged for deletion in the Dired buffer +associated with Image-Dired. + +--- +*** Image information is now shown in the header line of the thumbnail buffer. +This replaces the message that most navigation commands in the +thumbnail buffer used to show at the bottom of the screen. + +--- +*** New specifiers for 'image-dired-display-properties-format'. +This is used to format the new header line. The new specifiers are: +"%d" for the name of the directory that the file is in, "%n" for +file's number in the thumbnail buffer, and "%s" for the file size. + +The default format has been updated to use this. If you prefer the +old format, add this to your Init file: + + (setopt image-dired-display-properties-format "%b: %f (%t): %c") + +--- +*** New faces for the header line of the thumbnail buffer. +These faces correspond to different parts of the header line, as +specified in 'image-dired-display-properties-format': +- 'image-dired-thumb-header-directory-name' +- 'image-dired-thumb-header-file-name' +- 'image-dired-thumb-header-file-size' +- 'image-dired-thumb-header-image-count' + +--- +*** PDF support. +Image-Dired now displays thumbnails for PDF files. Type 'RET' on a +PDF file in the thumbnail buffer to visit the corresponding PDF. + +--- +*** Support GraphicsMagick command line tools. +Support for the GraphicsMagick command line tool ("gm") has been +added, and is used when it is available instead of ImageMagick. + +--- +*** Support Thumbnail Managing Standard v0.9.0 (Dec 2020). +This standard allows sharing generated thumbnails across different +programs. Version 0.9.0 adds two larger thumbnail sizes: 512x512 and +1024x1024 pixels. See the user option 'image-dired-thumbnail-storage' +to use it; it is not enabled by default. + +--- +*** Reduce dependency on external "exiftool" program. +The 'image-dired-copy-with-exif-file-name' command no longer requires +an external "exiftool" program to be available. The user options +'image-dired-cmd-read-exif-data-program' and +'image-dired-cmd-read-exif-data-options' are now obsolete. + +--- +*** Support for bookmark.el. +The command 'bookmark-set' (bound to 'C-x r m') is now supported in +the thumbnail view, and will create a bookmark that opens the current +directory in Image-Dired. + +--- +*** The 'image-dired-slideshow-start' command no longer prompts. +It no longer inconveniently prompts for a number of images and a +delay: it runs indefinitely, but stops automatically on any command. +You can set the delay with a prefix argument, or a negative prefix +argument to prompt for a delay. Customize the user option +'image-dired-slideshow-delay' to change the default from 5 seconds. + ++++ +*** 'image-dired-show-all-from-dir-max-files' increased to 1000. +This user option controls asking for confirmation when starting +Image-Dired in a directory with many files. Since Image-Dired creates +thumbnails in the background in recent versions, this is not as +important as it used to be. You can now also customize this option to +nil to disable this confirmation completely. + +--- +*** 'image-dired-thumb-size' increased to 128. + ++++ +*** 'image-dired-db-file' renamed to 'image-dired-tags-db-file'. + +--- +*** 'image-dired-display-image-mode' renamed to 'image-dired-image-mode'. +The corresponding keymap is now named 'image-dired-image-mode-map'. + ++++ +*** Some commands have been renamed to be shorter. +- 'image-dired-display-thumbnail-original-image' has been renamed to + 'image-dired-display-this'. +- 'image-dired-display-next-thumbnail-original' has been renamed to + 'image-dired-display-next'. +- 'image-dired-display-previous-thumbnail-original' has been renamed + to 'image-dired-display-previous'. +The old names are now obsolete aliases. + +--- +*** 'image-dired-thumb-{height,width}' are now obsolete. +Customize 'image-dired-thumb-size' instead, which will set both the +height and width. + +--- +*** HTML image gallery generation is now obsolete. +The 'image-dired-gallery-generate' command and these user options are +now obsolete: 'image-dired-gallery-thumb-image-root-url', +'image-dired-gallery-hidden-tags', 'image-dired-gallery-dir', +'image-dired-gallery-image-root-url'. + +--- +*** 'image-dired-rotate-thumbnail-{left,right}' are now obsolete. +Instead, use commands 'image-dired-refresh-thumb' to generate a new +thumbnail, or 'image-rotate' to rotate the thumbnail without updating +the thumbnail file. + ++++ +*** Some commands and user options are now obsolete. +Since 'image-dired-display-image-mode' is now based on 'image-mode', +some commands and user options are no longer needed and are now obsolete: +'image-dired-cmd-create-temp-image-options', +'image-dired-cmd-create-temp-image-program', +'image-dired-display-current-image-full', +'image-dired-display-current-image-sized', +'image-dired-display-window-height-correction', +'image-dired-display-window-width-correction', +'image-dired-temp-image-file'. + +** Exif + +--- +*** New function 'exif-field'. +This is a convenience function to extract the field data from +'exif-parse-file' and 'exif-parse-buffer'. + +** Bookmarks + +--- +*** 'list-bookmarks' now includes a type column. +Types are registered via a 'bookmark-handler-type' symbol property on +the jumping function. + ++++ +*** 'bookmark-sort-flag' can now be set to 'last-modified'. +This will display bookmark list from most recently set to least +recently set. + +--- +*** When editing a bookmark annotation, 'C-c C-k' will now cancel. +It is bound to the new command 'bookmark-edit-annotation-cancel'. + +--- +*** New user option 'bookmark-fringe-mark'. +This option controls the bitmap used to indicate bookmarks in the +fringe (or nil to disable showing this marker). + +** Xwidget + +--- +*** New user option 'xwidget-webkit-buffer-name-format'. +This option controls how xwidget-webkit buffers are named. + +--- +*** New user option 'xwidget-webkit-cookie-file'. +This option controls whether the xwidget-webkit buffers save cookies +set by web pages, and if so, in which file to save them. + ++++ +*** New minor mode 'xwidget-webkit-edit-mode'. +When this mode is enabled, self-inserting characters and other common +web browser shortcut keys are redefined to send themselves to the +WebKit widget. + ++++ +*** New minor mode 'xwidget-webkit-isearch-mode'. +This mode acts similarly to incremental search, and allows searching +the contents of a WebKit widget. In xwidget-webkit mode, it is bound +to 'C-s' and 'C-r'. + ++++ +*** New command 'xwidget-webkit-browse-history'. +This command displays a buffer containing the page load history of +the current WebKit widget, and allows you to navigate it. + +--- +*** On X, the WebKit inspector is now available inside xwidgets. +To access the inspector, right click on the widget and select "Inspect +Element". + +--- +*** "Open in New Window" in a WebKit widget's context menu now works. +The newly created buffer will be displayed via 'display-buffer', which +can be customized through the usual mechanism of 'display-buffer-alist' +and friends. + +** Tramp + ++++ +*** New connection methods "docker", "podman" and "kubernetes". +They allow accessing containers provided by Docker and similar +programs. + +--- +*** Tramp supports abbreviating remote home directories now. +When calling 'abbreviate-file-name' on a Tramp file name, the result +will abbreviate the user's home directory, for example by abbreviating +"/ssh:user@host:/home/user" to "/ssh:user@host:~". + ++++ +*** New user option 'tramp-use-scp-direct-remote-copying'. +When set to non-nil, Tramp does not copy files between two remote +hosts via a local copy in its temporary directory, but lets the 'scp' +command do this job. + ++++ +*** Proper password prompts for methods "doas", "sudo" and "sudoedit". +The password prompts for these methods reflect now the credentials of +the user requesting such a connection, and not of the user who is the +target. This has always been needed, just the password prompt and the +related 'auth-sources' entry were wrong. + ++++ +*** New user option 'tramp-completion-use-cache'. +During user and host name completion in the minibuffer, results from +Tramp's connection cache are taken into account. This can be disabled +by setting the user option 'tramp-completion-use-cache' to nil. + +** Browse URL + +--- +*** New user option 'browse-url-default-scheme'. +This user option decides which URL scheme that 'browse-url' and +related functions will use by default. For example, you could +customize this to "https" to always prefer HTTPS URLs. + +--- +*** New user option 'browse-url-irc-function'. +This option specifies a function for opening "irc://" links. It +defaults to the new function 'browse-url-irc'. + +--- +*** New function 'browse-url-irc'. +This multipurpose autoloaded function can be used for opening "irc://" +and "ircs://" URLS by any caller that passes a URL string as an initial +arg. + +--- +*** Support for the Netscape web browser has been removed. +This support has been obsolete since Emacs 25.1. The final version of +the Netscape web browser was released in February, 2008. + +--- +*** Support for the Galeon web browser has been removed. +This support has been obsolete since Emacs 25.1. The final version of +the Galeon web browser was released in September, 2008. + +--- +*** Support for the Mozilla web browser is now obsolete. +Note that this historical web browser is different from Mozilla +Firefox; it is its predecessor. + +** Python Mode + ++++ +*** Project shells and a new user option 'python-shell-dedicated'. +When called with a prefix argument, 'run-python' now offers the choice +of creating a shell dedicated to the current project. This shell runs +in the project root directory and is shared among all project buffers. + +Without a prefix argument, the kind of shell (buffer-dedicated, +project-dedicated or global) is specified by the new +'python-shell-dedicated' user option. + +** Ruby Mode + +--- +*** New user option 'ruby-toggle-block-space-before-parameters'. + +--- +*** Support for endless methods. + +--- +*** New user options that determine indentation logic. +'ruby-method-params-indent', 'ruby-block-indent', +'ruby-after-operator-indent', 'ruby-method-call-indent', +'ruby-parenless-call-arguments-indent'. See the docstrings for +explanations and examples. + +** Eshell + ++++ +*** New feature to easily bypass Eshell's own pipelining. +Prefixing '|', '<' or '>' with an asterisk, i.e. '*|', '*<' or '*>', +will cause the whole command to be passed to the operating system +shell. This is particularly useful to bypass Eshell's own pipelining +support for pipelines which will move a lot of data. See section +"Running Shell Pipelines Natively" in the Eshell manual, node +"(eshell) Pipelines". + ++++ +*** New module to help supplying absolute file names to remote commands. +After enabling the new 'eshell-elecslash' module, typing a forward +slash as the first character of a command line argument will +automatically insert the Tramp prefix. The automatic insertion +applies only when 'default-directory' is remote and the command is a +Lisp function. This frees you from having to keep track of whether +commands are Lisp function or external when supplying absolute file +name arguments. See the "(eshell) Electric forward slash" node in the +Eshell manual for details. + ++++ +*** Improved support for redirection operators in Eshell. +Eshell now supports a wider variety of redirection operators. For +example, you can now redirect both stdout and stderr via '&>' or +duplicate one output handle to another via 'NEW-FD>&OLD-FD'. For more +information, see the "(eshell) Redirection" node in the Eshell manual. + ++++ +*** New eshell built-in command 'doas'. +The privilege-escalation program 'doas' has been added to the existing +'su' and 'sudo' commands from the 'eshell-tramp' module. The external +command may still be accessed by using '*doas'. + ++++ +*** Double-quoting an Eshell expansion now treats the result as a single string. +If an Eshell expansion like '$FOO' is surrounded by double quotes, the +result will always be a single string, no matter the type that would +otherwise be returned. + ++++ +*** Concatenating Eshell expansions now works more similarly to other shells. +When concatenating an Eshell expansion that returns a list, "adjacent" +elements of each operand are now concatenated together, +e.g. '$(list "a" "b")c' returns '("a" "bc")'. See the "(eshell) +Expansion" node in the Eshell manual for more details. + ++++ +*** Eshell subcommands with multiline numeric output return lists of numbers. +If every line of the output of an Eshell subcommand like '${COMMAND}' +is numeric, the result will be a list of numbers (or a single number +if only one line of output). Previously, this only converted numbers +when there was a single line of output. + +--- +*** Built-in Eshell commands now follow 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'. New commands can take advantage of this with the +'eshell-eval-using-options' macro. See "Defining new built-in +commands" in the "(eshell) Built-ins" node of the Eshell manual. + +--- +*** Eshell globs ending with "/" now match only directories. +Additionally, globs ending with "**/" or "***/" no longer raise an +error, and now expand to all directories recursively (following +symlinks in the latter case). + ++++ +*** Lisp forms in Eshell now treat a nil result as a failed exit status. +When executing a command that looks like '(lisp form)' and returns +nil, Eshell will set the exit status (available in the '$?' +variable) to 2. This allows commands like that to be used in +conditionals. To change this behavior, customize the new +'eshell-lisp-form-nil-is-failure' user option. + +** Shell + +--- +*** New user option 'shell-kill-buffer-on-exit'. +Enabling this will automatically kill a "*shell*" buffer as soon as +the shell session terminates. + +--- +*** New minor mode 'shell-highlight-undef-mode'. +Customize 'shell-highlight-undef-enable' to t if you want to enable +this minor mode in "*shell*" buffers. It will highlight undefined +commands with a warning face as you type. + +** Calc + ++++ +*** New user option 'calc-kill-line-numbering'. +Set it to nil to exclude line numbering from kills and copies. + +** Hierarchy + ++++ +*** Tree Display can delay computation of children. +'hierarchy-add-tree' and 'hierarchy-add-trees' have an optional +argument which allows tree-widget display to be activated and computed +only when the user expands the node. + +** Proced + +--- +*** proced.el shows system processes of remote hosts. +When 'default-directory' is remote, and 'proced' is invoked with a +negative argument like 'C-u - proced', the system processes of that +remote host are shown. Alternatively, the user option +'proced-show-remote-processes' can be set to non-nil. +'proced-signal-function' has been marked obsolete. + +--- +*** Proced can now optionally show process details in color. +New user option 'proced-enable-color-flag' enables coloring of Proced +buffers. This option is disabled by default; customize it to a +non-nil value to enable colors. + +** Miscellaneous + +--- +*** New user option 'webjump-use-internal-browser'. +When non-nil, WebJump will use an internal browser to open web pages, +instead of the default external browser. + ++++ +*** New user option 'font-lock-ignore'. +This option provides a mechanism to selectively disable font-lock +keyword-driven fontifications. + +--- +*** New user option 'auto-save-visited-predicate'. +This user option is a predicate function which is called by +'auto-save-visited-mode' to decide whether or not to save a buffer. +You can use it to automatically save only specific buffers, for +example buffers using a particular mode or in some directory. + +--- +*** New user option 'remote-file-name-inhibit-auto-save-visited'. +If this user option is non-nil, 'auto-save-visited-mode' will not +auto-save remote buffers. The default is nil. + ++++ +*** New package vtable.el for formatting tabular data. +This package allows formatting data using variable-pitch fonts. +The resulting tables can display text in variable pitch fonts, text +using fonts of different sizes, and images. See the "(vtable) Top" +manual for more details. + +--- +*** New minor mode 'elide-head-mode'. +Enabling this minor mode turns on hiding header material, like +'elide-head' does; disabling it shows the header. The commands +'elide-head' and 'elide-head-show' are now obsolete. + +*** New package ansi-osc.el. +Support for OSC ("Operating System Command") escape sequences has been +extracted from comint.el in order to provide interpretation of OSC +sequences in compilation buffers. + +Adding the new function 'ansi-osc-compilation-filter' to +'compilation-filter-hook' enables interpretation of OSC escape +sequences in compilation buffers. By default, all sequences are +filtered out. + +The list of handlers (already covering OSC 7 and 8) has been extended +with a handler for OSC 2, the command to set a window title. + +--- +*** 'recentf-mode' now uses abbreviated file names by default. +This means that e.g. "/home/foo/bar" is now displayed as "~/bar". +Customize the user option 'recentf-filename-handlers' to nil to get +back the old behavior. + +--- +*** New command 'recentf-open'. +This command prompts for a recently opened file in the minibuffer, and +visits it. + +--- +*** 'ffap-machine-at-point' no longer pings hosts by default. +It will now simply look at a hostname to determine if it is valid, +instead of also trying to ping it. Customize the user option +'ffap-machine-p-known' to 'ping' to get the old behavior back. + +--- +*** The 'run-dig' command is now obsolete; use 'dig' instead. + +--- +*** Some 'bib-mode' commands and variables have been renamed. +To respect Emacs naming conventions, the variable 'unread-bib-file' +has been renamed to 'bib-unread-file'. The following commands have +also been renamed: + 'addbib' to 'bib-add' + 'return-key-bib' to 'bib-return-key' + 'mark-bib' to 'bib-mark' + 'unread-bib' to 'bib-unread' + +--- +*** 'outlineify-sticky' command is renamed to 'allout-outlinify-sticky'. +The old name is still available as an obsolete function alias. + +--- +*** The url-irc library now understands "ircs://" links. + +--- +*** New command 'world-clock-copy-time-as-kill' for 'world-clock-mode'. +It copies the current line into the kill ring. + +--- +*** 'edit-abbrevs' now uses font-locking. +The new face 'abbrev-table-name' is used to display the abbrev table +name. + +--- +*** New key binding 'O' in "*Buffer List*". +This key is now bound to 'Buffer-menu-view-other-window', which will +view this line's buffer in View mode in another window. + +** Scheme Mode + +--- +*** Auto-detection of Scheme library files. +Emacs now automatically enables the Scheme mode when opening R6RS +Scheme Library Source (".sls") files and R7RS Scheme Library +Definition (".sld") files. + +--- +*** Imenu members for R6RS and R7RS library members. +Imenu now lists the members directly nested in R6RS Scheme libraries +('library') and R7RS libraries ('define-library'). + + +* New Modes and Packages in Emacs 29.1 + ++++ +** Eglot: Emacs Client for the Language Server Protocol. +Emacs now comes with the Eglot package, which enhances various Emacs +features, such as completion, documentation, error detection, etc., +based on data provided by language servers using the Language Server +Protocol (LSP). See the new Info manual "(eglot) Top" for more. + ++++ +** use-package: Declarative package configuration. +use-package is now shipped with Emacs. It provides the 'use-package' +macro, which allows you to isolate package configuration in your init +file in a way that is declarative, tidy, and performance-oriented. +See the new Info manual "(use-package) Top" for more. + ++++ +** New commands 'image-crop' and 'image-cut'. +These commands allow interactively cropping/cutting the image at +point. The commands are bound to keys 'i c' and 'i x' (respectively) +in the local keymap over images. They rely on external programs, by +default "convert" from ImageMagick, to do the actual cropping/eliding +of the image file. + +--- +** New package 'wallpaper'. +This package provides the command 'wallpaper-set', which sets the +desktop background image. Depending on the system and the desktop, +this may require an external program (such as "swaybg", "gm", +"display" or "xloadimage"). If so, a suitable command should be +detected automatically in most cases. It can also be customized +manually if needed, using the new user options 'wallpaper-command' and +'wallpaper-command-args'. + ++++ +** New package 'oclosure'. +This allows the creation of "functions with slots" or "function +objects" via the macros 'oclosure-define' and 'oclosure-lambda'. + ++++ +*** New generic function 'oclosure-interactive-form'. +Used by 'interactive-form' when called on an OClosure. +This allows specific OClosure types to compute their interactive specs +on demand rather than precompute them when created. + +--- +** New theme 'leuven-dark'. +This is a dark version of the 'leuven' theme. + ++++ +** New mode 'erts-mode'. +This mode is used to edit files geared towards testing actions in +Emacs buffers, like indentation and the like. The new ert function +'ert-test-erts-file' is used to parse these files. + +--- +** New major mode 'js-json-mode'. +This is a lightweight variant of 'js-mode' that is used by default +when visiting JSON files. + ++++ +** New major mode 'csharp-mode'. +A major mode based on CC Mode for editing programs in the C# language. +This mode is auto-enabled for files with the ".cs" extension. + ++++ +** New major modes based on the tree-sitter library. +These new major modes are available if Emacs was built with the +tree-sitter library. They provide support for font-locking, +indentation, and navigation by defuns based on parsing the buffer text +by a tree-sitter parser. Some major modes also offer support for +Imenu and 'which-func'. + +The new modes based on tree-sitter are for now entirely optional, and +you must turn them on manually, or load them in your init file, or +customize 'auto-mode-alist' to turn them on automatically for certain +files. You can also customize 'major-mode-remap-alist' to +automatically turn on some tree-sitter based modes for the same files +for which a "built-in" mode would be turned on. For example: + + (add-to-list 'major-mode-remap-alist '(ruby-mode . ruby-ts-mode)) + +If you try these modes and don't like them, you can go back to the +"built-in" modes by restarting Emacs. But please tell us why you +didn't like the tree-sitter based modes, so that we could try +improving them. + +Each major mode based on tree-sitter needs a language grammar library, +usually named "libtree-sitter-LANG.so" ("libtree-sitter-LANG.dll" on +MS-Windows), where LANG is the corresponding language name. Emacs +looks for these libraries in the following places: + + . in the directories mentioned in the list 'treesit-extra-load-path' + . in the "tree-sitter" subdirectory of your 'user-emacs-directory' + (by default, "~/.emacs.d/tree-sitter") + . in the standard system directories where other shared libraries are + usually installed + +We recommend to install these libraries in one of the standard system +locations (the last place in the above list). + +If a language grammar library required by a mode is not found in any +of the above places, the mode will display a warning when you try to +turn it on. + ++++ +*** New major mode 'typescript-ts-mode'. +A major mode based on the tree-sitter library for editing programs +in the TypeScript language. + ++++ +*** New major mode 'tsx-ts-mode'. +A major mode based on the tree-sitter library for editing programs +in the TypeScript language, with support for TSX. + ++++ +*** New major mode 'c-ts-mode'. +An optional major mode based on the tree-sitter library for editing +programs in the C language. + ++++ +*** New major mode 'c++-ts-mode'. +An optional major mode based on the tree-sitter library for editing +programs in the C++ language. + ++++ +*** New command 'c-or-c++-ts-mode'. +A command that automatically guesses the language of a header file, +and enables either 'c-ts-mode' or 'c++-ts-mode' accordingly. + ++++ +*** New major mode 'java-ts-mode'. +An optional major mode based on the tree-sitter library for editing +programs in the Java language. + ++++ +*** New major mode 'python-ts-mode'. +An optional major mode based on the tree-sitter library for editing +programs in the Python language. + ++++ +*** New major mode 'css-ts-mode'. +An optional major mode based on the tree-sitter library for editing +CSS (Cascading Style Sheets). + ++++ +*** New major mode 'json-ts-mode'. +An optional major mode based on the tree-sitter library for editing +programs in the JSON language. + ++++ +*** New major mode 'csharp-ts-mode'. +An optional major mode based on the tree-sitter library for editing +programs in the C# language. + ++++ +*** New major mode 'bash-ts-mode'. +Am optional major mode based on the tree-sitter library for editing +Bash shell scripts. + ++++ +*** New major mode 'dockerfile-ts-mode'. +A major mode based on the tree-sitter library for editing +Dockerfiles. + ++++ +*** New major mode 'cmake-ts-mode'. +A major mode based on the tree-sitter library for editing CMake files. + ++++ +*** New major mode 'toml-ts-mode'. +An optional major mode based on the tree-sitter library for editing +files written in TOML, a format for writing configuration files. + ++++ +*** New major mode 'go-ts-mode'. +A major mode based on the tree-sitter library for editing programs in +the Go language. + ++++ +*** New major mode 'go-mod-ts-mode'. +A major mode based on the tree-sitter library for editing "go.mod" +files. + ++++ +*** New major mode 'yaml-ts-mode'. +A major mode based on the tree-sitter library for editing files +written in YAML. + ++++ +*** New major mode 'rust-ts-mode'. +A major mode based on the tree-sitter library for editing programs in +the Rust language. + +--- +*** New major mode 'ruby-ts-mode'. +An optional major mode based on the tree-sitter library for editing +programs in the Ruby language. + + +* Incompatible Lisp Changes in Emacs 29.1 + ++++ +** The implementation of overlays has changed. +Emacs now uses an implementation of overlays that is much more +efficient than the original one, and should speed up all the +operations that involve overlays, especially when there are lots of +them in a buffer. + +As result of this, some minor incompatibilities in behavior could be +observed, as described below. Except those minor incompatibilities, +no other changes in behavior of overlays should be visible on the Lisp +or user level, with the exception of better performance and the order +of overlays returned by functions that don't promise any particular +order. + +--- +*** The function 'overlay-recenter' is now a no-op. +This function does nothing, and in particular has no effect on the +value returned by 'overlay-lists'. The purpose of 'overlay-recenter' +was to allow more efficient lookup of overlays around a certain buffer +position; however with the new implementation the lookup of overlays +is efficient regardless of their position, and there's no longer any +need to "optimize" the lookup, nor any notion of a "center" of the +overlays. + +--- +*** The function 'overlay-lists' returns one unified list of overlays. +This function used to return a cons of two lists, one with overlays +before the "center" position, the other after that "center". It now +returns a list whose 'car' is the list of all the buffer overlays, and +whose 'cdr' is always nil. + ++++ +** 'format-prompt' now uses 'substitute-command-keys'. +This means that both the prompt and 'minibuffer-default-prompt-format' +will have key definitions and single quotes handled specially. + ++++ +** New function 'substitute-quotes'. +This function works like 'substitute-command-keys' but only +substitutes quote characters. + +--- +** 'find-image' now uses 'create-image'. +This means that images found through 'find-image' also have +auto-scaling applied. (This only makes a difference on HiDPI +displays.) + ++++ +** Changes in how "raw" in-memory XBM images are specified. +Some years back Emacs gained the ability to scale images, and you +could then specify ':width' and ':height' when using 'create-image' on all +image types -- except XBM images, because this format already used the +':width' and ':height' arguments to specify the width/height of the "raw" +in-memory format. This meant that if you used these specifications +on, for instance, XBM files, Emacs would refuse to display them. This +has been changed, and ':width'/':height' now works as with all other image +formats, and the way to specify the width/height of the "raw" +in-memory format is now by using ':data-width' and ':data-height'. + ++++ +** "loaddefs.el" generation has been reimplemented. +The various "loaddefs.el" files in the Emacs tree (which contain +information about autoloads, built-in packages and package prefixes) +used to be generated by functions in autoloads.el. These are now +generated by loaddefs-gen.el instead. This leads to functionally +equivalent "loaddefs.el" files, but they do not use exactly the same +syntax, so using 'M-x update-file-autoloads' no longer works. (This +didn't work well in most files in the past, either, but it will now +signal an error in any file.) + +In addition, files are scanned in a slightly different way. +Previously, ';;;###' specs inside a top-level form (i.e., something +like '(when ... ;;;### ...)' would be ignored. They are now parsed as +usual. + +--- +** Themes have special autoload cookies. +All built-in themes are scraped for ';;;###theme-autoload' cookies +that are loaded along with the regular auto-loaded code. + ++++ +** 'buffer-modified-p' has been extended. +This function was previously documented to return only nil or t. This +has been changed to nil/'autosaved'/non-nil. The new 'autosaved' +value means that the buffer is modified, but that it hasn't been +modified since the time of last auto-save. + +--- +** 'with-silent-modifications' also restores buffer autosave status. +'with-silent-modifications' is a macro meant to be used by the font +locking machinery to allow applying text properties without changing +the modification status of the buffer. However, it didn't restore the +buffer autosave status, so applying font locking to a modified buffer +that had already been auto-saved would trigger another auto-saving. +This is no longer the case. + +--- +** 'prin1' doesn't always escape "." and "?" in symbols any more. +Previously, symbols like 'foo.bar' would be printed by 'prin1' as +"foo\.bar". This now prints as "foo.bar" instead. The Emacs Lisp +reader interprets these strings as referring to the same symbol, so +this is virtually always backwards-compatible, but there may +theoretically be code out there that expects a specific printed +representation. + +The same is the case with the "?" character: The 'foo?' symbol is now +printed as "foo?" instead of "foo\?". + +If the "." and "?" characters are the first character in the symbol, +they will still be escaped, so the '.foo' symbol is still printed as +"\.foo" and the '?bar' symbol is still printed as "\?bar". + ++++ +** Remapping 'mode-line' face no longer works as expected. +'mode-line' is now the parent face of the new 'mode-line-active' face, +and remapping parent of basic faces does not work reliably. +Instead of remapping 'mode-line', you have to remap 'mode-line-active'. + ++++ +** 'make-process' has been extended to support ptys when ':stderr' is set. +Previously, setting ':stderr' to a non-nil value would force the +process's connection to use pipes. Now, Emacs will use a pty for +stdin and stdout if requested no matter the value of ':stderr'. + +--- +** User option 'mail-source-ignore-errors' is now obsolete. +The whole mechanism for prompting users to continue in case of +mail-source errors has been removed, so this option is no longer +needed. + +** Fonts + +--- +*** Emacs now supports 'medium' fonts. +Emacs previously didn't distinguish between the 'regular'/'normal' +weight and the 'medium' weight, but it now also supports the (heavier) +'medium' weight. However, this means that if you specify a weight of +'normal' and the font doesn't have this weight, Emacs won't find the +font spec. In these cases, replacing ":weight 'normal" with ":weight +'medium" should fix the issue. + +--- +** Keymap descriptions have changed. +'help--describe-command', 'C-h b' and associated functions that output +keymap descriptions have changed. In particular, prefix commands are +not output at all, and instead of "??" for closures/functions, +"[closure]"/"[lambda]" is output. + +--- +** 'downcase' details have changed slightly. +In certain locales, changing the case of an ASCII-range character may +turn it into a multibyte character, most notably with "I" in Turkish +(the lowercase is "ı", 0x0131). Previously, 'downcase' on a unibyte +string was buggy, and would mistakenly just return the lower byte of +this, 0x31 (the digit "1"). 'downcase' on a unibyte string has now +been changed to downcase such characters as if they were ASCII. To +get proper locale-dependent downcasing, the string has to be converted +to multibyte first. (This goes for the other case-changing functions, +too.) + +--- +** Functions in 'tramp-foreign-file-name-handler-alist' have changed. +Functions to determine which Tramp file name handler to use are now +passed a file name in dissected form (via 'tramp-dissect-file-name') +instead of in string form. + +--- +** 'def' indentation changes. +In 'emacs-lisp-mode', forms with a symbol with a name that start with +"def" have been automatically indented as if they were 'defun'-like +forms, for instance: + + (defzot 1 + 2 3) + +This heuristic has now been removed, and all functions/macros that +want to be indented this way have to be marked with + + (declare (indent defun)) + +or the like. If the function/macro definition itself can't be +changed, the indentation can also be adjusted by saying something +like: + + (put 'defzot 'lisp-indent-function 'defun) + +--- +** The 'inhibit-changing-match-data' variable is now obsolete. +Instead, functions like 'string-match' and 'looking-at' now take an +optional INHIBIT-MODIFY argument. + +--- +** 'gnus-define-keys' is now obsolete. +Use 'define-keymap' instead. + +--- +** MozRepl has been removed from js.el. +MozRepl was removed from Firefox in 2017, so this code doesn't work +with recent versions of Firefox. + +--- +** The function 'image-dired-get-exif-data' is now obsolete. +Use 'exif-parse-file' and 'exif-field' instead. + +--- +** 'insert-directory' alternatives should not change the free disk space line. +This change is now applied in 'dired-insert-directory'. + +--- +** 'compilation-last-buffer' is (finally) declared obsolete. +It has been obsolete since Emacs 22.1, actually. + +--- +** Calling 'lsh' now elicits a byte-compiler warning. +'lsh' behaves in somewhat surprising and platform-dependent ways for +negative arguments, and is generally slower than 'ash', which should be +used instead. This warning can be suppressed by surrounding calls to +'lsh' with the construct '(with-suppressed-warnings ((suspicious lsh)) ...)', +but switching to 'ash' is generally much preferable. + +--- +** Some functions and variables obsolete since Emacs 24 have been removed: +'Buffer-menu-buffer+size-width', 'Electric-buffer-menu-mode', +'Info-edit-map', 'allout-abbreviate-flattened-numbering', +'allout-exposure-change-hook', 'allout-mode-deactivate-hook', +'allout-structure-added-hook', 'allout-structure-deleted-hook', +'allout-structure-shifted-hook', 'ansi-color-unfontify-region', +'archive-extract-hooks', 'auth-source-forget-user-or-password', +'auth-source-hide-passwords', 'auth-source-user-or-password', +'automatic-hscrolling', 'automount-dir-prefix', 'bibtex-complete', +'bibtex-entry-field-alist', 'buffer-has-markers-at', +'buffer-substring-filters', 'byte-compile-disable-print-circle', +'c-prepare-bug-report-hooks', 'cfengine-mode-abbrevs', +'change-log-acknowledgement', 'chart-map', +'checkdoc-comment-style-hooks', 'comint--unquote&expand-filename', +'comint-dynamic-complete', 'comint-dynamic-complete-as-filename', +'comint-dynamic-simple-complete', 'comint-unquote-filename', +'command-history-map', 'compilation-parse-errors-function', +'completion-annotate-function', 'condition-case-no-debug', +'count-lines-region', 'crisp-mode-modeline-string', +'custom-print-functions', 'cvs-string-prefix-p', 'data-debug-map', +'deferred-action-function', 'deferred-action-list', +'dired-pop-to-buffer', 'dired-shrink-to-fit', +'dired-sort-set-modeline', 'dired-x-submit-report', +'display-buffer-function', +'ediff-choose-window-setup-function-automatically', +'eieio-defgeneric', 'eieio-defmethod', 'emacs-lock-from-exiting', +'erc-complete-word', 'erc-dcc-chat-filter-hook', +'eshell-add-to-window-buffer-names', 'eshell-cmpl-suffix-list', +'eshell-for', 'eshell-remove-from-window-buffer-names', +'eshell-status-in-modeline', 'filesets-cache-fill-content-hooks', +'font-list-limit', 'font-lock-maximum-size', +'font-lock-reference-face', 'gnus-carpal', +'gnus-debug-exclude-variables', 'gnus-debug-files', +'gnus-local-domain', 'gnus-outgoing-message-group', +'gnus-registry-user-format-function-M', 'gnus-secondary-servers', +'gnus-subscribe-newsgroup-hooks', 'gud-inhibit-global-bindings', +'hangul-input-method-inactivate', 'hfy-post-html-hooks', +'image-extension-data', 'image-library-alist', +'inactivate-current-input-method-function', 'inactivate-input-method', +'inhibit-first-line-modes-regexps', +'inhibit-first-line-modes-suffixes', 'input-method-inactivate-hook', +'intdos', 'javascript-generic-mode', 'javascript-generic-mode-hook', +'latex-string-prefix-p', 'macro-declaration-function' (function), +'macro-declaration-function' (variable), 'mail-complete', +'mail-complete-function', 'mail-mailer-swallows-blank-line', +'mail-sent-via', 'make-register', 'makefile-complete', +'menu-bar-kill-ring-save', 'meta-complete-symbol', 'meta-mode-map', +'mh-kill-folder-suppress-prompt-hooks', +'minibuffer-completing-symbol', +'minibuffer-local-filename-must-match-map', 'mode25', 'mode4350', +'mpc-string-prefix-p', 'msb-after-load-hooks', +'nndiary-request-accept-article-hooks', +'nndiary-request-create-group-hooks', +'nndiary-request-update-info-hooks', 'nnimap-split-rule', +'nntp-authinfo-file', 'ns-alternatives-map', +'ns-store-cut-buffer-internal', 'package-menu-view-commentary', +'pascal-last-completions', 'pascal-show-completions', +'pascal-toggle-completions', 'pcomplete-arg-quote-list', +'pcomplete-quote-argument', 'prolog-char-quote-workaround', +'python-buffer', 'python-guess-indent', 'python-indent', +'python-info-ppss-comment-or-string-p', 'python-info-ppss-context', +'python-info-ppss-context-type', 'python-preoutput-result', +'python-proc', 'python-send-receive', 'python-send-string', +'python-use-skeletons', 'quail-inactivate', 'quail-inactivate-hook', +'query-replace-interactive', 'rcirc-activity-hooks', +'rcirc-print-hooks', 'rcirc-receive-message-hooks', +'rcirc-sentinel-hooks', 'read-filename-at-point', 'redraw-modeline', +'reftex-index-map', 'reftex-index-phrases-map', +'reftex-select-bib-map', 'reftex-select-label-map', 'reftex-toc-map', +'register-name-alist', 'register-value', 'report-emacs-bug-info', +'report-emacs-bug-pretest-address', +'rmail-default-dont-reply-to-names', 'rmail-dont-reply-to', +'rmail-dont-reply-to-names', 'robin-inactivate', +'robin-inactivate-hook', 'rst-block-face', 'rst-comment-face', +'rst-definition-face', 'rst-directive-face', 'rst-emphasis1-face', +'rst-emphasis2-face', 'rst-external-face', 'rst-literal-face', +'rst-reference-face', 'semantic-change-hooks', +'semantic-edits-delete-change-hooks', +'semantic-edits-new-change-hooks', +'semantic-edits-reparse-change-hooks', 'semantic-grammar-map', +'semantic-grammar-syntax-table', 'semantic-lex-reset-hooks', +'semanticdb-elisp-sym-function-arglist', +'semanticdb-save-database-hooks', 'set-face-underline-p', +'set-register-value', 'sh-maybe-here-document', 'speedbar-key-map', +'speedbar-syntax-table', 'starttls-any-program-available', +'strokes-modeline-string', 'strokes-report-bug', +'term-default-bg-color', 'term-default-fg-color', +'tex-string-prefix-p', 'timeclock-modeline-display', +'timeclock-modeline-display', 'timeclock-update-modeline', +'toggle-emacs-lock', 'tooltip-use-echo-area', 'turn-on-cwarn-mode', +'turn-on-iimage-mode', 'ucs-input-inactivate', 'ucs-insert', +'url-recreate-url-attributes', 'user-variable-p', +'vc-string-prefix-p', 'vc-toggle-read-only', 'view-return-to-alist', +'view-return-to-alist-update', 'w32-default-color-map' (function), +'which-func-mode' (function), 'window-system-version', +'winner-mode-leave-hook', 'x-cut-buffer-or-selection-value'. + +--- +** Some functions and variables obsolete since Emacs 23 have been removed: +'find-emacs-lisp-shadows', 'newsticker-cache-filename', +'process-filter-multibyte-p', 'redisplay-end-trigger-functions', +'set-process-filter-multibyte', 'set-window-redisplay-end-trigger', +'unify-8859-on-decoding-mode', 'unify-8859-on-encoding-mode', +'vc-arch-command', 'window-redisplay-end-trigger', 'x-selection'. + +--- +** Some functions and variables obsolete since Emacs 21 or 22 have been removed: +'c-toggle-auto-state', 'find-file-not-found-hooks', +'ls-lisp-dired-ignore-case', 'query-replace-regexp-eval'. + ++++ +** New generic function 'function-documentation'. +It can dynamically generate a raw docstring depending on the type of a +function. Used mainly for docstrings of OClosures. + ++++ +** Base64 encoding no longer tolerates latin-1 input. +The functions 'base64-encode-string', 'base64url-encode-string', +'base64-encode-region' and 'base64url-encode-region' no longer accept +characters in the range U+0080..U+00FF as substitutes for single bytes +in the range 128..255, but signal an error for all multibyte characters. +The input must be unibyte encoded text. + ++++ +** The 'clone-indirect-buffer-hook' is now run by 'make-indirect-buffer'. +It was previously only run by 'clone-indirect-buffer' and +'clone-indirect-buffer-other-window'. Since 'make-indirect-buffer' is +called by both of these, the hook is now run by all 3 of these +functions. + +--- +** '?\' at the end of a line now signals an error. +Previously, it produced a nonsense value, -1, that was never intended. + +--- +** Some libraries obsolete since Emacs 24.1 and 24.3 have been removed: +abbrevlist.el, assoc.el, complete.el, cust-print.el, +erc-hecomplete.el, mailpost.el, mouse-sel.el, old-emacs-lock.el, +patcomp.el, pc-mode.el, pc-select.el, s-region.el, and sregex.el. + ++++ +** Many seldom-used generalized variables have been made obsolete. +Emacs has a number of rather obscure generalized variables defined, +that, for instance, allowed you to say things like: + + (setf (point-min) 4) + +These never caught on and have been made obsolete. The form above, +for instance, is the same as saying + + (narrow-to-region 4 (point-max)) + +The following generalized variables have been made obsolete: +'buffer-file-name', 'buffer-local-value', 'buffer-modified-p', +'buffer-name', 'buffer-string', 'buffer-substring', 'current-buffer', +'current-column', 'current-global-map', 'current-input-mode', +'current-local-map', 'current-window-configuration', +'default-file-modes', 'documentation-property', 'eq', 'frame-height', +'frame-width', 'frame-visible-p', 'global-key-binding', +'local-key-binding', 'mark', 'mark-marker', 'marker-position', +'mouse-position', 'point', 'point-marker', 'point-max', 'point-min', +'read-mouse-position', 'screen-height', 'screen-width', +'selected-frame', 'selected-screen', 'selected-window', +'standard-case-table', 'syntax-table', 'visited-file-modtime', +'window-height', 'window-width', and 'x-get-secondary-selection'. + + +* Lisp Changes in Emacs 29.1 + ++++ +** Interpreted closures are "safe for space". +As was already the case for byte-compiled closures, instead of capturing +the whole current lexical environment, interpreted closures now only +capture the part of the environment that they need. +The previous behavior could occasionally lead to memory leaks or +to problems where a printed closure would not be 'read'able because +of an un'read'able value in an unrelated lexical variable. + ++++ +** New accessor function 'file-attribute-file-identifier'. +It returns the list of the inode number and device identifier +retrieved by 'file-attributes'. This value can be used to identify a +file uniquely. The device identifier can be a single number or (for +remote files) a cons of 2 numbers. + ++++ +** New macro 'while-let'. +This is like 'when-let', but repeats until a binding form is nil. + ++++ +** New function 'make-obsolete-generalized-variable'. +This can be used to mark setters used by 'setf' as obsolete, and the +byte-compiler will then warn about using them. + ++++ +** New functions 'pos-eol' and 'pos-bol'. +These are like 'line-end-position' and 'line-beginning-position' +(respectively), but ignore fields (and are more efficient). + ++++ +** New function 'compiled-function-p'. +This returns non-nil if its argument is either a built-in, or a +byte-compiled, or a natively-compiled function object, or a function +loaded from a dynamic module. + +--- +** 'deactivate-mark' can have new value 'dont-save'. +This value means that Emacs should deactivate the mark as usual, but +without setting the primary selection, if 'select-active-regions' is +enabled. + ++++ +** New 'declare' form 'interactive-args'. +This can be used to specify what forms to put into 'command-history' +when executing commands interactively. + ++++ +** The FORM argument of 'time-convert' is mandatory. +'time-convert' can still be called without it, as before, but the +compiler now emits a warning about this deprecated usage. + ++++ +** Emacs now supports user-customizable and themable icons. +These can be used for buttons in buffers and the like. See the +"(elisp) Icons" and "(emacs) Icons" nodes in the manuals for details. + ++++ +** New arguments MESSAGE and TIMEOUT of 'set-transient-map'. +MESSAGE specifies a message to display after activating the transient +map, including a special formatting spec to list available keys. +TIMEOUT is the idle time after which to deactivate the transient map. +The default timeout value can be defined by the new variable +'set-transient-map-timeout'. + +** Connection Local Variables + ++++ +*** Some connection-local variables are now user options. +The variables 'connection-local-profile-alist' and +'connection-local-criteria-alist' are now user options, in order to +make it more convenient to inspect and modify them. + ++++ +*** New function 'connection-local-update-profile-variables'. +This function allows to modify the settings of an existing +connection-local profile. + ++++ +*** New macro 'with-connection-local-application-variables'. +This macro works like 'with-connection-local-variables', but it allows +to use another application but 'tramp'. This is useful when running +code in a buffer where Tramp has already set some connection-local +variables. + ++++ +*** New macro 'setq-connection-local'. +This allows dynamically setting variable values for a particular +connection within the body of 'with-connection-local-{application-}variables'. +See the "(elisp) Connection Local Variables" node in the Lisp +Reference manual for more information. + ++++ +** 'plist-get', 'plist-put' and 'plist-member' are no longer limited to 'eq'. +These function now take an optional comparison PREDICATE argument. + ++++ +** 'read-multiple-choice' can now use long-form answers. + ++++ +** 'M-s c' in 'read-regexp' now toggles case folding. + ++++ +** 'completing-read' now allows a function as its REQUIRE-MATCH argument. +This function is called to see whether what the user has typed is a +match. This is also available from functions that call +'completing-read', like 'read-file-name'. + ++++ +** 'posn-col-row' can now give position data based on windows. +Previously, it reported data only based on the frame. + ++++ +** 'file-expand-wildcards' can now also take a regexp as PATTERN argument. + +--- +** vc-mtn (the VC backend for Monotone) has been made obsolete. + ++++ +** 'gui-set-selection' can specify different values for different data types. +If DATA is a string, then its text properties are searched for values +for each specific data type while the selection is being converted. + +--- +** New eldoc function 'elisp-eldoc-var-docstring-with-value'. +This function includes the current value of the variable in eldoc display +and can be used as a more detailed alternative to 'elisp-eldoc-var-docstring'. + ++++ +** 'save-some-buffers' can now be extended to save other things. +Traditionally, 'save-some-buffers' saved buffers, and also saved +abbrevs. This has been generalized via the +'save-some-buffers-functions' variable, and packages can now register +things to be saved. + ++++ +** New function 'string-equal-ignore-case'. +This compares strings ignoring case differences. + ++++ +** 'symbol-file' can now report natively-compiled ".eln" files. +If Emacs was built with native-compilation enabled, Lisp programs can +now call 'symbol-file' with the new optional 3rd argument non-nil to +request the name of the ".eln" file which defined a given symbol. + ++++ +** New macro 'with-memoization' provides a very primitive form of memoization. + ++++ +** 'max-char' can now report the maximum codepoint according to Unicode. +When called with a new optional argument UNICODE non-nil, 'max-char' +will now report the maximum valid codepoint defined by the Unicode +Standard. + +** Seq + ++++ +*** New function 'seq-split'. +This returns a list of sub-sequences of the specified sequence. + ++++ +*** New function 'seq-remove-at-position'. +This function returns a copy of the specified sequence where the +element at a given (zero-based) index got removed. + ++++ +*** New function 'seq-positions'. +This returns a list of the (zero-based) indices of elements matching a +given predicate in the specified sequence. + ++++ +*** New function 'seq-keep'. +This is like 'seq-map', but removes all nil results from the returned +list. + +** Themes + +--- +*** New hooks 'enable-theme-functions' and 'disable-theme-functions'. +These are run after enabling and disabling a theme, respectively. + +--- +*** Themes can now be made obsolete. +Using 'make-obsolete' on a theme is now supported. This will make +'load-theme' issue a warning when loading the theme. + ++++ +** New hook 'display-monitors-changed-functions'. +It is called whenever the configuration of different monitors on a +display changes. + ++++ +** 'prin1' and 'prin1-to-string' now take an optional OVERRIDES argument. +This argument can be used to override values of print-related settings. + ++++ +** New minor mode 'header-line-indent-mode'. +This is meant to be used in modes that have a header line that should +be kept aligned with the buffer contents when the user switches +'display-line-numbers-mode' on or off. + ++++ +** New global minor mode 'lost-selection-mode'. +This global minor mode makes Emacs deactivate the mark in all buffers +when the primary selection is obtained by another program. + +--- +** On X, Emacs will try to preserve selection ownership when a frame is deleted. +This means that if you make Emacs the owner of a selection, such as by +selecting some text into the clipboard or primary selection, and then +delete the current frame, you will still be able to insert the +contents of that selection into other programs as long as another +frame is open on the same display. This behavior can be disabled by +setting the user option 'x-auto-preserve-selections' to nil. + ++++ +** New predicate 'char-uppercase-p'. +This returns non-nil if its argument its an uppercase character. + +** Byte Compilation + +--- +*** Byte compilation will now warn about some quoting mistakes in docstrings. +When writing code snippets that contains the "'" character (APOSTROPHE), +that quote character has to be escaped to avoid Emacs displaying it as +"’" (LEFT SINGLE QUOTATION MARK), which would make code examples like + + (setq foo '(1 2 3)) + +invalid. Emacs will now warn during byte compilation if it seems +something like that, and also warn about when using RIGHT/LEFT SINGLE +QUOTATION MARK directly. In both these cases, if these characters +should really be present in the docstring, they should be quoted with +"\=". + +--- +*** Byte compilation will now warn about some malformed 'defcustom' types. +It is very common to write 'defcustom' types on the form: + + :type '(choice (const :tag "foo" 'bar)) + +I.e., double-quoting the 'bar', which is almost never the correct +value. The byte compiler will now issue a warning if it encounters +these forms. + ++++ +** 'restore-buffer-modified-p' can now alter buffer auto-save state. +With a FLAG value of 'autosaved', it will mark the buffer as having +been auto-saved since the time of last modification. + +--- +** New minor mode 'isearch-fold-quotes-mode'. +This sets up 'search-default-mode' so that quote characters are +char-folded into each other. It is used, by default, in "*Help*" and +"*info*" buffers. + ++++ +** New macro 'buffer-local-set-state'. +This is a helper macro to be used by minor modes that wish to restore +buffer-local variables back to their original states when the mode is +switched off. + +--- +** New macro 'with-buffer-unmodified-if-unchanged'. +If the buffer is marked as unmodified, and code does modifications +that, in total, means that the buffer is identical to the buffer +before, mark the buffer as unmodified again. + +--- +** New function 'malloc-trim'. +This function allows returning unused memory back to the operating +system, and is mainly meant as a debugging tool. It is currently +available only when Emacs was built with glibc as the C library. + +--- +** 'x-show-tip' no longer hard-codes a timeout default. +The new variable 'x-show-tooltip-timeout' allows the user to alter +this for packages that don't use 'tooltip-show', but instead call the +lower level function directly. + +--- +** New function 'current-cpu-time'. +It gives access to the CPU time used by the Emacs process, for +example for benchmarking purposes. + +--- +** New function 'string-edit'. +This is meant to be used when the user has to edit a (potentially) +long string. It pops up a new buffer where you can edit the string, +and a callback is called when the user types 'C-c C-c'. + ++++ +** New function 'read-string-from-buffer'. +This is a modal version of 'string-edit', and can be used as an +alternative to 'read-string'. + ++++ +** The return value of 'clear-message-function' is not ignored anymore. +If the function returns 'dont-clear-message', then the message is not +cleared, with the assumption that the function cleared it itself. + ++++ +** The local variables section now supports defining fallback modes. +This was previously only available when using a property line (i.e., +putting the modes on the first line of a file). + ++++ +** New function 'flush-standard-output'. +This enables display of lines that don't end in a newline from +batch-based Emacs scripts. + ++++ +** New convenience function 'buttonize-region'. +This works like 'buttonize', but for a region instead of a string. + ++++ +** 'macroexp-let2*' can omit TEST argument and use single-var bindings. + ++++ +** New macro-writing macros, 'cl-with-gensyms' and 'cl-once-only'. +See the "(cl) Macro-Writing Macros" manual section for descriptions. + ++++ +** New variable 'last-event-device' and new function 'device-class'. +On X Windows, 'last-event-device' specifies the input extension device +from which the last input event originated, and 'device-class' can be +used to determine the type of an input device. + ++++ +** Variable 'track-mouse' can have a new value 'drag-source'. +This means the same as 'dropping', but modifies the mouse position +list in reported motion events if there is no frame underneath the +mouse pointer. + ++++ +** New functions for dragging items from Emacs to other programs. +The new functions 'x-begin-drag', 'dnd-begin-file-drag', +'dnd-begin-drag-files', and 'dnd-direct-save' allow dragging contents +(such as files and text) from Emacs to other programs. + +--- +** New function 'ietf-drums-parse-date-string'. +This function parses RFC5322 (and RFC822) date strings, and should be +used instead of 'parse-time-string' when parsing data that's standards +compliant. + ++++ +** New macro 'setopt'. +This is like 'setq', but is meant to be used for user options instead +of plain variables, and uses 'custom-set'/'set-default' to set them. + ++++ +** New utility predicate 'mode-line-window-selected-p'. +This is meant to be used from ':eval' mode line constructs to create +different mode line looks for selected and unselected windows. + ++++ +** New variable 'messages-buffer-name'. +This variable (defaulting to "*Messages*") allows packages to override +where messages are logged. + ++++ +** New function 'readablep'. +This function says whether an object can be written out and then +read back by the Emacs Lisp reader. + ++++ +** New variable 'print-unreadable-function'. +This variable allows changing how Emacs prints unreadable objects. + +--- +** The user option 'polling-period' now accepts floating point values. +This means Emacs can now poll for input during Lisp execution more +frequently than once in a second. + +--- +** New function 'bidi-string-strip-control-characters'. +This utility function is meant for displaying strings when it is +essential that there's no bidirectional context. It removes all the +bidirectional formatting control characters (such as RLM, LRO, PDF, +etc.) from its argument string. The characters it removes are listed +in the value of 'bidi-control-characters'. + +--- +** The Gnus range functions have been moved to a new library, range.el. +All the old names have been made obsolete. + ++++ +** 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. + ++++ +** New facility for handling session state: 'multisession-value'. +This can be used as a convenient way to store (simple) application +state, and the command 'list-multisession-values' allows users to list +(and edit) this data. + ++++ +** New function 'get-display-property'. +This is like 'get-text-property', but works on the 'display' text +property. + ++++ +** New function 'add-display-text-property'. +This is like 'put-text-property', but works on the 'display' text +property. + ++++ +** New 'min-width' 'display' property. +This allows setting a minimum display width for a region of text. + ++++ +** New 'cursor-face' text property. +This uses 'cursor-face' instead of the default face when cursor is on or +near the character and 'cursor-face-highlight-mode' is enabled. The +user option 'cursor-face-highlight-nonselected-window' is similar to +'highlight-nonselected-windows', but for this property. + ++++ +** New event type 'touch-end'. +This event is sent whenever the user's finger moves off the mouse +wheel on some mice, or when the user's finger moves off the touchpad. + ++++ +** New event type 'pinch'. +This event is sent when a user performs a pinch gesture on a touchpad, +which is comprised of placing two fingers on the touchpad and moving +them towards or away from each other. + ++++ +** New hook 'x-pre-popup-menu-hook'. +This hook, run before 'x-popup-menu', is about to display a +deck-of-cards menu on screen. + +--- +** New hook 'post-select-region-hook'. +This hook is run immediately after 'select-active-regions'. It causes +the region to be set as the primary selection. + ++++ +** New function 'buffer-match-p'. +Check if a buffer satisfies some condition. Some examples for +conditions can be regular expressions that match a buffer name, a +cons-cell like '(major-mode . shell-mode)' that matches any buffer +where 'major-mode' is 'shell-mode' or a combination with a condition +like '(and "\\`\\*.+\\*\\'" (major-mode . special-mode))'. + ++++ +** New function 'match-buffers'. +It uses 'buffer-match-p' to gather a list of buffers that match a +condition. + +--- +** New optional arguments TEXT-FACE and DEFAULT-FACE for 'tooltip-show'. +They allow changing the faces used for the tooltip text and frame +colors of the resulting tooltip frame from the default 'tooltip' face. + +** Text Security and Suspiciousness + ++++ +*** New library textsec.el. +This library contains a number of checks for whether a string is +"suspicious". This usually means that the string contains characters +that have glyphs that can be confused with other, more commonly used +glyphs, or contains bidirectional (or other) formatting characters +that may be used to confuse a user. + ++++ +*** New user option 'textsec-check'. +If non-nil (which is the default), Emacs packages that are vulnerable +to attackers trying to confuse the users will use the textsec library +to mark suspicious text. For instance shr/eww will mark suspicious +URLs and links, Gnus will mark suspicious From addresses, and +Message mode will query the user if the user is sending mail to a +suspicious address. If this variable is nil, these checks are +disabled. + ++++ +*** New function 'textsec-suspicious-p'. +This is the main function Emacs applications should be using to check +whether a string is suspicious. It heeds the 'textsec-check' user +option. + +** Keymaps and Key Definitions + ++++ +*** 'where-is-internal' can now filter events marked as non key events. +If a command maps to a key binding like '[some-event]', and 'some-event' +has a symbol plist containing a non-nil 'non-key-event' property, then +that binding is ignored by 'where-is-internal'. + ++++ +*** New functions for defining and manipulating keystrokes. +These all take the syntax defined by 'key-valid-p'. None of the older +functions have been deprecated or altered, but they are now +de-emphasized in the documentation. + ++++ +*** Use 'keymap-set' instead of 'define-key'. + ++++ +*** Use 'keymap-global-set' instead of 'global-set-key'. + ++++ +*** Use 'keymap-local-set' instead of 'local-set-key'. + ++++ +*** Use 'keymap-global-unset' instead of 'global-unset-key'. + ++++ +*** Use 'keymap-local-unset' instead of 'local-unset-key'. + ++++ +*** Use 'keymap-substitute' instead of 'substitute-key-definition'. + ++++ +*** Use 'keymap-set-after' instead of 'define-key-after'. + ++++ +*** Use 'keymap-lookup' instead of 'lookup-key' and 'key-binding'. + ++++ +*** Use 'keymap-local-lookup' instead of 'local-key-binding'. + ++++ +*** Use 'keymap-global-lookup' instead of 'global-key-binding'. + ++++ +*** 'define-key' now takes an optional REMOVE argument. +If non-nil, remove the definition from the keymap. This is subtly +different from setting a definition to nil (when the keymap has a +parent). + ++++ +*** 'read-multiple-choice' now takes an optional SHOW-HELP argument. +If non-nil, show the help buffer immediately, before any user input. + ++++ +*** New function 'key-valid-p'. +The 'kbd' function is quite permissive, and will try to return +something usable even if the syntax of the argument isn't completely +correct. The 'key-valid-p' predicate does a stricter check of the +syntax. + +--- +*** New function 'key-parse'. +This is like 'kbd', but only returns vectors instead of a mix of +vectors and strings. + ++++ +*** New ':type' for 'defcustom' for keys. +The new 'key' type can be used for options that should be a valid key +according to 'key-valid-p'. The type 'key-sequence' is now obsolete. + ++++ +** New function 'define-keymap'. +This function allows defining a number of keystrokes with one form. + ++++ +** New macro 'defvar-keymap'. +This macro allows defining keymap variables more conveniently. + +** 'defvar-keymap' can specify 'repeat-mode' behavior for the keymap. +Use ':repeat t' to have all bindings be repeatable or for more +advanced usage: + + :repeat (:enter (commands ...) :exit (commands ...)) + +--- +** 'kbd' can now be used in built-in, preloaded libraries. +It no longer depends on edmacro.el and cl-lib.el. + ++++ +** New substitution in docstrings and 'substitute-command-keys'. +Use \\`KEYSEQ' to insert a literal key sequence "KEYSEQ" (for example +\\`C-k') in a docstring or when calling 'substitute-command-keys', +which will use the same face as a command substitution. This should +be used only when a key sequence has no corresponding command, for +example when it is read directly with 'read-key-sequence'. It must be +a valid key sequence according to 'key-valid-p'. + +--- +** 'lookup-key' is more permissive when searching for extended menu items. +In Emacs 28.1, the behavior of 'lookup-key' was changed: when looking +for a menu item '[menu-bar Foo-Bar]', first try to find an exact +match, then look for the lowercased '[menu-bar foo-bar]'. + +This has been extended, so that when looking for a menu item with a +symbol containing spaces, as in '[menu-bar Foo\ Bar]', first look for +an exact match, then the lowercased '[menu-bar foo\ bar]' and finally +'[menu-bar foo-bar]'. This further improves backwards-compatibility +when converting menus to use 'easy-menu-define'. + ++++ +** New function 'file-name-split'. +This returns a list of all the components of a file name. + ++++ +** New function 'file-name-parent-directory'. +This returns the parent directory of a file name. + ++++ +** New macro 'with-undo-amalgamate'. +It records a particular sequence of operations as a single undo step. + ++++ +** New command 'yank-media'. +This command supports yanking non-plain-text media like images and +HTML from other applications into Emacs. It is only supported in +modes that have registered support for it, and only on capable +platforms. + ++++ +** New command 'yank-media-types'. +This command lets you examine all data in the current selection and +the clipboard, and insert it into the buffer. + ++++ +** New variable 'yank-transform-functions'. +This variable allows the user to alter the string to be inserted. + +--- +** New command 'yank-in-context'. +This command tries to preserve string/comment syntax when yanking. + +--- +** New function 'minibuffer-lazy-highlight-setup'. +This function allows setting up the minibuffer so that lazy +highlighting of its content is applied in the original window. + ++++ +** New text property 'inhibit-isearch'. +If set, 'isearch' will skip these areas, which can be useful (for +instance) when covering huge amounts of data (that has no meaningful +searchable data, like image data) with a 'display' text property. + ++++ +** 'insert-image' now takes an INHIBIT-ISEARCH optional argument. +It marks the image with the 'inhibit-isearch' text property, which +inhibits 'isearch' matching the STRING argument. + +--- +** New variable 'replace-regexp-function'. +Function to call to convert the entered FROM string to an Emacs +regexp in 'query-replace' and similar commands. It can be used to +implement a different regexp syntax for search/replace. + +--- +** New variables to customize defaults of FROM for 'query-replace*' commands. +The new variable 'query-replace-read-from-default' can be set to a +function that returns the default value of FROM when 'query-replace' +prompts for a string to be replaced. An example of such a function is +'find-tag-default'. + +The new variable 'query-replace-read-from-regexp-default' can be set +to a function (such as 'find-tag-default-as-regexp') that returns the +default value of FROM when 'query-replace-regexp' prompts for a regexp +whose matches are to be replaced. If these variables are nil (which +is the default), 'query-replace' and 'query-replace-regexp' take the +default value from the previous FROM-TO pair. + +** Lisp pretty-printer ('pp') + +--- +*** New function 'pp-emacs-lisp-code'. +'pp' formats general Lisp sexps. This function does much the same, +but applies formatting rules appropriate for Emacs Lisp code. Note +that this could currently be quite slow, and is thus appropriate only +for relatively small code fragments. + +--- +*** New user option 'pp-use-max-width'. +If non-nil, 'pp' and all 'pp-*' commands that format the results, will +attempt to limit the line length when formatting long lists and +vectors. This uses 'pp-emacs-lisp-code', and thus could be slow for +large lists. + ++++ +** New function 'file-has-changed-p'. +This convenience function is useful when writing code that parses +files at run-time, and allows Lisp programs to re-parse files only +when they have changed. + ++++ +** 'abbreviate-file-name' now respects magic file name handlers. + +--- +** New function 'font-has-char-p'. +This can be used to check whether a specific font has a glyph for a +character. + ++++ +** 'window-text-pixel-size' now accepts a new argument IGNORE-LINE-AT-END. +This controls whether or not the last screen line of the text being +measured will be counted for the purpose of calculating the text +dimensions. + ++++ +** 'window-text-pixel-size' understands a new meaning of FROM. +Specifying a cons as the FROM argument allows to start measuring text +from a specified amount of pixels above or below a position. + ++++ +** 'window-body-width' and 'window-body-height' can use remapped faces. +Specifying 'remap' as the PIXELWISE argument now checks if the default +face was remapped, and if so, uses the remapped face to determine the +character width/height. + ++++ +** 'set-window-vscroll' now accepts a new argument PRESERVE-VSCROLL-P. +This means the vscroll will not be reset when set on a window that is +"frozen" due to a mini-window being resized. + +** XDG Support + +--- +*** New function 'xdg-state-home'. +It returns the new 'XDG_STATE_HOME' environment variable. It should +point to a file name that "contains state data that should persist +between (application) restarts, but that is not important or portable +enough to the user that it should be stored in $XDG_DATA_HOME". +(This variable was introduced in the XDG Base Directory Specification +version 0.8 released on May 8, 2021.) + +--- +*** New function 'xdg-current-desktop'. +It returns a list of strings, corresponding to the colon-separated +list of names in the 'XDG_CURRENT_DESKTOP' environment variable, which +identify the current desktop environment. +(This variable was introduced in XDG Desktop Entry Specification +version 1.2.) + +--- +*** New function 'xdg-session-type'. +It returns the 'XDG_SESSION_TYPE' environment variable. (This is not +part of any official standard; see the man page pam_systemd(8) for +more information.) + ++++ +** New macro 'with-delayed-message'. +This macro is like 'progn', but will output the specified message if +the body takes longer to execute than the specified timeout. + +--- +** New function 'funcall-with-delayed-message'. +This function is like 'funcall', but will output the specified message +if the function takes longer to execute than the specified timeout. + +** Locale + +--- +*** New variable 'current-locale-environment'. +This holds the value of the previous call to 'set-locale-environment'. + +--- +*** New macro 'with-locale-environment'. +This macro can be used to change the locale temporarily while +executing code. + +** Table + +--- +*** New user option 'table-latex-environment'. +This allows switching between "table" and "tabular". + +** Tabulated List Mode + ++++ +*** A column can now be set to an image descriptor. +The 'tabulated-list-entries' variable now supports using an image +descriptor, which means to insert an image in that column instead of +text. See the documentation string of that variable for details. + ++++ +** ':keys' in 'menu-item' can now be a function. +If so, it is called whenever the menu is computed, and can be used to +calculate the keys dynamically. + ++++ +** New major mode 'clean-mode'. +This is a new major mode meant for debugging. It kills absolutely all +local variables and removes overlays and text properties. + ++++ +** 'kill-all-local-variables' can now kill all local variables. +If given the new optional KILL-PERMANENT argument, it also kills +permanent local variables. + ++++ +** Third 'mapconcat' argument SEPARATOR is now optional. +An explicit nil always meant the empty string, now it can be left out. + ++++ +** New function 'image-at-point-p'. +This function returns t if point is on a valid image, and nil +otherwise. + ++++ +** New function 'buffer-text-pixel-size'. +This is similar to 'window-text-pixel-size', but can be used when the +buffer isn't displayed. + ++++ +** New function 'string-pixel-width'. +This returns the width of a string in pixels. This can be useful when +dealing with variable pitch fonts and glyphs that have widths that +aren't integer multiples of the default font. + ++++ +** New function 'string-glyph-split'. +This function splits a string into a list of strings representing +separate glyphs. This takes into account combining characters and +grapheme clusters, by treating each sequence of characters composed on +display as a single unit. + +** Xwidget + ++++ +*** The function 'make-xwidget' now accepts an optional RELATED argument. +This argument is used as another widget for the newly created WebKit +widget to share settings and subprocesses with. It must be another +WebKit widget. + ++++ +*** New function 'xwidget-perform-lispy-event'. +This function allows you to send events to xwidgets. Usually, some +equivalent of the event will be sent, but there is no guarantee of +what the widget will actually receive. + +On GTK+, only key and function key events are implemented. + ++++ +*** New function 'xwidget-webkit-load-html'. +This function is used to load HTML text into WebKit xwidgets +directly, in contrast to creating a temporary file to hold the +markup, and passing the URI of the file as an argument to +'xwidget-webkit-goto-uri'. + ++++ +*** New functions for performing searches on WebKit xwidgets. +Some new functions, such as 'xwidget-webkit-search', have been added +for performing searches on WebKit xwidgets. + ++++ +*** New function 'xwidget-webkit-back-forward-list'. +This function returns the history of page-loads in a WebKit xwidget. + ++++ +*** New function 'xwidget-webkit-estimated-load-progress'. +This function returns the estimated progress of page loading in a +WebKit xwidget. + ++++ +*** New function 'xwidget-webkit-stop-loading'. +This function terminates all data transfer during page loads in a +WebKit xwidget. + ++++ +*** 'load-changed' xwidget events are now more detailed. +In particular, they can now have different arguments based on the +state of the WebKit widget. 'load-finished' is sent when a load has +completed, 'load-started' when a load first starts, 'load-redirected' +after a redirect, and 'load-committed' when the WebKit widget first +commits to the load. + ++++ +*** New event type 'xwidget-display-event'. +These events are sent whenever an xwidget requests that Emacs displays +another xwidget. The only arguments to this event are the xwidget +that should be displayed, and the xwidget that asked to display it. + ++++ +*** New function 'xwidget-webkit-set-cookie-storage-file'. +This function is used to control where and if an xwidget stores +cookies set by web pages on disk. + +--- +** New variable 'help-buffer-under-preparation'. +This variable is bound to t during the preparation of a "*Help*" buffer. + ++++ +** Timestamps like '(1 . 1000)' now work without warnings being generated. +For example, '(time-add nil '(1 . 1000))' no longer warns that the +'(1 . 1000)' acts like '(1000 . 1000000)'. This warning, which was a +temporary transition aid for Emacs 27, has served its purpose. + ++++ +** 'encode-time' now also accepts a 6-element list with just time and date. +'(encode-time (list SECOND MINUTE HOUR DAY MONTH YEAR))' is now short for +'(encode-time (list SECOND MINUTE HOUR DAY MONTH YEAR nil -1 nil))'. + ++++ +** 'date-to-time' now accepts arguments that lack month, day, or time. +The function now assumes the earliest possible values if its argument +lacks month, day, or time. For example, (date-to-time "2021-12-04") +now assumes a time of "00:00" instead of signaling an error. + ++++ +** 'format-seconds' now allows suppressing zero-value trailing elements. +The new "%x" non-printing control character will suppress zero-value +elements that appear after "%x". + ++++ +** New events for taking advantage of touchscreen devices. +The events 'touchscreen-begin', 'touchscreen-update', and +'touchscreen-end' have been added to take better advantage of +touch-capable display panels. + ++++ +** New error symbol 'permission-denied'. +This is a subcategory of 'file-error', and is signaled when some file +operation fails because the OS doesn't allow Emacs to access a file or +a directory. + ++++ +** The ':underline' face attribute now accepts a new property. +The property ':position' now specifies the position of the underline +when used as part of a property list specification for the +':underline' attribute. + ++++ +** 'defalias' records a more precise history of definitions. +This is recorded in the 'function-history' symbol property. + +--- +** New hook 'save-place-after-find-file-hook'. +This is called at the end of 'save-place-find-file-hook'. + +--- +** 'indian-tml-base-table' no longer translates digits. +Use 'indian-tml-base-digits-table' if you want digits translation. + +--- +** 'indian-tml-itrans-v5-hash' no longer translates digits. +Use 'indian-tml-itrans-digits-v5-hash' if you want digits +translation. + ++++ +** 'shell-quote-argument' has a new optional argument POSIX. +This is useful when quoting shell arguments for a remote shell +invocation. Such shells are POSIX conformant by default. + ++++ +** 'make-process' can set connection type independently for input and output. +When calling 'make-process', communication via pty can be enabled +selectively for just input or output by passing a cons cell for +':connection-type', e.g. '(pipe . pty)'. When examining a process +later, you can determine whether a particular stream for a process +uses a pty by passing one of 'stdin', 'stdout', or 'stderr' as the +second argument to 'process-tty-name'. + ++++ +** 'signal-process' now consults the list 'signal-process-functions'. +This is to determine which function has to be called in order to +deliver the signal. This allows Tramp to send the signal to remote +asynchronous processes. The hitherto existing implementation has been +moved to 'internal-default-signal-process'. + ++++ +** Some system information functions honor remote systems now. +'list-system-processes' returns remote process IDs. +'memory-info' returns memory information of remote systems. +'process-attributes' expects a remote process ID. +This happens only when the current buffer's 'default-directory' is +remote. In order to preserve the old behavior, bind +'default-directory' to a local directory, like + + (let ((default-directory temporary-file-directory)) + (list-system-processes)) + ++++ +** New functions 'take' and 'ntake'. +'(take N LIST)' returns the first N elements of LIST; 'ntake' does +the same but works by modifying LIST destructively. + +--- +** 'string-split' is now an alias for 'split-string'. + ++++ +** 'format-spec' now accepts functions in the replacement. +The function is called only when used in the format string. This is +useful to avoid side-effects such as prompting, when the value is not +actually being used for anything. + ++++ +** The variable 'max-specpdl-size' has been made obsolete. +Now 'max-lisp-eval-depth' alone is used for limiting Lisp recursion +and stack usage. 'max-specpdl-size' is still present as a plain +variable for compatibility but its limiting powers have been taken away. + +** New function 'external-completion-table'. +This function returns a completion table designed to ease +communication between Emacs's completion facilities and external tools +offering completion services, particularly tools whose full working +set is too big to transfer to Emacs every time a completion is +needed. The table uses new 'external' completion style exclusively +and cannot work with regular styles such as 'basic' or 'flex'. + ++++ +** Magic file name handlers for 'make-directory-internal' are no longer needed. +Instead, Emacs uses the already-existing 'make-directory' handlers. + ++++ +** '(make-directory DIR t)' returns non-nil if DIR already exists. +This can let a caller know whether it created DIR. Formerly, +'make-directory's return value was unspecified. + + +* Changes in Emacs 29.1 on Non-Free Operating Systems + +** MS-Windows + +--- +*** Emacs now supports double-buffering on MS-Windows to reduce display flicker. +(This was supported on Free systems since Emacs 26.1.) + +To disable double-buffering (e.g., if it causes display problems), set +the frame parameter 'inhibit-double-buffering' to a non-nil value. +You can do that either by adding + + '(inhibit-double-buffering . t) + +to 'default-frame-alist', or by modifying the frame parameters of the +selected frame by evaluating + + (modify-frame-parameters nil '((inhibit-double-buffering . t))) + ++++ +*** Emacs now supports system dark mode. +On Windows 10 (version 1809 and higher) and Windows 11, Emacs will now +follow the system's dark mode: GUI frames use the appropriate light or +dark title bar and scroll bars, based on the user's Windows-wide color +settings. + +--- +*** Emacs now uses native image APIs to display some image formats. +On Windows 2000 and later, Emacs now defaults to using the native +image APIs for displaying the BMP, GIF, JPEG, PNG, and TIFF images. +This means Emacs on MS-Windows needs no longer use external image +support libraries to display those images. Other image types -- XPM, +SVG, and WEBP -- still need support libraries for Emacs to be able to +display them. + +The use of native image APIs is controlled by the variable +'w32-use-native-image-API', whose value now defaults to t on systems +where those APIs are available. + ++++ +*** Emacs now supports display of BMP images using native image APIs. +When 'w32-use-native-image-API' is non-nil, Emacs on MS-Windows now +has built-in support for displaying BMP images. + +--- +*** GUI Yes/No dialogs now include a "Cancel" button. +The "Cancel" button is in addition to "Yes" and "No", and is intended +to allow users to quit the dialog, as an equivalent of 'C-g' when Emacs +asks a yes/no question via the echo area. This is controlled by the +new variable 'w32-yes-no-dialog-show-cancel', by default t. Set it to +nil to get back the old behavior of showing a modal dialog with only +two buttons: "Yes" and "No". + +** Cygwin + +--- +*** 'process-attributes' is now implemented. + + +---------------------------------------------------------------------- +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/>. + + +Local variables: +coding: utf-8 +mode: outline +mode: emacs-news +paragraph-separate: "[ ]" +end: diff --git a/etc/PROBLEMS b/etc/PROBLEMS index 69c42e9bed0..9ef231d4b16 100644 --- a/etc/PROBLEMS +++ b/etc/PROBLEMS @@ -1239,6 +1239,20 @@ you should use an Emacs input method instead. * X runtime problems +** X security problems + +*** Emacs faces trouble when running as an untrusted client. + +When Emacs is running as an untrusted client under X servers with the +Security extension, it is unable to use some window manager features +but reports them to the window manager anyway. This can lead to +constant prompting by the window manager about Emacs being +unresponsive. To resolve the problem, place: + + (setq x-detect-server-trust t) + +in your early-init.el. + ** X keyboard problems *** `x-focus-frame' fails to activate the frame. @@ -1710,8 +1724,8 @@ which can be carried out at the same time: 7) If selecting text with the mouse is slow, the main culprit is likely `select-active-regions', coupled with a program monitoring - the clipboard on the X server you are connected to. Try turning - that off. + the clipboard or primary selection on the X server you are + connected to. Try turning that off. However, over networks with moderate to high latency, with no clipboard monitor running, the bottleneck is likely to be @@ -1721,6 +1735,12 @@ which can be carried out at the same time: cause Emacs features that relies on accurate mouse position reporting to stop working reliably. +8) If creating or resizing frames is slow, turn off + `frame-resize-pixelwise' (this will not take effect until you + create a new frame); then, enable `x-lax-frame-positioning'. This + means frame placement will be less accurate, but makes frame + creation, movement, and resize visibly faster. + *** Emacs gives the error, Couldn't find per display information. This can result if the X server runs out of memory because Emacs uses diff --git a/etc/publicsuffix.txt b/etc/publicsuffix.txt index 60d72fd0d53..54988c7187c 100644 --- a/etc/publicsuffix.txt +++ b/etc/publicsuffix.txt @@ -7171,7 +7171,7 @@ org.zw // newGTLDs -// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2022-11-29T15:14:18Z +// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2022-12-07T15:13:11Z // This list is auto-generated, don't edit it manually. // aaa : 2015-02-26 American Automobile Association, Inc. aaa @@ -10461,9 +10461,6 @@ xin // xn--jlq480n2rg : 2019-12-19 Amazon Registry Services, Inc. 亚马逊 -// xn--jlq61u9w7b : 2015-01-08 Nokia Corporation -诺基亚 - // xn--jvr189m : 2015-02-26 Amazon Registry Services, Inc. 食品 diff --git a/etc/refcards/ru-refcard.tex b/etc/refcards/ru-refcard.tex index 3124ce4f7c7..815a2db2f6d 100644 --- a/etc/refcards/ru-refcard.tex +++ b/etc/refcards/ru-refcard.tex @@ -40,7 +40,7 @@ \newlength{\ColThreeWidth} \setlength{\ColThreeWidth}{25mm} -\newcommand{\versionemacs}[0]{29} % version of Emacs this is for +\newcommand{\versionemacs}[0]{30} % version of Emacs this is for \newcommand{\cyear}[0]{2023} % copyright year \newcommand\shortcopyrightnotice[0]{\vskip 1ex plus 2 fill diff --git a/etc/themes/modus-operandi-deuteranopia-theme.el b/etc/themes/modus-operandi-deuteranopia-theme.el new file mode 100644 index 00000000000..2bee995c570 --- /dev/null +++ b/etc/themes/modus-operandi-deuteranopia-theme.el @@ -0,0 +1,420 @@ +;;; modus-operandi-deuteranopia-theme.el --- Elegant, highly legible and customizable light theme -*- lexical-binding:t -*- + +;; Copyright (C) 2019-2023 Free Software Foundation, Inc. + +;; Author: Protesilaos Stavrou <info@protesilaos.com> +;; Maintainer: Modus-Themes Development <~protesilaos/modus-themes@lists.sr.ht> +;; URL: https://git.sr.ht/~protesilaos/modus-themes +;; Mailing-List: https://lists.sr.ht/~protesilaos/modus-themes +;; Keywords: faces, theme, accessibility + +;; 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: +;; +;; The Modus themes conform with the highest standard for +;; color-contrast accessibility between background and foreground +;; values (WCAG AAA). Please refer to the official Info manual for +;; further documentation (distributed with the themes, or available +;; at: <https://protesilaos.com/emacs/modus-themes>). + +;;; Code: + + + +(eval-and-compile + (unless (and (fboundp 'require-theme) + load-file-name + (equal (file-name-directory load-file-name) + (expand-file-name "themes/" data-directory)) + (require-theme 'modus-themes t)) + (require 'modus-themes)) + + (deftheme modus-operandi-deuteranopia + "Elegant, highly legible and customizable light theme. +This variant is optimized for users with red-green color +deficiency (deuteranopia). It conforms with the highest +legibility standard for color contrast between background and +foreground in any given piece of text, which corresponds to a +minimum contrast in relative luminance of 7:1 (WCAG AAA +standard).") + + (defconst modus-operandi-deuteranopia-palette + '( +;;; Basic values + + (bg-main "#ffffff") + (bg-dim "#f0f0f0") + (fg-main "#000000") + (fg-dim "#595959") + (fg-alt "#193668") + (bg-active "#c4c4c4") + (bg-inactive "#e0e0e0") + (border "#9f9f9f") + +;;; Common accent foregrounds + + (red "#a60000") + (red-warmer "#972500") + (red-cooler "#a0132f") + (red-faint "#7f0000") + (red-intense "#d00000") + (green "#006800") + (green-warmer "#316500") + (green-cooler "#00663f") + (green-faint "#2a5045") + (green-intense "#008900") + (yellow "#7b5000") + (yellow-warmer "#884900") + (yellow-cooler "#7a4f2f") + (yellow-faint "#624416") + (yellow-intense "#808000") + (blue "#0031a9") + (blue-warmer "#354fcf") + (blue-cooler "#0000b0") + (blue-faint "#003497") + (blue-intense "#0000ff") + (magenta "#721045") + (magenta-warmer "#8f0075") + (magenta-cooler "#531ab6") + (magenta-faint "#7c318f") + (magenta-intense "#dd22dd") + (cyan "#005e8b") + (cyan-warmer "#3f578f") + (cyan-cooler "#005f5f") + (cyan-faint "#005077") + (cyan-intense "#008899") + +;;; Uncommon accent foregrounds + + (rust "#8a290f") + (gold "#80601f") + (olive "#56692d") + (slate "#2f3f83") + (indigo "#4a3a8a") + (maroon "#731c52") + (pink "#7b435c") + +;;; Common accent backgrounds + + (bg-red-intense "#ff8f88") + (bg-green-intense "#8adf80") + (bg-yellow-intense "#f3d000") + (bg-blue-intense "#bfc9ff") + (bg-magenta-intense "#dfa0f0") + (bg-cyan-intense "#a4d5f9") + + (bg-red-subtle "#ffcfbf") + (bg-green-subtle "#b3fabf") + (bg-yellow-subtle "#fff576") + (bg-blue-subtle "#ccdfff") + (bg-magenta-subtle "#ffddff") + (bg-cyan-subtle "#bfefff") + + (bg-red-nuanced "#fff1f0") + (bg-green-nuanced "#ecf7ed") + (bg-yellow-nuanced "#fff3da") + (bg-blue-nuanced "#f3f3ff") + (bg-magenta-nuanced "#fdf0ff") + (bg-cyan-nuanced "#ebf6fa") + +;;; Uncommon accent backgrounds + + (bg-ochre "#f0e0cc") + (bg-lavender "#dfdbfa") + (bg-sage "#c0e7d4") + +;;; Graphs + + (bg-graph-red-0 "#b0b029") + (bg-graph-red-1 "#e0cab4") + (bg-graph-green-0 "#90b7c0") + (bg-graph-green-1 "#a3dfe5") + (bg-graph-yellow-0 "#ffcf00") + (bg-graph-yellow-1 "#f9ff00") + (bg-graph-blue-0 "#7f9fff") + (bg-graph-blue-1 "#9fc6ff") + (bg-graph-magenta-0 "#b0b0d0") + (bg-graph-magenta-1 "#d0dfdf") + (bg-graph-cyan-0 "#6faad9") + (bg-graph-cyan-1 "#bfe0ff") + +;;; Special purpose + + (bg-completion "#c0deff") + (bg-hover "#97dfed") + (bg-hover-secondary "#f5d0a0") + (bg-hl-line "#d0d6ec") + (bg-region "#bdbdbd") + (fg-region "#000000") + + (bg-char-0 "#7feaff") + (bg-char-1 "#ffaaff") + (bg-char-2 "#dff000") + + (bg-mode-line-active "#d0d6ff") + (fg-mode-line-active "#0f0f0f") + (border-mode-line-active "#4f4f74") + (bg-mode-line-inactive "#e6e6e6") + (fg-mode-line-inactive "#585858") + (border-mode-line-inactive "#a3a3a3") + + (modeline-err "#603a00") + (modeline-warning "#454500") + (modeline-info "#023d92") + + (bg-tab-bar "#dfdfdf") + (bg-tab-current "#ffffff") + (bg-tab-other "#c2c2c2") + +;;; Diffs + + (bg-added "#d5d5ff") + (bg-added-faint "#e6e6ff") + (bg-added-refine "#b5b5ef") + (bg-added-intense "#579acc") + (fg-added "#333399") + (fg-added-intense "#3333cc") + + (bg-changed "#eecfdf") + (bg-changed-faint "#f0dde5") + (bg-changed-refine "#e0b0d0") + (bg-changed-intense "#9f7abf") + (fg-changed "#6f1343") + (fg-changed-intense "#7f1f5f") + + (bg-removed "#fff585") + (bg-removed-faint "#f2f2bb") + (bg-removed-refine "#f0e068") + (bg-removed-intense "#d7c20a") + (fg-removed "#553d00") + (fg-removed-intense "#655000") + +;;; Paren match + + (bg-paren-match "#5fcfff") + (bg-paren-expression "#efd3f5") + (underline-paren-match unspecified) + +;;; Mappings + +;;;; General mappings + + (fringe bg-dim) + (cursor blue-intense) + + (keybind blue-cooler) + (name blue-cooler) + (identifier yellow-faint) + + (err yellow-warmer) + (warning yellow-cooler) + (info blue) + + (underline-err yellow-intense) + (underline-warning magenta-faint) + (underline-note cyan) + +;;;; Code mappings + + (builtin magenta-warmer) + (comment yellow) + (constant blue-cooler) + (docstring green-faint) + (docmarkup magenta-faint) + (fnname magenta) + (keyword magenta-cooler) + (preprocessor red-cooler) + (string blue-warmer) + (type cyan-cooler) + (variable cyan) + (rx-construct yellow-cooler) + (rx-backslash blue-cooler) + +;;;; Accent mappings + + (accent-0 blue) + (accent-1 yellow-warmer) + (accent-2 cyan) + (accent-3 magenta-cooler) + +;;;; Button mappings + + (fg-button-active fg-main) + (fg-button-inactive fg-dim) + (bg-button-active bg-active) + (bg-button-inactive bg-dim) + +;;;; Completion mappings + + (fg-completion-match-0 blue) + (fg-completion-match-1 yellow-warmer) + (fg-completion-match-2 cyan) + (fg-completion-match-3 magenta-cooler) + (bg-completion-match-0 unspecified) + (bg-completion-match-1 unspecified) + (bg-completion-match-2 unspecified) + (bg-completion-match-3 unspecified) + +;;;; Date mappings + + (date-common cyan) + (date-deadline yellow-warmer) + (date-event fg-alt) + (date-holiday yellow-warmer) + (date-now blue-faint) + (date-scheduled yellow-cooler) + (date-weekday cyan) + (date-weekend yellow-faint) + +;;;; Line number mappings + + (fg-line-number-inactive fg-dim) + (fg-line-number-active fg-main) + (bg-line-number-inactive bg-dim) + (bg-line-number-active bg-active) + +;;;; Link mappings + + (fg-link blue-warmer) + (bg-link unspecified) + (underline-link blue-warmer) + + (fg-link-symbolic cyan) + (bg-link-symbolic unspecified) + (underline-link-symbolic cyan) + + (fg-link-visited yellow-faint) + (bg-link-visited unspecified) + (underline-link-visited yellow-faint) + +;;;; Mail mappings + + (mail-cite-0 blue-warmer) + (mail-cite-1 yellow) + (mail-cite-2 blue-cooler) + (mail-cite-3 yellow-faint) + (mail-part blue) + (mail-recipient blue) + (mail-subject yellow-warmer) + (mail-other cyan-faint) + +;;;; Prompt mappings + + (fg-prompt blue) + (bg-prompt unspecified) + +;;;; Prose mappings + + (prose-block fg-dim) + (prose-code cyan-cooler) + (prose-done blue) + (prose-macro magenta-cooler) + (prose-metadata fg-dim) + (prose-metadata-value fg-alt) + (prose-table fg-alt) + (prose-tag magenta-faint) + (prose-todo yellow-warmer) + (prose-verbatim magenta-warmer) + +;;;; Rainbow mappings + + (rainbow-0 blue) + (rainbow-1 yellow) + (rainbow-2 blue-warmer) + (rainbow-3 yellow-cooler) + (rainbow-4 blue-cooler) + (rainbow-5 yellow-warmer) + (rainbow-6 blue-faint) + (rainbow-7 yellow-faint) + (rainbow-8 cyan) + +;;;; Heading mappings + + (fg-heading-0 cyan-cooler) + (fg-heading-1 fg-main) + (fg-heading-2 yellow-faint) + (fg-heading-3 fg-alt) + (fg-heading-4 magenta) + (fg-heading-5 green-faint) + (fg-heading-6 red-faint) + (fg-heading-7 cyan-warmer) + (fg-heading-8 fg-dim) + + (bg-heading-0 unspecified) + (bg-heading-1 unspecified) + (bg-heading-2 unspecified) + (bg-heading-3 unspecified) + (bg-heading-4 unspecified) + (bg-heading-5 unspecified) + (bg-heading-6 unspecified) + (bg-heading-7 unspecified) + (bg-heading-8 unspecified) + + (overline-heading-0 unspecified) + (overline-heading-1 unspecified) + (overline-heading-2 unspecified) + (overline-heading-3 unspecified) + (overline-heading-4 unspecified) + (overline-heading-5 unspecified) + (overline-heading-6 unspecified) + (overline-heading-7 unspecified) + (overline-heading-8 unspecified)) + "The entire palette of the `modus-operandi-deuteranopia' theme. + +Named colors have the form (COLOR-NAME HEX-VALUE) with the former +as a symbol and the latter as a string. + +Semantic color mappings have the form (MAPPING-NAME COLOR-NAME) +with both as symbols. The latter is a named color that already +exists in the palette and is associated with a HEX-VALUE. + +Semantic color mappings cannot be recursive: their value must be +either COLOR-NAME or HEX-VALUE.") + + (defcustom modus-operandi-deuteranopia-palette-overrides nil + "Overrides for `modus-operandi-deuteranopia-palette'. + +Mirror the elements of the aforementioned palette, overriding +their value. + +For overrides that are shared across all of the Modus themes, +refer to `modus-themes-common-palette-overrides'. + +Theme-specific overrides take precedence over shared overrides. +The idea of common overrides is to change semantic color +mappings, such as to make the cursor red. Wherea theme-specific +overrides can also be used to change the value of a named color, +such as what hexadecimal RGB value the red-warmer symbol +represents." + :group 'modus-themes + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :type '(repeat (list symbol (choice symbol string))) + :set #'modus-themes--set-option + :initialize #'custom-initialize-default + :link '(info-link "(modus-themes) Palette overrides")) + + (modus-themes-theme modus-operandi-deuteranopia + modus-operandi-deuteranopia-palette + modus-operandi-deuteranopia-palette-overrides) + + (provide-theme 'modus-operandi-deuteranopia)) + +;;;###theme-autoload +(put 'modus-operandi-deuteranopia 'theme-properties '(:background-mode light :kind color-scheme :family modus)) + +;;; modus-operandi-deuteranopia-theme.el ends here diff --git a/etc/themes/modus-operandi-theme.el b/etc/themes/modus-operandi-theme.el index 0d258a26bc8..09ca8888073 100644 --- a/etc/themes/modus-operandi-theme.el +++ b/etc/themes/modus-operandi-theme.el @@ -1,13 +1,11 @@ ;;; modus-operandi-theme.el --- Elegant, highly legible and customizable light theme -*- lexical-binding:t -*- -;; Copyright (C) 2019-2023 Free Software Foundation, Inc. +;; Copyright (C) 2019-2023 Free Software Foundation, Inc. ;; Author: Protesilaos Stavrou <info@protesilaos.com> ;; Maintainer: Modus-Themes Development <~protesilaos/modus-themes@lists.sr.ht> ;; URL: https://git.sr.ht/~protesilaos/modus-themes ;; Mailing-List: https://lists.sr.ht/~protesilaos/modus-themes -;; Version: 3.0.0 -;; Package-Requires: ((emacs "27.1")) ;; Keywords: faces, theme, accessibility ;; This file is part of GNU Emacs. @@ -27,26 +25,11 @@ ;;; Commentary: ;; -;; Modus Operandi is the light variant of the Modus themes (Modus -;; Vivendi is the dark one). The themes are designed for color-contrast -;; accessibility. More specifically: -;; -;; 1. Provide a consistent minimum contrast ratio between background -;; and foreground values of 7:1 or higher. This meets the highest -;; such accessibility criterion per the guidelines of the Worldwide -;; Web Consortium's Working Group on Accessibility (WCAG AAA -;; standard). -;; -;; 2. Offer as close to full face coverage as possible. The list is -;; already quite long, with more additions to follow as part of the -;; ongoing development process. -;; -;; For a complete view of the project, also refer to the following files -;; (should be distributed in the same repository/directory as the -;; current item): -;; -;; - modus-themes.el (Main code shared between the themes) -;; - modus-vivendi-theme.el (Dark theme) +;; The Modus themes conform with the highest standard for +;; color-contrast accessibility between background and foreground +;; values (WCAG AAA). Please refer to the official Info manual for +;; further documentation (distributed with the themes, or available +;; at: <https://protesilaos.com/emacs/modus-themes>). ;;; Code: @@ -67,7 +50,365 @@ between background and foreground in any given piece of text, which corresponds to a minimum contrast in relative luminance of 7:1 (WCAG AAA standard).") - (modus-themes-theme modus-operandi) + (defconst modus-operandi-palette + '( +;;; Basic values + + (bg-main "#ffffff") + (bg-dim "#f0f0f0") + (fg-main "#000000") + (fg-dim "#595959") + (fg-alt "#193668") + (bg-active "#c4c4c4") + (bg-inactive "#e0e0e0") + (border "#9f9f9f") + +;;; Common accent foregrounds + + (red "#a60000") + (red-warmer "#972500") + (red-cooler "#a0132f") + (red-faint "#7f0000") + (red-intense "#d00000") + (green "#006800") + (green-warmer "#316500") + (green-cooler "#00663f") + (green-faint "#2a5045") + (green-intense "#008900") + (yellow "#6f5500") + (yellow-warmer "#884900") + (yellow-cooler "#7a4f2f") + (yellow-faint "#624416") + (yellow-intense "#808000") + (blue "#0031a9") + (blue-warmer "#354fcf") + (blue-cooler "#0000b0") + (blue-faint "#003497") + (blue-intense "#0000ff") + (magenta "#721045") + (magenta-warmer "#8f0075") + (magenta-cooler "#531ab6") + (magenta-faint "#7c318f") + (magenta-intense "#dd22dd") + (cyan "#005e8b") + (cyan-warmer "#3f578f") + (cyan-cooler "#005f5f") + (cyan-faint "#005077") + (cyan-intense "#008899") + +;;; Uncommon accent foregrounds + + (rust "#8a290f") + (gold "#80601f") + (olive "#56692d") + (slate "#2f3f83") + (indigo "#4a3a8a") + (maroon "#731c52") + (pink "#7b435c") + +;;; Common accent backgrounds + + (bg-red-intense "#ff8f88") + (bg-green-intense "#8adf80") + (bg-yellow-intense "#f3d000") + (bg-blue-intense "#bfc9ff") + (bg-magenta-intense "#dfa0f0") + (bg-cyan-intense "#a4d5f9") + + (bg-red-subtle "#ffcfbf") + (bg-green-subtle "#b3fabf") + (bg-yellow-subtle "#fff576") + (bg-blue-subtle "#ccdfff") + (bg-magenta-subtle "#ffddff") + (bg-cyan-subtle "#bfefff") + + (bg-red-nuanced "#fff1f0") + (bg-green-nuanced "#ecf7ed") + (bg-yellow-nuanced "#fff3da") + (bg-blue-nuanced "#f3f3ff") + (bg-magenta-nuanced "#fdf0ff") + (bg-cyan-nuanced "#ebf6fa") + +;;; Uncommon accent backgrounds + + (bg-ochre "#f0e0cc") + (bg-lavender "#dfdbfa") + (bg-sage "#c0e7d4") + +;;; Graphs + + (bg-graph-red-0 "#ef7969") + (bg-graph-red-1 "#ffaab4") + (bg-graph-green-0 "#4faa09") + (bg-graph-green-1 "#8fef00") + (bg-graph-yellow-0 "#ffcf00") + (bg-graph-yellow-1 "#f9ff00") + (bg-graph-blue-0 "#7090ff") + (bg-graph-blue-1 "#9fc6ff") + (bg-graph-magenta-0 "#e07fff") + (bg-graph-magenta-1 "#fad0ff") + (bg-graph-cyan-0 "#70d3f0") + (bg-graph-cyan-1 "#afefff") + +;;; Special purpose + + (bg-completion "#c0deff") + (bg-hover "#94d4ff") + (bg-hover-secondary "#f5d0a0") + (bg-hl-line "#d0d6ec") + (bg-region "#bdbdbd") + (fg-region "#000000") + + (bg-char-0 "#7feaff") + (bg-char-1 "#ffaaff") + (bg-char-2 "#dff000") + + (bg-mode-line-active "#c8c8c8") + (fg-mode-line-active "#000000") + (border-mode-line-active "#5a5a5a") + (bg-mode-line-inactive "#e6e6e6") + (fg-mode-line-inactive "#585858") + (border-mode-line-inactive "#a3a3a3") + + (modeline-err "#7f0000") + (modeline-warning "#5f0070") + (modeline-info "#002580") + + (bg-tab-bar "#dfdfdf") + (bg-tab-current "#ffffff") + (bg-tab-other "#c2c2c2") + +;;; Diffs + + (bg-added "#c1f2d1") + (bg-added-faint "#d8f8e1") + (bg-added-refine "#aee5be") + (bg-added-intense "#8cca8c") + (fg-added "#005000") + (fg-added-intense "#006700") + + (bg-changed "#ffdfa9") + (bg-changed-faint "#ffefbf") + (bg-changed-refine "#fac090") + (bg-changed-intense "#d7c20a") + (fg-changed "#553d00") + (fg-changed-intense "#655000") + + (bg-removed "#ffd8d5") + (bg-removed-faint "#ffe9e9") + (bg-removed-refine "#f3b5af") + (bg-removed-intense "#d84a4f") + (fg-removed "#8f1313") + (fg-removed-intense "#aa2222") + +;;; Paren match + + (bg-paren-match "#5fcfff") + (bg-paren-expression "#efd3f5") + (underline-paren-match unspecified) + +;;; Mappings + +;;;; General mappings + + (fringe bg-dim) + (cursor fg-main) + + (keybind blue-cooler) + (name magenta) + (identifier yellow-cooler) + + (err red) + (warning yellow-warmer) + (info cyan-cooler) + + (underline-err red-intense) + (underline-warning yellow-intense) + (underline-note cyan-intense) + +;;;; Code mappings + + (builtin magenta-warmer) + (comment fg-dim) + (constant blue-cooler) + (docstring green-faint) + (docmarkup magenta-faint) + (fnname magenta) + (keyword magenta-cooler) + (preprocessor red-cooler) + (string blue-warmer) + (type cyan-cooler) + (variable cyan) + (rx-construct green-cooler) + (rx-backslash magenta) + +;;;; Accent mappings + + (accent-0 blue) + (accent-1 magenta-warmer) + (accent-2 cyan) + (accent-3 red) + +;;;; Button mappings + + (fg-button-active fg-main) + (fg-button-inactive fg-dim) + (bg-button-active bg-active) + (bg-button-inactive bg-dim) + +;;;; Completion mappings + + (fg-completion-match-0 blue) + (fg-completion-match-1 magenta-warmer) + (fg-completion-match-2 cyan) + (fg-completion-match-3 red) + (bg-completion-match-0 unspecified) + (bg-completion-match-1 unspecified) + (bg-completion-match-2 unspecified) + (bg-completion-match-3 unspecified) + +;;;; Date mappings + + (date-common cyan) + (date-deadline red) + (date-event fg-alt) + (date-holiday magenta) + (date-now fg-main) + (date-scheduled yellow-warmer) + (date-weekday cyan) + (date-weekend red-faint) + +;;;; Line number mappings + + (fg-line-number-inactive fg-dim) + (fg-line-number-active fg-main) + (bg-line-number-inactive bg-dim) + (bg-line-number-active bg-active) + +;;;; Link mappings + + (fg-link blue-warmer) + (bg-link unspecified) + (underline-link blue-warmer) + + (fg-link-symbolic cyan) + (bg-link-symbolic unspecified) + (underline-link-symbolic cyan) + + (fg-link-visited magenta) + (bg-link-visited unspecified) + (underline-link-visited magenta) + +;;;; Mail mappings + + (mail-cite-0 blue-faint) + (mail-cite-1 yellow-warmer) + (mail-cite-2 cyan-cooler) + (mail-cite-3 red-cooler) + (mail-part cyan) + (mail-recipient magenta-cooler) + (mail-subject magenta-warmer) + (mail-other magenta-faint) + +;;;; Prompt mappings + + (fg-prompt cyan-cooler) + (bg-prompt unspecified) + +;;;; Prose mappings + + (prose-block fg-dim) + (prose-code green-cooler) + (prose-done green) + (prose-macro magenta-cooler) + (prose-metadata fg-dim) + (prose-metadata-value fg-alt) + (prose-table fg-alt) + (prose-tag magenta-faint) + (prose-todo red) + (prose-verbatim magenta-warmer) + +;;;; Rainbow mappings + + (rainbow-0 fg-main) + (rainbow-1 magenta-intense) + (rainbow-2 cyan-intense) + (rainbow-3 red-warmer) + (rainbow-4 yellow-intense) + (rainbow-5 magenta-cooler) + (rainbow-6 green-intense) + (rainbow-7 blue-warmer) + (rainbow-8 magenta-warmer) + +;;;; Heading mappings + + (fg-heading-0 cyan-cooler) + (fg-heading-1 fg-main) + (fg-heading-2 yellow-faint) + (fg-heading-3 fg-alt) + (fg-heading-4 magenta) + (fg-heading-5 green-faint) + (fg-heading-6 red-faint) + (fg-heading-7 cyan-warmer) + (fg-heading-8 fg-dim) + + (bg-heading-0 unspecified) + (bg-heading-1 unspecified) + (bg-heading-2 unspecified) + (bg-heading-3 unspecified) + (bg-heading-4 unspecified) + (bg-heading-5 unspecified) + (bg-heading-6 unspecified) + (bg-heading-7 unspecified) + (bg-heading-8 unspecified) + + (overline-heading-0 unspecified) + (overline-heading-1 unspecified) + (overline-heading-2 unspecified) + (overline-heading-3 unspecified) + (overline-heading-4 unspecified) + (overline-heading-5 unspecified) + (overline-heading-6 unspecified) + (overline-heading-7 unspecified) + (overline-heading-8 unspecified)) + "The entire palette of the `modus-operandi' theme. + +Named colors have the form (COLOR-NAME HEX-VALUE) with the former +as a symbol and the latter as a string. + +Semantic color mappings have the form (MAPPING-NAME COLOR-NAME) +with both as symbols. The latter is a named color that already +exists in the palette and is associated with a HEX-VALUE. + +Semantic color mappings cannot be recursive: their value must be +either COLOR-NAME or HEX-VALUE.") + + (defcustom modus-operandi-palette-overrides nil + "Overrides for `modus-operandi-palette'. + +Mirror the elements of the aforementioned palette, overriding +their value. + +For overrides that are shared across all of the Modus themes, +refer to `modus-themes-common-palette-overrides'. + +Theme-specific overrides take precedence over shared overrides. +The idea of common overrides is to change semantic color +mappings, such as to make the cursor red. Wherea theme-specific +overrides can also be used to change the value of a named color, +such as what hexadecimal RGB value the red-warmer symbol +represents." + :group 'modus-themes + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :type '(repeat (list symbol (choice symbol string))) + :set #'modus-themes--set-option + :initialize #'custom-initialize-default + :link '(info-link "(modus-themes) Palette overrides")) + + (modus-themes-theme modus-operandi + modus-operandi-palette + modus-operandi-palette-overrides) (provide-theme 'modus-operandi)) diff --git a/etc/themes/modus-operandi-tinted-theme.el b/etc/themes/modus-operandi-tinted-theme.el new file mode 100644 index 00000000000..52024ceee95 --- /dev/null +++ b/etc/themes/modus-operandi-tinted-theme.el @@ -0,0 +1,417 @@ +;;; modus-operandi-tinted-theme.el --- Elegant, highly legible and customizable light theme -*- lexical-binding:t -*- + +;; Copyright (C) 2019-2023 Free Software Foundation, Inc. + +;; Author: Protesilaos Stavrou <info@protesilaos.com> +;; Maintainer: Modus-Themes Development <~protesilaos/modus-themes@lists.sr.ht> +;; URL: https://git.sr.ht/~protesilaos/modus-themes +;; Mailing-List: https://lists.sr.ht/~protesilaos/modus-themes + +;; 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: +;; +;; The Modus themes conform with the highest standard for +;; color-contrast accessibility between background and foreground +;; values (WCAG AAA). Please refer to the official Info manual for +;; further documentation (distributed with the themes, or available +;; at: <https://protesilaos.com/emacs/modus-themes>). + +;;; Code: + + + +(eval-and-compile + (unless (and (fboundp 'require-theme) + load-file-name + (equal (file-name-directory load-file-name) + (expand-file-name "themes/" data-directory)) + (require-theme 'modus-themes t)) + (require 'modus-themes)) + + (deftheme modus-operandi-tinted + "Elegant, highly legible and customizable light theme. +Conforms with the highest legibility standard for color contrast +between background and foreground in any given piece of text, +which corresponds to a minimum contrast in relative luminance of +7:1 (WCAG AAA standard).") + + (defconst modus-operandi-tinted-palette + '( +;;; Basic values + + (bg-main "#fbf7f0") + (bg-dim "#ede7db") + (fg-main "#000000") + (fg-dim "#595959") + (fg-alt "#193668") + (bg-active "#c9b9b0") + (bg-inactive "#dfd5cf") + (border "#9f9690") + +;;; Common accent foregrounds + + (red "#a60000") + (red-warmer "#972500") + (red-cooler "#a0132f") + (red-faint "#7f0000") + (red-intense "#d00000") + (green "#006800") + (green-warmer "#316500") + (green-cooler "#00663f") + (green-faint "#2a5045") + (green-intense "#008900") + (yellow "#6f5500") + (yellow-warmer "#884900") + (yellow-cooler "#7a4f2f") + (yellow-faint "#624416") + (yellow-intense "#808000") + (blue "#0031a9") + (blue-warmer "#354fcf") + (blue-cooler "#0000b0") + (blue-faint "#003497") + (blue-intense "#0000ff") + (magenta "#721045") + (magenta-warmer "#8f0075") + (magenta-cooler "#531ab6") + (magenta-faint "#7c318f") + (magenta-intense "#dd22dd") + (cyan "#005e8b") + (cyan-warmer "#3f578f") + (cyan-cooler "#005f5f") + (cyan-faint "#005077") + (cyan-intense "#008899") + +;;; Uncommon accent foregrounds + + (rust "#8a290f") + (gold "#80601f") + (olive "#56692d") + (slate "#2f3f83") + (indigo "#4a3a8a") + (maroon "#731c52") + (pink "#7b435c") + +;;; Common accent backgrounds + + (bg-red-intense "#ff8f88") + (bg-green-intense "#8adf80") + (bg-yellow-intense "#f3d000") + (bg-blue-intense "#bfc9ff") + (bg-magenta-intense "#dfa0f0") + (bg-cyan-intense "#a4d5f9") + + (bg-red-subtle "#ffcfbf") + (bg-green-subtle "#b3fabf") + (bg-yellow-subtle "#fff576") + (bg-blue-subtle "#ccdfff") + (bg-magenta-subtle "#ffddff") + (bg-cyan-subtle "#bfefff") + + (bg-red-nuanced "#fff1f0") + (bg-green-nuanced "#ecf7ed") + (bg-yellow-nuanced "#fff3da") + (bg-blue-nuanced "#f3f3ff") + (bg-magenta-nuanced "#fdf0ff") + (bg-cyan-nuanced "#ebf6fa") + +;;; Uncommon accent backgrounds + + (bg-ochre "#f0e0cc") + (bg-lavender "#dfdbfa") + (bg-sage "#c0e7d4") + +;;; Graphs + + (bg-graph-red-0 "#ef7969") + (bg-graph-red-1 "#ffaab4") + (bg-graph-green-0 "#4faa09") + (bg-graph-green-1 "#8fef00") + (bg-graph-yellow-0 "#ffcf00") + (bg-graph-yellow-1 "#f9ff00") + (bg-graph-blue-0 "#7090ff") + (bg-graph-blue-1 "#9fc6ff") + (bg-graph-magenta-0 "#e07fff") + (bg-graph-magenta-1 "#fad0ff") + (bg-graph-cyan-0 "#70d3f0") + (bg-graph-cyan-1 "#afefff") + +;;; Special purpose + + (bg-completion "#f0c1cf") + (bg-hover "#94d4ff") + (bg-hover-secondary "#f5d0a0") + (bg-hl-line "#f1d5d0") + (bg-region "#c2bcb5") + (fg-region "#000000") + + (bg-char-0 "#7feaff") + (bg-char-1 "#ffaaff") + (bg-char-2 "#dff000") + + (bg-mode-line-active "#cab9b2") + (fg-mode-line-active "#000000") + (border-mode-line-active "#545454") + (bg-mode-line-inactive "#dfd9cf") + (fg-mode-line-inactive "#585858") + (border-mode-line-inactive "#a59a94") + + (modeline-err "#7f0000") + (modeline-warning "#5f0070") + (modeline-info "#002580") + + (bg-tab-bar "#e0d4ce") + (bg-tab-current "#fbf7f0") + (bg-tab-other "#c8b8b2") + +;;; Diffs + + (bg-added "#c3ebc1") + (bg-added-faint "#dcf8d1") + (bg-added-refine "#acd6a5") + (bg-added-intense "#8cca8c") + (fg-added "#005000") + (fg-added-intense "#006700") + + (bg-changed "#ffdfa9") + (bg-changed-faint "#ffefbf") + (bg-changed-refine "#fac090") + (bg-changed-intense "#d7c20a") + (fg-changed "#553d00") + (fg-changed-intense "#655000") + + (bg-removed "#f4d0cf") + (bg-removed-faint "#ffe9e5") + (bg-removed-refine "#f3b5a7") + (bg-removed-intense "#d84a4f") + (fg-removed "#8f1313") + (fg-removed-intense "#aa2222") + +;;; Paren match + + (bg-paren-match "#7fdfcf") + (bg-paren-expression "#efd3f5") + (underline-paren-match unspecified) + +;;; Mappings + +;;;; General mappings + + (fringe bg-dim) + (cursor red) + + (keybind blue-cooler) + (name magenta) + (identifier yellow-cooler) + + (err red) + (warning yellow-warmer) + (info cyan-cooler) + + (underline-err red-intense) + (underline-warning yellow-intense) + (underline-note cyan-intense) + +;;;; Code mappings + + (builtin magenta-warmer) + (comment red-faint) + (constant blue-cooler) + (docstring green-faint) + (docmarkup magenta-faint) + (fnname magenta) + (keyword magenta-cooler) + (preprocessor red-cooler) + (string blue-warmer) + (type cyan-cooler) + (variable cyan) + (rx-construct green-cooler) + (rx-backslash magenta) + +;;;; Accent mappings + + (accent-0 blue) + (accent-1 magenta-warmer) + (accent-2 cyan) + (accent-3 red) + +;;;; Button mappings + + (fg-button-active fg-main) + (fg-button-inactive fg-dim) + (bg-button-active bg-active) + (bg-button-inactive bg-dim) + +;;;; Completion mappings + + (fg-completion-match-0 blue) + (fg-completion-match-1 magenta-warmer) + (fg-completion-match-2 cyan) + (fg-completion-match-3 red) + (bg-completion-match-0 unspecified) + (bg-completion-match-1 unspecified) + (bg-completion-match-2 unspecified) + (bg-completion-match-3 unspecified) + +;;;; Date mappings + + (date-common cyan) + (date-deadline red) + (date-event fg-alt) + (date-holiday magenta) + (date-now fg-main) + (date-scheduled yellow-warmer) + (date-weekday cyan) + (date-weekend red-faint) + +;;;; Line number mappings + + (fg-line-number-inactive fg-dim) + (fg-line-number-active fg-main) + (bg-line-number-inactive bg-dim) + (bg-line-number-active bg-active) + +;;;; Link mappings + + (fg-link blue-warmer) + (bg-link unspecified) + (underline-link blue-warmer) + + (fg-link-symbolic cyan) + (bg-link-symbolic unspecified) + (underline-link-symbolic cyan) + + (fg-link-visited magenta) + (bg-link-visited unspecified) + (underline-link-visited magenta) + +;;;; Mail mappings + + (mail-cite-0 blue-faint) + (mail-cite-1 yellow-warmer) + (mail-cite-2 cyan-cooler) + (mail-cite-3 red-cooler) + (mail-part cyan) + (mail-recipient magenta-cooler) + (mail-subject magenta-warmer) + (mail-other magenta-faint) + +;;;; Prompt mappings + + (fg-prompt cyan-cooler) + (bg-prompt unspecified) + +;;;; Prose mappings + + (prose-block fg-dim) + (prose-code green-cooler) + (prose-done green) + (prose-macro magenta-cooler) + (prose-metadata fg-dim) + (prose-metadata-value fg-alt) + (prose-table fg-alt) + (prose-tag magenta-faint) + (prose-todo red) + (prose-verbatim magenta-warmer) + +;;;; Rainbow mappings + + (rainbow-0 fg-main) + (rainbow-1 magenta-intense) + (rainbow-2 cyan-intense) + (rainbow-3 red-warmer) + (rainbow-4 yellow-intense) + (rainbow-5 magenta-cooler) + (rainbow-6 green-intense) + (rainbow-7 blue-warmer) + (rainbow-8 magenta-warmer) + +;;;; Heading mappings + + (fg-heading-0 cyan-cooler) + (fg-heading-1 fg-main) + (fg-heading-2 yellow-faint) + (fg-heading-3 fg-alt) + (fg-heading-4 magenta) + (fg-heading-5 green-faint) + (fg-heading-6 red-faint) + (fg-heading-7 cyan-warmer) + (fg-heading-8 fg-dim) + + (bg-heading-0 unspecified) + (bg-heading-1 unspecified) + (bg-heading-2 unspecified) + (bg-heading-3 unspecified) + (bg-heading-4 unspecified) + (bg-heading-5 unspecified) + (bg-heading-6 unspecified) + (bg-heading-7 unspecified) + (bg-heading-8 unspecified) + + (overline-heading-0 unspecified) + (overline-heading-1 unspecified) + (overline-heading-2 unspecified) + (overline-heading-3 unspecified) + (overline-heading-4 unspecified) + (overline-heading-5 unspecified) + (overline-heading-6 unspecified) + (overline-heading-7 unspecified) + (overline-heading-8 unspecified)) + "The entire palette of the `modus-operandi-tinted' theme. + +Named colors have the form (COLOR-NAME HEX-VALUE) with the former +as a symbol and the latter as a string. + +Semantic color mappings have the form (MAPPING-NAME COLOR-NAME) +with both as symbols. The latter is a named color that already +exists in the palette and is associated with a HEX-VALUE. + +Semantic color mappings cannot be recursive: their value must be +either COLOR-NAME or HEX-VALUE.") + + (defcustom modus-operandi-tinted-palette-overrides nil + "Overrides for `modus-operandi-tinted-palette'. + +Mirror the elements of the aforementioned palette, overriding +their value. + +For overrides that are shared across all of the Modus themes, +refer to `modus-themes-common-palette-overrides'. + +Theme-specific overrides take precedence over shared overrides. +The idea of common overrides is to change semantic color +mappings, such as to make the cursor red. Wherea theme-specific +overrides can also be used to change the value of a named color, +such as what hexadecimal RGB value the red-warmer symbol +represents." + :group 'modus-themes + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :type '(repeat (list symbol (choice symbol string))) + :set #'modus-themes--set-option + :initialize #'custom-initialize-default + :link '(info-link "(modus-themes) Palette overrides")) + + (modus-themes-theme modus-operandi-tinted + modus-operandi-tinted-palette + modus-operandi-tinted-palette-overrides) + + (provide-theme 'modus-operandi-tinted)) + +;;;###theme-autoload +(put 'modus-operandi-tinted 'theme-properties '(:background-mode light :kind color-scheme :family modus)) + +;;; modus-operandi-tinted-theme.el ends here diff --git a/etc/themes/modus-themes.el b/etc/themes/modus-themes.el index 79409cd01b1..f4f33aa36e0 100644 --- a/etc/themes/modus-themes.el +++ b/etc/themes/modus-themes.el @@ -1,12 +1,12 @@ ;;; modus-themes.el --- Elegant, highly legible and customizable themes -*- lexical-binding:t -*- -;; Copyright (C) 2019-2023 Free Software Foundation, Inc. +;; Copyright (C) 2019-2023 Free Software Foundation, Inc. ;; Author: Protesilaos Stavrou <info@protesilaos.com> ;; Maintainer: Modus-Themes Development <~protesilaos/modus-themes@lists.sr.ht> ;; URL: https://git.sr.ht/~protesilaos/modus-themes ;; Mailing-List: https://lists.sr.ht/~protesilaos/modus-themes -;; Version: 3.0.0 +;; Version: 4.0.1 ;; Package-Requires: ((emacs "27.1")) ;; Keywords: faces, theme, accessibility @@ -27,57 +27,11 @@ ;;; Commentary: ;; -;; The Modus themes conform with the highest standard for color-contrast -;; accessibility between background and foreground values (WCAG AAA). -;; This file contains all customization variables, helper functions, -;; interactive commands, and face specifications. Please refer to the -;; official Info manual for further documentation (distributed with the -;; themes, or available at: <https://protesilaos.com/emacs/modus-themes>). -;; -;; The themes share the following customization variables: -;; -;; modus-themes-completions (alist) -;; modus-themes-headings (alist) -;; modus-themes-org-agenda (alist) -;; modus-themes-bold-constructs (boolean) -;; modus-themes-deuteranopia (boolean) -;; modus-themes-inhibit-reload (boolean) -;; modus-themes-intense-mouseovers (boolean) -;; modus-themes-italic-constructs (boolean) -;; modus-themes-mixed-fonts (boolean) -;; modus-themes-subtle-line-numbers (boolean) -;; modus-themes-variable-pitch-ui (boolean) -;; modus-themes-box-buttons (choice) -;; modus-themes-diffs (choice) -;; modus-themes-fringes (choice) -;; modus-themes-hl-line (choice) -;; modus-themes-lang-checkers (choice) -;; modus-themes-links (choice) -;; modus-themes-mail-citations (choice) -;; modus-themes-markup (choice) -;; modus-themes-mode-line (choice) -;; modus-themes-org-blocks (choice) -;; modus-themes-paren-match (choice) -;; modus-themes-prompts (choice) -;; modus-themes-region (choice) -;; modus-themes-syntax (choice) -;; -;; There also exist two unique customization variables for overriding -;; color palette values. The specifics are documented in the manual. -;; The symbols are: -;; -;; modus-themes-operandi-color-overrides (alist) -;; modus-themes-vivendi-color-overrides (alist) -;; -;; Check the manual for all supported packages (there are hundreds of -;; them). -;; -;; For a complete view of the project, also refer to the following files -;; (should be distributed in the same repository/directory as the -;; current item): -;; -;; - modus-operandi-theme.el (Light theme) -;; - modus-vivendi-theme.el (Dark theme) +;; The Modus themes conform with the highest standard for +;; color-contrast accessibility between background and foreground +;; values (WCAG AAA). Please refer to the official Info manual for +;; further documentation (distributed with the themes, or available +;; at: <https://protesilaos.com/emacs/modus-themes>). ;;; Code: @@ -88,7 +42,7 @@ (require 'subr-x)) (defgroup modus-themes () - "Options for `modus-operandi', `modus-vivendi' themes. + "User options for the Modus themes. The Modus themes conform with the WCAG AAA standard for color contrast between background and foreground combinations (a minimum contrast of 7:1---the highest standard of its kind). The @@ -103,1139 +57,148 @@ cover the blue-cyan-magenta side of the spectrum." :tag "Modus Themes") (defgroup modus-themes-faces () - "Faces defined by `modus-operandi' and `modus-vivendi' themes." + "Faces defined by the Modus themes." :group 'modus-themes :link '(info-link "(modus-themes) Top") :prefix "modus-themes-" :tag "Modus Themes Faces") -(defvar modus-themes--version "3.0.0" - "Current version of the Modus themes. - -The version either is the last tagged release, such as '1.0.0', -or an in-development version like '1.1.0-dev'. As we use -semantic versioning, tags of the '1.0.1' sort are not reported: -those would count as part of '1.1.0-dev'.") - -;;;###autoload -(defun modus-themes-version (&optional insert) - "Print `modus-themes--version' in the echo area. -If optional INSERT argument is provided from Lisp or as a prefix -argument, insert the `modus-themes--version' at point." - (interactive "P") - (funcall (if insert 'insert 'message) modus-themes--version)) - -;;;###autoload -(defun modus-themes-report-bug () - "Submit a bug report or issue to the Modus themes developers." - (interactive) - (reporter-submit-bug-report - "~protesilaos/modus-themes@lists.sr.ht" - (format "modus-themes (%s)\n" modus-themes--version) - ;; I am just getting started with this. Let's first see what people - ;; think about it. - nil nil nil nil)) - -;;; Variables for each theme variant - -;;;; Modus Operandi - -(defconst modus-themes-operandi-colors - '(;; base values - (bg-main . "#ffffff") (fg-main . "#000000") - (bg-dim . "#f8f8f8") (fg-dim . "#282828") - (bg-alt . "#f0f0f0") (fg-alt . "#505050") - ;; specifically for on/off states and must be combined with - ;; themselves, though the backgrounds are also meant to be used with - ;; other "active" values, defined further below; bg-active-accent - ;; can work as a substitute for bg-active - (bg-active . "#d7d7d7") (fg-active . "#0a0a0a") - (bg-inactive . "#efefef") (fg-inactive . "#404148") - (bg-active-accent . "#d0d6ff") - ;; these special values are intended as alternatives to the base - ;; values for cases where we need to avoid confusion between the - ;; highlighted constructs; they must either be used as pairs based - ;; on their name or each can be combined with {fg,bg}-{main,alt,dim} - ;; always in accordance with their role as background or foreground - (bg-special-cold . "#dde3f4") (bg-special-faint-cold . "#f0f1ff") (fg-special-cold . "#093060") - (bg-special-mild . "#c4ede0") (bg-special-faint-mild . "#ebf5eb") (fg-special-mild . "#184034") - (bg-special-warm . "#f0e0d4") (bg-special-faint-warm . "#fef2ea") (fg-special-warm . "#5d3026") - (bg-special-calm . "#f8ddea") (bg-special-faint-calm . "#faeff9") (fg-special-calm . "#61284f") - ;; foregrounds that can be combined with bg-main, bg-dim, bg-alt - (red . "#a60000") - (red-alt . "#972500") - (red-alt-other . "#a0132f") - (red-faint . "#7f1010") - (red-alt-faint . "#702f00") - (red-alt-other-faint . "#7f002f") - (green . "#005e00") - (green-alt . "#315b00") - (green-alt-other . "#145c33") - (green-faint . "#104410") - (green-alt-faint . "#30440f") - (green-alt-other-faint . "#0f443f") - (yellow . "#813e00") - (yellow-alt . "#70480f") - (yellow-alt-other . "#863927") - (yellow-faint . "#5f4400") - (yellow-alt-faint . "#5d5000") - (yellow-alt-other-faint . "#5e3a20") - (blue . "#0031a9") - (blue-alt . "#2544bb") - (blue-alt-other . "#0000c0") - (blue-faint . "#003497") - (blue-alt-faint . "#0f3d8c") - (blue-alt-other-faint . "#001087") - (magenta . "#721045") - (magenta-alt . "#8f0075") - (magenta-alt-other . "#5317ac") - (magenta-faint . "#752f50") - (magenta-alt-faint . "#7b206f") - (magenta-alt-other-faint . "#55348e") - (cyan . "#00538b") - (cyan-alt . "#30517f") - (cyan-alt-other . "#005a5f") - (cyan-faint . "#005077") - (cyan-alt-faint . "#354f6f") - (cyan-alt-other-faint . "#125458") - ;; these foreground values can only be combined with bg-main and are - ;; thus not suitable for general purpose highlighting - (red-intense . "#b60000") - (orange-intense . "#904200") - (green-intense . "#006800") - (yellow-intense . "#605b00") - (blue-intense . "#1f1fce") - (magenta-intense . "#a8007f") - (purple-intense . "#7f10d0") - (cyan-intense . "#005f88") - ;; those foregrounds are meant exclusively for bg-active, bg-inactive - (red-active . "#8a0000") - (green-active . "#004c2e") - (yellow-active . "#702f00") - (blue-active . "#0030b4") - (magenta-active . "#5c2092") - (cyan-active . "#003f8a") - ;; the "subtle" values below be combined with fg-dim, while the - ;; "intense" should be paired with fg-main - (red-subtle-bg . "#f2b0a2") - (red-intense-bg . "#ff9f9f") - (green-subtle-bg . "#aecf90") - (green-intense-bg . "#5ada88") - (yellow-subtle-bg . "#e4c340") - (yellow-intense-bg . "#f5df23") - (blue-subtle-bg . "#b5d0ff") - (blue-intense-bg . "#77baff") - (magenta-subtle-bg . "#f0d3ff") - (magenta-intense-bg . "#d5baff") - (cyan-subtle-bg . "#c0efff") - (cyan-intense-bg . "#42cbd4") - ;; those background values must be combined with fg-main and should - ;; only be used for indicators that are placed on the fringes - (red-fringe-bg . "#f08290") - (green-fringe-bg . "#62c86a") - (yellow-fringe-bg . "#dbba3f") - (blue-fringe-bg . "#82afff") - (magenta-fringe-bg . "#e0a3ff") - (cyan-fringe-bg . "#2fcddf") - ;; those background values should only be used for graphs or similar - ;; applications where colored blocks are expected to be positioned - ;; next to each other - (red-graph-0-bg . "#ef7969") - (red-graph-1-bg . "#ffaab4") - (green-graph-0-bg . "#4faa09") - (green-graph-1-bg . "#8fef00") - (yellow-graph-0-bg . "#ffcf00") - (yellow-graph-1-bg . "#f9ff00") - (blue-graph-0-bg . "#7090ff") - (blue-graph-1-bg . "#9fc6ff") - (magenta-graph-0-bg . "#e07fff") - (magenta-graph-1-bg . "#fad0ff") - (cyan-graph-0-bg . "#70d3f0") - (cyan-graph-1-bg . "#afefff") - ;; the following are for cases where both the foreground and the - ;; background need to have a similar hue and so must be combined - ;; with themselves, even though the foregrounds can be paired with - ;; any of the base backgrounds - (red-refine-bg . "#ffcccc") (red-refine-fg . "#780000") - (green-refine-bg . "#aceaac") (green-refine-fg . "#004c00") - (yellow-refine-bg . "#fff29a") (yellow-refine-fg . "#604000") - (blue-refine-bg . "#8fcfff") (blue-refine-fg . "#002f88") - (magenta-refine-bg . "#ffccff") (magenta-refine-fg . "#770077") - (cyan-refine-bg . "#8eecf4") (cyan-refine-fg . "#004850") - ;; the "nuanced" backgrounds can be combined with all of the above - ;; foregrounds, as well as those included here, while the "nuanced" - ;; foregrounds can in turn also be combined with bg-main, bg-dim, - ;; bg-alt - (red-nuanced-bg . "#fff1f0") (red-nuanced-fg . "#5f0000") - (green-nuanced-bg . "#ecf7ed") (green-nuanced-fg . "#004000") - (yellow-nuanced-bg . "#fff3da") (yellow-nuanced-fg . "#3f3000") - (blue-nuanced-bg . "#f3f3ff") (blue-nuanced-fg . "#201f55") - (magenta-nuanced-bg . "#fdf0ff") (magenta-nuanced-fg . "#541f4f") - (cyan-nuanced-bg . "#ebf6fa") (cyan-nuanced-fg . "#0f3360") - ;; the following are reserved for specific cases - ;; - ;; bg-hl-line is between bg-dim and bg-alt, so it should - ;; work with all accents that cover those two, plus bg-main - ;; - ;; bg-hl-alt and bg-hl-alt-intense should only be used when no - ;; other grayscale or fairly neutral background is available to - ;; properly draw attention to a given construct - ;; - ;; bg-header is between bg-active and bg-inactive, so it - ;; can be combined with any of the "active" values, plus the - ;; "special" and base foreground colors - ;; - ;; bg-paren-match, bg-paren-match-intense, bg-region, - ;; bg-region-accent and bg-tab-active must be combined with fg-main, - ;; while bg-tab-inactive should be combined with fg-dim, whereas - ;; bg-tab-inactive-alt goes together with fg-main - ;; - ;; bg-completion-* and bg-char-* variants are meant to be combined - ;; with fg-main - ;; - ;; fg-escape-char-construct and fg-escape-char-backslash can - ;; be combined bg-main, bg-dim, bg-alt - ;; - ;; fg-lang-error, fg-lang-warning, fg-lang-note can be - ;; combined with bg-main, bg-dim, bg-alt - ;; - ;; fg-mark-sel, fg-mark-del, fg-mark-alt can be combined - ;; with bg-main, bg-dim, bg-alt, bg-hl-line - ;; - ;; fg-unfocused must be combined with bg-main - ;; - ;; fg-docstring, fg-comment-yellow can be combined with - ;; bg-main, bg-dim, bg-alt - ;; - ;; the window divider colors apply to faces with just an fg value - ;; - ;; all pairs are combinable with themselves - (bg-hl-line . "#f2eff3") - (bg-hl-line-intense . "#e0e0e0") - (bg-hl-line-intense-accent . "#cfe2ff") - (bg-hl-alt . "#fbeee0") - (bg-hl-alt-intense . "#e8dfd1") - (bg-paren-match . "#e0af82") - (bg-paren-match-intense . "#c488ff") - (bg-paren-expression . "#dff0ff") - (bg-region . "#bcbcbc") - (bg-region-accent . "#afafef") - (bg-region-accent-subtle . "#efdfff") - - (bg-completion . "#b7dbff") - (bg-completion-subtle . "#def3ff") - - (bg-char-0 . "#7feaff") - (bg-char-1 . "#ffaaff") - (bg-char-2 . "#dff000") - - (bg-tab-active . "#f6f6f6") - (bg-tab-inactive . "#b7b7b7") - (bg-tab-inactive-accent . "#a9b4f6") - (bg-tab-inactive-alt . "#9f9f9f") - (bg-tab-inactive-alt-accent . "#9fa6d0") - - (red-tab . "#680000") - (green-tab . "#003900") - (yellow-tab . "#393000") - (orange-tab . "#502300") - (blue-tab . "#000080") - (cyan-tab . "#052f60") - (magenta-tab . "#5f004d") - (purple-tab . "#400487") - - (fg-escape-char-construct . "#8b1030") - (fg-escape-char-backslash . "#654d0f") - - (fg-lang-error . "#9f004f") - (fg-lang-warning . "#604f0f") - (fg-lang-note . "#4040ae") - (fg-lang-underline-error . "#ef4f54") - (fg-lang-underline-warning . "#cf9f00") - (fg-lang-underline-note . "#3f6fef") - - (fg-window-divider-inner . "#888888") - (fg-window-divider-outer . "#585858") - - (fg-unfocused . "#56576d") - - (fg-docstring . "#2a486a") - (fg-comment-yellow . "#794319") - - (bg-header . "#e5e5e5") (fg-header . "#2a2a2a") - - (bg-whitespace . "#f5efef") (fg-whitespace . "#624956") - - (bg-diff-heading . "#b7cfe0") (fg-diff-heading . "#041645") - (bg-diff-added . "#d4fad4") (fg-diff-added . "#004500") - (bg-diff-added-deuteran . "#daefff") (fg-diff-added-deuteran . "#002044") - (bg-diff-changed . "#fcefcf") (fg-diff-changed . "#524200") - (bg-diff-removed . "#ffe8ef") (fg-diff-removed . "#691616") - - (bg-diff-refine-added . "#94cf94") (fg-diff-refine-added . "#002a00") - (bg-diff-refine-added-deuteran . "#77c0ef") (fg-diff-refine-added-deuteran . "#000035") - (bg-diff-refine-changed . "#cccf8f") (fg-diff-refine-changed . "#302010") - (bg-diff-refine-removed . "#daa2b0") (fg-diff-refine-removed . "#400000") - - (bg-diff-focus-added . "#bbeabb") (fg-diff-focus-added . "#002c00") - (bg-diff-focus-added-deuteran . "#bacfff") (fg-diff-focus-added-deuteran . "#001755") - (bg-diff-focus-changed . "#ecdfbf") (fg-diff-focus-changed . "#392900") - (bg-diff-focus-removed . "#efcbcf") (fg-diff-focus-removed . "#4a0000") - - (bg-mark-sel . "#a0f0cf") (fg-mark-sel . "#005040") - (bg-mark-del . "#ffccbb") (fg-mark-del . "#840040") - (bg-mark-alt . "#f5d88f") (fg-mark-alt . "#782900")) - "The entire palette of the `modus-operandi' theme. -Each element has the form (NAME . HEX) with the former as a -symbol and the latter as a string.") - -;;;; Modus Vivendi - -(defconst modus-themes-vivendi-colors - '(;; base values - (bg-main . "#000000") (fg-main . "#ffffff") - (bg-dim . "#100f10") (fg-dim . "#e0e6f0") - (bg-alt . "#191a1b") (fg-alt . "#a8a8a8") - ;; specifically for on/off states and must be combined with - ;; themselves, though the backgrounds are also meant to be used with - ;; other "active" values, defined further below; bg-active-accent - ;; can work as a substitute for bg-active - (bg-active . "#323232") (fg-active . "#f4f4f4") - (bg-inactive . "#1e1e1e") (fg-inactive . "#bfc0c4") - (bg-active-accent . "#2a2a66") - ;; these special values are intended as alternatives to the base - ;; values for cases where we need to avoid confusion between the - ;; highlighted constructs; they must either be used as pairs based - ;; on their name or each can be combined with {fg,bg}-{main,alt,dim} - ;; always in accordance with their role as background or foreground - (bg-special-cold . "#203448") (bg-special-faint-cold . "#0e183a") (fg-special-cold . "#c6eaff") - (bg-special-mild . "#00322e") (bg-special-faint-mild . "#001f1a") (fg-special-mild . "#bfebe0") - (bg-special-warm . "#382f27") (bg-special-faint-warm . "#241613") (fg-special-warm . "#f8dec0") - (bg-special-calm . "#392a48") (bg-special-faint-calm . "#251232") (fg-special-calm . "#fbd6f4") - ;; foregrounds that can be combined with bg-main, bg-dim, bg-alt - (red . "#ff8059") - (red-alt . "#ef8b50") - (red-alt-other . "#ff9077") - (red-faint . "#ffa0a0") - (red-alt-faint . "#f5aa80") - (red-alt-other-faint . "#ff9fbf") - (green . "#44bc44") - (green-alt . "#70b900") - (green-alt-other . "#00c06f") - (green-faint . "#78bf78") - (green-alt-faint . "#99b56f") - (green-alt-other-faint . "#88bf99") - (yellow . "#d0bc00") - (yellow-alt . "#c0c530") - (yellow-alt-other . "#d3b55f") - (yellow-faint . "#d2b580") - (yellow-alt-faint . "#cabf77") - (yellow-alt-other-faint . "#d0ba95") - (blue . "#2fafff") - (blue-alt . "#79a8ff" ) - (blue-alt-other . "#00bcff") - (blue-faint . "#82b0ec") - (blue-alt-faint . "#a0acef") - (blue-alt-other-faint . "#80b2f0") - (magenta . "#feacd0") - (magenta-alt . "#f78fe7") - (magenta-alt-other . "#b6a0ff") - (magenta-faint . "#e0b2d6") - (magenta-alt-faint . "#ef9fe4") - (magenta-alt-other-faint . "#cfa6ff") - (cyan . "#00d3d0") - (cyan-alt . "#4ae2f0") - (cyan-alt-other . "#6ae4b9") - (cyan-faint . "#90c4ed") - (cyan-alt-faint . "#a0bfdf") - (cyan-alt-other-faint . "#a4d0bb") - ;; these foreground values can only be combined with bg-main and are - ;; thus not suitable for general purpose highlighting - (red-intense . "#fe6060") - (orange-intense . "#fba849") - (green-intense . "#4fe42f") - (yellow-intense . "#f0dd60") - (blue-intense . "#4fafff") - (magenta-intense . "#ff62d4") - (purple-intense . "#9f80ff") - (cyan-intense . "#3fdfd0") - ;; those foregrounds are meant exclusively for bg-active, bg-inactive - (red-active . "#ffa7ba") - (green-active . "#70d73f") - (yellow-active . "#dbbe5f") - (blue-active . "#34cfff") - (magenta-active . "#d5b1ff") - (cyan-active . "#00d8b4") - ;; the "subtle" values below be combined with fg-dim, while the - ;; "intense" should be paired with fg-main - (red-subtle-bg . "#762422") - (red-intense-bg . "#a4202a") - (green-subtle-bg . "#2f4a00") - (green-intense-bg . "#006800") - (yellow-subtle-bg . "#604200") - (yellow-intense-bg . "#874900") - (blue-subtle-bg . "#10387c") - (blue-intense-bg . "#2a40b8") - (magenta-subtle-bg . "#49366e") - (magenta-intense-bg . "#7042a2") - (cyan-subtle-bg . "#00415e") - (cyan-intense-bg . "#005f88") - ;; those background values must be combined with fg-main and should - ;; only be used for indicators that are placed on the fringes - (red-fringe-bg . "#8f1f4b") - (green-fringe-bg . "#006700") - (yellow-fringe-bg . "#6f4f00") - (blue-fringe-bg . "#3f33af") - (magenta-fringe-bg . "#6f2f89") - (cyan-fringe-bg . "#004f8f") - ;; those background values should only be used for graphs or similar - ;; applications where colored blocks are expected to be positioned - ;; next to each other - (red-graph-0-bg . "#b52c2c") - (red-graph-1-bg . "#702020") - (green-graph-0-bg . "#4fd100") - (green-graph-1-bg . "#007800") - (yellow-graph-0-bg . "#f1e00a") - (yellow-graph-1-bg . "#b08600") - (blue-graph-0-bg . "#2fafef") - (blue-graph-1-bg . "#1f2f8f") - (magenta-graph-0-bg . "#bf94fe") - (magenta-graph-1-bg . "#5f509f") - (cyan-graph-0-bg . "#47dfea") - (cyan-graph-1-bg . "#00808f") - ;; the following are for cases where both the foreground and the - ;; background need to have a similar hue and so must be combined - ;; with themselves, even though the foregrounds can be paired with - ;; any of the base backgrounds - (red-refine-bg . "#77002a") (red-refine-fg . "#ffb9ab") - (green-refine-bg . "#00422a") (green-refine-fg . "#9ff0cf") - (yellow-refine-bg . "#693200") (yellow-refine-fg . "#e2d980") - (blue-refine-bg . "#242679") (blue-refine-fg . "#8ecfff") - (magenta-refine-bg . "#71206a") (magenta-refine-fg . "#ffcaf0") - (cyan-refine-bg . "#004065") (cyan-refine-fg . "#8ae4f2") - ;; the "nuanced" backgrounds can be combined with all of the above - ;; foregrounds, as well as those included here, while the "nuanced" - ;; foregrounds can in turn also be combined with bg-main, bg-dim, - ;; bg-alt - (red-nuanced-bg . "#2c0614") (red-nuanced-fg . "#ffcccc") - (green-nuanced-bg . "#001904") (green-nuanced-fg . "#b8e2b8") - (yellow-nuanced-bg . "#221000") (yellow-nuanced-fg . "#dfdfb0") - (blue-nuanced-bg . "#0f0e39") (blue-nuanced-fg . "#bfd9ff") - (magenta-nuanced-bg . "#230631") (magenta-nuanced-fg . "#e5cfef") - (cyan-nuanced-bg . "#041529") (cyan-nuanced-fg . "#a8e5e5") - ;; the following are reserved for specific cases - ;; - ;; bg-hl-line is between bg-dim and bg-alt, so it should - ;; work with all accents that cover those two, plus bg-main - ;; - ;; bg-hl-alt and bg-hl-alt-intense should only be used when no - ;; other grayscale or fairly neutral background is available to - ;; properly draw attention to a given construct - ;; - ;; bg-header is between bg-active and bg-inactive, so it - ;; can be combined with any of the "active" values, plus the - ;; "special" and base foreground colors - ;; - ;; bg-paren-match, bg-paren-match-intense, bg-region, - ;; bg-region-accent and bg-tab-active must be combined with fg-main, - ;; while bg-tab-inactive should be combined with fg-dim, whereas - ;; bg-tab-inactive-alt goes together with fg-main - ;; - ;; bg-completion-* and bg-char-* variants are meant to be combined - ;; with fg-main - ;; - ;; fg-escape-char-construct and fg-escape-char-backslash can - ;; be combined bg-main, bg-dim, bg-alt - ;; - ;; fg-lang-error, fg-lang-warning, fg-lang-note can be - ;; combined with bg-main, bg-dim, bg-alt - ;; - ;; fg-mark-sel, fg-mark-del, fg-mark-alt can be combined - ;; with bg-main, bg-dim, bg-alt, bg-hl-line - ;; - ;; fg-unfocused must be combined with bg-main - ;; - ;; fg-docstring, fg-comment-yellow can be combined with - ;; bg-main, bg-dim, bg-alt - ;; - ;; the window divider colors apply to faces with just an fg value - ;; - ;; all pairs are combinable with themselves - (bg-hl-line . "#151823") - (bg-hl-line-intense . "#292929") - (bg-hl-line-intense-accent . "#002a4f") - (bg-hl-alt . "#181732") - (bg-hl-alt-intense . "#282e46") - (bg-paren-match . "#6f3355") - (bg-paren-match-intense . "#7416b5") - (bg-paren-expression . "#221044") - (bg-region . "#3c3c3c") - (bg-region-accent . "#4f3d88") - (bg-region-accent-subtle . "#240f55") - - (bg-completion . "#142f69") - (bg-completion-subtle . "#0e194b") - - (bg-char-0 . "#0050af") - (bg-char-1 . "#7f1f7f") - (bg-char-2 . "#625a00") - - (bg-tab-active . "#0e0e0e") - (bg-tab-inactive . "#424242") - (bg-tab-inactive-accent . "#35398f") - (bg-tab-inactive-alt . "#595959") - (bg-tab-inactive-alt-accent . "#505588") - - (red-tab . "#ffc0bf") - (green-tab . "#88ef88") - (yellow-tab . "#d2e580") - (orange-tab . "#f5ca80") - (blue-tab . "#92d9ff") - (cyan-tab . "#60e7e0") - (magenta-tab . "#ffb8ff") - (purple-tab . "#cfcaff") - - (fg-escape-char-construct . "#e7a59a") - (fg-escape-char-backslash . "#abab00") - - (fg-lang-error . "#ef8690") - (fg-lang-warning . "#b0aa00") - (fg-lang-note . "#9d9def") - (fg-lang-underline-error . "#ff4a6f") - (fg-lang-underline-warning . "#d0de00") - (fg-lang-underline-note . "#5f6fff") - - (fg-window-divider-inner . "#646464") - (fg-window-divider-outer . "#969696") - - (fg-unfocused . "#93959b") - - (fg-docstring . "#b0d6f5") - (fg-comment-yellow . "#d0a070") - - (bg-header . "#212121") (fg-header . "#dddddd") - - (bg-whitespace . "#101424") (fg-whitespace . "#aa9e9f") - - (bg-diff-heading . "#304466") (fg-diff-heading . "#dae7ff") - (bg-diff-added . "#0a280a") (fg-diff-added . "#94ba94") - (bg-diff-added-deuteran . "#001a3f") (fg-diff-added-deuteran . "#c4cdf2") - (bg-diff-changed . "#2a2000") (fg-diff-changed . "#b0ba9f") - (bg-diff-removed . "#40160f") (fg-diff-removed . "#c6adaa") - - (bg-diff-refine-added . "#005a36") (fg-diff-refine-added . "#e0f6e0") - (bg-diff-refine-added-deuteran . "#234f8f") (fg-diff-refine-added-deuteran . "#dde4ff") - (bg-diff-refine-changed . "#585800") (fg-diff-refine-changed . "#ffffcc") - (bg-diff-refine-removed . "#852828") (fg-diff-refine-removed . "#ffd9eb") - - (bg-diff-focus-added . "#1d3c25") (fg-diff-focus-added . "#b4ddb4") - (bg-diff-focus-added-deuteran . "#003959") (fg-diff-focus-added-deuteran . "#bfe4ff") - (bg-diff-focus-changed . "#424200") (fg-diff-focus-changed . "#d0daaf") - (bg-diff-focus-removed . "#601f29") (fg-diff-focus-removed . "#eebdba") - - (bg-mark-sel . "#002f2f") (fg-mark-sel . "#60cfa2") - (bg-mark-del . "#5a0000") (fg-mark-del . "#ff99aa") - (bg-mark-alt . "#3f2210") (fg-mark-alt . "#f0aa20")) - "The entire palette of the `modus-vivendi' theme. -Each element has the form (NAME . HEX) with the former as a -symbol and the latter as a string.") +(make-obsolete-variable 'modus-themes-operandi-colors nil "4.0.0") +(make-obsolete-variable 'modus-themes-vivendi-colors nil "4.0.0") +(make-obsolete-variable 'modus-themes-version nil "4.0.0") +(make-obsolete 'modus-themes-report-bug nil "4.0.0") -;;; Custom faces +;;;; Custom faces ;; These faces are used internally to ensure consistency between various ;; groups and to streamline the evaluation of relevant customization ;; options. -(defface modus-themes-subtle-red nil - "Subtle red background combined with a dimmed foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-subtle-green nil - "Subtle green background combined with a dimmed foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-subtle-yellow nil - "Subtle yellow background combined with a dimmed foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-subtle-blue nil - "Subtle blue background combined with a dimmed foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-subtle-magenta nil - "Subtle magenta background combined with a dimmed foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-subtle-cyan nil - "Subtle cyan background combined with a dimmed foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-subtle-neutral nil - "Subtle gray background combined with a dimmed foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-intense-red nil - "Intense red background combined with the main foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-intense-green nil - "Intense green background combined with the main foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-intense-yellow nil - "Intense yellow background combined with the main foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-intense-blue nil - "Intense blue background combined with the main foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-intense-magenta nil - "Intense magenta background combined with the main foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-intense-cyan nil - "Intense cyan background combined with the main foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-intense-neutral nil - "Intense gray background combined with the main foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-refine-red nil - "Combination of accented red background and foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-refine-green nil - "Combination of accented green background and foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-refine-yellow nil - "Combination of accented yellow background and foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-refine-blue nil - "Combination of accented blue background and foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-refine-magenta nil - "Combination of accented magenta background and foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-refine-cyan nil - "Combination of accented cyan background and foreground. -This is used for general purpose highlighting, mostly in buffers -or for completion interfaces. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-active-red nil - "A red background meant for use on the mode line or similar. -This is combined with the mode lines primary foreground value. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-active-green nil - "A green background meant for use on the mode line or similar. -This is combined with the mode lines primary foreground value. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-active-yellow nil - "A yellow background meant for use on the mode line or similar. -This is combined with the mode lines primary foreground value. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-active-blue nil - "A blue background meant for use on the mode line or similar. -This is combined with the mode lines primary foreground value. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-active-magenta nil - "A magenta background meant for use on the mode line or similar. -This is combined with the mode lines primary foreground value. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-active-cyan nil - "A cyan background meant for use on the mode line or similar. -This is combined with the mode lines primary foreground value. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-fringe-red nil - "A red background meant for use on the fringe or similar. -This is combined with the main foreground value. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-fringe-green nil - "A green background meant for use on the fringe or similar. -This is combined with the main foreground value. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-fringe-yellow nil - "A yellow background meant for use on the fringe or similar. -This is combined with the main foreground value. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-fringe-blue nil - "A blue background meant for use on the fringe or similar. -This is combined with the main foreground value. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-fringe-magenta nil - "A magenta background meant for use on the fringe or similar. -This is combined with the main foreground value. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-fringe-cyan nil - "A cyan background meant for use on the fringe or similar. -This is combined with the main foreground value. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-nuanced-red nil - "A nuanced red background. -This does not specify a foreground of its own. Instead it is -meant to serve as the backdrop for elements such as Org blocks, -headings, and any other surface that needs to retain the colors -on display. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-nuanced-green nil - "A nuanced green background. -This does not specify a foreground of its own. Instead it is -meant to serve as the backdrop for elements such as Org blocks, -headings, and any other surface that needs to retain the colors -on display. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-nuanced-yellow nil - "A nuanced yellow background. -This does not specify a foreground of its own. Instead it is -meant to serve as the backdrop for elements such as Org blocks, -headings, and any other surface that needs to retain the colors -on display. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-nuanced-blue nil - "A nuanced blue background. -This does not specify a foreground of its own. Instead it is -meant to serve as the backdrop for elements such as Org blocks, -headings, and any other surface that needs to retain the colors -on display. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-nuanced-magenta nil - "A nuanced magenta background. -This does not specify a foreground of its own. Instead it is -meant to serve as the backdrop for elements such as Org blocks, -headings, and any other surface that needs to retain the colors -on display. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-nuanced-cyan nil - "A nuanced cyan background. -This does not specify a foreground of its own. Instead it is -meant to serve as the backdrop for elements such as Org blocks, -headings, and any other surface that needs to retain the colors -on display. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-special-cold nil - "Combines the special cold background and foreground values. -This is intended for cases when a neutral gray background is not -suitable and where a combination of more saturated colors would -not be appropriate. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-special-mild nil - "Combines the special mild background and foreground values. -This is intended for cases when a neutral gray background is not -suitable and where a combination of more saturated colors would -not be appropriate. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-special-warm nil - "Combines the special warm background and foreground values. -This is intended for cases when a neutral gray background is not -suitable and where a combination of more saturated colors would -not be appropriate. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-special-calm nil - "Combines the special calm background and foreground values. -This is intended for cases when a neutral gray background is not -suitable and where a combination of more saturated colors would -not be appropriate. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-diff-added nil - "Combines green colors for the added state in diffs. -The applied colors are contingent on the value assigned to -`modus-themes-diffs'. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-diff-changed nil - "Combines yellow colors for the changed state in diffs. -The applied colors are contingent on the value assigned to -`modus-themes-diffs'. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-diff-removed nil - "Combines red colors for the removed state in diffs. -The applied colors are contingent on the value assigned to -`modus-themes-diffs'. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-diff-refine-added nil - "Combines green colors for word-wise added state in diffs. -The applied colors are contingent on the value assigned to -`modus-themes-diffs'. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-diff-refine-changed nil - "Combines yellow colors for word-wise changed state in diffs. -The applied colors are contingent on the value assigned to -`modus-themes-diffs'. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-diff-refine-removed nil - "Combines red colors for word-wise removed state in diffs. -The applied colors are contingent on the value assigned to -`modus-themes-diffs'. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-diff-focus-added nil - "Combines green colors for the focused added state in diffs. -The applied colors are contingent on the value assigned to -`modus-themes-diffs'. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-diff-focus-changed nil - "Combines yellow colors for the focused changed state in diffs. -The applied colors are contingent on the value assigned to -`modus-themes-diffs'. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-diff-focus-removed nil - "Combines red colors for the focused removed state in diffs. -The applied colors are contingent on the value assigned to -`modus-themes-diffs'. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-diff-heading nil - "Combines blue colors for the diff hunk heading. -The applied colors are contingent on the value assigned to -`modus-themes-diffs'. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-pseudo-header nil - "Generic style for some elements that function like headings. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-mark-alt nil - "Combines yellow colors for marking special lines. -This is intended for use in modes such as Dired, Ibuffer, Proced. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-mark-del nil - "Combines red colors for marking deletable lines. -This is intended for use in modes such as Dired, Ibuffer, Proced. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-mark-sel nil - "Combines green colors for marking lines. -This is intended for use in modes such as Dired, Ibuffer, Proced. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-mark-symbol nil - "Applies a blue color and other styles for mark indicators. -This is intended for use in modes such as Dired, Ibuffer, Proced. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-heading-0 nil - "General purpose face for use as the document's title. -The exact attributes assigned to this face are contingent on the -values assigned to the `modus-themes-headings' variable. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-heading-1 nil - "General purpose face for use in headings level 1. -The exact attributes assigned to this face are contingent on the -values assigned to the `modus-themes-headings' variable. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-heading-2 nil - "General purpose face for use in headings level 2. -The exact attributes assigned to this face are contingent on the -values assigned to the `modus-themes-headings' variable. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-heading-3 nil - "General purpose face for use in headings level 3. -The exact attributes assigned to this face are contingent on the -values assigned to the `modus-themes-headings' variable. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-heading-4 nil - "General purpose face for use in headings level 4. -The exact attributes assigned to this face are contingent on the -values assigned to the `modus-themes-headings' variable. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-heading-5 nil - "General purpose face for use in headings level 5. -The exact attributes assigned to this face are contingent on the -values assigned to the `modus-themes-headings' variable. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-heading-6 nil - "General purpose face for use in headings level 6. -The exact attributes assigned to this face are contingent on the -values assigned to the `modus-themes-headings' variable. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-heading-7 nil - "General purpose face for use in headings level 7. -The exact attributes assigned to this face are contingent on the -values assigned to the `modus-themes-headings' variable. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-heading-8 nil - "General purpose face for use in headings level 8. -The exact attributes assigned to this face are contingent on the -values assigned to the `modus-themes-headings' variable. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-hl-line nil - "General purpose face for the current line. -The exact attributes assigned to this face are contingent on the -values assigned to the `modus-themes-hl-line' variable. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) +(dolist (color '( red green blue yellow magenta cyan + red-warmer green-warmer blue-warmer yellow-warmer magenta-warmer cyan-warmer + red-cooler green-cooler blue-cooler yellow-cooler magenta-cooler cyan-cooler + red-faint green-faint blue-faint yellow-faint magenta-faint cyan-faint + red-intense green-intense blue-intense yellow-intense magenta-intense cyan-intense)) + (custom-declare-face + (intern (format "modus-themes-fg-%s" color)) + nil (format "Face with %s foreground." color) + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :group 'modus-themes-faces)) + +(dolist (color '(red green yellow blue magenta cyan)) + (custom-declare-face + (intern (format "modus-themes-subtle-%s" color)) + nil (format "Subtle %s background." color) + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :group 'modus-themes-faces)) + +(dolist (color '(red green yellow blue magenta cyan)) + (custom-declare-face + (intern (format "modus-themes-intense-%s" color)) + nil (format "Intense %s background." color) + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :group 'modus-themes-faces)) + +(dolist (scope '(alt del sel)) + (custom-declare-face + (intern (format "modus-themes-mark-%s" scope)) + nil (format "Mark of type %s." scope) + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :group 'modus-themes-faces)) + +(dolist (scope '(note warning error)) + (custom-declare-face + (intern (format "modus-themes-lang-%s" scope)) + nil (format "Linter or spell check of type %s." scope) + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :group 'modus-themes-faces)) + +(dolist (scope '(current lazy)) + (custom-declare-face + (intern (format "modus-themes-search-%s" scope)) + nil (format "Search of type %s." scope) + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :group 'modus-themes-faces)) + +(define-obsolete-variable-alias + 'modus-themes-search-success + 'modus-themes-search-current + "4.0.0") + +(define-obsolete-variable-alias + 'modus-themes-search-success-lazy + 'modus-themes-search-lazy + "4.0.0") + +(dolist (scope '(code macro verbatim)) + (custom-declare-face + (intern (format "modus-themes-prose-%s" scope)) + nil (format "Construct of type %s for prose." scope) + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :group 'modus-themes-faces)) + +(define-obsolete-variable-alias + 'modus-themes-markup-code + 'modus-themes-prose-code + "4.0.0") + +(define-obsolete-variable-alias + 'modus-themes-markup-macro + 'modus-themes-prose-macro + "4.0.0") + +(define-obsolete-variable-alias + 'modus-themes-markup-verbatim + 'modus-themes-prose-verbatim + "4.0.0") + +(dotimes (n 9) + (custom-declare-face + (intern (format "modus-themes-heading-%d" n)) + nil (format "Level %d heading." n) + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :group 'modus-themes-faces)) (defface modus-themes-bold nil "Generic face for applying a conditional bold weight. -This behaves in accordance with `modus-themes-bold-constructs'. - -The actual styling of the face is done by `modus-themes-faces'." +This behaves in accordance with `modus-themes-bold-constructs'." + :package-version '(modus-themes . "4.0.0") + :version "30.1" :group 'modus-themes-faces) (defface modus-themes-slant nil "Generic face for applying a conditional slant (italics). -This behaves in accordance with `modus-themes-italic-constructs'. - -The actual styling of the face is done by `modus-themes-faces'." +This behaves in accordance with `modus-themes-italic-constructs'." + :package-version '(modus-themes . "4.0.0") + :version "30.1" :group 'modus-themes-faces) -(defface modus-themes-variable-pitch nil - "Generic face for applying a conditional `variable-pitch'. -This behaves in accordance with `modus-themes-mixed-fonts' and/or -`modus-themes-variable-pitch-ui'. - -The actual styling of the face is done by `modus-themes-faces'." +(defface modus-themes-key-binding nil + "Face for key bindings." + :package-version '(modus-themes . "4.0.0") + :version "30.1" :group 'modus-themes-faces) (defface modus-themes-fixed-pitch nil - "Generic face for applying a conditional `fixed-pitch'. -This behaves in accordance with `modus-themes-mixed-fonts'. - -The actual styling of the face is done by `modus-themes-faces'." + "Face for `fixed-pitch' if `modus-themes-mixed-fonts' is non-nil." + :package-version '(modus-themes . "4.0.0") + :version "30.1" :group 'modus-themes-faces) (defface modus-themes-ui-variable-pitch nil - "Face for `modus-themes-variable-pitch-ui'. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-lang-note nil - "Generic face for linter or spell checker notes. -The exact attributes and color combinations are controlled by -`modus-themes-lang-checkers'. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-lang-warning nil - "Generic face for linter or spell checker warnings. -The exact attributes and color combinations are controlled by -`modus-themes-lang-checkers'. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-lang-error nil - "Generic face for linter or spell checker errors. -The exact attributes and color combinations are controlled by -`modus-themes-lang-checkers'. - -The actual styling of the face is done by `modus-themes-faces'." + "Face for `variable-pitch' if `modus-themes-variable-pitch-ui' is non-nil." + :package-version '(modus-themes . "4.0.0") + :version "30.1" :group 'modus-themes-faces) (defface modus-themes-reset-soft nil @@ -1243,231 +206,178 @@ The actual styling of the face is done by `modus-themes-faces'." This is intended to be inherited by faces that should not retain properties from their context (e.g. an overlay over an underlined -text should not be underlined as well) yet still blend in. Also -see `modus-themes-reset-hard'. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-reset-hard nil - "Generic face to set all face properties to nil. - -This is intended to be inherited by faces that should not retain -properties from their context (e.g. an overlay over an underlined -text should not be underlined as well) and not blend in. Also -see `modus-themes-reset-soft'. - -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-key-binding nil - "Generic face for key bindings. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-search-success nil - "Generic face for successful search. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-search-success-modeline nil - "Generic mode line indicator for successful search. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-search-success-lazy nil - "Generic face for successful, lazily highlighted search. -The actual styling of the face is done by `modus-themes-faces'." +text should not be underlined as well) yet still blend in." :group 'modus-themes-faces) (defface modus-themes-prompt nil - "Generic face for command prompts. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -;; "Grue" is "green" and "blue". -(defface modus-themes-grue nil - "Generic face for `modus-themes-deuteranopia' foreground. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-grue-active nil - "Face for `modus-themes-deuteranopia' active foreground. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-grue-nuanced nil - "Face for `modus-themes-deuteranopia' nuanced foreground. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-grue-background-active nil - "Face for `modus-themes-deuteranopia' active background. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-grue-background-intense nil - "Face for `modus-themes-deuteranopia' intense background. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-grue-background-subtle nil - "Face for `modus-themes-deuteranopia' subtle background. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-grue-background-refine nil - "Face for `modus-themes-deuteranopia' refined background. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-link-symlink nil - "Face for `modus-themes-links' symbolic link. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-link-broken nil - "Face for `modus-themes-links' broken link. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-tab-backdrop nil - "Face of backdrop in tabbed interfaces. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-tab-active nil - "Face of active tab. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-tab-inactive nil - "Face of inactive tab. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-markup-code nil - "Face of inline code markup. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-markup-macro nil - "Face of macro markup. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-markup-verbatim nil - "Face of verbatim markup. -The actual styling of the face is done by `modus-themes-faces'." + "Generic face for command prompts." :group 'modus-themes-faces) (defface modus-themes-completion-selected nil - "Face for current selection in completion UIs. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-completion-selected-popup nil - "Face for current selection in completion UI popups. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-completion-match-0 nil - "Face for completions matches 0. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-completion-match-1 nil - "Face for completions matches 1. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-completion-match-2 nil - "Face for completions matches 2. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-completion-match-3 nil - "Face for completions matches 3. -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-box-button nil - "Face for widget buttons (e.g. in the Custom UI). -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) - -(defface modus-themes-box-button-pressed nil - "Face for pressed widget buttons (e.g. in the Custom UI). -The actual styling of the face is done by `modus-themes-faces'." - :group 'modus-themes-faces) + "Face for current selection in completion UIs." + :group 'modus-themes-faces) + +(defface modus-themes-button nil + "Face for graphical buttons." + :group 'modus-themes-faces) + +(dotimes (n 4) + (custom-declare-face + (intern (format "modus-themes-completion-match-%d" n)) + nil (format "Completions match level %d." n) + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :group 'modus-themes-faces)) + +(make-obsolete-variable 'modus-themes-reset-hard nil "4.0.0") +(make-obsolete-variable 'modus-themes-subtle-neutral nil "4.0.0") +(make-obsolete-variable 'modus-themes-intense-neutral nil "4.0.0") +(make-obsolete-variable 'modus-themes-refine-red nil "4.0.0") +(make-obsolete-variable 'modus-themes-refine-green nil "4.0.0") +(make-obsolete-variable 'modus-themes-refine-yellow nil "4.0.0") +(make-obsolete-variable 'modus-themes-refine-blue nil "4.0.0") +(make-obsolete-variable 'modus-themes-refine-magenta nil "4.0.0") +(make-obsolete-variable 'modus-themes-refine-cyan nil "4.0.0") +(make-obsolete-variable 'modus-themes-active-red nil "4.0.0") +(make-obsolete-variable 'modus-themes-active-green nil "4.0.0") +(make-obsolete-variable 'modus-themes-active-yellow nil "4.0.0") +(make-obsolete-variable 'modus-themes-active-blue nil "4.0.0") +(make-obsolete-variable 'modus-themes-active-magenta nil "4.0.0") +(make-obsolete-variable 'modus-themes-active-cyan nil "4.0.0") +(make-obsolete-variable 'modus-themes-fringe-red nil "4.0.0") +(make-obsolete-variable 'modus-themes-fringe-green nil "4.0.0") +(make-obsolete-variable 'modus-themes-fringe-yellow nil "4.0.0") +(make-obsolete-variable 'modus-themes-fringe-blue nil "4.0.0") +(make-obsolete-variable 'modus-themes-fringe-magenta nil "4.0.0") +(make-obsolete-variable 'modus-themes-fringe-cyan nil "4.0.0") +(make-obsolete-variable 'modus-themes-grue nil "4.0.0") +(make-obsolete-variable 'modus-themes-grue-nuanced nil "4.0.0") +(make-obsolete-variable 'modus-themes-red-nuanced nil "4.0.0") +(make-obsolete-variable 'modus-themes-green-nuanced nil "4.0.0") +(make-obsolete-variable 'modus-themes-yellow-nuanced nil "4.0.0") +(make-obsolete-variable 'modus-themes-blue-nuanced nil "4.0.0") +(make-obsolete-variable 'modus-themes-magenta-nuanced nil "4.0.0") +(make-obsolete-variable 'modus-themes-cyan-nuanced nil "4.0.0") +(make-obsolete-variable 'modus-themes-special-calm nil "4.0.0") +(make-obsolete-variable 'modus-themes-special-cold nil "4.0.0") +(make-obsolete-variable 'modus-themes-special-mild nil "4.0.0") +(make-obsolete-variable 'modus-themes-special-warm nil "4.0.0") +(make-obsolete-variable 'modus-themes-diff-added nil "4.0.0") +(make-obsolete-variable 'modus-themes-diff-changed nil "4.0.0") +(make-obsolete-variable 'modus-themes-diff-removed nil "4.0.0") +(make-obsolete-variable 'modus-themes-diff-refine-added nil "4.0.0") +(make-obsolete-variable 'modus-themes-diff-refine-changed nil "4.0.0") +(make-obsolete-variable 'modus-themes-diff-refine-removed nil "4.0.0") +(make-obsolete-variable 'modus-themes-diff-focus-added nil "4.0.0") +(make-obsolete-variable 'modus-themes-diff-focus-changed nil "4.0.0") +(make-obsolete-variable 'modus-themes-diff-focus-removed nil "4.0.0") +(make-obsolete-variable 'modus-themes-diff-heading nil "4.0.0") +(make-obsolete-variable 'modus-themes-pseudo-header nil "4.0.0") +(make-obsolete-variable 'modus-themes-mark-symbol nil "4.0.0") +(make-obsolete-variable 'modus-themes-hl-line nil "4.0.0") +(make-obsolete-variable 'modus-themes-search-success-modeline nil "4.0.0") +(make-obsolete-variable 'modus-themes-grue-active nil "4.0.0") +(make-obsolete-variable 'modus-themes-grue-background-active nil "4.0.0") +(make-obsolete-variable 'modus-themes-grue-background-intense nil "4.0.0") +(make-obsolete-variable 'modus-themes-grue-background-subtle nil "4.0.0") +(make-obsolete-variable 'modus-themes-grue-background-refine nil "4.0.0") +(make-obsolete-variable 'modus-themes-link-broken nil "4.0.0") +(make-obsolete-variable 'modus-themes-link-symlink nil "4.0.0") +(make-obsolete-variable 'modus-themes-tab-backdrop nil "4.0.0") +(make-obsolete-variable 'modus-themes-tab-active nil "4.0.0") +(make-obsolete-variable 'modus-themes-tab-inactive nil "4.0.0") +(make-obsolete-variable 'modus-themes-completion-selected-popup nil "4.0.0") +(make-obsolete-variable 'modus-themes-box-button nil "4.0.0") +(make-obsolete-variable 'modus-themes-box-button-pressed nil "4.0.0") -;;; Customization variables +;;;; Customization variables + +(defcustom modus-themes-custom-auto-reload t + "Automatically reload theme after setting options with Customize. -(defcustom modus-themes-inhibit-reload t - "Control theme reload when setting options with Customize. +All theme user options take effect when a theme is loaded. Any +subsequent changes require the theme to be reloaded. -By default, customizing a theme-related user option through the -Custom interfaces or with `customize-set-variable' will not -reload the currently active Modus theme. +When this variable has a non-nil value, any change made via the +Custom UI or related functions such as `customize-set-variable' +and `setopt' (Emacs 29), will trigger a reload automatically. -Enable this behavior by setting this variable to nil." +With a nil value, changes to user options have no further +consequences. The user must manually reload the theme." :group 'modus-themes - :package-version '(modus-themes . "1.5.0") - :version "28.1" + :package-version '(modus-themes . "4.0.0") + :version "30.1" :type 'boolean :link '(info-link "(modus-themes) Custom reload theme")) +(make-obsolete-variable 'modus-themes-inhibit-reload 'modus-themes-custom-auto-reload "4.0.0") + (defun modus-themes--set-option (sym val) "Custom setter for theme related user options. Will set SYM to VAL, and reload the current theme, unless -`modus-themes-inhibit-reload' is non-nil." +`modus-themes-custom-auto-reload' is nil." (set-default sym val) - (unless (or modus-themes-inhibit-reload - ;; Check if a theme is being loaded, in which case we - ;; don't want to reload a theme if the setter is - ;; invoked. `custom--inhibit-theme-enable' is set to nil - ;; by `enable-theme'. - (null (bound-and-true-p custom--inhibit-theme-enable))) - (let ((modus-themes-inhibit-reload t)) - (pcase (modus-themes--current-theme) - ('modus-operandi (modus-themes-load-operandi)) - ('modus-vivendi (modus-themes-load-vivendi)))))) - -(defcustom modus-themes-operandi-color-overrides nil - "Override colors in the Modus Operandi palette. - -For form, see `modus-themes-operandi-colors'." - :group 'modus-themes - :package-version '(modus-themes . "1.1.0") - :version "28.1" - :type '(alist :key-type symbol :value-type color) + (when (and modus-themes-custom-auto-reload + ;; Check if a theme is being loaded, in which case we + ;; don't want to reload a theme if the setter is + ;; invoked. `custom--inhibit-theme-enable' is set to nil + ;; by `enable-theme'. + (bound-and-true-p custom--inhibit-theme-enable)) + (when-let* ((modus-themes-custom-auto-reload t) + (theme (modus-themes--current-theme))) + (modus-themes-load-theme theme)))) + +(defconst modus-themes-items + '( modus-operandi modus-vivendi + modus-operandi-tinted modus-vivendi-tinted + modus-operandi-deuteranopia modus-vivendi-deuteranopia) + "Symbols of the Modus themes.") + +(defcustom modus-themes-to-toggle '(modus-operandi modus-vivendi) + "Specify two Modus themes for `modus-themes-toggle' command. +The variable `modus-themes-items' contains the symbols of all +official themes that form part of this collection. + +The default value of this user option includes the original +themes: `modus-operandi' (light) and `modus-vivendi' (dark). + +If the value is nil or otherwise does not specify two valid Modus +themes, the command `modus-themes-toggle' reverts to selecting a +theme from the list of available Modus themes. In effect, it is +the same as using the command `modus-themes-select'." + :type `(choice + (const :tag "No toggle" nil) + (list :tag "Pick two themes to toggle between" + (choice :tag "Theme one of two" + ,@(mapcar (lambda (theme) + (list 'const theme)) + modus-themes-items)) + (choice :tag "Theme two of two" + ,@(mapcar (lambda (theme) + (list 'const theme)) + modus-themes-items)))) + :package-version '(modus-themes . "4.0.0") + :version "30.1" :set #'modus-themes--set-option :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Override colors")) + :group 'modus-themes) -(defcustom modus-themes-vivendi-color-overrides nil - "Override colors in the Modus Vivendi palette. +(defvaralias 'modus-themes-post-load-hook 'modus-themes-after-load-theme-hook) -For form, see `modus-themes-vivendi-colors'." - :group 'modus-themes - :package-version '(modus-themes . "1.1.0") - :version "28.1" - :type '(alist :key-type symbol :value-type color) +(defcustom modus-themes-after-load-theme-hook nil + "Hook that runs after loading a Modus theme. +This is used by the command `modus-themes-toggle'." + :type 'hook + :package-version '(modus-themes . "4.0.0") + :version "30.1" :set #'modus-themes--set-option :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Override colors")) - -;; The byte compiler complains when a defcustom isn't a top level form -(let* ((names (mapcar (lambda (pair) - (symbol-name (car pair))) - modus-themes-operandi-colors)) - (colors (mapcar #'intern (sort names #'string<)))) - (put 'modus-themes-operandi-color-overrides - 'custom-options (copy-sequence colors)) - (put 'modus-themes-vivendi-color-overrides - 'custom-options (copy-sequence colors))) + :group 'modus-themes) + +(make-obsolete-variable 'modus-themes-operandi-color-overrides nil "4.0.0") +(make-obsolete-variable 'modus-themes-vivendi-color-overrides nil "4.0.0") (defvaralias 'modus-themes-slanted-constructs 'modus-themes-italic-constructs) @@ -1510,7 +420,9 @@ tables and code blocks, to remain monospaced when users opt for something like the command `variable-pitch-mode'. Users may need to explicitly configure the font family of -`fixed-pitch' in order to get a consistent experience." +`fixed-pitch' in order to get a consistent experience with their +typography (also check the `fontaine' package on GNU ELPA (by +Protesilaos))." :group 'modus-themes :package-version '(modus-themes . "1.7.0") :version "29.1" @@ -1519,68 +431,60 @@ Users may need to explicitly configure the font family of :initialize #'custom-initialize-default :link '(info-link "(modus-themes) Mixed fonts")) -(defcustom modus-themes-intense-mouseovers nil - "When non-nil use more intense style for mouse hover effects. - -This affects the generic `highlight' face which, strictly -speaking, is not limited to mouse usage." - :group 'modus-themes - :package-version '(modus-themes . "2.3.0") - :version "29.1" - :type 'boolean - :set #'modus-themes--set-option - :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Mouse hover effects")) - -(defconst modus-themes--headings-choice - '(set :tag "Properties" :greedy t - (const :tag "Background color" background) +(make-obsolete-variable 'modus-themes-intense-mouseovers nil "4.0.0") + +(defconst modus-themes--weight-widget + '(choice :tag "Font weight (must be supported by the typeface)" + (const :tag "Unspecified (use whatever the default is)" nil) + (const :tag "Thin" thin) + (const :tag "Ultra-light" ultralight) + (const :tag "Extra-light" extralight) + (const :tag "Light" light) + (const :tag "Semi-light" semilight) + (const :tag "Regular" regular) + (const :tag "Medium" medium) + (const :tag "Semi-bold" semibold) + (const :tag "Bold" bold) + (const :tag "Extra-bold" extrabold) + (const :tag "Ultra-bold" ultrabold)) + "List of supported font weights used by `defcustom' forms.") + +(defconst modus-themes--headings-widget + `(set :tag "Properties" :greedy t (const :tag "Proportionately spaced font (variable-pitch)" variable-pitch) - (const :tag "Overline" overline) - (choice :tag "Font weight (must be supported by the typeface)" - (const :tag "Bold (default)" nil) - (const :tag "Thin" thin) - (const :tag "Ultra-light" ultralight) - (const :tag "Extra-light" extralight) - (const :tag "Light" light) - (const :tag "Semi-light" semilight) - (const :tag "Regular" regular) - (const :tag "Medium" medium) - (const :tag "Semi-bold" semibold) - (const :tag "Extra-bold" extrabold) - (const :tag "Ultra-bold" ultrabold)) + ,modus-themes--weight-widget (radio :tag "Height" (float :tag "Floating point to adjust height by") (cons :tag "Cons cell of `(height . FLOAT)'" (const :tag "The `height' key (constant)" height) - (float :tag "Floating point"))) - (choice :tag "Colors" - (const :tag "Subtle colors" nil) - (const :tag "Rainbow colors" rainbow) - (const :tag "Monochrome" monochrome))) + (float :tag "Floating point")))) "Refer to the doc string of `modus-themes-headings'. This is a helper variable intended for internal use.") (defcustom modus-themes-headings nil - "Heading styles with optional list of values for levels 0-8. + "Heading styles with optional list of values per heading level. -This is an alist that accepts a (key . list-of-values) -combination. The key is either a number, representing the +This is an alist that accepts a (KEY . LIST-OF-VALUES) +combination. The KEY is either a number, representing the heading's level (0-8) or t, which pertains to the fallback style. +The named keys `agenda-date' and `agenda-structure' apply to the +Org agenda. -Level 0 is a special heading: it is used for what counts as a -document title or equivalent, such as the #+title construct we -find in Org files. Levels 1-8 are regular headings. +Level 0 is used for what counts as a document title or +equivalent, such as the #+title construct we find in Org files. +Levels 1-8 are regular headings. -The list of values covers symbols that refer to properties, as -described below. Here is a complete sample, followed by a -presentation of all available properties: +The LIST-OF-VALUES covers symbols that refer to properties, as +described below. Here is a complete sample with various +stylistic combinations, followed by a presentation of all +available properties: (setq modus-themes-headings - (quote ((1 . (background overline variable-pitch 1.5)) - (2 . (overline rainbow 1.3)) - (3 . (overline 1.1)) - (t . (monochrome))))) + (quote ((1 . (variable-pitch 1.5)) + (2 . (1.3)) + (agenda-date . (1.3)) + (agenda-structure . (variable-pitch light 1.8)) + (t . (1.1))))) By default (a nil value for this variable), all headings have a bold typographic weight, use a desaturated text color, have a @@ -1588,20 +492,6 @@ font family that is the same as the `default' face (typically monospaced), and a height that is equal to the `default' face's height. -A `rainbow' property makes the text color more saturated. - -An `overline' property draws a line above the area of the -heading. - -A `background' property applies a subtle tinted color to the -background of the heading. - -A `monochrome' property makes the heading the same as the base -color, which is that of the `default' face's foreground. When -`background' is also set, `monochrome' changes its color to gray. -If both `monochrome' and `rainbow' are set, the former takes -precedence. - A `variable-pitch' property changes the font family of the heading to that of the `variable-pitch' face (normally a proportionately spaced typeface). @@ -1611,9 +501,7 @@ accordingly, such as `light', `semibold', etc. Valid symbols are defined in the variable `modus-themes-weights'. The absence of a weight means that bold will be used by virtue of inheriting the `bold' face (check the manual for tweaking bold and italic -faces). For backward compatibility, the `no-bold' value is -accepted, though users are encouraged to specify a `regular' -weight instead. +faces). A number, expressed as a floating point (e.g. 1.5), adjusts the height of the heading to that many times the base font size. The @@ -1626,19 +514,20 @@ Combinations of any of those properties are expressed as a list, like in these examples: (semibold) - (rainbow background) - (overline monochrome semibold 1.3) - (overline monochrome semibold (height 1.3)) ; same as above - (overline monochrome semibold (height . 1.3)) ; same as above + (variable-pitch semibold 1.3) + (variable-pitch semibold (height 1.3)) ; same as above + (variable-pitch semibold (height . 1.3)) ; same as above The order in which the properties are set is not significant. In user configuration files the form may look like this: (setq modus-themes-headings - (quote ((1 . (background overline rainbow 1.5)) - (2 . (background overline 1.3)) - (t . (overline semibold))))) + (quote ((1 . (variable-pitch 1.5)) + (2 . (1.3)) + (agenda-date . (1.3)) + (agenda-structure . (variable-pitch light 1.8)) + (t . (1.1))))) When defining the styles per heading level, it is possible to pass a non-nil value (t) instead of a list of properties. This @@ -1646,350 +535,39 @@ will retain the original aesthetic for that level. For example: (setq modus-themes-headings (quote ((1 . t) ; keep the default style - (2 . (background overline)) - (t . (rainbow))))) ; style for all other headings + (2 . (semibold 1.2)) + (t . (variable-pitch))))) ; style for all other headings (setq modus-themes-headings - (quote ((1 . (background overline)) - (2 . (rainbow semibold)) + (quote ((1 . (variable-pitch extrabold 1.5)) + (2 . (semibold)) (t . t)))) ; default style for all other levels -For Org users, the extent of the heading depends on the variable -`org-fontify-whole-heading-line'. This affects the `overline' -and `background' properties. Depending on the version of Org, -there may be others, such as `org-fontify-done-headline'." +Note that the text color of headings, of their background, and +overline can all be set via the overrides. It is possible to +have any color combination for any heading level (something that +could not be done in older versions of the themes). + +Read Info node `(modus-themes) Option for palette overrides' as +well as Info node `(modus-themes) Make headings more or less +colorful'. Else check `modus-themes-common-palette-overrides' +and related user options." :group 'modus-themes - :package-version '(modus-themes . "2.5.0") - :version "29.1" + :package-version '(modus-themes . "4.0.0") + :version "30.1" :type `(alist :options ,(mapcar (lambda (el) - (list el modus-themes--headings-choice)) - '(0 1 2 3 4 5 6 7 8 t)) + (list el modus-themes--headings-widget)) + '(0 1 2 3 4 5 6 7 8 t agenda-date agenda-structure)) :key-type symbol - :value-type ,modus-themes--headings-choice) + :value-type ,modus-themes--headings-widget) :set #'modus-themes--set-option :initialize #'custom-initialize-default :link '(info-link "(modus-themes) Heading styles")) -(defcustom modus-themes-org-agenda nil - "Control the style of individual Org agenda constructs. - -This is an alist that accepts a (key . value) combination. Here -is a sample, followed by a description of all possible -combinations: - - (setq modus-themes-org-agenda - (quote ((header-block . (variable-pitch 1.5 semibold)) - (header-date . (grayscale workaholic bold-today 1.2)) - (event . (accented italic varied)) - (scheduled . uniform) - (habit . traffic-light)))) - -A `header-block' key applies to elements that concern the -headings which demarcate blocks in the structure of the agenda. -By default (a nil value) those are rendered in a bold typographic -weight, plus a height that is slightly taller than the default -font size. Acceptable values come in the form of a list that can -include either or both of those properties: - -- `variable-pitch' to use a proportionately spaced typeface; - -- A number as a floating point (e.g. 1.5) to set the height of - the text to that many times the default font height. A float - of 1.0 or the symbol `no-scale' have the same effect of making - the font the same height as the rest of the buffer. When - neither a number nor `no-scale' are present, the default is a - small increase in height (a value of 1.15). - - Instead of a floating point, an acceptable value can be in the - form of a cons cell like (height . FLOAT) or (height FLOAT), - where FLOAT is the given number. - -- The symbol of a weight attribute adjusts the font of the - heading accordingly, such as `light', `semibold', etc. Valid - symbols are defined in the variable `modus-themes-weights'. - The absence of a weight means that bold will be used by virtue - of inheriting the `bold' face (check the manual for tweaking - bold and italic faces). - -In case both a number and `no-scale' are in the list, the latter -takes precedence. If two numbers are specified, the first one is -applied. - -Example usage: - - (header-block . nil) - (header-block . (1.5)) - (header-block . (no-scale)) - (header-block . (variable-pitch 1.5)) - (header-block . (variable-pitch 1.5 semibold)) - -A `header-date' key covers date headings. Dates use only a -foreground color by default (a nil value), with weekdays and -weekends having a slight difference in hueness. The current date -has an added gray background. This key accepts a list of values -that can include any of the following properties: - -- `grayscale' to make weekdays use the main foreground color and - weekends a more subtle gray; - -- `workaholic' to make weekdays and weekends look the same in - terms of color; - -- `bold-today' to apply a bold typographic weight to the current - date; - -- `bold-all' to render all date headings in a bold weight; - -- `underline-today' applies an underline to the current date - while removing the background it has by default; - -- A number as a floating point (e.g. 1.2) to set the height of - the text to that many times the default font height. The - default is the same as the base font height (the equivalent of - 1.0). Instead of a floating point, an acceptable value can be - in the form of a cons cell like (height . FLOAT) or (height - FLOAT), where FLOAT is the given number. - -For example: - - (header-date . nil) - (header-date . (workaholic)) - (header-date . (grayscale bold-all)) - (header-date . (grayscale workaholic)) - (header-date . (grayscale workaholic bold-today)) - (header-date . (grayscale workaholic bold-today 1.2)) - -An `event' key covers (i) headings with a plain time stamp that -are shown on the agenda, also known as events, (ii) entries -imported from the diary, and (iii) other items that derive from a -symbolic expression or sexp (phases of the moon, holidays, etc.). -By default all those look the same and have a subtle foreground -color (the default is a nil value or an empty list). This key -accepts a list of properties. Those are: - -- `accented' applies an accent value to the event's foreground, - replacing the original gray. It makes all entries stand out more. -- `italic' adds a slant to the font's forms (italic or oblique - forms, depending on the typeface). -- `varied' differentiates between events with a plain time stamp - and entries that are generated from either the diary or a - symbolic expression. It generally puts more emphasis on - events. When `varied' is combined with `accented', it makes - only events use an accent color, while diary/sexp entries - retain their original subtle foreground. When `varied' is used - in tandem with `italic', it applies a slant only to diary and - sexp entries, not events. And when `varied' is the sole - property passed to the `event' key, it has the same meaning as - the list (italic varied). The combination of `varied', - `accented', `italic' covers all of the aforementioned cases. - -For example: - - (event . nil) - (event . (italic)) - (event . (accented italic)) - (event . (accented italic varied)) - -A `scheduled' key applies to tasks with a scheduled date. By -default (a nil value), these use varying shades of yellow to -denote (i) a past or current date and (ii) a future date. Valid -values are symbols: - -- nil (default); -- `uniform' to make all scheduled dates the same color; -- `rainbow' to use contrasting colors for past, present, future - scheduled dates. - -For example: - - (scheduled . nil) - (scheduled . uniform) - (scheduled . rainbow) - -A `habit' key applies to the `org-habit' graph. All possible -value are passed as a symbol. Those are: - -- The default (nil) is meant to conform with the original - aesthetic of `org-habit'. It employs all four color codes that - correspond to the org-habit states---clear, ready, alert, and - overdue---while distinguishing between their present and future - variants. This results in a total of eight colors in use: red, - yellow, green, blue, in tinted and shaded versions. They cover - the full set of information provided by the `org-habit' - consistency graph. - -- `simplified' is like the default except that it removes the - dichotomy between current and future variants by applying - uniform color-coded values. It applies a total of four colors: - red, yellow, green, blue. They produce a simplified - consistency graph that is more legible (or less \"busy\") than - the default. The intent is to shift focus towards the - distinction between the four states of a habit task, rather - than each state's present/future outlook. - -- `traffic-light' further reduces the available colors to red, - yellow, and green. As in `simplified', present and future - variants appear uniformly, but differently from it, the CLEAR - state is rendered in a green hue, instead of the original blue. - This is meant to capture the use-case where a habit task being - too early is less important than it being too late. The - difference between READY and CLEAR states is attenuated by - painting both of them using shades of green. This option thus - highlights the alert and overdue states. - -- When `modus-themes-deuteranopia' is non-nil the exact style of - the habit graph adapts to the needs of users with red-green - color deficiency by substituting every instance of green with - blue or cyan (depending on the specifics). - -For example: - - (habit . nil) - (habit . simplified) - (habit . traffic-light)" - :group 'modus-themes - :package-version '(modus-themes . "2.3.0") - :version "29.1" - :type '(set - (cons :tag "Block header" - (const header-block) - (set :tag "Header presentation" :greedy t - (choice :tag "Font style" - (const :tag "Use the original typeface (default)" nil) - (const :tag "Use `variable-pitch' font" variable-pitch)) - (choice :tag "Font weight (must be supported by the typeface)" - (const :tag "Bold (default)" nil) - (const :tag "Thin" thin) - (const :tag "Ultra-light" ultralight) - (const :tag "Extra-light" extralight) - (const :tag "Light" light) - (const :tag "Semi-light" semilight) - (const :tag "Regular" regular) - (const :tag "Medium" medium) - (const :tag "Semi-bold" semibold) - (const :tag "Extra-bold" extrabold) - (const :tag "Ultra-bold" ultrabold)) - (radio :tag "Scaling" - (const :tag "Slight increase in height (default)" nil) - (const :tag "Do not scale" no-scale) - (radio :tag "Number (float) to adjust height by" - (float :tag "Just the number") - (cons :tag "Cons cell of `(height . FLOAT)'" - (const :tag "The `height' key (constant)" height) - (float :tag "Floating point")))))) - (cons :tag "Date header" :greedy t - (const header-date) - (set :tag "Header presentation" :greedy t - (const :tag "Use grayscale for date headers" grayscale) - (const :tag "Do not differentiate weekdays from weekends" workaholic) - (const :tag "Make today bold" bold-today) - (const :tag "Make all dates bold" bold-all) - (const :tag "Make today underlined; remove the background" underline-today) - (radio :tag "Number (float) to adjust height by" - (float :tag "Just the number") - (cons :tag "Cons cell of `(height . FLOAT)'" - (const :tag "The `height' key (constant)" height) - (float :tag "Floating point"))))) - (cons :tag "Event entry" :greedy t - (const event) - (set :tag "Text presentation" :greedy t - (const :tag "Apply an accent color" accented) - (const :tag "Italic font slant (oblique forms)" italic) - (const :tag "Differentiate events from diary/sexp entries" varied))) - (cons :tag "Scheduled tasks" - (const scheduled) - (choice (const :tag "Yellow colors to distinguish current and future tasks (default)" nil) - (const :tag "Uniform subtle warm color for all scheduled tasks" uniform) - (const :tag "Rainbow-colored scheduled tasks" rainbow))) - (cons :tag "Habit graph" - (const habit) - (choice (const :tag "Follow the original design of `org-habit' (default)" nil) - (const :tag "Do not distinguish between present and future variants" simplified) - (const :tag "Use only red, yellow, green" traffic-light)))) - :set #'modus-themes--set-option - :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Org agenda")) - -(defcustom modus-themes-fringes 'subtle - "Control the visibility of fringes. - -When the value is nil, do not apply a distinct background color. - -With a value of `subtle' use a gray background color that is -visible yet close to the main background color. - -With `intense' use a more pronounced gray background color." - :group 'modus-themes - :package-version '(modus-themes . "3.0.0") - :version "29.1" - :type '(choice - (const :format "[%v] %t\n" :tag "No visible fringes" nil) - (const :format "[%v] %t\n" :tag "Subtle gray background" subtle) - (const :format "[%v] %t\n" :tag "Intense gray background" intense)) - :set #'modus-themes--set-option - :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Fringes")) - -(defcustom modus-themes-lang-checkers nil - "Control the style of spelling and code checkers/linters. - -The value is a list of properties, each designated by a symbol. -The default (nil) applies a color-coded underline to the affected -text, while it leaves the original foreground intact. If the -display spec of Emacs has support for it, the underline's style -is that of a wave, otherwise it is a straight line. - -The property `straight-underline' ensures that the underline -under the affected text is always drawn as a straight line. - -The property `text-also' applies the same color of the underline -to the affected text. - -The property `background' adds a color-coded background. - -The property `intense' amplifies the applicable colors if -`background' and/or `text-also' are set. If `intense' is set on -its own, then it implies `text-also'. - -The property `faint' uses nuanced colors for the underline and -for the foreground when `text-also' is included. If both `faint' -and `intense' are specified, the former takes precedence. - -Combinations of any of those properties can be expressed in a -list, as in those examples: - - (background) - (straight-underline intense) - (background text-also straight-underline) - -The order in which the properties are set is not significant. - -In user configuration files the form may look like this: - - (setq modus-themes-lang-checkers (quote (text-also background))) - -NOTE: The placement of the straight underline, though not the -wave style, is controlled by the built-in variables -`underline-minimum-offset', `x-underline-at-descent-line', -`x-use-underline-position-properties'. - -To disable fringe indicators for Flymake or Flycheck, refer to -variables `flymake-fringe-indicator-position' and -`flycheck-indication-mode', respectively." - :group 'modus-themes - :package-version '(modus-themes . "1.7.0") - :version "29.1" - :type '(set :tag "Properties" :greedy t - (const :tag "Straight underline" straight-underline) - (const :tag "Colorise text as well" text-also) - (const :tag "With background" background) - (choice :tag "Overall coloration" - (const :tag "Intense colors" intense) - (const :tag "Faint colors" faint))) - :set #'modus-themes--set-option - :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Language checkers")) +(make-obsolete-variable 'modus-themes-org-agenda nil "4.0.0") +(make-obsolete-variable 'modus-themes-fringes nil "4.0.0") +(make-obsolete-variable 'modus-themes-lang-checkers nil "4.0.0") (defcustom modus-themes-org-blocks nil "Set the overall style of Org code blocks, quotes, and the like. @@ -2004,208 +582,47 @@ block's contents. It also affects the begin and end lines of the block as they get another shade of gray as their background, which differentiates them from the contents of the block. All background colors extend to the edge of the window, giving the -area a rectangular, \"blocky\" presentation. +area a rectangular, \"blocky\" presentation. If the begin/end +lines do not extend in this way, check the value of the Org user +option `org-fontify-whole-block-delimiter-line'. -Option `tinted-background' uses a slightly colored background for -the contents of the block. The exact color will depend on the +Option `tinted-background' uses a colored background for the +contents of the block. The exact color value will depend on the programming language and is controlled by the variable `org-src-block-faces' (refer to the theme's source code for the current association list). For this to take effect, the Org -buffer needs to be restarted with `org-mode-restart'. In this -scenario, it may be better to inhibit the extension of the -delimiter lines' background to the edge of the window because Org -does not provide a mechanism to update their colors depending on -the contents of the block. Disable the extension of such -backgrounds by setting `org-fontify-whole-block-delimiter-line' -to nil. - -Code blocks use their major mode's colors only when the variable -`org-src-fontify-natively' is non-nil. While quote/verse blocks -require setting `org-fontify-quote-and-verse-blocks' to a non-nil -value. - -Older versions of the themes provided options `grayscale' (or -`greyscale') and `rainbow'. Those will continue to work as they -are aliases for `gray-background' and `tinted-background', -respectively." +buffer needs to be restarted with `org-mode-restart'. + +Code blocks use their major mode's fontification (syntax +highlighting) only when the variable `org-src-fontify-natively' +is non-nil. While quote/verse blocks require setting +`org-fontify-quote-and-verse-blocks' to a non-nil value." :group 'modus-themes - :package-version '(modus-themes . "2.1.0") - :version "28.1" + :package-version '(modus-themes . "4.0.0") + :version "30.1" :type '(choice (const :format "[%v] %t\n" :tag "No Org block background (default)" nil) (const :format "[%v] %t\n" :tag "Subtle gray block background" gray-background) - (const :format "[%v] %t\n" :tag "Alias for `gray-background'" grayscale) ; for backward compatibility - (const :format "[%v] %t\n" :tag "Alias for `gray-background'" greyscale) - (const :format "[%v] %t\n" :tag "Color-coded background per programming language" tinted-background) - (const :format "[%v] %t\n" :tag "Alias for `tinted-background'" rainbow)) ; back compat + (const :format "[%v] %t\n" :tag "Color-coded background per programming language" tinted-background)) :set #'modus-themes--set-option :initialize #'custom-initialize-default :link '(info-link "(modus-themes) Org mode blocks")) -(defcustom modus-themes-mode-line nil - "Control the overall style of the mode line. - -The value is a list of properties, each designated by a symbol. -The default (a nil value or an empty list) is a two-dimensional -rectangle with a border around it. The active and the inactive -mode lines use different shades of grayscale values for the -background, foreground, border. - -The `3d' property applies a three-dimensional effect to the -active mode line. The inactive mode lines remain two-dimensional -and are toned down a bit, relative to the default style. - -The `moody' property optimizes the mode line for use with the -library of the same name (hereinafter referred to as Moody). -In practice, it removes the box effect and replaces it with -underline and overline properties. It also tones down the -inactive mode lines. Despite its intended purpose, this option -can also be used without the Moody library (please consult the -themes' manual on this point for more details). If both `3d' and -`moody' properties are set, the latter takes precedence. - -The `borderless' property removes the color of the borders. It -does not actually remove the borders, but only makes their color -the same as the background, effectively creating some padding. - -The `accented' property ensures that the active mode line uses a -colored background instead of the standard shade of gray. - -A positive integer (natural number or natnum) applies a padding -effect of NATNUM pixels at the boundaries of the mode lines. The -default value is 1 and does not need to be specified explicitly. -The padding has no effect when the `moody' property is also used, -because Moody already applies its own tweaks. To ensure that the -underline is placed at the bottom of the mode line, set -`x-underline-at-descent-line' to non-nil (this is not needed when -the `borderless' property is also set). For users on Emacs 29, -the `x-use-underline-position-properties' variable must also be -set to nil. - -The padding can also be expressed as a cons cell in the form -of (padding . NATNUM) or (padding NATNUM) where the key is -constant and NATNUM is the desired natural number. - -A floating point (e.g. 0.9) applies an adjusted height to the -mode line's text as a multiple of the main font size. The -default rate is 1.0 and does not need to be specified. Apart -from a floating point, the height may also be expressed as a cons -cell in the form of (height . FLOAT) or (height FLOAT) where the -key is constant and the FLOAT is the desired number. - -Combinations of any of those properties are expressed as a list, -like in these examples: - - (accented) - (borderless 3d) - (moody accented borderless) - -Same as above, using the padding and height as an example (these -all yield the same result): - - (accented borderless 4 0.9) - (accented borderless (padding . 4) (height . 0.9)) - (accented borderless (padding 4) (height 0.9)) +(make-obsolete-variable 'modus-themes-mode-line nil "4.0.0") +(make-obsolete-variable 'modus-themes-diffs nil "4.0.0") -The order in which the properties are set is not significant. - -In user configuration files the form may look like this: - - (setq modus-themes-mode-line (quote (borderless accented))) - -Note that Moody does not expose any faces that the themes could -style directly. Instead it re-purposes existing ones to render -its tabs and ribbons. As such, there may be cases where the -contrast ratio falls below the 7:1 target that the themes conform -with (WCAG AAA). To hedge against this, we configure a fallback -foreground for the `moody' property, which will come into effect -when the background of the mode line changes to something less -accessible, such as Moody ribbons (read the doc string of -`set-face-attribute', specifically `:distant-foreground'). This -fallback is activated when Emacs determines that the background -and foreground of the given construct are too close to each other -in terms of color distance. In practice, users will need to -experiment with the variable `face-near-same-color-threshold' to -trigger the effect. We find that a value of 45000 shall suffice, -contrary to the default 30000. Though for the combinations that -involve the `accented' and `moody' properties, as mentioned -above, that should be raised up to 70000. Do not set it too -high, because it has the adverse effect of always overriding the -default colors (which have been carefully designed to be highly -accessible). - -Furthermore, because Moody expects an underline and overline -instead of a box style, it is strongly advised to set -`x-underline-at-descent-line' to a non-nil value." - :group 'modus-themes - :package-version '(modus-themes . "2.3.0") - :version "29.1" - :type '(set :tag "Properties" :greedy t - (choice :tag "Overall style" - (const :tag "Rectangular Border" nil) - (const :tag "3d borders" 3d) - (const :tag "No box effects (Moody-compatible)" moody)) - (const :tag "Colored background" accented) - (const :tag "Without border color" borderless) - (radio :tag "Padding" - (natnum :tag "Natural number (e.g. 4)") - (cons :tag "Cons cell of `(padding . NATNUM)'" - (const :tag "The `padding' key (constant)" padding) - (natnum :tag "Natural number"))) - (radio :tag "Height" - (float :tag "Floating point (e.g. 0.9)") - (cons :tag "Cons cell of `(height . FLOAT)'" - (const :tag "The `height' key (constant)" height) - (float :tag "Floating point")))) - :set #'modus-themes--set-option - :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Mode line")) - -(defcustom modus-themes-diffs nil - "Adjust the overall style of diffs. - -The default (nil) uses fairly intense color combinations for -diffs, by applying prominently colored backgrounds, with -appropriately tinted foregrounds. - -Option `desaturated' follows the same principles as with the -default (nil), though it tones down all relevant colors. - -Option `bg-only' applies a background but does not override the -text's foreground. This makes it suitable for a non-nil value -passed to `diff-font-lock-syntax' (note: Magit does not support -syntax highlighting in diffs---last checked on 2021-12-02). - -When the user option `modus-themes-deuteranopia' is non-nil, all -diffs will use a red/blue color-coding system instead of the -standard red/green. Other stylistic changes are made in the -interest of optimizing for such a use-case." - :group 'modus-themes - :package-version '(modus-themes . "2.0.0") - :version "29.1" - :type '(choice - (const :format "[%v] %t\n" :tag "Intensely colored backgrounds (default)" nil) - (const :format "[%v] %t\n" :tag "Slightly accented backgrounds with tinted text" desaturated) - (const :format "[%v] %t\n" :tag "Apply color-coded backgrounds; keep syntax colors intact" bg-only)) - :set #'modus-themes--set-option - :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Diffs")) - -(defcustom modus-themes-completions - '((selection . (intense)) - (popup . (intense))) +(defcustom modus-themes-completions nil "Control the style of completion user interfaces. -This affects Company, Corfu, Flx, Helm, Icomplete/Fido, Ido, Ivy, -Orderless, Selectrum, Vertico. The value is an alist that takes -the form of a (KEY . PROPERTIES) combination. KEY is a symbol, -while PROPERTIES is a list. Here is a sample, followed by a -description of the particularities: +This affects Company, Corfu, Flx, Icomplete/Fido, Ido, Ivy, +Orderless, Vertico. The value is an alist of expressions, each +of which takes the form of (KEY . LIST-OF-PROPERTIES). KEY is a +symbol, while PROPERTIES is a list. Here is a sample, followed +by a description of the particularities: (setq modus-themes-completions - (quote ((matches . (extrabold background intense)) - (selection . (semibold accented intense)) - (popup . (accented))))) + (quote ((matches . (extrabold background)) + (selection . (semibold italic))))) The `matches' key refers to the highlighted characters that correspond to the user's input. When its properties are nil or @@ -2214,11 +631,6 @@ have a bold weight and a colored foreground. The list of properties may include any of the following symbols regardless of the order they may appear in: -- `background' to add a background color; - -- `intense' to increase the overall coloration (also amplifies - the `background', if present); - - `underline' to draw a line below the characters; - `italic' to use a slanted font (italic or oblique forms); @@ -2235,13 +647,6 @@ a subtle gray background, a bold weight, and the base foreground value for the text. The list of properties it accepts is as follows (order is not significant): -- `accented' to make the background colorful instead of gray; - -- `text-also' to apply extra color to the text of the selected - line; - -- `intense' to increase the overall coloration; - - `underline' to draw a line below the characters; - `italic' to use a slanted font (italic or oblique forms); @@ -2251,99 +656,33 @@ follows (order is not significant): variable `modus-themes-weights'. The absence of a weight means that bold will be used. -The `popup' key takes the same values as `selection'. The only -difference is that it applies specifically to user interfaces -that display an inline popup and thus have slightly different -styling requirements than the minibuffer. The two prominent -packages are `company' and `corfu'. - -Apart from specifying each key separately, a fallback list is +Apart from specifying each key separately, a catch-all list is accepted. This is only useful when the desired aesthetic is the same across all keys that are not explicitly referenced. For example, this: (setq modus-themes-completions - (quote ((t . (extrabold intense))))) + (quote ((t . (extrabold underline))))) Is the same as: (setq modus-themes-completions - (quote ((matches . (extrabold intense)) - (selection . (extrabold intense)) - (popup . (extrabold intense))))) - -In the case of the fallback, any property that does not apply to -the corresponding key is simply ignored (`matches' does not have -`accented' and `text-also', while `selection' and `popup' do not -have `background'). - -Check the manual for tweaking `bold' and `italic' faces: Info -node `(modus-themes) Configure bold and italic faces'. - -Also refer to the documentation of the `orderless' package for -its intersection with `company' (if you choose to use those in -tandem)." + (quote ((matches . (extrabold underline)) + (selection . (extrabold underline)))))" :group 'modus-themes - :package-version '(modus-themes . "3.0.0") - :version "29.1" + :package-version '(modus-themes . "4.0.0") + :version "30.1" :type `(set (cons :tag "Matches" (const matches) (set :tag "Style of matches" :greedy t - (choice :tag "Font weight (must be supported by the typeface)" - (const :tag "Bold (default)" nil) - (const :tag "Thin" thin) - (const :tag "Ultra-light" ultralight) - (const :tag "Extra-light" extralight) - (const :tag "Light" light) - (const :tag "Semi-light" semilight) - (const :tag "Regular" regular) - (const :tag "Medium" medium) - (const :tag "Semi-bold" semibold) - (const :tag "Extra-bold" extrabold) - (const :tag "Ultra-bold" ultrabold)) - (const :tag "With added background" background) - (const :tag "Increased coloration" intense) + ,modus-themes--weight-widget (const :tag "Italic font (oblique or slanted forms)" italic) (const :tag "Underline" underline))) (cons :tag "Selection" (const selection) (set :tag "Style of selection" :greedy t - (choice :tag "Font weight (must be supported by the typeface)" - (const :tag "Bold (default)" nil) - (const :tag "Thin" thin) - (const :tag "Ultra-light" ultralight) - (const :tag "Extra-light" extralight) - (const :tag "Light" light) - (const :tag "Semi-light" semilight) - (const :tag "Regular" regular) - (const :tag "Medium" medium) - (const :tag "Semi-bold" semibold) - (const :tag "Extra-bold" extrabold) - (const :tag "Ultra-bold" ultrabold)) - (const :tag "Apply color to the line's text" text-also) - (const :tag "With accented background" accented) - (const :tag "Increased coloration" intense) - (const :tag "Italic font (oblique or slanted forms)" italic) - (const :tag "Underline" underline))) - (cons :tag "Popup" - (const popup) - (set :tag "Style of completion pop-ups" :greedy t - (choice :tag "Font weight (must be supported by the typeface)" - (const :tag "Bold (default)" nil) - (const :tag "Thin" thin) - (const :tag "Ultra-light" ultralight) - (const :tag "Extra-light" extralight) - (const :tag "Light" light) - (const :tag "Semi-light" semilight) - (const :tag "Regular" regular) - (const :tag "Medium" medium) - (const :tag "Semi-bold" semibold) - (const :tag "Extra-bold" extrabold) - (const :tag "Ultra-bold" ultrabold)) - (const :tag "Apply color to the line's text" text-also) - (const :tag "With accented background" accented) - (const :tag "Increased coloration" intense) + ,modus-themes--weight-widget (const :tag "Italic font (oblique or slanted forms)" italic) (const :tag "Underline" underline)))) :set #'modus-themes--set-option @@ -2355,512 +694,509 @@ tandem)." The value is a list of properties, each designated by a symbol. The default (a nil value or an empty list) means to only use a -subtle accented foreground color. - -The property `background' applies a background color to the -prompt's text. By default, this is a subtle accented value. - -The property `intense' makes the foreground color more prominent. -If the `background' property is also set, it amplifies the value -of the background as well. - -The property `gray' changes the prompt's colors to grayscale. -This affects the foreground and, if the `background' property is -also set, the background. Its effect is subtle, unless it is -combined with the `intense' property. +subtle colored foreground color. -The property `bold' makes the text use a bold typographic weight. -Similarly, `italic' adds a slant to the font's forms (italic or +The `italic' property adds a slant to the font's forms (italic or oblique forms, depending on the typeface). -Combinations of any of those properties are expressed as a list, -like in these examples: - - (intense) - (bold intense) - (intense bold gray) - (intense background gray bold) - -The order in which the properties are set is not significant. - -In user configuration files the form may look like this: - - (setq modus-themes-prompts (quote (background gray)))" - :group 'modus-themes - :package-version '(modus-themes . "1.5.0") - :version "28.1" - :type '(set :tag "Properties" :greedy t - (const :tag "With Background" background) - (const :tag "Intense" intense) - (const :tag "Grayscale" gray) - (const :tag "Bold font weight" bold) - (const :tag "Italic font slant" italic)) - :set #'modus-themes--set-option - :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Command prompts")) - -(defcustom modus-themes-hl-line '(intense) - "Control the current line highlight of `hl-line-mode'. - -The value is a list of properties, each designated by a symbol. -With a nil value, or an empty list, the style is a subtle gray -background color. - -The property `accented' changes the background to a colored -variant. - -An `underline' property draws a line below the highlighted area. -Its color is similar to the background, so gray by default or an -accent color when `accented' is also set. - -An `intense' property amplifies the colors in use, which may be -both the background and the underline. - -Combinations of any of those properties are expressed as a list, -like in these examples: - - (intense) - (underline intense) - (accented intense underline) - -The order in which the properties are set is not significant. - -In user configuration files the form may look like this: - - (setq modus-themes-hl-line (quote (underline accented))) - -Set `x-underline-at-descent-line' to a non-nil value so that the -placement of the underline coincides with the lower boundary of -the colored background." - :group 'modus-themes - :package-version '(modus-themes . "3.0.0") - :version "29.1" - :type '(set :tag "Properties" :greedy t - (const :tag "Colored background" accented) - (const :tag "Underline" underline) - (const :tag "Intense style" intense)) - :set #'modus-themes--set-option - :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Line highlighting")) - -(defcustom modus-themes-subtle-line-numbers nil - "Use more subtle style for command `display-line-numbers-mode'." - :group 'modus-themes - :package-version '(modus-themes . "1.2.0") - :version "28.1" - :type 'boolean - :set #'modus-themes--set-option - :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Line numbers")) - -(defcustom modus-themes-markup nil - "Style markup in Org, Markdown, and others. - -This affects constructs such as Org's =verbatim= and ~code~. - -The value is a list of properties, each designated by a symbol. -The default (a nil value or an empty list) is a foreground -color. - -The `italic' property applies a typographic slant (italics). - -The `bold' property applies a heavier typographic weight. - -The `background' property adds a background color. The -background is a shade of gray, unless the `intense' property is -also set. - -The `intense' property amplifies the existing coloration. When -`background' is used, the background color is enhanced as well -and becomes tinted instead of being gray. +The symbol of a font weight attribute such as `light', `semibold', +et cetera, adds the given weight to links. Valid symbols are +defined in the variable `modus-themes-weights'. The absence of a +weight means that the one of the underlying text will be used. Combinations of any of those properties are expressed as a list, like in these examples: - (bold) (bold italic) - (bold italic intense) - (bold italic intense background) + (italic semibold) The order in which the properties are set is not significant. In user configuration files the form may look like this: - (setq modus-themes-markup (quote (bold italic))) - -Also check the variables `org-hide-emphasis-markers', -`org-hide-macro-markers'." - :group 'modus-themes - :package-version '(modus-themes . "2.1.0") - :version "29.1" - :type '(set :tag "Properties" :greedy t - (const :tag "Added background" background) - (const :tag "Intense colors" intense) - (const :tag "Bold weight" bold) - (const :tag "Italics (slanted text)" italic)) - :set #'modus-themes--set-option - :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Markup")) - -(defcustom modus-themes-paren-match nil - "Control the style of matching parentheses or delimiters. - -The value is a list of properties, each designated by a symbol. -The default (a nil value or an empty list) is a subtle background -color. - -The `bold' property adds a bold weight to the characters of the -matching delimiters. - -The `intense' property applies a more prominent background color -to the delimiters. - -The `underline' property draws a straight line under the affected -text. - -Combinations of any of those properties are expressed as a list, -like in these examples: - - (bold) - (underline intense) - (bold intense underline) - -The order in which the properties are set is not significant. - -In user configuration files the form may look like this: - - (setq modus-themes-paren-match (quote (bold intense)))" - :group 'modus-themes - :package-version '(modus-themes . "1.5.0") - :version "28.1" - :type '(set :tag "Properties" :greedy t - (const :tag "Bold weight" bold) - (const :tag "Intense background color" intense) - (const :tag "Underline" underline)) - :set #'modus-themes--set-option - :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Matching parentheses")) - -(defcustom modus-themes-syntax nil - "Control the overall style of code syntax highlighting. - -The value is a list of properties, each designated by a symbol. -The default (a nil value or an empty list) is to use a balanced -combination of colors on the cyan-blue-magenta side of the -spectrum. There is little to no use of greens, yellows, and -reds. Comments are gray, strings are blue colored, doc strings -are a shade of cyan, while color combinations are designed to -avoid exaggerations. - -The property `faint' fades the saturation of all applicable -colors, where that is possible or appropriate. - -The property `yellow-comments' applies a yellow color to -comments. - -The property `green-strings' applies a green color to strings and -a green tint to doc strings. - -The property `alt-syntax' changes the combination of colors -beyond strings and comments, so that the effective palette is -broadened to provide greater variety relative to the default. - -Combinations of any of those properties are expressed as a list, -like in these examples: - - (faint) - (green-strings yellow-comments) - (alt-syntax green-strings yellow-comments) - (faint alt-syntax green-strings yellow-comments) - -The order in which the properties are set is not significant. - -In user configuration files the form may look like this: - - (setq modus-themes-syntax (quote (faint alt-syntax))) - -Independent of this variable, users may also control the use of a -bold weight or italic text: `modus-themes-bold-constructs' and -`modus-themes-italic-constructs'." - :group 'modus-themes - :package-version '(modus-themes . "1.5.0") - :version "28.1" - :type '(set :tag "Properties" :greedy t - (const :tag "Faint colors" faint) - (const :tag "Yellow comments" yellow-comments) - (const :tag "Green strings" green-strings) - (const :tag "Alternative set of colors" alt-syntax)) - :set #'modus-themes--set-option - :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Syntax styles")) - -(defcustom modus-themes-links nil - "Set the style of links. - -The value is a list of properties, each designated by a symbol. -The default (a nil value or an empty list) is a prominent text -color, typically blue, with an underline of the same color. - -For the style of the underline, a `neutral-underline' property -turns the color of the line into a subtle gray, while the -`no-underline' property removes the line altogether. If both of -those are set, the latter takes precedence. - -For text coloration, a `faint' property desaturates the color of -the text and the underline, unless the underline is affected by -the aforementioned properties. While a `no-color' property -removes the color from the text. If both of those are set, the -latter takes precedence. - -A `bold' property applies a heavy typographic weight to the text -of the link. - -An `italic' property adds a slant to the link's text (italic or -oblique forms, depending on the typeface). - -A `background' property applies a subtle tinted background color. - -In case both `no-underline' and `no-color' are set, then a subtle -gray background is applied to all links. This can still be -combined with the `bold' and `italic' properties. - -Combinations of any of those properties are expressed as a list, -like in these examples: - - (faint) - (no-underline faint) - (no-color no-underline bold) - (italic bold background no-color no-underline) - -The order in which the properties are set is not significant. - -In user configuration files the form may look like this: - - (setq modus-themes-links (quote (neutral-underline background))) - -The placement of the underline, meaning its proximity to the -text, is controlled by `x-use-underline-position-properties', -`x-underline-at-descent-line', `underline-minimum-offset'. -Please refer to their documentation strings." + (setq modus-themes-prompts (quote (extrabold italic)))" :group 'modus-themes - :package-version '(modus-themes . "1.5.0") - :version "28.1" - :type '(set :tag "Properties" :greedy t - (choice :tag "Text coloration" - (const :tag "Saturared color (default)" nil) - (const :tag "Faint coloration" faint) - (const :tag "No color (use main black/white)" no-color)) - (choice :tag "Underline" - (const :tag "Same color as text (default)" nil) - (const :tag "Neutral (gray) underline color" neutral-underline) - (const :tag "No underline" no-underline)) - (const :tag "Bold font weight" bold) + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :type `(set :tag "Properties" :greedy t (const :tag "Italic font slant" italic) - (const :tag "Subtle background color" background)) + ,modus-themes--weight-widget) :set #'modus-themes--set-option :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Link styles")) - -(defcustom modus-themes-region nil - "Control the overall style of the active region. - -The value is a list of properties, each designated by a symbol. -The default (a nil value or an empty list) is a prominent gray -background that overrides all foreground colors in the area it -encompasses. Its reach extends to the edge of the window. - -The `no-extend' property limits the region to the end of the -line, so that it does not reach the edge of the window. - -The `bg-only' property makes the region's background color more -subtle to allow the underlying text to retain its foreground -colors. - -The `accented' property applies a more colorful background to the -region. - -Combinations of any of those properties are expressed as a list, -like in these examples: - - (no-extend) - (bg-only accented) - (accented bg-only no-extend) - -The order in which the properties are set is not significant. - -In user configuration files the form may look like this: + :link '(info-link "(modus-themes) Command prompts")) - (setq modus-themes-region (quote (bg-only no-extend)))" +(make-obsolete-variable 'modus-themes-subtle-line-numbers nil "4.0.0") +(make-obsolete-variable 'modus-themes-markup nil "4.0.0") +(make-obsolete-variable 'modus-themes-paren-match nil "4.0.0") +(make-obsolete-variable 'modus-themes-syntax nil "4.0.0") +(make-obsolete-variable 'modus-themes-links nil "4.0.0") +(make-obsolete-variable 'modus-themes-region nil "4.0.0") +(make-obsolete-variable 'modus-themes-deuteranopia nil "4.0.0") +(make-obsolete-variable 'modus-themes-mail-citations nil "4.0.0") +(make-obsolete-variable 'modus-themes-tabs-accented nil "4.0.0") +(make-obsolete-variable 'modus-themes-box-buttons nil "4.0.0") + +(defcustom modus-themes-common-palette-overrides nil + "Set palette overrides for all the Modus themes. + +Mirror the elements of a theme's palette, overriding their value. +The palette variables are named THEME-NAME-palette, while +individual theme overrides are THEME-NAME-palette-overrides. The +THEME-NAME is one of the symbols in `modus-themes-items'. For +example: + +- `modus-operandi-palette' +- `modus-operandi-palette-overrides' + +Individual theme overrides take precedence over these common +overrides. + +The idea of common overrides is to change semantic color +mappings, such as to make the cursor red. Wherea theme-specific +overrides can also be used to change the value of a named color, +such as what hexadecimal RGB value the red-warmer symbol +represents." :group 'modus-themes - :package-version '(modus-themes . "1.5.0") - :version "28.1" - :type '(set :tag "Properties" :greedy t - (const :tag "Do not extend to the edge of the window" no-extend) - (const :tag "Background only (preserve underlying colors)" bg-only) - (const :tag "Accented background" accented)) + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :type '(repeat (list symbol (choice symbol string))) ; TODO 2022-12-18: Refine overrides' :type :set #'modus-themes--set-option :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Active region")) - -(defcustom modus-themes-deuteranopia nil - "When non-nil use red/blue color-coding instead of red/green. - -This is to account for red-green color deficiency, also know as -deuteranopia and variants. It applies to all contexts where -there can be a color-coded distinction between failure or -success, a to-do or done state, a mark for deletion versus a mark -for selection (e.g. in Dired), current and lazily highlighted -search matches, removed lines in diffs as opposed to added ones, -and so on. - -Note that this does not change all colors throughout the active -theme, but only applies to cases that have color-coding -significance. For example, regular code syntax highlighting is -not affected. There is no such need because of the themes' -overarching commitment to the highest legibility standard, which -ensures that text is readable regardless of hue, as well as the -predominance of colors on the blue-cyan-magenta-purple side of -the spectrum." - :group 'modus-themes - :package-version '(modus-themes . "2.0.0") - :version "29.1" - :type 'boolean - :set #'modus-themes--set-option - :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Deuteranopia style")) + :link '(info-link "(modus-themes) Palette overrides")) -(defcustom modus-themes-mail-citations nil - "Control the color of citations/quotes in messages or emails. - -By default (a nil value) citations are styled with contrasting -hues to denote their depth. Colors are easy to tell apart -because they complement each other, but they otherwise are not -very prominent. + -Option `intense' is similar to the default in terms of using -contrasting and complementary hues, but applies more saturated -colors. +;;;; Presets of palette overrides + +(defvar modus-themes-preset-overrides-faint + '((bg-completion bg-inactive) + (bg-hover bg-cyan-subtle) + (bg-hover-secondary bg-magenta-subtle) + (bg-hl-line bg-dim) + (bg-paren-match bg-cyan-subtle) + (bg-region bg-active) + + (bg-mode-line-active bg-inactive) + (border-mode-line-active fg-dim) + (bg-mode-line-inactive bg-dim) + (border-mode-line-inactive bg-active) + + (bg-tab-bar bg-inactive) + (bg-tab-current bg-main) + (bg-tab-other bg-active) + + (fringe unspecified) + (builtin maroon) + (comment fg-dim) + (constant blue-faint) + (docstring fg-alt) + (docmarkup magenta-faint) + (fnname pink) + (keyword indigo) + (preprocessor rust) + (string slate) + (type cyan-faint) + (variable cyan-faint) + (rx-construct gold) + (rx-backslash olive) + + (underline-err red-faint) + (underline-warning yellow-faint) + (underline-note cyan-faint) + + (bg-button-active bg-main) + (fg-button-active fg-main) + (bg-button-inactive bg-inactive) + (fg-button-inactive "gray50") + + (date-common cyan-faint) + (date-deadline red-faint) + (date-event fg-alt) + (date-holiday magenta) + (date-now fg-main) + (date-scheduled yellow-faint) + (date-weekday fg-dim) + (date-weekend fg-dim) + + (name maroon) + (identifier fg-dim) + + (fg-line-number-active fg-main) + (fg-line-number-inactive "gray50") + (bg-line-number-active unspecified) + (bg-line-number-inactive unspecified) + + (fg-link blue-faint) + (bg-link unspecified) + (underline-link bg-active) + + (fg-link-symbolic cyan-faint) + (bg-link-symbolic unspecified) + (underline-link-symbolic bg-active) + + (fg-link-visited magenta-faint) + (bg-link-visited unspecified) + (underline-link-visited bg-active) + + (mail-cite-0 cyan-faint) + (mail-cite-1 yellow-faint) + (mail-cite-2 green-faint) + (mail-cite-3 red-faint) + (mail-part olive) + (mail-recipient indigo) + (mail-subject maroon) + (mail-other slate) + + (fg-prompt cyan-faint) + + (prose-code olive) + (prose-done green-faint) + (prose-macro indigo) + (prose-tag rust) + (prose-todo red-faint) + (prose-verbatim maroon) + + (rainbow-0 fg-main) + (rainbow-1 magenta) + (rainbow-2 cyan) + (rainbow-3 red-faint) + (rainbow-4 yellow-faint) + (rainbow-5 magenta-cooler) + (rainbow-6 green) + (rainbow-7 blue-warmer) + (rainbow-8 magenta-faint)) + "Preset for palette overrides with faint coloration. + +This changes many parts of the theme to make them look less +colorful/intense. Grays are toned down, gray backgrounds are +removed from some contexts, and almost all accent colors are +desaturated. + +To set a preset, assign its symbol without a quote as the value +of the `modus-themes-common-palette-overrides' or as the value of +theme-specific options such as `modus-operandi-palette-overrides'. + +Also see `modus-themes-preset-overrides-intense'. + +For overriding named colors and/or semantic color mappings read +Info node `(modus-themes) Option for palette overrides'.") + +(defvar modus-themes-preset-overrides-intense + '((bg-region bg-cyan-intense) + + (bg-completion bg-cyan-subtle) + (bg-hover bg-yellow-intense) + (bg-hover-secondary bg-magenta-intense) + (bg-hl-line bg-cyan-subtle) + + (bg-mode-line-active bg-blue-subtle) + (fg-mode-line-active fg-main) + (border-mode-line-active blue-intense) + + (fringe bg-inactive) + (comment red-faint) + + (date-common cyan) + (date-deadline red) + (date-event blue) + (date-holiday magenta-warmer) + (date-now blue-faint) + (date-scheduled yellow-warmer) + (date-weekday fg-main) + (date-weekend red-faint) + + (keybind blue-intense) + + (mail-cite-0 blue) + (mail-cite-1 yellow) + (mail-cite-2 green) + (mail-cite-3 magenta) + (mail-part magenta-cooler) + (mail-recipient cyan) + (mail-subject red-warmer) + (mail-other cyan-cooler) + + (fg-prompt blue-intense) + + (prose-block red-faint) + (prose-done green-intense) + (prose-metadata cyan-faint) + (prose-metadata-value blue-cooler) + (prose-table cyan) + (prose-todo red-intense) + + (fg-heading-0 blue-cooler) + (fg-heading-1 magenta-cooler) + (fg-heading-2 magenta-warmer) + (fg-heading-3 blue) + (fg-heading-4 cyan) + (fg-heading-5 green-warmer) + (fg-heading-6 yellow) + (fg-heading-7 red) + (fg-heading-8 magenta) + + (bg-heading-0 unspecified) + (bg-heading-1 bg-magenta-nuanced) + (bg-heading-2 bg-red-nuanced) + (bg-heading-3 bg-blue-nuanced) + (bg-heading-4 bg-cyan-nuanced) + (bg-heading-5 bg-green-nuanced) + (bg-heading-6 bg-yellow-nuanced) + (bg-heading-7 bg-red-nuanced) + (bg-heading-8 bg-magenta-nuanced) + + (overline-heading-0 unspecified) + (overline-heading-1 magenta-cooler) + (overline-heading-2 magenta-warmer) + (overline-heading-3 blue) + (overline-heading-4 cyan) + (overline-heading-5 green) + (overline-heading-6 yellow-cooler) + (overline-heading-7 red-cooler) + (overline-heading-8 magenta)) + "Preset for palette overrides with faint coloration. + +This changes many parts of the theme to make them look more +colorful/intense. Many background colors are accented and +coloration is increased to pop out more. + +To set a preset, assign its symbol without a quote as the value +of the `modus-themes-common-palette-overrides' or as the value of +theme-specific options such as `modus-operandi-palette-overrides'. + +Also see `modus-themes-preset-overrides-faint'. + +For overriding named colors and/or semantic color mappings read +Info node `(modus-themes) Option for palette overrides'.") -Option `faint' maintains the same color-based distinction between -citation levels though the colors it uses have subtle differences -between them. + -Option `monochrome' turns all quotes into a shade of gray. +;;;; Helper functions for theme setup -Whatever the value assigned to this variable, citations in emails -are controlled by typographic elements and/or indentation, which -the themes do not touch." - :group 'modus-themes - :package-version '(modus-themes . "2.1.0") - :version "29.1" - :type '(choice - (const :format "[%v] %t\n" :tag "Colorful email citations with contrasting hues (default)" nil) - (const :format "[%v] %t\n" :tag "Like the default, but with more saturated colors" intense) - (const :format "[%v] %t\n" :tag "Like the default, but with less saturated colors" faint) - (const :format "[%v] %t\n" :tag "Deprecated alias of `faint'" desaturated) - (const :format "[%v] %t\n" :tag "Uniformly gray mail citations" monochrome)) - :set #'modus-themes--set-option - :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Mail citations")) +;; This is the WCAG formula: https://www.w3.org/TR/WCAG20-TECHS/G18.html +(defun modus-themes-wcag-formula (hex) + "Get WCAG value of color value HEX. +The value is defined in hexadecimal RGB notation, such #123456." + (cl-loop for k in '(0.2126 0.7152 0.0722) + for x in (color-name-to-rgb hex) + sum (* k (if (<= x 0.03928) + (/ x 12.92) + (expt (/ (+ x 0.055) 1.055) 2.4))))) -(defcustom modus-themes-tabs-accented nil - "Toggle accented tab backgrounds, instead of the default gray. -This affects the built-in tab-bar mode and tab-line mode, as well -as the Centaur tabs package." - :group 'modus-themes - :package-version '(modus-themes . "1.6.0") - :version "28.1" - :type 'boolean - :set #'modus-themes--set-option - :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Tab style")) +;;;###autoload +(defun modus-themes-contrast (c1 c2) + "Measure WCAG contrast ratio between C1 and C2. +C1 and C2 are color values written in hexadecimal RGB." + (let ((ct (/ (+ (modus-themes-wcag-formula c1) 0.05) + (+ (modus-themes-wcag-formula c2) 0.05)))) + (max ct (/ ct)))) -(defcustom modus-themes-box-buttons nil - "Control the style of buttons in the Custom UI and related. +(make-obsolete 'modus-themes-color nil "4.0.0") +(make-obsolete 'modus-themes-color-alts nil "4.0.0") + +(declare-function cl-remove-if-not "cl-seq" (cl-pred cl-list &rest cl-keys)) + +(defun modus-themes--list-enabled-themes () + "Return list of `custom-enabled-themes' with modus- prefix." + (cl-remove-if-not + (lambda (theme) + (string-prefix-p "modus-" (symbol-name theme))) + custom-enabled-themes)) + +(defun modus-themes--enable-themes () + "Enable the Modus themes." + (mapc (lambda (theme) + (unless (memq theme custom-known-themes) + (load-theme theme :no-confirm :no-enable))) + modus-themes-items)) + +(defun modus-themes--list-known-themes () + "Return list of `custom-known-themes' with modus- prefix." + (modus-themes--enable-themes) + (cl-remove-if-not + (lambda (theme) + (string-prefix-p "modus-" (symbol-name theme))) + custom-known-themes)) -The value is a list of properties, each designated by a symbol. -The default (a nil value or an empty list) is a gray background -combined with a pseudo three-dimensional effect. +(defun modus-themes--current-theme () + "Return first enabled Modus theme." + (car (modus-themes--list-enabled-themes))) + +(defun modus-themes--palette-symbol (theme &optional overrides) + "Return THEME palette as a symbol. +With optional OVERRIDES, return THEME palette overrides as a +symbol." + (when-let ((suffix (cond + ((and theme overrides) + "palette-overrides") + (theme + "palette")))) + (intern (format "%s-%s" theme suffix)))) + +(defun modus-themes--palette-value (theme &optional overrides) + "Return palette value of THEME with optional OVERRIDES." + (let ((base-value (symbol-value (modus-themes--palette-symbol theme)))) + (if overrides + (append (symbol-value (modus-themes--palette-symbol theme :overrides)) + modus-themes-common-palette-overrides + base-value) + base-value))) + +(defun modus-themes--current-theme-palette (&optional overrides) + "Return palette value of active Modus theme, else produce `user-error'. +With optional OVERRIDES return palette value plus whatever +overrides." + (if-let ((theme (modus-themes--current-theme))) + (if overrides + (modus-themes--palette-value theme :overrides) + (modus-themes--palette-value theme)) + (user-error "No enabled Modus theme could be found"))) + +(defun modus-themes-load-theme (theme) + "Load THEME while disabling other Modus themes. +Run `modus-themes-after-load-theme-hook'." + (mapc #'disable-theme (modus-themes--list-known-themes)) + (load-theme theme :no-confirm) + (run-hooks 'modus-themes-after-load-theme-hook)) -The `flat' property makes the button two dimensional. +;;;; Commands -The `accented' property changes the background from gray to an -accent color. +(make-obsolete 'modus-themes-load-themes nil "4.0.0") +(make-obsolete 'modus-themes-load-operandi nil "4.0.0; Check `modus-themes-load-theme'") +(make-obsolete 'modus-themes-load-vivendi nil "4.0.0; Check `modus-themes-load-theme'") -The `faint' property reduces the overall coloration. +(defvar modus-themes--select-theme-history nil + "Minibuffer history of `modus-themes--select-prompt'.") -The `variable-pitch' property applies a proportionately spaced -typeface to the button's text. +(defun modus-themes--select-prompt () + "Minibuffer prompt to select a Modus theme." + (intern + (completing-read + "Select Modus theme: " + (modus-themes--list-known-themes) + nil t nil + 'modus-themes--select-theme-history))) -The `underline' property draws a line below the affected text and -removes whatever box effect. This is optimal when Emacs runs -inside a terminal emulator. If `flat' and `underline' are -defined together, the latter takes precedence. +;;;###autoload +(defun modus-themes-select (theme) + "Load a Modus THEME using minibuffer completion. +Run `modus-themes-after-load-theme-hook' after loading the theme." + (interactive (list (modus-themes--select-prompt))) + (modus-themes-load-theme theme)) + +(defun modus-themes--toggle-theme-p () + "Return non-nil if `modus-themes-to-toggle' are valid." + (mapc (lambda (theme) + (if (or (memq theme modus-themes-items) + (memq theme (modus-themes--list-known-themes))) + theme + (user-error "`%s' is not part of `modus-themes-items'" theme))) + modus-themes-to-toggle)) -The symbol of a weight attribute adjusts the font of the button -accordingly, such as `light', `semibold', etc. Valid symbols are -defined in the variable `modus-themes-weights'. +;;;###autoload +(defun modus-themes-toggle () + "Toggle between the two `modus-themes-to-toggle'. +If `modus-themes-to-toggle' does not specify two Modus themes, +prompt with completion for a theme among our collection (this is +practically the same as the `modus-themes-select' command). -A number, expressed as a floating point (e.g. 0.9), adjusts the -height of the button's text to that many times the base font -size. The default height is the same as 1.0, though it need not -be explicitly stated. Instead of a floating point, an acceptable -value can be in the form of a cons cell like (height . FLOAT) -or (height FLOAT), where FLOAT is the given number. +Run `modus-themes-after-load-theme-hook' after loading the theme." + (interactive) + (if-let* ((themes (modus-themes--toggle-theme-p)) + (one (car themes)) + (two (cadr themes))) + (if (eq (car custom-enabled-themes) one) + (modus-themes-load-theme two) + (modus-themes-load-theme one)) + (modus-themes-load-theme (modus-themes--select-prompt)))) + +(defun modus-themes--list-colors-render (buffer theme &optional mappings &rest _) + "Render colors in BUFFER from THEME for `modus-themes-list-colors'. +Optional MAPPINGS changes the output to only list the semantic +color mappings of the palette, instead of its named colors." + (let* ((current (modus-themes--palette-value theme :overrides)) + (palette (if mappings + (seq-remove (lambda (cell) + (or (stringp (cadr cell)) + (eq (cadr cell) 'unspecified))) + current) + (seq-remove (lambda (cell) + (symbolp (cadr cell))) + current))) + (current-buffer buffer) + (current-theme theme)) + (with-help-window buffer + (with-current-buffer standard-output + (erase-buffer) + (when (<= (display-color-cells) 256) + (insert (concat "Your display terminal may not render all color previews!\n" + "It seems to only support <= 256 colors.\n\n")) + (put-text-property (point-min) (point) 'face 'warning)) + ;; We need this to properly render the first line. + (insert " ") + (dolist (cell palette) + (let* ((name (car cell)) + (color (cadr cell)) + (mapping (if mappings + (cadr (seq-find (lambda (c) + (eq (car c) color)) + current)) + color)) + (fg (readable-foreground-color mapping)) + (pad (make-string 5 ?\s))) + (let ((old-point (point))) + (insert (format "%s %s" mapping pad)) + (put-text-property old-point (point) 'face `( :foreground ,mapping))) + (let ((old-point (point))) + (insert (format " %s %s %s\n" mapping pad name)) + (put-text-property old-point (point) + 'face `( :background ,mapping + :foreground ,fg + :extend t))) + ;; We need this to properly render the last line. + (insert " "))) + (setq-local revert-buffer-function + (lambda (_ignore-auto _noconfirm) + (modus-themes--list-colors-render current-buffer current-theme))))))) -The `all-buttons' property extends the box button effect (or the -aforementioned properties) to the faces of the generic widget -library. By default, those do not look like the buttons of the -Custom UI as they are ordinary text wrapped in square brackets. +(defvar modus-themes--list-colors-prompt-history '() + "Minibuffer history for `modus-themes--list-colors-prompt'.") -Combinations of any of those properties are expressed as a list, -like in these examples: +(defun modus-themes--list-colors-prompt () + "Prompt for Modus theme. +Helper function for `modus-themes-list-colors'." + (let ((def (format "%s" (modus-themes--current-theme)))) + (completing-read + (format "Use palette from theme [%s]: " def) + (modus-themes--list-known-themes) nil t nil + 'modus-themes--list-colors-prompt-history def))) - (flat) - (variable-pitch flat) - (variable-pitch flat semibold 0.9) - (variable-pitch flat semibold (height 0.9)) ; same as above - (variable-pitch flat semibold (height . 0.9)) ; same as above +(defun modus-themes-list-colors (theme &optional mappings) + "Preview named colors of the Modus THEME of choice. +With optional prefix argument for MAPPINGS preview the semantic +color mappings instead of the named colors." + (interactive (list (intern (modus-themes--list-colors-prompt)) current-prefix-arg)) + (modus-themes--list-colors-render + (format (if mappings "*%s-list-mappings*" "*%s-list-colors*") theme) + theme + mappings)) -The order in which the properties are set is not significant. +(defalias 'modus-themes-preview-colors 'modus-themes-list-colors + "Alias of `modus-themes-list-colors'.") -In user configuration files the form may look like this: +(defun modus-themes-list-colors-current (&optional mappings) + "Call `modus-themes-list-colors' for the current Modus theme. +Optional prefix argument MAPPINGS has the same meaning as for +`modus-themes-list-colors'." + (interactive "P") + (modus-themes-list-colors (modus-themes--current-theme) mappings)) - (setq modus-themes-box-buttons (quote (variable-pitch flat 0.9)))" - :group 'modus-themes - :package-version '(modus-themes . "2.3.0") - :version "29.1" - :type '(set :tag "Properties" :greedy t - (const :tag "Two-dimensional button" flat) - (const :tag "Accented background instead of gray" accented) - (const :tag "Reduce overall coloration" faint) - (const :tag "Proportionately spaced font (variable-pitch)" variable-pitch) - (const :tag "Underline instead of a box effect" underline) - (const :tag "Apply box button style to generic widget faces" all-buttons) - (choice :tag "Font weight (must be supported by the typeface)" - (const :tag "Thin" thin) - (const :tag "Ultra-light" ultralight) - (const :tag "Extra-light" extralight) - (const :tag "Light" light) - (const :tag "Semi-light" semilight) - (const :tag "Regular (default)" nil) - (const :tag "Medium" medium) - (const :tag "Bold" bold) - (const :tag "Semi-bold" semibold) - (const :tag "Extra-bold" extrabold) - (const :tag "Ultra-bold" ultrabold)) - (radio :tag "Height" - (float :tag "Floating point to adjust height by") - (cons :tag "Cons cell of `(height . FLOAT)'" - (const :tag "The `height' key (constant)" height) - (float :tag "Floating point")))) - :set #'modus-themes--set-option - :initialize #'custom-initialize-default - :link '(info-link "(modus-themes) Box buttons")) +(defalias 'modus-themes-preview-colors-current 'modus-themes-list-colors-current + "Alias of `modus-themes-list-colors-current'.") -;;; Internal functions +;;;; Internal functions (defun modus-themes--warn (option) "Warn that OPTION has changed." @@ -2890,51 +1226,6 @@ list given LIST-PRED, using DEFAULT as a fallback." (car val) val)) -(defun modus-themes--palette (theme) - "Return color palette for Modus theme THEME. -THEME is a symbol, either `modus-operandi' or `modus-vivendi'." - (pcase theme - ('modus-operandi - (append modus-themes-operandi-color-overrides - modus-themes-operandi-colors)) - ('modus-vivendi - (append modus-themes-vivendi-color-overrides - modus-themes-vivendi-colors)) - (_theme - (error "'%s' is not a Modus theme" theme)))) - -(defvar modus-themes-faces) -(defvar modus-themes-custom-variables) - -(defmacro modus-themes-theme (name) - "Bind NAME's color palette around face specs and variables. - -NAME should be the proper name of a Modus theme, either -`modus-operandi' or `modus-vivendi'. - -Face specifications are passed to `custom-theme-set-faces'. -While variables are handled by `custom-theme-set-variables'. -Those are stored in `modus-themes-faces' and -`modus-themes-custom-variables' respectively." - (declare (indent 0)) - (let ((palette-sym (gensym)) - (colors (mapcar #'car modus-themes-operandi-colors))) - `(let* ((class '((class color) (min-colors 89))) - (,palette-sym (modus-themes--palette ',name)) - ,@(mapcar (lambda (color) - (list color `(alist-get ',color ,palette-sym))) - colors)) - (custom-theme-set-faces ',name ,@modus-themes-faces) - (custom-theme-set-variables ',name ,@modus-themes-custom-variables)))) - -(defun modus-themes--current-theme () - "Return current modus theme." - (car - (seq-filter - (lambda (theme) - (string-match-p "^modus" (symbol-name theme))) - custom-enabled-themes))) - ;; Helper functions that are meant to ease the implementation of the ;; above customization variables. (defun modus-themes--bold-weight () @@ -2957,145 +1248,13 @@ Those are stored in `modus-themes-faces' and (when modus-themes-variable-pitch-ui (list :inherit 'variable-pitch))) -(defun modus-themes--fringe (mainbg subtlebg intensebg) - "Conditional use of background colors for fringes. -MAINBG is the default. SUBTLEBG should be a subtle grayscale -value. INTENSEBG must be a more pronounced grayscale color." - (pcase modus-themes-fringes - ('intense (list :background intensebg)) - ('subtle (list :background subtlebg)) - (_ (list :background mainbg)))) - -(defun modus-themes--line-numbers (mainfg mainbg altfg &optional altbg) - "Conditional use of colors for line numbers. -MAINBG and MAINFG are the default colors. ALTFG is a color that -combines with the theme's primary background (white/black)." - (if modus-themes-subtle-line-numbers - (list :background (or altbg 'unspecified) :foreground altfg) - (list :background mainbg :foreground mainfg))) - -(defun modus-themes--markup (mainfg intensefg subtlebg intensebg) - "Conditional use of colors for markup in Org and others. -MAINFG is the default foreground. SUBTLEBG is a gray background. -INTENSEBG is a colorful background for use with the main -foreground. INTENSEFG is an alternative to the default." - (let ((properties modus-themes-markup)) - (list - :inherit - (cond - ((and (memq 'bold properties) - (memq 'italic properties)) - (list 'bold-italic 'modus-themes-fixed-pitch)) - ((memq 'italic properties) - (list 'italic 'modus-themes-fixed-pitch)) - ((memq 'bold properties) - (list 'bold 'modus-themes-fixed-pitch)) - (t 'modus-themes-fixed-pitch)) - :background - (cond - ((and (memq 'background properties) - (memq 'intense properties)) - intensebg) - ((memq 'background properties) - subtlebg) - (t - 'unspecified)) - :foreground - (cond - ((and (memq 'background properties) - (memq 'intense properties)) - mainfg) - ((memq 'intense properties) - intensefg) - (t - mainfg))))) - -(defun modus-themes--lang-check (underline subtlefg intensefg intensefg-alt subtlebg intensebg faintfg) - "Conditional use of foreground colors for language checkers. -UNDERLINE is a color-code value for the affected text's underline -property. SUBTLEFG and INTENSEFG follow the same color-coding -pattern and represent a value that is faint or vibrant -respectively. INTENSEFG-ALT is used when the intensity is high. -SUBTLEBG and INTENSEBG are color-coded background colors that -differ in overall intensity. FAINTFG is a nuanced color." - (let ((properties (modus-themes--list-or-warn 'modus-themes-lang-checkers))) - (list :underline - (list :color - (if (memq 'faint properties) - faintfg underline) - :style - (if (memq 'straight-underline properties) - 'line 'wave)) - :background - (cond - ((and (memq 'background properties) - (memq 'faint properties)) - subtlebg) - ((and (memq 'background properties) - (memq 'intense properties)) - intensebg) - ((memq 'background properties) - subtlebg) - ('unspecified)) - :foreground - (cond - ((and (memq 'faint properties) - (memq 'text-also properties)) - faintfg) - ((and (memq 'background properties) - (memq 'intense properties)) - intensefg-alt) - ((memq 'intense properties) - intensefg) - ((memq 'text-also properties) - subtlefg) - ('unspecified))))) - -(defun modus-themes--prompt (mainfg intensefg grayfg subtlebg intensebg intensebg-fg subtlebggray intensebggray) +(defun modus-themes--prompt (fg bg) "Conditional use of colors for text prompt faces. -MAINFG is the prompt's standard foreground. INTENSEFG is a more -prominent alternative to the main foreground, while GRAYFG is a -less luminant shade of gray. - -SUBTLEBG is a subtle accented background that works with either -MAINFG or INTENSEFG. - -INTENSEBG is a more pronounced accented background color that -should be combinable with INTENSEBG-FG. - -SUBTLEBGGRAY and INTENSEBGGRAY are background values. The former -can be combined with GRAYFG, while the latter only works with the -theme's fallback text color." - (let ((properties (modus-themes--list-or-warn 'modus-themes-prompts))) - (list :foreground - (cond - ((and (memq 'gray properties) - (memq 'intense properties)) - 'unspecified) - ((memq 'gray properties) - grayfg) - ((and (memq 'background properties) - (memq 'intense properties)) - intensebg-fg) - ((memq 'intense properties) - intensefg) - (mainfg)) - :background - (cond - ((and (memq 'gray properties) - (memq 'background properties) - (memq 'intense properties)) - intensebggray) - ((and (memq 'gray properties) - (memq 'background properties)) - subtlebggray) - ((and (memq 'background properties) - (memq 'intense properties)) - intensebg) - ((memq 'background properties) - subtlebg) - ('unspecified)) - :inherit +FG is the prompt's standard foreground. BG is a background +color that is combined with FG-FOR-BG." + (let* ((properties (modus-themes--list-or-warn 'modus-themes-prompts)) + (weight (modus-themes--weight properties))) + (list :inherit (cond ((and (memq 'bold properties) (memq 'italic properties)) @@ -3104,104 +1263,16 @@ theme's fallback text color." 'italic) ((memq 'bold properties) 'bold) - ('unspecified))))) - -(defun modus-themes--paren (normalbg intensebg) - "Conditional use of intense colors for matching parentheses. -NORMALBG should be the special palette color bg-paren-match or -something similar. INTENSEBG must be easier to discern next to -other backgrounds, such as the special palette color -bg-paren-match-intense." - (let ((properties (modus-themes--list-or-warn 'modus-themes-paren-match))) - (list :inherit - (if (memq 'bold properties) - 'bold - 'unspecified) - :background - (if (memq 'intense properties) - intensebg - normalbg) - :underline - (if (memq 'underline properties) - t - nil)))) - -(defun modus-themes--syntax-foreground (fg faint) - "Apply foreground value to code syntax. -FG is the default. FAINT is typically the same color in its -desaturated version." - (let ((properties (modus-themes--list-or-warn 'modus-themes-syntax))) - (list :foreground - (cond - ((memq 'faint properties) - faint) - (fg))))) - -(defun modus-themes--syntax-extra (fg faint alt &optional faint-alt) - "Apply foreground value to code syntax. -FG is the default. FAINT is typically the same color in its -desaturated version. ALT is another hue while optional FAINT-ALT -is its subtle alternative." - (let ((properties (modus-themes--list-or-warn 'modus-themes-syntax))) - (list :foreground - (cond - ((and (memq 'alt-syntax properties) - (memq 'faint properties)) - (or faint-alt alt)) - ((memq 'faint properties) - faint) - ((memq 'alt-syntax properties) - alt) - (fg))))) - -(defun modus-themes--syntax-string (fg faint green alt &optional faint-green faint-alt) - "Apply foreground value to strings in code syntax. -FG is the default. FAINT is typically the same color in its -desaturated version. GREEN is a color variant in that side of -the spectrum. ALT is another hue. Optional FAINT-GREEN is a -subtle alternative to GREEN. Optional FAINT-ALT is a subtle -alternative to ALT." - (let ((properties (modus-themes--list-or-warn 'modus-themes-syntax))) - (list :foreground - (cond - ((and (memq 'faint properties) - (memq 'green-strings properties)) - (or faint-green green)) - ((and (memq 'alt-syntax properties) - (memq 'faint properties)) - (or faint-alt faint)) - ((memq 'faint properties) - faint) - ((memq 'green-strings properties) - green) - ((memq 'alt-syntax properties) - alt) - (fg))))) - -(defun modus-themes--syntax-comment (fg yellow &optional faint-yellow faint) - "Apply foreground value to strings in code syntax. -FG is the default. YELLOW is a color variant of that name while -optional FAINT-YELLOW is its subtle variant. Optional FAINT is -an alternative to the default value." - (let ((properties (modus-themes--list-or-warn 'modus-themes-syntax))) - (list :foreground - (cond - ((and (memq 'faint properties) - (memq 'yellow-comments properties)) - (or faint-yellow yellow)) - ((and (memq 'alt-syntax properties) - (memq 'yellow-comments properties) - (not (memq 'green-strings properties))) - yellow) - ((memq 'yellow-comments properties) - yellow) - ((memq 'faint properties) - (or faint fg)) - (fg))))) - -(defun modus-themes--key-cdr (key alist) - "Get cdr of KEY in ALIST." - (cdr (assoc key alist))) + ('unspecified)) + :background bg + :foreground fg + :weight + ;; If we have `bold' specifically, we inherit the face of + ;; the same name. This allows the user to customise that + ;; face, such as to change its font family. + (if (and weight (not (eq weight 'bold))) + weight + 'unspecified)))) (defconst modus-themes-weights '( thin ultralight extralight light semilight regular medium @@ -3209,29 +1280,23 @@ an alternative to the default value." "List of font weights.") (defun modus-themes--weight (list) - "Search for `modus-themes--heading' weight in LIST." + "Search for `modus-themes-weights' weight in LIST." (catch 'found (dolist (elt list) (when (memq elt modus-themes-weights) (throw 'found elt))))) -(defun modus-themes--heading (level fg fg-alt bg bg-gray border) +(defun modus-themes--heading (level fg &optional bg ol) "Conditional styles for `modus-themes-headings'. LEVEL is the heading's position in their order. FG is the -default text color. FG-ALT is an accented, more saturated value -than the default. BG is a nuanced, typically accented, -background that can work well with either of the foreground -values. BG-GRAY is a gray background. BORDER is a color value -that combines well with the background and foreground." - (let* ((key (modus-themes--key-cdr level modus-themes-headings)) - (style (or key (modus-themes--key-cdr t modus-themes-headings))) +default text color. Optional BG is an appropriate background. +Optional OL is the color of an overline." + (let* ((key (alist-get level modus-themes-headings)) + (style (or key (alist-get t modus-themes-headings))) (style-listp (listp style)) (properties style) (var (when (memq 'variable-pitch properties) 'variable-pitch)) - (varbold (if var - (append (list 'bold) (list var)) - 'bold)) (weight (when style-listp (modus-themes--weight style)))) (list :inherit (cond @@ -3239,336 +1304,28 @@ that combines well with the background and foreground." ;; deprecate a variable's value. ((or weight (memq 'no-bold properties)) var) - (varbold)) - :background - (cond - ((and (memq 'monochrome properties) - (memq 'background properties)) - bg-gray) - ((memq 'background properties) - bg) - ('unspecified)) - :foreground - (cond - ((memq 'monochrome properties) - 'unspecified) - ((memq 'rainbow properties) - fg-alt) - (fg)) - :height - (modus-themes--property-lookup properties 'height #'floatp 'unspecified) - :weight - (or weight 'unspecified) - :overline - (if (memq 'overline properties) - border - 'unspecified)))) - -(defun modus-themes--agenda-structure (fg) - "Control the style of the Org agenda structure. -FG is the foreground color to use." - (let* ((properties (modus-themes--key-cdr 'header-block modus-themes-org-agenda)) - (weight (modus-themes--weight properties))) - (list :inherit - (cond - ((and weight (memq 'variable-pitch properties)) - 'variable-pitch) - (weight 'unspecified) - ((memq 'variable-pitch properties) - (list 'bold 'variable-pitch)) + (var (append (list 'bold) (list var))) ('bold)) - :weight - (or weight 'unspecified) - :height - (cond ((memq 'no-scale properties) 'unspecified) - ((modus-themes--property-lookup properties 'height #'floatp 1.15))) - :foreground fg))) - -(defun modus-themes--agenda-date (defaultfg grayscalefg &optional workaholicfg grayscaleworkaholicfg bg bold ul) - "Control the style of date headings in Org agenda buffers. -DEFAULTFG is the original accent color for the foreground. -GRAYSCALEFG is a neutral color. Optional WORKAHOLICFG and -GRAYSCALEWORKAHOLICFG are alternative foreground colors. -Optional BG is a background color. Optional BOLD applies a bold -weight. Optional UL applies an underline." - (let ((properties (modus-themes--key-cdr 'header-date modus-themes-org-agenda))) - (list :inherit - (cond - ((or (memq 'bold-all properties) - (and bold (memq 'bold-today properties))) - 'bold) - (t - 'unspecified)) - :background - (cond - ((memq 'underline-today properties) - 'unspecified) - ((or bg 'unspecified))) - :foreground - (cond - ((and (memq 'grayscale properties) - (memq 'workaholic properties)) - (or grayscaleworkaholicfg grayscalefg)) - ((memq 'grayscale properties) - grayscalefg) - ((memq 'workaholic properties) - (or workaholicfg defaultfg)) - (t - defaultfg)) - :height - (modus-themes--property-lookup properties 'height #'floatp 'unspecified) - :underline - (if (and ul (memq 'underline-today properties)) - t - 'unspecified)))) - -(defun modus-themes--agenda-event (fg-accent &optional varied) - "Control the style of the Org agenda events. -FG-ACCENT is the accent color to use. Optional VARIED is a -toggle to behave in accordance with the semantics of the `varied' -property that the `event' key accepts in -`modus-themes-org-agenda'." - (let ((properties (modus-themes--key-cdr 'event modus-themes-org-agenda))) - (list :foreground - (cond - ((or (and (memq 'varied properties) varied) - (and (memq 'accented properties) - (memq 'varied properties) - varied)) - 'unspecified) - ((memq 'accented properties) - fg-accent) - ('unspecified)) - :inherit - (cond - ((and (memq 'italic properties) - (memq 'varied properties) - varied) - '(shadow italic)) - ((and (memq 'accented properties) - (memq 'varied properties) - varied) - 'shadow) - ((or (and (memq 'varied properties) varied) - (and (memq 'italic properties) varied)) - '(shadow italic)) - ((and (memq 'italic properties) - (not (memq 'varied properties))) - '(shadow italic)) - ('shadow))))) - -(defun modus-themes--agenda-scheduled (defaultfg uniformfg rainbowfg) - "Control the style of the Org agenda scheduled tasks. -DEFAULTFG is an accented foreground color that is meant to -differentiate between past or present and future tasks. -UNIFORMFG is a more subtle color that eliminates the color coding -for scheduled tasks. RAINBOWFG is a prominent accent value that -clearly distinguishes past, present, future tasks." - (pcase (modus-themes--key-cdr 'scheduled modus-themes-org-agenda) - ('uniform (list :foreground uniformfg)) - ('rainbow (list :foreground rainbowfg)) - (_ (list :foreground defaultfg)))) - -(defun modus-themes--agenda-habit (default traffic simple &optional default-d traffic-d simple-d) - "Specify background values for `modus-themes-org-agenda' habits. -DEFAULT is the original foregrounc color. TRAFFIC is to be used -when the traffic-light style is applied, while SIMPLE corresponds -to the simplified style. - -Optional DEFAULT-D, TRAFFIC-D, SIMPLE-D are alternatives to the -main colors, meant for dopia when `modus-themes-deuteranopia' is -non-nil." - (let ((habit (modus-themes--key-cdr 'habit modus-themes-org-agenda))) - (cond - ((and modus-themes-deuteranopia (null habit)) - (list :background (or default-d default))) - ((and modus-themes-deuteranopia (eq habit 'traffic-light)) - (list :background (or traffic-d traffic))) - ((and modus-themes-deuteranopia (eq habit 'simplified)) - (list :background (or simple-d simple))) - (t - (pcase habit - ('traffic-light (list :background traffic)) - ('simplified (list :background simple)) - (_ (list :background default))))))) - -(defun modus-themes--org-block (bgblk fgdefault &optional fgblk) - "Conditionally set the background of Org blocks. -BGBLK applies to a distinct neutral background. Else blocks have -no background of their own (the default), so they look the same -as the rest of the buffer. FGDEFAULT is used when no distinct -background is present. While optional FGBLK specifies a -foreground value that can be combined with BGBLK. - -`modus-themes-org-blocks' also accepts `tinted-background' (alias -`rainbow') as a value which applies to `org-src-block-faces' (see -the theme's source code)." - (if (or (eq modus-themes-org-blocks 'gray-background) - (eq modus-themes-org-blocks 'grayscale) - (eq modus-themes-org-blocks 'greyscale)) - (list :background bgblk :foreground (or fgblk fgdefault) :extend t) - (list :background 'unspecified :foreground fgdefault))) - -(defun modus-themes--org-block-delim (bgaccent fgaccent bg fg) - "Conditionally set the styles of Org block delimiters. -BG, FG, BGACCENT, FGACCENT apply a background and foreground -color respectively. - -The former pair is a grayscale combination that should be more -distinct than the background of the block. It is applied to the -default styles or when `modus-themes-org-blocks' is set -to `grayscale' (or `greyscale'). - -The latter pair should be more subtle than the background of the -block, as it is used when `modus-themes-org-blocks' is -set to `rainbow'." - (pcase modus-themes-org-blocks - ('gray-background (list :background bg :foreground fg :extend t)) - ('grayscale (list :background bg :foreground fg :extend t)) - ('greyscale (list :background bg :foreground fg :extend t)) - ('tinted-background (list :background bgaccent :foreground fgaccent :extend nil)) - ('rainbow (list :background bgaccent :foreground fgaccent :extend nil)) - (_ (list :foreground fg :extend nil)))) - -(defun modus-themes--mode-line-attrs - (fg bg fg-alt bg-alt fg-accent bg-accent border border-3d &optional alt-style fg-distant) - "Color combinations for `modus-themes-mode-line'. - -FG and BG are the default colors. FG-ALT and BG-ALT are meant to -accommodate the options for a 3D mode line or a `moody' compliant -one. FG-ACCENT and BG-ACCENT are used for all variants. BORDER -applies to all permutations of the mode line, except the -three-dimensional effect, where BORDER-3D is used instead. - -Optional ALT-STYLE applies an appropriate style to the mode -line's box property. - -Optional FG-DISTANT should be close to the main background -values. It is intended to be used as a distant-foreground -property." - (let* ((properties (modus-themes--list-or-warn 'modus-themes-mode-line)) - (padding (modus-themes--property-lookup properties 'padding #'natnump 1)) - (height (modus-themes--property-lookup properties 'height #'floatp 'unspecified)) - (padded (> padding 1)) - (base (cond ((memq 'accented properties) - (cons fg-accent bg-accent)) - ((and (or (memq 'moody properties) - (memq '3d properties)) - (not (memq 'borderless properties))) - (cons fg-alt bg-alt)) - ((cons fg bg)))) - (line (cond ((not (or (memq 'moody properties) padded)) - 'unspecified) - ((and (not (memq 'moody properties)) - padded - (memq 'borderless properties)) - 'unspecified) - ((and (memq 'borderless properties) - (memq 'accented properties)) - bg-accent) - ((memq 'borderless properties) - bg) - (border)))) - (list :foreground (car base) - :background (cdr base) - :height height - :box - (cond ((memq 'moody properties) - 'unspecified) - ((and (memq '3d properties) padded) - (list :line-width padding - :color - (cond ((and (memq 'accented properties) - (memq 'borderless properties)) - bg-accent) - ((or (memq 'accented properties) - (memq 'borderless properties)) - bg) - (bg-alt)) - :style (when alt-style 'released-button))) - ((and (memq 'accented properties) padded) - (list :line-width padding :color bg-accent)) - ((memq '3d properties) - (list :line-width padding - :color - (cond ((and (memq 'accented properties) - (memq 'borderless properties)) - bg-accent) - ((memq 'borderless properties) bg) - (border-3d)) - :style (when alt-style 'released-button))) - ((and (memq 'accented properties) - (memq 'borderless properties)) - (list :line-width padding :color bg-accent)) - ((or (memq 'borderless properties) padded) - (list :line-width padding :color bg)) - (border)) - :overline line - :underline line - :distant-foreground - (if (memq 'moody properties) - fg-distant - 'unspecified)))) - -;; Basically this is just for the keycast key indicator. -(defun modus-themes--mode-line-padded-box (color) - "Set padding of mode line box attribute with given COLOR." - (list :box (list :color color - :line-width - (or (cl-loop - for x in modus-themes-mode-line - if (natnump x) return x) - 1)))) - -(defun modus-themes--diff (mainbg mainfg altbg altfg &optional deubg deufg deualtbg deualtfg bg-only-fg) - "Color combinations for `modus-themes-diffs'. - -MAINBG must be one of the dedicated backgrounds for diffs while -MAINFG must be the same for the foreground. - -ALTBG needs to be a slightly accented background that is meant to -be combined with ALTFG. Both must be less intense than MAINBG -and MAINFG respectively. - -DEUBG and DEUFG must be combinations of colors that account for -red-green color defficiency (deuteranopia). They are the -equivalent of MAINBG and MAINFG. - -DEUALTBG and DEUALTFG are the equivalent of ALTBG and ALTFG for -deuteranopia. - -Optional non-nil BG-ONLY-FG applies ALTFG else leaves the -foreground unspecified." - (if modus-themes-deuteranopia - (pcase modus-themes-diffs - ('desaturated (list :background (or deualtbg altbg) :foreground (or deualtfg altfg))) - ('bg-only (list :background (or deualtbg altbg) :foreground (if bg-only-fg (or deualtfg altfg) 'unspecified))) - (_ (list :background (or deubg mainbg) :foreground (or deufg mainfg)))) - (pcase modus-themes-diffs - ('desaturated (list :background altbg :foreground altfg)) - ('bg-only (list :background altbg :foreground (if bg-only-fg altfg 'unspecified))) - (_ (list :background mainbg :foreground mainfg))))) - -(defun modus-themes--deuteran (deuteran main) - "Determine whether to color-code success as DEUTERAN or MAIN." - (if modus-themes-deuteranopia - (list deuteran) - (list main))) - -(defun modus-themes--completion-line (key bg fg bgintense fgintense &optional bgaccent bgaccentintense) - "Styles for `modus-themes-completions'. -KEY is the key of a cons cell. BG and FG are the main colors. -BGINTENSE works with the main foreground. FGINTENSE works on its -own. BGACCENT and BGACCENTINTENSE are colorful variants of the -other backgrounds." + :background (or bg 'unspecified) + :foreground fg + :overline (or ol 'unspecified) + :height (modus-themes--property-lookup properties 'height #'floatp 'unspecified) + :weight (or weight 'unspecified)))) + +(defun modus-themes--org-block (fg bg) + "Conditionally set the FG and BG of Org blocks." + (let ((gray (or (eq modus-themes-org-blocks 'gray-background) + (eq modus-themes-org-blocks 'grayscale) ; for backward compatibility + (eq modus-themes-org-blocks 'greyscale)))) + (list :inherit 'modus-themes-fixed-pitch + :background (if gray bg 'unspecified) + :foreground fg + :extend (if gray t 'unspecified)))) + +(defun modus-themes--completion-line (bg) + "Styles for `modus-themes-completions' with BG as the background." (let* ((var (modus-themes--list-or-warn 'modus-themes-completions)) - (properties (or (alist-get key var) (alist-get t var))) - (popup (eq key 'popup)) - (selection (eq key 'selection)) - (line (or popup selection)) - (text (memq 'text-also properties)) - (accented (memq 'accented properties)) - (intense (memq 'intense properties)) + (properties (or (alist-get 'selection var) (alist-get t var))) (italic (memq 'italic properties)) (weight (modus-themes--weight properties)) (bold (when (and weight (eq weight 'bold)) 'bold))) @@ -3581,35 +1338,18 @@ other backgrounds." 'unspecified) (italic 'bold-italic) ('bold)) - :background - (cond - ((and accented intense line) - bgaccentintense) - ((and accented line) - bgaccent) - (intense bgintense) - (bg)) - :foreground - (cond - ((and line text intense) - fgintense) - ((and line text) - fg) - ('unspecified)) + :background bg + :foreground 'unspecified :underline (if (memq 'underline properties) t 'unspecified) :weight (if (and weight (null bold)) weight 'unspecified)))) -(defun modus-themes--completion-match (key bg fg bgintense fgintense) +(defun modus-themes--completion-match (fg bg) "Styles for `modus-themes-completions'. -KEY is the key of a cons cell. BG and FG are the main colors. -BGINTENSE works with the main foreground. FGINTENSE works on its -own." +FG and BG are the main colors." (let* ((var (modus-themes--list-or-warn 'modus-themes-completions)) - (properties (or (alist-get key var) (alist-get t var))) - (background (memq 'background properties)) - (intense (memq 'intense properties)) + (properties (or (alist-get 'matches var) (alist-get t var))) (italic (memq 'italic properties)) (weight (modus-themes--weight properties)) (bold (when (and weight (eq weight 'bold)) 'bold))) @@ -3622,443 +1362,13 @@ own." 'unspecified) (italic 'bold-italic) ('bold)) - :background - (cond - ((and background intense) - bgintense) - (background bg) - ('unspecified)) - :foreground - (cond - ((and background intense) - 'unspecified) - (background fg) - (intense fgintense) - (fg)) + :background bg + :foreground fg :underline (if (memq 'underline properties) t 'unspecified) :weight (if (and weight (null bold)) weight 'unspecified)))) -(defun modus-themes--link (fg fgfaint underline bg bgneutral) - "Conditional application of link styles. -FG is the link's default color for its text and underline -property. FGFAINT is a desaturated color for the text and -underline. UNDERLINE is a gray color only for the undeline. BG -is a background color and BGNEUTRAL is its fallback value." - (let ((properties (modus-themes--list-or-warn 'modus-themes-links))) - (list :inherit - (cond - ((and (memq 'bold properties) - (memq 'italic properties)) - 'bold-italic) - ((memq 'italic properties) - 'italic) - ((memq 'bold properties) - 'bold) - ('unspecified)) - :background - (cond - ((and (memq 'no-color properties) - (memq 'no-underline properties)) - bgneutral) - ((memq 'background properties) - bg) - ('unspecified)) - :foreground - (cond - ((memq 'no-color properties) - 'unspecified) - ((memq 'faint properties) - fgfaint) - (fg)) - :underline - (cond - ((memq 'no-underline properties) - 'unspecified) - ((memq 'neutral-underline properties) - underline) - (t))))) - -(defun modus-themes--link-color (fg fgfaint &optional neutralfg) - "Extend `modus-themes--link'. -FG is the main accented foreground. FGFAINT is also accented, -yet desaturated. Optional NEUTRALFG is a gray value." - (let ((properties (modus-themes--list-or-warn 'modus-themes-links))) - (list :foreground - (cond - ((memq 'no-color properties) - (or neutralfg 'unspecified)) - ((memq 'faint properties) - fgfaint) - (fg)) - :underline - (cond - ((memq 'no-underline properties) - 'unspecified) - ((memq 'neutral-underline properties) - (or neutralfg 'unspecified)) - (t))))) - -(defun modus-themes--region (bg fg bgsubtle bgaccent bgaccentsubtle) - "Apply `modus-themes-region' styles. - -BG and FG are the main values that are used by default. BGSUBTLE -is a subtle background value that can be combined with all colors -used to fontify text and code syntax. BGACCENT is a colored -background that combines well with FG. BGACCENTSUBTLE can be -combined with all colors used to fontify text." - (let ((properties (modus-themes--list-or-warn 'modus-themes-region))) - (list :background - (cond - ((and (memq 'accented properties) - (memq 'bg-only properties)) - bgaccentsubtle) - ((memq 'accented properties) - bgaccent) - ((memq 'bg-only properties) - bgsubtle) - (bg)) - :foreground - (cond - ((and (memq 'accented properties) - (memq 'bg-only properties)) - 'unspecified) - ((memq 'bg-only properties) - 'unspecified) - (fg)) - :extend - (cond - ((memq 'no-extend properties) - nil) - (t))))) - -(defun modus-themes--hl-line - (bgdefault bgintense bgaccent bgaccentsubtle lineneutral lineaccent lineneutralintense lineaccentintense) - "Apply `modus-themes-hl-line' styles. - -BGDEFAULT is a subtle neutral background. BGINTENSE is like the -default, but more prominent. BGACCENT is a prominent accented -background, while BGACCENTSUBTLE is more subtle. LINENEUTRAL and -LINEACCENT are color values that can remain distinct against the -buffer's possible backgrounds: the former is neutral, the latter -is accented. LINENEUTRALINTENSE and LINEACCENTINTENSE are their -more prominent alternatives." - (let ((properties (modus-themes--list-or-warn 'modus-themes-hl-line))) - (list :background - (cond - ((and (memq 'intense properties) - (memq 'accented properties)) - bgaccent) - ((memq 'accented properties) - bgaccentsubtle) - ((memq 'intense properties) - bgintense) - (bgdefault)) - :underline - (cond - ((and (memq 'intense properties) - (memq 'accented properties) - (memq 'underline properties)) - lineaccentintense) - ((and (memq 'accented properties) - (memq 'underline properties)) - lineaccent) - ((and (memq 'intense properties) - (memq 'underline properties)) - lineneutralintense) - ((or (memq 'no-background properties) - (memq 'underline properties)) - lineneutral) - ('unspecified))))) - -(defun modus-themes--mail-cite (mainfg intensefg subtlefg) - "Combinations for `modus-themes-mail-citations'. - -MAINFG is an accented foreground value. SUBTLEFG is its -desaturated counterpart. INTENSEFG is a more saturated variant." - (pcase modus-themes-mail-citations - ('monochrome (list :inherit 'shadow)) - ('intense (list :foreground intensefg)) - ('faint (list :foreground subtlefg)) - ('desaturated (list :foreground subtlefg)) - (_ (list :foreground mainfg)))) - -(defun modus-themes--tab (bg &optional bgaccent fg fgaccent box-p bold-p var-p) - "Helper function for tabs. -BG is the default background, while BGACCENT is its more colorful -alternative. Optional FG is a foreground color that combines -with BG. Same principle FGACCENT. - -BOX-P and BOLD-P determine the use of a box property and the -application of a bold weight, respectively. VAR-P controls the -application of a variable-pitch font." - (let ((background (if modus-themes-tabs-accented (or bgaccent bg) bg)) - (foreground (if modus-themes-tabs-accented (or fgaccent fg) fg))) - (list - :inherit (cond - ((and bold-p var-p) - (if modus-themes-variable-pitch-ui - '(variable-pitch bold) - '(bold))) - (bold-p 'bold) - (var-p (when modus-themes-variable-pitch-ui 'variable-pitch)) - ('unspecified)) - :background background - :foreground (or foreground 'unspecified) - :box (if box-p (list :line-width 2 :color background) 'unspecified)))) - -(defun modus-themes--button (bg bgfaint bgaccent bgaccentfaint border &optional pressed-button-p) - "Apply `modus-themes-box-buttons' styles. - -BG is the main background. BGFAINT is its subtle alternative. -BGACCENT is its accented variant and BGACCENTFAINT is the same -but less intense. BORDER is the color around the box. - -When optional PRESSED-BUTTON-P is non-nil, the box uses the -pressed button style, else the released button." - (let* ((properties modus-themes-box-buttons) - (weight (modus-themes--weight properties))) - (list :inherit - (cond - ((and (memq 'variable-pitch properties) - (eq weight 'bold)) - (list 'bold 'variable-pitch)) - ((memq 'variable-pitch properties) - 'variable-pitch) - ((eq weight 'bold) - 'bold) - ('unspecified)) - :background - (cond - ((and (memq 'accented properties) - (memq 'faint properties) - bgaccentfaint)) - ((memq 'faint properties) - bgfaint) - ((memq 'accented properties) - bgaccent) - (bg)) - :box - (cond - ((memq 'underline properties) - 'unspecified) - ((memq 'flat properties) - (list :line-width -1 :color border)) - ((list :line-width -1 - :style (if pressed-button-p - 'pressed-button - 'released-button) - :color border))) - :weight - (cond - ((eq weight 'bold) - 'unspecified) ; we :inherit the `bold' face above - (weight weight) - ('unspecified)) - :height - (modus-themes--property-lookup properties 'height #'floatp 'unspecified) - :underline - (if (memq 'underline properties) - t - 'unspecified)))) - - - -;;;; Utilities for DIY users - -;;;;; List colors (a variant of M-x list-colors-display) - -(defun modus-themes--list-colors-render (buffer theme &rest _) - "Render colors in BUFFER from THEME. -Routine for `modus-themes-list-colors'." - (let ((palette (seq-uniq (modus-themes--palette theme) - (lambda (x y) - (eq (car x) (car y))))) - (current-buffer buffer) - (current-theme theme)) - (with-help-window buffer - (with-current-buffer standard-output - (erase-buffer) - (when (<= (display-color-cells) 256) - (insert (concat "Your display terminal may not render all color previews!\n" - "It seems to only support <= 256 colors.\n\n")) - (put-text-property (point-min) (point) 'face 'warning)) - ;; We need this to properly render the first line. - (insert " ") - (dolist (cell palette) - (let* ((name (car cell)) - (color (cdr cell)) - (fg (readable-foreground-color color)) - (pad (make-string 5 ?\s))) - (let ((old-point (point))) - (insert (format "%s %s" color pad)) - (put-text-property old-point (point) 'face `( :foreground ,color))) - (let ((old-point (point))) - (insert (format " %s %s %s\n" color pad name)) - (put-text-property old-point (point) - 'face `( :background ,color - :foreground ,fg - :extend t))) - ;; We need this to properly render the last line. - (insert " "))) - (setq-local revert-buffer-function - (lambda (_ignore-auto _noconfirm) - (modus-themes--list-colors-render current-buffer current-theme))))))) - -(defvar modus-themes--list-colors-prompt-history '() - "Minibuffer history for `modus-themes--list-colors-prompt'.") - -(defun modus-themes--list-colors-prompt () - "Prompt for Modus theme. -Helper function for `modus-themes-list-colors'." - (let ((def (format "%s" (modus-themes--current-theme)))) - (completing-read - (format "Use palette from theme [%s]: " def) - '(modus-operandi modus-vivendi) nil t nil - 'modus-themes--list-colors-prompt-history def))) - -(defun modus-themes-list-colors (theme) - "Preview palette of the Modus THEME of choice." - (interactive (list (intern (modus-themes--list-colors-prompt)))) - (modus-themes--list-colors-render - (format "*%s-list-colors*" theme) - theme)) - -(defun modus-themes-list-colors-current () - "Call `modus-themes-list-colors' for the current Modus theme." - (interactive) - (modus-themes-list-colors (modus-themes--current-theme))) - -;;;;; Formula to measure relative luminance - -;; This is the WCAG formula: https://www.w3.org/TR/WCAG20-TECHS/G18.html -(defun modus-themes-wcag-formula (hex) - "Get WCAG value of color value HEX. -The value is defined in hexadecimal RGB notation, such as those in -`modus-themes-operandi-colors' and `modus-themes-vivendi-colors'." - (cl-loop for k in '(0.2126 0.7152 0.0722) - for x in (color-name-to-rgb hex) - sum (* k (if (<= x 0.03928) - (/ x 12.92) - (expt (/ (+ x 0.055) 1.055) 2.4))))) - -;;;###autoload -(defun modus-themes-contrast (c1 c2) - "Measure WCAG contrast ratio between C1 and C2. -C1 and C2 are color values written in hexadecimal RGB." - (let ((ct (/ (+ (modus-themes-wcag-formula c1) 0.05) - (+ (modus-themes-wcag-formula c2) 0.05)))) - (max ct (/ ct)))) - -;;;;; Retrieve colors from the themes - -(defun modus-themes-current-palette () - "Return current color palette." - (modus-themes--palette (modus-themes--current-theme))) - -;;;###autoload -(defun modus-themes-color (color) - "Return color value for COLOR from current palette. -COLOR is a key in `modus-themes-operandi-colors' or -`modus-themes-vivendi-colors'." - (alist-get color (modus-themes-current-palette))) - -;;;###autoload -(defun modus-themes-color-alts (light-color dark-color) - "Return color value from current palette. -When Modus Operandi is enabled, return color value for color -LIGHT-COLOR. When Modus Vivendi is enabled, return color value -for DARK-COLOR. LIGHT-COLOR and DARK-COLOR are keys in -`modus-themes-operandi-colors' or `modus-themes-vivendi-colors'." - (let* ((theme (modus-themes--current-theme)) - (color (pcase theme - ('modus-operandi light-color) - ('modus-vivendi dark-color) - (_theme - (error "'%s' is not a Modus theme" theme))))) - (alist-get color (modus-themes--palette theme)))) - -(defmacro modus-themes-with-colors (&rest body) - "Evaluate BODY with colors from current palette bound. -For colors bound, see `modus-themes-operandi-colors' or -`modus-themes-vivendi-colors'." - (declare (indent 0)) - (let ((palette-sym (gensym)) - (colors (mapcar #'car modus-themes-operandi-colors))) - `(let* ((class '((class color) (min-colors 89))) - (,palette-sym (modus-themes-current-palette)) - ,@(mapcar (lambda (color) - (list color `(alist-get ',color ,palette-sym))) - colors)) - (ignore class ,@colors) ; Silence unused variable warnings - ,@body))) - - - -;;;; Commands - -;;;###autoload -(defun modus-themes-load-themes () - "Ensure that the Modus themes are in `custom-enabled-themes'. - -This function is intended for use in package declarations such as -those defined with the help of `use-package'. The idea is to add -this function to the `:init' stage of the package's loading, so -that subsequent calls that assume the presence of a loaded theme, -like `modus-themes-toggle' or `modus-themes-load-operandi', will -continue to work as intended even if they are lazy-loaded (such -as when they are declared in the `:config' phase)." - (unless (or (custom-theme-p 'modus-operandi) - (custom-theme-p 'modus-vivendi)) - (load-theme 'modus-operandi t t) - (load-theme 'modus-vivendi t t))) - -(defvar modus-themes-after-load-theme-hook nil - "Hook that runs after the `modus-themes-toggle' routines.") - -;;;###autoload -(defun modus-themes-load-operandi () - "Load `modus-operandi' and disable `modus-vivendi'. -Also run `modus-themes-after-load-theme-hook'." - (interactive) - (disable-theme 'modus-vivendi) - (load-theme 'modus-operandi t) - (run-hooks 'modus-themes-after-load-theme-hook)) - -;;;###autoload -(defun modus-themes-load-vivendi () - "Load `modus-vivendi' and disable `modus-operandi'. -Also run `modus-themes-after-load-theme-hook'." - (interactive) - (disable-theme 'modus-operandi) - (load-theme 'modus-vivendi t) - (run-hooks 'modus-themes-after-load-theme-hook)) - -(defun modus-themes--load-prompt () - "Helper for `modus-themes-toggle'." - (let ((theme - (intern - (completing-read "Load Modus theme (will disable all others): " - '(modus-operandi modus-vivendi) nil t)))) - (mapc #'disable-theme custom-enabled-themes) - (pcase theme - ('modus-operandi (modus-themes-load-operandi)) - ('modus-vivendi (modus-themes-load-vivendi))))) - -;;;###autoload -(defun modus-themes-toggle () - "Toggle between `modus-operandi' and `modus-vivendi' themes. -Also runs `modus-themes-after-load-theme-hook' at its last stage -by virtue of calling either of `modus-themes-load-operandi' and -`modus-themes-load-vivendi' functions." - (interactive) - (modus-themes-load-themes) - (pcase (modus-themes--current-theme) - ('modus-operandi (modus-themes-load-vivendi)) - ('modus-vivendi (modus-themes-load-operandi)) - (_ (modus-themes--load-prompt)))) - ;;;; Face specifications @@ -4067,901 +1377,555 @@ by virtue of calling either of `modus-themes-load-operandi' and '( ;;;; custom faces ;; these bespoke faces are inherited by other constructs below +;;;;; just the foregrounds + `(modus-themes-fg-red ((,c :foreground ,red))) + `(modus-themes-fg-red-warmer ((,c :foreground ,red-warmer))) + `(modus-themes-fg-red-cooler ((,c :foreground ,red-cooler))) + `(modus-themes-fg-red-faint ((,c :foreground ,red-faint))) + `(modus-themes-fg-red-intense ((,c :foreground ,red-intense))) + `(modus-themes-fg-green ((,c :foreground ,green))) + `(modus-themes-fg-green-warmer ((,c :foreground ,green-warmer))) + `(modus-themes-fg-green-cooler ((,c :foreground ,green-cooler))) + `(modus-themes-fg-green-faint ((,c :foreground ,green-faint))) + `(modus-themes-fg-green-intense ((,c :foreground ,green-intense))) + `(modus-themes-fg-yellow ((,c :foreground ,yellow))) + `(modus-themes-fg-yellow-warmer ((,c :foreground ,yellow-warmer))) + `(modus-themes-fg-yellow-cooler ((,c :foreground ,yellow-cooler))) + `(modus-themes-fg-yellow-faint ((,c :foreground ,yellow-faint))) + `(modus-themes-fg-yellow-intense ((,c :foreground ,yellow-intense))) + `(modus-themes-fg-blue ((,c :foreground ,blue))) + `(modus-themes-fg-blue-warmer ((,c :foreground ,blue-warmer))) + `(modus-themes-fg-blue-cooler ((,c :foreground ,blue-cooler))) + `(modus-themes-fg-blue-faint ((,c :foreground ,blue-faint))) + `(modus-themes-fg-blue-intense ((,c :foreground ,blue-intense))) + `(modus-themes-fg-magenta ((,c :foreground ,magenta))) + `(modus-themes-fg-magenta-warmer ((,c :foreground ,magenta-warmer))) + `(modus-themes-fg-magenta-cooler ((,c :foreground ,magenta-cooler))) + `(modus-themes-fg-magenta-faint ((,c :foreground ,magenta-faint))) + `(modus-themes-fg-magenta-intense ((,c :foreground ,magenta-intense))) + `(modus-themes-fg-cyan ((,c :foreground ,cyan))) + `(modus-themes-fg-cyan-warmer ((,c :foreground ,cyan-warmer))) + `(modus-themes-fg-cyan-cooler ((,c :foreground ,cyan-cooler))) + `(modus-themes-fg-cyan-faint ((,c :foreground ,cyan-faint))) + `(modus-themes-fg-cyan-intense ((,c :foreground ,cyan-intense))) ;;;;; subtle colored backgrounds - `(modus-themes-subtle-red ((,class :background ,red-subtle-bg :foreground ,fg-dim))) - `(modus-themes-subtle-green ((,class :background ,green-subtle-bg :foreground ,fg-dim))) - `(modus-themes-subtle-yellow ((,class :background ,yellow-subtle-bg :foreground ,fg-dim))) - `(modus-themes-subtle-blue ((,class :background ,blue-subtle-bg :foreground ,fg-dim))) - `(modus-themes-subtle-magenta ((,class :background ,magenta-subtle-bg :foreground ,fg-dim))) - `(modus-themes-subtle-cyan ((,class :background ,cyan-subtle-bg :foreground ,fg-dim))) - `(modus-themes-subtle-neutral ((,class :background ,bg-inactive :foreground ,fg-inactive))) + `(modus-themes-subtle-red ((,c :background ,bg-red-subtle :foreground ,fg-main))) + `(modus-themes-subtle-green ((,c :background ,bg-green-subtle :foreground ,fg-main))) + `(modus-themes-subtle-yellow ((,c :background ,bg-yellow-subtle :foreground ,fg-main))) + `(modus-themes-subtle-blue ((,c :background ,bg-blue-subtle :foreground ,fg-main))) + `(modus-themes-subtle-magenta ((,c :background ,bg-magenta-subtle :foreground ,fg-main))) + `(modus-themes-subtle-cyan ((,c :background ,bg-cyan-subtle :foreground ,fg-main))) ;;;;; intense colored backgrounds - `(modus-themes-intense-red ((,class :background ,red-intense-bg :foreground ,fg-main))) - `(modus-themes-intense-green ((,class :background ,green-intense-bg :foreground ,fg-main))) - `(modus-themes-intense-yellow ((,class :background ,yellow-intense-bg :foreground ,fg-main))) - `(modus-themes-intense-blue ((,class :background ,blue-intense-bg :foreground ,fg-main))) - `(modus-themes-intense-magenta ((,class :background ,magenta-intense-bg :foreground ,fg-main))) - `(modus-themes-intense-cyan ((,class :background ,cyan-intense-bg :foreground ,fg-main))) - `(modus-themes-intense-neutral ((,class :background ,bg-active :foreground ,fg-main))) -;;;;; refined background and foreground combinations - ;; general purpose styles that use an accented foreground against an - ;; accented background - `(modus-themes-refine-red ((,class :background ,red-refine-bg :foreground ,red-refine-fg))) - `(modus-themes-refine-green ((,class :background ,green-refine-bg :foreground ,green-refine-fg))) - `(modus-themes-refine-yellow ((,class :background ,yellow-refine-bg :foreground ,yellow-refine-fg))) - `(modus-themes-refine-blue ((,class :background ,blue-refine-bg :foreground ,blue-refine-fg))) - `(modus-themes-refine-magenta ((,class :background ,magenta-refine-bg :foreground ,magenta-refine-fg))) - `(modus-themes-refine-cyan ((,class :background ,cyan-refine-bg :foreground ,cyan-refine-fg))) -;;;;; "active" combinations, mostly for use on the mode line - `(modus-themes-active-red ((,class :background ,red-active :foreground ,bg-active))) - `(modus-themes-active-green ((,class :background ,green-active :foreground ,bg-active))) - `(modus-themes-active-yellow ((,class :background ,yellow-active :foreground ,bg-active))) - `(modus-themes-active-blue ((,class :background ,blue-active :foreground ,bg-active))) - `(modus-themes-active-magenta ((,class :background ,magenta-active :foreground ,bg-active))) - `(modus-themes-active-cyan ((,class :background ,cyan-active :foreground ,bg-active))) -;;;;; nuanced backgrounds - ;; useful for adding an accented background that is suitable for all - ;; main foreground colors (intended for use in Org source blocks) - `(modus-themes-nuanced-red ((,class :background ,red-nuanced-bg :extend t))) - `(modus-themes-nuanced-green ((,class :background ,green-nuanced-bg :extend t))) - `(modus-themes-nuanced-yellow ((,class :background ,yellow-nuanced-bg :extend t))) - `(modus-themes-nuanced-blue ((,class :background ,blue-nuanced-bg :extend t))) - `(modus-themes-nuanced-magenta ((,class :background ,magenta-nuanced-bg :extend t))) - `(modus-themes-nuanced-cyan ((,class :background ,cyan-nuanced-bg :extend t))) -;;;;; fringe-specific combinations - `(modus-themes-fringe-red ((,class :background ,red-fringe-bg :foreground ,fg-main))) - `(modus-themes-fringe-green ((,class :background ,green-fringe-bg :foreground ,fg-main))) - `(modus-themes-fringe-yellow ((,class :background ,yellow-fringe-bg :foreground ,fg-main))) - `(modus-themes-fringe-blue ((,class :background ,blue-fringe-bg :foreground ,fg-main))) - `(modus-themes-fringe-magenta ((,class :background ,magenta-fringe-bg :foreground ,fg-main))) - `(modus-themes-fringe-cyan ((,class :background ,cyan-fringe-bg :foreground ,fg-main))) -;;;;; special base values - ;; these are closer to the grayscale than the accents defined above - ;; and should only be used when the next closest alternative would be - ;; a grayscale value than an accented one - `(modus-themes-special-cold ((,class :background ,bg-special-cold :foreground ,fg-special-cold))) - `(modus-themes-special-mild ((,class :background ,bg-special-mild :foreground ,fg-special-mild))) - `(modus-themes-special-warm ((,class :background ,bg-special-warm :foreground ,fg-special-warm))) - `(modus-themes-special-calm ((,class :background ,bg-special-calm :foreground ,fg-special-calm))) -;;;;; diff-specific combinations - ;; intended for `diff-mode' or equivalent - `(modus-themes-diff-added - ((,class ,@(modus-themes--diff - bg-diff-focus-added fg-diff-focus-added - green-nuanced-bg fg-diff-added - bg-diff-focus-added-deuteran fg-diff-focus-added-deuteran - blue-nuanced-bg fg-diff-added-deuteran)))) - `(modus-themes-diff-changed - ((,class ,@(modus-themes--diff - bg-diff-focus-changed fg-diff-focus-changed - yellow-nuanced-bg fg-diff-changed)))) - `(modus-themes-diff-removed - ((,class ,@(modus-themes--diff - bg-diff-focus-removed fg-diff-focus-removed - red-nuanced-bg fg-diff-removed)))) - `(modus-themes-diff-refine-added - ((,class ,@(modus-themes--diff - bg-diff-refine-added fg-diff-refine-added - bg-diff-focus-added fg-diff-focus-added - bg-diff-refine-added-deuteran fg-diff-refine-added-deuteran - bg-diff-focus-added-deuteran fg-diff-focus-added-deuteran)))) - `(modus-themes-diff-refine-changed - ((,class ,@(modus-themes--diff - bg-diff-refine-changed fg-diff-refine-changed - bg-diff-focus-changed fg-diff-focus-changed)))) - `(modus-themes-diff-refine-removed - ((,class ,@(modus-themes--diff - bg-diff-refine-removed fg-diff-refine-removed - bg-diff-focus-removed fg-diff-focus-removed)))) - `(modus-themes-diff-focus-added - ((,class ,@(modus-themes--diff - bg-diff-focus-added fg-diff-focus-added - bg-diff-added fg-diff-added - bg-diff-focus-added-deuteran fg-diff-focus-added-deuteran - bg-diff-added-deuteran fg-diff-added-deuteran)))) - `(modus-themes-diff-focus-changed - ((,class ,@(modus-themes--diff - bg-diff-focus-changed fg-diff-focus-changed - bg-diff-changed fg-diff-changed)))) - `(modus-themes-diff-focus-removed - ((,class ,@(modus-themes--diff - bg-diff-focus-removed fg-diff-focus-removed - bg-diff-removed fg-diff-removed)))) - `(modus-themes-diff-heading - ((,class ,@(modus-themes--diff - bg-diff-heading fg-diff-heading - cyan-nuanced-bg cyan-nuanced-fg - bg-header fg-main - bg-header fg-main - t)))) -;;;;; deuteranopia-specific - `(modus-themes-grue ((,class :foreground ,@(modus-themes--deuteran blue green)))) - `(modus-themes-grue-active ((,class :foreground ,@(modus-themes--deuteran blue-active green-active)))) - `(modus-themes-grue-nuanced ((,class :foreground ,@(modus-themes--deuteran blue-nuanced-fg green-nuanced-fg)))) - `(modus-themes-grue-background-active ((,class :inherit ,@(modus-themes--deuteran - 'modus-themes-fringe-blue - 'modus-themes-fringe-green)))) - `(modus-themes-grue-background-intense ((,class :inherit ,@(modus-themes--deuteran - 'modus-themes-intense-blue - 'modus-themes-intense-green)))) - `(modus-themes-grue-background-subtle ((,class :inherit ,@(modus-themes--deuteran - 'modus-themes-subtle-blue - 'modus-themes-subtle-green)))) - `(modus-themes-grue-background-subtle ((,class :inherit ,@(modus-themes--deuteran - 'modus-themes-refine-blue - 'modus-themes-refine-green)))) + `(modus-themes-intense-red ((,c :background ,bg-red-intense :foreground ,fg-main))) + `(modus-themes-intense-green ((,c :background ,bg-green-intense :foreground ,fg-main))) + `(modus-themes-intense-yellow ((,c :background ,bg-yellow-intense :foreground ,fg-main))) + `(modus-themes-intense-blue ((,c :background ,bg-blue-intense :foreground ,fg-main))) + `(modus-themes-intense-magenta ((,c :background ,bg-magenta-intense :foreground ,fg-main))) + `(modus-themes-intense-cyan ((,c :background ,bg-cyan-intense :foreground ,fg-main))) ;;;;; mark indicators ;; color combinations intended for Dired, Ibuffer, or equivalent - `(modus-themes-pseudo-header ((,class :inherit bold :foreground ,fg-main))) - `(modus-themes-mark-alt ((,class :inherit bold :background ,bg-mark-alt :foreground ,fg-mark-alt))) - `(modus-themes-mark-del ((,class :inherit bold :background ,bg-mark-del :foreground ,fg-mark-del))) - `(modus-themes-mark-sel ((,class :inherit bold - :background ,@(modus-themes--deuteran - cyan-refine-bg - bg-mark-sel) - :foreground ,fg-mark-sel))) - `(modus-themes-mark-symbol ((,class :inherit bold :foreground ,blue-alt))) + `(modus-themes-mark-alt ((,c :inherit bold :background ,bg-yellow-subtle :foreground ,yellow))) + `(modus-themes-mark-del ((,c :inherit bold :background ,bg-red-subtle :foreground ,red))) + `(modus-themes-mark-sel ((,c :inherit bold :background ,bg-cyan-subtle :foreground ,cyan))) ;;;;; heading levels ;; styles for regular headings used in Org, Markdown, Info, etc. - `(modus-themes-heading-0 - ((,class ,@(modus-themes--heading - 0 cyan-alt-other blue-alt - cyan-nuanced-bg bg-alt bg-region)))) - `(modus-themes-heading-1 - ((,class ,@(modus-themes--heading - 1 fg-main magenta-alt-other - magenta-nuanced-bg bg-alt bg-region)))) - `(modus-themes-heading-2 - ((,class ,@(modus-themes--heading - 2 fg-special-warm magenta-alt - red-nuanced-bg bg-alt bg-region)))) - `(modus-themes-heading-3 - ((,class ,@(modus-themes--heading - 3 fg-special-cold blue - blue-nuanced-bg bg-alt bg-region)))) - `(modus-themes-heading-4 - ((,class ,@(modus-themes--heading - 4 fg-special-mild cyan - cyan-nuanced-bg bg-alt bg-region)))) - `(modus-themes-heading-5 - ((,class ,@(modus-themes--heading - 5 fg-special-calm green-alt-other - green-nuanced-bg bg-alt bg-region)))) - `(modus-themes-heading-6 - ((,class ,@(modus-themes--heading - 6 yellow-nuanced-fg yellow-alt-other - yellow-nuanced-bg bg-alt bg-region)))) - `(modus-themes-heading-7 - ((,class ,@(modus-themes--heading - 7 red-nuanced-fg red-alt - red-nuanced-bg bg-alt bg-region)))) - `(modus-themes-heading-8 - ((,class ,@(modus-themes--heading - 8 magenta-nuanced-fg magenta - bg-alt bg-alt bg-region)))) + `(modus-themes-heading-0 ((,c ,@(modus-themes--heading 0 fg-heading-0 bg-heading-0 overline-heading-0)))) + `(modus-themes-heading-1 ((,c ,@(modus-themes--heading 1 fg-heading-1 bg-heading-1 overline-heading-1)))) + `(modus-themes-heading-2 ((,c ,@(modus-themes--heading 2 fg-heading-2 bg-heading-2 overline-heading-2)))) + `(modus-themes-heading-3 ((,c ,@(modus-themes--heading 3 fg-heading-3 bg-heading-3 overline-heading-3)))) + `(modus-themes-heading-4 ((,c ,@(modus-themes--heading 4 fg-heading-4 bg-heading-4 overline-heading-4)))) + `(modus-themes-heading-5 ((,c ,@(modus-themes--heading 5 fg-heading-5 bg-heading-5 overline-heading-5)))) + `(modus-themes-heading-6 ((,c ,@(modus-themes--heading 6 fg-heading-6 bg-heading-6 overline-heading-6)))) + `(modus-themes-heading-7 ((,c ,@(modus-themes--heading 7 fg-heading-7 bg-heading-7 overline-heading-7)))) + `(modus-themes-heading-8 ((,c ,@(modus-themes--heading 8 fg-heading-8 bg-heading-8 overline-heading-8)))) ;;;;; language checkers - `(modus-themes-lang-error ((,class ,@(modus-themes--lang-check - fg-lang-underline-error fg-lang-error - red red-refine-fg red-nuanced-bg red-refine-bg red-faint)))) - `(modus-themes-lang-note ((,class ,@(modus-themes--lang-check - fg-lang-underline-note fg-lang-note - blue-alt blue-refine-fg blue-nuanced-bg blue-refine-bg blue-faint)))) - `(modus-themes-lang-warning ((,class ,@(modus-themes--lang-check - fg-lang-underline-warning fg-lang-warning - yellow yellow-refine-fg yellow-nuanced-bg yellow-refine-bg yellow-faint)))) -;;;;; links - `(modus-themes-link-broken ((,class :inherit button ,@(modus-themes--link-color red red-faint)))) - `(modus-themes-link-symlink ((,class :inherit button ,@(modus-themes--link-color cyan cyan-faint)))) + `(modus-themes-lang-error ((,c :underline (:style wave :color ,underline-err)))) + `(modus-themes-lang-note ((,c :underline (:style wave :color ,underline-note)))) + `(modus-themes-lang-warning ((,c :underline (:style wave :color ,underline-warning)))) ;;;;; markup - `(modus-themes-markup-code - ((,class ,@(modus-themes--markup cyan-alt-other cyan-intense bg-alt - bg-special-faint-mild)))) - `(modus-themes-markup-macro - ((,class ,@(modus-themes--markup magenta-alt-other purple-intense bg-alt - bg-special-faint-cold)))) - `(modus-themes-markup-verbatim - ((,class ,@(modus-themes--markup magenta-alt magenta-intense bg-alt - bg-special-faint-calm)))) + `(modus-themes-prose-code ((,c :inherit modus-themes-fixed-pitch :foreground ,prose-code))) + `(modus-themes-prose-macro ((,c :inherit modus-themes-fixed-pitch :foreground ,prose-macro))) + `(modus-themes-prose-verbatim ((,c :inherit modus-themes-fixed-pitch :foreground ,prose-verbatim))) ;;;;; search - `(modus-themes-search-success ((,class :inherit modus-themes-intense-yellow))) - `(modus-themes-search-success-lazy ((,class :inherit modus-themes-subtle-cyan))) - `(modus-themes-search-success-modeline ((,class :foreground ,@(modus-themes--deuteran - blue-active - green-active)))) -;;;;; tabs - `(modus-themes-tab-active ((,class ,@(modus-themes--tab bg-tab-active nil nil nil t t)))) - `(modus-themes-tab-backdrop ((,class ,@(modus-themes--tab bg-active bg-active-accent nil nil nil nil t)))) - `(modus-themes-tab-inactive ((,class ,@(modus-themes--tab bg-tab-inactive bg-tab-inactive-accent fg-dim nil t)))) + `(modus-themes-search-current ((,c :background ,bg-yellow-intense :foreground ,fg-main))) + `(modus-themes-search-lazy ((,c :background ,bg-cyan-intense :foreground ,fg-main))) ;;;;; completion frameworks - `(modus-themes-completion-match-0 - ((,class ,@(modus-themes--completion-match - 'matches bg-special-faint-calm magenta-alt - magenta-subtle-bg magenta-intense)))) - `(modus-themes-completion-match-1 - ((,class ,@(modus-themes--completion-match - 'matches bg-special-faint-cold blue - blue-subtle-bg blue-intense)))) - `(modus-themes-completion-match-2 - ((,class ,@(modus-themes--completion-match - 'matches bg-special-faint-mild green - green-subtle-bg green-intense)))) - `(modus-themes-completion-match-3 - ((,class ,@(modus-themes--completion-match - 'matches bg-special-faint-warm yellow - yellow-subtle-bg orange-intense)))) - `(modus-themes-completion-selected - ((,class ,@(modus-themes--completion-line - 'selection bg-inactive blue-alt - bg-active blue-active - bg-completion-subtle bg-completion)))) - `(modus-themes-completion-selected-popup - ((,class ,@(modus-themes--completion-line - 'popup bg-active blue-alt - bg-region blue-active - cyan-subtle-bg cyan-refine-bg)))) -;;;;; buttons - `(modus-themes-box-button - ((,class ,@(modus-themes--button bg-active bg-main bg-active-accent - bg-special-cold bg-region)))) - `(modus-themes-box-button-pressed - ((,class ,@(modus-themes--button bg-active bg-main bg-active-accent - bg-special-cold bg-region t)))) + `(modus-themes-completion-match-0 ((,c ,@(modus-themes--completion-match fg-completion-match-0 bg-completion-match-0)))) + `(modus-themes-completion-match-1 ((,c ,@(modus-themes--completion-match fg-completion-match-1 bg-completion-match-1)))) + `(modus-themes-completion-match-2 ((,c ,@(modus-themes--completion-match fg-completion-match-2 bg-completion-match-2)))) + `(modus-themes-completion-match-3 ((,c ,@(modus-themes--completion-match fg-completion-match-3 bg-completion-match-3)))) + `(modus-themes-completion-selected ((,c ,@(modus-themes--completion-line bg-completion)))) ;;;;; typography - `(modus-themes-bold ((,class ,@(modus-themes--bold-weight)))) - `(modus-themes-fixed-pitch ((,class ,@(modus-themes--fixed-pitch)))) - `(modus-themes-slant ((,class ,@(modus-themes--slant)))) - `(modus-themes-ui-variable-pitch ((,class ,@(modus-themes--variable-pitch-ui)))) + `(modus-themes-bold ((,c ,@(modus-themes--bold-weight)))) + `(modus-themes-fixed-pitch ((,c ,@(modus-themes--fixed-pitch)))) + `(modus-themes-slant ((,c ,@(modus-themes--slant)))) + `(modus-themes-ui-variable-pitch ((,c ,@(modus-themes--variable-pitch-ui)))) ;;;;; other custom faces - `(modus-themes-hl-line ((,class ,@(modus-themes--hl-line - bg-hl-line bg-hl-line-intense - bg-hl-line-intense-accent blue-nuanced-bg - bg-region blue-intense-bg - fg-alt blue-intense) - :extend t))) - `(modus-themes-key-binding ((,class :inherit (bold modus-themes-fixed-pitch) - :foreground ,blue-alt-other))) - `(modus-themes-prompt ((,class ,@(modus-themes--prompt - cyan-alt-other blue-alt-other fg-alt - cyan-nuanced-bg blue-refine-bg fg-main - bg-alt bg-active)))) - `(modus-themes-reset-hard ((,class :inherit (fixed-pitch modus-themes-reset-soft) - :family ,(face-attribute 'default :family)))) - `(modus-themes-reset-soft ((,class :background ,bg-main :foreground ,fg-main - :weight normal :slant normal :strike-through nil - :box nil :underline nil :overline nil :extend nil))) + `(modus-themes-button ((,c :inherit variable-pitch :box ,border :background ,bg-button-active :foreground ,fg-button-active))) + `(modus-themes-key-binding ((,c :inherit (bold modus-themes-fixed-pitch) :foreground ,keybind))) + `(modus-themes-prompt ((,c ,@(modus-themes--prompt fg-prompt bg-prompt)))) + `(modus-themes-reset-soft ((,c :background ,bg-main :foreground ,fg-main + :weight normal :slant normal :strike-through nil + :box nil :underline nil :overline nil :extend nil))) ;;;; standard faces ;;;;; absolute essentials - `(default ((,class :background ,bg-main :foreground ,fg-main))) - `(cursor ((,class :background ,fg-main))) - `(fringe ((,class ,@(modus-themes--fringe bg-main bg-inactive bg-active) - :foreground ,fg-main))) - `(vertical-border ((,class :foreground ,fg-window-divider-inner))) + `(default ((,c :background ,bg-main :foreground ,fg-main))) + `(cursor ((,c :background ,cursor))) + `(fringe ((,c :background ,fringe :foreground ,fg-main))) + `(menu ((,c :background ,bg-tab-bar :foreground ,fg-main))) + `(scroll-bar ((,c :background ,fringe :foreground ,fg-dim))) + `(tool-bar ((,c :background ,bg-tab-bar :foreground ,fg-main))) + `(vertical-border ((,c :foreground ,border))) ;;;;; basic and/or ungrouped styles - `(bold ((,class :weight bold))) - `(bold-italic ((,class :inherit (bold italic)))) - `(underline ((,class :underline ,fg-alt))) - `(buffer-menu-buffer ((,class :inherit bold))) - `(child-frame-border ((,class :background ,fg-window-divider-inner))) - `(comint-highlight-input ((,class :inherit bold))) - `(comint-highlight-prompt ((,class :inherit modus-themes-prompt))) - `(confusingly-reordered ((,class :inherit modus-themes-lang-error))) - `(edmacro-label ((,class :inherit bold :foreground ,cyan))) - `(elisp-shorthand-font-lock-face ((,class :inherit font-lock-variable-name-face))) - `(error ((,class :inherit bold :foreground ,red))) - `(escape-glyph ((,class :foreground ,fg-escape-char-construct))) - `(file-name-shadow ((,class :inherit shadow))) - `(header-line ((,class :inherit modus-themes-ui-variable-pitch - :background ,bg-header :foreground ,fg-header))) - `(header-line-highlight ((,class :inherit highlight))) - `(help-argument-name ((,class :inherit modus-themes-slant :foreground ,cyan))) - `(help-key-binding ((,class :inherit modus-themes-key-binding))) - `(homoglyph ((,class :foreground ,red-alt-faint))) - `(ibuffer-locked-buffer ((,class :foreground ,yellow-alt-other-faint))) - `(icon-button ((,class :inherit modus-themes-box-button))) - `(italic ((,class :slant italic))) - `(nobreak-hyphen ((,class :foreground ,fg-escape-char-construct))) - `(nobreak-space ((,class :foreground ,fg-escape-char-construct :underline t))) - `(menu ((,class :inverse-video unspecified :inherit modus-themes-intense-neutral))) - `(minibuffer-prompt ((,class :inherit modus-themes-prompt))) - `(mm-command-output ((,class :foreground ,red-alt-other))) - `(mm-uu-extract ((,class :background ,bg-dim :foreground ,fg-special-mild))) - `(next-error ((,class :inherit modus-themes-subtle-red :extend t))) - `(pgtk-im-0 ((,class :inherit modus-themes-refine-cyan))) - `(read-multiple-choice-face ((,class :inherit (bold modus-themes-mark-alt)))) - `(rectangle-preview ((,class :inherit modus-themes-special-warm))) - `(region ((,class ,@(modus-themes--region bg-region fg-main - bg-hl-alt-intense bg-region-accent - bg-region-accent-subtle)))) - `(secondary-selection ((,class :inherit modus-themes-special-cold))) - `(separator-line ((,class :underline ,bg-region))) - `(shadow ((,class :foreground ,fg-alt))) - `(success ((,class :inherit (bold modus-themes-grue)))) - `(trailing-whitespace ((,class :background ,red-intense-bg))) - `(warning ((,class :inherit bold :foreground ,yellow))) + `(bold ((,c :weight bold))) + `(bold-italic ((,c :inherit (bold italic)))) + `(underline ((,c :underline ,fg-dim))) + `(buffer-menu-buffer ((,c :inherit bold))) + `(child-frame-border ((,c :background ,border))) + `(comint-highlight-input ((,c :inherit bold))) + `(comint-highlight-prompt ((,c :inherit modus-themes-prompt))) + `(confusingly-reordered ((,c :inherit modus-themes-lang-error))) + `(edmacro-label ((,c :inherit bold :foreground ,accent-0))) + `(elisp-shorthand-font-lock-face ((,c :inherit font-lock-variable-name-face))) + `(error ((,c :inherit bold :foreground ,err))) + `(escape-glyph ((,c :foreground ,err))) + `(file-name-shadow ((,c :inherit shadow))) + `(header-line ((,c :inherit modus-themes-ui-variable-pitch :background ,bg-dim))) + `(header-line-highlight ((,c :inherit highlight))) + `(help-argument-name ((,c :inherit modus-themes-slant :foreground ,variable))) + `(help-key-binding ((,c :inherit modus-themes-key-binding))) + `(homoglyph ((,c :foreground ,warning))) + `(ibuffer-locked-buffer ((,c :foreground ,warning))) + `(icon-button ((,c :inherit modus-themes-button))) + `(italic ((,c :slant italic))) + `(nobreak-hyphen ((,c :foreground ,err))) + `(nobreak-space ((,c :foreground ,err :underline t))) + `(menu ((,c :inverse-video unspecified :background ,bg-active :foreground ,fg-main))) + `(minibuffer-prompt ((,c :inherit modus-themes-prompt))) + `(mm-command-output ((,c :foreground ,mail-part))) + `(mm-uu-extract ((,c :foreground ,mail-part))) + `(next-error ((,c :inherit modus-themes-subtle-red :extend t))) + `(pgtk-im-0 ((,c :inherit modus-themes-intense-cyan))) + `(read-multiple-choice-face ((,c :inherit (bold modus-themes-mark-alt)))) + `(rectangle-preview ((,c :inherit secondary-selection))) + `(region ((,c :background ,bg-region :foreground ,fg-region))) + `(secondary-selection ((,c :background ,bg-hover-secondary))) + `(separator-line ((,c :underline ,bg-active))) + `(shadow ((,c :foreground ,fg-dim))) + `(success ((,c :inherit bold :foreground ,info))) + `(trailing-whitespace ((,c :background ,bg-red-intense))) + `(warning ((,c :inherit bold :foreground ,warning))) ;;;;; buttons, links, widgets - `(button ((,class ,@(modus-themes--link - blue-alt-other blue-alt-other-faint - bg-region blue-nuanced-bg bg-alt)))) - `(link ((,class :inherit button))) - `(link-visited ((,class :inherit button - ,@(modus-themes--link-color - magenta-alt-other magenta-alt-other-faint fg-alt)))) - `(tooltip ((,class :background ,bg-special-cold :foreground ,fg-main))) - `(widget-button ((,class ,@(if (memq 'all-buttons modus-themes-box-buttons) - (list :inherit 'modus-themes-box-button) - (list :inherit 'bold :foreground blue-alt))))) - `(widget-button-pressed ((,class ,@(if (memq 'all-buttons modus-themes-box-buttons) - (list :inherit 'modus-themes-box-button-pressed) - (list :inherit 'bold :foreground magenta-alt))))) - `(widget-documentation ((,class :foreground ,green))) - `(widget-field ((,class :background ,bg-alt :foreground ,fg-main :extend nil))) - `(widget-inactive ((,class :inherit shadow :background ,bg-dim))) - `(widget-single-line-field ((,class :inherit widget-field))) -;;;;; alert - `(alert-high-face ((,class :inherit bold :foreground ,red-alt))) - `(alert-low-face ((,class :foreground ,fg-special-mild))) - `(alert-moderate-face ((,class :inherit bold :foreground ,yellow))) - `(alert-trivial-face ((,class :foreground ,fg-special-calm))) - `(alert-urgent-face ((,class :inherit bold :foreground ,red-intense))) + `(button ((,c :background ,bg-link :foreground ,fg-link :underline ,underline-link))) + `(link ((,c :inherit button))) + `(link-visited ((,c :background ,bg-link-visited :foreground ,fg-link-visited :underline ,underline-link-visited))) + `(tooltip ((,c :background ,bg-active))) +;;;;; agda2-mode + `(agda2-highlight-bound-variable-face ((,c :inherit font-lock-variable-name-face))) + `(agda2-highlight-catchall-clause-face ((,c :background ,bg-inactive))) + `(agda2-highlight-coinductive-constructor-face ((,c :inherit font-lock-type-face))) + `(agda2-highlight-coverage-problem-face ((,c :inherit modus-themes-lang-error))) + `(agda2-highlight-datatype-face ((,c :inherit font-lock-type-face))) + `(agda2-highlight-deadcode-face ((,c :background ,bg-active))) + `(agda2-highlight-dotted-face ((,c :inherit font-lock-variable-name-face))) + `(agda2-highlight-error-face ((,c :inherit modus-themes-lang-error))) + `(agda2-highlight-field-face ((,c :inherit font-lock-type-face))) + `(agda2-highlight-function-face ((,c :inherit font-lock-function-name-face))) + `(agda2-highlight-generalizable-variable-face ((,c :inherit font-lock-variable-name-face))) + `(agda2-highlight-incomplete-pattern-face ((,c :inherit modus-themes-lang-warning))) + `(agda2-highlight-inductive-constructor-face ((,c :inherit font-lock-type-face))) + `(agda2-highlight-keyword-face ((,c :inherit font-lock-keyword-face))) + `(agda2-highlight-macro-face ((,c :inherit font-lock-keyword-face))) + `(agda2-highlight-module-face ((,c :inherit font-lock-variable-name-face))) + `(agda2-highlight-number-face ((,c :inherit shadow))) + `(agda2-highlight-operator-face ((,c :inherit font-lock-variable-name-face))) + `(agda2-highlight-positivity-problem-face ((,c :inherit modus-themes-lang-warning))) + `(agda2-highlight-postulate-face ((,c :inherit font-lock-type-face))) + `(agda2-highlight-pragma-face ((,c :inherit font-lock-preprocessor-face))) + `(agda2-highlight-primitive-face ((,c :inherit font-lock-type-face))) + `(agda2-highlight-primitive-type-face ((,c :inherit font-lock-type-face))) + `(agda2-highlight-record-face ((,c :inherit font-lock-type-face))) + `(agda2-highlight-string-face ((,c :inherit font-lock-string-face))) + `(agda2-highlight-symbol-face ((,c :inherit font-lock-constant-face))) + `(agda2-highlight-termination-problem-face ((,c :inherit modus-themes-lang-warning))) + `(agda2-highlight-typechecks-face ((,c :inherit font-lock-warning-face))) + `(agda2-highlight-unsolved-constraint-face ((,c :inherit modus-themes-lang-warning))) + `(agda2-highlight-unsolved-meta-face ((,c :inherit modus-themes-lang-warning))) ;;;;; all-the-icons - `(all-the-icons-blue ((,class :foreground ,blue-alt-other))) - `(all-the-icons-blue-alt ((,class :foreground ,blue-alt))) - `(all-the-icons-cyan ((,class :foreground ,cyan-intense))) - `(all-the-icons-cyan-alt ((,class :foreground ,cyan-alt))) - `(all-the-icons-dblue ((,class :foreground ,blue-faint))) - `(all-the-icons-dcyan ((,class :foreground ,cyan-faint))) - `(all-the-icons-dgreen ((,class :foreground ,green))) - `(all-the-icons-dmaroon ((,class :foreground ,magenta-alt-faint))) - `(all-the-icons-dorange ((,class :foreground ,red-alt-faint))) - `(all-the-icons-dpink ((,class :foreground ,magenta-faint))) - `(all-the-icons-dpurple ((,class :foreground ,magenta-alt-other-faint))) - `(all-the-icons-dred ((,class :foreground ,red-faint))) - `(all-the-icons-dsilver ((,class :foreground ,cyan-alt-faint))) - `(all-the-icons-dyellow ((,class :foreground ,yellow-alt-faint))) - `(all-the-icons-green ((,class :foreground ,green-intense))) - `(all-the-icons-lblue ((,class :foreground ,blue-alt-other))) - `(all-the-icons-lcyan ((,class :foreground ,cyan))) - `(all-the-icons-lgreen ((,class :foreground ,green-alt-other))) - `(all-the-icons-lmaroon ((,class :foreground ,magenta-alt))) - `(all-the-icons-lorange ((,class :foreground ,red-alt))) - `(all-the-icons-lpink ((,class :foreground ,magenta))) - `(all-the-icons-lpurple ((,class :foreground ,magenta-faint))) - `(all-the-icons-lred ((,class :foreground ,red))) - `(all-the-icons-lsilver ((,class :foreground ,fg-docstring))) - `(all-the-icons-lyellow ((,class :foreground ,yellow-alt))) - `(all-the-icons-maroon ((,class :foreground ,magenta-intense))) - `(all-the-icons-orange ((,class :foreground ,orange-intense))) - `(all-the-icons-pink ((,class :foreground ,fg-special-calm))) - `(all-the-icons-purple ((,class :foreground ,magenta-alt-other))) - `(all-the-icons-purple-alt ((,class :foreground ,purple-intense))) - `(all-the-icons-red ((,class :foreground ,red-intense))) - `(all-the-icons-red-alt ((,class :foreground ,red-alt-other))) - `(all-the-icons-silver ((,class :foreground ,fg-special-cold))) - `(all-the-icons-yellow ((,class :foreground ,yellow))) + `(all-the-icons-blue ((,c :foreground ,blue-cooler))) + `(all-the-icons-blue-warmer ((,c :foreground ,blue-warmer))) + `(all-the-icons-cyan ((,c :foreground ,cyan-intense))) + `(all-the-icons-cyan-warmer ((,c :foreground ,cyan-warmer))) + `(all-the-icons-dblue ((,c :foreground ,blue-faint))) + `(all-the-icons-dcyan ((,c :foreground ,cyan-faint))) + `(all-the-icons-dgreen ((,c :foreground ,green-faint))) + `(all-the-icons-dmaroon ((,c :foreground ,magenta-faint))) + `(all-the-icons-dorange ((,c :foreground ,red-faint))) + `(all-the-icons-dpink ((,c :foreground ,magenta-faint))) + `(all-the-icons-dpurple ((,c :foreground ,magenta-cooler))) + `(all-the-icons-dred ((,c :foreground ,red-faint))) + `(all-the-icons-dsilver ((,c :foreground ,cyan-faint))) + `(all-the-icons-dyellow ((,c :foreground ,yellow-faint))) + `(all-the-icons-green ((,c :foreground ,green))) + `(all-the-icons-lblue ((,c :foreground ,blue-cooler))) + `(all-the-icons-lcyan ((,c :foreground ,cyan))) + `(all-the-icons-lgreen ((,c :foreground ,green-warmer))) + `(all-the-icons-lmaroon ((,c :foreground ,magenta-warmer))) + `(all-the-icons-lorange ((,c :foreground ,red-warmer))) + `(all-the-icons-lpink ((,c :foreground ,magenta))) + `(all-the-icons-lpurple ((,c :foreground ,magenta-faint))) + `(all-the-icons-lred ((,c :foreground ,red))) + `(all-the-icons-lyellow ((,c :foreground ,yellow-warmer))) + `(all-the-icons-maroon ((,c :foreground ,yellow-cooler))) + `(all-the-icons-red ((,c :foreground ,red-intense))) + `(all-the-icons-red-warmer ((,c :foreground ,red-cooler))) + `(all-the-icons-yellow ((,c :foreground ,yellow-intense))) ;;;;; all-the-icons-dired - `(all-the-icons-dired-dir-face ((,class :foreground ,cyan-faint))) + `(all-the-icons-dired-dir-face ((,c :foreground ,cyan-faint))) ;;;;; all-the-icons-ibuffer - `(all-the-icons-ibuffer-dir-face ((,class :foreground ,cyan-faint))) - `(all-the-icons-ibuffer-file-face ((,class :foreground ,blue-faint))) - `(all-the-icons-ibuffer-mode-face ((,class :foreground ,cyan))) - `(all-the-icons-ibuffer-size-face ((,class :foreground ,cyan-alt-other))) + `(all-the-icons-ibuffer-dir-face ((,c :foreground ,cyan-faint))) + `(all-the-icons-ibuffer-file-face ((,c :foreground ,blue-faint))) + `(all-the-icons-ibuffer-mode-face ((,c :foreground ,cyan))) + `(all-the-icons-ibuffer-size-face ((,c :foreground ,cyan-cooler))) ;;;;; annotate - `(annotate-annotation ((,class :inherit modus-themes-subtle-blue))) - `(annotate-annotation-secondary ((,class :inherit modus-themes-subtle-green))) - `(annotate-highlight ((,class :background ,blue-nuanced-bg :underline ,blue-intense))) - `(annotate-highlight-secondary ((,class :background ,green-nuanced-bg :underline ,green-intense))) + `(annotate-annotation ((,c :inherit modus-themes-subtle-blue))) + `(annotate-annotation-secondary ((,c :inherit modus-themes-subtle-magenta))) + `(annotate-highlight ((,c :background ,bg-blue-subtle :underline ,blue-intense))) + `(annotate-highlight-secondary ((,c :background ,bg-magenta-subtle :underline ,magenta-intense))) ;;;;; ansi-color ;; Those are in Emacs28. - `(ansi-color-black ((,class :background "black" :foreground "black"))) - `(ansi-color-blue ((,class :background ,blue :foreground ,blue))) - `(ansi-color-bold ((,class :inherit bold))) - `(ansi-color-bright-black ((,class :background "gray35" :foreground "gray35"))) - `(ansi-color-bright-blue ((,class :background ,blue-alt :foreground ,blue-alt))) - `(ansi-color-bright-cyan ((,class :background ,cyan-alt-other :foreground ,cyan-alt-other))) - `(ansi-color-bright-green ((,class :background ,green-alt-other :foreground ,green-alt-other))) - `(ansi-color-bright-magenta ((,class :background ,magenta-alt-other :foreground ,magenta-alt-other))) - `(ansi-color-bright-red ((,class :background ,red-alt :foreground ,red-alt))) - `(ansi-color-bright-white ((,class :background "white" :foreground "white"))) - `(ansi-color-bright-yellow ((,class :background ,yellow-alt :foreground ,yellow-alt))) - `(ansi-color-cyan ((,class :background ,cyan :foreground ,cyan))) - `(ansi-color-green ((,class :background ,green :foreground ,green))) - `(ansi-color-magenta ((,class :background ,magenta :foreground ,magenta))) - `(ansi-color-red ((,class :background ,red :foreground ,red))) - `(ansi-color-white ((,class :background "gray65" :foreground "gray65"))) - `(ansi-color-yellow ((,class :background ,yellow :foreground ,yellow))) + `(ansi-color-black ((,c :background "black" :foreground "black"))) + `(ansi-color-blue ((,c :background ,blue :foreground ,blue))) + `(ansi-color-bold ((,c :inherit bold))) + `(ansi-color-bright-black ((,c :background "gray35" :foreground "gray35"))) + `(ansi-color-bright-blue ((,c :background ,blue-warmer :foreground ,blue-warmer))) + `(ansi-color-bright-cyan ((,c :background ,cyan-cooler :foreground ,cyan-cooler))) + `(ansi-color-bright-green ((,c :background ,green-cooler :foreground ,green-cooler))) + `(ansi-color-bright-magenta ((,c :background ,magenta-cooler :foreground ,magenta-cooler))) + `(ansi-color-bright-red ((,c :background ,red-warmer :foreground ,red-warmer))) + `(ansi-color-bright-white ((,c :background "white" :foreground "white"))) + `(ansi-color-bright-yellow ((,c :background ,yellow-warmer :foreground ,yellow-warmer))) + `(ansi-color-cyan ((,c :background ,cyan :foreground ,cyan))) + `(ansi-color-green ((,c :background ,green :foreground ,green))) + `(ansi-color-magenta ((,c :background ,magenta :foreground ,magenta))) + `(ansi-color-red ((,c :background ,red :foreground ,red))) + `(ansi-color-white ((,c :background "gray65" :foreground "gray65"))) + `(ansi-color-yellow ((,c :background ,yellow :foreground ,yellow))) ;;;;; anzu - `(anzu-match-1 ((,class :inherit modus-themes-subtle-cyan))) - `(anzu-match-2 ((,class :inherit modus-themes-search-success))) - `(anzu-match-3 ((,class :inherit modus-themes-subtle-yellow))) - `(anzu-mode-line ((,class :inherit (bold modus-themes-search-success-modeline)))) - `(anzu-mode-line-no-match ((,class :inherit bold :foreground ,red-active))) - `(anzu-replace-highlight ((,class :inherit modus-themes-refine-red :underline t))) - `(anzu-replace-to ((,class :inherit modus-themes-search-success))) -;;;;; apropos - `(apropos-button ((,class :foreground ,magenta-alt-other))) - `(apropos-function-button ((,class :foreground ,magenta))) - `(apropos-keybinding ((,class :inherit modus-themes-key-binding))) - `(apropos-misc-button ((,class :foreground ,green-alt-other))) - `(apropos-property ((,class :inherit modus-themes-bold :foreground ,magenta-alt))) - `(apropos-symbol ((,class :inherit modus-themes-pseudo-header))) - `(apropos-user-option-button ((,class :foreground ,cyan))) - `(apropos-variable-button ((,class :foreground ,blue-alt))) -;;;;; artbollocks-mode - `(artbollocks-face ((,class :inherit modus-themes-lang-note))) - `(artbollocks-lexical-illusions-face ((,class :background ,bg-alt :foreground ,red-alt :underline t))) - `(artbollocks-passive-voice-face ((,class :inherit modus-themes-lang-warning))) - `(artbollocks-weasel-words-face ((,class :inherit modus-themes-lang-error))) + `(anzu-match-1 ((,c :inherit modus-themes-subtle-cyan))) + `(anzu-match-2 ((,c :inherit modus-themes-search-current))) + `(anzu-match-3 ((,c :inherit modus-themes-subtle-yellow))) + `(anzu-mode-line ((,c :inherit bold))) + `(anzu-mode-line-no-match ((,c :inherit error))) + `(anzu-replace-highlight ((,c :inherit modus-themes-intense-red :underline t))) + `(anzu-replace-to ((,c :inherit modus-themes-search-current))) ;;;;; auctex and Tex - `(font-latex-bold-face ((,class :inherit bold))) - `(font-latex-doctex-documentation-face ((,class :inherit font-lock-doc-face))) - `(font-latex-doctex-preprocessor-face ((,class :inherit font-lock-preprocessor-face))) - `(font-latex-italic-face ((,class :inherit italic))) - `(font-latex-math-face ((,class :inherit font-lock-constant-face))) - `(font-latex-script-char-face ((,class :inherit font-lock-builtin-face))) - `(font-latex-sectioning-5-face ((,class :inherit (bold modus-themes-variable-pitch) :foreground ,blue-nuanced-fg))) - `(font-latex-sedate-face ((,class :inherit font-lock-keyword-face))) - `(font-latex-slide-title-face ((,class :inherit modus-themes-heading-1))) - `(font-latex-string-face ((,class :inherit font-lock-string-face))) - `(font-latex-subscript-face ((,class :height 0.95))) - `(font-latex-superscript-face ((,class :height 0.95))) - `(font-latex-underline-face ((,class :inherit underline))) - `(font-latex-verbatim-face ((,class :inherit modus-themes-markup-verbatim))) - `(font-latex-warning-face ((,class :inherit font-lock-warning-face))) - `(tex-verbatim ((,class :inherit modus-themes-markup-verbatim))) - `(texinfo-heading ((,class :foreground ,magenta))) - `(TeX-error-description-error ((,class :inherit error))) - `(TeX-error-description-help ((,class :inherit success))) - `(TeX-error-description-tex-said ((,class :inherit success))) - `(TeX-error-description-warning ((,class :inherit warning))) + `(font-latex-bold-face ((,c :inherit bold))) + `(font-latex-doctex-documentation-face ((,c :inherit font-lock-doc-face))) + `(font-latex-doctex-preprocessor-face ((,c :inherit font-lock-preprocessor-face))) + `(font-latex-italic-face ((,c :inherit italic))) + `(font-latex-math-face ((,c :inherit font-lock-constant-face))) + `(font-latex-script-char-face ((,c :inherit font-lock-builtin-face))) + `(font-latex-sectioning-5-face ((,c :inherit (bold modus-themes-variable-pitch) :foreground ,fg-alt))) + `(font-latex-sedate-face ((,c :inherit font-lock-keyword-face))) + `(font-latex-slide-title-face ((,c :inherit modus-themes-heading-1))) + `(font-latex-string-face ((,c :inherit font-lock-string-face))) + `(font-latex-subscript-face ((,c :height 0.95))) + `(font-latex-superscript-face ((,c :height 0.95))) + `(font-latex-underline-face ((,c :inherit underline))) + `(font-latex-verbatim-face ((,c :inherit modus-themes-prose-verbatim))) + `(font-latex-warning-face ((,c :inherit font-lock-warning-face))) + `(tex-verbatim ((,c :inherit modus-themes-prose-verbatim))) + ;; `(texinfo-heading ((,c :foreground ,magenta))) + `(TeX-error-description-error ((,c :inherit error))) + `(TeX-error-description-help ((,c :inherit success))) + `(TeX-error-description-tex-said ((,c :inherit success))) + `(TeX-error-description-warning ((,c :inherit warning))) ;;;;; auto-dim-other-buffers - `(auto-dim-other-buffers-face ((,class :background ,bg-alt))) + `(auto-dim-other-buffers-face ((,c :background ,bg-inactive))) ;;;;; avy - `(avy-background-face ((,class :background ,bg-dim :foreground ,fg-dim :extend t))) - `(avy-goto-char-timer-face ((,class :inherit (modus-themes-intense-neutral bold)))) - `(avy-lead-face ((,class :inherit (bold modus-themes-reset-soft) :background ,bg-char-0))) - `(avy-lead-face-0 ((,class :inherit (bold modus-themes-reset-soft) :background ,bg-char-1))) - `(avy-lead-face-1 ((,class :inherit (modus-themes-special-warm modus-themes-reset-soft)))) - `(avy-lead-face-2 ((,class :inherit (bold modus-themes-reset-soft) :background ,bg-char-2))) + `(avy-background-face ((,c :background ,bg-dim :foreground ,fg-dim :extend t))) + `(avy-goto-char-timer-face ((,c :inherit bold :background ,bg-active))) + `(avy-lead-face ((,c :inherit (bold modus-themes-reset-soft) :background ,bg-char-0))) + `(avy-lead-face-0 ((,c :inherit (bold modus-themes-reset-soft) :background ,bg-char-1))) + `(avy-lead-face-1 ((,c :inherit modus-themes-reset-soft :background ,bg-inactive))) + `(avy-lead-face-2 ((,c :inherit (bold modus-themes-reset-soft) :background ,bg-char-2))) ;;;;; aw (ace-window) - `(aw-background-face ((,class :foreground ,fg-unfocused))) - `(aw-key-face ((,class :inherit modus-themes-key-binding))) - `(aw-leading-char-face ((,class :inherit (bold modus-themes-reset-soft) :height 1.5 - :foreground ,red-intense))) - `(aw-minibuffer-leading-char-face ((,class :inherit (modus-themes-intense-red bold)))) - `(aw-mode-line-face ((,class :inherit bold))) -;;;;; awesome-tray - `(awesome-tray-module-awesome-tab-face ((,class :inherit bold :foreground ,red-alt-other))) - `(awesome-tray-module-battery-face ((,class :inherit bold :foreground ,cyan-alt-other))) - `(awesome-tray-module-buffer-name-face ((,class :inherit bold :foreground ,yellow-alt-other))) - `(awesome-tray-module-circe-face ((,class :inherit bold :foreground ,blue-alt))) - `(awesome-tray-module-date-face ((,class :inherit bold :foreground ,fg-dim))) - `(awesome-tray-module-evil-face ((,class :inherit bold :foreground ,green-alt))) - `(awesome-tray-module-git-face ((,class :inherit bold :foreground ,magenta))) - `(awesome-tray-module-last-command-face ((,class :inherit bold :foreground ,blue-alt-other))) - `(awesome-tray-module-location-face ((,class :inherit bold :foreground ,yellow))) - `(awesome-tray-module-mode-name-face ((,class :inherit bold :foreground ,green))) - `(awesome-tray-module-parent-dir-face ((,class :inherit bold :foreground ,cyan))) - `(awesome-tray-module-rvm-face ((,class :inherit bold :foreground ,magenta-alt-other))) -;;;;; bbdb - `(bbdb-name ((,class :foreground ,magenta-alt-other))) - `(bbdb-organization ((,class :foreground ,red-alt-other))) - `(bbdb-field-name ((,class :foreground ,cyan-alt-other))) + `(aw-background-face ((,c :foreground "gray50"))) + `(aw-key-face ((,c :inherit modus-themes-key-binding))) + `(aw-leading-char-face ((,c :inherit (bold modus-themes-reset-soft) :height 1.5 :foreground ,red-intense))) + `(aw-minibuffer-leading-char-face ((,c :inherit (modus-themes-intense-red bold)))) + `(aw-mode-line-face ((,c :inherit bold))) ;;;;; binder - `(binder-sidebar-highlight ((,class :inherit modus-themes-subtle-cyan))) - `(binder-sidebar-marked ((,class :inherit modus-themes-mark-sel))) - `(binder-sidebar-missing ((,class :inherit modus-themes-subtle-red))) - `(binder-sidebar-tags ((,class :foreground ,cyan))) -;;;;; bm - `(bm-face ((,class :inherit modus-themes-subtle-yellow :extend t))) - `(bm-fringe-face ((,class :inherit modus-themes-fringe-yellow))) - `(bm-fringe-persistent-face ((,class :inherit modus-themes-fringe-blue))) - `(bm-persistent-face ((,class :inherit modus-themes-intense-blue :extend t))) + `(binder-sidebar-highlight ((,c :inherit modus-themes-subtle-cyan))) + `(binder-sidebar-marked ((,c :inherit modus-themes-mark-sel))) + `(binder-sidebar-missing ((,c :inherit modus-themes-subtle-red))) + `(binder-sidebar-tags ((,c :foreground ,variable))) ;;;;; bongo - `(bongo-album-title ((,class :foreground ,fg-active))) - `(bongo-artist ((,class :foreground ,magenta-active))) - `(bongo-currently-playing-track ((,class :inherit bold))) - `(bongo-elapsed-track-part ((,class :inherit modus-themes-subtle-magenta :underline t))) - `(bongo-filled-seek-bar ((,class :background ,blue-intense-bg :foreground ,fg-main))) - `(bongo-marked-track ((,class :foreground ,fg-mark-alt))) - `(bongo-marked-track-line ((,class :background ,bg-mark-alt))) - `(bongo-played-track ((,class :foreground ,fg-unfocused :strike-through t))) - `(bongo-track-length ((,class :inherit shadow))) - `(bongo-track-title ((,class :foreground ,blue-active))) - `(bongo-unfilled-seek-bar ((,class :background ,bg-special-cold :foreground ,fg-main))) + `(bongo-album-title (( ))) + `(bongo-artist ((,c :foreground ,accent-0))) + `(bongo-currently-playing-track ((,c :inherit bold))) + `(bongo-elapsed-track-part ((,c :background ,bg-inactive :underline t))) + `(bongo-filled-seek-bar ((,c :background ,bg-hover))) + `(bongo-marked-track ((,c :inherit modus-themes-mark-alt))) + `(bongo-marked-track-line ((,c :background ,bg-dim))) + `(bongo-played-track ((,c :inherit shadow :strike-through t))) + `(bongo-track-length ((,c :inherit shadow))) + `(bongo-track-title ((,c :foreground ,accent-1))) + `(bongo-unfilled-seek-bar ((,c :background ,bg-dim))) ;;;;; boon - `(boon-modeline-cmd ((,class :inherit modus-themes-active-blue))) - `(boon-modeline-ins ((,class :inherit modus-themes-active-red))) - `(boon-modeline-off ((,class :inherit modus-themes-active-yellow))) - `(boon-modeline-spc ((,class :inherit modus-themes-active-green))) + `(boon-modeline-cmd ((,c :inherit modus-themes-intense-blue))) + `(boon-modeline-ins ((,c :inherit modus-themes-intense-red))) + `(boon-modeline-off ((,c :inherit modus-themes-intense-yellow))) + `(boon-modeline-spc ((,c :inherit modus-themes-intense-green))) ;;;;; bookmark - `(bookmark-face ((,class :inherit modus-themes-fringe-cyan))) - `(bookmark-menu-bookmark ((,class :inherit bold))) -;;;;; breakpoint (built-in gdb-mi.el) - `(breakpoint-disabled ((,class :inherit shadow))) - `(breakpoint-enabled ((,class :inherit bold :foreground ,red))) + `(bookmark-face ((,c :inherit success))) + `(bookmark-menu-bookmark ((,c :inherit bold))) ;;;;; calendar and diary - `(calendar-month-header ((,class :inherit modus-themes-pseudo-header))) - `(calendar-today ((,class :inherit bold :underline t))) - `(calendar-weekday-header ((,class :foreground ,fg-unfocused))) - `(calendar-weekend-header ((,class :foreground ,red-faint))) - `(diary ((,class :background ,blue-nuanced-bg :foreground ,blue-alt-other))) - `(diary-anniversary ((,class :foreground ,red-alt-other))) - `(diary-time ((,class :foreground ,cyan))) - `(holiday ((,class :background ,magenta-nuanced-bg :foreground ,magenta-alt))) -;;;;; calfw - `(cfw:face-annotation ((,class :foreground ,fg-special-warm))) - `(cfw:face-day-title ((,class :foreground ,fg-main))) - `(cfw:face-default-content ((,class :foreground ,green-alt))) - `(cfw:face-default-day ((,class :inherit (cfw:face-day-title bold)))) - `(cfw:face-disable ((,class :foreground ,fg-unfocused))) - `(cfw:face-grid ((,class :foreground ,fg-window-divider-outer))) - `(cfw:face-header ((,class :inherit bold :foreground ,fg-main))) - `(cfw:face-holiday ((,class :foreground ,magenta-alt-other))) - `(cfw:face-periods ((,class :foreground ,cyan-alt-other))) - `(cfw:face-saturday ((,class :inherit bold :foreground ,cyan-alt-other))) - `(cfw:face-select ((,class :inherit modus-themes-intense-blue))) - `(cfw:face-sunday ((,class :inherit bold :foreground ,cyan-alt-other))) - `(cfw:face-title ((,class :inherit modus-themes-heading-1 :background ,bg-main :overline nil :foreground ,fg-special-cold))) - `(cfw:face-today ((,class :background ,bg-inactive))) - `(cfw:face-today-title ((,class :background ,bg-active))) - `(cfw:face-toolbar ((,class :background ,bg-alt :foreground ,bg-alt))) - `(cfw:face-toolbar-button-off ((,class :inherit shadow))) - `(cfw:face-toolbar-button-on ((,class :inherit bold :background ,blue-nuanced-bg - :foreground ,blue-alt))) + `(calendar-month-header ((,c :inherit bold))) + `(calendar-today ((,c :inherit bold :underline t))) + `(calendar-weekday-header ((,c :foreground ,date-weekday))) + `(calendar-weekend-header ((,c :foreground ,date-weekend))) + `(diary ((,c :background ,bg-dim :foreground ,accent-0))) + `(diary-anniversary ((,c :foreground ,accent-1))) + `(diary-time ((,c :foreground ,date-common))) + `(holiday ((,c :foreground ,date-holiday))) ;;;;; calibredb - `(calibredb-archive-face ((,class :foreground ,magenta-alt-faint))) - `(calibredb-author-face ((,class :foreground ,blue-faint))) - `(calibredb-comment-face ((,class :inherit shadow))) - `(calibredb-date-face ((,class :foreground ,cyan))) - `(calibredb-edit-annotation-header-title-face ((,class :inherit bold))) - `(calibredb-favorite-face ((,class :foreground ,red-alt))) + ;; NOTE 2022-12-27: Calibredb needs to be reviewed. I had to + ;; change the applicable colours for the transition to + ;; modus-themes version 4, but I cannot test this currently (it + ;; depends on an external program). + `(calibredb-archive-face ((,c :foreground ,accent-3))) + `(calibredb-author-face ((,c :foreground ,name))) + `(calibredb-comment-face ((,c :inherit shadow))) + `(calibredb-date-face ((,c :foreground ,date-common))) + `(calibredb-edit-annotation-header-title-face ((,c :inherit bold))) + `(calibredb-favorite-face ((,c :foreground ,red-warmer))) `(calibredb-file-face (( ))) - `(calibredb-format-face ((,class :foreground ,cyan-faint))) - `(calibredb-highlight-face ((,class :inherit success))) + `(calibredb-format-face ((,c :foreground ,fg-alt))) + `(calibredb-highlight-face ((,c :inherit success))) `(calibredb-id-face (( ))) `(calibredb-ids-face (( ))) - `(calibredb-search-header-highlight-face ((,class :inherit modus-themes-hl-line))) - `(calibredb-search-header-library-name-face ((,class :foreground ,blue-active))) - `(calibredb-search-header-library-path-face ((,class :inherit bold))) - `(calibredb-search-header-sort-face ((,class :inherit bold :foreground ,magenta-active))) - `(calibredb-search-header-total-face ((,class :inherit bold :foreground ,cyan-active))) - `(calibredb-search-header-filter-face ((,class :inherit bold))) - `(calibredb-mark-face ((,class :inherit modus-themes-mark-sel))) + `(calibredb-search-header-highlight-face ((,c :background ,bg-hl-line :extend t))) + `(calibredb-search-header-library-name-face ((,c :foreground ,accent-2))) + `(calibredb-search-header-library-path-face ((,c :inherit bold))) + `(calibredb-search-header-sort-face ((,c :inherit bold :foreground ,accent-1))) + `(calibredb-search-header-total-face ((,c :inherit bold :foreground ,accent-0))) + `(calibredb-search-header-filter-face ((,c :inherit bold))) + `(calibredb-mark-face ((,c :inherit modus-themes-mark-sel))) `(calibredb-size-face (( ))) - `(calibredb-tag-face ((,class :foreground ,magenta-alt-faint))) + `(calibredb-tag-face ((,c :foreground ,fg-alt))) ;;;;; centaur-tabs - `(centaur-tabs-active-bar-face ((,class :background ,blue-active))) - `(centaur-tabs-close-mouse-face ((,class :inherit bold :foreground ,red-active :underline t))) - `(centaur-tabs-close-selected ((,class :inherit centaur-tabs-selected))) - `(centaur-tabs-close-unselected ((,class :inherit centaur-tabs-unselected))) - `(centaur-tabs-modified-marker-selected ((,class :inherit centaur-tabs-selected))) - `(centaur-tabs-modified-marker-unselected ((,class :inherit centaur-tabs-unselected))) - `(centaur-tabs-default ((,class :background ,bg-main))) - `(centaur-tabs-selected ((,class :inherit modus-themes-tab-active))) - `(centaur-tabs-selected-modified ((,class :inherit (italic centaur-tabs-selected)))) - `(centaur-tabs-unselected ((,class :inherit modus-themes-tab-inactive))) - `(centaur-tabs-unselected-modified ((,class :inherit (italic centaur-tabs-unselected)))) -;;;;; cfrs - `(cfrs-border-color ((,class :background ,fg-window-divider-inner))) + `(centaur-tabs-active-bar-face ((,c :background ,blue))) + `(centaur-tabs-close-mouse-face ((,c :inherit bold :foreground ,red :underline t))) + `(centaur-tabs-close-selected ((,c :inherit centaur-tabs-selected))) + `(centaur-tabs-close-unselected ((,c :inherit centaur-tabs-unselected))) + `(centaur-tabs-modified-marker-selected ((,c :inherit centaur-tabs-selected))) + `(centaur-tabs-modified-marker-unselected ((,c :inherit centaur-tabs-unselected))) + `(centaur-tabs-default ((,c :background ,bg-main))) + `(centaur-tabs-selected ((,c :inherit bold :box (:line-width -2 :color ,bg-tab-current) :background ,bg-tab-current))) + `(centaur-tabs-selected-modified ((,c :inherit (italic centaur-tabs-selected)))) + `(centaur-tabs-unselected ((,c :box (:line-width -2 :color ,bg-tab-other) :background ,bg-tab-other))) + `(centaur-tabs-unselected-modified ((,c :inherit (italic centaur-tabs-unselected)))) ;;;;; change-log and log-view (`vc-print-log' and `vc-print-root-log') - `(change-log-acknowledgment ((,class :inherit shadow))) - `(change-log-conditionals ((,class :foreground ,yellow))) - `(change-log-date ((,class :foreground ,cyan))) - `(change-log-email ((,class :foreground ,cyan-alt-other))) - `(change-log-file ((,class :inherit bold :foreground ,fg-special-cold))) - `(change-log-function ((,class :foreground ,green-alt-other))) - `(change-log-list ((,class :foreground ,magenta-alt))) - `(change-log-name ((,class :foreground ,magenta-alt-other))) - `(log-edit-header ((,class :foreground ,fg-special-warm))) - `(log-edit-headers-separator ((,class :height 1 :background ,fg-window-divider-inner :extend t))) - `(log-edit-summary ((,class :inherit bold :foreground ,blue))) - `(log-edit-unknown-header ((,class :inherit shadow))) - `(log-view-commit-body ((,class :foreground ,blue-nuanced-fg))) - `(log-view-file ((,class :inherit bold :foreground ,fg-special-cold))) - `(log-view-message ((,class :background ,bg-alt :foreground ,fg-alt))) + `(change-log-acknowledgment ((,c :foreground ,identifier))) + `(change-log-conditionals ((,c :inherit error))) + `(change-log-date ((,c :foreground ,date-common))) + `(change-log-email ((,c :foreground ,fg-alt))) + `(change-log-file ((,c :inherit bold))) + `(change-log-function ((,c :inherit warning))) + `(change-log-list ((,c :inherit bold))) + `(change-log-name ((,c :foreground ,name))) + `(log-edit-header ((,c :inherit bold))) + `(log-edit-headers-separator ((,c :height 1 :background ,border :extend t))) + `(log-edit-summary ((,c :inherit bold :foreground ,blue))) + `(log-edit-unknown-header ((,c :inherit shadow))) + `(log-view-commit-body (( ))) + `(log-view-file ((,c :inherit bold))) + `(log-view-message ((,c :foreground ,identifier))) ;;;;; cider - `(cider-debug-code-overlay-face ((,class :background ,bg-alt))) - `(cider-debug-prompt-face ((,class :foreground ,magenta-alt :underline t))) - `(cider-deprecated-face ((,class :inherit modus-themes-refine-yellow))) - `(cider-docview-emphasis-face ((,class :inherit italic :foreground ,fg-special-cold))) - `(cider-docview-literal-face ((,class :foreground ,blue-alt))) - `(cider-docview-strong-face ((,class :inherit bold :foreground ,fg-special-cold))) - `(cider-docview-table-border-face ((,class :inherit shadow))) - `(cider-enlightened-face ((,class :box (:line-width -1 :color ,yellow-alt :style nil) :background ,bg-dim))) - `(cider-enlightened-local-face ((,class :inherit bold :foreground ,yellow-alt-other))) - `(cider-error-highlight-face ((,class :foreground ,red :underline t))) - `(cider-fragile-button-face ((,class :box (:line-width 3 :color ,fg-alt :style released-button) :foreground ,yellow))) - `(cider-fringe-good-face ((,class :foreground ,green-active))) - `(cider-instrumented-face ((,class :box (:line-width -1 :color ,red :style nil) :background ,bg-dim))) - `(cider-reader-conditional-face ((,class :inherit italic :foreground ,fg-special-warm))) - `(cider-repl-input-face ((,class :inherit bold))) - `(cider-repl-prompt-face ((,class :inherit modus-themes-prompt))) - `(cider-repl-stderr-face ((,class :inherit bold :foreground ,red))) - `(cider-repl-stdout-face ((,class :foreground ,blue))) - `(cider-result-overlay-face ((,class :box (:line-width -1 :color ,blue :style nil) :background ,bg-dim))) - `(cider-stacktrace-error-class-face ((,class :inherit bold :foreground ,red))) - `(cider-stacktrace-error-message-face ((,class :inherit italic :foreground ,red-alt-other))) - `(cider-stacktrace-face ((,class :foreground ,fg-main))) - `(cider-stacktrace-filter-active-face ((,class :foreground ,cyan-alt :underline t))) - `(cider-stacktrace-filter-inactive-face ((,class :foreground ,cyan-alt))) - `(cider-stacktrace-fn-face ((,class :inherit bold :foreground ,fg-main))) - `(cider-stacktrace-ns-face ((,class :inherit (shadow italic)))) - `(cider-stacktrace-promoted-button-face ((,class :box (:line-width 3 :color ,fg-alt :style released-button) :foreground ,red))) - `(cider-stacktrace-suppressed-button-face ((,class :box (:line-width 3 :color ,fg-alt :style pressed-button) - :background ,bg-alt :foreground ,fg-alt))) - `(cider-test-error-face ((,class :inherit modus-themes-subtle-red))) - `(cider-test-failure-face ((,class :inherit (modus-themes-intense-red bold)))) - `(cider-test-success-face ((,class :inherit modus-themes-grue-background-intense))) - `(cider-traced-face ((,class :box (:line-width -1 :color ,cyan :style nil) :background ,bg-dim))) - `(cider-warning-highlight-face ((,class :foreground ,yellow :underline t))) + `(cider-deprecated-face ((,c :inherit warning))) + `(cider-enlightened-face ((,c :box ,warning))) + `(cider-enlightened-local-face ((,c :inherit warning))) + `(cider-error-highlight-face ((,c :inherit modus-themes-lang-error))) + `(cider-fringe-good-face ((,c :foreground ,info))) + `(cider-instrumented-face ((,c :box ,err))) + `(cider-reader-conditional-face ((,c :inherit font-lock-type-face))) + `(cider-repl-prompt-face ((,c :inherit minibuffer-prompt))) + `(cider-repl-stderr-face ((,c :foreground ,err))) + `(cider-repl-stdout-face (( ))) + `(cider-warning-highlight-face ((,c :inherit modus-themes-lang-warning))) ;;;;; circe (and lui) - `(circe-fool-face ((,class :inherit shadow))) - `(circe-highlight-nick-face ((,class :inherit bold :foreground ,blue))) - `(circe-prompt-face ((,class :inherit modus-themes-prompt))) - `(circe-server-face ((,class :foreground ,fg-unfocused))) - `(lui-button-face ((,class :inherit button))) - `(lui-highlight-face ((,class :foreground ,magenta-alt))) - `(lui-time-stamp-face ((,class :foreground ,blue-nuanced-fg))) + `(circe-fool-face ((,c :inherit shadow))) + `(circe-highlight-nick-face ((,c :inherit error))) + `(circe-prompt-face ((,c :inherit modus-themes-prompt))) + `(circe-server-face ((,c :inherit shadow))) + `(lui-button-face ((,c :inherit button))) + `(lui-highlight-face ((,c :inherit error))) + `(lui-time-stamp-face ((,c :foreground ,date-common))) ;;;;; citar - `(citar ((,class :inherit shadow))) + `(citar ((,c :inherit shadow))) `(citar-highlight (( ))) -;;;;; color-rg - `(color-rg-font-lock-column-number ((,class :foreground ,magenta-alt-other))) - `(color-rg-font-lock-command ((,class :inherit bold :foreground ,fg-main))) - `(color-rg-font-lock-file ((,class :inherit bold :foreground ,fg-special-cold))) - `(color-rg-font-lock-flash ((,class :inherit modus-themes-intense-blue))) - `(color-rg-font-lock-function-location ((,class :inherit modus-themes-special-calm))) - `(color-rg-font-lock-header-line-directory ((,class :foreground ,blue-active))) - `(color-rg-font-lock-header-line-edit-mode ((,class :foreground ,magenta-active))) - `(color-rg-font-lock-header-line-keyword ((,class :foreground ,green-active))) - `(color-rg-font-lock-header-line-text ((,class :foreground ,fg-active))) - `(color-rg-font-lock-line-number ((,class :foreground ,fg-special-warm))) - `(color-rg-font-lock-mark-changed ((,class :inherit bold :foreground ,blue))) - `(color-rg-font-lock-mark-deleted ((,class :inherit bold :foreground ,red))) - `(color-rg-font-lock-match ((,class :inherit modus-themes-special-calm))) - `(color-rg-font-lock-position-splitter ((,class :inherit shadow))) +;;;;; clojure-mode + `(clojure-keyword-face ((,c :inherit font-lock-builtin-face))) ;;;;; column-enforce-mode - `(column-enforce-face ((,class :inherit modus-themes-refine-yellow))) + `(column-enforce-face ((,c :inherit modus-themes-intense-yellow))) ;;;;; company-mode - `(company-echo-common ((,class :inherit modus-themes-completion-match-0))) - `(company-preview ((,class :background ,bg-dim :foreground ,fg-dim))) - `(company-preview-common ((,class :inherit company-echo-common))) - `(company-preview-search ((,class :inherit modus-themes-special-calm))) - `(company-template-field ((,class :inherit modus-themes-intense-magenta))) - `(company-scrollbar-bg ((,class :background ,bg-active))) - `(company-scrollbar-fg ((,class :background ,fg-active))) - `(company-tooltip ((,class :background ,bg-alt))) - `(company-tooltip-annotation ((,class :inherit completions-annotations))) - `(company-tooltip-common ((,class :inherit company-echo-common))) - `(company-tooltip-deprecated ((,class :inherit company-tooltip :strike-through t))) - `(company-tooltip-mouse ((,class :inherit highlight))) - `(company-tooltip-scrollbar-thumb ((,class :background ,fg-active))) - `(company-tooltip-scrollbar-track ((,class :background ,bg-active))) - `(company-tooltip-search ((,class :inherit (modus-themes-search-success-lazy bold)))) - `(company-tooltip-search-selection ((,class :inherit modus-themes-search-success :underline t))) - `(company-tooltip-selection ((,class :inherit modus-themes-completion-selected-popup))) -;;;;; company-posframe - `(company-posframe-active-backend-name ((,class :inherit bold :background ,bg-active :foreground ,blue-active))) - `(company-posframe-inactive-backend-name ((,class :background ,bg-active :foreground ,fg-active))) - `(company-posframe-metadata ((,class :background ,bg-inactive :foreground ,fg-inactive))) + `(company-echo-common ((,c :inherit modus-themes-completion-match-0))) + `(company-preview ((,c :background ,bg-dim :foreground ,fg-dim))) + `(company-preview-common ((,c :inherit company-echo-common))) + `(company-preview-search ((,c :background ,bg-yellow-intense))) + `(company-scrollbar-bg ((,c :background ,bg-active))) + `(company-scrollbar-fg ((,c :background ,fg-main))) + `(company-template-field ((,c :background ,bg-active))) + `(company-tooltip ((,c :background ,bg-inactive))) + `(company-tooltip-annotation ((,c :inherit completions-annotations))) + `(company-tooltip-common ((,c :inherit company-echo-common))) + `(company-tooltip-deprecated ((,c :inherit company-tooltip :strike-through t))) + `(company-tooltip-mouse ((,c :inherit highlight))) + `(company-tooltip-scrollbar-thumb ((,c :background ,fg-alt))) + `(company-tooltip-scrollbar-track ((,c :background ,bg-inactive))) + `(company-tooltip-search ((,c :inherit secondary-selection))) + `(company-tooltip-search-selection ((,c :inherit secondary-selection :underline t))) + `(company-tooltip-selection ((,c :inherit modus-themes-completion-selected))) ;;;;; compilation - `(compilation-column-number ((,class :inherit compilation-line-number))) - `(compilation-error ((,class :inherit modus-themes-bold :foreground ,red))) - `(compilation-info ((,class :inherit modus-themes-bold :foreground ,fg-special-cold))) - `(compilation-line-number ((,class :foreground ,fg-special-warm))) - `(compilation-mode-line-exit ((,class :inherit bold))) - `(compilation-mode-line-fail ((,class :inherit modus-themes-bold :foreground ,red-active))) - `(compilation-mode-line-run ((,class :inherit modus-themes-bold :foreground ,cyan-active))) - `(compilation-warning ((,class :inherit modus-themes-bold :foreground ,yellow-alt))) + `(compilation-column-number ((,c :inherit compilation-line-number))) + `(compilation-error ((,c :inherit modus-themes-bold :foreground ,err))) + `(compilation-info ((,c :inherit modus-themes-bold :foreground ,info))) + `(compilation-line-number ((,c :inherit shadow))) + `(compilation-mode-line-exit ((,c :inherit bold))) + `(compilation-mode-line-fail ((,c :inherit bold :foreground ,modeline-err))) + `(compilation-mode-line-run ((,c :inherit bold :foreground ,modeline-warning))) + `(compilation-warning ((,c :inherit warning))) ;;;;; completions - `(completions-annotations ((,class :inherit modus-themes-slant :foreground ,cyan-faint))) - `(completions-common-part ((,class :inherit modus-themes-completion-match-0))) - `(completions-first-difference ((,class :inherit modus-themes-completion-match-1))) + `(completions-annotations ((,c :inherit modus-themes-slant :foreground ,docstring))) + `(completions-common-part ((,c :inherit modus-themes-completion-match-0))) + `(completions-first-difference ((,c :inherit modus-themes-completion-match-1))) ;;;;; consult - `(consult-async-running ((,class :inherit bold :foreground ,blue))) - `(consult-async-split ((,class :foreground ,magenta-alt))) - `(consult-bookmark ((,class :foreground ,blue))) - `(consult-file ((,class :foreground ,fg-special-cold))) - `(consult-imenu-prefix ((,class :inherit shadow))) - `(consult-key ((,class :inherit modus-themes-key-binding))) - `(consult-line-number ((,class :foreground ,fg-special-warm))) - `(consult-line-number-prefix ((,class :foreground ,fg-unfocused))) - `(consult-narrow-indicator ((,class :foreground ,magenta-alt))) - `(consult-preview-cursor ((,class :inherit modus-themes-intense-blue))) - `(consult-preview-insertion ((,class :inherit modus-themes-special-warm))) + `(consult-async-split ((,c :inherit error))) + `(consult-key ((,c :inherit modus-themes-key-binding))) + `(consult-imenu-prefix ((,c :inherit shadow))) + `(consult-line-number ((,c :inherit shadow))) ;;;;; corfu - `(corfu-current ((,class :inherit modus-themes-completion-selected-popup))) - `(corfu-bar ((,class :background ,fg-alt))) - `(corfu-border ((,class :background ,bg-active))) - `(corfu-default ((,class :background ,bg-alt))) + `(corfu-current ((,c :inherit modus-themes-completion-selected))) + `(corfu-bar ((,c :background ,fg-dim))) + `(corfu-border ((,c :background ,bg-active))) + `(corfu-default ((,c :background ,bg-dim))) ;;;;; corfu-quick - `(corfu-quick1 ((,class :inherit bold :background ,bg-char-0))) - `(corfu-quick2 ((,class :inherit bold :background ,bg-char-1))) + `(corfu-quick1 ((,c :inherit bold :background ,bg-char-0))) + `(corfu-quick2 ((,c :inherit bold :background ,bg-char-1))) ;;;;; counsel - `(counsel-active-mode ((,class :foreground ,magenta-alt-other))) - `(counsel-application-name ((,class :foreground ,red-alt-other))) - `(counsel-key-binding ((,class :inherit modus-themes-key-binding))) - `(counsel-outline-1 ((,class :inherit org-level-1))) - `(counsel-outline-2 ((,class :inherit org-level-2))) - `(counsel-outline-3 ((,class :inherit org-level-3))) - `(counsel-outline-4 ((,class :inherit org-level-4))) - `(counsel-outline-5 ((,class :inherit org-level-5))) - `(counsel-outline-6 ((,class :inherit org-level-6))) - `(counsel-outline-7 ((,class :inherit org-level-7))) - `(counsel-outline-8 ((,class :inherit org-level-8))) - `(counsel-outline-default ((,class :foreground ,fg-main))) - `(counsel-variable-documentation ((,class :inherit modus-themes-slant :foreground ,yellow-alt-other))) -;;;;; counsel-css - `(counsel-css-selector-depth-face-1 ((,class :foreground ,blue))) - `(counsel-css-selector-depth-face-2 ((,class :foreground ,cyan))) - `(counsel-css-selector-depth-face-3 ((,class :foreground ,green))) - `(counsel-css-selector-depth-face-4 ((,class :foreground ,yellow))) - `(counsel-css-selector-depth-face-5 ((,class :foreground ,magenta))) - `(counsel-css-selector-depth-face-6 ((,class :foreground ,red))) -;;;;; cov - `(cov-coverage-not-run-face ((,class :foreground ,red-intense))) - `(cov-coverage-run-face ((,class :foreground ,green-intense))) - `(cov-heavy-face ((,class :foreground ,magenta-intense))) - `(cov-light-face ((,class :foreground ,blue-intense))) - `(cov-med-face ((,class :foreground ,yellow-intense))) - `(cov-none-face ((,class :foreground ,cyan-intense))) + `(counsel-active-mode ((,c :foreground ,keyword))) + `(counsel-application-name ((,c :foreground ,name))) + `(counsel-key-binding ((,c :inherit modus-themes-key-binding))) + `(counsel-outline-default ((,c :foreground ,fg-main))) + `(counsel-variable-documentation ((,c :inherit font-lock-doc-face))) ;;;;; cperl-mode - `(cperl-nonoverridable-face ((,class :foreground unspecified))) - `(cperl-array-face ((,class :inherit font-lock-keyword-face))) - `(cperl-hash-face ((,class :inherit font-lock-variable-name-face))) + `(cperl-nonoverridable-face ((,c :foreground unspecified))) + `(cperl-array-face ((,c :inherit font-lock-keyword-face))) + `(cperl-hash-face ((,c :inherit font-lock-variable-name-face))) ;;;;; crontab-mode - `(crontab-minute ((,class :foreground ,blue-alt))) - `(crontab-hour ((,class :foreground ,magenta-alt-other))) - `(crontab-month-day ((,class :foreground ,magenta-alt))) - `(crontab-month ((,class :foreground ,blue))) - `(crontab-week-day ((,class :foreground ,cyan))) - `(crontab-predefined ((,class :foreground ,blue-alt))) + `(crontab-minute ((,c :foreground ,string))) + `(crontab-hour ((,c :foreground ,keyword))) + `(crontab-month-day ((,c :foreground ,builtin))) + `(crontab-month ((,c :foreground ,constant))) + `(crontab-week-day ((,c :foreground ,variable))) + `(crontab-predefined ((,c :foreground ,string))) ;;;;; css-mode - `(css-property ((,class :inherit font-lock-type-face))) - `(css-selector ((,class :inherit font-lock-keyword-face))) + `(css-property ((,c :inherit font-lock-type-face))) + `(css-selector ((,c :inherit font-lock-keyword-face))) ;;;;; csv-mode - `(csv-separator-face ((,class :foreground ,red-intense))) + `(csv-separator-face ((,c :foreground ,red-intense))) ;;;;; ctrlf - `(ctrlf-highlight-active ((,class :inherit modus-themes-search-success))) - `(ctrlf-highlight-line ((,class :inherit modus-themes-hl-line))) - `(ctrlf-highlight-passive ((,class :inherit modus-themes-search-success-lazy))) + `(ctrlf-highlight-active ((,c :inherit modus-themes-search-current))) + `(ctrlf-highlight-line ((,c :inherit highlight))) + `(ctrlf-highlight-passive ((,c :inherit modus-themes-search-lazy))) ;;;;; custom (M-x customize) - `(custom-button ((,class :inherit modus-themes-box-button))) - `(custom-button-mouse ((,class :inherit (highlight custom-button)))) - `(custom-button-pressed ((,class :inherit modus-themes-box-button-pressed))) - `(custom-changed ((,class :inherit modus-themes-subtle-cyan))) - `(custom-comment ((,class :inherit shadow))) - `(custom-comment-tag ((,class :background ,bg-alt :foreground ,yellow-alt-other))) - `(custom-face-tag ((,class :inherit bold :foreground ,blue-intense))) - `(custom-group-tag ((,class :inherit modus-themes-pseudo-header :foreground ,magenta-alt))) - `(custom-group-tag-1 ((,class :inherit modus-themes-special-warm))) - `(custom-invalid ((,class :inherit (modus-themes-intense-red bold)))) - `(custom-modified ((,class :inherit modus-themes-subtle-cyan))) - `(custom-rogue ((,class :inherit modus-themes-refine-magenta))) - `(custom-set ((,class :foreground ,blue-alt))) - `(custom-state ((,class :foreground ,red-alt-faint))) - `(custom-themed ((,class :inherit modus-themes-subtle-blue))) - `(custom-variable-obsolete ((,class :inherit shadow))) - `(custom-variable-tag ((,class :foreground ,cyan))) -;;;;; dap-mode - `(dap-mouse-eval-thing-face ((,class :box (:line-width -1 :color ,blue-active :style nil) - :background ,bg-active :foreground ,fg-main))) - `(dap-result-overlay-face ((,class :box (:line-width -1 :color ,bg-active :style nil) - :background ,bg-active :foreground ,fg-main))) - `(dap-ui-breakpoint-verified-fringe ((,class :inherit bold :foreground ,green-active))) - `(dap-ui-compile-errline ((,class :inherit bold :foreground ,red-intense))) - `(dap-ui-locals-scope-face ((,class :inherit bold :foreground ,magenta :underline t))) - `(dap-ui-locals-variable-face ((,class :inherit bold :foreground ,cyan))) - `(dap-ui-locals-variable-leaf-face ((,class :inherit italic :foreground ,cyan-alt-other))) - `(dap-ui-marker-face ((,class :inherit modus-themes-subtle-blue))) - `(dap-ui-sessions-stack-frame-face ((,class :inherit bold :foreground ,magenta-alt))) - `(dap-ui-sessions-terminated-active-face ((,class :inherit bold :foreground ,fg-alt))) - `(dap-ui-sessions-terminated-face ((,class :inherit shadow))) + `(custom-button ((,c :inherit modus-themes-button))) + `(custom-button-mouse ((,c :inherit (highlight custom-button)))) + `(custom-button-pressed ((,c :inherit (secondary-selection custom-button)))) + `(custom-changed ((,c :background ,bg-changed))) + `(custom-comment ((,c :inherit shadow))) + `(custom-comment-tag ((,c :inherit (bold shadow)))) + `(custom-invalid ((,c :inherit error :strike-through t))) + `(custom-modified ((,c :inherit custom-changed))) + `(custom-rogue ((,c :inherit custom-invalid))) + `(custom-set ((,c :inherit success))) + `(custom-state ((,c :foreground ,warning))) + `(custom-themed ((,c :inherit custom-changed))) + `(custom-variable-obsolete ((,c :inherit shadow))) + `(custom-face-tag ((,c :inherit bold :foreground ,type))) + `(custom-group-tag ((,c :inherit bold :foreground ,builtin))) + `(custom-group-tag-1 ((,c :inherit bold :foreground ,constant))) + `(custom-variable-tag ((,c :inherit bold :foreground ,variable))) ;;;;; deadgrep - `(deadgrep-filename-face ((,class :inherit bold :foreground ,fg-special-cold))) - `(deadgrep-match-face ((,class :inherit modus-themes-special-calm))) - `(deadgrep-meta-face ((,class :inherit shadow))) - `(deadgrep-regexp-metachar-face ((,class :inherit bold :foreground ,yellow-intense))) - `(deadgrep-search-term-face ((,class :inherit bold :foreground ,green-intense))) -;;;;; debbugs - `(debbugs-gnu-archived ((,class :inverse-video t))) - `(debbugs-gnu-done ((,class :inherit shadow))) - `(debbugs-gnu-forwarded ((,class :foreground ,fg-special-warm))) - `(debbugs-gnu-handled ((,class :foreground ,blue))) - `(debbugs-gnu-new ((,class :foreground ,red))) - `(debbugs-gnu-pending ((,class :foreground ,cyan))) - `(debbugs-gnu-stale-1 ((,class :foreground ,yellow-nuanced-fg))) - `(debbugs-gnu-stale-2 ((,class :foreground ,yellow))) - `(debbugs-gnu-stale-3 ((,class :foreground ,yellow-alt))) - `(debbugs-gnu-stale-4 ((,class :foreground ,yellow-alt-other))) - `(debbugs-gnu-stale-5 ((,class :foreground ,red-alt))) - `(debbugs-gnu-tagged ((,class :foreground ,magenta-alt))) + `(deadgrep-filename-face ((,c :inherit bold :foreground ,name))) + `(deadgrep-match-face ((,c :inherit match))) + `(deadgrep-meta-face ((,c :inherit shadow))) + `(deadgrep-regexp-metachar-face ((,c :inherit font-lock-regexp-grouping-construct))) + `(deadgrep-search-term-face ((,c :inherit success))) ;;;;; deft - `(deft-filter-string-face ((,class :inherit bold :foreground ,blue))) - `(deft-header-face ((,class :foreground ,fg-special-warm))) - `(deft-separator-face ((,class :foreground "gray50"))) - `(deft-summary-face ((,class :inherit (shadow modus-themes-slant)))) - `(deft-time-face ((,class :foreground ,cyan))) - `(deft-title-face ((,class :inherit bold))) -;;;;; denote - `(denote-faces-date ((,class :foreground ,cyan))) - `(denote-faces-keywords ((,class :inherit modus-themes-bold :foreground ,magenta-alt))) + `(deft-filter-string-face ((,c :inherit success))) + `(deft-header-face ((,c :inherit shadow))) + `(deft-separator-face ((,c :foreground "gray50"))) + `(deft-summary-face ((,c :inherit (shadow modus-themes-slant)))) + `(deft-time-face ((,c :foreground ,date-common))) + `(deft-title-face ((,c :inherit bold))) ;;;;; devdocs - `(devdocs-code-block ((,class :inherit modus-themes-fixed-pitch :background ,bg-dim :extend t))) + `(devdocs-code-block ((,c :inherit modus-themes-fixed-pitch :background ,bg-dim :extend t))) ;;;;; dictionary - `(dictionary-button-face ((,class :inherit bold :foreground ,fg-special-cold))) - `(dictionary-reference-face ((,class :inherit button))) - `(dictionary-word-definition-face (())) - `(dictionary-word-entry-face ((,class :inherit font-lock-comment-face))) + `(dictionary-button-face ((,c :inherit bold))) + `(dictionary-reference-face ((,c :inherit link))) + `(dictionary-word-definition-face (( ))) + `(dictionary-word-entry-face ((,c :inherit font-lock-comment-face))) ;;;;; diff-hl - `(diff-hl-change ((,class :inherit modus-themes-fringe-yellow))) - `(diff-hl-delete ((,class :inherit modus-themes-fringe-red))) - `(diff-hl-insert ((,class :inherit modus-themes-grue-background-active))) - `(diff-hl-reverted-hunk-highlight ((,class :background ,fg-main :foreground ,bg-main))) + `(diff-hl-change ((,c :background ,bg-changed-intense))) + `(diff-hl-delete ((,c :background ,bg-removed-intense))) + `(diff-hl-insert ((,c :background ,bg-added-intense))) + `(diff-hl-reverted-hunk-highlight ((,c :background ,fg-main :foreground ,bg-main))) ;;;;; diff-mode - `(diff-added ((,class :inherit modus-themes-diff-added))) - `(diff-changed ((,class :inherit modus-themes-diff-changed :extend t))) - `(diff-changed-unspecified ((,class :inherit diff-changed))) - `(diff-context ((,class ,@(unless (eq modus-themes-diffs 'bg-only) (list :foreground fg-unfocused))))) - `(diff-error ((,class :inherit modus-themes-intense-red))) - `(diff-file-header ((,class :inherit (bold diff-header)))) - `(diff-function ((,class :inherit modus-themes-diff-heading))) - `(diff-header ((,class :foreground ,fg-main))) - `(diff-hunk-header ((,class :inherit (bold modus-themes-diff-heading)))) - `(diff-index ((,class :inherit bold :foreground ,blue-alt))) - `(diff-indicator-added ((,class :inherit (modus-themes-grue diff-added bold)))) - `(diff-indicator-changed ((,class :inherit (diff-changed bold) :foreground ,yellow))) - `(diff-indicator-removed ((,class :inherit (diff-removed bold) :foreground ,red))) - `(diff-nonexistent ((,class :inherit (modus-themes-neutral bold)))) - `(diff-refine-added ((,class :inherit modus-themes-diff-refine-added))) - `(diff-refine-changed ((,class :inherit modus-themes-diff-refine-changed))) - `(diff-refine-removed ((,class :inherit modus-themes-diff-refine-removed))) - `(diff-removed ((,class :inherit modus-themes-diff-removed))) + `(diff-added ((,c :background ,bg-added))) + `(diff-changed ((,c :background ,bg-changed :extend t))) + `(diff-changed-unspecified ((,c :inherit diff-changed))) + `(diff-removed ((,c :background ,bg-removed))) + `(diff-refine-added ((,c :background ,bg-added-refine))) + `(diff-refine-changed ((,c :background ,bg-changed-refine))) + `(diff-refine-removed ((,c :background ,bg-removed-refine))) + `(diff-indicator-added ((,c :inherit diff-added :foreground ,fg-added-intense))) + `(diff-indicator-changed ((,c :inherit diff-changed :foreground ,fg-changed-intense))) + `(diff-indicator-removed ((,c :inherit diff-removed :foreground ,fg-removed-intense))) + `(diff-context (( ))) + `(diff-error ((,c :inherit error))) + `(diff-file-header ((,c :inherit bold))) + `(diff-function ((,c :background ,bg-inactive))) + `(diff-header (( ))) + `(diff-hunk-header ((,c :inherit bold :background ,bg-inactive))) + `(diff-index ((,c :inherit italic))) + `(diff-nonexistent ((,c :inherit bold))) ;;;;; dim-autoload - `(dim-autoload-cookie-line ((,class :inherit font-lock-comment-face))) -;;;;; dir-treeview - `(dir-treeview-archive-face ((,class :foreground ,fg-special-warm))) - `(dir-treeview-archive-icon-face ((,class :inherit dir-treeview-default-icon-face :foreground ,yellow))) - `(dir-treeview-audio-face ((,class :foreground ,magenta))) - `(dir-treeview-audio-icon-face ((,class :inherit dir-treeview-default-icon-face :foreground ,magenta-alt))) - `(dir-treeview-control-face ((,class :inherit shadow))) - `(dir-treeview-control-mouse-face ((,class :inherit highlight))) - `(dir-treeview-default-icon-face ((,class :inherit (shadow bold) :family "Font Awesome"))) - `(dir-treeview-default-filename-face ((,class :foreground ,fg-main))) - `(dir-treeview-directory-face ((,class :foreground ,blue))) - `(dir-treeview-directory-icon-face ((,class :inherit dir-treeview-default-icon-face :foreground ,blue-alt))) - `(dir-treeview-executable-face ((,class :foreground ,red-alt))) - `(dir-treeview-executable-icon-face ((,class :inherit dir-treeview-default-icon-face :foreground ,red-alt-other))) - `(dir-treeview-image-face ((,class :foreground ,green-alt-other))) - `(dir-treeview-image-icon-face ((,class :inherit dir-treeview-default-icon-face :foreground ,green-alt))) - `(dir-treeview-indent-face ((,class :inherit shadow))) - `(dir-treeview-label-mouse-face ((,class :inherit highlight))) - `(dir-treeview-start-dir-face ((,class :inherit modus-themes-pseudo-header))) - `(dir-treeview-symlink-face ((,class :inherit modus-themes-link-symlink))) - `(dir-treeview-video-face ((,class :foreground ,magenta-alt-other))) - `(dir-treeview-video-icon-face ((,class :inherit dir-treeview-default-icon-face :foreground ,magenta-alt-other))) + `(dim-autoload-cookie-line ((,c :inherit font-lock-comment-face))) ;;;;; dired - `(dired-broken-symlink ((,class :inherit modus-themes-link-broken))) - `(dired-directory ((,class :foreground ,blue))) - `(dired-flagged ((,class :inherit modus-themes-mark-del))) - `(dired-header ((,class :inherit modus-themes-pseudo-header))) - `(dired-ignored ((,class :inherit shadow))) - `(dired-mark ((,class :inherit modus-themes-mark-symbol))) - `(dired-marked ((,class :inherit modus-themes-mark-sel))) - `(dired-perm-write ((,class :foreground ,fg-special-warm))) - `(dired-symlink ((,class :inherit modus-themes-link-symlink))) - `(dired-warning ((,class :inherit bold :foreground ,yellow))) + `(dired-broken-symlink ((,c :inherit button :foreground ,err))) + `(dired-directory ((,c :foreground ,accent-0))) + `(dired-flagged ((,c :inherit modus-themes-mark-del))) + `(dired-header ((,c :inherit bold))) + `(dired-ignored ((,c :inherit shadow))) + `(dired-mark ((,c :inherit bold))) + `(dired-marked ((,c :inherit modus-themes-mark-sel))) + `(dired-perm-write ((,c :inherit shadow))) + `(dired-symlink ((,c :inherit button :background ,bg-link-symbolic :foreground ,fg-link-symbolic :underline ,underline-link-symbolic))) + `(dired-warning ((,c :inherit warning))) ;;;;; dired-async - `(dired-async-failures ((,class :inherit bold :foreground ,red-active))) - `(dired-async-message ((,class :inherit bold :foreground ,blue-active))) - `(dired-async-mode-message ((,class :inherit bold :foreground ,cyan-active))) + `(dired-async-failures ((,c :inherit error))) + `(dired-async-message ((,c :inherit bold))) + `(dired-async-mode-message ((,c :inherit bold))) ;;;;; dired-git - `(dired-git-branch-else ((,class :inherit bold :foreground ,magenta-alt))) - `(dired-git-branch-master ((,class :inherit bold :foreground ,magenta-alt-other))) + `(dired-git-branch-else ((,c :inherit bold :foreground ,accent-0))) + `(dired-git-branch-master ((,c :inherit bold :foreground ,accent-1))) ;;;;; dired-git-info - `(dgi-commit-message-face ((,class :foreground ,cyan-alt-other))) + `(dgi-commit-message-face ((,c :foreground ,docstring))) ;;;;; dired-narrow - `(dired-narrow-blink ((,class :inherit (modus-themes-subtle-cyan bold)))) + `(dired-narrow-blink ((,c :inherit (modus-themes-subtle-cyan bold)))) ;;;;; dired-subtree ;; remove backgrounds from dired-subtree faces, else they break ;; dired-{flagged,marked} and any other face that sets a background @@ -4974,739 +1938,410 @@ by virtue of calling either of `modus-themes-load-operandi' and `(dired-subtree-depth-5-face (())) `(dired-subtree-depth-6-face (())) ;;;;; diredfl - `(diredfl-autofile-name ((,class :inherit modus-themes-special-cold))) - `(diredfl-compressed-file-name ((,class :foreground ,fg-special-warm))) - `(diredfl-compressed-file-suffix ((,class :foreground ,red-alt))) - `(diredfl-date-time ((,class :foreground ,cyan))) - `(diredfl-deletion ((,class :inherit modus-themes-mark-del))) - `(diredfl-deletion-file-name ((,class :inherit modus-themes-mark-del))) - `(diredfl-dir-heading ((,class :inherit modus-themes-pseudo-header))) - `(diredfl-dir-name ((,class :inherit dired-directory))) - `(diredfl-dir-priv ((,class :foreground ,blue-alt))) - `(diredfl-exec-priv ((,class :foreground ,magenta-alt))) - `(diredfl-executable-tag ((,class :foreground ,magenta-alt))) - `(diredfl-file-name ((,class :foreground ,fg-main))) - `(diredfl-file-suffix ((,class :foreground ,magenta-alt-other))) - `(diredfl-flag-mark ((,class :inherit modus-themes-mark-sel))) - `(diredfl-flag-mark-line ((,class :inherit modus-themes-mark-sel))) - `(diredfl-ignored-file-name ((,class :inherit shadow))) - `(diredfl-link-priv ((,class :foreground ,blue-alt-other))) - `(diredfl-no-priv ((,class :foreground "gray50"))) - `(diredfl-number ((,class :foreground ,cyan-alt-other-faint))) - `(diredfl-other-priv ((,class :foreground ,yellow))) - `(diredfl-rare-priv ((,class :foreground ,red))) - `(diredfl-read-priv ((,class :foreground ,fg-main))) - `(diredfl-symlink ((,class :inherit dired-symlink))) - `(diredfl-tagged-autofile-name ((,class :inherit modus-themes-refine-magenta))) - `(diredfl-write-priv ((,class :foreground ,cyan))) -;;;;; dired+ - `(diredp-autofile-name ((,class :inherit modus-themes-special-cold))) - `(diredp-compressed-file-name ((,class :foreground ,fg-special-warm))) - `(diredp-compressed-file-suffix ((,class :foreground ,red-alt))) - `(diredp-date-time ((,class :foreground ,cyan))) - `(diredp-deletion ((,class :inherit modus-themes-mark-del))) - `(diredp-deletion-file-name ((,class :inherit modus-themes-mark-del))) - `(diredp-dir-heading ((,class :inherit modus-themes-pseudo-header))) - `(diredp-dir-name ((,class :inherit dired-directory))) - `(diredp-dir-priv ((,class :foreground ,blue-alt))) - `(diredp-exec-priv ((,class :foreground ,magenta-alt))) - `(diredp-executable-tag ((,class :foreground ,magenta-alt))) - `(diredp-file-name ((,class :foreground ,fg-main))) - `(diredp-file-suffix ((,class :foreground ,magenta-alt-other))) - `(diredp-flag-mark ((,class :inherit modus-themes-mark-sel))) - `(diredp-flag-mark-line ((,class :inherit modus-themes-mark-sel))) - `(diredp-ignored-file-name ((,class :inherit shadow))) - `(diredp-link-priv ((,class :foreground ,blue-alt-other))) - `(diredp-mode-line-flagged ((,class :foreground ,red-active))) - `(diredp-mode-line-marked ((,class :foreground ,green-active))) - `(diredp-no-priv ((,class :foreground "gray50"))) - `(diredp-number ((,class :foreground ,cyan-alt-other-faint))) - `(diredp-omit-file-name ((,class :inherit shadow :strike-through t))) - `(diredp-other-priv ((,class :foreground ,yellow))) - `(diredp-rare-priv ((,class :foreground ,red))) - `(diredp-read-priv ((,class :foreground ,fg-main))) - `(diredp-symlink ((,class :inherit dired-symlink))) - `(diredp-tagged-autofile-name ((,class :inherit modus-themes-refine-magenta))) - `(diredp-write-priv ((,class :foreground ,cyan))) + `(diredfl-autofile-name ((,c :background ,bg-inactive))) + `(diredfl-compressed-file-name ((,c :foreground ,warning))) + `(diredfl-compressed-file-suffix ((,c :foreground ,err))) + `(diredfl-date-time ((,c :foreground ,date-common))) + `(diredfl-deletion ((,c :inherit dired-flagged))) + `(diredfl-deletion-file-name ((,c :inherit diredfl-deletion))) + `(diredfl-dir-heading ((,c :inherit bold))) + `(diredfl-dir-name ((,c :inherit dired-directory))) + `(diredfl-dir-priv ((,c :inherit dired-directory))) + `(diredfl-exec-priv ((,c :foreground ,accent-1))) + `(diredfl-executable-tag ((,c :inherit diredfl-exec-priv))) + `(diredfl-file-name ((,c :foreground ,fg-main))) + `(diredfl-file-suffix ((,c :foreground ,variable))) + `(diredfl-flag-mark ((,c :inherit dired-marked))) + `(diredfl-flag-mark-line ((,c :inherit dired-marked))) + `(diredfl-ignored-file-name ((,c :inherit shadow))) + `(diredfl-link-priv ((,c :foreground ,fg-link))) + `(diredfl-no-priv ((,c :inherit shadow))) + `(diredfl-number ((,c :inherit shadow))) + `(diredfl-other-priv ((,c :foreground ,accent-2))) + `(diredfl-rare-priv ((,c :foreground ,accent-3))) + `(diredfl-read-priv ((,c :foreground ,fg-main))) + `(diredfl-symlink ((,c :inherit dired-symlink))) + `(diredfl-tagged-autofile-name ((,c :inherit (diredfl-autofile-name dired-marked)))) + `(diredfl-write-priv ((,c :foreground ,accent-0))) ;;;;; display-fill-column-indicator-mode - `(fill-column-indicator ((,class :height 1 :background ,bg-region :foreground ,bg-region))) + `(fill-column-indicator ((,c :height 1 :background ,bg-active :foreground ,bg-active))) ;;;;; doom-modeline - `(doom-modeline-bar ((,class :inherit modus-themes-active-blue))) - `(doom-modeline-bar-inactive ((,class :background ,fg-inactive :foreground ,bg-main))) - `(doom-modeline-battery-charging ((,class :foreground ,green-active))) - `(doom-modeline-battery-critical ((,class :inherit bold :foreground ,red-active))) - `(doom-modeline-battery-error ((,class :inherit bold :box (:line-width -2) - :foreground ,red-active))) - `(doom-modeline-battery-full ((,class :foreground ,blue-active))) - `(doom-modeline-battery-normal ((,class :foreground ,fg-active))) - `(doom-modeline-battery-warning ((,class :inherit bold :foreground ,yellow-active))) - `(doom-modeline-buffer-file ((,class :inherit bold :foreground ,fg-active))) - `(doom-modeline-buffer-major-mode ((,class :inherit bold :foreground ,cyan-active))) - `(doom-modeline-buffer-minor-mode ((,class :foreground ,fg-inactive))) - `(doom-modeline-buffer-modified ((,class :inherit bold :foreground ,magenta-active))) - `(doom-modeline-buffer-path ((,class :inherit bold :foreground ,fg-active))) - `(doom-modeline-debug ((,class :inherit bold :foreground ,yellow-active))) - `(doom-modeline-debug-visual ((,class :inherit bold :foreground ,red-active))) - `(doom-modeline-evil-emacs-state ((,class :inherit bold :foreground ,magenta-active))) - `(doom-modeline-evil-insert-state ((,class :inherit bold :foreground ,green-active))) - `(doom-modeline-evil-motion-state ((,class :inherit bold :foreground ,fg-inactive))) - `(doom-modeline-evil-normal-state ((,class :inherit bold :foreground ,fg-active))) - `(doom-modeline-evil-operator-state ((,class :inherit bold :foreground ,blue-active))) - `(doom-modeline-evil-replace-state ((,class :inherit bold :foreground ,red-active))) - `(doom-modeline-evil-visual-state ((,class :inherit bold :foreground ,cyan-active))) - `(doom-modeline-highlight ((,class :inherit bold :foreground ,blue-active))) - `(doom-modeline-host ((,class :inherit italic))) - `(doom-modeline-info ((,class :foreground ,green-active))) - `(doom-modeline-lsp-error ((,class :inherit bold :foreground ,red-active))) - `(doom-modeline-lsp-success ((,class :inherit (bold modus-themes-grue-active)))) - `(doom-modeline-lsp-warning ((,class :inherit bold :foreground ,yellow-active))) - `(doom-modeline-panel ((,class :inherit modus-themes-active-blue))) - `(doom-modeline-persp-buffer-not-in-persp ((,class :inherit italic :foreground ,yellow-active))) - `(doom-modeline-persp-name ((,class :foreground ,fg-active))) - `(doom-modeline-project-dir ((,class :inherit bold :foreground ,blue-active))) - `(doom-modeline-project-parent-dir ((,class :foreground ,blue-active))) - `(doom-modeline-project-root-dir ((,class :foreground ,fg-active))) - `(doom-modeline-unread-number ((,class :inherit italic :foreground ,fg-active))) - `(doom-modeline-urgent ((,class :inherit bold :foreground ,red-active))) - `(doom-modeline-warning ((,class :inherit bold :foreground ,yellow-active))) -;;;;; easy-jekyll - `(easy-jekyll-help-face ((,class :background ,bg-dim :foreground ,blue-alt-other))) -;;;;; ebdb - `(ebdb-address-default ((,class :foreground ,fg-special-calm))) - `(ebdb-defunct ((,class :inherit shadow))) - `(ebdb-field-hidden ((,class :foreground ,magenta))) - `(ebdb-label ((,class :foreground ,cyan-alt-other))) - `(ebdb-mail-default ((,class :foreground ,fg-main))) - `(ebdb-mail-primary ((,class :foreground ,magenta-alt))) - `(ebdb-marked ((,class :background ,cyan-intense-bg))) - `(ebdb-organization-name ((,class :foreground ,red-alt-other))) - `(ebdb-person-name ((,class :foreground ,magenta-alt-other))) - `(ebdb-phone-default ((,class :foreground ,cyan))) - `(eieio-custom-slot-tag-face ((,class :foreground ,red-alt))) + `(doom-modeline-bar ((,c :background ,blue))) + `(doom-modeline-bar-inactive ((,c :background ,border))) + `(doom-modeline-battery-charging ((,c :foreground ,modeline-info))) + `(doom-modeline-battery-critical ((,c :underline t :foreground ,modeline-err))) + `(doom-modeline-battery-error ((,c :underline t :foreground ,modeline-err))) + `(doom-modeline-battery-full (( ))) + `(doom-modeline-battery-warning ((,c :inherit warning))) + `(doom-modeline-buffer-file ((,c :inherit bold))) + `(doom-modeline-buffer-major-mode (( ))) + `(doom-modeline-buffer-minor-mode (( ))) + `(doom-modeline-buffer-modified ((,c :foreground ,modeline-err))) + `(doom-modeline-buffer-path (( ))) + `(doom-modeline-evil-emacs-state ((,c :inherit italic))) + `(doom-modeline-evil-insert-state ((,c :foreground ,modeline-info))) + `(doom-modeline-evil-motion-state (( ))) + `(doom-modeline-evil-normal-state (( ))) + `(doom-modeline-evil-operator-state ((,c :inherit bold))) + `(doom-modeline-evil-replace-state ((,c :inherit error))) + `(doom-modeline-evil-visual-state ((,c :inherit warning))) + `(doom-modeline-info ((,c :inherit success))) + `(doom-modeline-input-method (( ))) + `(doom-modeline-lsp-error ((,c :inherit bold-italic))) + `(doom-modeline-lsp-running (( ))) + `(doom-modeline-lsp-success ((,c :inherit success))) + `(doom-modeline-lsp-warning ((,c :inherit warning))) + `(doom-modeline-notification ((,c :inherit error))) + `(doom-modeline-project-dir (( ))) + `(doom-modeline-project-parent-dir (( ))) + `(doom-modeline-project-root-dir (( ))) + `(doom-modeline-repl-success ((,c :inherit success))) + `(doom-modeline-repl-warning ((,c :inherit warning))) + `(doom-modeline-time (( ))) + `(doom-modeline-urgent ((,c :inherit bold-italic :foreground ,modeline-err))) + `(doom-modeline-warning ((,c :inherit warning))) ;;;;; ediff - `(ediff-current-diff-A ((,class :inherit modus-themes-diff-removed))) - `(ediff-current-diff-Ancestor ((,class ,@(modus-themes--diff - bg-special-cold fg-special-cold - blue-nuanced-bg blue)))) - `(ediff-current-diff-B ((,class :inherit modus-themes-diff-added))) - `(ediff-current-diff-C ((,class :inherit modus-themes-diff-changed))) - `(ediff-even-diff-A ((,class :background ,bg-alt))) - `(ediff-even-diff-Ancestor ((,class :background ,bg-alt))) - `(ediff-even-diff-B ((,class :background ,bg-alt))) - `(ediff-even-diff-C ((,class :background ,bg-alt))) - `(ediff-fine-diff-A ((,class :inherit modus-themes-diff-refine-removed))) - `(ediff-fine-diff-Ancestor ((,class :inherit modus-themes-refine-cyan))) - `(ediff-fine-diff-B ((,class :inherit modus-themes-diff-refine-added))) - `(ediff-fine-diff-C ((,class :inherit modus-themes-diff-refine-changed))) - `(ediff-odd-diff-A ((,class :inherit ediff-even-diff-A))) - `(ediff-odd-diff-Ancestor ((,class :inherit ediff-even-diff-Ancestor))) - `(ediff-odd-diff-B ((,class :inherit ediff-even-diff-B))) - `(ediff-odd-diff-C ((,class :inherit ediff-even-diff-C))) + `(ediff-current-diff-A ((,c :inherit diff-removed))) + `(ediff-current-diff-Ancestor ((,c :background ,bg-region))) ; TODO 2022-11-29: Needs review + `(ediff-current-diff-B ((,c :inherit diff-added))) + `(ediff-current-diff-C ((,c :inherit diff-changed))) + `(ediff-even-diff-A ((,c :background ,bg-dim))) + `(ediff-even-diff-Ancestor ((,c :background ,bg-dim))) + `(ediff-even-diff-B ((,c :background ,bg-dim))) + `(ediff-even-diff-C ((,c :background ,bg-dim))) + `(ediff-fine-diff-A ((,c :inherit diff-refine-removed))) + `(ediff-fine-diff-Ancestor ((,c :inherit diff-refine-cyan))) + `(ediff-fine-diff-B ((,c :inherit diff-refine-added))) + `(ediff-fine-diff-C ((,c :inherit diff-refine-changed))) + `(ediff-odd-diff-A ((,c :inherit ediff-even-diff-A))) + `(ediff-odd-diff-Ancestor ((,c :inherit ediff-even-diff-Ancestor))) + `(ediff-odd-diff-B ((,c :inherit ediff-even-diff-B))) + `(ediff-odd-diff-C ((,c :inherit ediff-even-diff-C))) ;;;;; ein (Emacs IPython Notebook) - `(ein:basecell-input-area-face ((,class :background ,bg-dim :extend t))) + `(ein:basecell-input-area-face ((,c :background ,bg-dim :extend t))) `(ein:cell-output-area (( ))) - `(ein:cell-output-area-error ((,class :background ,red-nuanced-bg :extend t))) - `(ein:cell-output-stderr ((,class :background ,red-nuanced-bg :extend t))) + `(ein:cell-output-area-error ((,c :background ,bg-removed :extend t))) + `(ein:cell-output-stderr ((,c :background ,bg-removed :extend t))) `(ein:markdowncell-input-area-face (( ))) - `(ein:notification-tab-normal ((,class :underline t))) + `(ein:notification-tab-normal ((,c :underline t))) ;;;;; eglot - `(eglot-mode-line ((,class :inherit modus-themes-bold :foreground ,magenta-active))) + `(eglot-mode-line ((,c :inherit bold :foreground ,modeline-info))) ;;;;; el-search - `(el-search-highlight-in-prompt-face ((,class :inherit bold :foreground ,magenta-alt))) - `(el-search-match ((,class :inherit modus-themes-search-success))) - `(el-search-other-match ((,class :inherit modus-themes-special-mild))) - `(el-search-occur-match ((,class :inherit modus-themes-special-calm))) + `(el-search-highlight-in-prompt-face ((,c :inherit italic))) + `(el-search-match ((,c :inherit modus-themes-search-current))) + `(el-search-other-match ((,c :inherit modus-themes-search-lazy))) + `(el-search-occur-match ((,c :inherit match))) ;;;;; eldoc ;; NOTE: see https://github.com/purcell/package-lint/issues/187 - (list 'eldoc-highlight-function-argument `((,class :inherit bold - :background ,yellow-nuanced-bg - :foreground ,yellow-alt-other))) + (list 'eldoc-highlight-function-argument `((,c :inherit modus-themes-mark-alt))) ;;;;; eldoc-box - `(eldoc-box-body ((,class :background ,bg-alt :foreground ,fg-main))) - `(eldoc-box-border ((,class :background ,fg-alt))) + `(eldoc-box-body ((,c :background ,bg-dim :foreground ,fg-main))) + `(eldoc-box-border ((,c :background ,border))) ;;;;; elfeed - `(elfeed-log-date-face ((,class :inherit elfeed-search-date-face))) - `(elfeed-log-debug-level-face ((,class :inherit elfeed-search-filter-face))) - `(elfeed-log-error-level-face ((,class :inherit error))) - `(elfeed-log-info-level-face ((,class :inherit success))) - `(elfeed-log-warn-level-face ((,class :inherit warning))) - `(elfeed-search-date-face ((,class :foreground ,cyan))) - `(elfeed-search-feed-face ((,class :foreground ,blue-faint))) - `(elfeed-search-filter-face ((,class :inherit bold :foreground ,magenta-active))) - `(elfeed-search-last-update-face ((,class :inherit bold :foreground ,cyan-active))) - `(elfeed-search-tag-face ((,class :foreground ,magenta-alt-faint))) - `(elfeed-search-title-face ((,class :foreground ,fg-dim))) - `(elfeed-search-unread-count-face ((,class :inherit bold :foreground ,fg-active))) - `(elfeed-search-unread-title-face ((,class :inherit bold :foreground ,fg-main))) + `(elfeed-log-date-face ((,c :inherit elfeed-search-date-face))) + `(elfeed-log-debug-level-face ((,c :inherit elfeed-search-filter-face))) + `(elfeed-log-error-level-face ((,c :inherit error))) + `(elfeed-log-info-level-face ((,c :inherit success))) + `(elfeed-log-warn-level-face ((,c :inherit warning))) + `(elfeed-search-date-face ((,c :foreground ,date-common))) + `(elfeed-search-feed-face ((,c :foreground ,accent-1))) + `(elfeed-search-filter-face ((,c :inherit bold))) + `(elfeed-search-last-update-face ((,c :inherit bold :foreground ,date-common))) + `(elfeed-search-tag-face ((,c :foreground ,accent-0))) + `(elfeed-search-title-face ((,c :foreground ,fg-dim))) + `(elfeed-search-unread-count-face (( ))) + `(elfeed-search-unread-title-face ((,c :inherit bold :foreground ,fg-main))) ;;;;; elfeed-score - `(elfeed-score-date-face ((,class :foreground ,blue))) - `(elfeed-score-debug-level-face ((,class :foreground ,magenta-alt-other))) - `(elfeed-score-error-level-face ((,class :foreground ,red))) - `(elfeed-score-info-level-face ((,class :foreground ,cyan))) - `(elfeed-score-warn-level-face ((,class :foreground ,yellow))) + `(elfeed-score-date-face ((,c :foreground ,date-common))) + `(elfeed-score-debug-level-face ((,c :inherit bold))) + `(elfeed-score-error-level-face ((,c :inherit error))) + `(elfeed-score-info-level-face ((,c :inherit success))) + `(elfeed-score-warn-level-face ((,c :inherit warning))) ;;;;; elpher - `(elpher-gemini-heading1 ((,class :inherit modus-themes-heading-1))) - `(elpher-gemini-heading2 ((,class :inherit modus-themes-heading-2))) - `(elpher-gemini-heading3 ((,class :inherit modus-themes-heading-3))) + `(elpher-gemini-heading1 ((,c :inherit modus-themes-heading-1))) + `(elpher-gemini-heading2 ((,c :inherit modus-themes-heading-2))) + `(elpher-gemini-heading3 ((,c :inherit modus-themes-heading-3))) ;;;;; embark - `(embark-keybinding ((,class :inherit modus-themes-key-binding))) - `(embark-collect-marked ((,class :inherit modus-themes-mark-sel))) + `(embark-keybinding ((,c :inherit modus-themes-key-binding))) + `(embark-collect-marked ((,c :inherit modus-themes-mark-sel))) ;;;;; ement (ement.el) - `(ement-room-fully-read-marker ((,class :background ,cyan-subtle-bg))) - `(ement-room-membership ((,class :inherit shadow))) - `(ement-room-mention ((,class :background ,bg-hl-alt-intense))) - `(ement-room-name ((,class :inherit bold))) - `(ement-room-reactions ((,class :inherit shadow))) - `(ement-room-read-receipt-marker ((,class :background ,yellow-subtle-bg))) - `(ement-room-self ((,class :inherit bold :foreground ,magenta))) - `(ement-room-self-message ((,class :foreground ,magenta-faint))) - `(ement-room-timestamp ((,class :inherit shadow))) - `(ement-room-timestamp-header ((,class :inherit bold :foreground ,cyan))) - `(ement-room-user ((,class :inherit bold :foreground ,blue))) + `(ement-room-fully-read-marker ((,c :inherit success))) + `(ement-room-membership ((,c :inherit shadow))) + `(ement-room-mention ((,c :inherit highlight))) + `(ement-room-name ((,c :inherit bold))) + `(ement-room-reactions ((,c :inherit shadow))) + `(ement-room-read-receipt-marker ((,c :inherit match))) + `(ement-room-self ((,c :inherit bold :foreground ,accent-1))) + `(ement-room-self-message ((,c :foreground ,fg-alt))) + `(ement-room-timestamp ((,c :inherit shadow))) + `(ement-room-timestamp-header ((,c :inherit bold :foreground ,date-common))) + `(ement-room-user ((,c :inherit bold :foreground ,accent-0))) ;;;;; emms - `(emms-browser-album-face ((,class :foreground ,magenta-alt-other))) - `(emms-browser-artist-face ((,class :foreground ,cyan))) - `(emms-browser-composer-face ((,class :foreground ,magenta-alt))) - `(emms-browser-performer-face ((,class :inherit emms-browser-artist-face))) - `(emms-browser-track-face ((,class :inherit emms-playlist-track-face))) - `(emms-browser-year/genre-face ((,class :foreground ,cyan-alt-other))) - `(emms-playlist-track-face ((,class :foreground ,blue-alt))) - `(emms-playlist-selected-face ((,class :inherit bold :foreground ,blue-alt-other))) - `(emms-metaplaylist-mode-current-face ((,class :inherit emms-playlist-selected-face))) - `(emms-metaplaylist-mode-face ((,class :foreground ,cyan))) + `(emms-browser-album-face ((,c :foreground ,keyword))) + `(emms-browser-artist-face ((,c :foreground ,variable))) + `(emms-browser-composer-face ((,c :foreground ,builtin))) + `(emms-browser-performer-face ((,c :inherit emms-browser-artist-face))) + `(emms-browser-track-face ((,c :inherit emms-playlist-track-face))) + `(emms-browser-year/genre-face ((,c :foreground ,type))) + `(emms-playlist-track-face ((,c :foreground ,string))) + `(emms-playlist-selected-face ((,c :inherit bold :foreground ,constant))) + `(emms-metaplaylist-mode-current-face ((,c :inherit emms-playlist-selected-face))) + `(emms-metaplaylist-mode-face ((,c :foreground ,variable))) ;;;;; enh-ruby-mode (enhanced-ruby-mode) - `(enh-ruby-heredoc-delimiter-face ((,class :inherit font-lock-constant-face))) - `(enh-ruby-op-face ((,class :foreground ,fg-main))) - `(enh-ruby-regexp-delimiter-face ((,class :inherit font-lock-regexp-grouping-construct))) - `(enh-ruby-regexp-face ((,class :inherit font-lock-string-face))) - `(enh-ruby-string-delimiter-face ((,class :inherit font-lock-string-face))) - `(erm-syn-errline ((,class :inherit modus-themes-lang-error))) - `(erm-syn-warnline ((,class :inherit modus-themes-lang-warning))) + `(enh-ruby-heredoc-delimiter-face ((,c :inherit font-lock-constant-face))) + `(enh-ruby-op-face ((,c :foreground ,fg-main))) + `(enh-ruby-regexp-delimiter-face ((,c :inherit font-lock-regexp-grouping-construct))) + `(enh-ruby-regexp-face ((,c :inherit font-lock-string-face))) + `(enh-ruby-string-delimiter-face ((,c :inherit font-lock-string-face))) + `(erm-syn-errline ((,c :inherit modus-themes-lang-error))) + `(erm-syn-warnline ((,c :inherit modus-themes-lang-warning))) ;;;;; epa - `(epa-field-body ((,class :foreground ,fg-main))) - `(epa-field-name ((,class :inherit bold :foreground ,fg-dim))) - `(epa-mark ((,class :inherit bold :foreground ,magenta))) - `(epa-string ((,class :foreground ,blue-alt))) - `(epa-validity-disabled ((,class :foreground ,red))) - `(epa-validity-high ((,class :inherit bold :foreground ,cyan))) - `(epa-validity-low ((,class :inherit shadow))) - `(epa-validity-medium ((,class :foreground ,green-alt))) -;;;;; equake - `(equake-buffer-face ((,class :background ,bg-main :foreground ,fg-main))) - `(equake-shell-type-eshell ((,class :background ,bg-inactive :foreground ,blue-active))) - `(equake-shell-type-rash ((,class :background ,bg-inactive :foreground ,red-active))) - `(equake-shell-type-shell ((,class :background ,bg-inactive :foreground ,cyan-active))) - `(equake-shell-type-term ((,class :background ,bg-inactive :foreground ,yellow-active))) - `(equake-shell-type-vterm ((,class :background ,bg-inactive :foreground ,magenta-active))) - `(equake-tab-active ((,class :background ,fg-alt :foreground ,bg-alt))) - `(equake-tab-inactive ((,class :foreground ,fg-inactive))) + `(epa-field-body (( ))) + `(epa-field-name ((,c :inherit bold :foreground ,fg-dim))) + `(epa-mark ((,c :inherit bold))) + `(epa-string ((,c :foreground ,string))) + `(epa-validity-disabled ((,c :foreground ,err))) + `(epa-validity-high ((,c :inherit success))) + `(epa-validity-low ((,c :inherit shadow))) + `(epa-validity-medium ((,c :foreground ,info))) ;;;;; erc - `(erc-action-face ((,class :foreground ,cyan-alt-other))) - `(erc-bold-face ((,class :inherit bold))) - `(erc-button ((,class :inherit button))) - `(erc-command-indicator-face ((,class :inherit bold :foreground ,cyan-alt))) - `(erc-current-nick-face ((,class :inherit bold :foreground ,red-alt))) - `(erc-dangerous-host-face ((,class :inherit modus-themes-intense-red))) - `(erc-direct-msg-face ((,class :foreground ,fg-special-warm))) - `(erc-error-face ((,class :inherit bold :foreground ,red))) - `(erc-fool-face ((,class :inherit shadow))) - `(erc-header-line ((,class :background ,bg-header :foreground ,fg-header))) - `(erc-input-face ((,class :foreground ,magenta))) - `(erc-inverse-face ((,class :inherit erc-default-face :inverse-video t))) - `(erc-keyword-face ((,class :inherit bold :foreground ,magenta-alt-other))) - `(erc-my-nick-face ((,class :inherit bold :foreground ,magenta))) - `(erc-my-nick-prefix-face ((,class :inherit erc-my-nick-face))) - `(erc-nick-default-face ((,class :inherit bold :foreground ,blue))) - `(erc-nick-msg-face ((,class :inherit warning))) - `(erc-nick-prefix-face ((,class :inherit erc-nick-default-face))) - `(erc-notice-face ((,class :inherit font-lock-comment-face))) - `(erc-pal-face ((,class :inherit bold :foreground ,magenta-alt))) - `(erc-prompt-face ((,class :inherit modus-themes-prompt))) - `(erc-timestamp-face ((,class :foreground ,cyan))) - `(erc-underline-face ((,class :underline t))) - `(bg:erc-color-face0 ((,class :background "white"))) - `(bg:erc-color-face1 ((,class :background "black"))) - `(bg:erc-color-face10 ((,class :background ,cyan-subtle-bg))) - `(bg:erc-color-face11 ((,class :background ,cyan-intense-bg))) - `(bg:erc-color-face12 ((,class :background ,blue-subtle-bg))) - `(bg:erc-color-face13 ((,class :background ,magenta-subtle-bg))) - `(bg:erc-color-face14 ((,class :background "gray60"))) - `(bg:erc-color-face15 ((,class :background "gray80"))) - `(bg:erc-color-face2 ((,class :background ,blue-intense-bg))) - `(bg:erc-color-face3 ((,class :background ,green-intense-bg))) - `(bg:erc-color-face4 ((,class :background ,red-subtle-bg))) - `(bg:erc-color-face5 ((,class :background ,red-intense-bg))) - `(bg:erc-color-face6 ((,class :background ,magenta-refine-bg))) - `(bg:erc-color-face7 ((,class :background ,yellow-subtle-bg))) - `(bg:erc-color-face8 ((,class :background ,yellow-refine-bg))) - `(bg:erc-color-face9 ((,class :background ,green-subtle-bg))) - `(fg:erc-color-face0 ((,class :foreground "white"))) - `(fg:erc-color-face1 ((,class :foreground "black"))) - `(fg:erc-color-face10 ((,class :foreground ,cyan))) - `(fg:erc-color-face11 ((,class :foreground ,cyan-alt-other))) - `(fg:erc-color-face12 ((,class :foreground ,blue))) - `(fg:erc-color-face13 ((,class :foreground ,magenta-alt))) - `(fg:erc-color-face14 ((,class :foreground "gray60"))) - `(fg:erc-color-face15 ((,class :foreground "gray80"))) - `(fg:erc-color-face2 ((,class :foreground ,blue-alt-other))) - `(fg:erc-color-face3 ((,class :foreground ,green))) - `(fg:erc-color-face4 ((,class :foreground ,red))) - `(fg:erc-color-face5 ((,class :foreground ,red-alt))) - `(fg:erc-color-face6 ((,class :foreground ,magenta-alt-other))) - `(fg:erc-color-face7 ((,class :foreground ,yellow-alt-other))) - `(fg:erc-color-face8 ((,class :foreground ,yellow-alt))) - `(fg:erc-color-face9 ((,class :foreground ,green-alt-other))) -;;;;; eros - `(eros-result-overlay-face ((,class :box (:line-width -1 :color ,blue) - :background ,bg-dim :foreground ,fg-dim))) + `(erc-action-face ((,c :foreground ,accent-2))) + `(erc-bold-face ((,c :inherit bold))) + `(erc-button ((,c :inherit button))) + `(erc-command-indicator-face ((,c :inherit bold :foreground ,accent-3))) + `(erc-current-nick-face ((,c :inherit match))) + `(erc-dangerous-host-face ((,c :inherit modus-themes-intense-red))) + `(erc-direct-msg-face ((,c :inherit shadow))) + `(erc-error-face ((,c :inherit error))) + `(erc-fool-face ((,c :inherit shadow))) + `(erc-input-face ((,c :foreground ,fnname))) + `(erc-inverse-face ((,c :inherit erc-default-face :inverse-video t))) + `(erc-keyword-face ((,c :inherit bold :foreground ,keyword))) + `(erc-my-nick-face ((,c :inherit bold :foreground ,name))) + `(erc-my-nick-prefix-face ((,c :inherit erc-my-nick-face))) + `(erc-nick-default-face ((,c :inherit bold :foreground ,accent-0))) + `(erc-nick-msg-face ((,c :inherit warning))) + `(erc-nick-prefix-face ((,c :inherit erc-nick-default-face))) + `(erc-notice-face ((,c :inherit font-lock-comment-face))) + `(erc-pal-face ((,c :inherit bold :foreground ,accent-1))) + `(erc-prompt-face ((,c :inherit modus-themes-prompt))) + `(erc-timestamp-face ((,c :foreground ,date-common))) + `(erc-underline-face ((,c :underline t))) ;;;;; ert - `(ert-test-result-expected ((,class :inherit modus-themes-intense-green))) - `(ert-test-result-unexpected ((,class :inherit modus-themes-intense-red))) + `(ert-test-result-expected ((,c :inherit modus-themes-intense-cyan))) + `(ert-test-result-unexpected ((,c :inherit modus-themes-intense-red))) ;;;;; eshell - `(eshell-ls-archive ((,class :foreground ,cyan-alt))) - `(eshell-ls-backup ((,class :inherit shadow))) - `(eshell-ls-clutter ((,class :foreground ,red-alt))) - `(eshell-ls-directory ((,class :foreground ,blue-alt))) - `(eshell-ls-executable ((,class :foreground ,magenta-alt))) - `(eshell-ls-missing ((,class :inherit modus-themes-intense-red))) - `(eshell-ls-product ((,class :inherit shadow))) - `(eshell-ls-readonly ((,class :foreground ,yellow-faint))) - `(eshell-ls-special ((,class :foreground ,magenta))) - `(eshell-ls-symlink ((,class :inherit modus-themes-link-symlink))) - `(eshell-ls-unreadable ((,class :background ,bg-inactive :foreground ,fg-inactive))) - `(eshell-prompt ((,class :inherit modus-themes-prompt))) + `(eshell-ls-archive ((,c :foreground ,accent-2))) + `(eshell-ls-backup ((,c :inherit shadow))) + `(eshell-ls-clutter ((,c :inherit shadow))) + `(eshell-ls-directory ((,c :foreground ,accent-0))) + `(eshell-ls-executable ((,c :foreground ,accent-1))) + `(eshell-ls-missing ((,c :inherit error))) + `(eshell-ls-product ((,c :inherit shadow))) + `(eshell-ls-readonly ((,c :foreground ,warning))) + `(eshell-ls-special ((,c :foreground ,accent-3))) + `(eshell-ls-symlink ((,c :inherit link))) + `(eshell-ls-unreadable ((,c :inherit shadow))) + `(eshell-prompt ((,c :inherit modus-themes-prompt))) ;;;;; eshell-fringe-status - `(eshell-fringe-status-failure ((,class :inherit error))) - `(eshell-fringe-status-success ((,class :inherit success))) -;;;;; eshell-git-prompt - `(eshell-git-prompt-add-face ((,class :foreground ,magenta-alt-other))) - `(eshell-git-prompt-branch-face ((,class :foreground ,magenta-alt))) - `(eshell-git-prompt-directory-face ((,class :inherit bold :foreground ,blue))) - `(eshell-git-prompt-exit-fail-face ((,class :inherit error))) - `(eshell-git-prompt-exit-success-face ((,class :inherit success))) - `(eshell-git-prompt-modified-face ((,class :foreground ,yellow))) - `(eshell-git-prompt-powerline-clean-face ((,class :background ,green-refine-bg))) - `(eshell-git-prompt-powerline-dir-face ((,class :background ,blue-refine-bg))) - `(eshell-git-prompt-powerline-not-clean-face ((,class :background ,yellow-fringe-bg))) - `(eshell-git-prompt-robyrussell-branch-face ((,class :foreground ,magenta-alt))) - `(eshell-git-prompt-robyrussell-git-dirty-face ((,class :foreground ,yellow))) - `(eshell-git-prompt-robyrussell-git-face ((,class :foreground ,magenta-alt-other))) -;;;;; eshell-prompt-extras (epe) - `(epe-dir-face ((,class :inherit bold :foreground ,blue))) - `(epe-git-dir-face ((,class :foreground ,red-alt-other))) - `(epe-git-face ((,class :foreground ,magenta-alt))) - `(epe-pipeline-delimiter-face ((,class :inherit shadow))) - `(epe-pipeline-host-face ((,class :foreground ,fg-main))) - `(epe-pipeline-time-face ((,class :foreground ,fg-main))) - `(epe-pipeline-user-face ((,class :foreground ,magenta-alt-other))) - `(epe-remote-face ((,class :inherit (shadow modus-themes-slant)))) - `(epe-status-face ((,class :foreground ,magenta-alt-other))) - `(epe-venv-face ((,class :inherit (shadow modus-themes-slant)))) -;;;;; eshell-syntax-highlighting - `(eshell-syntax-highlighting-directory-face ((,class :inherit eshell-ls-directory))) - `(eshell-syntax-highlighting-invalid-face ((,class :foreground ,red))) - `(eshell-syntax-highlighting-shell-command-face ((,class :foreground ,fg-main))) + `(eshell-fringe-status-failure ((,c :inherit error))) + `(eshell-fringe-status-success ((,c :inherit success))) ;;;;; evil-mode - `(evil-ex-commands ((,class :foreground ,magenta-alt-other))) - `(evil-ex-info ((,class :foreground ,cyan-alt-other))) - `(evil-ex-lazy-highlight ((,class :inherit modus-themes-search-success-lazy))) - `(evil-ex-search ((,class :inherit modus-themes-search-success))) - `(evil-ex-substitute-matches ((,class :inherit modus-themes-refine-yellow :underline t))) - `(evil-ex-substitute-replacement ((,class :inherit modus-themes-search-success))) -;;;;; evil-goggles - `(evil-goggles-change-face ((,class :inherit modus-themes-refine-yellow))) - `(evil-goggles-commentary-face ((,class :inherit (modus-themes-subtle-neutral modus-themes-slant)))) - `(evil-goggles-default-face ((,class :inherit modus-themes-subtle-neutral))) - `(evil-goggles-delete-face ((,class :inherit modus-themes-refine-red))) - `(evil-goggles-fill-and-move-face ((,class :inherit evil-goggles-default-face))) - `(evil-goggles-indent-face ((,class :inherit evil-goggles-default-face))) - `(evil-goggles-join-face ((,class :inherit modus-themes-subtle-green))) - `(evil-goggles-nerd-commenter-face ((,class :inherit evil-goggles-commentary-face))) - `(evil-goggles-paste-face ((,class :inherit modus-themes-subtle-cyan))) - `(evil-goggles-record-macro-face ((,class :inherit modus-themes-special-cold))) - `(evil-goggles-replace-with-register-face ((,class :inherit modus-themes-refine-magenta))) - `(evil-goggles-set-marker-face ((,class :inherit modus-themes-intense-magenta))) - `(evil-goggles-shift-face ((,class :inherit evil-goggles-default-face))) - `(evil-goggles-surround-face ((,class :inherit evil-goggles-default-face))) - `(evil-goggles-yank-face ((,class :inherit modus-themes-subtle-blue))) -;;;;; evil-snipe - `(evil-snipe-first-match-face ((,class :inherit (bold modus-themes-intense-blue)))) - `(evil-snipe-matches-face ((,class :inherit modus-themes-refine-magenta))) -;;;;; evil-visual-mark-mode - `(evil-visual-mark-face ((,class :inherit modus-themes-intense-magenta))) + `(evil-ex-commands ((,c :inherit font-lock-keyword-face))) + `(evil-ex-info ((,c :inherit font-lock-type-face))) + `(evil-ex-lazy-highlight ((,c :inherit modus-themes-search-lazy))) + `(evil-ex-search ((,c :inherit modus-themes-search-current))) + `(evil-ex-substitute-matches ((,c :inherit modus-themes-intense-yellow :underline t))) + `(evil-ex-substitute-replacement ((,c :inherit modus-themes-search-current))) ;;;;; eww - `(eww-invalid-certificate ((,class :foreground ,red-faint))) - `(eww-valid-certificate ((,class :foreground ,blue-faint))) - `(eww-form-checkbox ((,class :inherit eww-form-text))) - `(eww-form-file ((,class :inherit eww-form-submit))) - `(eww-form-select ((,class :inherit eww-form-submit))) - `(eww-form-submit ((,class :inherit modus-themes-box-button))) - `(eww-form-text ((,class :inherit widget-field))) - `(eww-form-textarea ((,class :inherit eww-form-text))) + `(eww-invalid-certificate ((,c :foreground ,err))) + `(eww-valid-certificate ((,c :foreground ,info))) + `(eww-form-checkbox ((,c :inherit eww-form-text))) + `(eww-form-file ((,c :inherit eww-form-submit))) + `(eww-form-select ((,c :inherit eww-form-submit))) + `(eww-form-submit ((,c :inherit modus-themes-button))) + `(eww-form-text ((,c :inherit widget-field))) + `(eww-form-textarea ((,c :inherit eww-form-text))) ;;;;; eyebrowse - `(eyebrowse-mode-line-active ((,class :inherit bold :foreground ,blue-active))) -;;;;; fancy-dabbrev - `(fancy-dabbrev-menu-face ((,class :background ,bg-alt :foreground ,fg-alt))) - `(fancy-dabbrev-preview-face ((,class :inherit shadow :underline t))) - `(fancy-dabbrev-selection-face ((,class :inherit (modus-themes-intense-cyan bold)))) + `(eyebrowse-mode-line-active ((,c :inherit mode-line-emphasis))) ;;;;; flycheck - `(flycheck-error ((,class :inherit modus-themes-lang-error))) - `(flycheck-error-list-checker-name ((,class :foreground ,magenta-active))) - `(flycheck-error-list-column-number ((,class :foreground ,fg-special-cold))) - `(flycheck-error-list-error ((,class :inherit modus-themes-bold :foreground ,red))) - `(flycheck-error-list-filename ((,class :foreground ,blue))) - `(flycheck-error-list-highlight ((,class :inherit modus-themes-hl-line))) - `(flycheck-error-list-id ((,class :foreground ,magenta-alt-other))) - `(flycheck-error-list-id-with-explainer ((,class :inherit flycheck-error-list-id :box t))) - `(flycheck-error-list-info ((,class :foreground ,cyan))) - `(flycheck-error-list-line-number ((,class :foreground ,fg-special-warm))) - `(flycheck-error-list-warning ((,class :foreground ,yellow))) - `(flycheck-fringe-error ((,class :inherit modus-themes-fringe-red))) - `(flycheck-fringe-info ((,class :inherit modus-themes-fringe-cyan))) - `(flycheck-fringe-warning ((,class :inherit modus-themes-fringe-yellow))) - `(flycheck-info ((,class :inherit modus-themes-lang-note))) - `(flycheck-verify-select-checker ((,class :box (:line-width 1 :color nil :style released-button)))) - `(flycheck-warning ((,class :inherit modus-themes-lang-warning))) + `(flycheck-error ((,c :inherit modus-themes-lang-error))) + `(flycheck-fringe-error ((,c :inherit modus-themes-intense-red))) + `(flycheck-fringe-info ((,c :inherit modus-themes-intense-cyan))) + `(flycheck-fringe-warning ((,c :inherit modus-themes-intense-yellow))) + `(flycheck-info ((,c :inherit modus-themes-lang-note))) + `(flycheck-warning ((,c :inherit modus-themes-lang-warning))) ;;;;; flycheck-color-mode-line - `(flycheck-color-mode-line-error-face ((,class :inherit flycheck-fringe-error))) - `(flycheck-color-mode-line-info-face ((,class :inherit flycheck-fringe-info))) - `(flycheck-color-mode-line-running-face ((,class :inherit italic :foreground ,fg-inactive))) - `(flycheck-color-mode-line-info-face ((,class :inherit flycheck-fringe-warning))) + `(flycheck-color-mode-line-error-face ((,c :inherit flycheck-fringe-error))) + `(flycheck-color-mode-line-info-face ((,c :inherit flycheck-fringe-info))) + `(flycheck-color-mode-line-running-face ((,c :inherit italic))) + `(flycheck-color-mode-line-info-face ((,c :inherit flycheck-fringe-warning))) ;;;;; flycheck-indicator - `(flycheck-indicator-disabled ((,class :inherit modus-themes-slant :foreground ,fg-inactive))) - `(flycheck-indicator-error ((,class :inherit modus-themes-bold :foreground ,red-active))) - `(flycheck-indicator-info ((,class :inherit modus-themes-bold :foreground ,blue-active))) - `(flycheck-indicator-running ((,class :inherit modus-themes-bold :foreground ,magenta-active))) - `(flycheck-indicator-success ((,class :inherit (modus-themes-bold modus-themes-grue-active)))) - `(flycheck-indicator-warning ((,class :inherit modus-themes-bold :foreground ,yellow-active))) -;;;;; flycheck-posframe - `(flycheck-posframe-background-face ((,class :background ,bg-alt))) - `(flycheck-posframe-border-face ((,class :inherit shadow))) - `(flycheck-posframe-error-face ((,class :inherit bold :foreground ,red))) - `(flycheck-posframe-face ((,class :inherit modus-themes-slant :foreground ,fg-main))) - `(flycheck-posframe-info-face ((,class :inherit bold :foreground ,cyan))) - `(flycheck-posframe-warning-face ((,class :inherit bold :foreground ,yellow))) + `(flycheck-indicator-disabled ((,c :inherit modus-themes-slant :foreground ,fg-dim))) + `(flycheck-indicator-error ((,c :inherit error))) + `(flycheck-indicator-info ((,c :inherit bold))) + `(flycheck-indicator-running ((,c :inherit modus-themes-slant))) + `(flycheck-indicator-success ((,c :inherit success))) + `(flycheck-indicator-warning ((,c :inherit warning))) ;;;;; flymake - `(flymake-error ((,class :inherit modus-themes-lang-error))) - `(flymake-note ((,class :inherit modus-themes-lang-note))) - `(flymake-warning ((,class :inherit modus-themes-lang-warning))) + `(flymake-error ((,c :inherit modus-themes-lang-error))) + `(flymake-note ((,c :inherit modus-themes-lang-note))) + `(flymake-warning ((,c :inherit modus-themes-lang-warning))) ;;;;; flyspell - `(flyspell-duplicate ((,class :inherit modus-themes-lang-warning))) - `(flyspell-incorrect ((,class :inherit modus-themes-lang-error))) + `(flyspell-duplicate ((,c :inherit modus-themes-lang-warning))) + `(flyspell-incorrect ((,c :inherit modus-themes-lang-error))) ;;;;; flx - `(flx-highlight-face ((,class :inherit modus-themes-completion-match-0))) -;;;;; freeze-it - `(freeze-it-show ((,class :background ,bg-dim :foreground ,fg-special-warm))) + `(flx-highlight-face ((,c :inherit modus-themes-completion-match-0))) ;;;;; focus - `(focus-unfocused ((,class :foreground ,fg-unfocused))) + `(focus-unfocused ((,c :foreground "gray50"))) ;;;;; fold-this - `(fold-this-overlay ((,class :inherit modus-themes-special-mild))) + `(fold-this-overlay ((,c :background ,bg-inactive))) ;;;;; font-lock - `(font-lock-builtin-face ((,class :inherit modus-themes-bold - ,@(modus-themes--syntax-extra - magenta-alt magenta-alt-faint - magenta magenta-faint)))) - `(font-lock-comment-delimiter-face ((,class :inherit font-lock-comment-face))) - `(font-lock-comment-face ((,class :inherit modus-themes-slant - ,@(modus-themes--syntax-comment - fg-alt fg-comment-yellow yellow-alt-other-faint)))) - `(font-lock-constant-face ((,class ,@(modus-themes--syntax-extra - blue-alt-other blue-alt-other-faint - magenta-alt-other magenta-alt-other-faint)))) - `(font-lock-doc-face ((,class :inherit modus-themes-slant - ,@(modus-themes--syntax-string - fg-docstring fg-special-cold - fg-special-mild fg-special-calm - fg-special-mild magenta-nuanced-fg)))) - `(font-lock-function-name-face ((,class ,@(modus-themes--syntax-extra - magenta magenta-faint - magenta-alt magenta-alt-faint)))) - `(font-lock-keyword-face ((,class :inherit modus-themes-bold - ,@(modus-themes--syntax-extra - magenta-alt-other magenta-alt-other-faint - cyan cyan-faint)))) - `(font-lock-negation-char-face ((,class :inherit modus-themes-bold - ,@(modus-themes--syntax-foreground - yellow yellow-faint)))) - `(font-lock-preprocessor-face ((,class ,@(modus-themes--syntax-extra - red-alt-other red-alt-other-faint - cyan-alt-other cyan-alt-faint)))) - `(font-lock-regexp-grouping-backslash ((,class :inherit modus-themes-bold - ,@(modus-themes--syntax-string - fg-escape-char-backslash yellow-alt-faint - yellow-alt magenta-alt - red-faint green-alt-other-faint)))) - `(font-lock-regexp-grouping-construct ((,class :inherit modus-themes-bold - ,@(modus-themes--syntax-string - fg-escape-char-construct red-alt-other-faint - red-alt-other blue-alt-other - blue-faint blue-alt-other-faint)))) - `(font-lock-string-face ((,class ,@(modus-themes--syntax-string - blue-alt blue-alt-faint - green-alt-other red-alt-other - green-alt-faint red-alt-faint)))) - `(font-lock-type-face ((,class :inherit modus-themes-bold - ,@(modus-themes--syntax-extra - cyan-alt-other cyan-alt-faint - magenta-alt-other magenta-alt-other-faint)))) - `(font-lock-variable-name-face ((,class ,@(modus-themes--syntax-extra - cyan cyan-faint - blue-alt blue-alt-faint)))) - `(font-lock-warning-face ((,class :inherit modus-themes-bold - ,@(modus-themes--syntax-comment - yellow red yellow-alt-faint red-faint)))) -;;;;; forge - `(forge-post-author ((,class :inherit bold :foreground ,fg-main))) - `(forge-post-date ((,class :foreground ,fg-special-cold))) - `(forge-topic-closed ((,class :inherit shadow))) - `(forge-topic-merged ((,class :inherit shadow))) - `(forge-topic-open ((,class :foreground ,fg-special-mild))) - `(forge-topic-unmerged ((,class :inherit modus-themes-slant :foreground ,magenta))) - `(forge-topic-unread ((,class :inherit bold :foreground ,fg-main))) -;;;;; fountain-mode - `(fountain-character ((,class :foreground ,blue-alt-other))) - `(fountain-comment ((,class :inherit font-lock-comment-face))) - `(fountain-dialog ((,class :foreground ,blue-alt))) - `(fountain-metadata-key ((,class :foreground ,green-alt-other))) - `(fountain-metadata-value ((,class :foreground ,blue))) - `(fountain-non-printing ((,class :inherit shadow))) - `(fountain-note ((,class :inherit modus-themes-slant :foreground ,yellow))) - `(fountain-page-break ((,class :inherit bold :foreground ,red-alt))) - `(fountain-page-number ((,class :inherit bold :foreground ,red-alt-other))) - `(fountain-paren ((,class :foreground ,cyan))) - `(fountain-scene-heading ((,class :inherit bold :foreground ,blue-nuanced-fg))) - `(fountain-section-heading ((,class :inherit modus-themes-heading-1))) - `(fountain-section-heading-1 ((,class :inherit modus-themes-heading-1))) - `(fountain-section-heading-2 ((,class :inherit modus-themes-heading-2))) - `(fountain-section-heading-3 ((,class :inherit modus-themes-heading-3))) - `(fountain-section-heading-4 ((,class :inherit modus-themes-heading-4))) - `(fountain-section-heading-5 ((,class :inherit modus-themes-heading-5))) - `(fountain-synopsis ((,class :foreground ,cyan-alt))) - `(fountain-trans ((,class :foreground ,yellow-alt-other))) + `(font-lock-builtin-face ((,c :inherit modus-themes-bold :foreground ,builtin))) + `(font-lock-comment-delimiter-face ((,c :inherit font-lock-comment-face))) + `(font-lock-comment-face ((,c :inherit modus-themes-slant :foreground ,comment))) + `(font-lock-constant-face ((,c :foreground ,constant))) + `(font-lock-doc-face ((,c :inherit modus-themes-slant :foreground ,docstring))) + `(font-lock-doc-markup-face ((,c :inherit modus-themes-slant :foreground ,docmarkup))) + `(font-lock-function-name-face ((,c :foreground ,fnname))) + `(font-lock-keyword-face ((,c :inherit modus-themes-bold :foreground ,keyword))) + `(font-lock-negation-char-face ((,c :inherit error))) + `(font-lock-preprocessor-face ((,c :foreground ,preprocessor))) + `(font-lock-regexp-grouping-backslash ((,c :inherit modus-themes-bold :foreground ,rx-backslash))) + `(font-lock-regexp-grouping-construct ((,c :inherit modus-themes-bold :foreground ,rx-construct))) + `(font-lock-string-face ((,c :foreground ,string))) + `(font-lock-type-face ((,c :inherit modus-themes-bold :foreground ,type))) + `(font-lock-variable-name-face ((,c :foreground ,variable))) + `(font-lock-warning-face ((,c :inherit modus-themes-bold :foreground ,warning))) ;;;;; geiser - `(geiser-font-lock-autodoc-current-arg ((,class :inherit bold - :background ,yellow-nuanced-bg - :foreground ,yellow-alt-other))) - `(geiser-font-lock-autodoc-identifier ((,class :foreground ,cyan))) - `(geiser-font-lock-doc-button ((,class :inherit button :foreground ,fg-docstring))) - `(geiser-font-lock-doc-link ((,class :inherit button))) - `(geiser-font-lock-error-link ((,class :inherit button :foreground ,red))) - `(geiser-font-lock-image-button ((,class :inherit button :foreground ,green-alt))) - `(geiser-font-lock-repl-input ((,class :inherit bold))) - `(geiser-font-lock-repl-output ((,class :inherit font-lock-keyword-face))) - `(geiser-font-lock-repl-prompt ((,class :inherit modus-themes-prompt))) - `(geiser-font-lock-xref-header ((,class :inherit bold))) - `(geiser-font-lock-xref-link ((,class :inherit button))) + `(geiser-font-lock-autodoc-current-arg ((,c :inherit modus-themes-mark-alt))) + `(geiser-font-lock-autodoc-identifier ((,c :foreground ,docstring))) + `(geiser-font-lock-doc-button ((,c :inherit button))) + `(geiser-font-lock-doc-link ((,c :inherit button))) + `(geiser-font-lock-error-link ((,c :inherit button :foreground ,err))) + `(geiser-font-lock-image-button ((,c :inherit button :foreground ,info))) + `(geiser-font-lock-repl-input ((,c :inherit bold))) + `(geiser-font-lock-repl-output ((,c :inherit font-lock-keyword-face))) + `(geiser-font-lock-repl-prompt ((,c :inherit modus-themes-prompt))) + `(geiser-font-lock-xref-header ((,c :inherit bold))) + `(geiser-font-lock-xref-link ((,c :inherit button))) ;;;;; git-commit - `(git-commit-comment-action ((,class :inherit font-lock-comment-face))) - `(git-commit-comment-branch-local ((,class :inherit font-lock-comment-face :foreground ,blue-alt))) - `(git-commit-comment-branch-remote ((,class :inherit font-lock-comment-face :foreground ,magenta-alt))) - `(git-commit-comment-detached ((,class :inherit font-lock-comment-face :foreground ,cyan-alt))) - `(git-commit-comment-file ((,class :inherit font-lock-comment-face :foreground ,cyan))) - `(git-commit-comment-heading ((,class :inherit (bold font-lock-comment-face)))) - `(git-commit-keyword ((,class :foreground ,magenta))) - `(git-commit-known-pseudo-header ((,class :foreground ,cyan-alt-other))) - `(git-commit-nonempty-second-line ((,class :inherit error))) - `(git-commit-overlong-summary ((,class :inherit warning))) - `(git-commit-pseudo-header ((,class :foreground ,blue))) - `(git-commit-summary ((,class :inherit bold :foreground ,blue))) + `(git-commit-comment-action ((,c :inherit font-lock-comment-face))) + `(git-commit-comment-branch-local ((,c :inherit font-lock-comment-face :foreground ,accent-0))) + `(git-commit-comment-branch-remote ((,c :inherit font-lock-comment-face :foreground ,accent-1))) + `(git-commit-comment-heading ((,c :inherit (bold font-lock-comment-face)))) + `(git-commit-comment-file ((,c :inherit font-lock-comment-face :foreground ,name))) + `(git-commit-keyword ((,c :foreground ,keyword))) + `(git-commit-nonempty-second-line ((,c :inherit error))) + `(git-commit-overlong-summary ((,c :inherit warning))) + `(git-commit-summary ((,c :inherit bold :foreground ,blue))) ;;;;; git-gutter - `(git-gutter:added ((,class :inherit modus-themes-grue-background-active))) - `(git-gutter:deleted ((,class :inherit modus-themes-fringe-red))) - `(git-gutter:modified ((,class :inherit modus-themes-fringe-yellow))) - `(git-gutter:separator ((,class :inherit modus-themes-fringe-cyan))) - `(git-gutter:unchanged ((,class :inherit modus-themes-fringe-magenta))) + `(git-gutter:added ((,c :background ,bg-added-intense))) + `(git-gutter:deleted ((,c :background ,bg-removed-intense))) + `(git-gutter:modified ((,c :background ,bg-changed-intense))) + `(git-gutter:separator ((,c :inherit modus-themes-intense-cyan))) + `(git-gutter:unchanged ((,c :inherit modus-themes-intense-magenta))) ;;;;; git-gutter-fr - `(git-gutter-fr:added ((,class :inherit modus-themes-grue-background-active))) - `(git-gutter-fr:deleted ((,class :inherit modus-themes-fringe-red))) - `(git-gutter-fr:modified ((,class :inherit modus-themes-fringe-yellow))) + `(git-gutter-fr:added ((,c :background ,bg-added-intense))) + `(git-gutter-fr:deleted ((,c :background ,bg-removed-intense))) + `(git-gutter-fr:modified ((,c :background ,bg-changed-intense))) ;;;;; git-rebase - `(git-rebase-comment-hash ((,class :inherit font-lock-comment-face :foreground ,cyan))) - `(git-rebase-comment-heading ((,class :inherit (bold font-lock-comment-face)))) - `(git-rebase-description ((,class :foreground ,fg-main))) - `(git-rebase-hash ((,class :foreground ,cyan-alt-other))) + `(git-rebase-comment-hash ((,c :inherit (bold font-lock-comment-face) :foreground ,identifier))) + `(git-rebase-comment-heading ((,c :inherit (bold font-lock-comment-face)))) + `(git-rebase-description ((,c :foreground ,fg-main))) + `(git-rebase-hash ((,c :foreground ,identifier))) ;;;;; git-timemachine - `(git-timemachine-commit ((,class :inherit bold :foreground ,yellow-active))) - `(git-timemachine-minibuffer-author-face ((,class :foreground ,fg-special-warm))) - `(git-timemachine-minibuffer-detail-face ((,class :foreground ,red-alt))) + `(git-timemachine-commit ((,c :inherit warning))) + `(git-timemachine-minibuffer-author-face ((,c :foreground ,name))) + `(git-timemachine-minibuffer-detail-face ((,c :foreground ,fg-main))) ;;;;; gnus - `(gnus-button ((,class :inherit button))) - `(gnus-cite-1 ((,class :inherit message-cited-text-1))) - `(gnus-cite-2 ((,class :inherit message-cited-text-2))) - `(gnus-cite-3 ((,class :inherit message-cited-text-3))) - `(gnus-cite-4 ((,class :inherit message-cited-text-4))) - `(gnus-cite-5 ((,class :inherit gnus-cite-1))) - `(gnus-cite-6 ((,class :inherit gnus-cite-2))) - `(gnus-cite-7 ((,class :inherit gnus-cite-3))) - `(gnus-cite-8 ((,class :inherit gnus-cite-4))) - `(gnus-cite-9 ((,class :inherit gnus-cite-1))) - `(gnus-cite-10 ((,class :inherit gnus-cite-2))) - `(gnus-cite-11 ((,class :inherit gnus-cite-3))) - `(gnus-cite-attribution ((,class :inherit italic :foreground ,fg-main))) - `(gnus-emphasis-bold ((,class :inherit bold))) - `(gnus-emphasis-bold-italic ((,class :inherit bold-italic))) - `(gnus-emphasis-highlight-words ((,class :inherit modus-themes-refine-yellow))) - `(gnus-emphasis-italic ((,class :inherit italic))) - `(gnus-emphasis-underline-bold ((,class :inherit gnus-emphasis-bold :underline t))) - `(gnus-emphasis-underline-bold-italic ((,class :inherit gnus-emphasis-bold-italic :underline t))) - `(gnus-emphasis-underline-italic ((,class :inherit gnus-emphasis-italic :underline t))) - `(gnus-group-mail-1 ((,class :inherit bold :foreground ,magenta-alt))) - `(gnus-group-mail-1-empty ((,class :foreground ,magenta-alt))) - `(gnus-group-mail-2 ((,class :inherit bold :foreground ,magenta))) - `(gnus-group-mail-2-empty ((,class :foreground ,magenta))) - `(gnus-group-mail-3 ((,class :inherit bold :foreground ,magenta-alt-other))) - `(gnus-group-mail-3-empty ((,class :foreground ,magenta-alt-other))) - `(gnus-group-mail-low ((,class :inherit bold :foreground ,magenta-nuanced-fg))) - `(gnus-group-mail-low-empty ((,class :foreground ,magenta-nuanced-fg))) - `(gnus-group-news-1 ((,class :inherit bold :foreground ,green))) - `(gnus-group-news-1-empty ((,class :foreground ,green))) - `(gnus-group-news-2 ((,class :inherit bold :foreground ,cyan))) - `(gnus-group-news-2-empty ((,class :foreground ,cyan))) - `(gnus-group-news-3 ((,class :inherit bold :foreground ,yellow-nuanced-fg))) - `(gnus-group-news-3-empty ((,class :foreground ,yellow-nuanced-fg))) - `(gnus-group-news-4 ((,class :inherit bold :foreground ,cyan-nuanced-fg))) - `(gnus-group-news-4-empty ((,class :foreground ,cyan-nuanced-fg))) - `(gnus-group-news-5 ((,class :inherit bold :foreground ,red-nuanced-fg))) - `(gnus-group-news-5-empty ((,class :foreground ,red-nuanced-fg))) - `(gnus-group-news-6 ((,class :inherit bold :foreground ,fg-unfocused))) - `(gnus-group-news-6-empty ((,class :foreground ,fg-unfocused))) - `(gnus-group-news-low ((,class :inherit bold :foreground ,green-nuanced-fg))) - `(gnus-group-news-low-empty ((,class :foreground ,green-nuanced-fg))) - `(gnus-header-content ((,class :inherit message-header-other))) - `(gnus-header-from ((,class :inherit message-header-to :underline nil))) - `(gnus-header-name ((,class :inherit message-header-name))) - `(gnus-header-newsgroups ((,class :inherit message-header-newsgroups))) - `(gnus-header-subject ((,class :inherit message-header-subject))) - `(gnus-server-agent ((,class :inherit bold :foreground ,cyan))) - `(gnus-server-closed ((,class :inherit bold :foreground ,magenta))) - `(gnus-server-cloud ((,class :inherit bold :foreground ,cyan-alt))) - `(gnus-server-cloud-host ((,class :inherit modus-themes-refine-cyan))) - `(gnus-server-denied ((,class :inherit bold :foreground ,red))) - `(gnus-server-offline ((,class :inherit bold :foreground ,yellow))) - `(gnus-server-opened ((,class :inherit bold :foreground ,green))) - `(gnus-signature ((,class :inherit italic :foreground ,fg-special-cold))) - `(gnus-splash ((,class :inherit shadow))) - `(gnus-summary-cancelled ((,class :inherit modus-themes-mark-alt :extend t))) - `(gnus-summary-high-ancient ((,class :inherit bold :foreground ,fg-alt))) - `(gnus-summary-high-read ((,class :inherit bold :foreground ,fg-special-cold))) - `(gnus-summary-high-ticked ((,class :inherit bold :foreground ,red-alt-other))) - `(gnus-summary-high-undownloaded ((,class :inherit bold :foreground ,yellow))) - `(gnus-summary-high-unread ((,class :inherit bold :foreground ,fg-main))) - `(gnus-summary-low-ancient ((,class :inherit italic :foreground ,fg-alt))) - `(gnus-summary-low-read ((,class :inherit italic :foreground ,fg-alt))) - `(gnus-summary-low-ticked ((,class :inherit italic :foreground ,red-refine-fg))) - `(gnus-summary-low-undownloaded ((,class :inherit italic :foreground ,yellow-refine-fg))) - `(gnus-summary-low-unread ((,class :inherit italic :foreground ,fg-special-cold))) - `(gnus-summary-normal-ancient ((,class :foreground ,fg-special-calm))) - `(gnus-summary-normal-read ((,class :inherit shadow))) - `(gnus-summary-normal-ticked ((,class :foreground ,red-alt-other))) - `(gnus-summary-normal-undownloaded ((,class :foreground ,yellow))) - `(gnus-summary-normal-unread ((,class :foreground ,fg-main))) - `(gnus-summary-selected ((,class :inherit highlight :extend t))) + `(gnus-button ((,c :inherit button))) + `(gnus-cite-1 ((,c :inherit message-cited-text-1))) + `(gnus-cite-2 ((,c :inherit message-cited-text-2))) + `(gnus-cite-3 ((,c :inherit message-cited-text-3))) + `(gnus-cite-4 ((,c :inherit message-cited-text-4))) + `(gnus-cite-5 ((,c :inherit message-cited-text-1))) + `(gnus-cite-6 ((,c :inherit message-cited-text-2))) + `(gnus-cite-7 ((,c :inherit message-cited-text-3))) + `(gnus-cite-8 ((,c :inherit message-cited-text-4))) + `(gnus-cite-9 ((,c :inherit message-cited-text-1))) + `(gnus-cite-10 ((,c :inherit message-cited-text-2))) + `(gnus-cite-11 ((,c :inherit message-cited-text-3))) + `(gnus-cite-attribution ((,c :inherit italic))) + `(gnus-emphasis-bold ((,c :inherit bold))) + `(gnus-emphasis-bold-italic ((,c :inherit bold-italic))) + `(gnus-emphasis-highlight-words ((,c :inherit warning))) + `(gnus-emphasis-italic ((,c :inherit italic))) + `(gnus-emphasis-underline-bold ((,c :inherit gnus-emphasis-bold :underline t))) + `(gnus-emphasis-underline-bold-italic ((,c :inherit gnus-emphasis-bold-italic :underline t))) + `(gnus-emphasis-underline-italic ((,c :inherit gnus-emphasis-italic :underline t))) + `(gnus-group-mail-1 ((,c :inherit (bold gnus-group-mail-1-empty)))) + `(gnus-group-mail-1-empty ((,c :foreground ,magenta-warmer))) + `(gnus-group-mail-2 ((,c :inherit (bold gnus-group-mail-2-empty)))) + `(gnus-group-mail-2-empty ((,c :foreground ,magenta))) + `(gnus-group-mail-3 ((,c :inherit (bold gnus-group-mail-3-empty)))) + `(gnus-group-mail-3-empty ((,c :foreground ,magenta-cooler))) + `(gnus-group-mail-low ((,c :inherit (bold gnus-group-mail-low-empty)))) + `(gnus-group-mail-low-empty ((,c :foreground ,fg-dim))) + `(gnus-group-news-1 ((,c :inherit (bold gnus-group-news-1-empty)))) + `(gnus-group-news-1-empty ((,c :foreground ,green))) + `(gnus-group-news-2 ((,c :inherit (bold gnus-group-news-2-empty)))) + `(gnus-group-news-2-empty ((,c :foreground ,cyan))) + `(gnus-group-news-3 ((,c :inherit (bold gnus-group-news-3-empty)))) + `(gnus-group-news-3-empty ((,c :foreground ,yellow-faint))) + `(gnus-group-news-4 ((,c :inherit (bold gnus-group-news-4-empty)))) + `(gnus-group-news-4-empty ((,c :foreground ,magenta-faint))) + `(gnus-group-news-5 ((,c :inherit (bold gnus-group-news-5-empty)))) + `(gnus-group-news-5-empty ((,c :foreground ,fg-alt))) + `(gnus-group-news-6 ((,c :inherit (bold gnus-group-news-6-empty)))) + `(gnus-group-news-6-empty ((,c :foreground ,fg-dim))) + `(gnus-group-news-low ((,c :inherit (bold gnus-group-news-low-empty)))) + `(gnus-group-news-low-empty ((,c :foreground ,fg-dim))) + `(gnus-header-content ((,c :inherit message-header-other))) + `(gnus-header-from ((,c :inherit message-header-to :underline nil))) + `(gnus-header-name ((,c :inherit message-header-name))) + `(gnus-header-newsgroups ((,c :inherit message-header-newsgroups))) + `(gnus-header-subject ((,c :inherit message-header-subject))) + `(gnus-server-agent ((,c :inherit bold))) + `(gnus-server-closed ((,c :inherit italic))) + `(gnus-server-cloud ((,c :inherit bold :foreground ,fg-alt))) + `(gnus-server-cloud-host ((,c :inherit bold :foreground ,fg-alt :underline t))) + `(gnus-server-denied ((,c :inherit error))) + `(gnus-server-offline ((,c :inherit shadow))) + `(gnus-server-opened ((,c :inherit success))) + `(gnus-summary-cancelled ((,c :inherit italic :foreground ,warning))) + `(gnus-summary-high-ancient ((,c :inherit bold :foreground ,fg-alt))) + `(gnus-summary-high-read ((,c :inherit bold :foreground ,fg-dim))) + `(gnus-summary-high-ticked ((,c :inherit bold :foreground ,err))) + `(gnus-summary-high-undownloaded ((,c :inherit bold-italic :foreground ,warning))) + `(gnus-summary-high-unread ((,c :inherit bold))) + `(gnus-summary-low-ancient ((,c :inherit italic))) + `(gnus-summary-low-read ((,c :inherit (shadow italic)))) + `(gnus-summary-low-ticked ((,c :inherit italic :foreground ,err))) + `(gnus-summary-low-undownloaded ((,c :inherit italic :foreground ,warning))) + `(gnus-summary-low-unread ((,c :inherit italic))) + `(gnus-summary-normal-ancient (( ))) + `(gnus-summary-normal-read ((,c :inherit shadow))) + `(gnus-summary-normal-ticked ((,c :foreground ,err))) + `(gnus-summary-normal-undownloaded ((,c :foreground ,warning))) + `(gnus-summary-normal-unread (( ))) + `(gnus-summary-selected ((,c :inherit highlight))) ;;;;; gotest - `(go-test--ok-face ((,class :inherit success))) - `(go-test--error-face ((,class :inherit error))) - `(go-test--warning-face ((,class :inherit warning))) - `(go-test--pointer-face ((,class :foreground ,magenta-alt-other))) - `(go-test--standard-face ((,class :foreground ,fg-special-cold))) + `(go-test--ok-face ((,c :inherit success))) + `(go-test--error-face ((,c :inherit error))) + `(go-test--warning-face ((,c :inherit warning))) + `(go-test--pointer-face ((,c :foreground ,accent-0))) + `(go-test--standard-face (( ))) ;;;;; golden-ratio-scroll-screen - `(golden-ratio-scroll-highlight-line-face ((,class :background ,cyan-subtle-bg :foreground ,fg-main))) -;;;;; helm - `(helm-M-x-key ((,class :inherit modus-themes-key-binding))) - `(helm-action ((,class :underline t))) - `(helm-bookmark-addressbook ((,class :foreground ,green-alt))) - `(helm-bookmark-directory ((,class :inherit bold :foreground ,blue))) - `(helm-bookmark-file ((,class :foreground ,fg-main))) - `(helm-bookmark-file-not-found ((,class :background ,bg-alt :foreground ,fg-alt))) - `(helm-bookmark-gnus ((,class :foreground ,magenta))) - `(helm-bookmark-info ((,class :foreground ,cyan-alt))) - `(helm-bookmark-man ((,class :foreground ,yellow-alt))) - `(helm-bookmark-w3m ((,class :foreground ,blue-alt))) - `(helm-buffer-archive ((,class :inherit bold :foreground ,cyan))) - `(helm-buffer-directory ((,class :inherit bold :foreground ,blue))) - `(helm-buffer-file ((,class :foreground ,fg-main))) - `(helm-buffer-modified ((,class :foreground ,yellow-alt))) - `(helm-buffer-not-saved ((,class :foreground ,red-alt))) - `(helm-buffer-process ((,class :foreground ,magenta))) - `(helm-buffer-saved-out ((,class :inherit bold :background ,bg-alt :foreground ,red))) - `(helm-buffer-size ((,class :inherit shadow))) - `(helm-candidate-number ((,class :foreground ,cyan-active))) - `(helm-candidate-number-suspended ((,class :foreground ,yellow-active))) - `(helm-comint-prompts-buffer-name ((,class :foreground ,green-active))) - `(helm-comint-prompts-promptidx ((,class :foreground ,cyan-active))) - `(helm-delete-async-message ((,class :inherit bold :foreground ,magenta-active))) - `(helm-eob-line ((,class :background ,bg-main :foreground ,fg-main))) - `(helm-eshell-prompts-buffer-name ((,class :foreground ,green-active))) - `(helm-eshell-prompts-promptidx ((,class :foreground ,cyan-active))) - `(helm-etags-file ((,class :foreground ,fg-dim :underline t))) - `(helm-ff-backup-file ((,class :inherit shadow))) - `(helm-ff-denied ((,class :inherit modus-themes-intense-red))) - `(helm-ff-directory ((,class :inherit helm-buffer-directory))) - `(helm-ff-dirs ((,class :inherit bold :foreground ,blue-alt-other))) - `(helm-ff-dotted-directory ((,class :inherit bold :background ,bg-alt :foreground ,fg-alt))) - `(helm-ff-dotted-symlink-directory ((,class :inherit (button helm-ff-dotted-directory)))) - `(helm-ff-executable ((,class :foreground ,magenta-alt))) - `(helm-ff-file ((,class :foreground ,fg-main))) - `(helm-ff-file-extension ((,class :foreground ,fg-special-warm))) - `(helm-ff-invalid-symlink ((,class :inherit modus-themes-link-broken))) - `(helm-ff-pipe ((,class :inherit modus-themes-special-calm))) - `(helm-ff-prefix ((,class :inherit modus-themes-special-warm))) - `(helm-ff-socket ((,class :foreground ,red-alt-other))) - `(helm-ff-suid ((,class :inherit modus-themes-special-warm))) - `(helm-ff-symlink ((,class :inherit modus-themes-link-symlink))) - `(helm-ff-truename ((,class :foreground ,blue-alt-other))) - `(helm-fd-finish ((,class :inherit success))) - `(helm-grep-cmd-line ((,class :foreground ,yellow-alt-other))) - `(helm-grep-file ((,class :inherit bold :foreground ,fg-special-cold))) - `(helm-grep-finish ((,class :inherit bold))) - `(helm-grep-lineno ((,class :foreground ,fg-special-warm))) - `(helm-grep-match ((,class :inherit modus-themes-special-calm))) - `(helm-header ((,class :inherit bold :foreground ,fg-special-cold))) - `(helm-header-line-left-margin ((,class :inherit bold :foreground ,yellow-intense))) - `(helm-history-deleted ((,class :inherit modus-themes-special-warm))) - `(helm-history-remote ((,class :foreground ,red-alt-other))) - `(helm-lisp-completion-info ((,class :inherit modus-themes-bold :foreground ,fg-special-cold))) - `(helm-lisp-show-completion ((,class :inherit modus-themes-special-warm))) - `(helm-locate-finish ((,class :inherit success))) - `(helm-match ((,class :inherit modus-themes-completion-match-0))) - `(helm-match-item ((,class :inherit helm-match))) - `(helm-minibuffer-prompt ((,class :inherit modus-themes-prompt))) - `(helm-moccur-buffer ((,class :inherit button :foreground ,cyan-alt-other))) - `(helm-mode-prefix ((,class :inherit modus-themes-special-calm))) - `(helm-non-file-buffer ((,class :inherit shadow))) - `(helm-prefarg ((,class :foreground ,red-active))) - `(helm-resume-need-update ((,class :inherit modus-themes-special-calm))) - `(helm-selection ((,class :inherit modus-themes-completion-selected))) - `(helm-selection-line ((,class :background ,bg-hl-alt-intense))) - `(helm-separator ((,class :foreground ,fg-special-mild))) - `(helm-time-zone-current ((,class :foreground ,green))) - `(helm-time-zone-home ((,class :foreground ,magenta))) - `(helm-source-header ((,class :inherit modus-themes-pseudo-header :foreground ,fg-special-warm))) - `(helm-top-columns ((,class :inherit helm-header))) - `(helm-ucs-char ((,class :foreground ,yellow-alt-other))) - `(helm-visible-mark ((,class :inherit modus-themes-subtle-cyan))) -;;;;; helm-ls-git - `(helm-ls-git-added-copied-face ((,class :foreground ,green-intense))) - `(helm-ls-git-added-modified-face ((,class :foreground ,yellow-intense))) - `(helm-ls-git-conflict-face ((,class :inherit bold :foreground ,red-intense))) - `(helm-ls-git-deleted-and-staged-face ((,class :foreground ,red-nuanced-fg))) - `(helm-ls-git-deleted-not-staged-face ((,class :foreground ,red))) - `(helm-ls-git-modified-and-staged-face ((,class :foreground ,yellow-nuanced-fg))) - `(helm-ls-git-modified-not-staged-face ((,class :foreground ,yellow))) - `(helm-ls-git-renamed-modified-face ((,class :foreground ,magenta))) - `(helm-ls-git-untracked-face ((,class :foreground ,fg-special-cold))) -;;;;; helm-switch-shell - `(helm-switch-shell-new-shell-face ((,class :inherit modus-themes-completion-match-0))) -;;;;; helm-xref - `(helm-xref-file-name ((,class :inherit modus-themes-bold :foreground ,fg-special-cold))) + `(golden-ratio-scroll-highlight-line-face ((,c :background ,bg-cyan-subtle :foreground ,fg-main))) ;;;;; helpful - `(helpful-heading ((,class :inherit modus-themes-heading-1))) + `(helpful-heading ((,c :inherit modus-themes-heading-1))) ;;;;; highlight region or ad-hoc regexp ;; HACK 2022-06-23: The :inverse-video prevents hl-line-mode from ;; overriding the background. Such an override really defeats the ;; purpose of setting those highlights. ;; - ;; NOTE 2022-10-04: We do not use the ,class here but instead + ;; NOTE 2022-10-04: We do not use the ,c here but instead ;; hardcode color values. We have to do this as the themes lack ;; entries in their palette for such an edge case. Defining those ;; entries is not appropriate. @@ -5714,26 +2349,26 @@ by virtue of calling either of `modus-themes-load-operandi' and :background "white" :foreground "#227f9f" :inverse-video t) (((class color) (min-colors 88) (background dark)) :background "black" :foreground "#66cbdc" :inverse-video t))) - `(hi-black-b ((,class :inverse-video t))) - `(hi-black-hb ((,class :background ,bg-main :foreground ,fg-alt :inverse-video t))) + `(hi-black-b ((,c :inverse-video t))) + `(hi-black-hb ((,c :background ,bg-main :foreground ,fg-dim :inverse-video t))) `(hi-blue ((((class color) (min-colors 88) (background light)) :background "white" :foreground "#3366dd" :inverse-video t) (((class color) (min-colors 88) (background dark)) :background "black" :foreground "#aaccff" :inverse-video t))) - `(hi-blue-b ((,class :inherit (bold hi-blue)))) + `(hi-blue-b ((,c :inherit (bold hi-blue)))) `(hi-green ((((class color) (min-colors 88) (background light)) - :background "white" :foreground "#008a00" :inverse-video t) - (((class color) (min-colors 88) (background dark)) - :background "black" :foreground "#66dd66" :inverse-video t))) - `(hi-green-b ((,class :inherit (bold hi-green)))) + :background "white" :foreground "#008a00" :inverse-video t) + (((class color) (min-colors 88) (background dark)) + :background "black" :foreground "#66dd66" :inverse-video t))) + `(hi-green-b ((,c :inherit (bold hi-green)))) `(hi-pink ((((class color) (min-colors 88) (background light)) - :background "white" :foreground "#bd30aa" :inverse-video t) - (((class color) (min-colors 88) (background dark)) - :background "black" :foreground "#ff88ee" :inverse-video t))) + :background "white" :foreground "#bd30aa" :inverse-video t) + (((class color) (min-colors 88) (background dark)) + :background "black" :foreground "#ff88ee" :inverse-video t))) `(hi-red-b ((((class color) (min-colors 88) (background light)) - :background "white" :foreground "#dd0000" :inverse-video t) - (((class color) (min-colors 88) (background dark)) - :background "black" :foreground "#f06666" :inverse-video t))) + :background "white" :foreground "#dd0000" :inverse-video t) + (((class color) (min-colors 88) (background dark)) + :background "black" :foreground "#f06666" :inverse-video t))) `(hi-salmon ((((class color) (min-colors 88) (background light)) :background "white" :foreground "#bf555a" :inverse-video t) (((class color) (min-colors 88) (background dark)) @@ -5742,1734 +2377,1299 @@ by virtue of calling either of `modus-themes-load-operandi' and :background "white" :foreground "#af6400" :inverse-video t) (((class color) (min-colors 88) (background dark)) :background "black" :foreground "#faea00" :inverse-video t))) - `(highlight ((,class ,@(if modus-themes-intense-mouseovers - (list :background blue-intense-bg :foreground fg-main) - (list :background cyan-subtle-bg :foreground fg-main))))) - `(highlight-changes ((,class :foreground ,red-alt :underline nil))) - `(highlight-changes-delete ((,class :background ,red-nuanced-bg - :foreground ,red :underline t))) - `(hl-line ((,class :inherit modus-themes-hl-line))) -;;;;; highlight-indentation - `(highlight-indentation-face ((,class :inherit modus-themes-hl-line))) - `(highlight-indentation-current-column-face ((,class :background ,bg-active))) + `(highlight ((,c :background ,bg-hover))) + `(highlight-changes ((,c :foreground ,warning :underline nil))) + `(highlight-changes-delete ((,c :foreground ,err :underline t))) + `(hl-line ((,c :background ,bg-hl-line :extend t))) ;;;;; highlight-numbers - `(highlight-numbers-number ((,class :foreground ,blue-alt-other))) + `(highlight-numbers-number ((,c :foreground ,constant))) ;;;;; highlight-thing - `(highlight-thing ((,class :inherit modus-themes-special-calm))) -;;;;; hl-defined - `(hdefd-functions ((,class :foreground ,blue))) - `(hdefd-undefined ((,class :foreground ,red-alt))) - `(hdefd-variables ((,class :foreground ,cyan-alt))) + `(highlight-thing ((,c :inherit match))) ;;;;; hl-fill-column - `(hl-fill-column-face ((,class :background ,bg-active :foreground ,fg-active))) + `(hl-fill-column-face ((,c :background ,bg-active))) ;;;;; hl-todo - `(hl-todo ((,class :inherit (bold modus-themes-slant) :foreground ,red-alt-other))) + `(hl-todo ((,c :inherit (bold font-lock-comment-face) :foreground ,err))) ;;;;; hydra - `(hydra-face-amaranth ((,class :inherit bold :foreground ,yellow-alt))) - `(hydra-face-blue ((,class :inherit bold :foreground ,blue))) - `(hydra-face-pink ((,class :inherit bold :foreground ,magenta-alt-faint))) - `(hydra-face-red ((,class :inherit bold :foreground ,red-faint))) - `(hydra-face-teal ((,class :inherit bold :foreground ,cyan-alt-other))) + `(hydra-face-amaranth ((,c :inherit bold :foreground ,yellow-warmer))) + `(hydra-face-blue ((,c :inherit bold :foreground ,blue))) + `(hydra-face-pink ((,c :inherit bold :foreground ,magenta))) + `(hydra-face-red ((,c :inherit bold :foreground ,red-faint))) + `(hydra-face-teal ((,c :inherit bold :foreground ,cyan-cooler))) ;;;;; icomplete - `(icomplete-first-match ((,class :inherit modus-themes-completion-match-0))) - `(icomplete-selected-match ((,class :inherit modus-themes-completion-selected))) -;;;;; icomplete-vertical - `(icomplete-vertical-separator ((,class :inherit shadow))) + `(icomplete-first-match ((,c :inherit modus-themes-completion-match-0))) + `(icomplete-selected-match ((,c :inherit modus-themes-completion-selected))) ;;;;; ido-mode - `(ido-first-match ((,class :inherit modus-themes-completion-match-0))) - `(ido-incomplete-regexp ((,class :inherit error))) - `(ido-indicator ((,class :inherit modus-themes-subtle-yellow))) - `(ido-only-match ((,class :inherit ido-first-match))) - `(ido-subdir ((,class :foreground ,blue))) - `(ido-virtual ((,class :foreground ,magenta-alt-other))) + `(ido-first-match ((,c :inherit modus-themes-completion-match-0))) + `(ido-incomplete-regexp ((,c :inherit error))) + `(ido-indicator ((,c :inherit bold))) + `(ido-only-match ((,c :inherit ido-first-match))) + `(ido-subdir ((,c :foreground ,accent-0))) + `(ido-virtual ((,c :foreground ,accent-1))) ;;;;; iedit - `(iedit-occurrence ((,class :inherit modus-themes-refine-blue))) - `(iedit-read-only-occurrence ((,class :inherit modus-themes-intense-yellow))) + `(iedit-occurrence ((,c :inherit modus-themes-intense-blue))) + `(iedit-read-only-occurrence ((,c :inherit modus-themes-intense-yellow))) ;;;;; iflipb - `(iflipb-current-buffer-face ((,class :inherit bold :foreground ,cyan-alt))) - `(iflipb-other-buffer-face ((,class :inherit shadow))) + `(iflipb-current-buffer-face ((,c :inherit bold :foreground ,name))) + `(iflipb-other-buffer-face ((,c :inherit shadow))) ;;;;; image-dired - `(image-dired-thumb-flagged ((,class :background ,red-intense-bg))) - `(image-dired-thumb-header-file-name ((,class :inherit bold))) - `(image-dired-thumb-header-file-size ((,class :foreground ,blue-active))) - `(image-dired-thumb-mark ((,class :inherit modus-themes-grue-background-intense))) + `(image-dired-thumb-flagged ((,c :inherit modus-themes-intense-red))) + `(image-dired-thumb-header-file-name ((,c :inherit bold))) + `(image-dired-thumb-header-file-size ((,c :foreground ,constant))) + `(image-dired-thumb-mark ((,c :inherit modus-themes-intense-cyan))) ;;;;; imenu-list - `(imenu-list-entry-face-0 ((,class :foreground ,cyan))) - `(imenu-list-entry-face-1 ((,class :foreground ,blue))) - `(imenu-list-entry-face-2 ((,class :foreground ,cyan-alt-other))) - `(imenu-list-entry-face-3 ((,class :foreground ,blue-alt))) - `(imenu-list-entry-subalist-face-0 ((,class :inherit bold :foreground ,magenta-alt-other :underline t))) - `(imenu-list-entry-subalist-face-1 ((,class :inherit bold :foreground ,magenta :underline t))) - `(imenu-list-entry-subalist-face-2 ((,class :inherit bold :foreground ,green-alt-other :underline t))) - `(imenu-list-entry-subalist-face-3 ((,class :inherit bold :foreground ,red-alt-other :underline t))) + `(imenu-list-entry-face-0 ((,c :foreground ,fg-heading-0))) + `(imenu-list-entry-face-1 ((,c :foreground ,fg-heading-1))) + `(imenu-list-entry-face-2 ((,c :foreground ,fg-heading-2))) + `(imenu-list-entry-face-3 ((,c :foreground ,fg-heading-3))) + `(imenu-list-entry-subalist-face-0 ((,c :inherit bold :foreground ,fg-heading-4 :underline t))) + `(imenu-list-entry-subalist-face-1 ((,c :inherit bold :foreground ,fg-heading-5 :underline t))) + `(imenu-list-entry-subalist-face-2 ((,c :inherit bold :foreground ,fg-heading-6 :underline t))) + `(imenu-list-entry-subalist-face-3 ((,c :inherit bold :foreground ,fg-heading-7 :underline t))) ;;;;; indium - `(indium-breakpoint-face ((,class :foreground ,red-active))) - `(indium-frame-url-face ((,class :inherit (shadow button)))) - `(indium-keyword-face ((,class :inherit font-lock-keyword-face))) - `(indium-litable-face ((,class :inherit modus-themes-slant :foreground ,fg-special-warm))) - `(indium-repl-error-face ((,class :inherit error))) - `(indium-repl-prompt-face ((,class :inherit modus-themes-prompt))) - `(indium-repl-stdout-face ((,class :foreground ,fg-main))) + `(indium-breakpoint-face ((,c :foreground ,err))) + `(indium-frame-url-face ((,c :inherit (shadow button)))) + `(indium-keyword-face ((,c :inherit font-lock-keyword-face))) + `(indium-litable-face ((,c :inherit modus-themes-slant))) + `(indium-repl-error-face ((,c :inherit error))) + `(indium-repl-prompt-face ((,c :inherit modus-themes-prompt))) + `(indium-repl-stdout-face (( ))) ;;;;; info - `(Info-quoted ((,class :inherit modus-themes-markup-verbatim))) ; the capitalization is canonical - `(info-header-node ((,class :inherit (shadow bold)))) - `(info-header-xref ((,class :foreground ,blue-active))) - `(info-index-match ((,class :inherit match))) - `(info-menu-header ((,class :inherit modus-themes-pseudo-header))) - `(info-menu-star ((,class :foreground ,red))) - `(info-node ((,class :inherit bold))) - `(info-title-1 ((,class :inherit modus-themes-heading-1))) - `(info-title-2 ((,class :inherit modus-themes-heading-2))) - `(info-title-3 ((,class :inherit modus-themes-heading-3))) - `(info-title-4 ((,class :inherit modus-themes-heading-4))) + `(Info-quoted ((,c :inherit modus-themes-prose-verbatim))) ; the capitalization is canonical + `(info-header-node ((,c :inherit (shadow bold)))) + `(info-header-xref ((,c :foreground ,fg-link))) + `(info-index-match ((,c :inherit match))) + `(info-menu-header ((,c :inherit bold))) + `(info-menu-star ((,c :foreground ,red-intense))) + `(info-node ((,c :inherit bold))) + `(info-title-1 ((,c :inherit modus-themes-heading-1))) + `(info-title-2 ((,c :inherit modus-themes-heading-2))) + `(info-title-3 ((,c :inherit modus-themes-heading-3))) + `(info-title-4 ((,c :inherit modus-themes-heading-4))) ;;;;; info+ (info-plus) - `(info-command-ref-item ((,class :inherit font-lock-function-name-face))) - `(info-constant-ref-item ((,class :inherit font-lock-constant-face))) - `(info-custom-delimited ((,class :inherit modus-themes-markup-verbatim))) - `(info-double-quoted-name ((,class :inherit font-lock-string-face))) + `(info-command-ref-item ((,c :inherit font-lock-function-name-face))) + `(info-constant-ref-item ((,c :inherit font-lock-constant-face))) + `(info-custom-delimited ((,c :inherit modus-themes-prose-verbatim))) + `(info-double-quoted-name ((,c :inherit font-lock-string-face))) `(info-file (( ))) - `(info-function-ref-item ((,class :inherit font-lock-function-name-face))) - `(info-glossary-word ((,class :inherit modus-themes-box-button))) + `(info-function-ref-item ((,c :inherit font-lock-function-name-face))) + `(info-glossary-word ((,c :inherit modus-themes-button))) `(info-indented-text (( ))) `(info-isolated-backquote (( ))) `(info-isolated-quote (( ))) - `(info-macro-ref-item ((,class :inherit font-lock-keyword-face))) - `(info-menu ((,class :inherit bold))) - `(info-quoted-name ((,class :inherit modus-themes-markup-verbatim))) - `(info-reference-item ((,class :inherit bold))) - `(info-special-form-ref-item ((,class :inherit warning))) - `(info-string ((,class :inherit font-lock-string-face))) - `(info-syntax-class-item ((,class :inherit modus-themes-markup-code))) - `(info-user-option-ref-item ((,class :inherit font-lock-variable-name-face))) - `(info-variable-ref-item ((,class :inherit font-lock-variable-name-face))) + `(info-macro-ref-item ((,c :inherit font-lock-keyword-face))) + `(info-menu ((,c :inherit bold))) + `(info-quoted-name ((,c :inherit modus-themes-prose-verbatim))) + `(info-reference-item ((,c :inherit bold))) + `(info-special-form-ref-item ((,c :inherit warning))) + `(info-string ((,c :inherit font-lock-string-face))) + `(info-syntax-class-item ((,c :inherit modus-themes-prose-code))) + `(info-user-option-ref-item ((,c :inherit font-lock-variable-name-face))) + `(info-variable-ref-item ((,c :inherit font-lock-variable-name-face))) ;;;;; info-colors - `(info-colors-lisp-code-block ((,class :inherit modus-themes-fixed-pitch))) - `(info-colors-ref-item-command ((,class :inherit font-lock-function-name-face))) - `(info-colors-ref-item-constant ((,class :inherit font-lock-constant-face))) - `(info-colors-ref-item-function ((,class :inherit font-lock-function-name-face))) - `(info-colors-ref-item-macro ((,class :inherit font-lock-keyword-face))) - `(info-colors-ref-item-other ((,class :inherit font-lock-doc-face))) - `(info-colors-ref-item-special-form ((,class :inherit font-lock-keyword-face))) - `(info-colors-ref-item-syntax-class ((,class :inherit font-lock-builtin-face))) - `(info-colors-ref-item-type ((,class :inherit font-lock-type-face))) - `(info-colors-ref-item-user-option ((,class :inherit font-lock-variable-name-face))) - `(info-colors-ref-item-variable ((,class :inherit font-lock-variable-name-face))) -;;;;; interaction-log - `(ilog-buffer-face ((,class :foreground ,magenta-alt-other))) - `(ilog-change-face ((,class :foreground ,magenta-alt))) - `(ilog-echo-face ((,class :foreground ,yellow-alt-other))) - `(ilog-load-face ((,class :foreground ,green))) - `(ilog-message-face ((,class :inherit shadow))) - `(ilog-non-change-face ((,class :foreground ,blue))) + `(info-colors-lisp-code-block ((,c :inherit modus-themes-fixed-pitch))) + `(info-colors-ref-item-command ((,c :inherit font-lock-function-name-face))) + `(info-colors-ref-item-constant ((,c :inherit font-lock-constant-face))) + `(info-colors-ref-item-function ((,c :inherit font-lock-function-name-face))) + `(info-colors-ref-item-macro ((,c :inherit font-lock-keyword-face))) + `(info-colors-ref-item-other ((,c :inherit font-lock-doc-face))) + `(info-colors-ref-item-special-form ((,c :inherit font-lock-keyword-face))) + `(info-colors-ref-item-syntax-class ((,c :inherit font-lock-builtin-face))) + `(info-colors-ref-item-type ((,c :inherit font-lock-type-face))) + `(info-colors-ref-item-user-option ((,c :inherit font-lock-variable-name-face))) + `(info-colors-ref-item-variable ((,c :inherit font-lock-variable-name-face))) ;;;;; ioccur - `(ioccur-cursor ((,class :foreground ,fg-main))) - `(ioccur-invalid-regexp ((,class :foreground ,red))) - `(ioccur-match-face ((,class :inherit modus-themes-special-calm))) - `(ioccur-match-overlay-face ((,class :inherit modus-themes-special-cold :extend t))) - `(ioccur-num-line-face ((,class :foreground ,fg-special-warm))) - `(ioccur-overlay-face ((,class :inherit modus-themes-refine-blue :extend t))) - `(ioccur-regexp-face ((,class :inherit (modus-themes-intense-magenta bold)))) - `(ioccur-title-face ((,class :inherit modus-themes-pseudo-header :foreground ,fg-special-cold))) + `(ioccur-cursor ((,c :foreground ,fg-main))) + `(ioccur-invalid-regexp ((,c :inherit error))) + `(ioccur-match-face ((,c :inherit match))) + `(ioccur-match-overlay-face ((,c :background ,bg-inactive :extend t))) + `(ioccur-num-line-face ((,c :inherit shadow))) + `(ioccur-overlay-face ((,c :background ,bg-hl-line :extend t))) + `(ioccur-regexp-face ((,c :inherit (modus-themes-search-current bold)))) + `(ioccur-title-face ((,c :inherit bold :foreground ,name))) ;;;;; isearch, occur, and the like - `(isearch ((,class :inherit modus-themes-search-success))) - `(isearch-fail ((,class :inherit modus-themes-refine-red))) - `(isearch-group-1 ((,class :inherit modus-themes-refine-blue))) - `(isearch-group-2 ((,class :inherit modus-themes-refine-magenta))) - `(lazy-highlight ((,class :inherit modus-themes-search-success-lazy))) - `(match ((,class :inherit modus-themes-special-calm))) - `(query-replace ((,class :inherit modus-themes-intense-red))) + `(isearch ((,c :inherit modus-themes-search-current))) + `(isearch-fail ((,c :inherit modus-themes-intense-red))) + `(isearch-group-1 ((,c :inherit modus-themes-intense-blue))) + `(isearch-group-2 ((,c :inherit modus-themes-intense-magenta))) + `(lazy-highlight ((,c :inherit modus-themes-search-lazy))) + `(match ((,c :background ,bg-magenta-subtle :foreground ,fg-main))) + `(query-replace ((,c :inherit modus-themes-intense-red))) ;;;;; ivy - `(ivy-action ((,class :inherit modus-themes-key-binding))) - `(ivy-confirm-face ((,class :inherit success))) - `(ivy-current-match ((,class :inherit modus-themes-completion-selected))) - `(ivy-cursor ((,class :background ,fg-main :foreground ,bg-main))) - `(ivy-highlight-face ((,class :foreground ,magenta))) - `(ivy-match-required-face ((,class :inherit error))) + `(ivy-action ((,c :inherit modus-themes-key-binding))) + `(ivy-confirm-face ((,c :inherit success))) + `(ivy-current-match ((,c :inherit modus-themes-completion-selected))) + `(ivy-match-required-face ((,c :inherit error))) `(ivy-minibuffer-match-face-1 (( ))) - `(ivy-minibuffer-match-face-2 ((,class :inherit modus-themes-completion-match-0))) - `(ivy-minibuffer-match-face-3 ((,class :inherit modus-themes-completion-match-1))) - `(ivy-minibuffer-match-face-4 ((,class :inherit modus-themes-completion-match-2))) - `(ivy-org ((,class :foreground ,cyan-alt-other))) - `(ivy-remote ((,class :foreground ,magenta))) - `(ivy-separator ((,class :inherit shadow))) - `(ivy-subdir ((,class :foreground ,blue))) - `(ivy-virtual ((,class :foreground ,magenta-alt-other))) + `(ivy-minibuffer-match-face-2 ((,c :inherit modus-themes-completion-match-0))) + `(ivy-minibuffer-match-face-3 ((,c :inherit modus-themes-completion-match-1))) + `(ivy-minibuffer-match-face-4 ((,c :inherit modus-themes-completion-match-2))) + `(ivy-remote ((,c :inherit italic))) + `(ivy-separator ((,c :inherit shadow))) + `(ivy-subdir ((,c :foreground ,accent-0))) + `(ivy-virtual ((,c :foreground ,accent-1))) ;;;;; ivy-posframe - `(ivy-posframe-border ((,class :background ,fg-window-divider-inner))) - `(ivy-posframe-cursor ((,class :background ,fg-main :foreground ,bg-main))) + `(ivy-posframe-border ((,c :background ,border))) + `(ivy-posframe-cursor ((,c :background ,fg-main :foreground ,bg-main))) ;;;;; jira (org-jira) - `(jiralib-comment-face ((,class :background ,bg-alt))) - `(jiralib-comment-header-face ((,class :inherit bold))) - `(jiralib-issue-info-face ((,class :inherit modus-themes-special-warm))) - `(jiralib-issue-info-header-face ((,class :inherit (modus-themes-special-warm bold)))) - `(jiralib-issue-summary-face ((,class :inherit bold))) - `(jiralib-link-filter-face ((,class :underline t))) - `(jiralib-link-issue-face ((,class :underline t))) - `(jiralib-link-project-face ((,class :underline t))) + `(jiralib-comment-face ((,c :background ,bg-inactive))) + `(jiralib-comment-header-face ((,c :inherit bold))) + `(jiralib-issue-info-face ((,c :background ,bg-inactive))) + `(jiralib-issue-info-header-face ((,c :inherit bold :background ,bg-inactive))) + `(jiralib-issue-summary-face ((,c :inherit bold))) + `(jiralib-link-filter-face ((,c :underline t))) + `(jiralib-link-issue-face ((,c :underline t))) + `(jiralib-link-project-face ((,c :underline t))) ;;;;; journalctl-mode - `(journalctl-error-face ((,class :inherit error))) - `(journalctl-finished-face ((,class :inherit success))) - `(journalctl-host-face ((,class :foreground ,blue))) - `(journalctl-process-face ((,class :foreground ,cyan-alt-other))) - `(journalctl-starting-face ((,class :foreground ,green))) - `(journalctl-timestamp-face ((,class :foreground ,fg-special-cold))) - `(journalctl-warning-face ((,class :inherit warning))) + `(journalctl-error-face ((,c :inherit error))) + `(journalctl-finished-face ((,c :inherit success))) + `(journalctl-host-face ((,c :foreground ,name))) + `(journalctl-process-face ((,c :foreground ,warning))) + `(journalctl-starting-face ((,c :foreground ,info))) + `(journalctl-timestamp-face ((,c :foreground ,date-common))) + `(journalctl-warning-face ((,c :inherit warning))) ;;;;; js2-mode - `(js2-error ((,class :inherit modus-themes-lang-error))) - `(js2-external-variable ((,class :inherit font-lock-variable-name-face))) - `(js2-function-call ((,class :inherit font-lock-function-name-face))) - `(js2-function-param ((,class :inherit font-lock-constant-face))) - `(js2-instance-member ((,class :inherit font-lock-keyword-face))) - `(js2-jsdoc-html-tag-delimiter ((,class :foreground ,fg-main))) - `(js2-jsdoc-html-tag-name ((,class :inherit font-lock-function-name-face))) - `(js2-jsdoc-tag ((,class :inherit (font-lock-builtin-face font-lock-comment-face) :weight normal))) - `(js2-jsdoc-type ((,class :inherit (font-lock-type-face font-lock-comment-face) :weight normal))) - `(js2-jsdoc-value ((,class :inherit (font-lock-constant-face font-lock-comment-face) :weight normal))) - `(js2-object-property ((,class :foreground ,fg-main))) - `(js2-object-property-access ((,class :foreground ,fg-main))) - `(js2-private-function-call ((,class :inherit font-lock-preprocessor-face))) - `(js2-private-member ((,class :inherit font-lock-warning-face))) - `(js2-warning ((,class :inherit modus-themes-lang-warning))) + `(js2-error ((,c :inherit modus-themes-lang-error))) + `(js2-external-variable ((,c :inherit font-lock-variable-name-face))) + `(js2-function-call ((,c :inherit font-lock-function-name-face))) + `(js2-function-param ((,c :inherit font-lock-constant-face))) + `(js2-instance-member ((,c :inherit font-lock-keyword-face))) + `(js2-jsdoc-html-tag-delimiter ((,c :foreground ,fg-main))) + `(js2-jsdoc-html-tag-name ((,c :inherit font-lock-function-name-face))) + `(js2-jsdoc-tag ((,c :inherit (font-lock-builtin-face font-lock-comment-face) :weight normal))) + `(js2-jsdoc-type ((,c :inherit (font-lock-type-face font-lock-comment-face) :weight normal))) + `(js2-jsdoc-value ((,c :inherit (font-lock-constant-face font-lock-comment-face) :weight normal))) + `(js2-object-property ((,c :foreground ,fg-main))) + `(js2-object-property-access ((,c :foreground ,fg-main))) + `(js2-private-function-call ((,c :inherit font-lock-preprocessor-face))) + `(js2-private-member ((,c :inherit font-lock-warning-face))) + `(js2-warning ((,c :inherit modus-themes-lang-warning))) ;;;;; julia - `(julia-macro-face ((,class :inherit font-lock-builtin-face))) - `(julia-quoted-symbol-face ((,class :inherit font-lock-constant-face))) -;;;;; jupyter - `(jupyter-eval-overlay ((,class :inherit bold :foreground ,blue))) - `(jupyter-repl-input-prompt ((,class :foreground ,cyan-alt-other))) - `(jupyter-repl-output-prompt ((,class :foreground ,magenta-alt-other))) - `(jupyter-repl-traceback ((,class :inherit modus-themes-intense-red))) + `(julia-macro-face ((,c :inherit font-lock-builtin-face))) + `(julia-quoted-symbol-face ((,c :inherit font-lock-constant-face))) ;;;;; kaocha-runner - `(kaocha-runner-error-face ((,class :inherit error))) - `(kaocha-runner-success-face ((,class :inherit success))) - `(kaocha-runner-warning-face ((,class :inherit warning))) + `(kaocha-runner-error-face ((,c :inherit error))) + `(kaocha-runner-success-face ((,c :inherit success))) + `(kaocha-runner-warning-face ((,c :inherit warning))) ;;;;; keycast - `(keycast-command ((,class :inherit bold :foreground ,blue-active))) - ;; FIXME 2022-05-03: The padding breaks `keycast-tab-bar-mode' - `(keycast-key ((,class ;; ,@(modus-themes--mode-line-padded-box blue-active) - :background ,blue-active :foreground ,bg-main))) + `(keycast-command ((,c :inherit bold :foreground ,keybind))) + `(keycast-key ((,c :background ,keybind :foreground ,bg-main :box ,keybind))) ;;;;; ledger-mode - `(ledger-font-auto-xact-face ((,class :foreground ,magenta))) - `(ledger-font-account-name-face ((,class :foreground ,fg-special-cold))) - `(ledger-font-directive-face ((,class :foreground ,magenta-alt-other))) - `(ledger-font-posting-date-face ((,class :inherit bold :foreground ,fg-main))) - `(ledger-font-periodic-xact-face ((,class :foreground ,cyan-alt-other))) - `(ledger-font-posting-amount-face ((,class :foreground ,fg-special-mild))) - `(ledger-font-payee-cleared-face ((,class :foreground ,blue-alt))) - `(ledger-font-payee-pending-face ((,class :foreground ,yellow))) - `(ledger-font-payee-uncleared-face ((,class :foreground ,red-alt-other))) - `(ledger-font-xact-highlight-face ((,class :background ,bg-hl-alt))) + `(ledger-font-auto-xact-face ((,c :inherit font-lock-builtin-face))) + `(ledger-font-account-name-face ((,c :foreground ,name))) + `(ledger-font-directive-face ((,c :inherit font-lock-keyword-face))) + `(ledger-font-posting-date-face ((,c :inherit modus-themes-bold :foreground ,date-common))) + `(ledger-font-periodic-xact-face ((,c :inherit font-lock-variable-name-face))) + `(ledger-font-posting-amount-face ((,c :inherit font-lock-constant-face))) + `(ledger-font-payee-cleared-face ((,c :inherit success))) + `(ledger-font-payee-pending-face ((,c :inherit warning))) + `(ledger-font-payee-uncleared-face ((,c :inherit error))) + `(ledger-font-xact-highlight-face ((,c :inherit highlight))) ;;;;; leerzeichen - `(leerzeichen ((,class :background ,bg-whitespace :foreground ,fg-whitespace))) + `(leerzeichen ((,c :background ,bg-inactive))) ;;;;; line numbers (display-line-numbers-mode and global variant) ;; Here we cannot inherit `modus-themes-fixed-pitch'. We need to ;; fall back to `default' otherwise line numbers do not scale when ;; using `text-scale-adjust'. - `(line-number - ((,class :inherit ,(if modus-themes-mixed-fonts '(fixed-pitch default) 'default) - ,@(modus-themes--line-numbers - fg-alt bg-dim - fg-unfocused)))) - `(line-number-current-line - ((,class :inherit (bold line-number) - ,@(modus-themes--line-numbers - fg-main bg-active - blue-alt-other)))) - `(line-number-major-tick - ((,class :inherit (bold line-number) - ,@(modus-themes--line-numbers - yellow-nuanced-fg yellow-nuanced-bg - red-alt)))) - `(line-number-minor-tick - ((,class :inherit (bold line-number) - ,@(modus-themes--line-numbers - fg-alt bg-inactive - fg-inactive)))) -;;;;; lsp-mode - `(lsp-face-highlight-read ((,class :inherit modus-themes-subtle-blue :underline t))) - `(lsp-face-highlight-textual ((,class :inherit modus-themes-subtle-blue))) - `(lsp-face-highlight-write ((,class :inherit (modus-themes-refine-blue bold)))) - `(lsp-face-semhl-constant ((,class :foreground ,blue-alt-other))) - `(lsp-face-semhl-deprecated ((,class :inherit modus-themes-lang-warning))) - `(lsp-face-semhl-enummember ((,class :foreground ,blue-alt-other))) - `(lsp-face-semhl-field ((,class :foreground ,cyan-alt))) - `(lsp-face-semhl-field-static ((,class :inherit modus-themes-slant :foreground ,cyan-alt))) - `(lsp-face-semhl-function ((,class :foreground ,magenta))) - `(lsp-face-semhl-method ((,class :foreground ,magenta))) - `(lsp-face-semhl-namespace ((,class :inherit modus-themes-bold :foreground ,magenta-alt))) - `(lsp-face-semhl-preprocessor ((,class :foreground ,red-alt-other))) - `(lsp-face-semhl-static-method ((,class :inherit modus-themes-slant :foreground ,magenta))) - `(lsp-face-semhl-type-class ((,class :foreground ,magenta-alt))) - `(lsp-face-semhl-type-enum ((,class :foreground ,magenta-alt))) - `(lsp-face-semhl-type-primitive ((,class :inherit modus-themes-slant :foreground ,magenta-alt))) - `(lsp-face-semhl-type-template ((,class :inherit modus-themes-slant :foreground ,magenta-alt))) - `(lsp-face-semhl-type-typedef ((,class :inherit modus-themes-slant :foreground ,magenta-alt))) - `(lsp-face-semhl-variable ((,class :foreground ,cyan))) - `(lsp-face-semhl-variable-local ((,class :foreground ,cyan))) - `(lsp-face-semhl-variable-parameter ((,class :foreground ,cyan-alt-other))) - `(lsp-lens-face ((,class :inherit shadow :height 0.8))) - `(lsp-lens-mouse-face ((,class :height 0.8 :foreground ,blue-alt-other :underline t))) - `(lsp-ui-doc-background ((,class :background ,bg-alt))) - `(lsp-ui-doc-header ((,class :background ,bg-header :foreground ,fg-header))) - `(lsp-ui-doc-url ((,class :inherit button))) - `(lsp-ui-peek-filename ((,class :foreground ,fg-special-warm))) - `(lsp-ui-peek-footer ((,class :background ,bg-header :foreground ,fg-header))) - `(lsp-ui-peek-header ((,class :background ,bg-header :foreground ,fg-header))) - `(lsp-ui-peek-highlight ((,class :inherit modus-themes-subtle-blue))) - `(lsp-ui-peek-line-number ((,class :inherit shadow))) - `(lsp-ui-peek-list ((,class :background ,bg-dim))) - `(lsp-ui-peek-peek ((,class :background ,bg-alt))) - `(lsp-ui-peek-selection ((,class :inherit modus-themes-subtle-cyan))) - `(lsp-ui-sideline-code-action ((,class :foreground ,yellow))) - `(lsp-ui-sideline-current-symbol ((,class :inherit bold :height 0.99 :box (:line-width -1 :style nil) :foreground ,fg-main))) - `(lsp-ui-sideline-symbol ((,class :inherit bold :height 0.99 :box (:line-width -1 :style nil) :foreground ,fg-alt))) - `(lsp-ui-sideline-symbol-info ((,class :inherit italic :height 0.99))) -;;;;; macrostep - `(macrostep-compiler-macro-face ((,class :inherit italic))) - `(macrostep-expansion-highlight-face ((,class :background ,blue-nuanced-bg))) - `(macrostep-gensym-1 ((,class :inherit bold :foreground ,blue :box t))) - `(macrostep-gensym-2 ((,class :inherit bold :foreground ,green :box t))) - `(macrostep-gensym-3 ((,class :inherit bold :foreground ,yellow :box t))) - `(macrostep-gensym-4 ((,class :inherit bold :foreground ,red :box t))) - `(macrostep-gensym-5 ((,class :inherit bold :foreground ,magenta :box t))) - `(macrostep-macro-face ((,class :inherit button :foreground ,green-alt))) + `(line-number ((,c :inherit ,(if modus-themes-mixed-fonts '(fixed-pitch default) 'default) :background ,bg-line-number-inactive :foreground ,fg-line-number-inactive))) + `(line-number-current-line ((,c :inherit (bold line-number) :background ,bg-line-number-active :foreground ,fg-line-number-active))) + `(line-number-major-tick ((,c :inherit line-number :foreground ,err))) + `(line-number-minor-tick ((,c :inherit line-number :foreground ,fg-alt))) ;;;;; magit - `(magit-bisect-bad ((,class :inherit error))) - `(magit-bisect-good ((,class :inherit success))) - `(magit-bisect-skip ((,class :inherit warning))) - `(magit-blame-date ((,class :foreground ,blue))) - `(magit-blame-dimmed ((,class :inherit (shadow modus-themes-reset-hard)))) - `(magit-blame-hash ((,class :foreground ,fg-special-warm))) - `(magit-blame-heading ((,class :inherit modus-themes-reset-hard :background ,bg-alt :extend t))) - `(magit-blame-highlight ((,class :inherit modus-themes-nuanced-cyan))) - `(magit-blame-margin ((,class :inherit (magit-blame-highlight modus-themes-reset-hard)))) - `(magit-blame-name ((,class :foreground ,magenta-alt-other))) - `(magit-blame-summary ((,class :foreground ,cyan-alt-other))) - ;; ;; NOTE 2021-11-23: we do not set the `magit-branch-current' - ;; ;; because its definition checks if the :box attribute can be set - ;; ;; and if not, it uses :inverse-video. Useful for terminal - ;; ;; emulators. - ;; - ;; `(magit-branch-current ((,class :foreground ,blue-alt-other :box t))) - `(magit-branch-local ((,class :foreground ,blue-alt))) - `(magit-branch-remote ((,class :foreground ,magenta-alt))) - `(magit-branch-remote-head ((,class :foreground ,magenta-alt-other :box t))) - `(magit-branch-upstream ((,class :inherit italic))) - `(magit-branch-warning ((,class :inherit warning))) - `(magit-cherry-equivalent ((,class :background ,bg-main :foreground ,magenta-intense))) - `(magit-cherry-unmatched ((,class :background ,bg-main :foreground ,cyan-intense))) - ;; NOTE: here we break from the pattern of inheriting from the - ;; modus-themes-diff-* faces, though only for the standard actions, - ;; not the highlighted ones. This is because Magit's interaction - ;; model relies on highlighting the current diff hunk. - `(magit-diff-added ((,class ,@(modus-themes--diff - bg-diff-added fg-diff-added - green-nuanced-bg fg-diff-added - bg-diff-added-deuteran fg-diff-added-deuteran - blue-nuanced-bg fg-diff-added-deuteran)))) - `(magit-diff-added-highlight ((,class :inherit modus-themes-diff-focus-added))) - `(magit-diff-base ((,class ,@(modus-themes--diff - bg-diff-changed fg-diff-changed - yellow-nuanced-bg fg-diff-changed)))) - `(magit-diff-base-highlight ((,class :inherit modus-themes-diff-focus-changed))) - `(magit-diff-context ((,class ,@(unless (eq modus-themes-diffs 'bg-only) (list :foreground fg-unfocused))))) - `(magit-diff-context-highlight ((,class ,@(modus-themes--diff - bg-inactive fg-inactive - bg-dim fg-alt - bg-dim fg-alt)))) - `(magit-diff-file-heading ((,class :inherit bold :foreground ,fg-special-cold))) - `(magit-diff-file-heading-highlight ((,class :inherit (modus-themes-special-cold bold)))) - `(magit-diff-file-heading-selection ((,class :inherit modus-themes-refine-cyan))) - ;; NOTE: here we break from the pattern of inheriting from the - ;; modus-themes-diff-* faces. - `(magit-diff-hunk-heading ((,class :inherit bold - ,@(modus-themes--diff - bg-active fg-inactive - bg-inactive fg-inactive - bg-inactive fg-inactive - nil nil - t)))) - ;; NOTE: we do not follow the pattern of inheriting from - ;; modus-themes-grue-* faces, as this is a special case. - `(magit-diff-hunk-heading-highlight - ((,class :inherit bold - :background ,@(modus-themes--deuteran bg-active bg-diff-heading) - :foreground ,@(modus-themes--deuteran fg-main fg-diff-heading)))) - `(magit-diff-hunk-heading-selection ((,class :inherit modus-themes-refine-blue))) - `(magit-diff-hunk-region ((,class :inherit bold))) - `(magit-diff-lines-boundary ((,class :background ,fg-main))) - `(magit-diff-lines-heading ((,class :inherit modus-themes-refine-magenta))) - `(magit-diff-removed ((,class ,@(modus-themes--diff - bg-diff-removed fg-diff-removed - red-nuanced-bg fg-diff-removed)))) - `(magit-diff-removed-highlight ((,class :inherit modus-themes-diff-focus-removed))) - `(magit-diffstat-added ((,class :inherit modus-themes-grue))) - `(magit-diffstat-removed ((,class :foreground ,red))) - `(magit-dimmed ((,class :foreground ,fg-unfocused))) - `(magit-filename ((,class :foreground ,fg-special-cold))) - `(magit-hash ((,class :inherit shadow))) - `(magit-head ((,class :inherit magit-branch-local))) - `(magit-header-line ((,class :inherit bold :foreground ,magenta-active))) - `(magit-header-line-key ((,class :inherit modus-themes-key-binding))) - `(magit-header-line-log-select ((,class :inherit bold :foreground ,fg-main))) - `(magit-keyword ((,class :foreground ,magenta))) - `(magit-keyword-squash ((,class :inherit bold :foreground ,yellow-alt-other))) - `(magit-log-author ((,class :foreground ,cyan))) - `(magit-log-date ((,class :inherit shadow))) - `(magit-log-graph ((,class :foreground ,fg-dim))) - `(magit-mode-line-process ((,class :inherit bold :foreground ,cyan-active))) - `(magit-mode-line-process-error ((,class :inherit bold :foreground ,red-active))) - `(magit-process-ng ((,class :inherit error))) - `(magit-process-ok ((,class :inherit success))) - `(magit-reflog-amend ((,class :inherit warning))) - `(magit-reflog-checkout ((,class :inherit bold :foreground ,blue-alt))) - `(magit-reflog-cherry-pick ((,class :inherit success))) - `(magit-reflog-commit ((,class :inherit bold))) - `(magit-reflog-merge ((,class :inherit success))) - `(magit-reflog-other ((,class :inherit bold :foreground ,cyan))) - `(magit-reflog-rebase ((,class :inherit bold :foreground ,magenta))) - `(magit-reflog-remote ((,class :inherit bold :foreground ,magenta-alt-other))) - `(magit-reflog-reset ((,class :inherit error))) - `(magit-refname ((,class :inherit shadow))) - `(magit-refname-pullreq ((,class :inherit shadow))) - `(magit-refname-stash ((,class :inherit shadow))) - `(magit-refname-wip ((,class :inherit shadow))) - `(magit-section ((,class :background ,bg-dim :foreground ,fg-main))) - `(magit-section-heading ((,class :inherit bold :foreground ,cyan))) - `(magit-section-heading-selection ((,class :inherit (modus-themes-refine-cyan bold)))) - `(magit-section-highlight ((,class :background ,bg-alt))) - `(magit-sequence-done ((,class :inherit success))) - `(magit-sequence-drop ((,class :inherit error))) - `(magit-sequence-exec ((,class :inherit bold :foreground ,magenta-alt))) - `(magit-sequence-head ((,class :inherit bold :foreground ,cyan-alt))) - `(magit-sequence-onto ((,class :inherit (bold shadow)))) - `(magit-sequence-part ((,class :inherit warning))) - `(magit-sequence-pick ((,class :inherit bold))) - `(magit-sequence-stop ((,class :inherit error))) - `(magit-signature-bad ((,class :inherit error))) - `(magit-signature-error ((,class :inherit error))) - `(magit-signature-expired ((,class :inherit warning))) - `(magit-signature-expired-key ((,class :foreground ,yellow))) - `(magit-signature-good ((,class :inherit success))) - `(magit-signature-revoked ((,class :inherit bold :foreground ,magenta))) - `(magit-signature-untrusted ((,class :inherit (bold shadow)))) - `(magit-tag ((,class :foreground ,yellow-alt-other))) -;;;;; magit-imerge - `(magit-imerge-overriding-value ((,class :inherit bold :foreground ,red-alt))) + `(magit-bisect-bad ((,c :inherit error))) + `(magit-bisect-good ((,c :inherit success))) + `(magit-bisect-skip ((,c :inherit warning))) + `(magit-blame-date (( ))) + `(magit-blame-dimmed ((,c :inherit shadow))) + `(magit-blame-hash (( ))) + `(magit-blame-highlight ((,c :background ,bg-active :foreground ,fg-main))) + `(magit-blame-name (( ))) + `(magit-blame-summary (( ))) + `(magit-branch-local ((,c :foreground ,accent-0))) + `(magit-branch-remote ((,c :foreground ,accent-1))) + `(magit-branch-upstream ((,c :inherit italic))) + `(magit-branch-warning ((,c :inherit warning))) + `(magit-cherry-equivalent ((,c :foreground ,magenta))) + `(magit-cherry-unmatched ((,c :foreground ,cyan))) + `(magit-diff-added ((,c :background ,bg-added-faint :foreground ,fg-added))) + `(magit-diff-added-highlight ((,c :background ,bg-added :foreground ,fg-added))) + `(magit-diff-base ((,c :background ,bg-changed-faint :foreground ,fg-changed))) + `(magit-diff-base-highlight ((,c :background ,bg-changed :foreground ,fg-changed))) + `(magit-diff-context ((,c :inherit shadow))) + `(magit-diff-context-highlight ((,c :background ,bg-dim))) + `(magit-diff-file-heading ((,c :inherit bold :foreground ,accent-0))) + `(magit-diff-file-heading-highlight ((,c :inherit magit-diff-file-heading :background ,bg-inactive))) + `(magit-diff-file-heading-selection ((,c :inherit bold :background ,bg-hover-secondary))) + `(magit-diff-hunk-heading ((,c :background ,bg-inactive))) + `(magit-diff-hunk-heading-highlight ((,c :inherit bold :background ,bg-active))) + `(magit-diff-hunk-heading-selection ((,c :inherit bold :background ,bg-hover-secondary))) + `(magit-diff-hunk-region ((,c :inherit bold))) + `(magit-diff-lines-boundary ((,c :background ,fg-main))) + `(magit-diff-lines-heading ((,c :background ,fg-dim :foreground ,bg-main))) + `(magit-diff-removed ((,c :background ,bg-removed-faint :foreground ,fg-removed))) + `(magit-diff-removed-highlight ((,c :background ,bg-removed :foreground ,fg-removed))) + `(magit-diffstat-added ((,c :foreground ,fg-added-intense))) + `(magit-diffstat-removed ((,c :foreground ,fg-removed-intense))) + `(magit-dimmed ((,c :inherit shadow))) + `(magit-filename ((,c :foreground ,accent-2))) + `(magit-hash ((,c :foreground ,identifier))) + `(magit-head ((,c :inherit magit-branch-local))) + `(magit-header-line ((,c :inherit bold))) + `(magit-header-line-key ((,c :inherit modus-themes-key-binding))) + `(magit-header-line-log-select ((,c :inherit bold))) + `(magit-keyword ((,c :foreground ,keyword))) + `(magit-keyword-squash ((,c :inherit bold :foreground ,warning))) + `(magit-log-author ((,c :foreground ,name))) + `(magit-log-date ((,c :foreground ,date-common))) + `(magit-log-graph ((,c :inherit shadow))) + `(magit-mode-line-process ((,c :inherit bold :foreground ,modeline-info))) + `(magit-mode-line-process-error ((,c :inherit bold :foreground ,modeline-err))) + `(magit-process-ng ((,c :inherit error))) + `(magit-process-ok ((,c :inherit success))) + `(magit-reflog-amend ((,c :inherit warning))) + `(magit-reflog-checkout ((,c :inherit bold :foreground ,blue))) + `(magit-reflog-cherry-pick ((,c :inherit success))) + `(magit-reflog-commit ((,c :inherit bold))) + `(magit-reflog-merge ((,c :inherit success))) + `(magit-reflog-other ((,c :inherit bold :foreground ,cyan))) + `(magit-reflog-rebase ((,c :inherit bold :foreground ,magenta))) + `(magit-reflog-remote ((,c :inherit (bold magit-branch-remote)))) + `(magit-reflog-reset ((,c :inherit error))) + `(magit-refname ((,c :inherit shadow))) + `(magit-refname-pullreq ((,c :inherit shadow))) + `(magit-refname-stash ((,c :inherit shadow))) + `(magit-refname-wip ((,c :inherit shadow))) + `(magit-section ((,c :background ,bg-dim :foreground ,fg-main))) + `(magit-section-heading ((,c :inherit bold))) + `(magit-section-heading-selection ((,c :inherit bold :background ,bg-hover-secondary))) + `(magit-section-highlight ((,c :background ,bg-dim))) + `(magit-sequence-done ((,c :inherit success))) + `(magit-sequence-drop ((,c :inherit error))) + `(magit-sequence-exec ((,c :inherit bold :foreground ,magenta))) + `(magit-sequence-head ((,c :inherit bold :foreground ,cyan))) + `(magit-sequence-onto ((,c :inherit (bold shadow)))) + `(magit-sequence-part ((,c :inherit warning))) + `(magit-sequence-pick ((,c :inherit bold))) + `(magit-sequence-stop ((,c :inherit error))) + `(magit-signature-bad ((,c :inherit error))) + `(magit-signature-error ((,c :inherit error))) + `(magit-signature-expired ((,c :inherit warning))) + `(magit-signature-expired-key ((,c :foreground ,warning))) + `(magit-signature-good ((,c :inherit success))) + `(magit-signature-revoked ((,c :inherit bold :foreground ,warning))) + `(magit-signature-untrusted ((,c :inherit (bold shadow)))) + `(magit-tag ((,c :foreground ,accent-3))) ; compare with branches ;;;;; make-mode (makefiles) - `(makefile-makepp-perl ((,class :background ,cyan-nuanced-bg))) - `(makefile-space ((,class :background ,magenta-nuanced-bg))) + `(makefile-makepp-perl ((,c :background ,bg-dim))) + `(makefile-space ((,c :background ,bg-inactive))) ;;;;; man - `(Man-overstrike ((,class :inherit bold :foreground ,magenta-alt))) - `(Man-reverse ((,class :inherit modus-themes-subtle-magenta))) - `(Man-underline ((,class :foreground ,cyan-alt-other :underline t))) + `(Man-overstrike ((,c :inherit bold :foreground ,accent-0))) + `(Man-underline ((,c :foreground ,accent-1 :underline t))) ;;;;; marginalia - `(marginalia-archive ((,class :foreground ,cyan-alt-other))) - `(marginalia-char ((,class :foreground ,magenta))) - `(marginalia-date ((,class :foreground ,cyan))) - `(marginalia-documentation ((,class :inherit modus-themes-slant :foreground ,fg-docstring))) - `(marginalia-file-name ((,class :foreground ,blue-faint))) - `(marginalia-file-owner ((,class :foreground ,red-faint))) - `(marginalia-file-priv-dir ((,class :foreground ,blue-alt))) - `(marginalia-file-priv-exec ((,class :foreground ,magenta-alt))) - `(marginalia-file-priv-link ((,class :foreground ,blue-alt-other))) - `(marginalia-file-priv-no ((,class :foreground "gray50"))) - `(marginalia-file-priv-other ((,class :foreground ,yellow))) - `(marginalia-file-priv-rare ((,class :foreground ,red))) - `(marginalia-file-priv-read ((,class :foreground ,fg-main))) - `(marginalia-file-priv-write ((,class :foreground ,cyan))) - `(marginalia-function ((,class :foreground ,magenta-alt-faint))) - `(marginalia-key ((,class :inherit modus-themes-key-binding))) - `(marginalia-lighter ((,class :foreground ,blue-alt))) - `(marginalia-list ((,class :foreground ,magenta-alt-other-faint))) - `(marginalia-mode ((,class :foreground ,cyan))) - `(marginalia-modified ((,class :foreground ,magenta-alt-faint))) - `(marginalia-null ((,class :inherit shadow))) - `(marginalia-number ((,class :foreground ,cyan))) - `(marginalia-size ((,class :foreground ,cyan-alt-other-faint))) - `(marginalia-string ((,class :foreground ,blue-alt))) - `(marginalia-symbol ((,class :foreground ,blue-alt-other-faint))) - `(marginalia-true ((,class :foreground ,fg-main))) - `(marginalia-type ((,class :foreground ,cyan-alt-other))) - `(marginalia-value ((,class :foreground ,cyan))) - `(marginalia-version ((,class :foreground ,cyan))) + `(marginalia-archive ((,c :foreground ,accent-0))) + `(marginalia-char ((,c :foreground ,accent-2))) + `(marginalia-date ((,c :foreground ,date-common))) + `(marginalia-documentation ((,c :inherit italic :foreground ,docstring))) + `(marginalia-file-name (( ))) + `(marginalia-file-owner ((,c :inherit shadow))) + `(marginalia-file-priv-dir ((,c :foreground ,accent-0))) + `(marginalia-file-priv-exec ((,c :foreground ,accent-1))) + `(marginalia-file-priv-link ((,c :foreground ,fg-link))) + `(marginalia-file-priv-no ((,c :inherit shadow))) + `(marginalia-file-priv-other ((,c :foreground ,accent-2))) + `(marginalia-file-priv-rare ((,c :foreground ,accent-3))) + `(marginalia-file-priv-read ((,c :foreground ,fg-main))) + `(marginalia-file-priv-write ((,c :foreground ,accent-0))) + `(marginalia-function ((,c :foreground ,fnname))) + `(marginalia-key ((,c :inherit modus-themes-key-binding))) + `(marginalia-lighter ((,c :inherit shadow))) + `(marginalia-liqst ((,c :inherit shadow))) + `(marginalia-mode ((,c :foreground ,constant))) + `(marginalia-modified ((,c :inherit warning))) + `(marginalia-null ((,c :inherit shadow))) + `(marginalia-number ((,c :foreground ,constant))) + `(marginalia-size ((,c :foreground ,variable))) + `(marginalia-string ((,c :foreground ,string))) + `(marginalia-symbol ((,c :foreground ,builtin))) + `(marginalia-true (( ))) + `(marginalia-type ((,c :foreground ,type))) + `(marginalia-value ((,c :inherit shadow))) + `(marginalia-version ((,c :foreground ,date-common))) ;;;;; markdown-mode - `(markdown-blockquote-face ((,class :inherit modus-themes-slant :foreground ,fg-special-cold))) - `(markdown-bold-face ((,class :inherit bold))) - `(markdown-code-face ((,class :inherit modus-themes-fixed-pitch :background ,bg-dim :extend t))) - `(markdown-comment-face ((,class :inherit font-lock-comment-face))) - `(markdown-footnote-marker-face ((,class :inherit bold :foreground ,cyan-alt))) - `(markdown-footnote-text-face ((,class :inherit modus-themes-slant :foreground ,fg-main))) - `(markdown-gfm-checkbox-face ((,class :foreground ,yellow-alt-other))) - `(markdown-header-delimiter-face ((,class :inherit modus-themes-bold :foreground ,fg-dim))) - `(markdown-header-face ((t nil))) - `(markdown-header-face-1 ((,class :inherit modus-themes-heading-1))) - `(markdown-header-face-2 ((,class :inherit modus-themes-heading-2))) - `(markdown-header-face-3 ((,class :inherit modus-themes-heading-3))) - `(markdown-header-face-4 ((,class :inherit modus-themes-heading-4))) - `(markdown-header-face-5 ((,class :inherit modus-themes-heading-5))) - `(markdown-header-face-6 ((,class :inherit modus-themes-heading-6))) - `(markdown-header-rule-face ((,class :inherit bold :foreground ,fg-special-warm))) - `(markdown-highlighting-face ((,class :inherit modus-themes-refine-yellow))) - `(markdown-hr-face ((,class :inherit bold :foreground ,fg-special-warm))) - `(markdown-html-attr-name-face ((,class :inherit modus-themes-fixed-pitch - :foreground ,cyan))) - `(markdown-html-attr-value-face ((,class :inherit modus-themes-fixed-pitch - :foreground ,blue))) - `(markdown-html-entity-face ((,class :inherit modus-themes-fixed-pitch - :foreground ,cyan))) - `(markdown-html-tag-delimiter-face ((,class :inherit modus-themes-fixed-pitch - :foreground ,fg-special-mild))) - `(markdown-html-tag-name-face ((,class :inherit modus-themes-fixed-pitch - :foreground ,magenta-alt))) - `(markdown-inline-code-face ((,class :inherit modus-themes-markup-verbatim))) - `(markdown-italic-face ((,class :inherit italic))) - `(markdown-language-info-face ((,class :inherit modus-themes-fixed-pitch - :foreground ,fg-special-cold))) - `(markdown-language-keyword-face ((,class :inherit modus-themes-fixed-pitch - :background ,bg-alt - :foreground ,fg-alt))) - `(markdown-line-break-face ((,class :inherit modus-themes-refine-cyan :underline t))) - `(markdown-link-face ((,class :inherit button))) - `(markdown-link-title-face ((,class :inherit modus-themes-slant :foreground ,fg-special-cold))) - `(markdown-list-face ((,class :foreground ,fg-dim))) - `(markdown-markup-face ((,class :inherit shadow))) - `(markdown-math-face ((,class :foreground ,magenta-alt-other))) - `(markdown-metadata-key-face ((,class :foreground ,cyan-alt-other))) - `(markdown-metadata-value-face ((,class :foreground ,blue-alt))) - `(markdown-missing-link-face ((,class :inherit bold :foreground ,yellow))) - `(markdown-plain-url-face ((,class :inherit markdown-link-face))) - `(markdown-pre-face ((,class :inherit markdown-code-face :foreground ,fg-special-mild))) - `(markdown-reference-face ((,class :inherit markdown-markup-face))) - `(markdown-strike-through-face ((,class :strike-through t))) - `(markdown-table-face ((,class :inherit modus-themes-fixed-pitch - :foreground ,fg-special-cold))) - `(markdown-url-face ((,class :foreground ,blue-alt))) + `(markdown-blockquote-face ((,c :inherit font-lock-doc-face))) + `(markdown-bold-face ((,c :inherit bold))) + `(markdown-code-face ((,c :inherit modus-themes-fixed-pitch :background ,bg-dim :extend t))) + `(markdown-gfm-checkbox-face ((,c :foreground ,warning))) + `(markdown-header-face (( ))) + `(markdown-header-face-1 ((,c :inherit modus-themes-heading-1))) + `(markdown-header-face-2 ((,c :inherit modus-themes-heading-2))) + `(markdown-header-face-3 ((,c :inherit modus-themes-heading-3))) + `(markdown-header-face-4 ((,c :inherit modus-themes-heading-4))) + `(markdown-header-face-5 ((,c :inherit modus-themes-heading-5))) + `(markdown-header-face-6 ((,c :inherit modus-themes-heading-6))) + `(markdown-highlighting-face ((,c :inherit secondary-selection))) + `(markdown-inline-code-face ((,c :inherit modus-themes-prose-code))) + `(markdown-italic-face ((,c :inherit italic))) + `(markdown-language-keyword-face ((,c :inherit modus-themes-fixed-pitch :foreground ,prose-block))) + `(markdown-line-break-face ((,c :inherit nobreak-space))) + `(markdown-link-face ((,c :inherit link))) + `(markdown-markup-face ((,c :inherit shadow))) + `(markdown-metadata-key-face ((,c :inherit bold))) + `(markdown-metadata-value-face ((,c :foreground ,string))) + `(markdown-missing-link-face ((,c :inherit warning))) + `(markdown-pre-face ((,c :inherit markdown-code-face))) + `(markdown-table-face ((,c :inherit modus-themes-fixed-pitch :foreground ,prose-table))) + `(markdown-url-face ((,c :foreground ,fg-alt))) ;;;;; markup-faces (`adoc-mode') - `(markup-attribute-face ((,class :inherit (italic markup-meta-face)))) - `(markup-bold-face ((,class :inherit bold :foreground ,red-nuanced-fg))) - `(markup-code-face ((,class :foreground ,magenta))) - `(markup-comment-face ((,class :inherit font-lock-comment-face))) - `(markup-complex-replacement-face ((,class :background ,magenta-nuanced-bg :foreground ,magenta-alt-other))) - `(markup-emphasis-face ((,class :inherit markup-italic-face))) - `(markup-error-face ((,class :inherit error))) - `(markup-gen-face ((,class :foreground ,magenta-alt))) - `(markup-internal-reference-face ((,class :inherit modus-themes-slant :foreground ,fg-alt))) - `(markup-italic-face ((,class :inherit italic))) - `(markup-list-face ((,class :inherit modus-themes-special-cold))) - `(markup-meta-face ((,class :inherit (modus-themes-fixed-pitch shadow)))) - `(markup-meta-hide-face ((,class :foreground "gray50"))) - `(markup-reference-face ((,class :inherit modus-themes-slant :foreground ,blue-alt))) - `(markup-replacement-face ((,class :inherit modus-themes-fixed-pitch :foreground ,red-alt))) - `(markup-secondary-text-face ((,class :height 0.9 :foreground ,cyan-alt-other))) - `(markup-small-face ((,class :inherit markup-gen-face :height 0.9))) - `(markup-strong-face ((,class :inherit markup-bold-face))) - `(markup-subscript-face ((,class :height 0.9 :foreground ,magenta-alt-other))) - `(markup-superscript-face ((,class :height 0.9 :foreground ,magenta-alt-other))) - `(markup-table-cell-face ((,class :inherit modus-themes-subtle-neutral))) - `(markup-table-face ((,class :inherit modus-themes-subtle-neutral))) - `(markup-table-row-face ((,class :inherit modus-themes-special-cold))) - `(markup-title-0-face ((,class :inherit modus-themes-heading-1))) - `(markup-title-1-face ((,class :inherit modus-themes-heading-2))) - `(markup-title-2-face ((,class :inherit modus-themes-heading-3))) - `(markup-title-3-face ((,class :inherit modus-themes-heading-4))) - `(markup-title-4-face ((,class :inherit modus-themes-heading-5))) - `(markup-title-5-face ((,class :inherit modus-themes-heading-6))) - `(markup-verbatim-face ((,class :inherit modus-themes-fixed-pitch :background ,bg-alt))) -;;;;; mentor - `(mentor-download-message ((,class :foreground ,fg-special-warm))) - `(mentor-download-name ((,class :foreground ,fg-special-cold))) - `(mentor-download-progress ((,class :foreground ,blue-alt-other))) - `(mentor-download-size ((,class :foreground ,magenta-alt-other))) - `(mentor-download-speed-down ((,class :foreground ,cyan-alt))) - `(mentor-download-speed-up ((,class :foreground ,red-alt))) - `(mentor-download-state ((,class :foreground ,yellow-alt))) - `(mentor-highlight-face ((,class :inherit modus-themes-subtle-blue))) - `(mentor-tracker-name ((,class :foreground ,magenta-alt))) + `(markup-attribute-face ((,c :inherit (italic markup-meta-face)))) + `(markup-bold-face ((,c :inherit bold))) + `(markup-code-face ((,c :foreground ,prose-code))) + `(markup-comment-face ((,c :inherit font-lock-comment-face))) + `(markup-complex-replacement-face ((,c :foreground ,prose-macro))) + `(markup-emphasis-face ((,c :inherit markup-italic-face))) + `(markup-error-face ((,c :inherit error))) + `(markup-gen-face ((,c :foreground ,prose-verbatim))) + `(markup-internal-reference-face ((,c :inherit (shadow modus-themes-slant)))) + `(markup-italic-face ((,c :inherit italic))) + `(markup-list-face ((,c :background ,bg-inactive))) + `(markup-meta-face ((,c :inherit (modus-themes-fixed-pitch shadow)))) + `(markup-meta-hide-face ((,c :foreground "gray50"))) + `(markup-reference-face ((,c :inherit modus-themes-slant :foreground ,fg-alt))) + `(markup-replacement-face ((,c :inherit modus-themes-fixed-pitch :foreground ,err))) + `(markup-secondary-text-face ((,c :height 0.9 :foreground ,fg-alt))) + `(markup-small-face ((,c :inherit markup-gen-face :height 0.9))) + `(markup-strong-face ((,c :inherit markup-bold-face))) + `(markup-subscript-face ((,c :height 0.9 :foreground ,fg-alt))) + `(markup-superscript-face ((,c :height 0.9 :foreground ,fg-alt))) + `(markup-table-cell-face (( ))) + `(markup-table-face ((,c :foreground ,prose-table))) + `(markup-table-row-face (( ))) + `(markup-title-0-face ((,c :inherit modus-themes-heading-1))) + `(markup-title-1-face ((,c :inherit modus-themes-heading-2))) + `(markup-title-2-face ((,c :inherit modus-themes-heading-3))) + `(markup-title-3-face ((,c :inherit modus-themes-heading-4))) + `(markup-title-4-face ((,c :inherit modus-themes-heading-5))) + `(markup-title-5-face ((,c :inherit modus-themes-heading-6))) + `(markup-verbatim-face ((,c :inherit modus-themes-fixed-pitch :foreground ,prose-verbatim))) ;;;;; messages - `(message-cited-text-1 ((,class ,@(modus-themes--mail-cite blue-faint blue fg-special-cold)))) - `(message-cited-text-2 ((,class ,@(modus-themes--mail-cite yellow-faint yellow yellow-alt-faint)))) - `(message-cited-text-3 ((,class ,@(modus-themes--mail-cite magenta-alt-faint magenta-alt fg-special-calm)))) - `(message-cited-text-4 ((,class ,@(modus-themes--mail-cite cyan-alt-other-faint cyan-alt-other fg-special-mild)))) - `(message-header-cc ((,class :foreground ,blue-alt-other))) - `(message-header-name ((,class :inherit bold :foreground ,cyan))) - `(message-header-newsgroups ((,class :inherit message-header-other))) - `(message-header-other ((,class :foreground ,fg-special-calm))) - `(message-header-subject ((,class :inherit bold :foreground ,magenta-alt))) - `(message-header-to ((,class :inherit bold :foreground ,magenta-alt-other))) - `(message-header-xheader ((,class :foreground ,blue-alt))) - `(message-mml ((,class :foreground ,cyan-alt-other))) - `(message-separator ((,class :inherit modus-themes-intense-neutral))) -;;;;; mini-modeline - `(mini-modeline-mode-line ((,class :background ,blue-intense :height 0.14))) - `(mini-modeline-mode-line-inactive ((,class :background ,fg-window-divider-inner :height 0.1))) + `(message-cited-text-1 ((,c :foreground ,mail-cite-0))) + `(message-cited-text-2 ((,c :foreground ,mail-cite-1))) + `(message-cited-text-3 ((,c :foreground ,mail-cite-2))) + `(message-cited-text-4 ((,c :foreground ,mail-cite-3))) + `(message-header-name ((,c :inherit bold))) + `(message-header-newsgroups ((,c :inherit message-header-other))) + `(message-header-to ((,c :inherit bold :foreground ,mail-recipient))) + `(message-header-cc ((,c :foreground ,mail-recipient))) + `(message-header-subject ((,c :inherit bold :foreground ,mail-subject))) + `(message-header-xheader ((,c :inherit message-header-other))) + `(message-header-other ((,c :foreground ,mail-other))) + `(message-mml ((,c :foreground ,mail-part))) + `(message-separator ((,c :background ,bg-active))) ;;;;; minimap - `(minimap-active-region-background ((,class :background ,bg-active))) - `(minimap-current-line-face ((,class :background ,cyan-intense-bg :foreground ,fg-main))) -;;;;; mmm-mode - `(mmm-cleanup-submode-face ((,class :background ,yellow-nuanced-bg))) - `(mmm-code-submode-face ((,class :background ,bg-alt))) - `(mmm-comment-submode-face ((,class :background ,blue-nuanced-bg))) - `(mmm-declaration-submode-face ((,class :background ,cyan-nuanced-bg))) - `(mmm-default-submode-face ((,class :background ,bg-dim))) - `(mmm-init-submode-face ((,class :background ,magenta-nuanced-bg))) - `(mmm-output-submode-face ((,class :background ,red-nuanced-bg))) - `(mmm-special-submode-face ((,class :background ,green-nuanced-bg))) + `(minimap-active-region-background ((,c :background ,bg-active))) + `(minimap-current-line-face ((,c :background ,bg-cyan-intense :foreground ,fg-main))) ;;;;; mode-line - `(mode-line ((,class :inherit modus-themes-ui-variable-pitch - ,@(modus-themes--mode-line-attrs - fg-active bg-active - fg-dim bg-active - fg-main bg-active-accent - fg-alt bg-active - 'alt-style bg-main)))) - `(mode-line-active ((,class :inherit mode-line))) - `(mode-line-buffer-id ((,class :inherit bold))) - `(mode-line-emphasis ((,class :inherit bold :foreground ,magenta-active))) - `(mode-line-highlight ((,class ,@(if modus-themes-intense-mouseovers - (list :inherit 'modus-themes-active-blue) - (list :inherit 'highlight))))) - `(mode-line-inactive ((,class :inherit modus-themes-ui-variable-pitch - ,@(modus-themes--mode-line-attrs - fg-inactive bg-inactive - fg-alt bg-dim - fg-inactive bg-inactive - bg-region bg-active)))) + `(mode-line ((,c :inherit modus-themes-ui-variable-pitch + :box ,border-mode-line-active + :background ,bg-mode-line-active + :foreground ,fg-mode-line-active))) + `(mode-line-active ((,c :inherit mode-line))) + `(mode-line-buffer-id ((,c :inherit bold))) + `(mode-line-emphasis ((,c :inherit bold :foreground ,modeline-info))) + `(mode-line-highlight ((,c :background ,bg-hover :foreground ,fg-main :box ,fg-main))) + `(mode-line-inactive ((,c :inherit modus-themes-ui-variable-pitch + :box ,border-mode-line-inactive + :background ,bg-mode-line-inactive + :foreground ,fg-mode-line-inactive))) ;;;;; mood-line - `(mood-line-modified ((,class :foreground ,magenta-active))) - `(mood-line-status-error ((,class :inherit bold :foreground ,red-active))) - `(mood-line-status-info ((,class :foreground ,cyan-active))) - `(mood-line-status-neutral ((,class :foreground ,blue-active))) - `(mood-line-status-success ((,class :inherit modus-themes-grue-active))) - `(mood-line-status-warning ((,class :inherit bold :foreground ,yellow-active))) - `(mood-line-unimportant ((,class :foreground ,fg-inactive))) + `(mood-line-modified ((,c :inherit italic))) + `(mood-line-status-error ((,c :inherit error))) + `(mood-line-status-info ((,c :foreground ,info))) + `(mood-line-status-neutral (( ))) + `(mood-line-status-success ((,c :inherit success))) + `(mood-line-status-warning ((,c :inherit warning))) + `(mood-line-unimportant ((,c :inherit shadow))) ;;;;; mpdel - `(mpdel-browser-directory-face ((,class :foreground ,blue))) - `(mpdel-playlist-current-song-face ((,class :inherit bold :foreground ,blue-alt-other))) + `(mpdel-browser-directory-face ((,c :foreground ,accent-0))) + `(mpdel-playlist-current-song-face ((,c :inherit bold :foreground ,accent-0))) ;;;;; mu4e - `(mu4e-attach-number-face ((,class :inherit bold :foreground ,fg-dim))) - `(mu4e-cited-1-face ((,class :inherit message-cited-text-1))) - `(mu4e-cited-2-face ((,class :inherit message-cited-text-2))) - `(mu4e-cited-3-face ((,class :inherit message-cited-text-3))) - `(mu4e-cited-4-face ((,class :inherit message-cited-text-4))) - `(mu4e-cited-5-face ((,class :inherit message-cited-text-1))) - `(mu4e-cited-6-face ((,class :inherit message-cited-text-2))) - `(mu4e-cited-7-face ((,class :inherit message-cited-text-3))) - `(mu4e-compose-header-face ((,class :inherit mu4e-compose-separator-face))) - `(mu4e-compose-separator-face ((,class :inherit modus-themes-intense-neutral))) - `(mu4e-contact-face ((,class :inherit message-header-to))) - `(mu4e-context-face ((,class :foreground ,blue-active))) - `(mu4e-draft-face ((,class :foreground ,magenta-alt))) - `(mu4e-flagged-face ((,class :foreground ,red-alt-other))) - `(mu4e-footer-face ((,class :inherit modus-themes-slant :foreground ,fg-special-cold))) - `(mu4e-forwarded-face ((,class :foreground ,magenta-alt-other))) - `(mu4e-header-face ((,class :inherit shadow))) - `(mu4e-header-highlight-face ((,class :inherit modus-themes-hl-line))) - `(mu4e-header-key-face ((,class :inherit message-header-name))) - `(mu4e-header-marks-face ((,class :inherit mu4e-special-header-value-face))) - `(mu4e-header-title-face ((,class :foreground ,fg-special-mild))) - `(mu4e-header-value-face ((,class :inherit message-header-other))) - `(mu4e-highlight-face ((,class :inherit modus-themes-key-binding))) - `(mu4e-link-face ((,class :inherit button))) - `(mu4e-modeline-face ((,class :foreground ,magenta-active))) - `(mu4e-moved-face ((,class :inherit modus-themes-slant :foreground ,yellow))) - `(mu4e-ok-face ((,class :inherit bold :foreground ,green))) - `(mu4e-region-code ((,class :inherit modus-themes-special-calm))) - `(mu4e-related-face ((,class :inherit (italic shadow)))) - `(mu4e-replied-face ((,class :foreground ,blue))) - `(mu4e-special-header-value-face ((,class :inherit message-header-subject))) - `(mu4e-system-face ((,class :inherit modus-themes-slant :foreground ,fg-mark-del))) - `(mu4e-title-face ((,class :foreground ,fg-main))) - `(mu4e-trashed-face ((,class :foreground ,red))) - `(mu4e-unread-face ((,class :inherit bold))) - `(mu4e-url-number-face ((,class :inherit shadow))) - `(mu4e-view-body-face ((,class :foreground ,fg-main))) - `(mu4e-warning-face ((,class :inherit warning))) + `(mu4e-attach-number-face ((,c :inherit bold :foreground ,fg-dim))) + `(mu4e-cited-1-face ((,c :inherit message-cited-text-1))) + `(mu4e-cited-2-face ((,c :inherit message-cited-text-2))) + `(mu4e-cited-3-face ((,c :inherit message-cited-text-3))) + `(mu4e-cited-4-face ((,c :inherit message-cited-text-4))) + `(mu4e-cited-5-face ((,c :inherit message-cited-text-1))) + `(mu4e-cited-6-face ((,c :inherit message-cited-text-2))) + `(mu4e-cited-7-face ((,c :inherit message-cited-text-3))) + `(mu4e-compose-header-face ((,c :inherit mu4e-compose-separator-face))) + `(mu4e-compose-separator-face ((,c :inherit message-separator))) + `(mu4e-contact-face ((,c :inherit message-header-to))) + `(mu4e-context-face ((,c :inherit bold))) + `(mu4e-draft-face ((,c :foreground ,warning))) + `(mu4e-flagged-face ((,c :foreground ,err))) + `(mu4e-footer-face ((,c :inherit italic :foreground ,fg-alt))) + `(mu4e-forwarded-face ((,c :inherit italic :foreground ,info))) + `(mu4e-header-face ((,c :inherit shadow))) + `(mu4e-header-highlight-face ((,c :inherit highlight))) + `(mu4e-header-key-face ((,c :inherit message-header-name))) + `(mu4e-header-marks-face ((,c :inherit mu4e-special-header-value-face))) + `(mu4e-header-title-face ((,c :foreground ,fg-alt))) + `(mu4e-header-value-face ((,c :inherit message-header-other))) + `(mu4e-highlight-face ((,c :inherit modus-themes-key-binding))) + `(mu4e-link-face ((,c :inherit link))) + `(mu4e-modeline-face (( ))) + `(mu4e-moved-face ((,c :inherit italic :foreground ,warning))) + `(mu4e-ok-face ((,c :inherit success))) + `(mu4e-region-code ((,c :foreground ,builtin))) + `(mu4e-related-face ((,c :inherit (italic shadow)))) + `(mu4e-replied-face ((,c :foreground ,info))) + `(mu4e-special-header-value-face ((,c :inherit message-header-subject))) + `(mu4e-system-face ((,c :inherit italic))) + `(mu4e-title-face (( ))) + `(mu4e-trashed-face ((,c :foreground ,err))) + `(mu4e-unread-face ((,c :inherit bold))) + `(mu4e-url-number-face ((,c :inherit shadow))) + `(mu4e-view-body-face (( ))) + `(mu4e-warning-face ((,c :inherit warning))) ;;;;; multiple-cursors - `(mc/cursor-bar-face ((,class :height 1 :background ,fg-main))) - `(mc/cursor-face ((,class :inverse-video t))) - `(mc/region-face ((,class :inherit region))) -;;;;; nano-modeline - `(nano-modeline-active-primary ((,class :inherit mode-line :foreground ,fg-special-mild))) - `(nano-modeline-active-secondary ((,class :inherit mode-line :foreground ,fg-special-cold))) - `(nano-modeline-active-status-** ((,class :inherit mode-line :background ,yellow-subtle-bg))) - `(nano-modeline-active-status-RO ((,class :inherit mode-line :background ,red-subtle-bg))) - `(nano-modeline-active-status-RW ((,class :inherit mode-line :background ,cyan-subtle-bg))) - `(nano-modeline-inactive-primary ((,class :inherit mode-line-inactive :foreground ,fg-inactive))) - `(nano-modeline-inactive-secondary ((,class :inherit mode-line-inactive :foreground ,fg-inactive))) - `(nano-modeline-inactive-status-** ((,class :inherit mode-line-inactive :foreground ,yellow-active))) - `(nano-modeline-inactive-status-RO ((,class :inherit mode-line-inactive :foreground ,red-active))) - `(nano-modeline-inactive-status-RW ((,class :inherit mode-line-inactive :foreground ,cyan-active))) + `(mc/cursor-bar-face ((,c :height 1 :foreground ,fg-main :background ,bg-main))) + `(mc/cursor-face ((,c :inverse-video t))) + `(mc/region-face ((,c :inherit region))) ;;;;; neotree - `(neo-banner-face ((,class :foreground ,magenta))) - `(neo-button-face ((,class :inherit button))) - `(neo-dir-link-face ((,class :inherit bold :foreground ,blue))) - `(neo-expand-btn-face ((,class :foreground ,cyan))) - `(neo-file-link-face ((,class :foreground ,fg-main))) - `(neo-header-face ((,class :inherit bold :foreground ,fg-main))) - `(neo-root-dir-face ((,class :inherit bold :foreground ,cyan-alt))) - `(neo-vc-added-face ((,class :inherit modus-themes-grue))) - `(neo-vc-conflict-face ((,class :inherit error))) - `(neo-vc-default-face ((,class :foreground ,fg-main))) - `(neo-vc-edited-face ((,class :foreground ,yellow))) - `(neo-vc-ignored-face ((,class :foreground ,fg-inactive))) - `(neo-vc-missing-face ((,class :foreground ,red-alt))) - `(neo-vc-needs-merge-face ((,class :foreground ,magenta-alt))) - `(neo-vc-needs-update-face ((,class :underline t))) - `(neo-vc-removed-face ((,class :strike-through t))) - `(neo-vc-unlocked-changes-face ((,class :inherit modus-themes-refine-blue))) - `(neo-vc-up-to-date-face ((,class :inherit shadow))) - `(neo-vc-user-face ((,class :foreground ,magenta))) + `(neo-banner-face ((,c :foreground ,accent-0))) + `(neo-button-face ((,c :inherit button))) + `(neo-dir-link-face (( ))) + `(neo-expand-btn-face (( ))) + `(neo-file-link-face (( ))) + `(neo-header-face ((,c :inherit bold))) + `(neo-root-dir-face ((,c :inherit bold :foreground ,accent-0))) + `(neo-vc-added-face ((,c :inherit success))) + `(neo-vc-conflict-face ((,c :inherit error))) + `(neo-vc-default-face (( ))) + `(neo-vc-edited-face ((,c :inherit italic))) + `(neo-vc-ignored-face ((,c :inherit shadow))) + `(neo-vc-missing-face ((,c :inherit error))) + `(neo-vc-needs-merge-face ((,c :inherit italic))) + `(neo-vc-needs-update-face ((,c :underline t))) + `(neo-vc-removed-face ((,c :strike-through t))) + `(neo-vc-unlocked-changes-face ((,c :inherit success))) + `(neo-vc-up-to-date-face (( ))) + `(neo-vc-user-face ((,c :inherit warning))) ;;;;; notmuch - `(notmuch-crypto-decryption ((,class :inherit (shadow bold)))) - `(notmuch-crypto-part-header ((,class :foreground ,magenta-alt-other))) - `(notmuch-crypto-signature-bad ((,class :inherit error))) - `(notmuch-crypto-signature-good ((,class :inherit success))) - `(notmuch-crypto-signature-good-key ((,class :inherit bold :foreground ,cyan))) - `(notmuch-crypto-signature-unknown ((,class :inherit warning))) - `(notmuch-hello-logo-background ((,class :background "gray50"))) - `(notmuch-jump-key ((,class :inherit modus-themes-key-binding))) - `(notmuch-message-summary-face ((,class :inherit (bold modus-themes-nuanced-cyan)))) - `(notmuch-search-count ((,class :inherit shadow))) - `(notmuch-search-date ((,class :foreground ,cyan))) - `(notmuch-search-flagged-face ((,class :foreground ,red-alt-other))) - `(notmuch-search-matching-authors ((,class :foreground ,fg-special-cold))) - `(notmuch-search-non-matching-authors ((,class :inherit shadow))) - `(notmuch-search-subject ((,class :foreground ,fg-main))) - `(notmuch-search-unread-face ((,class :inherit bold))) - `(notmuch-tag-added ((,class :underline ,blue))) - `(notmuch-tag-deleted ((,class :strike-through ,red))) - `(notmuch-tag-face ((,class :foreground ,blue))) - `(notmuch-tag-flagged ((,class :foreground ,red-alt))) - `(notmuch-tag-unread ((,class :foreground ,magenta-alt))) - `(notmuch-tree-match-author-face ((,class :inherit notmuch-search-matching-authors))) - `(notmuch-tree-match-date-face ((,class :inherit notmuch-search-date))) - `(notmuch-tree-match-face ((,class :foreground ,fg-main))) - `(notmuch-tree-match-tag-face ((,class :inherit notmuch-tag-face))) - `(notmuch-tree-no-match-face ((,class :inherit shadow))) - `(notmuch-tree-no-match-date-face ((,class :inherit shadow))) - `(notmuch-wash-cited-text ((,class :inherit message-cited-text-1))) - `(notmuch-wash-toggle-button ((,class :background ,bg-alt :foreground ,fg-alt))) + `(notmuch-crypto-decryption ((,c :inherit bold))) + `(notmuch-crypto-part-header ((,c :foreground ,mail-part))) ; like `message-mml' + `(notmuch-crypto-signature-bad ((,c :inherit error))) + `(notmuch-crypto-signature-good ((,c :inherit success))) + `(notmuch-crypto-signature-good-key ((,c :inherit success))) + `(notmuch-crypto-signature-unknown ((,c :inherit warning))) + `(notmuch-jump-key ((,c :inherit modus-themes-key-binding))) + `(notmuch-message-summary-face ((,c :inherit bold :background ,bg-inactive))) + `(notmuch-search-count ((,c :foreground ,fg-dim))) + `(notmuch-search-date ((,c :foreground ,date-common))) + `(notmuch-search-flagged-face ((,c :foreground ,err))) + `(notmuch-search-matching-authors ((,c :foreground ,mail-recipient))) + `(notmuch-search-non-matching-authors ((,c :inherit shadow))) + `(notmuch-search-subject ((,c :foreground ,fg-main))) + `(notmuch-search-unread-face ((,c :inherit bold))) + `(notmuch-tag-added ((,c :underline ,info))) + `(notmuch-tag-deleted ((,c :strike-through ,err))) + `(notmuch-tag-face ((,c :foreground ,accent-0))) + `(notmuch-tag-flagged ((,c :foreground ,err))) + `(notmuch-tag-unread ((,c :foreground ,accent-1))) + `(notmuch-tree-match-author-face ((,c :inherit notmuch-search-matching-authors))) + `(notmuch-tree-match-date-face ((,c :inherit notmuch-search-date))) + `(notmuch-tree-match-face ((,c :foreground ,fg-main))) + `(notmuch-tree-match-tag-face ((,c :inherit notmuch-tag-face))) + `(notmuch-tree-no-match-face ((,c :inherit shadow))) + `(notmuch-tree-no-match-date-face ((,c :inherit shadow))) + `(notmuch-wash-cited-text ((,c :inherit message-cited-text-1))) + `(notmuch-wash-toggle-button ((,c :background ,bg-dim))) ;;;;; num3-mode - `(num3-face-even ((,class :inherit bold :background ,bg-alt))) + `(num3-face-even ((,c :inherit bold :background ,bg-inactive))) ;;;;; nxml-mode - `(nxml-attribute-colon ((,class :foreground ,fg-main))) - `(nxml-attribute-local-name ((,class :inherit font-lock-variable-name-face))) - `(nxml-attribute-prefix ((,class :inherit font-lock-type-face))) - `(nxml-attribute-value ((,class :inherit font-lock-constant-face))) - `(nxml-cdata-section-CDATA ((,class :inherit error))) - `(nxml-cdata-section-delimiter ((,class :inherit error))) - `(nxml-char-ref-delimiter ((,class :foreground ,fg-special-mild))) - `(nxml-char-ref-number ((,class :inherit modus-themes-bold :foreground ,fg-special-mild))) - `(nxml-delimited-data ((,class :inherit modus-themes-slant :foreground ,fg-special-cold))) - `(nxml-delimiter ((,class :foreground ,fg-dim))) - `(nxml-element-colon ((,class :foreground ,fg-main))) - `(nxml-element-local-name ((,class :inherit font-lock-function-name-face))) - `(nxml-element-prefix ((,class :inherit font-lock-builtin-face))) - `(nxml-entity-ref-delimiter ((,class :foreground ,fg-special-mild))) - `(nxml-entity-ref-name ((,class :inherit modus-themes-bold :foreground ,fg-special-mild))) - `(nxml-glyph ((,class :inherit modus-themes-intense-neutral))) - `(nxml-hash ((,class :inherit (bold font-lock-string-face)))) - `(nxml-heading ((,class :inherit bold))) - `(nxml-name ((,class :inherit font-lock-builtin-face))) - `(nxml-namespace-attribute-colon ((,class :foreground ,fg-main))) - `(nxml-namespace-attribute-prefix ((,class :inherit font-lock-variable-name-face))) - `(nxml-processing-instruction-target ((,class :inherit font-lock-keyword-face))) - `(nxml-prolog-keyword ((,class :inherit font-lock-keyword-face))) - `(nxml-ref ((,class :inherit modus-themes-bold :foreground ,fg-special-mild))) - `(rng-error ((,class :inherit error))) + `(nxml-attribute-colon ((,c :foreground ,fg-main))) + `(nxml-attribute-local-name ((,c :inherit font-lock-variable-name-face))) + `(nxml-attribute-prefix ((,c :inherit font-lock-type-face))) + `(nxml-attribute-value ((,c :inherit font-lock-constant-face))) + `(nxml-cdata-section-CDATA ((,c :inherit error))) + `(nxml-cdata-section-delimiter ((,c :inherit error))) + `(nxml-char-ref-delimiter ((,c :inherit shadow))) + `(nxml-char-ref-number ((,c :inherit (shadow modus-themes-bold)))) + `(nxml-delimited-data ((,c :inherit (shadow modus-themes-slant)))) + `(nxml-delimiter ((,c :foreground ,fg-dim))) + `(nxml-element-colon ((,c :foreground ,fg-main))) + `(nxml-element-local-name ((,c :inherit font-lock-function-name-face))) + `(nxml-element-prefix ((,c :inherit font-lock-builtin-face))) + `(nxml-entity-ref-delimiter ((,c :inherit shadow))) + `(nxml-entity-ref-name ((,c :inherit (shadow modus-themes-bold)))) + `(nxml-glyph ((,c :background ,bg-active :foreground ,fg-main))) + `(nxml-hash ((,c :inherit (bold font-lock-string-face)))) + `(nxml-heading ((,c :inherit bold))) + `(nxml-name ((,c :inherit font-lock-builtin-face))) + `(nxml-namespace-attribute-colon ((,c :foreground ,fg-main))) + `(nxml-namespace-attribute-prefix ((,c :inherit font-lock-variable-name-face))) + `(nxml-processing-instruction-target ((,c :inherit font-lock-keyword-face))) + `(nxml-prolog-keyword ((,c :inherit font-lock-keyword-face))) + `(nxml-ref ((,c :inherit (shadow modus-themes-bold)))) + `(rng-error ((,c :inherit error))) ;;;;; olivetti - `(olivetti-fringe ((,class :background ,bg-main))) + `(olivetti-fringe ((,c :background ,bg-main))) ;;;;; orderless - `(orderless-match-face-0 ((,class :inherit modus-themes-completion-match-0))) - `(orderless-match-face-1 ((,class :inherit modus-themes-completion-match-1))) - `(orderless-match-face-2 ((,class :inherit modus-themes-completion-match-2))) - `(orderless-match-face-3 ((,class :inherit modus-themes-completion-match-3))) + `(orderless-match-face-0 ((,c :inherit modus-themes-completion-match-0))) + `(orderless-match-face-1 ((,c :inherit modus-themes-completion-match-1))) + `(orderless-match-face-2 ((,c :inherit modus-themes-completion-match-2))) + `(orderless-match-face-3 ((,c :inherit modus-themes-completion-match-3))) ;;;;; org - `(org-agenda-calendar-event ((,class ,@(modus-themes--agenda-event blue-alt)))) - `(org-agenda-calendar-sexp ((,class ,@(modus-themes--agenda-event blue-alt t)))) - `(org-agenda-clocking ((,class :background ,yellow-nuanced-bg :foreground ,red-alt))) - `(org-agenda-column-dateline ((,class :background ,bg-alt))) - `(org-agenda-current-time ((,class :foreground ,blue-alt-other-faint))) - `(org-agenda-date ((,class ,@(modus-themes--agenda-date cyan fg-main)))) - `(org-agenda-date-today - ((,class ,@(modus-themes--agenda-date cyan fg-main nil nil bg-special-cold t t)))) - `(org-agenda-date-weekend - ((,class ,@(modus-themes--agenda-date cyan-alt-other-faint fg-alt cyan fg-main)))) - `(org-agenda-date-weekend-today - ((,class ,@(modus-themes--agenda-date cyan-alt-other-faint fg-alt cyan fg-main bg-special-cold t t)))) - `(org-agenda-diary ((,class :inherit org-agenda-calendar-sexp))) - `(org-agenda-dimmed-todo-face ((,class :inherit shadow))) - `(org-agenda-done ((,class :inherit modus-themes-grue-nuanced))) - `(org-agenda-filter-category ((,class :inherit bold :foreground ,cyan-active))) - `(org-agenda-filter-effort ((,class :inherit bold :foreground ,cyan-active))) - `(org-agenda-filter-regexp ((,class :inherit bold :foreground ,cyan-active))) - `(org-agenda-filter-tags ((,class :inherit bold :foreground ,cyan-active))) - `(org-agenda-restriction-lock ((,class :background ,bg-dim :foreground ,fg-dim))) - `(org-agenda-structure ((,class ,@(modus-themes--agenda-structure blue-alt)))) - `(org-agenda-structure-filter ((,class :inherit org-agenda-structure :foreground ,yellow))) - `(org-agenda-structure-secondary ((,class :foreground ,cyan))) - `(org-archived ((,class :background ,bg-alt :foreground ,fg-alt))) - `(org-block ((,class :inherit modus-themes-fixed-pitch - ,@(modus-themes--org-block bg-dim fg-main)))) - `(org-block-begin-line ((,class :inherit modus-themes-fixed-pitch - ,@(modus-themes--org-block-delim - bg-dim fg-special-cold - bg-alt fg-alt)))) - `(org-block-end-line ((,class :inherit org-block-begin-line))) - `(org-checkbox ((,class :foreground ,yellow-alt-other))) - `(org-checkbox-statistics-done ((,class :inherit org-done))) - `(org-checkbox-statistics-todo ((,class :inherit org-todo))) - `(org-clock-overlay ((,class :background ,yellow-nuanced-bg :foreground ,red-alt-faint))) - `(org-code ((,class :inherit modus-themes-markup-code :extend t))) - `(org-column ((,class :inherit (modus-themes-fixed-pitch default) - :background ,bg-alt))) - `(org-column-title ((,class :inherit (bold modus-themes-fixed-pitch default) - :underline t :background ,bg-alt))) - `(org-date ((,class :inherit (modus-themes-link-symlink modus-themes-fixed-pitch)))) - `(org-date-selected ((,class :foreground ,blue-alt :inverse-video t))) - `(org-dispatcher-highlight ((,class :inherit (bold modus-themes-mark-alt)))) - `(org-document-info ((,class :foreground ,fg-special-cold))) - `(org-document-info-keyword ((,class :inherit (shadow modus-themes-fixed-pitch)))) - `(org-document-title ((,class :inherit modus-themes-heading-0))) - `(org-done ((,class :inherit modus-themes-grue))) - `(org-drawer ((,class :inherit (shadow modus-themes-fixed-pitch)))) - `(org-ellipsis (())) ; inherits from the heading's color - `(org-footnote ((,class :inherit button - ,@(modus-themes--link-color - blue-alt blue-alt-faint)))) - `(org-formula ((,class :inherit modus-themes-fixed-pitch :foreground ,red-alt))) - `(org-habit-alert-face ((,class ,@(modus-themes--agenda-habit - yellow-graph-0-bg - yellow-graph-0-bg - yellow-graph-1-bg) - :foreground "black"))) ; special case - `(org-habit-alert-future-face ((,class ,@(modus-themes--agenda-habit - yellow-graph-1-bg - yellow-graph-0-bg - yellow-graph-1-bg)))) - `(org-habit-clear-face ((,class ,@(modus-themes--agenda-habit - blue-graph-0-bg - green-graph-1-bg - blue-graph-1-bg - blue-graph-1-bg - blue-graph-1-bg) - :foreground "black"))) ; special case - `(org-habit-clear-future-face ((,class ,@(modus-themes--agenda-habit - blue-graph-1-bg - green-graph-1-bg - blue-graph-1-bg - blue-graph-1-bg - blue-graph-1-bg)))) - `(org-habit-overdue-face ((,class ,@(modus-themes--agenda-habit - red-graph-0-bg - red-graph-0-bg - red-graph-1-bg)))) - `(org-habit-overdue-future-face ((,class ,@(modus-themes--agenda-habit - red-graph-1-bg - red-graph-0-bg - red-graph-1-bg)))) - `(org-habit-ready-face ((,class ,@(modus-themes--agenda-habit - green-graph-0-bg - green-graph-0-bg - green-graph-1-bg - cyan-graph-0-bg - blue-graph-0-bg - cyan-graph-1-bg) - :foreground "black"))) ; special case - `(org-habit-ready-future-face ((,class ,@(modus-themes--agenda-habit - green-graph-1-bg - green-graph-0-bg - green-graph-1-bg - cyan-graph-1-bg - blue-graph-0-bg - cyan-graph-1-bg)))) - `(org-headline-done ((,class :inherit (modus-themes-variable-pitch modus-themes-grue-nuanced)))) - `(org-headline-todo ((,class :inherit modus-themes-variable-pitch :foreground ,red-nuanced-fg))) - `(org-hide ((,class :foreground ,bg-main))) - `(org-indent ((,class :inherit (fixed-pitch org-hide)))) - `(org-imminent-deadline ((,class :foreground ,red-intense))) - `(org-latex-and-related ((,class :foreground ,magenta-faint))) - `(org-level-1 ((,class :inherit modus-themes-heading-1))) - `(org-level-2 ((,class :inherit modus-themes-heading-2))) - `(org-level-3 ((,class :inherit modus-themes-heading-3))) - `(org-level-4 ((,class :inherit modus-themes-heading-4))) - `(org-level-5 ((,class :inherit modus-themes-heading-5))) - `(org-level-6 ((,class :inherit modus-themes-heading-6))) - `(org-level-7 ((,class :inherit modus-themes-heading-7))) - `(org-level-8 ((,class :inherit modus-themes-heading-8))) - `(org-link ((,class :inherit button))) - `(org-list-dt ((,class :inherit bold))) - `(org-macro ((,class :inherit modus-themes-markup-macro))) - `(org-meta-line ((,class :inherit (shadow modus-themes-fixed-pitch)))) - `(org-mode-line-clock ((,class :foreground ,fg-main))) - `(org-mode-line-clock-overrun ((,class :inherit bold :foreground ,red-active))) - `(org-priority ((,class :foreground ,magenta))) - `(org-property-value ((,class :inherit modus-themes-fixed-pitch :foreground ,fg-special-cold))) - `(org-quote ((,class ,@(modus-themes--org-block bg-dim fg-special-cold fg-main)))) - `(org-scheduled ((,class ,@(modus-themes--agenda-scheduled yellow-faint fg-special-warm magenta-alt)))) - `(org-scheduled-previously ((,class ,@(modus-themes--agenda-scheduled yellow fg-special-warm yellow-alt-other)))) - `(org-scheduled-today ((,class ,@(modus-themes--agenda-scheduled yellow fg-special-warm magenta-alt-other)))) - `(org-sexp-date ((,class :foreground ,cyan-alt-other))) - `(org-special-keyword ((,class :inherit (shadow modus-themes-fixed-pitch)))) - `(org-table ((,class :inherit modus-themes-fixed-pitch :foreground ,fg-special-cold))) - `(org-table-header ((,class :inherit (fixed-pitch modus-themes-special-cold)))) - `(org-tag ((,class :foreground ,magenta-nuanced-fg))) - `(org-tag-group ((,class :inherit bold :foreground ,cyan-nuanced-fg))) - `(org-target ((,class :underline t))) - `(org-time-grid ((,class :inherit shadow))) - `(org-todo ((,class :foreground ,red))) - `(org-upcoming-deadline ((,class :foreground ,red-alt-other))) - `(org-upcoming-distant-deadline ((,class :foreground ,red-faint))) - `(org-verbatim ((,class :inherit modus-themes-markup-verbatim))) - `(org-verse ((,class :inherit org-quote))) - `(org-warning ((,class :inherit bold :foreground ,red-alt-other))) + `(org-agenda-calendar-event ((,c :foreground ,date-event))) + `(org-agenda-calendar-sexp ((,c :inherit (italic org-agenda-calendar-event)))) + `(org-agenda-clocking ((,c :inherit modus-themes-mark-alt))) + `(org-agenda-column-dateline ((,c :background ,bg-inactive))) + `(org-agenda-current-time ((,c :foreground ,date-now))) + `(org-agenda-date ((,c ,@(modus-themes--heading 'agenda-date date-weekday)))) + `(org-agenda-date-today ((,c :inherit org-agenda-date :underline t))) + `(org-agenda-date-weekend ((,c :inherit org-agenda-date :foreground ,date-weekend))) + `(org-agenda-date-weekend-today ((,c :inherit org-agenda-date-today :foreground ,date-weekend))) + `(org-agenda-diary ((,c :inherit org-agenda-calendar-sexp))) + `(org-agenda-dimmed-todo-face ((,c :inherit shadow))) + `(org-agenda-done ((,c :inherit org-done))) + `(org-agenda-filter-category ((,c :inherit bold :foreground ,modeline-err))) + `(org-agenda-filter-effort ((,c :inherit bold :foreground ,modeline-err))) + `(org-agenda-filter-regexp ((,c :inherit bold :foreground ,modeline-err))) + `(org-agenda-filter-tags ((,c :inherit bold :foreground ,modeline-err))) + `(org-agenda-restriction-lock ((,c :background ,bg-dim :foreground ,fg-dim))) + `(org-agenda-structure ((,c ,@(modus-themes--heading 'agenda-structure fg-alt)))) + `(org-agenda-structure-filter ((,c :inherit org-agenda-structure :foreground ,warning))) + `(org-agenda-structure-secondary ((,c :inherit font-lock-doc-face))) + `(org-archived ((,c :background ,bg-inactive :foreground ,fg-main))) + `(org-block ((,c ,@(modus-themes--org-block fg-main bg-dim)))) + `(org-block-begin-line ((,c ,@(modus-themes--org-block prose-block bg-inactive)))) + `(org-block-end-line ((,c :inherit org-block-begin-line))) + `(org-checkbox ((,c :foreground ,warning))) + `(org-checkbox-statistics-done ((,c :inherit org-done))) + `(org-checkbox-statistics-todo ((,c :inherit org-todo))) + `(org-clock-overlay ((,c :inherit secondary-selection))) + `(org-code ((,c :inherit modus-themes-prose-code))) + `(org-column ((,c :inherit default :background ,bg-dim))) + `(org-column-title ((,c :inherit (bold default) :underline t :background ,bg-dim))) + `(org-date ((,c :inherit modus-themes-fixed-pitch :foreground ,date-common))) + `(org-date-selected ((,c :foreground ,date-common :inverse-video t))) + `(org-document-info ((,c :foreground ,prose-metadata-value))) + `(org-document-info-keyword ((,c :foreground ,prose-metadata))) + `(org-document-title ((,c :inherit modus-themes-heading-0))) + `(org-done ((,c :foreground ,prose-done))) + `(org-drawer ((,c :inherit modus-themes-fixed-pitch :foreground ,prose-metadata))) + `(org-ellipsis (( ))) ; inherits from the heading's color + `(org-footnote ((,c :inherit link))) + `(org-formula ((,c :inherit modus-themes-fixed-pitch :foreground ,fnname))) + `(org-headline-done ((,c :inherit org-done))) + `(org-headline-todo ((,c :inherit org-todo))) + `(org-hide ((,c :foreground ,bg-main))) + `(org-indent ((,c :inherit (fixed-pitch org-hide)))) + `(org-imminent-deadline ((,c :inherit bold :foreground ,date-deadline))) + `(org-latex-and-related ((,c :foreground ,type))) + `(org-level-1 ((,c :inherit modus-themes-heading-1))) + `(org-level-2 ((,c :inherit modus-themes-heading-2))) + `(org-level-3 ((,c :inherit modus-themes-heading-3))) + `(org-level-4 ((,c :inherit modus-themes-heading-4))) + `(org-level-5 ((,c :inherit modus-themes-heading-5))) + `(org-level-6 ((,c :inherit modus-themes-heading-6))) + `(org-level-7 ((,c :inherit modus-themes-heading-7))) + `(org-level-8 ((,c :inherit modus-themes-heading-8))) + `(org-link ((,c :inherit link))) + `(org-list-dt ((,c :inherit bold))) + `(org-macro ((,c :inherit modus-themes-prose-macro))) + `(org-meta-line ((,c :inherit modus-themes-fixed-pitch :foreground ,prose-metadata))) + `(org-mode-line-clock (( ))) + `(org-mode-line-clock-overrun ((,c :inherit bold :foreground ,modeline-err))) + `(org-priority ((,c :foreground ,prose-tag))) + `(org-property-value ((,c :inherit modus-themes-fixed-pitch :foreground ,prose-metadata-value))) + `(org-quote ((,c :inherit org-block))) + `(org-scheduled ((,c :foreground ,date-scheduled))) + `(org-scheduled-previously ((,c :inherit org-scheduled))) + `(org-scheduled-today ((,c :inherit (bold org-scheduled)))) + `(org-sexp-date ((,c :foreground ,date-common))) + `(org-special-keyword ((,c :inherit org-drawer))) + `(org-table ((,c :inherit modus-themes-fixed-pitch :foreground ,prose-table))) + `(org-table-header ((,c :inherit (bold org-table)))) + `(org-tag ((,c :foreground ,prose-tag))) + `(org-tag-group ((,c :inherit (bold org-tag)))) + `(org-target ((,c :underline t))) + `(org-time-grid ((,c :foreground ,fg-dim))) + `(org-todo ((,c :foreground ,prose-todo))) + `(org-upcoming-deadline ((,c :foreground ,date-deadline))) + `(org-upcoming-distant-deadline ((,c :inherit org-upcoming-deadline))) + `(org-verbatim ((,c :inherit modus-themes-prose-verbatim))) + `(org-verse ((,c :inherit org-block))) + `(org-warning ((,c :inherit warning))) +;;;;; org-habit + `(org-habit-alert-face ((,c :background ,bg-graph-yellow-0 :foreground "black"))) ; fg is special case + `(org-habit-alert-future-face ((,c :background ,bg-graph-yellow-1))) + `(org-habit-clear-face ((,c :background ,bg-graph-blue-0 :foreground "black"))) ; fg is special case + `(org-habit-clear-future-face ((,c :background ,bg-graph-blue-1))) + `(org-habit-overdue-face ((,c :background ,bg-graph-red-0))) + `(org-habit-overdue-future-face ((,c :background ,bg-graph-red-1))) + `(org-habit-ready-face ((,c :background ,bg-graph-blue-0 :foreground "black"))) ; fg is special case + `(org-habit-ready-future-face ((,c :background ,bg-graph-blue-1))) ;;;;; org-journal - `(org-journal-calendar-entry-face ((,class :inherit modus-themes-slant :foreground ,yellow-alt-other))) - `(org-journal-calendar-scheduled-face ((,class :inherit modus-themes-slant :foreground ,red-alt-other))) - `(org-journal-highlight ((,class :foreground ,magenta-alt))) + `(org-journal-calendar-entry-face ((,c :inherit modus-themes-slant :foreground ,date-common))) + `(org-journal-calendar-scheduled-face ((,c :inherit (modus-themes-slant org-scheduled)))) + `(org-journal-highlight ((,c :foreground ,err))) ;;;;; org-noter - `(org-noter-no-notes-exist-face ((,class :inherit error))) - `(org-noter-notes-exist-face ((,class :inherit success))) + `(org-noter-no-notes-exist-face ((,c :inherit error))) + `(org-noter-notes-exist-face ((,c :inherit success))) ;;;;; org-pomodoro - `(org-pomodoro-mode-line ((,class :foreground ,red-active))) - `(org-pomodoro-mode-line-break ((,class :foreground ,cyan-active))) - `(org-pomodoro-mode-line-overtime ((,class :inherit bold :foreground ,red-active))) + `(org-pomodoro-mode-line ((,c :foreground ,err))) + `(org-pomodoro-mode-line-break ((,c :foreground ,info))) + `(org-pomodoro-mode-line-overtime ((,c :inherit error))) ;;;;; org-recur - `(org-recur ((,class :foreground ,magenta-active))) + `(org-recur ((,c :foreground ,fg-alt))) ;;;;; org-roam - `(org-roam-dim ((,class :foreground "gray50"))) - `(org-roam-header-line ((,class :inherit bold :foreground ,magenta-active))) - `(org-roam-olp ((,class :inherit shadow))) - `(org-roam-preview-heading ((,class :inherit modus-themes-subtle-neutral))) - `(org-roam-preview-heading-highlight ((,class :inherit modus-themes-intense-neutral))) - `(org-roam-preview-heading-selection ((,class :inherit modus-themes-special-cold))) - `(org-roam-preview-region ((,class :inherit bold))) - `(org-roam-title ((,class :inherit modus-themes-pseudo-header))) + `(org-roam-dim ((,c :foreground "gray50"))) + `(org-roam-olp ((,c :inherit shadow))) + `(org-roam-preview-heading ((,c :background ,bg-inactive))) + `(org-roam-preview-heading-highlight ((,c :background ,bg-active :foreground ,fg-main))) + `(org-roam-preview-region ((,c :inherit bold))) + `(org-roam-title ((,c :inherit bold))) ;;;;; org-superstar - `(org-superstar-item ((,class :foreground ,fg-main))) - `(org-superstar-leading ((,class :foreground ,fg-whitespace))) -;;;;; org-table-sticky-header - `(org-table-sticky-header-face ((,class :inherit modus-themes-special-cold))) + `(org-superstar-item ((,c :foreground ,fg-main))) ;;;;; org-tree-slide - `(org-tree-slide-header-overlay-face ((,class :inherit org-document-title))) + `(org-tree-slide-header-overlay-face ((,c :inherit org-document-title))) ;;;;; origami - `(origami-fold-header-face ((,class :background ,bg-dim :foreground ,fg-dim :box t))) - `(origami-fold-replacement-face ((,class :background ,bg-alt :foreground ,fg-alt))) + `(origami-fold-header-face ((,c :background ,bg-dim :foreground ,fg-dim :box t))) + `(origami-fold-replacement-face ((,c :background ,bg-inactive :foreground ,fg-dim))) ;;;;; outline-mode - `(outline-1 ((,class :inherit modus-themes-heading-1))) - `(outline-2 ((,class :inherit modus-themes-heading-2))) - `(outline-3 ((,class :inherit modus-themes-heading-3))) - `(outline-4 ((,class :inherit modus-themes-heading-4))) - `(outline-5 ((,class :inherit modus-themes-heading-5))) - `(outline-6 ((,class :inherit modus-themes-heading-6))) - `(outline-7 ((,class :inherit modus-themes-heading-7))) - `(outline-8 ((,class :inherit modus-themes-heading-8))) + `(outline-1 ((,c :inherit modus-themes-heading-1))) + `(outline-2 ((,c :inherit modus-themes-heading-2))) + `(outline-3 ((,c :inherit modus-themes-heading-3))) + `(outline-4 ((,c :inherit modus-themes-heading-4))) + `(outline-5 ((,c :inherit modus-themes-heading-5))) + `(outline-6 ((,c :inherit modus-themes-heading-6))) + `(outline-7 ((,c :inherit modus-themes-heading-7))) + `(outline-8 ((,c :inherit modus-themes-heading-8))) ;;;;; outline-minor-faces `(outline-minor-0 (())) ;;;;; package (M-x list-packages) - `(package-description ((,class :foreground ,fg-special-cold))) - `(package-help-section-name ((,class :inherit bold :foreground ,cyan))) - `(package-name ((,class :inherit button))) - `(package-status-available ((,class :foreground ,cyan-alt-other))) - `(package-status-avail-obso ((,class :inherit error))) - `(package-status-built-in ((,class :foreground ,magenta))) - `(package-status-dependency ((,class :foreground ,magenta-alt-other))) - `(package-status-disabled ((,class :inherit modus-themes-subtle-red))) - `(package-status-external ((,class :foreground ,cyan-alt-other))) - `(package-status-held ((,class :foreground ,yellow-alt))) - `(package-status-incompat ((,class :inherit warning))) - `(package-status-installed ((,class :foreground ,fg-special-warm))) - `(package-status-new ((,class :inherit success))) - `(package-status-unsigned ((,class :inherit error))) + `(package-description ((,c :foreground ,docstring))) + `(package-help-section-name ((,c :inherit bold))) + `(package-name ((,c :inherit link))) + `(package-status-available ((,c :foreground ,date-common))) + `(package-status-avail-obso ((,c :inherit error))) + `(package-status-built-in ((,c :foreground ,builtin))) + `(package-status-dependency ((,c :foreground ,warning))) + `(package-status-disabled ((,c :inherit error :strike-through t))) + `(package-status-from-source ((,c :foreground ,type))) + `(package-status-held ((,c :foreground ,warning))) + `(package-status-incompat ((,c :inherit warning))) + `(package-status-installed ((,c :foreground ,fg-alt))) + `(package-status-new ((,c :inherit success))) + `(package-status-unsigned ((,c :inherit error))) ;;;;; page-break-lines - `(page-break-lines ((,class :inherit default :foreground ,fg-window-divider-outer))) + `(page-break-lines ((,c :inherit default :foreground "gray50"))) ;;;;; pandoc-mode - `(pandoc-citation-key-face ((,class :background ,bg-dim :foreground ,magenta-alt))) - `(pandoc-directive-@@-face ((,class :background ,bg-dim :foreground ,blue-alt-other))) - `(pandoc-directive-braces-face ((,class :foreground ,blue-alt-other))) - `(pandoc-directive-contents-face ((,class :foreground ,cyan-alt-other))) - `(pandoc-directive-type-face ((,class :foreground ,magenta))) + `(pandoc-citation-key-face ((,c :inherit font-lock-builtin-face))) + `(pandoc-directive-@@-face ((,c :inherit font-lock-keyword-face))) + `(pandoc-directive-braces-face ((,c :inherit font-lock-constant-face))) + `(pandoc-directive-contents-face ((,c :inherit font-lock-string-face))) + `(pandoc-directive-type-face ((,c :inherit font-lock-type-face))) ;;;;; paren-face - `(parenthesis ((,class :foreground ,fg-unfocused))) + `(parenthesis ((,c :inherit shadow))) ;;;;; pass - `(pass-mode-directory-face ((,class :inherit bold :foreground ,fg-special-cold))) - `(pass-mode-entry-face ((,class :background ,bg-main :foreground ,fg-main))) - `(pass-mode-header-face ((,class :foreground ,fg-special-warm))) + `(pass-mode-directory-face ((,c :inherit bold :foreground ,accent-0))) + `(pass-mode-entry-face ((,c :background ,bg-main :foreground ,fg-main))) + `(pass-mode-header-face ((,c :inherit shadow))) ;;;;; pdf-tools - `(pdf-links-read-link ((,class :background ,fg-main :foreground ,magenta-intense-bg :inherit bold))) ; Foreground is background and vice versa - `(pdf-occur-document-face ((,class :inherit shadow))) - `(pdf-occur-page-face ((,class :inherit shadow))) + `(pdf-links-read-link ((,c :background ,fg-main :foreground ,bg-magenta-intense :inherit bold))) ; Foreground is background and vice versa + `(pdf-occur-document-face ((,c :inherit shadow))) + `(pdf-occur-page-face ((,c :inherit shadow))) ;;;;; persp-mode - `(persp-face-lighter-buffer-not-in-persp ((,class :inherit modus-themes-intense-red))) - `(persp-face-lighter-default ((,class :inherit bold :foreground ,blue-active))) - `(persp-face-lighter-nil-persp ((,class :inherit bold :foreground ,fg-active))) + `(persp-face-lighter-buffer-not-in-persp ((,c :inherit error))) + `(persp-face-lighter-default ((,c :inherit bold :foreground ,name))) + `(persp-face-lighter-nil-persp ((,c :inherit bold))) ;;;;; perspective - `(persp-selected-face ((,class :inherit bold :foreground ,blue-active))) -;;;;; phi-grep - `(phi-grep-heading-face ((,class :inherit modus-themes-pseudo-header :foreground ,fg-special-cold))) - `(phi-grep-line-number-face ((,class :foreground ,fg-special-warm))) - `(phi-grep-match-face ((,class :inherit modus-themes-special-calm))) - `(phi-grep-modified-face ((,class :inherit modus-themes-refine-yellow))) - `(phi-grep-overlay-face ((,class :inherit modus-themes-refine-blue))) -;;;;; pomidor - `(pomidor-break-face ((,class :foreground ,blue-alt-other))) - `(pomidor-overwork-face ((,class :foreground ,red-alt-other))) - `(pomidor-skip-face ((,class :inherit (shadow modus-themes-slant)))) - `(pomidor-work-face ((,class :inherit modus-themes-grue))) + `(persp-selected-face ((,c :inherit bold :foreground ,name))) ;;;;; popup - `(popup-face ((,class :background ,bg-alt :foreground ,fg-main))) - `(popup-isearch-match ((,class :inherit modus-themes-search-success))) - `(popup-menu-mouse-face ((,class :inherit highlight))) - `(popup-menu-selection-face ((,class :inherit modus-themes-completion-selected-popup))) - `(popup-scroll-bar-background-face ((,class :background ,bg-active))) - `(popup-scroll-bar-foreground-face ((,class :foreground ,fg-active))) - `(popup-summary-face ((,class :background ,bg-active :foreground ,fg-inactive))) - `(popup-tip-face ((,class :inherit modus-themes-refine-yellow))) + `(popup-face ((,c :background ,bg-inactive :foreground ,fg-main))) + `(popup-isearch-match ((,c :inherit modus-themes-search-current))) + `(popup-menu-mouse-face ((,c :inherit highlight))) + `(popup-menu-selection-face ((,c :inherit modus-themes-completion-selected))) + `(popup-scroll-bar-background-face ((,c :background ,bg-active))) + `(popup-scroll-bar-foreground-face (( ))) + `(popup-summary-face ((,c :background ,bg-active :foreground ,fg-dim))) + `(popup-tip-face ((,c :inherit modus-themes-intense-yellow))) ;;;;; powerline - `(powerline-active0 ((,class :background ,fg-unfocused :foreground ,bg-main))) - `(powerline-active1 ((,class :inherit mode-line-active))) - `(powerline-active2 ((,class :inherit mode-line-inactive))) - `(powerline-inactive0 ((,class :background ,bg-active :foreground ,fg-alt))) - `(powerline-inactive1 ((,class :background ,bg-main :foreground ,fg-alt))) - `(powerline-inactive2 ((,class :inherit mode-line-inactive))) + `(powerline-active0 ((,c :background ,fg-dim :foreground ,bg-main))) + `(powerline-active1 ((,c :inherit mode-line-active))) + `(powerline-active2 ((,c :inherit mode-line-inactive))) + `(powerline-inactive0 ((,c :background ,bg-active :foreground ,fg-dim))) + `(powerline-inactive1 ((,c :background ,bg-main :foreground ,fg-dim))) + `(powerline-inactive2 ((,c :inherit mode-line-inactive))) ;;;;; powerline-evil - `(powerline-evil-base-face ((,class :background ,fg-main :foreground ,bg-main))) - `(powerline-evil-emacs-face ((,class :inherit modus-themes-active-magenta))) - `(powerline-evil-insert-face ((,class :inherit modus-themes-active-green))) - `(powerline-evil-motion-face ((,class :inherit modus-themes-active-blue))) - `(powerline-evil-normal-face ((,class :background ,fg-alt :foreground ,bg-main))) - `(powerline-evil-operator-face ((,class :inherit modus-themes-active-yellow))) - `(powerline-evil-replace-face ((,class :inherit modus-themes-active-red))) - `(powerline-evil-visual-face ((,class :inherit modus-themes-active-cyan))) + `(powerline-evil-base-face ((,c :background ,fg-main :foreground ,bg-main))) + `(powerline-evil-emacs-face ((,c :inherit modus-themes-intense-magenta))) + `(powerline-evil-insert-face ((,c :inherit modus-themes-intense-green))) + `(powerline-evil-motion-face ((,c :inherit modus-themes-intense-blue))) + `(powerline-evil-normal-face ((,c :background ,fg-alt :foreground ,bg-main))) + `(powerline-evil-operator-face ((,c :inherit modus-themes-intense-yellow))) + `(powerline-evil-replace-face ((,c :inherit modus-themes-intense-red))) + `(powerline-evil-visual-face ((,c :inherit modus-themes-intense-cyan))) ;;;;; prescient - `(prescient-primary-highlight ((,class :inherit modus-themes-completion-match-0))) - `(prescient-secondary-highlight ((,class :inherit modus-themes-completion-match-1))) + `(prescient-primary-highlight ((,c :inherit modus-themes-completion-match-0))) + `(prescient-secondary-highlight ((,c :inherit modus-themes-completion-match-1))) ;;;;; proced - `(proced-mark ((,class :inherit modus-themes-mark-symbol))) - `(proced-marked ((,class :inherit modus-themes-mark-alt))) - `(proced-sort-header ((,class :inherit bold :foreground ,fg-special-calm :underline t))) + `(proced-mark ((,c :inherit bold))) + `(proced-marked ((,c :inherit modus-themes-mark-alt))) + `(proced-sort-header ((,c :inherit bold :underline t))) ;;;;; prodigy - `(prodigy-green-face ((,class :inherit success))) - `(prodigy-red-face ((,class :inherit error))) - `(prodigy-yellow-face ((,class :inherit warning))) + `(prodigy-green-face ((,c :inherit success))) + `(prodigy-red-face ((,c :inherit error))) + `(prodigy-yellow-face ((,c :inherit warning))) ;;;;; pulse - `(pulse-highlight-start-face ((,class :background ,bg-active-accent :extend t))) + `(pulse-highlight-start-face ((,c :background ,bg-blue-intense :extend t))) ;;;;; pyim - `(pyim-page ((,class :background ,bg-active :foreground ,fg-active))) - `(pyim-page-selection ((,class :inherit bold :background ,bg-active :foreground ,blue-active))) - `(pyim-page-subword ((,class :background ,bg-inactive))) + `(pyim-page ((,c :background ,bg-active))) + `(pyim-page-selection ((,c :inherit bold :background ,bg-active :foreground ,info))) + `(pyim-page-subword ((,c :background ,bg-inactive))) ;;;;; quick-peek - `(quick-peek-background-face ((,class :background ,bg-alt))) - `(quick-peek-border-face ((,class :background ,fg-window-divider-inner :height 1))) - `(quick-peek-padding-face ((,class :background ,bg-alt :height 0.15))) -;;;;; racket-mode - `(racket-debug-break-face ((,class :inherit modus-themes-intense-red))) - `(racket-debug-locals-face ((,class :box (:line-width -1 :color nil) - :foreground ,green-alt-other))) - `(racket-debug-result-face ((,class :inherit bold :box (:line-width -1 :color nil) - :foreground ,green))) - `(racket-here-string-face ((,class :foreground ,blue-alt))) - `(racket-keyword-argument-face ((,class :foreground ,red-alt))) - `(racket-logger-config-face ((,class :inherit (shadow modus-themes-slant)))) - `(racket-logger-debug-face ((,class :foreground ,blue-alt-other))) - `(racket-logger-info-face ((,class :foreground ,fg-lang-note))) - `(racket-logger-topic-face ((,class :inherit modus-themes-slant :foreground ,magenta))) - `(racket-selfeval-face ((,class :foreground ,green-alt))) - `(racket-xp-error-face ((,class :inherit modus-themes-lang-error))) -;;;;; rainbow-blocks - `(rainbow-blocks-depth-1-face ((,class :foreground ,magenta-alt-other))) - `(rainbow-blocks-depth-2-face ((,class :foreground ,blue))) - `(rainbow-blocks-depth-3-face ((,class :foreground ,magenta-alt))) - `(rainbow-blocks-depth-4-face ((,class :foreground ,green))) - `(rainbow-blocks-depth-5-face ((,class :foreground ,magenta))) - `(rainbow-blocks-depth-6-face ((,class :foreground ,cyan))) - `(rainbow-blocks-depth-7-face ((,class :foreground ,yellow))) - `(rainbow-blocks-depth-8-face ((,class :foreground ,cyan-alt))) - `(rainbow-blocks-depth-9-face ((,class :foreground ,red-alt))) - `(rainbow-blocks-unmatched-face ((,class :foreground ,red))) + `(quick-peek-background-face ((,c :background ,bg-inactive))) + `(quick-peek-border-face ((,c :background ,border :height 1))) + `(quick-peek-padding-face ((,c :background ,bg-inactive :height 0.15))) ;;;;; rainbow-delimiters - `(rainbow-delimiters-base-error-face ((,class :background ,red-subtle-bg :foreground ,fg-main))) - `(rainbow-delimiters-base-face ((,class :foreground ,fg-main))) - `(rainbow-delimiters-depth-1-face ((,class :foreground ,fg-main))) - `(rainbow-delimiters-depth-2-face ((,class :foreground ,magenta-intense))) - `(rainbow-delimiters-depth-3-face ((,class :foreground ,cyan-intense))) - `(rainbow-delimiters-depth-4-face ((,class :foreground ,orange-intense))) - `(rainbow-delimiters-depth-5-face ((,class :foreground ,purple-intense))) - `(rainbow-delimiters-depth-6-face ((,class :foreground ,green-intense))) - `(rainbow-delimiters-depth-7-face ((,class :foreground ,red-intense))) - `(rainbow-delimiters-depth-8-face ((,class :foreground ,blue-intense))) - `(rainbow-delimiters-depth-9-face ((,class :foreground ,yellow-intense))) - `(rainbow-delimiters-mismatched-face ((,class :inherit (bold modus-themes-refine-yellow)))) - `(rainbow-delimiters-unmatched-face ((,class :inherit (bold modus-themes-refine-red)))) + `(rainbow-delimiters-base-error-face ((,c :inherit modus-themes-subtle-red))) + `(rainbow-delimiters-base-face ((,c :foreground ,fg-main))) + `(rainbow-delimiters-depth-1-face ((,c :foreground ,rainbow-0))) + `(rainbow-delimiters-depth-2-face ((,c :foreground ,rainbow-1))) + `(rainbow-delimiters-depth-3-face ((,c :foreground ,rainbow-2))) + `(rainbow-delimiters-depth-4-face ((,c :foreground ,rainbow-3))) + `(rainbow-delimiters-depth-5-face ((,c :foreground ,rainbow-4))) + `(rainbow-delimiters-depth-6-face ((,c :foreground ,rainbow-5))) + `(rainbow-delimiters-depth-7-face ((,c :foreground ,rainbow-6))) + `(rainbow-delimiters-depth-8-face ((,c :foreground ,rainbow-7))) + `(rainbow-delimiters-depth-9-face ((,c :foreground ,rainbow-8))) + `(rainbow-delimiters-mismatched-face ((,c :inherit (bold modus-themes-intense-yellow)))) + `(rainbow-delimiters-unmatched-face ((,c :inherit (bold modus-themes-intense-red)))) ;;;;; rcirc - `(rcirc-bright-nick ((,class :inherit bold :foreground ,magenta-intense))) - `(rcirc-dim-nick ((,class :inherit shadow))) - `(rcirc-monospace-text ((,class :inherit fixed-pitch))) - `(rcirc-my-nick ((,class :inherit bold :foreground ,magenta))) - `(rcirc-nick-in-message ((,class :inherit bold :foreground ,red-alt))) - `(rcirc-nick-in-message-full-line ((,class :inherit bold :foreground ,cyan-alt-other))) - `(rcirc-other-nick ((,class :inherit bold :foreground ,blue))) - `(rcirc-prompt ((,class :inherit modus-themes-prompt))) - `(rcirc-server ((,class :inherit shadow))) - `(rcirc-timestamp ((,class :foreground ,cyan))) - `(rcirc-track-keyword ((,class :inherit bold))) - `(rcirc-track-nick ((,class :inherit bold :foreground ,red-active))) - `(rcirc-url ((,class :inherit link))) + `(rcirc-bright-nick ((,c :inherit bold :foreground ,accent-2))) + `(rcirc-dim-nick ((,c :inherit shadow))) + `(rcirc-monospace-text ((,c :inherit fixed-pitch))) + `(rcirc-my-nick ((,c :inherit bold :foreground ,accent-1))) + `(rcirc-nick-in-message ((,c :inherit rcirc-my-nick))) + `(rcirc-nick-in-message-full-line ((,c :inherit rcirc-my-nick))) + `(rcirc-other-nick ((,c :inherit bold :foreground ,accent-0))) + `(rcirc-prompt ((,c :inherit minibuffer-prompt))) + `(rcirc-server ((,c :inherit font-lock-comment-face))) + `(rcirc-timestamp ((,c :foreground ,date-common))) + `(rcirc-track-keyword ((,c :inherit bold :foreground ,modeline-warning))) + `(rcirc-track-nick ((,c :inherit rcirc-my-nick))) + `(rcirc-url ((,c :inherit link))) ;;;;; recursion-indicator - `(recursion-indicator-general ((,class :foreground ,blue-active))) - `(recursion-indicator-minibuffer ((,class :foreground ,red-active))) + `(recursion-indicator-general ((,c :foreground ,modeline-err))) + `(recursion-indicator-minibuffer ((,c :foreground ,modeline-info))) ;;;;; regexp-builder (re-builder) - `(reb-match-0 ((,class :inherit modus-themes-refine-cyan))) - `(reb-match-1 ((,class :inherit modus-themes-subtle-magenta))) - `(reb-match-2 ((,class :inherit modus-themes-subtle-green))) - `(reb-match-3 ((,class :inherit modus-themes-refine-yellow))) - `(reb-regexp-grouping-backslash ((,class :inherit font-lock-regexp-grouping-backslash))) - `(reb-regexp-grouping-construct ((,class :inherit font-lock-regexp-grouping-construct))) + `(reb-match-0 ((,c :inherit modus-themes-intense-cyan))) + `(reb-match-1 ((,c :inherit modus-themes-subtle-magenta))) + `(reb-match-2 ((,c :inherit modus-themes-subtle-green))) + `(reb-match-3 ((,c :inherit modus-themes-intense-yellow))) + `(reb-regexp-grouping-backslash ((,c :inherit font-lock-regexp-grouping-backslash))) + `(reb-regexp-grouping-construct ((,c :inherit font-lock-regexp-grouping-construct))) ;;;;; rg (rg.el) - `(rg-column-number-face ((,class :foreground ,magenta-alt-other))) - `(rg-context-face ((,class :foreground ,fg-unfocused))) - `(rg-error-face ((,class :inherit bold :foreground ,red))) - `(rg-file-tag-face ((,class :foreground ,fg-special-cold))) - `(rg-filename-face ((,class :inherit bold :foreground ,fg-special-cold))) - `(rg-line-number-face ((,class :foreground ,fg-special-warm))) - `(rg-literal-face ((,class :foreground ,blue-alt))) - `(rg-match-face ((,class :inherit modus-themes-special-calm))) - `(rg-regexp-face ((,class :foreground ,magenta-active))) - `(rg-toggle-off-face ((,class :inherit bold :foreground ,fg-inactive))) - `(rg-toggle-on-face ((,class :inherit bold :foreground ,cyan-active))) - `(rg-warning-face ((,class :inherit bold :foreground ,yellow))) + `(rg-column-number-face ((,c :inherit shadow))) + `(rg-context-face ((,c :inherit shadow))) + `(rg-error-face ((,c :inherit error))) + `(rg-file-tag-face ((,c :inherit font-lock-builtin-face))) + `(rg-filename-face ((,c :inherit bold :foreground ,name))) + `(rg-line-number-face ((,c :inherit shadow))) + `(rg-literal-face ((,c :inherit font-lock-constant-face))) + `(rg-match-face ((,c :inherit match))) + `(rg-regexp-face ((,c :foreground ,name))) + `(rg-toggle-off-face ((,c :inherit (shadow bold)))) + `(rg-toggle-on-face ((,c :inherit success))) + `(rg-warning-face ((,c :inherit warning))) ;;;;; ripgrep - `(ripgrep-context-face ((,class :foreground ,fg-unfocused))) - `(ripgrep-error-face ((,class :inherit bold :foreground ,red))) - `(ripgrep-hit-face ((,class :foreground ,cyan))) - `(ripgrep-match-face ((,class :inherit modus-themes-special-calm))) + `(ripgrep-context-face ((,c :inherit shadow))) + `(ripgrep-error-face ((,c :inherit error))) + `(ripgrep-hit-face ((,c :inherit success))) + `(ripgrep-match-face ((,c :inherit match))) ;;;;; rmail - `(rmail-header-name ((,class :foreground ,cyan-alt-other))) - `(rmail-highlight ((,class :inherit bold :foreground ,magenta-alt))) + `(rmail-header-name ((,c :inherit bold))) + `(rmail-highlight ((,c :inherit bold :foreground ,mail-other))) ;;;;; ruler-mode - `(ruler-mode-column-number ((,class :inherit ruler-mode-default :foreground ,fg-main))) - `(ruler-mode-comment-column ((,class :inherit ruler-mode-default :foreground ,red))) - `(ruler-mode-current-column ((,class :inherit ruler-mode-default :background ,blue-subtle-bg :foreground ,fg-main))) - `(ruler-mode-default ((,class :inherit default :background ,bg-alt :foreground ,fg-unfocused))) - `(ruler-mode-fill-column ((,class :inherit ruler-mode-default :foreground ,green))) - `(ruler-mode-fringes ((,class :inherit ruler-mode-default :foreground ,cyan))) - `(ruler-mode-goal-column ((,class :inherit ruler-mode-default :foreground ,blue))) - `(ruler-mode-margins ((,class :inherit ruler-mode-default :foreground ,bg-main))) - `(ruler-mode-pad ((,class :inherit ruler-mode-default :background ,bg-active :foreground ,fg-inactive))) - `(ruler-mode-tab-stop ((,class :inherit ruler-mode-default :foreground ,fg-special-warm))) -;;;;; selectrum - `(selectrum-current-candidate ((,class :inherit modus-themes-completion-selected))) - `(selectrum-mouse-highlight ((,class :inherit highlight))) - `(selectrum-quick-keys-highlight ((,class :inherit bold :background ,bg-char-0))) - `(selectrum-quick-keys-match ((,class :inherit bold :background ,bg-char-1))) -;;;;; semantic - `(semantic-complete-inline-face ((,class :foreground ,fg-special-warm :underline t))) - `(semantic-decoration-on-fileless-includes ((,class :inherit modus-themes-refine-green))) - `(semantic-decoration-on-private-members-face ((,class :inherit modus-themes-refine-cyan))) - `(semantic-decoration-on-protected-members-face ((,class :background ,bg-dim))) - `(semantic-decoration-on-unknown-includes ((,class :inherit modus-themes-refine-red))) - `(semantic-decoration-on-unparsed-includes ((,class :inherit modus-themes-refine-yellow))) - `(semantic-highlight-edits-face ((,class :background ,bg-alt))) - `(semantic-highlight-func-current-tag-face ((,class :background ,bg-alt))) - `(semantic-idle-symbol-highlight ((,class :inherit modus-themes-special-mild))) - `(semantic-tag-boundary-face ((,class :overline ,blue-intense))) - `(semantic-unmatched-syntax-face ((,class :underline ,fg-lang-error))) + `(ruler-mode-column-number ((,c :inherit ruler-mode-default))) + `(ruler-mode-comment-column ((,c :inherit ruler-mode-default :foreground ,red))) + `(ruler-mode-current-column ((,c :inherit ruler-mode-default :background ,bg-active :foreground ,fg-main))) + `(ruler-mode-default ((,c :inherit default :background ,bg-dim :foreground ,fg-dim))) + `(ruler-mode-fill-column ((,c :inherit ruler-mode-default :foreground ,green))) + `(ruler-mode-fringes ((,c :inherit ruler-mode-default :foreground ,cyan))) + `(ruler-mode-goal-column ((,c :inherit ruler-mode-default :foreground ,blue))) + `(ruler-mode-margins ((,c :inherit ruler-mode-default :foreground ,bg-main))) + `(ruler-mode-pad ((,c :inherit ruler-mode-default :background ,bg-inactive :foreground ,fg-dim))) + `(ruler-mode-tab-stop ((,c :inherit ruler-mode-default :foreground ,yellow))) ;;;;; sesman - `(sesman-browser-button-face ((,class :inherit button))) - `(sesman-browser-highligh-face ((,class :inherit highlight))) - `(sesman-buffer-face ((,class :foreground ,magenta))) - `(sesman-directory-face ((,class :inherit bold :foreground ,blue))) - `(sesman-project-face ((,class :inherit bold :foreground ,magenta-alt-other))) + `(sesman-browser-button-face ((,c :inherit button))) + `(sesman-browser-highligh-face ((,c :inherit highlight))) + `(sesman-buffer-face ((,c :foreground ,accent-1))) + `(sesman-directory-face ((,c :inherit bold :foreground ,accent-0))) + `(sesman-project-face ((,c :inherit bold :foreground ,accent-2))) ;;;;; shell-script-mode - `(sh-heredoc ((,class :foreground ,blue-alt))) - `(sh-quoted-exec ((,class :inherit modus-themes-bold :foreground ,magenta-alt))) + `(sh-heredoc ((,c :inherit font-lock-string-face))) + `(sh-quoted-exec ((,c :inherit font-lock-builtin-face))) ;;;;; shortdoc - `(shortdoc-heading ((,class :inherit modus-themes-pseudo-header))) + `(shortdoc-heading ((,c :inherit bold))) `(shortdoc-section (())) ; remove the default's variable-pitch style ;;;;; show-paren-mode - `(show-paren-match ((,class ,@(modus-themes--paren bg-paren-match - bg-paren-match-intense) - :foreground ,fg-main))) - `(show-paren-match-expression ((,class :background ,bg-paren-expression))) - `(show-paren-mismatch ((,class :inherit modus-themes-intense-red))) + `(show-paren-match ((,c :background ,bg-paren-match :foreground ,fg-main :underline ,underline-paren-match))) + `(show-paren-match-expression ((,c :background ,bg-paren-expression))) + `(show-paren-mismatch ((,c :inherit modus-themes-intense-red))) ;;;;; shr - `(shr-abbreviation ((,class :inherit modus-themes-lang-note))) - `(shr-code ((,class :inherit modus-themes-markup-verbatim))) - `(shr-h1 ((,class :inherit modus-themes-heading-1))) - `(shr-h2 ((,class :inherit modus-themes-heading-2))) - `(shr-h3 ((,class :inherit modus-themes-heading-3))) - `(shr-h4 ((,class :inherit modus-themes-heading-4))) - `(shr-h5 ((,class :inherit modus-themes-heading-5))) - `(shr-h6 ((,class :inherit modus-themes-heading-6))) - `(shr-selected-link ((,class :inherit modus-themes-subtle-red))) + `(shr-abbreviation ((,c :inherit modus-themes-lang-note))) + `(shr-code ((,c :inherit modus-themes-prose-verbatim))) + `(shr-h1 ((,c :inherit modus-themes-heading-1))) + `(shr-h2 ((,c :inherit modus-themes-heading-2))) + `(shr-h3 ((,c :inherit modus-themes-heading-3))) + `(shr-h4 ((,c :inherit modus-themes-heading-4))) + `(shr-h5 ((,c :inherit modus-themes-heading-5))) + `(shr-h6 ((,c :inherit modus-themes-heading-6))) + `(shr-selected-link ((,c :inherit modus-themes-subtle-red))) ;;;;; side-notes - `(side-notes ((,class :background ,bg-dim :foreground ,fg-dim))) + `(side-notes ((,c :background ,bg-dim :foreground ,fg-dim))) ;;;;; sieve-mode - `(sieve-action-commands ((,class :inherit font-lock-builtin-face))) - `(sieve-control-commands ((,class :inherit font-lock-keyword-face))) - `(sieve-tagged-arguments ((,class :inherit font-lock-type-face))) - `(sieve-test-commands ((,class :inherit font-lock-function-name-face))) + `(sieve-action-commands ((,c :inherit font-lock-builtin-face))) + `(sieve-control-commands ((,c :inherit font-lock-keyword-face))) + `(sieve-tagged-arguments ((,c :inherit font-lock-type-face))) + `(sieve-test-commands ((,c :inherit font-lock-function-name-face))) ;;;;; skewer-mode - `(skewer-error-face ((,class :foreground ,red :underline t))) + `(skewer-error-face ((,c :inherit modus-themes-lang-error))) ;;;;; slime (sldb) - `(sldb-condition-face ((,class :inherit font-lock-preprocessor-face))) - `(sldb-restart-number-face ((,class :inherit bold))) - `(sldb-restart-type-face ((,class :inherit font-lock-type-face))) - `(sldb-restartable-frame-line-face ((,class :inherit success))) - `(sldb-section-face ((,class :inherit modus-themes-pseudo-header))) - `(slime-error-face ((,class :inherit modus-themes-lang-error))) - `(slime-note-face ((,class :underline t))) - `(slime-repl-input-face ((,class :inherit bold))) - `(slime-repl-inputed-output-face ((,class :inherit font-lock-string-face))) - `(slime-repl-output-mouseover-face ((,class :inherit highlight))) - `(slime-repl-prompt-face ((,class :inherit modus-themes-prompt))) - `(slime-style-warning-face ((,class :inherit modus-themes-lang-note))) - `(slime-warning-face ((,class :inherit modus-themes-lang-warning))) + `(sldb-condition-face ((,c :inherit font-lock-preprocessor-face))) + `(sldb-restart-number-face ((,c :inherit bold))) + `(sldb-restart-type-face ((,c :inherit font-lock-type-face))) + `(sldb-restartable-frame-line-face ((,c :inherit success))) + `(sldb-section-face ((,c :inherit bold))) + `(slime-error-face ((,c :inherit modus-themes-lang-error))) + `(slime-note-face ((,c :underline t))) + `(slime-repl-input-face ((,c :inherit bold))) + `(slime-repl-inputed-output-face ((,c :inherit font-lock-string-face))) + `(slime-repl-output-mouseover-face ((,c :inherit highlight))) + `(slime-repl-prompt-face ((,c :inherit modus-themes-prompt))) + `(slime-style-warning-face ((,c :inherit modus-themes-lang-note))) + `(slime-warning-face ((,c :inherit modus-themes-lang-warning))) ;;;;; sly - `(sly-action-face ((,class :inherit font-lock-type-face))) - `(sly-db-condition-face ((,class :inherit font-lock-preprocessor-face))) - `(sly-db-restartable-frame-line-face ((,class :inherit success))) - `(sly-error-face ((,class :inherit modus-themes-lang-error))) - `(sly-mode-line ((,class :inherit mode-line-emphasis))) - `(sly-mrepl-output-face ((,class :inherit font-lock-string-face))) - `(sly-mrepl-output-face ((,class :inherit font-lock-string-face))) - `(sly-mrepl-prompt-face ((,class :inherit modus-themes-prompt))) - `(sly-note-face ((,class :inherit modus-themes-lang-note))) - `(sly-stickers-placed-face ((,class :inherit modus-themes-subtle-neutral))) - `(sly-style-warning-face ((,class :inherit modus-themes-lang-note))) - `(sly-warning-face ((,class :inherit modus-themes-lang-warning))) + `(sly-action-face ((,c :inherit font-lock-type-face))) + `(sly-db-condition-face ((,c :inherit font-lock-preprocessor-face))) + `(sly-db-restartable-frame-line-face ((,c :inherit success))) + `(sly-error-face ((,c :inherit modus-themes-lang-error))) + `(sly-mode-line ((,c :inherit mode-line-emphasis))) + `(sly-mrepl-output-face ((,c :inherit font-lock-string-face))) + `(sly-mrepl-output-face ((,c :inherit font-lock-string-face))) + `(sly-mrepl-prompt-face ((,c :inherit modus-themes-prompt))) + `(sly-note-face ((,c :inherit modus-themes-lang-note))) + `(sly-stickers-placed-face ((,c :background ,bg-inactive))) + `(sly-style-warning-face ((,c :inherit modus-themes-lang-note))) + `(sly-warning-face ((,c :inherit modus-themes-lang-warning))) ;;;;; smart-mode-line - `(sml/charging ((,class :foreground ,green-active))) - `(sml/discharging ((,class :foreground ,red-active))) - `(sml/filename ((,class :inherit bold :foreground ,blue-active))) - `(sml/folder ((,class :foreground ,fg-active))) - `(sml/git ((,class :inherit bold :foreground ,green-active))) - `(sml/global ((,class :foreground ,fg-active))) - `(sml/line-number ((,class :inherit sml/global))) - `(sml/minor-modes ((,class :inherit sml/global))) - `(sml/modes ((,class :inherit bold :foreground ,fg-active))) - `(sml/modified ((,class :inherit bold :foreground ,magenta-active))) - `(sml/mule-info ((,class :inherit sml/global))) - `(sml/name-filling ((,class :foreground ,yellow-active))) - `(sml/not-modified ((,class :inherit sml/global))) - `(sml/numbers-separator ((,class :inherit sml/global))) - `(sml/outside-modified ((,class :inherit modus-themes-intense-red))) - `(sml/position-percentage ((,class :inherit sml/global))) - `(sml/prefix ((,class :foreground ,green-active))) - `(sml/process ((,class :inherit sml/prefix))) - `(sml/projectile ((,class :inherit sml/git))) - `(sml/read-only ((,class :inherit bold :foreground ,cyan-active))) - `(sml/remote ((,class :inherit sml/global))) - `(sml/sudo ((,class :inherit modus-themes-subtle-red))) - `(sml/time ((,class :inherit sml/global))) - `(sml/vc ((,class :inherit sml/git))) - `(sml/vc-edited ((,class :inherit bold :foreground ,yellow-active))) -;;;;; smartparens - `(sp-pair-overlay-face ((,class :inherit modus-themes-special-warm))) - `(sp-show-pair-enclosing ((,class :inherit modus-themes-special-mild))) - `(sp-show-pair-match-face ((,class ,@(modus-themes--paren bg-paren-match - bg-paren-match-intense) - :foreground ,fg-main))) - `(sp-show-pair-mismatch-face ((,class :inherit modus-themes-intense-red))) - `(sp-wrap-overlay-closing-pair ((,class :inherit sp-pair-overlay-face))) - `(sp-wrap-overlay-face ((,class :inherit sp-pair-overlay-face))) - `(sp-wrap-overlay-opening-pair ((,class :inherit sp-pair-overlay-face))) - `(sp-wrap-tag-overlay-face ((,class :inherit sp-pair-overlay-face))) + `(sml/charging ((,c :foreground ,info))) + `(sml/discharging ((,c :foreground ,err))) + `(sml/filename ((,c :inherit bold :foreground ,name))) + `(sml/folder (( ))) + `(sml/git ((,c :inherit success))) + `(sml/global (( ))) + `(sml/line-number ((,c :inherit sml/global))) + `(sml/minor-modes ((,c :inherit sml/global))) + `(sml/modes ((,c :inherit bold))) + `(sml/modified ((,c :inherit italic))) + `(sml/mule-info ((,c :inherit sml/global))) + `(sml/name-filling ((,c :inherit warning))) + `(sml/not-modified ((,c :inherit sml/global))) + `(sml/numbers-separator ((,c :inherit sml/global))) + `(sml/outside-modified ((,c :inherit modus-themes-intense-red))) + `(sml/position-percentage ((,c :inherit sml/global))) + `(sml/prefix ((,c :foreground ,fg-alt))) + `(sml/process ((,c :inherit sml/prefix))) + `(sml/projectile ((,c :inherit sml/git))) + `(sml/read-only (( ))) + `(sml/remote ((,c :inherit sml/global))) + `(sml/sudo ((,c :inherit warning))) + `(sml/time ((,c :inherit sml/global))) + `(sml/vc ((,c :inherit sml/git))) + `(sml/vc-edited ((,c :inherit italic))) ;;;;; smerge - `(smerge-base ((,class :inherit modus-themes-diff-changed))) - `(smerge-lower ((,class :inherit modus-themes-diff-added))) - `(smerge-markers ((,class :inherit modus-themes-diff-heading))) - `(smerge-refined-added ((,class :inherit modus-themes-diff-refine-added))) + `(smerge-base ((,c :inherit diff-changed))) + `(smerge-lower ((,c :inherit diff-added))) + `(smerge-markers ((,c :inherit diff-heading))) + `(smerge-refined-added ((,c :inherit diff-refine-added))) `(smerge-refined-changed (())) - `(smerge-refined-removed ((,class :inherit modus-themes-diff-refine-removed))) - `(smerge-upper ((,class :inherit modus-themes-diff-removed))) -;;;;; spaceline - `(spaceline-evil-emacs ((,class :inherit modus-themes-active-magenta))) - `(spaceline-evil-insert ((,class :inherit modus-themes-active-green))) - `(spaceline-evil-motion ((,class :inherit modus-themes-active-blue))) - `(spaceline-evil-normal ((,class :background ,fg-alt :foreground ,bg-alt))) - `(spaceline-evil-replace ((,class :inherit modus-themes-active-red))) - `(spaceline-evil-visual ((,class :inherit modus-themes-active-cyan))) - `(spaceline-flycheck-error ((,class :foreground ,red-active))) - `(spaceline-flycheck-info ((,class :foreground ,cyan-active))) - `(spaceline-flycheck-warning ((,class :foreground ,yellow-active))) - `(spaceline-highlight-face ((,class :inherit modus-themes-fringe-blue))) - `(spaceline-modified ((,class :inherit modus-themes-fringe-magenta))) - `(spaceline-python-venv ((,class :foreground ,magenta-active))) - `(spaceline-read-only ((,class :inherit modus-themes-fringe-red))) - `(spaceline-unmodified ((,class :inherit modus-themes-fringe-cyan))) + `(smerge-refined-removed ((,c :inherit diff-refine-removed))) + `(smerge-upper ((,c :inherit diff-removed))) ;;;;; speedbar - `(speedbar-button-face ((,class :inherit button))) - `(speedbar-directory-face ((,class :inherit bold :foreground ,blue))) - `(speedbar-file-face ((,class :foreground ,fg-main))) - `(speedbar-highlight-face ((,class :inherit highlight))) - `(speedbar-selected-face ((,class :inherit bold :foreground ,cyan))) - `(speedbar-separator-face ((,class :inherit modus-themes-intense-neutral))) - `(speedbar-tag-face ((,class :foreground ,yellow-alt-other))) + `(speedbar-button-face ((,c :inherit button))) + `(speedbar-directory-face ((,c :inherit bold :foreground ,accent-0))) + `(speedbar-file-face ((,c :foreground ,fg-main))) + `(speedbar-highlight-face ((,c :inherit highlight))) + `(speedbar-selected-face ((,c :inherit modus-themes-mark-sel))) + `(speedbar-separator-face ((,c :background ,bg-active :foreground ,fg-main))) + `(speedbar-tag-face ((,c :foreground ,accent-1))) ;;;;; spell-fu - `(spell-fu-incorrect-face ((,class :inherit modus-themes-lang-error))) + `(spell-fu-incorrect-face ((,c :inherit modus-themes-lang-error))) ;;;;; stripes - `(stripes ((,class :background ,bg-alt))) + `(stripes ((,c :background ,bg-inactive))) ;;;;; suggest - `(suggest-heading ((,class :inherit bold :foreground ,yellow-alt-other))) + `(suggest-heading ((,c :inherit warning))) ;;;;; switch-window - `(switch-window-background ((,class :background ,bg-dim))) - `(switch-window-label ((,class :height 3.0 :foreground ,blue-intense))) + `(switch-window-background ((,c :background ,bg-inactive))) + `(switch-window-label ((,c :height 3.0 :foreground ,red-intense))) ;;;;; swiper `(swiper-background-match-face-1 (( ))) - `(swiper-background-match-face-2 ((,class :inherit modus-themes-completion-match-0))) - `(swiper-background-match-face-3 ((,class :inherit modus-themes-completion-match-1))) - `(swiper-background-match-face-4 ((,class :inherit modus-themes-completion-match-2))) - `(swiper-line-face ((,class :background ,bg-hl-alt-intense))) + `(swiper-background-match-face-2 ((,c :inherit modus-themes-completion-match-0))) + `(swiper-background-match-face-3 ((,c :inherit modus-themes-completion-match-1))) + `(swiper-background-match-face-4 ((,c :inherit modus-themes-completion-match-2))) + `(swiper-line-face ((,c :inherit highlight))) `(swiper-match-face-1 (( ))) - `(swiper-match-face-2 ((,class :inherit modus-themes-completion-match-0))) - `(swiper-match-face-3 ((,class :inherit modus-themes-completion-match-1))) - `(swiper-match-face-4 ((,class :inherit modus-themes-completion-match-2))) -;;;;; sx - `(sx-inbox-item-type ((,class :foreground ,magenta-alt-other))) - `(sx-inbox-item-type-unread ((,class :inherit (sx-inbox-item-type bold)))) - `(sx-question-list-answers ((,class :foreground ,green))) - `(sx-question-list-answers-accepted ((,class :box t :foreground ,green))) - `(sx-question-list-bounty ((,class :inherit bold :background ,bg-alt :foreground ,yellow))) - `(sx-question-list-date ((,class :foreground ,fg-special-cold))) - `(sx-question-list-favorite ((,class :inherit bold :foreground ,fg-special-warm))) - `(sx-question-list-parent ((,class :foreground ,fg-main))) - `(sx-question-list-read-question ((,class :inherit shadow))) - `(sx-question-list-score ((,class :foreground ,fg-special-mild))) - `(sx-question-list-score-upvoted ((,class :inherit (sx-question-list-score bold)))) - `(sx-question-list-unread-question ((,class :inherit bold :foreground ,fg-main))) - `(sx-question-mode-accepted ((,class :inherit bold :height 1.3 :foreground ,green))) - `(sx-question-mode-closed ((,class :inherit modus-themes-active-yellow :box (:line-width 2 :color nil)))) - `(sx-question-mode-closed-reason ((,class :box (:line-width 2 :color nil) :foreground ,fg-main))) - `(sx-question-mode-content-face ((,class :background ,bg-dim))) - `(sx-question-mode-date ((,class :foreground ,blue))) - `(sx-question-mode-header ((,class :inherit bold :foreground ,cyan))) - `(sx-question-mode-kbd-tag ((,class :inherit bold :height 0.9 :box (:line-width 3 :color ,fg-main :style released-button) :foreground ,fg-main))) - `(sx-question-mode-score ((,class :foreground ,fg-dim))) - `(sx-question-mode-score-downvoted ((,class :foreground ,yellow))) - `(sx-question-mode-score-upvoted ((,class :inherit bold :foreground ,magenta))) - `(sx-question-mode-title ((,class :inherit bold :foreground ,fg-main))) - `(sx-question-mode-title-comments ((,class :inherit (shadow bold)))) - `(sx-tag ((,class :foreground ,magenta-alt))) - `(sx-user-name ((,class :foreground ,blue-alt))) - `(sx-user-reputation ((,class :inherit shadow))) + `(swiper-match-face-2 ((,c :inherit modus-themes-completion-match-0))) + `(swiper-match-face-3 ((,c :inherit modus-themes-completion-match-1))) + `(swiper-match-face-4 ((,c :inherit modus-themes-completion-match-2))) ;;;;; symbol-overlay - `(symbol-overlay-default-face ((,class :inherit modus-themes-special-warm))) - `(symbol-overlay-face-1 ((,class :inherit modus-themes-intense-blue))) - `(symbol-overlay-face-2 ((,class :inherit modus-themes-refine-magenta))) - `(symbol-overlay-face-3 ((,class :inherit modus-themes-intense-yellow))) - `(symbol-overlay-face-4 ((,class :inherit modus-themes-intense-magenta))) - `(symbol-overlay-face-5 ((,class :inherit modus-themes-intense-red))) - `(symbol-overlay-face-6 ((,class :inherit modus-themes-refine-red))) - `(symbol-overlay-face-7 ((,class :inherit modus-themes-intense-cyan))) - `(symbol-overlay-face-8 ((,class :inherit modus-themes-refine-cyan))) + `(symbol-overlay-default-face ((,c :background ,bg-inactive))) + `(symbol-overlay-face-1 ((,c :inherit modus-themes-intense-blue))) + `(symbol-overlay-face-2 ((,c :inherit modus-themes-intense-magenta))) + `(symbol-overlay-face-3 ((,c :inherit modus-themes-intense-yellow))) + `(symbol-overlay-face-4 ((,c :inherit modus-themes-intense-magenta))) + `(symbol-overlay-face-5 ((,c :inherit modus-themes-intense-red))) + `(symbol-overlay-face-6 ((,c :inherit modus-themes-intense-red))) + `(symbol-overlay-face-7 ((,c :inherit modus-themes-intense-cyan))) + `(symbol-overlay-face-8 ((,c :inherit modus-themes-intense-cyan))) ;;;;; syslog-mode - `(syslog-debug ((,class :inherit bold :foreground ,cyan-alt-other))) - `(syslog-error ((,class :inherit error))) - `(syslog-file ((,class :inherit bold :foreground ,fg-special-cold))) - `(syslog-hide ((,class :background ,bg-main :foreground ,fg-main))) - `(syslog-hour ((,class :inherit bold :foreground ,magenta-alt-other))) - `(syslog-info ((,class :inherit success))) - `(syslog-ip ((,class :inherit bold :foreground ,fg-special-mild :underline t))) - `(syslog-su ((,class :inherit bold :foreground ,red-alt))) - `(syslog-warn ((,class :inherit warning))) -;;;;; tab-bar-groups - `(tab-bar-groups-tab-1 ((,class :inherit modus-themes-ui-variable-pitch :foreground ,blue-tab))) - `(tab-bar-groups-tab-2 ((,class :inherit modus-themes-ui-variable-pitch :foreground ,red-tab))) - `(tab-bar-groups-tab-3 ((,class :inherit modus-themes-ui-variable-pitch :foreground ,green-tab))) - `(tab-bar-groups-tab-4 ((,class :inherit modus-themes-ui-variable-pitch :foreground ,orange-tab))) - `(tab-bar-groups-tab-5 ((,class :inherit modus-themes-ui-variable-pitch :foreground ,purple-tab))) - `(tab-bar-groups-tab-6 ((,class :inherit modus-themes-ui-variable-pitch :foreground ,cyan-tab))) - `(tab-bar-groups-tab-7 ((,class :inherit modus-themes-ui-variable-pitch :foreground ,yellow-tab))) - `(tab-bar-groups-tab-8 ((,class :inherit modus-themes-ui-variable-pitch :foreground ,magenta-tab))) + `(syslog-debug ((,c :inherit italic))) + `(syslog-error ((,c :inherit error))) + `(syslog-file ((,c :inherit bold :foreground ,name))) + `(syslog-hide ((,c :background ,bg-main :foreground ,fg-main))) + `(syslog-hour ((,c :inherit bold :foreground ,date-common))) + `(syslog-info ((,c :inherit success))) + `(syslog-ip ((,c :inherit bold :foreground ,name :underline t))) + `(syslog-su ((,c :inherit error :underline t))) + `(syslog-warn ((,c :inherit warning))) ;;;;; tab-bar-mode - `(tab-bar ((,class :inherit modus-themes-tab-backdrop))) - `(tab-bar-tab-group-current ((,class ,@(modus-themes--tab bg-tab-active) - :box (:line-width (2 . -2) :color "gray50")))) - `(tab-bar-tab-group-inactive ((,class ,@(modus-themes--tab bg-tab-inactive bg-tab-inactive-accent fg-dim) - :box (:line-width (2 . -2) :color "gray50")))) - `(tab-bar-tab ((,class :inherit modus-themes-tab-active))) - `(tab-bar-tab-inactive ((,class :inherit modus-themes-tab-inactive))) + `(tab-bar ((,c :inherit modus-themes-ui-variable-pitch :background ,bg-tab-bar))) + `(tab-bar-tab-group-current ((,c :inherit bold :background ,bg-tab-current :box (:line-width -2 :color ,bg-tab-current) :foreground ,fg-alt))) + `(tab-bar-tab-group-inactive ((,c :background ,bg-tab-bar :box (:line-width -2 :color ,bg-tab-bar) :foreground ,fg-alt))) + `(tab-bar-tab ((,c :inherit bold :box (:line-width -2 :color ,bg-tab-current) :background ,bg-tab-current))) + `(tab-bar-tab-inactive ((,c :box (:line-width -2 :color ,bg-tab-other) :background ,bg-tab-other))) + `(tab-bar-tab-ungrouped ((,c :inherit tab-bar-tab-inactive))) ;;;;; tab-line-mode - `(tab-line ((,class :inherit modus-themes-tab-backdrop :height 0.95))) - `(tab-line-close-highlight ((,class :foreground ,red))) - `(tab-line-highlight ((,class :inherit modus-themes-active-blue))) - `(tab-line-tab ((,class :inherit modus-themes-tab-active))) - `(tab-line-tab-current ((,class :inherit tab-line-tab))) - `(tab-line-tab-inactive ((,class :inherit modus-themes-tab-inactive))) - `(tab-line-tab-inactive-alternate ((,class ,@(modus-themes--tab bg-tab-inactive-alt - bg-tab-inactive-alt-accent fg-main nil t)))) - `(tab-line-tab-modified ((,class :foreground ,red-alt-other-faint))) + `(tab-line ((,c :inherit modus-themes-ui-variable-pitch :background ,bg-tab-bar :height 0.95))) + `(tab-line-close-highlight ((,c :foreground ,err))) + `(tab-line-highlight ((,c :inherit highlight))) + `(tab-line-tab (( ))) + `(tab-line-tab-current ((,c :inherit bold :box (:line-width -2 :color ,bg-tab-current) :background ,bg-tab-current))) + `(tab-line-tab-inactive ((,c :box (:line-width -2 :color ,bg-tab-other) :background ,bg-tab-other))) + `(tab-line-tab-inactive-alternate ((,c :inherit tab-line-tab-inactive :foreground ,fg-alt))) + `(tab-line-tab-modified ((,c :foreground ,warning))) ;;;;; table (built-in table.el) - `(table-cell ((,class :background ,blue-nuanced-bg))) + `(table-cell ((,c :background ,bg-dim))) ;;;;; telega - `(telega-button ((,class :box t :foreground ,blue))) - `(telega-button-active ((,class :box ,blue-intense-bg :background ,blue-intense-bg :foreground ,fg-main))) - `(telega-button-highlight ((,class :inherit modus-themes-subtle-magenta))) - `(telega-chat-prompt ((,class :inherit bold))) - `(telega-entity-type-code ((,class :inherit modus-themes-markup-verbatim))) - `(telega-entity-type-mention ((,class :foreground ,cyan))) - `(telega-entity-type-pre ((,class :inherit modus-themes-markup-code))) - `(telega-entity-type-spoiler ((,class :background ,fg-main :foreground ,fg-main))) - `(telega-msg-heading ((,class :background ,bg-alt))) - `(telega-msg-self-title ((,class :inherit bold))) - `(telega-root-heading ((,class :inherit modus-themes-subtle-neutral))) - `(telega-secret-title ((,class :foreground ,magenta-alt))) - `(telega-unmuted-count ((,class :foreground ,blue-alt-other))) - `(telega-user-online-status ((,class :foreground ,cyan-active))) - `(telega-username ((,class :foreground ,cyan-alt-other))) - `(telega-webpage-chat-link ((,class :background ,bg-alt))) - `(telega-webpage-fixed ((,class :inherit modus-themes-fixed-pitch :height 0.85))) - `(telega-webpage-header ((,class :inherit modus-themes-variable-pitch :height 1.3))) - `(telega-webpage-preformatted ((,class :inherit modus-themes-fixed-pitch :background ,bg-alt))) - `(telega-webpage-subheader ((,class :inherit modus-themes-variable-pitch :height 1.15))) -;;;;; telephone-line - `(telephone-line-accent-active ((,class :background ,fg-inactive :foreground ,bg-inactive))) - `(telephone-line-accent-inactive ((,class :background ,bg-active :foreground ,fg-active))) - `(telephone-line-error ((,class :inherit bold :foreground ,red-active))) - `(telephone-line-evil ((,class :foreground ,fg-main))) - `(telephone-line-evil-emacs ((,class :inherit telephone-line-evil :background ,magenta-intense-bg))) - `(telephone-line-evil-insert ((,class :inherit telephone-line-evil :background ,green-intense-bg))) - `(telephone-line-evil-motion ((,class :inherit telephone-line-evil :background ,yellow-intense-bg))) - `(telephone-line-evil-normal ((,class :inherit telephone-line-evil :background ,bg-alt))) - `(telephone-line-evil-operator ((,class :inherit telephone-line-evil :background ,yellow-subtle-bg))) - `(telephone-line-evil-replace ((,class :inherit telephone-line-evil :background ,red-intense-bg))) - `(telephone-line-evil-visual ((,class :inherit telephone-line-evil :background ,cyan-intense-bg))) - `(telephone-line-projectile ((,class :foreground ,cyan-active))) - `(telephone-line-unimportant ((,class :foreground ,fg-inactive))) - `(telephone-line-warning ((,class :inherit bold :foreground ,yellow-active))) + `(telega-button ((,c :box t :foreground ,fg-link))) + `(telega-button-active ((,c :box ,fg-link :background ,fg-link :foreground ,bg-main))) + `(telega-button-highlight ((,c :inherit secondary-selection))) + `(telega-chat-prompt ((,c :inherit modus-themes-prompt))) + `(telega-entity-type-code ((,c :inherit modus-themes-prose-verbatim))) + `(telega-entity-type-mention ((,c :foreground ,cyan))) + `(telega-entity-type-pre ((,c :inherit modus-themes-prose-code))) + `(telega-entity-type-spoiler ((,c :background ,fg-main :foreground ,fg-main))) + `(telega-msg-heading ((,c :background ,bg-inactive))) + `(telega-msg-self-title ((,c :inherit bold))) + `(telega-root-heading ((,c :background ,bg-inactive))) + `(telega-secret-title ((,c :foreground ,magenta-warmer))) + `(telega-unmuted-count ((,c :foreground ,blue-cooler))) + `(telega-user-online-status ((,c :foreground ,cyan))) + `(telega-username ((,c :foreground ,cyan-cooler))) + `(telega-webpage-chat-link ((,c :background ,bg-inactive))) + `(telega-webpage-fixed ((,c :inherit modus-themes-fixed-pitch :height 0.85))) + `(telega-webpage-header ((,c :inherit modus-themes-variable-pitch :height 1.3))) + `(telega-webpage-preformatted ((,c :inherit modus-themes-fixed-pitch :background ,bg-inactive))) + `(telega-webpage-subheader ((,c :inherit modus-themes-variable-pitch :height 1.15))) ;;;;; terraform-mode - `(terraform--resource-name-face ((,class ,@(modus-themes--syntax-string - magenta-alt-other magenta-alt-other-faint - red-alt red-alt)))) - `(terraform--resource-type-face ((,class ,@(modus-themes--syntax-string - green green-faint - blue-alt magenta-alt)))) + `(terraform--resource-name-face ((,c :foreground ,keyword))) + `(terraform--resource-type-face ((,c :foreground ,type))) ;;;;; term - `(term ((,class :background ,bg-main :foreground ,fg-main))) - `(term-bold ((,class :inherit bold))) - `(term-color-black ((,class :background "gray35" :foreground "gray35"))) - `(term-color-blue ((,class :background ,blue :foreground ,blue))) - `(term-color-cyan ((,class :background ,cyan :foreground ,cyan))) - `(term-color-green ((,class :background ,green :foreground ,green))) - `(term-color-magenta ((,class :background ,magenta :foreground ,magenta))) - `(term-color-red ((,class :background ,red :foreground ,red))) - `(term-color-white ((,class :background "gray65" :foreground "gray65"))) - `(term-color-yellow ((,class :background ,yellow :foreground ,yellow))) - `(term-underline ((,class :underline t))) + `(term ((,c :background ,bg-main :foreground ,fg-main))) + `(term-bold ((,c :inherit bold))) + `(term-color-black ((,c :background "gray35" :foreground "gray35"))) + `(term-color-blue ((,c :background ,blue :foreground ,blue))) + `(term-color-cyan ((,c :background ,cyan :foreground ,cyan))) + `(term-color-green ((,c :background ,green :foreground ,green))) + `(term-color-magenta ((,c :background ,magenta :foreground ,magenta))) + `(term-color-red ((,c :background ,red :foreground ,red))) + `(term-color-white ((,c :background "gray65" :foreground "gray65"))) + `(term-color-yellow ((,c :background ,yellow :foreground ,yellow))) + `(term-underline ((,c :underline t))) ;;;;; textsec - `(textsec-suspicious (())) -;;;;; tomatinho - `(tomatinho-ok-face ((,class :foreground ,blue-intense))) - `(tomatinho-pause-face ((,class :foreground ,yellow-intense))) - `(tomatinho-reset-face ((,class :inherit shadow))) + `(textsec-suspicious (( ))) ;;;;; transient - `(transient-active-infix ((,class :inherit modus-themes-special-mild))) - `(transient-amaranth ((,class :inherit bold :foreground ,yellow-alt))) + `(transient-active-infix ((,c :inherit highlight))) + `(transient-amaranth ((,c :inherit bold :foreground ,yellow-warmer))) ;; Placate the compiler for what is a spurious warning. We also ;; have to do this with `eldoc-highlight-function-argument'. - (list 'transient-argument `((,class :inherit bold :background ,cyan-nuanced-bg :foreground ,cyan))) - `(transient-blue ((,class :inherit bold :foreground ,blue))) - `(transient-disabled-suffix ((,class :inherit modus-themes-intense-red))) - `(transient-enabled-suffix ((,class :inherit modus-themes-grue-background-subtle))) - `(transient-heading ((,class :inherit bold :foreground ,fg-main))) - `(transient-inactive-argument ((,class :inherit shadow))) - `(transient-inactive-value ((,class :inherit shadow))) - `(transient-key ((,class :inherit modus-themes-key-binding))) - `(transient-mismatched-key ((,class :underline t))) - `(transient-nonstandard-key ((,class :underline t))) - `(transient-pink ((,class :inherit bold :foreground ,magenta-alt-faint))) - `(transient-purple ((,class :inherit bold :foreground ,magenta-alt-other))) - `(transient-red ((,class :inherit bold :foreground ,red-faint))) - `(transient-teal ((,class :inherit bold :foreground ,cyan-alt-other))) - `(transient-unreachable ((,class :inherit shadow))) - `(transient-unreachable-key ((,class :inherit shadow))) - `(transient-value ((,class :inherit bold :background ,yellow-nuanced-bg :foreground ,yellow-alt-other))) + (list 'transient-argument `((,c :inherit (bold modus-themes-mark-alt)))) + `(transient-blue ((,c :inherit bold :foreground ,blue))) + `(transient-disabled-suffix ((,c :inherit modus-themes-intense-red))) + `(transient-enabled-suffix ((,c :inherit modus-themes-subtle-cyan))) + `(transient-heading ((,c :inherit bold :foreground ,fg-main))) + `(transient-inactive-argument ((,c :inherit shadow))) + `(transient-inactive-value ((,c :inherit shadow))) + `(transient-key ((,c :inherit modus-themes-key-binding))) + `(transient-mismatched-key ((,c :underline t))) + `(transient-nonstandard-key ((,c :underline t))) + `(transient-pink ((,c :inherit bold :foreground ,magenta))) + `(transient-purple ((,c :inherit bold :foreground ,magenta-cooler))) + `(transient-red ((,c :inherit bold :foreground ,red-faint))) + `(transient-teal ((,c :inherit bold :foreground ,cyan-cooler))) + `(transient-unreachable ((,c :inherit shadow))) + `(transient-unreachable-key ((,c :inherit shadow))) + `(transient-value ((,c :inherit (bold modus-themes-mark-sel)))) ;;;;; trashed - `(trashed-deleted ((,class :inherit modus-themes-mark-del))) - `(trashed-directory ((,class :foreground ,blue))) - `(trashed-mark ((,class :inherit modus-themes-mark-symbol))) - `(trashed-marked ((,class :inherit modus-themes-mark-alt))) - `(trashed-restored ((,class :inherit modus-themes-mark-sel))) - `(trashed-symlink ((,class :inherit modus-themes-link-symlink))) + `(trashed-deleted ((,c :inherit modus-themes-mark-del))) + `(trashed-directory ((,c :foreground ,accent-0))) + `(trashed-mark ((,c :inherit bold))) + `(trashed-marked ((,c :inherit modus-themes-mark-alt))) + `(trashed-restored ((,c :inherit modus-themes-mark-sel))) ;;;;; tree-sitter - `(tree-sitter-hl-face:attribute ((,class :inherit font-lock-variable-name-face))) - `(tree-sitter-hl-face:constant.builtin ((,class :inherit tree-sitter-hl-face:constant))) - `(tree-sitter-hl-face:escape ((,class :inherit font-lock-regexp-grouping-backslash))) - `(tree-sitter-hl-face:function ((,class :inherit font-lock-function-name-face))) - `(tree-sitter-hl-face:function.call ((,class :inherit tree-sitter-hl-face:function))) + `(tree-sitter-hl-face:attribute ((,c :inherit font-lock-variable-name-face))) + `(tree-sitter-hl-face:constant.builtin ((,c :inherit tree-sitter-hl-face:constant))) + `(tree-sitter-hl-face:escape ((,c :inherit font-lock-regexp-grouping-backslash))) + `(tree-sitter-hl-face:function ((,c :inherit font-lock-function-name-face))) + `(tree-sitter-hl-face:function.call ((,c :inherit tree-sitter-hl-face:function))) `(tree-sitter-hl-face:label (( ))) `(tree-sitter-hl-face:method.call (( ))) - `(tree-sitter-hl-face:operator ((,class :inherit modus-themes-bold))) + `(tree-sitter-hl-face:operator ((,c :inherit modus-themes-bold))) `(tree-sitter-hl-face:property (( ))) - `(tree-sitter-hl-face:property.definition ((,class :inherit font-lock-variable-name-face))) + `(tree-sitter-hl-face:property.definition ((,c :inherit font-lock-variable-name-face))) `(tree-sitter-hl-face:punctuation (( ))) `(tree-sitter-hl-face:punctuation.bracket (( ))) `(tree-sitter-hl-face:punctuation.delimiter (( ))) - `(tree-sitter-hl-face:punctuation.special ((,class :inherit font-lock-regexp-grouping-construct))) - `(tree-sitter-hl-face:string.special ((,class :inherit tree-sitter-hl-face:string))) - `(tree-sitter-hl-face:tag ((,class :inherit font-lock-function-name-face))) + `(tree-sitter-hl-face:punctuation.special ((,c :inherit font-lock-regexp-grouping-construct))) + `(tree-sitter-hl-face:string.special ((,c :inherit tree-sitter-hl-face:string))) + `(tree-sitter-hl-face:tag ((,c :inherit font-lock-function-name-face))) `(tree-sitter-hl-face:type.argument (( ))) -;;;;; treemacs - `(treemacs-directory-collapsed-face ((,class :foreground ,magenta-alt))) - `(treemacs-directory-face ((,class :inherit dired-directory))) - `(treemacs-file-face ((,class :foreground ,fg-main))) - `(treemacs-fringe-indicator-face ((,class :foreground ,fg-main))) - `(treemacs-git-added-face ((,class :inherit success))) - `(treemacs-git-conflict-face ((,class :inherit error))) - `(treemacs-git-ignored-face ((,class :inherit shadow))) - `(treemacs-git-modified-face ((,class :inherit warning))) - `(treemacs-git-renamed-face ((,class :inherit italic))) - `(treemacs-git-unmodified-face ((,class :foreground ,fg-main))) - `(treemacs-git-untracked-face ((,class :inherit shadow))) - `(treemacs-help-column-face ((,class :inherit modus-themes-bold :foreground ,magenta-alt-other :underline t))) - `(treemacs-help-title-face ((,class :foreground ,blue-alt-other))) - `(treemacs-on-failure-pulse-face ((,class :inherit modus-themes-intense-red))) - `(treemacs-on-success-pulse-face ((,class :inherit modus-themes-grue-background-intense))) - `(treemacs-root-face ((,class :inherit bold :foreground ,blue-alt-other :height 1.2 :underline t))) - `(treemacs-root-remote-disconnected-face ((,class :inherit treemacs-root-remote-face :foreground ,yellow))) - `(treemacs-root-remote-face ((,class :inherit treemacs-root-face :foreground ,magenta))) - `(treemacs-root-remote-unreadable-face ((,class :inherit treemacs-root-unreadable-face))) - `(treemacs-root-unreadable-face ((,class :inherit treemacs-root-face :strike-through t))) - `(treemacs-tags-face ((,class :foreground ,blue-alt))) ;;;;; tty-menu - `(tty-menu-disabled-face ((,class :background ,bg-alt :foreground ,fg-alt))) - `(tty-menu-enabled-face ((,class :inherit bold :background ,bg-alt :foreground ,fg-main))) - `(tty-menu-selected-face ((,class :inherit modus-themes-intense-blue))) + `(tty-menu-disabled-face ((,c :background ,bg-inactive :foreground ,fg-dim))) + `(tty-menu-enabled-face ((,c :inherit bold :background ,bg-inactive :foreground ,fg-main))) + `(tty-menu-selected-face ((,c :inherit modus-themes-intense-blue))) ;;;;; tuareg - `(caml-types-def-face ((,class :inherit modus-themes-subtle-red))) - `(caml-types-expr-face ((,class :inherit modus-themes-subtle-green))) - `(caml-types-occ-face ((,class :inherit modus-themes-subtle-green))) - `(caml-types-scope-face ((,class :inherit modus-themes-subtle-blue))) - `(caml-types-typed-face ((,class :inherit modus-themes-subtle-magenta))) - `(tuareg-font-double-semicolon-face ((,class :inherit font-lock-preprocessor-face))) - `(tuareg-font-lock-attribute-face ((,class :inherit font-lock-function-name-face))) - `(tuareg-font-lock-constructor-face ((,class :foreground ,fg-main))) - `(tuareg-font-lock-error-face ((,class :inherit (modus-themes-intense-red bold)))) - `(tuareg-font-lock-extension-node-face ((,class :background ,bg-alt :foreground ,magenta))) - `(tuareg-font-lock-governing-face ((,class :inherit bold :foreground ,fg-main))) - `(tuareg-font-lock-infix-extension-node-face ((,class :inherit font-lock-function-name-face))) - `(tuareg-font-lock-interactive-directive-face ((,class :foreground ,fg-special-cold))) - `(tuareg-font-lock-interactive-error-face ((,class :inherit error))) - `(tuareg-font-lock-interactive-output-face ((,class :inherit font-lock-constant-face))) - `(tuareg-font-lock-label-face ((,class :inherit font-lock-type-face))) - `(tuareg-font-lock-line-number-face ((,class :foreground ,fg-special-warm))) - `(tuareg-font-lock-module-face ((,class :inherit font-lock-builtin-face))) - `(tuareg-font-lock-multistage-face ((,class :inherit bold :background ,bg-alt :foreground ,blue))) - `(tuareg-font-lock-operator-face ((,class :inherit font-lock-preprocessor-face))) - `(tuareg-opam-error-face ((,class :inherit error))) - `(tuareg-opam-pkg-variable-name-face ((,class :inherit font-lock-variable-name-face))) + `(caml-types-def-face ((,c :inherit modus-themes-subtle-red))) + `(caml-types-expr-face ((,c :inherit modus-themes-subtle-green))) + `(caml-types-occ-face ((,c :inherit modus-themes-subtle-green))) + `(caml-types-scope-face ((,c :inherit modus-themes-subtle-blue))) + `(caml-types-typed-face ((,c :inherit modus-themes-subtle-magenta))) + `(tuareg-font-double-semicolon-face ((,c :inherit font-lock-preprocessor-face))) + `(tuareg-font-lock-attribute-face ((,c :inherit font-lock-function-name-face))) + `(tuareg-font-lock-constructor-face ((,c :foreground ,fg-main))) + `(tuareg-font-lock-error-face ((,c :inherit (modus-themes-intense-red bold)))) + ;; `(tuareg-font-lock-extension-node-face ((,c :background ,bg-inactive :foreground ,magenta))) + `(tuareg-font-lock-governing-face ((,c :inherit bold :foreground ,fg-main))) + `(tuareg-font-lock-infix-extension-node-face ((,c :inherit font-lock-function-name-face))) + `(tuareg-font-lock-interactive-directive-face ((,c :inherit font-lock-preprocessor-face))) + `(tuareg-font-lock-interactive-error-face ((,c :inherit error))) + `(tuareg-font-lock-interactive-output-face ((,c :inherit font-lock-constant-face))) + `(tuareg-font-lock-label-face ((,c :inherit font-lock-type-face))) + `(tuareg-font-lock-line-number-face ((,c :inherit shadow))) + `(tuareg-font-lock-module-face ((,c :inherit font-lock-builtin-face))) + ;; `(tuareg-font-lock-multistage-face ((,c :inherit bold :background ,bg-inactive :foreground ,blue))) + `(tuareg-font-lock-operator-face ((,c :inherit font-lock-preprocessor-face))) + `(tuareg-opam-error-face ((,c :inherit error))) + `(tuareg-opam-pkg-variable-name-face ((,c :inherit font-lock-variable-name-face))) ;;;;; typescript - `(typescript-jsdoc-tag ((,class :inherit (font-lock-builtin-face font-lock-comment-face) :weight normal))) - `(typescript-jsdoc-type ((,class :inherit (font-lock-type-face font-lock-comment-face) :weight normal))) - `(typescript-jsdoc-value ((,class :inherit (font-lock-constant-face font-lock-comment-face) :weight normal))) + `(typescript-jsdoc-tag ((,c :inherit (font-lock-builtin-face font-lock-comment-face) :weight normal))) + `(typescript-jsdoc-type ((,c :inherit (font-lock-type-face font-lock-comment-face) :weight normal))) + `(typescript-jsdoc-value ((,c :inherit (font-lock-constant-face font-lock-comment-face) :weight normal))) ;;;;; undo-tree - `(undo-tree-visualizer-active-branch-face ((,class :inherit bold :foreground ,fg-main))) - `(undo-tree-visualizer-current-face ((,class :foreground ,blue-intense))) - `(undo-tree-visualizer-default-face ((,class :inherit shadow))) - `(undo-tree-visualizer-register-face ((,class :foreground ,magenta-intense))) - `(undo-tree-visualizer-unmodified-face ((,class :foreground ,green-intense))) + `(undo-tree-visualizer-active-branch-face ((,c :inherit bold :foreground ,fg-main))) + `(undo-tree-visualizer-current-face ((,c :foreground ,blue-intense))) + `(undo-tree-visualizer-default-face ((,c :inherit shadow))) + `(undo-tree-visualizer-register-face ((,c :foreground ,magenta-intense))) + `(undo-tree-visualizer-unmodified-face ((,c :foreground ,green-intense))) ;;;;; vc (vc-dir.el, vc-hooks.el) - `(vc-dir-directory ((,class :foreground ,blue))) - `(vc-dir-file ((,class :foreground ,fg-main))) - `(vc-dir-header ((,class :foreground ,cyan-alt-other))) - `(vc-dir-header-value ((,class :foreground ,magenta-alt-other))) - `(vc-dir-mark-indicator ((,class :foreground ,blue-alt-other))) - `(vc-dir-status-edited ((,class :foreground ,yellow))) - `(vc-dir-status-ignored ((,class :inherit shadow))) - `(vc-dir-status-up-to-date ((,class :foreground ,cyan))) - `(vc-dir-status-warning ((,class :inherit error))) - `(vc-conflict-state ((,class :inherit bold :foreground ,red-active))) - `(vc-edited-state ((,class :foreground ,yellow-active))) - `(vc-locally-added-state ((,class :foreground ,cyan-active))) - `(vc-locked-state ((,class :foreground ,blue-active))) - `(vc-missing-state ((,class :inherit modus-themes-slant :foreground ,magenta-active))) - `(vc-needs-update-state ((,class :inherit modus-themes-slant :foreground ,green-active))) - `(vc-removed-state ((,class :foreground ,red-active))) - `(vc-state-base ((,class :foreground ,fg-active))) - `(vc-up-to-date-state ((,class :foreground ,fg-special-cold))) + `(vc-dir-directory (( ))) + `(vc-dir-file ((,c :foreground ,name))) + `(vc-dir-header ((,c :inherit bold))) + `(vc-dir-header-value ((,c :foreground ,string))) + `(vc-dir-mark-indicator (( ))) + `(vc-dir-status-edited ((,c :inherit italic))) + `(vc-dir-status-ignored ((,c :inherit shadow))) + `(vc-dir-status-up-to-date ((,c :foreground ,info))) + `(vc-dir-status-warning ((,c :inherit error))) + `(vc-conflict-state ((,c :inherit error))) + `(vc-edited-state ((,c :inherit italic))) + `(vc-git-log-edit-summary-max-warning ((,c :inherit error))) + `(vc-git-log-edit-summary-target-warning ((,c :inherit warning))) + `(vc-locally-added-state ((,c :inherit italic))) + `(vc-locked-state ((,c :inherit success))) + `(vc-missing-state ((,c :inherit error))) + `(vc-needs-update-state ((,c :inherit error))) + `(vc-removed-state ((,c :inherit error))) + `(vc-state-base (( ))) + `(vc-up-to-date-state (( ))) ;;;;; vertico - `(vertico-current ((,class :inherit modus-themes-completion-selected))) + `(vertico-current ((,c :inherit modus-themes-completion-selected))) ;;;;; vertico-quick - `(vertico-quick1 ((,class :inherit bold :background ,bg-char-0))) - `(vertico-quick2 ((,class :inherit bold :background ,bg-char-1))) + `(vertico-quick1 ((,c :inherit bold :background ,bg-char-0))) + `(vertico-quick2 ((,c :inherit bold :background ,bg-char-1))) ;;;;; vimish-fold - `(vimish-fold-fringe ((,class :foreground ,cyan-active))) - `(vimish-fold-mouse-face ((,class :inherit modus-themes-intense-blue))) - `(vimish-fold-overlay ((,class :background ,bg-alt :foreground ,fg-special-cold))) + `(vimish-fold-fringe ((,c :foreground ,cyan))) + `(vimish-fold-mouse-face ((,c :inherit modus-themes-intense-blue))) + `(vimish-fold-overlay ((,c :background ,bg-inactive))) ;;;;; visible-mark - `(visible-mark-active ((,class :background ,blue-intense-bg))) - `(visible-mark-face1 ((,class :background ,cyan-intense-bg))) - `(visible-mark-face2 ((,class :background ,yellow-intense-bg))) - `(visible-mark-forward-face1 ((,class :background ,magenta-intense-bg))) - `(visible-mark-forward-face2 ((,class :background ,green-intense-bg))) + `(visible-mark-active ((,c :background ,bg-blue-intense))) + `(visible-mark-face1 ((,c :background ,bg-cyan-intense))) + `(visible-mark-face2 ((,c :background ,bg-yellow-intense))) + `(visible-mark-forward-face1 ((,c :background ,bg-magenta-intense))) + `(visible-mark-forward-face2 ((,c :background ,bg-green-intense))) ;;;;; visual-regexp - `(vr/group-0 ((,class :inherit modus-themes-intense-blue))) - `(vr/group-1 ((,class :inherit modus-themes-intense-magenta))) - `(vr/group-2 ((,class :inherit modus-themes-intense-green))) - `(vr/match-0 ((,class :inherit modus-themes-refine-yellow))) - `(vr/match-1 ((,class :inherit modus-themes-refine-yellow))) - `(vr/match-separator-face ((,class :inherit (modus-themes-intense-neutral bold)))) + `(vr/group-0 ((,c :inherit modus-themes-intense-blue))) + `(vr/group-1 ((,c :inherit modus-themes-intense-magenta))) + `(vr/group-2 ((,c :inherit modus-themes-intense-green))) + `(vr/match-0 ((,c :inherit modus-themes-intense-yellow))) + `(vr/match-1 ((,c :inherit modus-themes-intense-yellow))) + `(vr/match-separator-face ((,c :inherit bold :background ,bg-active))) ;;;;; vterm - `(vterm-color-black ((,class :background "gray35" :foreground "gray35"))) - `(vterm-color-blue ((,class :background ,blue :foreground ,blue))) - `(vterm-color-cyan ((,class :background ,cyan :foreground ,cyan))) - `(vterm-color-default ((,class :background ,bg-main :foreground ,fg-main))) - `(vterm-color-green ((,class :background ,green :foreground ,green))) - `(vterm-color-inverse-video ((,class :background ,bg-main :inverse-video t))) - `(vterm-color-magenta ((,class :background ,magenta :foreground ,magenta))) - `(vterm-color-red ((,class :background ,red :foreground ,red))) - `(vterm-color-underline ((,class :foreground ,fg-special-warm :underline t))) - `(vterm-color-white ((,class :background "gray65" :foreground "gray65"))) - `(vterm-color-yellow ((,class :background ,yellow :foreground ,yellow))) + `(vterm-color-black ((,c :background "gray35" :foreground "gray35"))) + `(vterm-color-blue ((,c :background ,blue :foreground ,blue))) + `(vterm-color-cyan ((,c :background ,cyan :foreground ,cyan))) + `(vterm-color-default ((,c :background ,bg-main :foreground ,fg-main))) + `(vterm-color-green ((,c :background ,green :foreground ,green))) + `(vterm-color-inverse-video ((,c :background ,bg-main :inverse-video t))) + `(vterm-color-magenta ((,c :background ,magenta :foreground ,magenta))) + `(vterm-color-red ((,c :background ,red :foreground ,red))) + `(vterm-color-underline ((,c :underline t))) + `(vterm-color-white ((,c :background "gray65" :foreground "gray65"))) + `(vterm-color-yellow ((,c :background ,yellow :foreground ,yellow))) ;;;;; vundo - `(vundo-highlight ((,class :inherit (bold vundo-node) :foreground ,red-intense))) + `(vundo-highlight ((,c :inherit (bold vundo-node) :foreground ,red-intense))) ;;;;; wcheck-mode - `(wcheck-default-face ((,class :foreground ,red :underline t))) + `(wcheck-default-face ((,c :foreground ,red :underline t))) ;;;;; web-mode - `(web-mode-annotation-face ((,class :inherit web-mode-comment-face))) - `(web-mode-annotation-html-face ((,class :inherit web-mode-comment-face))) - `(web-mode-annotation-tag-face ((,class :inherit web-mode-comment-face :underline t))) - `(web-mode-block-attr-name-face ((,class :inherit font-lock-constant-face))) - `(web-mode-block-attr-value-face ((,class :inherit font-lock-type-face))) - `(web-mode-block-comment-face ((,class :inherit web-mode-comment-face))) - `(web-mode-block-control-face ((,class :inherit font-lock-builtin-face))) - `(web-mode-block-delimiter-face ((,class :foreground ,fg-main))) - `(web-mode-block-face ((,class :background ,bg-dim))) - `(web-mode-block-string-face ((,class :inherit web-mode-string-face))) - `(web-mode-bold-face ((,class :inherit bold))) - `(web-mode-builtin-face ((,class :inherit font-lock-builtin-face))) - `(web-mode-comment-face ((,class :inherit font-lock-comment-face))) - `(web-mode-comment-keyword-face ((,class :inherit font-lock-warning-face))) - `(web-mode-constant-face ((,class :inherit font-lock-constant-face))) - `(web-mode-css-at-rule-face ((,class :inherit font-lock-constant-face))) - `(web-mode-css-color-face ((,class :inherit font-lock-builtin-face))) - `(web-mode-css-comment-face ((,class :inherit web-mode-comment-face))) - `(web-mode-css-function-face ((,class :inherit font-lock-builtin-face))) - `(web-mode-css-priority-face ((,class :inherit font-lock-warning-face))) - `(web-mode-css-property-name-face ((,class :inherit font-lock-keyword-face))) - `(web-mode-css-pseudo-class-face ((,class :inherit font-lock-doc-face))) - `(web-mode-css-selector-face ((,class :inherit font-lock-keyword-face))) - `(web-mode-css-string-face ((,class :inherit web-mode-string-face))) - `(web-mode-css-variable-face ((,class :foreground ,fg-special-warm))) - `(web-mode-current-column-highlight-face ((,class :background ,bg-alt))) - `(web-mode-current-element-highlight-face ((,class :inherit modus-themes-special-mild))) - `(web-mode-doctype-face ((,class :inherit modus-themes-slant :foreground ,fg-special-cold))) - `(web-mode-error-face ((,class :inherit modus-themes-intense-red))) - `(web-mode-filter-face ((,class :inherit font-lock-function-name-face))) - `(web-mode-folded-face ((,class :underline t))) - `(web-mode-function-call-face ((,class :inherit font-lock-function-name-face))) - `(web-mode-function-name-face ((,class :inherit font-lock-function-name-face))) - `(web-mode-html-attr-custom-face ((,class :inherit font-lock-variable-name-face))) - `(web-mode-html-attr-engine-face ((,class :foreground ,fg-main))) - `(web-mode-html-attr-equal-face ((,class :foreground ,fg-main))) - `(web-mode-html-attr-name-face ((,class :inherit font-lock-variable-name-face))) - `(web-mode-html-attr-value-face ((,class :inherit font-lock-constant-face))) - `(web-mode-html-entity-face ((,class :inherit font-lock-negation-char-face))) - `(web-mode-html-tag-bracket-face ((,class :foreground ,fg-dim))) - `(web-mode-html-tag-custom-face ((,class :inherit font-lock-function-name-face))) - `(web-mode-html-tag-face ((,class :inherit font-lock-function-name-face))) - `(web-mode-html-tag-namespaced-face ((,class :inherit font-lock-builtin-face))) - `(web-mode-html-tag-unclosed-face ((,class :inherit error :underline t))) - `(web-mode-inlay-face ((,class :background ,bg-alt))) - `(web-mode-italic-face ((,class :inherit italic))) - `(web-mode-javascript-comment-face ((,class :inherit web-mode-comment-face))) - `(web-mode-javascript-string-face ((,class :inherit web-mode-string-face))) - `(web-mode-json-comment-face ((,class :inherit web-mode-comment-face))) - `(web-mode-json-context-face ((,class :inherit font-lock-builtin-face))) - `(web-mode-json-key-face ((,class :foreground ,blue-nuanced-fg))) - `(web-mode-json-string-face ((,class :inherit web-mode-string-face))) - `(web-mode-jsx-depth-1-face ((,class :background ,blue-intense-bg :foreground ,fg-main))) - `(web-mode-jsx-depth-2-face ((,class :background ,blue-subtle-bg :foreground ,fg-main))) - `(web-mode-jsx-depth-3-face ((,class :background ,bg-special-cold :foreground ,fg-special-cold))) - `(web-mode-jsx-depth-4-face ((,class :background ,bg-alt :foreground ,blue-refine-fg))) - `(web-mode-jsx-depth-5-face ((,class :background ,bg-alt :foreground ,blue-nuanced-fg))) - `(web-mode-keyword-face ((,class :inherit font-lock-keyword-face))) - `(web-mode-param-name-face ((,class :inherit font-lock-function-name-face))) - `(web-mode-part-comment-face ((,class :inherit web-mode-comment-face))) - `(web-mode-part-face ((,class :inherit web-mode-block-face))) - `(web-mode-part-string-face ((,class :inherit web-mode-string-face))) - `(web-mode-preprocessor-face ((,class :inherit font-lock-preprocessor-face))) - `(web-mode-script-face ((,class :inherit web-mode-part-face))) - `(web-mode-sql-keyword-face ((,class :inherit font-lock-negation-char-face))) - `(web-mode-string-face ((,class :inherit font-lock-string-face))) - `(web-mode-style-face ((,class :inherit web-mode-part-face))) - `(web-mode-symbol-face ((,class :inherit font-lock-constant-face))) - `(web-mode-type-face ((,class :inherit font-lock-builtin-face))) - `(web-mode-underline-face ((,class :underline t))) - `(web-mode-variable-name-face ((,class :inherit font-lock-variable-name-face))) - `(web-mode-warning-face ((,class :inherit font-lock-warning-face))) - `(web-mode-whitespace-face ((,class :background ,bg-whitespace :foreground ,fg-whitespace))) + `(web-mode-annotation-face ((,c :inherit web-mode-comment-face))) + `(web-mode-annotation-html-face ((,c :inherit web-mode-comment-face))) + `(web-mode-annotation-tag-face ((,c :inherit web-mode-comment-face :underline t))) + `(web-mode-block-attr-name-face ((,c :inherit font-lock-constant-face))) + `(web-mode-block-attr-value-face ((,c :inherit font-lock-type-face))) + `(web-mode-block-comment-face ((,c :inherit web-mode-comment-face))) + `(web-mode-block-control-face ((,c :inherit font-lock-builtin-face))) + `(web-mode-block-delimiter-face ((,c :foreground ,fg-main))) + `(web-mode-block-face ((,c :background ,bg-dim))) + `(web-mode-block-string-face ((,c :inherit web-mode-string-face))) + `(web-mode-bold-face ((,c :inherit bold))) + `(web-mode-builtin-face ((,c :inherit font-lock-builtin-face))) + `(web-mode-comment-face ((,c :inherit font-lock-comment-face))) + `(web-mode-comment-keyword-face ((,c :inherit font-lock-warning-face))) + `(web-mode-constant-face ((,c :inherit font-lock-constant-face))) + `(web-mode-css-at-rule-face ((,c :inherit font-lock-constant-face))) + `(web-mode-css-color-face ((,c :inherit font-lock-builtin-face))) + `(web-mode-css-comment-face ((,c :inherit web-mode-comment-face))) + `(web-mode-css-function-face ((,c :inherit font-lock-builtin-face))) + `(web-mode-css-priority-face ((,c :inherit font-lock-warning-face))) + `(web-mode-css-property-name-face ((,c :inherit font-lock-keyword-face))) + `(web-mode-css-pseudo-class-face ((,c :inherit font-lock-doc-face))) + `(web-mode-css-selector-face ((,c :inherit font-lock-keyword-face))) + `(web-mode-css-string-face ((,c :inherit web-mode-string-face))) + `(web-mode-css-variable-face ((,c :inherit font-lock-variable-name-face))) + `(web-mode-current-column-highlight-face ((,c :background ,bg-inactive))) + `(web-mode-current-element-highlight-face ((,c :inherit modus-themes-cyan-subtle))) + `(web-mode-doctype-face ((,c :inherit font-lock-doc-face))) + `(web-mode-error-face ((,c :inherit modus-themes-intense-red))) + `(web-mode-filter-face ((,c :inherit font-lock-function-name-face))) + `(web-mode-folded-face ((,c :underline t))) + `(web-mode-function-call-face ((,c :inherit font-lock-function-name-face))) + `(web-mode-function-name-face ((,c :inherit font-lock-function-name-face))) + `(web-mode-html-attr-custom-face ((,c :inherit font-lock-variable-name-face))) + `(web-mode-html-attr-engine-face ((,c :foreground ,fg-main))) + `(web-mode-html-attr-equal-face ((,c :foreground ,fg-main))) + `(web-mode-html-attr-name-face ((,c :inherit font-lock-variable-name-face))) + `(web-mode-html-attr-value-face ((,c :inherit font-lock-constant-face))) + `(web-mode-html-entity-face ((,c :inherit font-lock-negation-char-face))) + `(web-mode-html-tag-bracket-face ((,c :foreground ,fg-dim))) + `(web-mode-html-tag-custom-face ((,c :inherit font-lock-function-name-face))) + `(web-mode-html-tag-face ((,c :inherit font-lock-function-name-face))) + `(web-mode-html-tag-namespaced-face ((,c :inherit font-lock-builtin-face))) + `(web-mode-html-tag-unclosed-face ((,c :inherit error :underline t))) + `(web-mode-inlay-face ((,c :background ,bg-inactive))) + `(web-mode-italic-face ((,c :inherit italic))) + `(web-mode-javascript-comment-face ((,c :inherit web-mode-comment-face))) + `(web-mode-javascript-string-face ((,c :inherit web-mode-string-face))) + `(web-mode-json-comment-face ((,c :inherit web-mode-comment-face))) + `(web-mode-json-context-face ((,c :inherit font-lock-builtin-face))) + `(web-mode-json-key-face ((,c :foreground ,blue-faint))) + `(web-mode-json-string-face ((,c :inherit web-mode-string-face))) + `(web-mode-keyword-face ((,c :inherit font-lock-keyword-face))) + `(web-mode-param-name-face ((,c :inherit font-lock-function-name-face))) + `(web-mode-part-comment-face ((,c :inherit web-mode-comment-face))) + `(web-mode-part-face ((,c :inherit web-mode-block-face))) + `(web-mode-part-string-face ((,c :inherit web-mode-string-face))) + `(web-mode-preprocessor-face ((,c :inherit font-lock-preprocessor-face))) + `(web-mode-script-face ((,c :inherit web-mode-part-face))) + `(web-mode-sql-keyword-face ((,c :inherit font-lock-negation-char-face))) + `(web-mode-string-face ((,c :inherit font-lock-string-face))) + `(web-mode-style-face ((,c :inherit web-mode-part-face))) + `(web-mode-symbol-face ((,c :inherit font-lock-constant-face))) + `(web-mode-type-face ((,c :inherit font-lock-builtin-face))) + `(web-mode-underline-face ((,c :underline t))) + `(web-mode-variable-name-face ((,c :inherit font-lock-variable-name-face))) + `(web-mode-warning-face ((,c :inherit font-lock-warning-face))) + `(web-mode-whitespace-face ((,c :background ,bg-inactive))) ;;;;; wgrep - `(wgrep-delete-face ((,class :inherit warning))) - `(wgrep-done-face ((,class :inherit success))) - `(wgrep-face ((,class :inherit bold))) - `(wgrep-file-face ((,class :foreground ,fg-special-warm))) - `(wgrep-reject-face ((,class :inherit error))) + `(wgrep-delete-face ((,c :inherit warning))) + `(wgrep-done-face ((,c :inherit success))) + `(wgrep-face ((,c :inherit bold))) + `(wgrep-file-face ((,c :foreground ,fg-alt))) + `(wgrep-reject-face ((,c :inherit error))) ;;;;; which-function-mode - `(which-func ((,class :foreground ,magenta-active))) + `(which-func ((,c :inherit bold :foreground ,modeline-info))) ;;;;; which-key - `(which-key-command-description-face ((,class :foreground ,fg-main))) - `(which-key-group-description-face ((,class :foreground ,magenta-alt))) - `(which-key-highlighted-command-face ((,class :foreground ,yellow :underline t))) - `(which-key-key-face ((,class :inherit modus-themes-key-binding))) - `(which-key-local-map-description-face ((,class :foreground ,fg-main))) - `(which-key-note-face ((,class :foreground ,fg-special-warm))) - `(which-key-separator-face ((,class :inherit shadow))) - `(which-key-special-key-face ((,class :inherit bold :foreground ,red-alt))) + `(which-key-command-description-face ((,c :foreground ,fg-main))) + `(which-key-group-description-face ((,c :foreground ,err))) + `(which-key-highlighted-command-face ((,c :foreground ,warning :underline t))) + `(which-key-key-face ((,c :inherit modus-themes-key-binding))) + `(which-key-local-map-description-face ((,c :foreground ,fg-main))) + `(which-key-note-face ((,c :inherit shadow))) + `(which-key-separator-face ((,c :inherit shadow))) + `(which-key-special-key-face ((,c :inherit error))) ;;;;; whitespace-mode - `(whitespace-big-indent ((,class :inherit modus-themes-subtle-red))) - `(whitespace-empty ((,class :inherit modus-themes-intense-magenta))) - `(whitespace-hspace ((,class :background ,bg-whitespace :foreground ,fg-whitespace))) - `(whitespace-indentation ((,class :background ,bg-whitespace :foreground ,fg-whitespace))) - `(whitespace-line ((,class :inherit modus-themes-subtle-yellow))) - `(whitespace-newline ((,class :background ,bg-whitespace :foreground ,fg-whitespace))) - `(whitespace-space ((,class :background ,bg-whitespace :foreground ,fg-whitespace))) - `(whitespace-space-after-tab ((,class :inherit modus-themes-subtle-magenta))) - `(whitespace-space-before-tab ((,class :inherit modus-themes-subtle-cyan))) - `(whitespace-tab ((,class :background ,bg-whitespace :foreground ,fg-whitespace))) - `(whitespace-trailing ((,class :inherit modus-themes-intense-red))) + `(whitespace-big-indent ((,c :inherit modus-themes-subtle-red))) + `(whitespace-empty ((,c :inherit modus-themes-intense-magenta))) + `(whitespace-hspace ((,c :background ,bg-dim :foreground ,fg-dim))) + `(whitespace-indentation ((,c :background ,bg-dim :foreground ,fg-dim))) + `(whitespace-line ((,c :inherit modus-themes-subtle-yellow))) + `(whitespace-newline ((,c :background ,bg-dim :foreground ,fg-dim))) + `(whitespace-space ((,c :background ,bg-dim :foreground ,fg-dim))) + `(whitespace-space-after-tab ((,c :inherit modus-themes-subtle-magenta))) + `(whitespace-space-before-tab ((,c :inherit modus-themes-subtle-cyan))) + `(whitespace-tab ((,c :background ,bg-dim :foreground ,fg-dim))) + `(whitespace-trailing ((,c :inherit modus-themes-intense-red))) ;;;;; window-divider-mode - `(window-divider ((,class :foreground ,fg-window-divider-inner))) - `(window-divider-first-pixel ((,class :foreground ,fg-window-divider-outer))) - `(window-divider-last-pixel ((,class :foreground ,fg-window-divider-outer))) -;;;;; winum - `(winum-face ((,class :inherit modus-themes-bold :foreground ,cyan-active))) + `(window-divider ((,c :foreground ,border))) + `(window-divider-first-pixel ((,c :foreground ,bg-inactive))) + `(window-divider-last-pixel ((,c :foreground ,bg-inactive))) +;;;;; widget + `(widget-button ((,c :inherit bold :foreground ,fg-link))) + `(widget-button-pressed ((,c :inherit widget-buton :foreground ,fg-link-visited))) + `(widget-documentation ((,c :inherit font-lock-doc-face))) + `(widget-field ((,c :background ,bg-inactive :foreground ,fg-main :extend nil))) + `(widget-inactive ((,c :background ,bg-button-inactive :foreground ,fg-button-inactive))) + `(widget-single-line-field ((,c :inherit widget-field))) ;;;;; writegood-mode - `(writegood-duplicates-face ((,class :background ,bg-alt :foreground ,red-alt :underline t))) - `(writegood-passive-voice-face ((,class :inherit modus-themes-lang-warning))) - `(writegood-weasels-face ((,class :inherit modus-themes-lang-error))) + `(writegood-duplicates-face ((,c :inherit modus-themes-lang-error))) + `(writegood-passive-voice-face ((,c :inherit modus-themes-lang-warning))) + `(writegood-weasels-face ((,c :inherit modus-themes-lang-warning))) ;;;;; woman - `(woman-addition ((,class :foreground ,magenta-alt-other))) - `(woman-bold ((,class :inherit bold :foreground ,magenta-alt))) - `(woman-italic ((,class :inherit italic :foreground ,cyan))) - `(woman-unknown ((,class :foreground ,green-alt))) + `(woman-addition ((,c :foreground ,accent-2))) + `(woman-bold ((,c :inherit bold :foreground ,accent-0))) + `(woman-italic ((,c :inherit italic :foreground ,accent-1))) + `(woman-unknown ((,c :foreground ,accent-3))) ;;;;; xah-elisp-mode - `(xah-elisp-at-symbol ((,class :inherit font-lock-warning-face))) - `(xah-elisp-cap-variable ((,class :inherit font-lock-preprocessor-face))) - `(xah-elisp-command-face ((,class :inherit font-lock-type-face))) - `(xah-elisp-dollar-symbol ((,class :inherit font-lock-variable-name-face))) -;;;;; xref - `(xref-file-header ((,class :inherit bold :foreground ,fg-special-cold))) - `(xref-line-number ((,class :inherit shadow))) - `(xref-match ((,class :inherit match))) + `(xah-elisp-at-symbol ((,c :inherit font-lock-warning-face))) + `(xah-elisp-cap-variable ((,c :inherit font-lock-preprocessor-face))) + `(xah-elisp-command-face ((,c :inherit font-lock-type-face))) + `(xah-elisp-dollar-symbol ((,c :inherit font-lock-variable-name-face))) ;;;;; yaml-mode - `(yaml-tab-face ((,class :inherit modus-themes-intense-red))) + `(yaml-tab-face ((,c :inherit modus-themes-intense-red))) ;;;;; yasnippet - `(yas-field-highlight-face ((,class :background ,bg-hl-alt-intense))) -;;;;; ztree - `(ztreep-arrow-face ((,class :foreground ,fg-inactive))) - `(ztreep-diff-header-face ((,class :inherit bold :height 1.2 :foreground ,fg-special-cold))) - `(ztreep-diff-header-small-face ((,class :foreground ,fg-main))) - `(ztreep-diff-model-add-face ((,class :inherit modus-themes-grue))) - `(ztreep-diff-model-diff-face ((,class :foreground ,red))) - `(ztreep-diff-model-ignored-face ((,class :inherit shadow :strike-through t))) - `(ztreep-diff-model-normal-face ((,class :inherit shadow))) - `(ztreep-expand-sign-face ((,class :inherit ztreep-arrow-face))) - `(ztreep-header-face ((,class :inherit bold :height 1.2 :foreground ,fg-special-cold))) - `(ztreep-leaf-face ((,class :foreground ,cyan))) - `(ztreep-node-count-children-face ((,class :foreground ,fg-special-warm))) - `(ztreep-node-face ((,class :foreground ,fg-main)))) + `(yas-field-highlight-face ((,c :inherit highlight)))) "Face specs for use with `modus-themes-theme'.") (defconst modus-themes-custom-variables @@ -7477,93 +3677,161 @@ by virtue of calling either of `modus-themes-load-operandi' and ;;;; ansi-colors `(ansi-color-faces-vector [default bold shadow italic underline success warning error]) `(ansi-color-names-vector ["gray35" ,red ,green ,yellow ,blue ,magenta ,cyan "gray65"]) -;;;; awesome-tray - `(awesome-tray-mode-line-active-color ,blue) - `(awesome-tray-mode-line-inactive-color ,bg-active) ;;;; chart `(chart-face-color-list - '( ,red-graph-0-bg ,green-graph-0-bg ,yellow-graph-0-bg ,blue-graph-0-bg ,magenta-graph-0-bg ,cyan-graph-0-bg - ,red-graph-1-bg ,green-graph-1-bg ,yellow-graph-1-bg ,blue-graph-1-bg ,magenta-graph-1-bg ,cyan-graph-1-bg)) + '( ,bg-graph-red-0 ,bg-graph-green-0 ,bg-graph-yellow-0 ,bg-graph-blue-0 ,bg-graph-magenta-0 ,bg-graph-cyan-0 + ,bg-graph-red-1 ,bg-graph-green-1 ,bg-graph-yellow-1 ,bg-graph-blue-1 ,bg-graph-magenta-1 ,bg-graph-cyan-1)) ;;;; exwm - `(exwm-floating-border-color ,fg-window-divider-inner) + `(exwm-floating-border-color ,border) ;;;; flymake fringe indicators - `(flymake-error-bitmap '(flymake-double-exclamation-mark modus-themes-fringe-red)) - `(flymake-warning-bitmap '(exclamation-mark modus-themes-fringe-yellow)) - `(flymake-note-bitmap '(exclamation-mark modus-themes-fringe-cyan)) + `(flymake-error-bitmap '(flymake-double-exclamation-mark modus-themes-intense-red)) + `(flymake-warning-bitmap '(exclamation-mark modus-themes-intense-yellow)) + `(flymake-note-bitmap '(exclamation-mark modus-themes-intense-cyan)) ;;;; highlight-changes `(highlight-changes-colors nil) `(highlight-changes-face-list '(success warning error bold bold-italic)) ;;;; ibuffer `(ibuffer-deletion-face 'modus-themes-mark-del) - `(ibuffer-filter-group-name-face 'modus-themes-pseudo-header) + `(ibuffer-filter-group-name-face 'bold) `(ibuffer-marked-face 'modus-themes-mark-sel) `(ibuffer-title-face 'default) ;;;; hl-todo `(hl-todo-keyword-faces - '(("HOLD" . ,yellow-alt) - ("TODO" . ,magenta) - ("NEXT" . ,magenta-alt-other) - ("THEM" . ,magenta-alt) - ("PROG" . ,cyan) - ("OKAY" . ,cyan-alt) - ("DONT" . ,green-alt) - ("FAIL" . ,red) - ("BUG" . ,red) - ("DONE" . ,green) - ("NOTE" . ,yellow-alt-other) - ("KLUDGE" . ,yellow) - ("HACK" . ,yellow) - ("TEMP" . ,red-nuanced-fg) - ("FIXME" . ,red-alt-other) - ("XXX+" . ,red-alt) - ("REVIEW" . ,cyan-alt-other) - ("DEPRECATED" . ,blue-nuanced-fg))) -;;;; mini-modeline - `(mini-modeline-face-attr '(:background unspecified)) + '(("HOLD" . ,warning) + ("TODO" . ,err) + ("NEXT" . ,fg-alt) + ("THEM" . ,fg-alt) + ("PROG" . ,info) + ("OKAY" . ,info) + ("DONT" . ,warning) + ("FAIL" . ,err) + ("BUG" . ,err) + ("DONE" . ,info) + ("NOTE" . ,warning) + ("KLUDGE" . ,warning) + ("HACK" . ,warning) + ("TEMP" . ,warning) + ("FIXME" . ,err) + ("XXX+" . ,err) + ("REVIEW" . ,info) + ("DEPRECATED" . ,info))) ;;;; pdf-tools - `(pdf-view-midnight-colors - '(,fg-main . ,bg-dim)) -;;;; wid-edit - `(widget-link-prefix ,(if (memq 'all-buttons modus-themes-box-buttons) - " " - "[")) - `(widget-link-suffix ,(if (memq 'all-buttons modus-themes-box-buttons) - " " - "]")) - `(widget-mouse-face '(highlight widget-button)) - `(widget-push-button-prefix ,(if (memq 'all-buttons modus-themes-box-buttons) - " " - "[")) - `(widget-push-button-suffix ,(if (memq 'all-buttons modus-themes-box-buttons) - " " - "]")) -;;;; xterm-color - `(xterm-color-names ["black" ,red ,green ,yellow ,blue ,magenta ,cyan "gray65"]) - `(xterm-color-names-bright ["gray35" ,red-alt ,green-alt ,yellow-alt ,blue-alt ,magenta-alt ,cyan-alt "white"]) + `(pdf-view-midnight-colors '(,fg-main . ,bg-dim)) +;;;; rcirc-color + `(rcirc-colors + '(modus-themes-fg-red + modus-themes-fg-green + modus-themes-fg-blue + modus-themes-fg-yellow + modus-themes-fg-magenta + modus-themes-fg-cyan + modus-themes-fg-red-warmer + modus-themes-fg-green-warmer + modus-themes-fg-blue-warmer + modus-themes-fg-yellow-warmer + modus-themes-fg-magenta-warmer + modus-themes-fg-cyan-warmer + modus-themes-fg-red-cooler + modus-themes-fg-green-cooler + modus-themes-fg-blue-cooler + modus-themes-fg-yellow-cooler + modus-themes-fg-magenta-cooler + modus-themes-fg-cyan-cooler + modus-themes-fg-red-faint + modus-themes-fg-green-faint + modus-themes-fg-blue-faint + modus-themes-fg-yellow-faint + modus-themes-fg-magenta-faint + modus-themes-fg-cyan-faint + modus-themes-fg-red-intense + modus-themes-fg-green-intense + modus-themes-fg-blue-intense + modus-themes-fg-yellow-intense + modus-themes-fg-magenta-intense + modus-themes-fg-cyan-intense)) +;;;; org-src-block-faces (if (or (eq modus-themes-org-blocks 'tinted-background) (eq modus-themes-org-blocks 'rainbow)) `(org-src-block-faces - `(("emacs-lisp" modus-themes-nuanced-magenta) - ("elisp" modus-themes-nuanced-magenta) - ("clojure" modus-themes-nuanced-magenta) - ("clojurescript" modus-themes-nuanced-magenta) - ("c" modus-themes-nuanced-blue) - ("c++" modus-themes-nuanced-blue) - ("sh" modus-themes-nuanced-green) - ("shell" modus-themes-nuanced-green) - ("html" modus-themes-nuanced-yellow) - ("xml" modus-themes-nuanced-yellow) - ("css" modus-themes-nuanced-red) - ("scss" modus-themes-nuanced-red) - ("python" modus-themes-nuanced-green) - ("ipython" modus-themes-nuanced-magenta) - ("r" modus-themes-nuanced-cyan) - ("yaml" modus-themes-nuanced-cyan) - ("conf" modus-themes-nuanced-cyan) - ("docker" modus-themes-nuanced-cyan))) + `(("emacs-lisp" (:inherit modus-themes-subtle-magenta :extend t)) + ("elisp" (:inherit modus-themes-subtle-magenta :extend t)) + ("clojure" (:inherit modus-themes-subtle-magenta :extend t)) + ("clojurescript" (:inherit modus-themes-subtle-magenta :extend t)) + ("c" (:inherit modus-themes-subtle-blue :extend t)) + ("c++" (:inherit modus-themes-subtle-blue :extend t)) + ("sh" (:inherit modus-themes-subtle-green :extend t)) + ("shell" (:inherit modus-themes-subtle-green :extend t)) + ("html" (:inherit modus-themes-subtle-yellow :extend t)) + ("xml" (:inherit modus-themes-subtle-yellow :extend t)) + ("css" (:inherit modus-themes-subtle-red :extend t)) + ("scss" (:inherit modus-themes-subtle-red :extend t)) + ("python" (:inherit modus-themes-subtle-green :extend t)) + ("ipython" (:inherit modus-themes-subtle-magenta :extend t)) + ("r" (:inherit modus-themes-subtle-cyan :extend t)) + ("yaml" (:inherit modus-themes-subtle-cyan :extend t)) + ("conf" (:inherit modus-themes-subtle-cyan :extend t)) + ("docker" (:inherit modus-themes-subtle-cyan :extend t)))) `(org-src-block-faces '()))) "Custom variables for `modus-themes-theme'.") +;;; Theme macros + +;;;; Instantiate a Modus theme + +;;;###autoload +(defmacro modus-themes-theme (name palette &optional overrides) + "Bind NAME's color PALETTE around face specs and variables. +Face specifications are passed to `custom-theme-set-faces'. +While variables are handled by `custom-theme-set-variables'. +Those are stored in `modus-themes-faces' and +`modus-themes-custom-variables' respectively. + +Optional OVERRIDES are appended to PALETTE, overriding +corresponding entries." + (declare (indent 0)) + (let ((sym (gensym)) + (colors (mapcar #'car (symbol-value palette)))) + `(let* ((c '((class color) (min-colors 256))) + (,sym (append ,overrides modus-themes-common-palette-overrides ,palette)) + ,@(mapcar (lambda (color) + (list color + `(let* ((value (car (alist-get ',color ,sym)))) + (if (or (stringp value) + (eq value 'unspecified)) + value + (car (alist-get value ,sym)))))) + colors)) + (ignore c ,@colors) ; Silence unused variable warnings + (custom-theme-set-faces ',name ,@modus-themes-faces) + (custom-theme-set-variables ',name ,@modus-themes-custom-variables)))) + +;;;; Use theme colors + +(defmacro modus-themes-with-colors (&rest body) + "Evaluate BODY with colors from current palette bound." + (declare (indent 0)) + (let* ((sym (gensym)) + ;; NOTE 2022-08-23: We just give it a sample palette at this + ;; stage. It only needs to collect each car. Then we + ;; instantiate the actual theme's palette. We have to do this + ;; otherwise the macro does not work properly when called from + ;; inside a function. + (colors (mapcar #'car (modus-themes--current-theme-palette)))) + `(let* ((c '((class color) (min-colors 256))) + (,sym (modus-themes--current-theme-palette :overrides)) + ,@(mapcar (lambda (color) + (list color + `(let* ((value (car (alist-get ',color ,sym)))) + (if (or (stringp value) + (eq value 'unspecified)) + value + (car (alist-get value ,sym)))))) + colors)) + (ignore c ,@colors) ; Silence unused variable warnings + ,@body))) + +;;;; Add themes from package to path + ;;;###autoload (when load-file-name (let ((dir (file-name-directory load-file-name))) diff --git a/etc/themes/modus-vivendi-deuteranopia-theme.el b/etc/themes/modus-vivendi-deuteranopia-theme.el new file mode 100644 index 00000000000..2c3ecd72a03 --- /dev/null +++ b/etc/themes/modus-vivendi-deuteranopia-theme.el @@ -0,0 +1,419 @@ +;;; modus-vivendi-deuteranopia-theme.el --- Elegant, highly legible and customizable dark theme -*- lexical-binding:t -*- + +;; Copyright (C) 2019-2023 Free Software Foundation, Inc. + +;; Author: Protesilaos Stavrou <info@protesilaos.com> +;; Maintainer: Modus-Themes Development <~protesilaos/modus-themes@lists.sr.ht> +;; URL: https://git.sr.ht/~protesilaos/modus-themes +;; Mailing-List: https://lists.sr.ht/~protesilaos/modus-themes + +;; 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: +;; +;; The Modus themes conform with the highest standard for +;; color-contrast accessibility between background and foreground +;; values (WCAG AAA). Please refer to the official Info manual for +;; further documentation (distributed with the themes, or available +;; at: <https://protesilaos.com/emacs/modus-themes>). + +;;; Code: + + + +(eval-and-compile + (unless (and (fboundp 'require-theme) + load-file-name + (equal (file-name-directory load-file-name) + (expand-file-name "themes/" data-directory)) + (require-theme 'modus-themes t)) + (require 'modus-themes)) + + (deftheme modus-vivendi-deuteranopia + "Elegant, highly legible and customizable dark theme. +This variant is optimized for users with red-green color +deficiency (deuteranopia). It conforms with the highest +legibility standard for color contrast between background and +foreground in any given piece of text, which corresponds to a +minimum contrast in relative luminance of 7:1 (WCAG AAA +standard).") + + (defconst modus-vivendi-deuteranopia-palette + '( +;;; Basic values + + (bg-main "#000000") + (bg-dim "#1e1e1e") + (fg-main "#ffffff") + (fg-dim "#989898") + (fg-alt "#c6daff") + (bg-active "#535353") + (bg-inactive "#303030") + (border "#646464") + +;;; Common accent foregrounds + + (red "#ff5f59") + (red-warmer "#ff6b55") + (red-cooler "#ff7f9f") + (red-faint "#ff9580") + (red-intense "#ff5f5f") + (green "#44bc44") + (green-warmer "#70b900") + (green-cooler "#00c06f") + (green-faint "#88ca9f") + (green-intense "#44df44") + (yellow "#d0bc00") + (yellow-warmer "#fec43f") + (yellow-cooler "#dfaf7a") + (yellow-faint "#d2b580") + (yellow-intense "#efef00") + (blue "#2fafff") + (blue-warmer "#79a8ff") + (blue-cooler "#00bcff") + (blue-faint "#82b0ec") + (blue-intense "#338fff") + (magenta "#feacd0") + (magenta-warmer "#f78fe7") + (magenta-cooler "#b6a0ff") + (magenta-faint "#caa6df") + (magenta-intense "#ff66ff") + (cyan "#00d3d0") + (cyan-warmer "#4ae2f0") + (cyan-cooler "#6ae4b9") + (cyan-faint "#9ac8e0") + (cyan-intense "#00eff0") + +;;; Uncommon accent foregrounds + + (rust "#db7b5f") + (gold "#c0965b") + (olive "#9cbd6f") + (slate "#76afbf") + (indigo "#9099d9") + (maroon "#cf7fa7") + (pink "#d09dc0") + +;;; Common accent backgrounds + + (bg-red-intense "#9d1f1f") + (bg-green-intense "#2f822f") + (bg-yellow-intense "#7a6100") + (bg-blue-intense "#1640b0") + (bg-magenta-intense "#7030af") + (bg-cyan-intense "#2266ae") + + (bg-red-subtle "#620f2a") + (bg-green-subtle "#00422a") + (bg-yellow-subtle "#4a4000") + (bg-blue-subtle "#242679") + (bg-magenta-subtle "#552f5f") + (bg-cyan-subtle "#004065") + + (bg-red-nuanced "#2c0614") + (bg-green-nuanced "#001904") + (bg-yellow-nuanced "#221000") + (bg-blue-nuanced "#0f0e39") + (bg-magenta-nuanced "#230631") + (bg-cyan-nuanced "#041529") + +;;; Uncommon accent backgrounds + + (bg-ochre "#442c2f") + (bg-lavender "#38325c") + (bg-sage "#0f3d30") + +;;; Graphs + + (bg-graph-red-0 "#705c3c") + (bg-graph-red-1 "#504420") + (bg-graph-green-0 "#4f666f") + (bg-graph-green-1 "#204840") + (bg-graph-yellow-0 "#c1c00a") + (bg-graph-yellow-1 "#6f6f00") + (bg-graph-blue-0 "#2fafef") + (bg-graph-blue-1 "#1f2f8f") + (bg-graph-magenta-0 "#7f7f8e") + (bg-graph-magenta-1 "#4f4f5f") + (bg-graph-cyan-0 "#376f9a") + (bg-graph-cyan-1 "#00404f") + +;;; Special purpose + + (bg-completion "#2f447f") + (bg-hover "#004f70") + (bg-hover-secondary "#654a39") + (bg-hl-line "#2f3849") + (bg-region "#5a5a5a") + (fg-region "#ffffff") + + (bg-char-0 "#0050af") + (bg-char-1 "#7f1f7f") + (bg-char-2 "#625a00") + + (bg-mode-line-active "#2a2a6a") + (fg-mode-line-active "#f0f0f0") + (border-mode-line-active "#8080a7") + (bg-mode-line-inactive "#2d2d2d") + (fg-mode-line-inactive "#969696") + (border-mode-line-inactive "#606060") + + (modeline-err "#e5bf00") + (modeline-warning "#c0cf35") + (modeline-info "#abeadf") + + (bg-tab-bar "#313131") + (bg-tab-current "#000000") + (bg-tab-other "#545454") + +;;; Diffs + + (bg-added "#003066") + (bg-added-faint "#001a4f") + (bg-added-refine "#0f4a77") + (bg-added-intense "#0f4fbf") + (fg-added "#c4d5ff") + (fg-added-intense "#a0afff") + + (bg-changed "#2f123f") + (bg-changed-faint "#1f022f") + (bg-changed-refine "#3f325f") + (bg-changed-intense "#7f42af") + (fg-changed "#e3cfff") + (fg-changed-intense "#c0a4ff") + + (bg-removed "#3d3d00") + (bg-removed-faint "#281f00") + (bg-removed-refine "#515100") + (bg-removed-intense "#dfd23a") + (fg-removed "#d4d48f") + (fg-removed-intense "#c0b05f") + +;;; Paren match + + (bg-paren-match "#2f7f9f") + (bg-paren-expression "#453040") + (underline-paren-match unspecified) + +;;; Mappings + +;;;; General mappings + + (fringe bg-dim) + (cursor yellow-intense) + + (keybind blue-cooler) + (name blue-cooler) + (identifier yellow-faint) + + (err yellow-warmer) + (warning yellow-cooler) + (info blue) + + (underline-err yellow-intense) + (underline-warning magenta-faint) + (underline-note cyan) + +;;;; Code mappings + + (builtin magenta-warmer) + (comment yellow-cooler) + (constant blue-cooler) + (docstring cyan-faint) + (docmarkup magenta-faint) + (fnname magenta) + (keyword magenta-cooler) + (preprocessor red-cooler) + (string blue-warmer) + (type cyan-cooler) + (variable cyan) + (rx-construct yellow-cooler) + (rx-backslash blue-cooler) + +;;;; Accent mappings + + (accent-0 blue-cooler) + (accent-1 yellow) + (accent-2 cyan-cooler) + (accent-3 magenta-warmer) + +;;;; Button mappings + + (fg-button-active fg-main) + (fg-button-inactive fg-dim) + (bg-button-active bg-active) + (bg-button-inactive bg-dim) + +;;;; Completion mappings + + (fg-completion-match-0 blue-cooler) + (fg-completion-match-1 yellow) + (fg-completion-match-2 cyan-cooler) + (fg-completion-match-3 magenta-warmer) + (bg-completion-match-0 unspecified) + (bg-completion-match-1 unspecified) + (bg-completion-match-2 unspecified) + (bg-completion-match-3 unspecified) + +;;;; Date mappings + + (date-common cyan) + (date-deadline yellow-warmer) + (date-event fg-alt) + (date-holiday yellow-warmer) + (date-now blue-faint) + (date-scheduled yellow-cooler) + (date-weekday cyan) + (date-weekend yellow-faint) + +;;;; Line number mappings + + (fg-line-number-inactive fg-dim) + (fg-line-number-active fg-main) + (bg-line-number-inactive bg-dim) + (bg-line-number-active bg-active) + +;;;; Link mappings + + (fg-link blue-warmer) + (bg-link unspecified) + (underline-link blue-warmer) + + (fg-link-symbolic cyan) + (bg-link-symbolic unspecified) + (underline-link-symbolic cyan) + + (fg-link-visited yellow-faint) + (bg-link-visited unspecified) + (underline-link-visited yellow-faint) + +;;;; Mail mappings + + (mail-cite-0 blue-warmer) + (mail-cite-1 yellow-cooler) + (mail-cite-2 blue-cooler) + (mail-cite-3 yellow) + (mail-part blue) + (mail-recipient blue) + (mail-subject yellow-warmer) + (mail-other cyan-faint) + +;;;; Prompt mappings + + (fg-prompt blue) + (bg-prompt unspecified) + +;;;; Prose mappings + + (prose-block fg-dim) + (prose-code cyan-cooler) + (prose-done blue) + (prose-macro magenta-cooler) + (prose-metadata fg-dim) + (prose-metadata-value fg-alt) + (prose-table fg-alt) + (prose-tag magenta-faint) + (prose-todo yellow-warmer) + (prose-verbatim magenta-warmer) + +;;;; Rainbow mappings + + (rainbow-0 yellow-warmer) + (rainbow-1 blue) + (rainbow-2 yellow-cooler) + (rainbow-3 blue-warmer) + (rainbow-4 yellow) + (rainbow-5 cyan-warmer) + (rainbow-6 yellow-faint) + (rainbow-7 blue-faint) + (rainbow-8 magenta-faint) + +;;;; Heading mappings + + (fg-heading-0 cyan-cooler) + (fg-heading-1 fg-main) + (fg-heading-2 yellow-faint) + (fg-heading-3 blue-faint) + (fg-heading-4 magenta) + (fg-heading-5 green-faint) + (fg-heading-6 red-faint) + (fg-heading-7 cyan-faint) + (fg-heading-8 fg-dim) + + (bg-heading-0 unspecified) + (bg-heading-1 unspecified) + (bg-heading-2 unspecified) + (bg-heading-3 unspecified) + (bg-heading-4 unspecified) + (bg-heading-5 unspecified) + (bg-heading-6 unspecified) + (bg-heading-7 unspecified) + (bg-heading-8 unspecified) + + (overline-heading-0 unspecified) + (overline-heading-1 unspecified) + (overline-heading-2 unspecified) + (overline-heading-3 unspecified) + (overline-heading-4 unspecified) + (overline-heading-5 unspecified) + (overline-heading-6 unspecified) + (overline-heading-7 unspecified) + (overline-heading-8 unspecified)) + "The entire palette of the `modus-vivendi-deuteranopia' theme. + +Named colors have the form (COLOR-NAME HEX-VALUE) with the former +as a symbol and the latter as a string. + +Semantic color mappings have the form (MAPPING-NAME COLOR-NAME) +with both as symbols. The latter is a named color that already +exists in the palette and is associated with a HEX-VALUE. + +Semantic color mappings cannot be recursive: their value must be +either COLOR-NAME or HEX-VALUE.") + + (defcustom modus-vivendi-deuteranopia-palette-overrides nil + "Overrides for `modus-vivendi-deuteranopia-palette'. + +Mirror the elements of the aforementioned palette, overriding +their value. + +For overrides that are shared across all of the Modus themes, +refer to `modus-themes-common-palette-overrides'. + +Theme-specific overrides take precedence over shared overrides. +The idea of common overrides is to change semantic color +mappings, such as to make the cursor red. Wherea theme-specific +overrides can also be used to change the value of a named color, +such as what hexadecimal RGB value the red-warmer symbol +represents." + :group 'modus-themes + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :type '(repeat (list symbol (choice symbol string))) + :set #'modus-themes--set-option + :initialize #'custom-initialize-default + :link '(info-link "(modus-themes) Palette overrides")) + + (modus-themes-theme modus-vivendi-deuteranopia + modus-vivendi-deuteranopia-palette + modus-vivendi-deuteranopia-palette-overrides) + + (provide-theme 'modus-vivendi-deuteranopia)) + +;;;###theme-autoload +(put 'modus-vivendi-deuteranopia 'theme-properties '(:background-mode dark :kind color-scheme :family modus)) + +;;; modus-vivendi-deuteranopia-theme.el ends here diff --git a/etc/themes/modus-vivendi-theme.el b/etc/themes/modus-vivendi-theme.el index 6b365f421cc..d2ec3fd2753 100644 --- a/etc/themes/modus-vivendi-theme.el +++ b/etc/themes/modus-vivendi-theme.el @@ -1,14 +1,11 @@ ;;; modus-vivendi-theme.el --- Elegant, highly legible and customizable dark theme -*- lexical-binding:t -*- -;; Copyright (C) 2019-2023 Free Software Foundation, Inc. +;; Copyright (C) 2019-2023 Free Software Foundation, Inc. ;; Author: Protesilaos Stavrou <info@protesilaos.com> ;; Maintainer: Modus-Themes Development <~protesilaos/modus-themes@lists.sr.ht> ;; URL: https://git.sr.ht/~protesilaos/modus-themes ;; Mailing-List: https://lists.sr.ht/~protesilaos/modus-themes -;; Version: 3.0.0 -;; Package-Requires: ((emacs "27.1")) -;; Keywords: faces, theme, accessibility ;; This file is part of GNU Emacs. @@ -27,26 +24,11 @@ ;;; Commentary: ;; -;; Modus Vivendi is the dark variant of the Modus themes (Modus Operandi -;; is the light one). The themes are designed for color-contrast -;; accessibility. More specifically: -;; -;; 1. Provide a consistent minimum contrast ratio between background -;; and foreground values of 7:1 or higher. This meets the highest -;; such accessibility criterion per the guidelines of the Worldwide -;; Web Consortium's Working Group on Accessibility (WCAG AAA -;; standard). -;; -;; 2. Offer as close to full face coverage as possible. The list is -;; already quite long, with more additions to follow as part of the -;; ongoing development process. -;; -;; For a complete view of the project, also refer to the following files -;; (should be distributed in the same repository/directory as the -;; current item): -;; -;; - modus-themes.el (Main code shared between the themes) -;; - modus-operandi-theme.el (Light theme) +;; The Modus themes conform with the highest standard for +;; color-contrast accessibility between background and foreground +;; values (WCAG AAA). Please refer to the official Info manual for +;; further documentation (distributed with the themes, or available +;; at: <https://protesilaos.com/emacs/modus-themes>). ;;; Code: @@ -67,7 +49,366 @@ between background and foreground in any given piece of text, which corresponds to a minimum contrast in relative luminance of 7:1 (WCAG AAA standard).") - (modus-themes-theme modus-vivendi) + (defconst modus-vivendi-palette + '( +;;; Basic values + + (bg-main "#000000") + (bg-dim "#1e1e1e") + (fg-main "#ffffff") + (fg-dim "#989898") + (fg-alt "#c6daff") + (bg-active "#535353") + (bg-inactive "#303030") + (border "#646464") + +;;; Common accent foregrounds + + (red "#ff5f59") + (red-warmer "#ff6b55") + (red-cooler "#ff7f9f") + (red-faint "#ff9580") + (red-intense "#ff5f5f") + (green "#44bc44") + (green-warmer "#70b900") + (green-cooler "#00c06f") + (green-faint "#88ca9f") + (green-intense "#44df44") + (yellow "#d0bc00") + (yellow-warmer "#fec43f") + (yellow-cooler "#dfaf7a") + (yellow-faint "#d2b580") + (yellow-intense "#efef00") + (blue "#2fafff") + (blue-warmer "#79a8ff") + (blue-cooler "#00bcff") + (blue-faint "#82b0ec") + (blue-intense "#338fff") + (magenta "#feacd0") + (magenta-warmer "#f78fe7") + (magenta-cooler "#b6a0ff") + (magenta-faint "#caa6df") + (magenta-intense "#ff66ff") + (cyan "#00d3d0") + (cyan-warmer "#4ae2f0") + (cyan-cooler "#6ae4b9") + (cyan-faint "#9ac8e0") + (cyan-intense "#00eff0") + +;;; Uncommon accent foregrounds + + (rust "#db7b5f") + (gold "#c0965b") + (olive "#9cbd6f") + (slate "#76afbf") + (indigo "#9099d9") + (maroon "#cf7fa7") + (pink "#d09dc0") + +;;; Common accent backgrounds + + (bg-red-intense "#9d1f1f") + (bg-green-intense "#2f822f") + (bg-yellow-intense "#7a6100") + (bg-blue-intense "#1640b0") + (bg-magenta-intense "#7030af") + (bg-cyan-intense "#2266ae") + + (bg-red-subtle "#620f2a") + (bg-green-subtle "#00422a") + (bg-yellow-subtle "#4a4000") + (bg-blue-subtle "#242679") + (bg-magenta-subtle "#552f5f") + (bg-cyan-subtle "#004065") + + (bg-red-nuanced "#2c0614") + (bg-green-nuanced "#001904") + (bg-yellow-nuanced "#221000") + (bg-blue-nuanced "#0f0e39") + (bg-magenta-nuanced "#230631") + (bg-cyan-nuanced "#041529") + +;;; Uncommon accent backgrounds + + (bg-ochre "#442c2f") + (bg-lavender "#38325c") + (bg-sage "#0f3d30") + +;;; Graphs + + (bg-graph-red-0 "#b52c2c") + (bg-graph-red-1 "#702020") + (bg-graph-green-0 "#4fd100") + (bg-graph-green-1 "#007800") + (bg-graph-yellow-0 "#f1e00a") + (bg-graph-yellow-1 "#b08600") + (bg-graph-blue-0 "#2fafef") + (bg-graph-blue-1 "#1f2f8f") + (bg-graph-magenta-0 "#bf94fe") + (bg-graph-magenta-1 "#5f509f") + (bg-graph-cyan-0 "#47dfea") + (bg-graph-cyan-1 "#00808f") + +;;; Special purpose + + (bg-completion "#2f447f") + (bg-hover "#004f70") + (bg-hover-secondary "#654a39") + (bg-hl-line "#2f3849") + (bg-region "#5a5a5a") + (fg-region "#ffffff") + + (bg-char-0 "#0050af") + (bg-char-1 "#7f1f7f") + (bg-char-2 "#625a00") + + (bg-mode-line-active "#505050") + (fg-mode-line-active "#ffffff") + (border-mode-line-active "#959595") + (bg-mode-line-inactive "#2d2d2d") + (fg-mode-line-inactive "#969696") + (border-mode-line-inactive "#606060") + + (modeline-err "#ffa9bf") + (modeline-warning "#dfcf43") + (modeline-info "#9fefff") + + (bg-tab-bar "#313131") + (bg-tab-current "#000000") + (bg-tab-other "#545454") + +;;; Diffs + + (bg-added "#00381f") + (bg-added-faint "#002910") + (bg-added-refine "#034f2f") + (bg-added-intense "#237f3f") + (fg-added "#a0e0a0") + (fg-added-intense "#80e080") + + (bg-changed "#363300") + (bg-changed-faint "#2a1f00") + (bg-changed-refine "#4a4a00") + (bg-changed-intense "#8a7a00") + (fg-changed "#efef80") + (fg-changed-intense "#c0b05f") + + (bg-removed "#4f1119") + (bg-removed-faint "#380a0f") + (bg-removed-refine "#781a1f") + (bg-removed-intense "#b81a1f") + (fg-removed "#ffbfbf") + (fg-removed-intense "#ff9095") + +;;; Paren match + + (bg-paren-match "#2f7f9f") + (bg-paren-expression "#453040") + (underline-paren-match unspecified) + +;;; Mappings + +;;;; General mappings + + (fringe bg-dim) + (cursor fg-main) + + (keybind blue-cooler) + (name magenta) + (identifier yellow-faint) + + (err red) + (warning yellow-warmer) + (info cyan-cooler) + + (underline-err red-intense) + (underline-warning yellow) + (underline-note cyan) + +;;;; Code mappings + + (builtin magenta-warmer) + (comment fg-dim) + (constant blue-cooler) + (docstring cyan-faint) + (docmarkup magenta-faint) + (fnname magenta) + (keyword magenta-cooler) + (preprocessor red-cooler) + (string blue-warmer) + (type cyan-cooler) + (variable cyan) + (rx-construct green-cooler) + (rx-backslash magenta) + +;;;; Accent mappings + + (accent-0 blue-cooler) + (accent-1 magenta-warmer) + (accent-2 cyan-cooler) + (accent-3 yellow) + +;;;; Button mappings + + (fg-button-active fg-main) + (fg-button-inactive fg-dim) + (bg-button-active bg-active) + (bg-button-inactive bg-dim) + +;;;; Completion mappings + + (fg-completion-match-0 blue-cooler) + (fg-completion-match-1 magenta-warmer) + (fg-completion-match-2 cyan-cooler) + (fg-completion-match-3 yellow) + (bg-completion-match-0 unspecified) + (bg-completion-match-1 unspecified) + (bg-completion-match-2 unspecified) + (bg-completion-match-3 unspecified) + +;;;; Date mappings + + (date-common cyan) + (date-deadline red) + (date-event fg-alt) + (date-holiday magenta) + (date-now fg-main) + (date-scheduled yellow-warmer) + (date-weekday cyan) + (date-weekend red-faint) + +;;;; Line number mappings + + (fg-line-number-inactive fg-dim) + (fg-line-number-active fg-main) + (bg-line-number-inactive bg-dim) + (bg-line-number-active bg-active) + +;;;; Link mappings + + (fg-link blue-warmer) + (bg-link unspecified) + (underline-link blue-warmer) + + (fg-link-symbolic cyan) + (bg-link-symbolic unspecified) + (underline-link-symbolic cyan) + + (fg-link-visited magenta) + (bg-link-visited unspecified) + (underline-link-visited magenta) + +;;;; Mail mappings + + (mail-cite-0 blue-warmer) + (mail-cite-1 yellow-cooler) + (mail-cite-2 cyan-cooler) + (mail-cite-3 red-cooler) + (mail-part blue) + (mail-recipient magenta-cooler) + (mail-subject magenta-warmer) + (mail-other magenta-faint) + +;;;; Prompt mappings + + (fg-prompt cyan-cooler) + (bg-prompt unspecified) + +;;;; Prose mappings + + (prose-block fg-dim) + (prose-code cyan-cooler) + (prose-done green) + (prose-macro magenta-cooler) + (prose-metadata fg-dim) + (prose-metadata-value fg-alt) + (prose-table fg-alt) + (prose-tag magenta-faint) + (prose-todo red) + (prose-verbatim magenta-warmer) + +;;;; Rainbow mappings + + (rainbow-0 fg-main) + (rainbow-1 magenta-intense) + (rainbow-2 cyan-intense) + (rainbow-3 red-warmer) + (rainbow-4 yellow-intense) + (rainbow-5 magenta-cooler) + (rainbow-6 green-intense) + (rainbow-7 blue-warmer) + (rainbow-8 magenta-warmer) + +;;;; Heading mappings + + (fg-heading-0 cyan-cooler) + (fg-heading-1 fg-main) + (fg-heading-2 yellow-faint) + (fg-heading-3 blue-faint) + (fg-heading-4 magenta) + (fg-heading-5 green-faint) + (fg-heading-6 red-faint) + (fg-heading-7 cyan-faint) + (fg-heading-8 fg-dim) + + (bg-heading-0 unspecified) + (bg-heading-1 unspecified) + (bg-heading-2 unspecified) + (bg-heading-3 unspecified) + (bg-heading-4 unspecified) + (bg-heading-5 unspecified) + (bg-heading-6 unspecified) + (bg-heading-7 unspecified) + (bg-heading-8 unspecified) + + (overline-heading-0 unspecified) + (overline-heading-1 unspecified) + (overline-heading-2 unspecified) + (overline-heading-3 unspecified) + (overline-heading-4 unspecified) + (overline-heading-5 unspecified) + (overline-heading-6 unspecified) + (overline-heading-7 unspecified) + (overline-heading-8 unspecified)) + "The entire palette of the `modus-vivendi' theme. + +Named colors have the form (COLOR-NAME HEX-VALUE) with the former +as a symbol and the latter as a string. + +Semantic color mappings have the form (MAPPING-NAME COLOR-NAME) +with both as symbols. The latter is a named color that already +exists in the palette and is associated with a HEX-VALUE. + +Semantic color mappings cannot be recursive: their value must be +either COLOR-NAME or HEX-VALUE.") + + + (defcustom modus-vivendi-palette-overrides nil + "Overrides for `modus-vivendi-palette'. + +Mirror the elements of the aforementioned palette, overriding +their value. + +For overrides that are shared across all of the Modus themes, +refer to `modus-themes-common-palette-overrides'. + +Theme-specific overrides take precedence over shared overrides. +The idea of common overrides is to change semantic color +mappings, such as to make the cursor red. Wherea theme-specific +overrides can also be used to change the value of a named color, +such as what hexadecimal RGB value the red-warmer symbol +represents." + :group 'modus-themes + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :type '(repeat (list symbol (choice symbol string))) + :set #'modus-themes--set-option + :initialize #'custom-initialize-default + :link '(info-link "(modus-themes) Palette overrides")) + + (modus-themes-theme modus-vivendi + modus-vivendi-palette + modus-vivendi-palette-overrides) (provide-theme 'modus-vivendi)) diff --git a/etc/themes/modus-vivendi-tinted-theme.el b/etc/themes/modus-vivendi-tinted-theme.el new file mode 100644 index 00000000000..001a8470986 --- /dev/null +++ b/etc/themes/modus-vivendi-tinted-theme.el @@ -0,0 +1,417 @@ +;;; modus-vivendi-tinted-theme.el --- Elegant, highly legible and customizable dark theme -*- lexical-binding:t -*- + +;; Copyright (C) 2019-2023 Free Software Foundation, Inc. + +;; Author: Protesilaos Stavrou <info@protesilaos.com> +;; Maintainer: Modus-Themes Development <~protesilaos/modus-themes@lists.sr.ht> +;; URL: https://git.sr.ht/~protesilaos/modus-themes +;; Mailing-List: https://lists.sr.ht/~protesilaos/modus-themes + +;; 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: +;; +;; The Modus themes conform with the highest standard for +;; color-contrast accessibility between background and foreground +;; values (WCAG AAA). Please refer to the official Info manual for +;; further documentation (distributed with the themes, or available +;; at: <https://protesilaos.com/emacs/modus-themes>). + +;;; Code: + + + +(eval-and-compile + (unless (and (fboundp 'require-theme) + load-file-name + (equal (file-name-directory load-file-name) + (expand-file-name "themes/" data-directory)) + (require-theme 'modus-themes t)) + (require 'modus-themes)) + + (deftheme modus-vivendi-tinted + "Elegant, highly legible and customizable dark theme. +Conforms with the highest legibility standard for color contrast +between background and foreground in any given piece of text, +which corresponds to a minimum contrast in relative luminance of +7:1 (WCAG AAA standard).") + + (defconst modus-vivendi-tinted-palette + '( +;;; Basic values + + (bg-main "#0d0e1c") + (bg-dim "#1d2235") + (fg-main "#ffffff") + (fg-dim "#989898") + (fg-alt "#c6daff") + (bg-active "#4a4f69") + (bg-inactive "#2b3045") + (border "#61647a") + +;;; Common accent foregrounds + + (red "#ff5f59") + (red-warmer "#ff6b55") + (red-cooler "#ff7f9f") + (red-faint "#ff9f80") + (red-intense "#ff5f5f") + (green "#44bc44") + (green-warmer "#70b900") + (green-cooler "#00c06f") + (green-faint "#88ca9f") + (green-intense "#44df44") + (yellow "#d0bc00") + (yellow-warmer "#fec43f") + (yellow-cooler "#dfaf7a") + (yellow-faint "#d2b580") + (yellow-intense "#efef00") + (blue "#2fafff") + (blue-warmer "#79a8ff") + (blue-cooler "#00bcff") + (blue-faint "#82b0ec") + (blue-intense "#338fff") + (magenta "#feacd0") + (magenta-warmer "#f78fe7") + (magenta-cooler "#b6a0ff") + (magenta-faint "#caa6df") + (magenta-intense "#ff66ff") + (cyan "#00d3d0") + (cyan-warmer "#4ae2f0") + (cyan-cooler "#6ae4b9") + (cyan-faint "#9ac8e0") + (cyan-intense "#00eff0") + +;;; Uncommon accent foregrounds + + (rust "#db7b5f") + (gold "#c0965b") + (olive "#9cbd6f") + (slate "#76afbf") + (indigo "#9099d9") + (maroon "#cf7fa7") + (pink "#d09dc0") + +;;; Common accent backgrounds + + (bg-red-intense "#9d1f1f") + (bg-green-intense "#2f822f") + (bg-yellow-intense "#7a6100") + (bg-blue-intense "#1640b0") + (bg-magenta-intense "#7030af") + (bg-cyan-intense "#2266ae") + + (bg-red-subtle "#620f2a") + (bg-green-subtle "#00422a") + (bg-yellow-subtle "#4a4000") + (bg-blue-subtle "#242679") + (bg-magenta-subtle "#552f5f") + (bg-cyan-subtle "#004065") + + (bg-red-nuanced "#2c0614") + (bg-green-nuanced "#001904") + (bg-yellow-nuanced "#221000") + (bg-blue-nuanced "#0f0e39") + (bg-magenta-nuanced "#230631") + (bg-cyan-nuanced "#041529") + +;;; Graphs + + (bg-graph-red-0 "#b52c2c") + (bg-graph-red-1 "#702020") + (bg-graph-green-0 "#4fd100") + (bg-graph-green-1 "#007800") + (bg-graph-yellow-0 "#f1e00a") + (bg-graph-yellow-1 "#b08600") + (bg-graph-blue-0 "#2fafef") + (bg-graph-blue-1 "#1f2f8f") + (bg-graph-magenta-0 "#bf94fe") + (bg-graph-magenta-1 "#5f509f") + (bg-graph-cyan-0 "#47dfea") + (bg-graph-cyan-1 "#00808f") + +;;; Special purpose + + (bg-completion "#483d8a") + (bg-hover "#004f70") + (bg-hover-secondary "#654a39") + (bg-hl-line "#303a6f") + (bg-region "#555a66") + (fg-region "#ffffff") + + (bg-char-0 "#0050af") + (bg-char-1 "#7f1f7f") + (bg-char-2 "#625a00") + + (bg-mode-line-active "#484d67") + (fg-mode-line-active "#ffffff") + (border-mode-line-active "#979797") + (bg-mode-line-inactive "#292d48") + (fg-mode-line-inactive "#969696") + (border-mode-line-inactive "#606270") + + (modeline-err "#ffa9bf") + (modeline-warning "#dfcf43") + (modeline-info "#9fefff") + + (bg-tab-bar "#2c3045") + (bg-tab-current "#0d0e1c") + (bg-tab-other "#4a4f6a") + +;;; Diffs + + (bg-added "#003a2f") + (bg-added-faint "#002922") + (bg-added-refine "#035542") + (bg-added-intense "#237f4f") + (fg-added "#a0e0a0") + (fg-added-intense "#80e080") + + (bg-changed "#363300") + (bg-changed-faint "#2a1f00") + (bg-changed-refine "#4a4a00") + (bg-changed-intense "#8a7a00") + (fg-changed "#efef80") + (fg-changed-intense "#c0b05f") + + (bg-removed "#4f1127") + (bg-removed-faint "#380a19") + (bg-removed-refine "#781a3a") + (bg-removed-intense "#b81a26") + (fg-removed "#ffbfbf") + (fg-removed-intense "#ff9095") + +;;; Uncommon accent backgrounds + + (bg-ochre "#442c2f") + (bg-lavender "#38325c") + (bg-sage "#0f3d30") + +;;; Paren match + + (bg-paren-match "#2f7f9f") + (bg-paren-expression "#453040") + (underline-paren-match unspecified) + +;;; Mappings + +;;;; General mappings + + (fringe bg-dim) + (cursor magenta-warmer) + + (keybind blue-cooler) + (name magenta) + (identifier yellow-faint) + + (err red) + (warning yellow-warmer) + (info cyan-cooler) + + (underline-err red-intense) + (underline-warning yellow) + (underline-note cyan) + +;;;; Code mappings + + (builtin magenta-warmer) + (comment red-faint) + (constant blue-cooler) + (docstring cyan-faint) + (docmarkup magenta-faint) + (fnname magenta) + (keyword magenta-cooler) + (preprocessor red-cooler) + (string blue-warmer) + (type cyan-cooler) + (variable cyan) + (rx-construct green-cooler) + (rx-backslash magenta) + +;;;; Accent mappings + + (accent-0 blue-cooler) + (accent-1 magenta-warmer) + (accent-2 cyan-cooler) + (accent-3 yellow) + +;;;; Button mappings + + (fg-button-active fg-main) + (fg-button-inactive fg-dim) + (bg-button-active bg-active) + (bg-button-inactive bg-dim) + +;;;; Completion mappings + + (fg-completion-match-0 blue-cooler) + (fg-completion-match-1 magenta-warmer) + (fg-completion-match-2 cyan-cooler) + (fg-completion-match-3 yellow) + (bg-completion-match-0 unspecified) + (bg-completion-match-1 unspecified) + (bg-completion-match-2 unspecified) + (bg-completion-match-3 unspecified) + +;;;; Date mappings + + (date-common cyan) + (date-deadline red) + (date-event fg-alt) + (date-holiday magenta) + (date-now fg-main) + (date-scheduled yellow-warmer) + (date-weekday cyan) + (date-weekend red-faint) + +;;;; Line number mappings + + (fg-line-number-inactive fg-dim) + (fg-line-number-active fg-main) + (bg-line-number-inactive bg-dim) + (bg-line-number-active bg-active) + +;;;; Link mappings + + (fg-link blue-warmer) + (bg-link unspecified) + (underline-link blue-warmer) + + (fg-link-symbolic cyan) + (bg-link-symbolic unspecified) + (underline-link-symbolic cyan) + + (fg-link-visited magenta) + (bg-link-visited unspecified) + (underline-link-visited magenta) + +;;;; Mail mappings + + (mail-cite-0 blue-warmer) + (mail-cite-1 yellow-cooler) + (mail-cite-2 cyan-cooler) + (mail-cite-3 red-cooler) + (mail-part blue) + (mail-recipient magenta-cooler) + (mail-subject magenta-warmer) + (mail-other magenta-faint) + +;;;; Prompt mappings + + (fg-prompt cyan-cooler) + (bg-prompt unspecified) + +;;;; Prose mappings + + (prose-block fg-dim) + (prose-code cyan-cooler) + (prose-done green) + (prose-macro magenta-cooler) + (prose-metadata fg-dim) + (prose-metadata-value fg-alt) + (prose-table fg-alt) + (prose-tag magenta-faint) + (prose-todo red) + (prose-verbatim magenta-warmer) + +;;;; Rainbow mappings + + (rainbow-0 fg-main) + (rainbow-1 magenta-intense) + (rainbow-2 cyan-intense) + (rainbow-3 red-warmer) + (rainbow-4 yellow-intense) + (rainbow-5 magenta-cooler) + (rainbow-6 green-intense) + (rainbow-7 blue-warmer) + (rainbow-8 magenta-warmer) + +;;;; Heading mappings + + (fg-heading-0 cyan-cooler) + (fg-heading-1 fg-main) + (fg-heading-2 yellow-faint) + (fg-heading-3 blue-faint) + (fg-heading-4 magenta) + (fg-heading-5 green-faint) + (fg-heading-6 red-faint) + (fg-heading-7 cyan-faint) + (fg-heading-8 fg-dim) + + (bg-heading-0 unspecified) + (bg-heading-1 unspecified) + (bg-heading-2 unspecified) + (bg-heading-3 unspecified) + (bg-heading-4 unspecified) + (bg-heading-5 unspecified) + (bg-heading-6 unspecified) + (bg-heading-7 unspecified) + (bg-heading-8 unspecified) + + (overline-heading-0 unspecified) + (overline-heading-1 unspecified) + (overline-heading-2 unspecified) + (overline-heading-3 unspecified) + (overline-heading-4 unspecified) + (overline-heading-5 unspecified) + (overline-heading-6 unspecified) + (overline-heading-7 unspecified) + (overline-heading-8 unspecified)) + "The entire palette of the `modus-vivendi-tinted' theme. + +Named colors have the form (COLOR-NAME HEX-VALUE) with the former +as a symbol and the latter as a string. + +Semantic color mappings have the form (MAPPING-NAME COLOR-NAME) +with both as symbols. The latter is a named color that already +exists in the palette and is associated with a HEX-VALUE. + +Semantic color mappings cannot be recursive: their value must be +either COLOR-NAME or HEX-VALUE.") + + (defcustom modus-vivendi-tinted-palette-overrides nil + "Overrides for `modus-vivendi-tinted-palette'. + +Mirror the elements of the aforementioned palette, overriding +their value. + +For overrides that are shared across all of the Modus themes, +refer to `modus-themes-common-palette-overrides'. + +Theme-specific overrides take precedence over shared overrides. +The idea of common overrides is to change semantic color +mappings, such as to make the cursor red. Wherea theme-specific +overrides can also be used to change the value of a named color, +such as what hexadecimal RGB value the red-warmer symbol +represents." + :group 'modus-themes + :package-version '(modus-themes . "4.0.0") + :version "30.1" + :type '(repeat (list symbol (choice symbol string))) + :set #'modus-themes--set-option + :initialize #'custom-initialize-default + :link '(info-link "(modus-themes) Palette overrides")) + + (modus-themes-theme modus-vivendi-tinted + modus-vivendi-tinted-palette + modus-vivendi-tinted-palette-overrides) + + (provide-theme 'modus-vivendi-tinted)) + +;;;###theme-autoload +(put 'modus-vivendi-tinted 'theme-properties '(:background-mode dark :kind color-scheme :family modus)) + +;;; modus-vivendi-tinted-theme.el ends here diff --git a/lib-src/Makefile.in b/lib-src/Makefile.in index b246d832943..5b82cf1151c 100644 --- a/lib-src/Makefile.in +++ b/lib-src/Makefile.in @@ -193,18 +193,18 @@ LIBRESOLV=@LIBRESOLV@ ## -llockfile if HAVE_LIBLOCKFILE or -lmail if HAVE_LIBMAIL LIBS_MAIL=@LIBS_MAIL@ ## empty or -lrt or -lposix4 if HAVE_CLOCK_GETTIME -LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@ +CLOCK_TIME_LIB = @CLOCK_TIME_LIB@ ## empty or -lbcrypt or -ladvapi32 -LIB_GETRANDOM = @LIB_GETRANDOM@ +GETRANDOM_LIB = @GETRANDOM_LIB@ ## Whatever libraries are needed for euidaccess -LIB_EACCESS=@LIB_EACCESS@ +EUIDACCESS_LIBGEN=@EUIDACCESS_LIBGEN@ ## Libraries needed for file_has_acl -LIB_HAS_ACL=@LIB_HAS_ACL@ +FILE_HAS_ACL_LIB=@FILE_HAS_ACL_LIB@ ## empty or -lwsock2 for MinGW LIB_WSOCK32=@LIB_WSOCK32@ ## Extra libraries for etags -LIBS_ETAGS = $(LIB_CLOCK_GETTIME) $(LIB_GETRANDOM) +LIBS_ETAGS = $(CLOCK_TIME_LIB) $(GETRANDOM_LIB) HAVE_SECCOMP=@HAVE_SECCOMP@ HAVE_LIBSECCOMP=@HAVE_LIBSECCOMP@ @@ -426,12 +426,14 @@ pop.o: ${srcdir}/pop.c ${srcdir}/pop.h ${srcdir}/../lib/min-max.h $(config_h) emacsclient${EXEEXT}: ${srcdir}/emacsclient.c $(NTLIB) $(config_h) $(AM_V_CCLD)$(CC) ${ALL_CFLAGS} $< \ $(NTLIB) $(LOADLIBES) \ - $(LIB_WSOCK32) $(LIB_EACCESS) $(LIB_HAS_ACL) $(LIBS_ECLIENT) -o $@ + $(LIB_WSOCK32) $(EUIDACCESS_LIBGEN) \ + $(FILE_HAS_ACL_LIB) $(LIBS_ECLIENT) \ + -o $@ emacsclientw${EXEEXT}: ${srcdir}/emacsclient.c $(NTLIB) $(CLIENTRES) $(config_h) $(AM_V_CCLD)$(CC) ${ALL_CFLAGS} $(CLIENTRES) -mwindows $< \ $(LOADLIBES) \ - $(LIB_WSOCK32) $(LIB_EACCESS) $(LIBS_ECLIENT) -o $@ + $(LIB_WSOCK32) $(EUIDACCESS_LIBGEN) $(LIBS_ECLIENT) -o $@ be-resources: ${srcdir}/be_resources.cc ${config_h} $(AM_V_CXXLD)$(CXX) ${ALL_CXXFLAGS} ${HAIKU_LIBS} $< -o $@ diff --git a/lib-src/etags.c b/lib-src/etags.c index 9fb9e312a66..2628849d78e 100644 --- a/lib-src/etags.c +++ b/lib-src/etags.c @@ -7772,7 +7772,7 @@ escape_shell_arg_string (char *str) #endif static void -do_move_file(const char *src_file, const char *dst_file) +do_move_file (const char *src_file, const char *dst_file) { if (rename (src_file, dst_file) == 0) return; diff --git a/lib/alloca.in.h b/lib/alloca.in.h index b9ce9ef5603..a1bb3d758dc 100644 --- a/lib/alloca.in.h +++ b/lib/alloca.in.h @@ -1,7 +1,7 @@ /* Memory allocation on the stack. - Copyright (C) 1995, 1999, 2001-2004, 2006-2023 Free Software - Foundation, Inc. + Copyright (C) 1995, 1999, 2001-2004, 2006-2023 Free Software Foundation, + Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/attribute.h b/lib/attribute.h index 36b2978bb2c..130644d8798 100644 --- a/lib/attribute.h +++ b/lib/attribute.h @@ -32,7 +32,7 @@ /* This file defines two types of attributes: - * C2x standard attributes. These have macro names that do not begin with + * C23 standard attributes. These have macro names that do not begin with 'ATTRIBUTE_'. * Selected GCC attributes; see: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html diff --git a/lib/binary-io.h b/lib/binary-io.h index dd9829aa88d..6f4db253354 100644 --- a/lib/binary-io.h +++ b/lib/binary-io.h @@ -1,6 +1,5 @@ /* Binary mode I/O. - Copyright (C) 2001, 2003, 2005, 2008-2023 Free Software Foundation, - Inc. + Copyright (C) 2001, 2003, 2005, 2008-2023 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/c-ctype.h b/lib/c-ctype.h index 9d093f7f722..35ca83d7d43 100644 --- a/lib/c-ctype.h +++ b/lib/c-ctype.h @@ -5,8 +5,7 @@ <ctype.h> functions' behaviour depends on the current locale set via setlocale. - Copyright (C) 2000-2003, 2006, 2008-2023 Free Software Foundation, - Inc. + Copyright (C) 2000-2003, 2006, 2008-2023 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/c-strcasecmp.c b/lib/c-strcasecmp.c index c90c6d6a09c..8a958dc4fd9 100644 --- a/lib/c-strcasecmp.c +++ b/lib/c-strcasecmp.c @@ -1,6 +1,5 @@ /* c-strcasecmp.c -- case insensitive string comparator in C locale - Copyright (C) 1998-1999, 2005-2006, 2009-2023 Free Software - Foundation, Inc. + Copyright (C) 1998-1999, 2005-2006, 2009-2023 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/c-strncasecmp.c b/lib/c-strncasecmp.c index bc30ce0ffc4..4ca8c5f4001 100644 --- a/lib/c-strncasecmp.c +++ b/lib/c-strncasecmp.c @@ -1,6 +1,5 @@ /* c-strncasecmp.c -- case insensitive string comparator in C locale - Copyright (C) 1998-1999, 2005-2006, 2009-2023 Free Software - Foundation, Inc. + Copyright (C) 1998-1999, 2005-2006, 2009-2023 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/careadlinkat.c b/lib/careadlinkat.c index 1d7db893731..359d497396c 100644 --- a/lib/careadlinkat.c +++ b/lib/careadlinkat.c @@ -1,7 +1,7 @@ /* Read symbolic links into a buffer without size limitation, relative to fd. - Copyright (C) 2001, 2003-2004, 2007, 2009-2023 Free Software - Foundation, Inc. + Copyright (C) 2001, 2003-2004, 2007, 2009-2023 Free Software Foundation, + Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/cloexec.c b/lib/cloexec.c index ba53d0020b1..e4cecbd2e8a 100644 --- a/lib/cloexec.c +++ b/lib/cloexec.c @@ -1,7 +1,6 @@ /* cloexec.c - set or clear the close-on-exec descriptor flag - Copyright (C) 1991, 2004-2006, 2009-2023 Free Software Foundation, - Inc. + Copyright (C) 1991, 2004-2006, 2009-2023 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/close-stream.c b/lib/close-stream.c index b68b30e6ff0..ab686bac2ae 100644 --- a/lib/close-stream.c +++ b/lib/close-stream.c @@ -1,7 +1,6 @@ /* Close a stream, with nicer error checking than fclose's. - Copyright (C) 1998-2002, 2004, 2006-2023 Free Software Foundation, - Inc. + Copyright (C) 1998-2002, 2004, 2006-2023 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/lib/diffseq.h b/lib/diffseq.h index ad3f258ab6b..dfaf4f295e8 100644 --- a/lib/diffseq.h +++ b/lib/diffseq.h @@ -1,7 +1,7 @@ /* Analyze differences between two vectors. - Copyright (C) 1988-1989, 1992-1995, 2001-2004, 2006-2023 Free - Software Foundation, Inc. + Copyright (C) 1988-1989, 1992-1995, 2001-2004, 2006-2023 Free Software + Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/lib/dup2.c b/lib/dup2.c index 1597d9d1e6e..7d197ca3123 100644 --- a/lib/dup2.c +++ b/lib/dup2.c @@ -1,7 +1,6 @@ /* Duplicate an open file descriptor to a specified file descriptor. - Copyright (C) 1999, 2004-2007, 2009-2023 Free Software Foundation, - Inc. + Copyright (C) 1999, 2004-2007, 2009-2023 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c index 8c1d26ec7d4..b31a2ea2523 100644 --- a/lib/file-has-acl.c +++ b/lib/file-has-acl.c @@ -29,9 +29,98 @@ #include "acl-internal.h" -#if GETXATTR_WITH_POSIX_ACLS +#if USE_ACL && GETXATTR_WITH_POSIX_ACLS +# include <string.h> +# include <arpa/inet.h> # include <sys/xattr.h> # include <linux/xattr.h> +# ifndef XATTR_NAME_NFSV4_ACL +# define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" +# endif + +enum { + /* ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000, */ + ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001, + ACE4_IDENTIFIER_GROUP = 0x00000040 +}; + +/* Return 1 if given ACL in XDR format is non-trivial, 0 if it is trivial. + -1 upon failure to determine it. Possibly change errno. Assume that + the ACL is valid, except avoid undefined behavior even if invalid. + + See <https://linux.die.net/man/5/nfs4_acl>. The NFSv4 acls are + defined in Internet RFC 7530 and as such, every NFSv4 server + supporting ACLs should support NFSv4 ACLs (they differ from from + POSIX draft ACLs). The ACLs can be obtained via the + nfsv4-acl-tools, e.g., the nfs4_getfacl command. Gnulib provides + only basic support of NFSv4 ACLs, i.e., recognize trivial vs + nontrivial ACLs. */ + +static int +acl_nfs4_nontrivial (uint32_t *xattr, ssize_t nbytes) +{ + enum { BYTES_PER_NETWORK_UINT = 4}; + + /* Grab the number of aces in the acl. */ + nbytes -= BYTES_PER_NETWORK_UINT; + if (nbytes < 0) + return -1; + uint32_t num_aces = ntohl (*xattr++); + if (6 < num_aces) + return 1; + int ace_found = 0; + + for (int ace_n = 0; ace_n < num_aces; ace_n++) + { + /* Get the acl type and flag. Skip the mask; it's too risky to + test it and it does not seem to be needed. Get the wholen. */ + nbytes -= 4 * BYTES_PER_NETWORK_UINT; + if (nbytes < 0) + return -1; + uint32_t type = ntohl (xattr[0]); + uint32_t flag = ntohl (xattr[1]); + uint32_t wholen = ntohl (xattr[3]); + xattr += 4; + int whowords = (wholen / BYTES_PER_NETWORK_UINT + + (wholen % BYTES_PER_NETWORK_UINT != 0)); + int64_t wholen4 = whowords; + wholen4 *= BYTES_PER_NETWORK_UINT; + + /* Trivial ACLs have only ACE4_ACCESS_ALLOWED_ACE_TYPE or + ACE4_ACCESS_DENIED_ACE_TYPE. */ + if (ACE4_ACCESS_DENIED_ACE_TYPE < type) + return 1; + + /* RFC 7530 says FLAG should be 0, but be generous to NetApp and + also accept the group flag. */ + if (flag & ~ACE4_IDENTIFIER_GROUP) + return 1; + + /* Get the who string. Check NBYTES - WHOLEN4 before storing + into NBYTES, to avoid truncation on conversion. */ + if (nbytes - wholen4 < 0) + return -1; + nbytes -= wholen4; + + /* For a trivial ACL, max 6 (typically 3) ACEs, 3 allow, 3 deny. + Check that there is at most one ACE of each TYPE and WHO. */ + int who2 + = (wholen == 6 && memcmp (xattr, "OWNER@", 6) == 0 ? 0 + : wholen == 6 && memcmp (xattr, "GROUP@", 6) == 0 ? 2 + : wholen == 9 && memcmp (xattr, "EVERYONE@", 9) == 0 ? 4 + : -1); + if (who2 < 0) + return 1; + int ace_found_bit = 1 << (who2 | type); + if (ace_found & ace_found_bit) + return 1; + ace_found |= ace_found_bit; + + xattr += whowords; + } + + return 0; +} #endif /* Return 1 if NAME has a nontrivial access control list, @@ -51,6 +140,7 @@ file_has_acl (char const *name, struct stat const *sb) # if GETXATTR_WITH_POSIX_ACLS ssize_t ret; + int initial_errno = errno; ret = getxattr (name, XATTR_NAME_POSIX_ACL_ACCESS, NULL, 0); if (ret < 0 && errno == ENODATA) @@ -68,6 +158,35 @@ file_has_acl (char const *name, struct stat const *sb) } if (ret < 0) + { + /* Check for NFSv4 ACLs. The max length of a trivial + ACL is 6 words for owner, 6 for group, 7 for everyone, + all times 2 because there are both allow and deny ACEs. + There are 6 words for owner because of type, flag, mask, + wholen, "OWNER@"+pad and similarly for group; everyone is + another word to hold "EVERYONE@". */ + uint32_t xattr[2 * (6 + 6 + 7)]; + + ret = getxattr (name, XATTR_NAME_NFSV4_ACL, xattr, sizeof xattr); + if (ret < 0) + switch (errno) + { + case ENODATA: return 0; + case ERANGE : return 1; /* ACL must be nontrivial. */ + } + else + { + /* It looks like a trivial ACL, but investigate further. */ + ret = acl_nfs4_nontrivial (xattr, ret); + if (ret < 0) + { + errno = EINVAL; + return ret; + } + errno = initial_errno; + } + } + if (ret < 0) return - acl_errno_valid (errno); return ret; diff --git a/lib/filemode.h b/lib/filemode.h index d456cc585b3..15a8dcc3760 100644 --- a/lib/filemode.h +++ b/lib/filemode.h @@ -1,7 +1,7 @@ /* Make a string describing file modes. - Copyright (C) 1998-1999, 2003, 2006, 2009-2023 Free Software - Foundation, Inc. + Copyright (C) 1998-1999, 2003, 2006, 2009-2023 Free Software Foundation, + Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/lib/fpending.c b/lib/fpending.c index df3cd85f3a6..afa840b8512 100644 --- a/lib/fpending.c +++ b/lib/fpending.c @@ -1,6 +1,6 @@ /* fpending.c -- return the number of pending output bytes on a stream - Copyright (C) 2000, 2004, 2006-2007, 2009-2023 Free Software - Foundation, Inc. + Copyright (C) 2000, 2004, 2006-2007, 2009-2023 Free Software Foundation, + Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/lib/fpending.h b/lib/fpending.h index fe310384f7e..5e860db6810 100644 --- a/lib/fpending.h +++ b/lib/fpending.h @@ -1,7 +1,7 @@ /* Declare __fpending. - Copyright (C) 2000, 2003, 2005-2006, 2009-2023 Free Software - Foundation, Inc. + Copyright (C) 2000, 2003, 2005-2006, 2009-2023 Free Software Foundation, + Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/lib/fsusage.c b/lib/fsusage.c index 2be120a06de..f6f4b1c35fd 100644 --- a/lib/fsusage.c +++ b/lib/fsusage.c @@ -1,7 +1,7 @@ /* fsusage.c -- return space usage of mounted file systems - Copyright (C) 1991-1992, 1996, 1998-1999, 2002-2006, 2009-2023 Free - Software Foundation, Inc. + Copyright (C) 1991-1992, 1996, 1998-1999, 2002-2006, 2009-2023 Free Software + Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/getgroups.c b/lib/getgroups.c index 6a2bda8d71e..93829d3b15e 100644 --- a/lib/getgroups.c +++ b/lib/getgroups.c @@ -1,7 +1,6 @@ /* provide consistent interface to getgroups for systems that don't allow N==0 - Copyright (C) 1996, 1999, 2003, 2006-2023 Free Software Foundation, - Inc. + Copyright (C) 1996, 1999, 2003, 2006-2023 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/getloadavg.c b/lib/getloadavg.c index 37fcea0a76b..59b53e79980 100644 --- a/lib/getloadavg.c +++ b/lib/getloadavg.c @@ -1,7 +1,7 @@ /* Get the system load averages. - Copyright (C) 1985-1989, 1991-1995, 1997, 1999-2000, 2003-2023 Free - Software Foundation, Inc. + Copyright (C) 1985-1989, 1991-1995, 1997, 1999-2000, 2003-2023 Free Software + Foundation, Inc. NOTE: The canonical source of this file is maintained with gnulib. Bugs can be reported to bug-gnulib@gnu.org. diff --git a/lib/gettext.h b/lib/gettext.h index 582886f9f51..d0462c47e17 100644 --- a/lib/gettext.h +++ b/lib/gettext.h @@ -1,6 +1,6 @@ /* Convenience header for conditional use of GNU <libintl.h>. - Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2023 Free - Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2023 Free Software + Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/gettime.c b/lib/gettime.c index cfba830478e..f86cc4efbff 100644 --- a/lib/gettime.c +++ b/lib/gettime.c @@ -1,7 +1,6 @@ /* gettime -- get the system clock - Copyright (C) 2002, 2004-2007, 2009-2023 Free Software Foundation, - Inc. + Copyright (C) 2002, 2004-2007, 2009-2023 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/gettimeofday.c b/lib/gettimeofday.c index 7207c851272..d896ec132b9 100644 --- a/lib/gettimeofday.c +++ b/lib/gettimeofday.c @@ -1,7 +1,6 @@ /* Provide gettimeofday for systems that don't have it or for which it's broken. - Copyright (C) 2001-2003, 2005-2007, 2009-2023 Free Software - Foundation, Inc. + Copyright (C) 2001-2003, 2005-2007, 2009-2023 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index 9ab4b741595..2097850c812 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -93,7 +93,6 @@ # dup2 \ # environ \ # execinfo \ -# explicit_bzero \ # faccessat \ # fchmodat \ # fcntl \ @@ -126,6 +125,7 @@ # memmem-simple \ # mempcpy \ # memrchr \ +# memset_explicit \ # minmax \ # mkostemp \ # mktime \ @@ -204,6 +204,7 @@ CFLAGS_SOUND = @CFLAGS_SOUND@ CHECK_STRUCTS = @CHECK_STRUCTS@ CLIENTRES = @CLIENTRES@ CLIENTW = @CLIENTW@ +CLOCK_TIME_LIB = @CLOCK_TIME_LIB@ CM_OBJ = @CM_OBJ@ COM_ERRLIB = @COM_ERRLIB@ CPP = @CPP@ @@ -238,8 +239,10 @@ ENOLINK_VALUE = @ENOLINK_VALUE@ EOVERFLOW_HIDDEN = @EOVERFLOW_HIDDEN@ EOVERFLOW_VALUE = @EOVERFLOW_VALUE@ ERRNO_H = @ERRNO_H@ +EUIDACCESS_LIBGEN = @EUIDACCESS_LIBGEN@ EXECINFO_H = @EXECINFO_H@ EXEEXT = @EXEEXT@ +FILE_HAS_ACL_LIB = @FILE_HAS_ACL_LIB@ FIND_DELETE = @FIND_DELETE@ FIRSTFILE_OBJ = @FIRSTFILE_OBJ@ FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@ @@ -253,6 +256,7 @@ GETADDRINFO_A_LIBS = @GETADDRINFO_A_LIBS@ GETLOADAVG_LIBS = @GETLOADAVG_LIBS@ GETOPT_CDEFS_H = @GETOPT_CDEFS_H@ GETOPT_H = @GETOPT_H@ +GETRANDOM_LIB = @GETRANDOM_LIB@ GFILENOTIFY_CFLAGS = @GFILENOTIFY_CFLAGS@ GFILENOTIFY_LIBS = @GFILENOTIFY_LIBS@ GL_CFLAG_ALLOW_WARNINGS = @GL_CFLAG_ALLOW_WARNINGS@ @@ -264,7 +268,6 @@ GL_COND_OBJ_DIRFD_CONDITION = @GL_COND_OBJ_DIRFD_CONDITION@ GL_COND_OBJ_DUP2_CONDITION = @GL_COND_OBJ_DUP2_CONDITION@ GL_COND_OBJ_EUIDACCESS_CONDITION = @GL_COND_OBJ_EUIDACCESS_CONDITION@ GL_COND_OBJ_EXECINFO_CONDITION = @GL_COND_OBJ_EXECINFO_CONDITION@ -GL_COND_OBJ_EXPLICIT_BZERO_CONDITION = @GL_COND_OBJ_EXPLICIT_BZERO_CONDITION@ GL_COND_OBJ_FACCESSAT_CONDITION = @GL_COND_OBJ_FACCESSAT_CONDITION@ GL_COND_OBJ_FCHMODAT_CONDITION = @GL_COND_OBJ_FCHMODAT_CONDITION@ GL_COND_OBJ_FCNTL_CONDITION = @GL_COND_OBJ_FCNTL_CONDITION@ @@ -286,6 +289,7 @@ GL_COND_OBJ_LCHMOD_CONDITION = @GL_COND_OBJ_LCHMOD_CONDITION@ GL_COND_OBJ_LSTAT_CONDITION = @GL_COND_OBJ_LSTAT_CONDITION@ GL_COND_OBJ_MEMPCPY_CONDITION = @GL_COND_OBJ_MEMPCPY_CONDITION@ GL_COND_OBJ_MEMRCHR_CONDITION = @GL_COND_OBJ_MEMRCHR_CONDITION@ +GL_COND_OBJ_MEMSET_EXPLICIT_CONDITION = @GL_COND_OBJ_MEMSET_EXPLICIT_CONDITION@ GL_COND_OBJ_MINI_GMP_GNULIB_CONDITION = @GL_COND_OBJ_MINI_GMP_GNULIB_CONDITION@ GL_COND_OBJ_MKOSTEMP_CONDITION = @GL_COND_OBJ_MKOSTEMP_CONDITION@ GL_COND_OBJ_NANOSLEEP_CONDITION = @GL_COND_OBJ_NANOSLEEP_CONDITION@ @@ -485,6 +489,7 @@ GL_GNULIB_MEMCHR = @GL_GNULIB_MEMCHR@ GL_GNULIB_MEMMEM = @GL_GNULIB_MEMMEM@ GL_GNULIB_MEMPCPY = @GL_GNULIB_MEMPCPY@ GL_GNULIB_MEMRCHR = @GL_GNULIB_MEMRCHR@ +GL_GNULIB_MEMSET_EXPLICIT = @GL_GNULIB_MEMSET_EXPLICIT@ GL_GNULIB_MKDIR = @GL_GNULIB_MKDIR@ GL_GNULIB_MKDIRAT = @GL_GNULIB_MKDIRAT@ GL_GNULIB_MKDTEMP = @GL_GNULIB_MKDTEMP@ @@ -674,6 +679,7 @@ HAVE_DECL_GETLOGIN = @HAVE_DECL_GETLOGIN@ HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@ HAVE_DECL_GETPAGESIZE = @HAVE_DECL_GETPAGESIZE@ HAVE_DECL_GETUSERSHELL = @HAVE_DECL_GETUSERSHELL@ +HAVE_DECL_GETW = @HAVE_DECL_GETW@ HAVE_DECL_IMAXABS = @HAVE_DECL_IMAXABS@ HAVE_DECL_IMAXDIV = @HAVE_DECL_IMAXDIV@ HAVE_DECL_INITSTATE = @HAVE_DECL_INITSTATE@ @@ -682,6 +688,7 @@ HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@ HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@ HAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@ HAVE_DECL_POSIX_SPAWN_SETSID = @HAVE_DECL_POSIX_SPAWN_SETSID@ +HAVE_DECL_PUTW = @HAVE_DECL_PUTW@ HAVE_DECL_SETENV = @HAVE_DECL_SETENV@ HAVE_DECL_SETHOSTNAME = @HAVE_DECL_SETHOSTNAME@ HAVE_DECL_SETSTATE = @HAVE_DECL_SETSTATE@ @@ -749,6 +756,7 @@ HAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@ HAVE_MBSLEN = @HAVE_MBSLEN@ HAVE_MBTOWC = @HAVE_MBTOWC@ HAVE_MEMPCPY = @HAVE_MEMPCPY@ +HAVE_MEMSET_EXPLICIT = @HAVE_MEMSET_EXPLICIT@ HAVE_MKDIRAT = @HAVE_MKDIRAT@ HAVE_MKDTEMP = @HAVE_MKDTEMP@ HAVE_MKFIFO = @HAVE_MKFIFO@ @@ -935,13 +943,13 @@ LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@ LIB_EACCESS = @LIB_EACCESS@ LIB_EXECINFO = @LIB_EXECINFO@ LIB_GETRANDOM = @LIB_GETRANDOM@ -LIB_HAS_ACL = @LIB_HAS_ACL@ LIB_MATH = @LIB_MATH@ LIB_NANOSLEEP = @LIB_NANOSLEEP@ LIB_PTHREAD = @LIB_PTHREAD@ LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@ LIB_TIMER_TIME = @LIB_TIMER_TIME@ LIB_WSOCK32 = @LIB_WSOCK32@ +LIB_XATTR = @LIB_XATTR@ LIMITS_H = @LIMITS_H@ LN_S_FILEONLY = @LN_S_FILEONLY@ LTLIBGMP = @LTLIBGMP@ @@ -955,6 +963,7 @@ MKDIR_P = @MKDIR_P@ MODULES_OBJ = @MODULES_OBJ@ MODULES_SECONDARY_SUFFIX = @MODULES_SECONDARY_SUFFIX@ MODULES_SUFFIX = @MODULES_SUFFIX@ +NANOSLEEP_LIB = @NANOSLEEP_LIB@ NATIVE_COMPILATION_AOT = @NATIVE_COMPILATION_AOT@ NEXT_ASSERT_H = @NEXT_ASSERT_H@ NEXT_AS_FIRST_DIRECTIVE_ASSERT_H = @NEXT_AS_FIRST_DIRECTIVE_ASSERT_H@ @@ -1031,7 +1040,9 @@ PRE_ALLOC_OBJ = @PRE_ALLOC_OBJ@ PRIPTR_PREFIX = @PRIPTR_PREFIX@ PROFILING_CFLAGS = @PROFILING_CFLAGS@ PTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@ +PTHREAD_SIGMASK_LIB = @PTHREAD_SIGMASK_LIB@ PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@ +QCOPY_ACL_LIB = @QCOPY_ACL_LIB@ RALLOC_OBJ = @RALLOC_OBJ@ RANLIB = @RANLIB@ REPLACE_ACCESS = @REPLACE_ACCESS@ @@ -1218,6 +1229,7 @@ SUBDIR_MAKEFILES_IN = @SUBDIR_MAKEFILES_IN@ SYSTEM_TYPE = @SYSTEM_TYPE@ SYS_TIME_H_DEFINES_STRUCT_TIMESPEC = @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@ TERMCAP_OBJ = @TERMCAP_OBJ@ +TIMER_TIME_LIB = @TIMER_TIME_LIB@ TIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@ TIME_H_DEFINES_TIME_UTC = @TIME_H_DEFINES_TIME_UTC@ TOOLKIT_LIBW = @TOOLKIT_LIBW@ @@ -1857,16 +1869,6 @@ EXTRA_DIST += execinfo.in.h endif ## end gnulib module execinfo -## begin gnulib module explicit_bzero -ifeq (,$(OMIT_GNULIB_MODULE_explicit_bzero)) - -ifneq (,$(GL_COND_OBJ_EXPLICIT_BZERO_CONDITION)) -libgnu_a_SOURCES += explicit_bzero.c -endif - -endif -## end gnulib module explicit_bzero - ## begin gnulib module faccessat ifeq (,$(OMIT_GNULIB_MODULE_faccessat)) @@ -2536,6 +2538,16 @@ endif endif ## end gnulib module memrchr +## begin gnulib module memset_explicit +ifeq (,$(OMIT_GNULIB_MODULE_memset_explicit)) + +ifneq (,$(GL_COND_OBJ_MEMSET_EXPLICIT_CONDITION)) +libgnu_a_SOURCES += memset_explicit.c +endif + +endif +## end gnulib module memset_explicit + ## begin gnulib module minmax ifeq (,$(OMIT_GNULIB_MODULE_minmax)) @@ -3102,7 +3114,9 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) -e 's|@''HAVE_DECL_FTELLO''@|$(HAVE_DECL_FTELLO)|g' \ -e 's|@''HAVE_DECL_GETDELIM''@|$(HAVE_DECL_GETDELIM)|g' \ -e 's|@''HAVE_DECL_GETLINE''@|$(HAVE_DECL_GETLINE)|g' \ + -e 's|@''HAVE_DECL_GETW''@|$(HAVE_DECL_GETW)|g' \ -e 's|@''HAVE_DECL_OBSTACK_PRINTF''@|$(HAVE_DECL_OBSTACK_PRINTF)|g' \ + -e 's|@''HAVE_DECL_PUTW''@|$(HAVE_DECL_PUTW)|g' \ -e 's|@''HAVE_DECL_SNPRINTF''@|$(HAVE_DECL_SNPRINTF)|g' \ -e 's|@''HAVE_DECL_VSNPRINTF''@|$(HAVE_DECL_VSNPRINTF)|g' \ -e 's|@''HAVE_DPRINTF''@|$(HAVE_DPRINTF)|g' \ @@ -3362,6 +3376,7 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H -e 's/@''GNULIB_MEMMEM''@/$(GL_GNULIB_MEMMEM)/g' \ -e 's/@''GNULIB_MEMPCPY''@/$(GL_GNULIB_MEMPCPY)/g' \ -e 's/@''GNULIB_MEMRCHR''@/$(GL_GNULIB_MEMRCHR)/g' \ + -e 's/@''GNULIB_MEMSET_EXPLICIT''@/$(GL_GNULIB_MEMSET_EXPLICIT)/g' \ -e 's/@''GNULIB_RAWMEMCHR''@/$(GL_GNULIB_RAWMEMCHR)/g' \ -e 's/@''GNULIB_STPCPY''@/$(GL_GNULIB_STPCPY)/g' \ -e 's/@''GNULIB_STPNCPY''@/$(GL_GNULIB_STPNCPY)/g' \ @@ -3393,6 +3408,7 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H -e 's|@''HAVE_DECL_MEMMEM''@|$(HAVE_DECL_MEMMEM)|g' \ -e 's|@''HAVE_MEMPCPY''@|$(HAVE_MEMPCPY)|g' \ -e 's|@''HAVE_DECL_MEMRCHR''@|$(HAVE_DECL_MEMRCHR)|g' \ + -e 's|@''HAVE_MEMSET_EXPLICIT''@|$(HAVE_MEMSET_EXPLICIT)|g' \ -e 's|@''HAVE_RAWMEMCHR''@|$(HAVE_RAWMEMCHR)|g' \ -e 's|@''HAVE_STPCPY''@|$(HAVE_STPCPY)|g' \ -e 's|@''HAVE_STPNCPY''@|$(HAVE_STPNCPY)|g' \ diff --git a/lib/group-member.c b/lib/group-member.c index 6e3f640dcf0..96a09f94a8f 100644 --- a/lib/group-member.c +++ b/lib/group-member.c @@ -1,7 +1,7 @@ /* group-member.c -- determine whether group id is in calling user's group list - Copyright (C) 1994, 1997-1998, 2003, 2005-2006, 2009-2023 Free - Software Foundation, Inc. + Copyright (C) 1994, 1997-1998, 2003, 2005-2006, 2009-2023 Free Software + Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/limits.in.h b/lib/limits.in.h index ae46a5aa25f..eaeac472299 100644 --- a/lib/limits.in.h +++ b/lib/limits.in.h @@ -99,7 +99,7 @@ # endif #endif -/* Macros specified by C2x and by ISO/IEC TS 18661-1:2014. */ +/* Macros specified by C23 and by ISO/IEC TS 18661-1:2014. */ #if (! defined ULLONG_WIDTH \ && (defined _GNU_SOURCE || defined __STDC_WANT_IEC_60559_BFP_EXT__ \ @@ -117,7 +117,7 @@ # define ULLONG_WIDTH _GL_INTEGER_WIDTH (0, ULLONG_MAX) #endif -/* Macros specified by C2x. */ +/* Macros specified by C23. */ #if (! defined BOOL_WIDTH \ && (defined _GNU_SOURCE \ diff --git a/lib/malloc.c b/lib/malloc.c index 92f8c841cd7..3ade35cb63f 100644 --- a/lib/malloc.c +++ b/lib/malloc.c @@ -1,7 +1,6 @@ /* malloc() function that is glibc compatible. - Copyright (C) 1997-1998, 2006-2007, 2009-2023 Free Software - Foundation, Inc. + Copyright (C) 1997-1998, 2006-2007, 2009-2023 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/md5-stream.c b/lib/md5-stream.c index ab48fe3261a..ba76792cbbe 100644 --- a/lib/md5-stream.c +++ b/lib/md5-stream.c @@ -1,7 +1,7 @@ /* Functions to compute MD5 message digest of files or memory blocks. according to the definition of MD5 in RFC 1321 from April 1992. - Copyright (C) 1995-1997, 1999-2001, 2005-2006, 2008-2023 Free - Software Foundation, Inc. + Copyright (C) 1995-1997, 1999-2001, 2005-2006, 2008-2023 Free Software + Foundation, Inc. This file is part of the GNU C Library. This file is free software: you can redistribute it and/or modify diff --git a/lib/md5.c b/lib/md5.c index b1e139339f4..4a6accf28ff 100644 --- a/lib/md5.c +++ b/lib/md5.c @@ -1,7 +1,7 @@ /* Functions to compute MD5 message digest of files or memory blocks. according to the definition of MD5 in RFC 1321 from April 1992. - Copyright (C) 1995-1997, 1999-2001, 2005-2006, 2008-2023 Free - Software Foundation, Inc. + Copyright (C) 1995-1997, 1999-2001, 2005-2006, 2008-2023 Free Software + Foundation, Inc. This file is part of the GNU C Library. This file is free software: you can redistribute it and/or modify diff --git a/lib/md5.h b/lib/md5.h index 3b0b4ff730f..f34e7cb8dfa 100644 --- a/lib/md5.h +++ b/lib/md5.h @@ -1,7 +1,7 @@ /* Declaration of functions and data types used for MD5 sum computing library functions. - Copyright (C) 1995-1997, 1999-2001, 2004-2006, 2008-2023 Free - Software Foundation, Inc. + Copyright (C) 1995-1997, 1999-2001, 2004-2006, 2008-2023 Free Software + Foundation, Inc. This file is part of the GNU C Library. This file is free software: you can redistribute it and/or modify diff --git a/lib/memmem.c b/lib/memmem.c index 665815efb1a..c0b48c1b25d 100644 --- a/lib/memmem.c +++ b/lib/memmem.c @@ -1,5 +1,5 @@ -/* Copyright (C) 1991-1994, 1996-1998, 2000, 2004, 2007-2023 Free - Software Foundation, Inc. +/* Copyright (C) 1991-1994, 1996-1998, 2000, 2004, 2007-2023 Free Software + Foundation, Inc. This file is part of the GNU C Library. This file is free software: you can redistribute it and/or modify diff --git a/lib/memrchr.c b/lib/memrchr.c index a34fc71f7da..c5b1fe8b2e3 100644 --- a/lib/memrchr.c +++ b/lib/memrchr.c @@ -1,7 +1,7 @@ /* memrchr -- find the last occurrence of a byte in a memory block - Copyright (C) 1991, 1993, 1996-1997, 1999-2000, 2003-2023 Free - Software Foundation, Inc. + Copyright (C) 1991, 1993, 1996-1997, 1999-2000, 2003-2023 Free Software + Foundation, Inc. Based on strlen implementation by Torbjorn Granlund (tege@sics.se), with help from Dan Sahlin (dan@sics.se) and diff --git a/lib/memset_explicit.c b/lib/memset_explicit.c new file mode 100644 index 00000000000..6d21a5e8797 --- /dev/null +++ b/lib/memset_explicit.c @@ -0,0 +1,55 @@ +/* Erase sensitive data from memory. + Copyright 2022-2023 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +/* memset_s need this define */ +#if HAVE_MEMSET_S +# define __STDC_WANT_LIB_EXT1__ 1 +#endif + +#include <string.h> + +/* Set S's bytes to C, where S has LEN bytes. The compiler will not + optimize effects away, even if S is dead after the call. */ +void * +memset_explicit (void *s, int c, size_t len) +{ +#if HAVE_EXPLICIT_MEMSET + return explicit_memset (s, c, len); +#elif HAVE_MEMSET_S + (void) memset_s (s, len, c, len); + return s; +#elif defined __GNUC__ && !defined __clang__ + memset (s, c, len); + /* Compiler barrier. */ + __asm__ volatile ("" ::: "memory"); + return s; +#elif defined __clang__ + memset (s, c, len); + /* Compiler barrier. */ + /* With asm ("" ::: "memory") LLVM analyzes uses of 's' and finds that the + whole thing is dead and eliminates it. Use 'g' to work around this + problem. See <https://bugs.llvm.org/show_bug.cgi?id=15495#c11>. */ + __asm__ volatile ("" : : "g"(s) : "memory"); + return s; +#else + /* Invoke memset through a volatile function pointer. This defeats compiler + optimizations. */ + void * (* const volatile volatile_memset) (void *, int, size_t) = memset; + return volatile_memset (s, c, len); +#endif +} diff --git a/lib/nanosleep.c b/lib/nanosleep.c index 6383115c0f1..3f295f49b5d 100644 --- a/lib/nanosleep.c +++ b/lib/nanosleep.c @@ -1,7 +1,6 @@ /* Provide a replacement for the POSIX nanosleep function. - Copyright (C) 1999-2000, 2002, 2004-2023 Free Software Foundation, - Inc. + Copyright (C) 1999-2000, 2002, 2004-2023 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/qcopy-acl.c b/lib/qcopy-acl.c index 883bcf7d588..0f4159b7fd9 100644 --- a/lib/qcopy-acl.c +++ b/lib/qcopy-acl.c @@ -23,6 +23,20 @@ #include "acl-internal.h" +#if USE_XATTR + +# include <attr/libattr.h> + +/* Returns 1 if NAME is the name of an extended attribute that is related + to permissions, i.e. ACLs. Returns 0 otherwise. */ + +static int +is_attr_permissions (const char *name, struct error_context *ctx) +{ + return attr_copy_action (name, ctx) == ATTR_ACTION_PERMISSIONS; +} + +#endif /* USE_XATTR */ /* Copy access control lists from one file to another. If SOURCE_DESC is a valid file descriptor, use file descriptor operations, else use @@ -39,13 +53,33 @@ int qcopy_acl (const char *src_name, int source_desc, const char *dst_name, int dest_desc, mode_t mode) { - struct permission_context ctx; int ret; +#ifdef USE_XATTR + /* in case no ACLs present and also to set higher mode bits + we chmod before setting ACLs as doing it after could overwrite them + (especially true for NFSv4, posix ACL has that ugly "mask" hack that + nobody understands) */ + ret = chmod_or_fchmod (dst_name, dest_desc, mode); + /* Rather than fiddling with acls one by one, we just copy the whole ACL xattrs + (Posix or NFSv4). Of course, that won't address ACLs conversion + (i.e. posix <-> nfs4) but we can't do it anyway, so for now, we don't care + Functions attr_copy_* return 0 in case we copied something OR nothing + to copy */ + if (ret == 0) + ret = source_desc <= 0 || dest_desc <= 0 + ? attr_copy_file (src_name, dst_name, is_attr_permissions, NULL) + : attr_copy_fd (src_name, source_desc, dst_name, dest_desc, + is_attr_permissions, NULL); +#else + /* no XATTR, so we proceed the old dusty way */ + struct permission_context ctx; + ret = get_permissions (src_name, source_desc, mode, &ctx); if (ret != 0) return -2; ret = set_permissions (&ctx, dst_name, dest_desc); free_permission_context (&ctx); +#endif return ret; } diff --git a/lib/save-cwd.h b/lib/save-cwd.h index f26319389c2..d089b0e2145 100644 --- a/lib/save-cwd.h +++ b/lib/save-cwd.h @@ -1,7 +1,7 @@ /* Save and restore current working directory. - Copyright (C) 1995, 1997-1998, 2003, 2009-2023 Free Software - Foundation, Inc. + Copyright (C) 1995, 1997-1998, 2003, 2009-2023 Free Software Foundation, + Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/lib/sha1.c b/lib/sha1.c index 3f6d86a285c..80f0b7a3314 100644 --- a/lib/sha1.c +++ b/lib/sha1.c @@ -1,8 +1,7 @@ /* sha1.c - Functions to compute SHA1 message digest of files or memory blocks according to the NIST specification FIPS-180-1. - Copyright (C) 2000-2001, 2003-2006, 2008-2023 Free Software - Foundation, Inc. + Copyright (C) 2000-2001, 2003-2006, 2008-2023 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/sig2str.c b/lib/sig2str.c index 4f68cb7ca8a..c5219caaaed 100644 --- a/lib/sig2str.c +++ b/lib/sig2str.c @@ -1,7 +1,6 @@ /* sig2str.c -- convert between signal names and numbers - Copyright (C) 2002, 2004, 2006, 2009-2023 Free Software Foundation, - Inc. + Copyright (C) 2002, 2004, 2006, 2009-2023 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/lib/stdio.in.h b/lib/stdio.in.h index 59cbea3d47d..8b5ef4bd2dd 100644 --- a/lib/stdio.in.h +++ b/lib/stdio.in.h @@ -951,9 +951,13 @@ _GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead"); # endif _GL_CXXALIAS_MDA (getw, int, (FILE *restrict stream)); # else +# if @HAVE_DECL_GETW@ _GL_CXXALIAS_SYS (getw, int, (FILE *restrict stream)); +# endif # endif +# if __GLIBC__ >= 2 _GL_CXXALIASWARN (getw); +# endif #endif #if @GNULIB_OBSTACK_PRINTF@ || @GNULIB_OBSTACK_PRINTF_POSIX@ @@ -1190,9 +1194,13 @@ _GL_CXXALIASWARN (puts); # endif _GL_CXXALIAS_MDA (putw, int, (int w, FILE *restrict stream)); # else +# if @HAVE_DECL_PUTW@ _GL_CXXALIAS_SYS (putw, int, (int w, FILE *restrict stream)); +# endif # endif +# if __GLIBC__ >= 2 _GL_CXXALIASWARN (putw); +# endif #endif #if @GNULIB_REMOVE@ diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h index 4c8aad76124..b79e5f70965 100644 --- a/lib/stdlib.in.h +++ b/lib/stdlib.in.h @@ -1,7 +1,6 @@ /* A GNU-like <stdlib.h>. - Copyright (C) 1995, 2001-2004, 2006-2023 Free Software Foundation, - Inc. + Copyright (C) 1995, 2001-2004, 2006-2023 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/string.in.h b/lib/string.in.h index 459dd063cbe..b227a178873 100644 --- a/lib/string.in.h +++ b/lib/string.in.h @@ -59,10 +59,11 @@ # include <unistd.h> #endif -/* AIX 7.2 declares ffsl and ffsll in <strings.h>, not in <string.h>. */ +/* AIX 7.2 and Android 13 declare ffsl and ffsll in <strings.h>, not in + <string.h>. */ /* But in any case avoid namespace pollution on glibc systems. */ #if ((@GNULIB_FFSL@ || @GNULIB_FFSLL@ || defined GNULIB_POSIXCHECK) \ - && defined _AIX) \ + && (defined _AIX || defined __ANDROID__)) \ && ! defined __GLIBC__ # include <strings.h> #endif @@ -82,7 +83,14 @@ can be freed via 'free'; it can be used only after declaring 'free'. */ /* Applies to: functions. Cannot be used on inline functions. */ #ifndef _GL_ATTRIBUTE_DEALLOC_FREE -# define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (free, 1) +# if defined __cplusplus && defined __GNUC__ && !defined __clang__ +/* Work around GCC bug <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108231> */ +# define _GL_ATTRIBUTE_DEALLOC_FREE \ + _GL_ATTRIBUTE_DEALLOC ((void (*) (void *)) free, 1) +# else +# define _GL_ATTRIBUTE_DEALLOC_FREE \ + _GL_ATTRIBUTE_DEALLOC (free, 1) +# endif #endif /* _GL_ATTRIBUTE_MALLOC declares that the function returns a pointer to freshly @@ -336,7 +344,7 @@ _GL_CXXALIAS_SYS_CAST2 (memrchr, || defined __clang__) _GL_CXXALIASWARN1 (memrchr, void *, (void *, int, size_t) throw ()); _GL_CXXALIASWARN1 (memrchr, void const *, (void const *, int, size_t) throw ()); -# else +# elif __GLIBC__ >= 2 _GL_CXXALIASWARN (memrchr); # endif #elif defined GNULIB_POSIXCHECK @@ -347,6 +355,23 @@ _GL_WARN_ON_USE (memrchr, "memrchr is unportable - " # endif #endif +/* Overwrite a block of memory. The compiler will not optimize + effects away, even if the block is dead after the call. */ +#if @GNULIB_MEMSET_EXPLICIT@ +# if ! @HAVE_MEMSET_EXPLICIT@ +_GL_FUNCDECL_SYS (memset_explicit, void *, + (void *__dest, int __c, size_t __n) _GL_ARG_NONNULL ((1))); +# endif +_GL_CXXALIAS_SYS (memset_explicit, void *, (void *__dest, int __c, size_t __n)); +_GL_CXXALIASWARN (memset_explicit); +#elif defined GNULIB_POSIXCHECK +# undef memset_explicit +# if HAVE_RAW_DECL_MEMSET_EXPLICIT +_GL_WARN_ON_USE (memset_explicit, "memset_explicit is unportable - " + "use gnulib module memset_explicit for portability"); +# endif +#endif + /* Find the first occurrence of C in S. More efficient than memchr(S,C,N), at the expense of undefined behavior if C does not occur within N bytes. */ @@ -474,7 +499,7 @@ _GL_CXXALIAS_SYS_CAST2 (strchrnul, _GL_CXXALIASWARN1 (strchrnul, char *, (char *__s, int __c_in) throw ()); _GL_CXXALIASWARN1 (strchrnul, char const *, (char const *__s, int __c_in) throw ()); -# else +# elif __GLIBC__ >= 2 _GL_CXXALIASWARN (strchrnul); # endif #elif defined GNULIB_POSIXCHECK @@ -839,7 +864,7 @@ _GL_CXXALIASWARN1 (strcasestr, char *, (char *haystack, const char *needle) throw ()); _GL_CXXALIASWARN1 (strcasestr, const char *, (const char *haystack, const char *needle) throw ()); -# else +# elif __GLIBC__ >= 2 _GL_CXXALIASWARN (strcasestr); # endif #elif defined GNULIB_POSIXCHECK diff --git a/lib/strtoimax.c b/lib/strtoimax.c index d8d74e8c699..f7977e28e64 100644 --- a/lib/strtoimax.c +++ b/lib/strtoimax.c @@ -1,7 +1,7 @@ /* Convert string representation of a number into an intmax_t value. - Copyright (C) 1999, 2001-2004, 2006, 2009-2023 Free Software - Foundation, Inc. + Copyright (C) 1999, 2001-2004, 2006, 2009-2023 Free Software Foundation, + Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/strtol.c b/lib/strtol.c index 6bc1f061877..d11269b2622 100644 --- a/lib/strtol.c +++ b/lib/strtol.c @@ -1,7 +1,7 @@ /* Convert string representation of a number into an integer value. - Copyright (C) 1991-1992, 1994-1999, 2003, 2005-2007, 2009-2023 Free - Software Foundation, Inc. + Copyright (C) 1991-1992, 1994-1999, 2003, 2005-2007, 2009-2023 Free Software + Foundation, Inc. NOTE: The canonical source of this file is maintained with the GNU C Library. Bugs can be reported to bug-glibc@gnu.org. diff --git a/lib/strtoll.c b/lib/strtoll.c index 919b453984c..9fdfa19b220 100644 --- a/lib/strtoll.c +++ b/lib/strtoll.c @@ -1,6 +1,6 @@ /* Function to parse a 'long long int' from text. - Copyright (C) 1995-1997, 1999, 2001, 2009-2023 Free Software - Foundation, Inc. + Copyright (C) 1995-1997, 1999, 2001, 2009-2023 Free Software Foundation, + Inc. This file is part of the GNU C Library. This file is free software: you can redistribute it and/or modify diff --git a/lib/time.in.h b/lib/time.in.h index a0e67f76b29..50c9b30b6b3 100644 --- a/lib/time.in.h +++ b/lib/time.in.h @@ -315,6 +315,7 @@ _GL_CXXALIASWARN (strptime); # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # define ctime rpl_ctime # endif +_GL_ATTRIBUTE_DEPRECATED _GL_FUNCDECL_RPL (ctime, char *, (time_t const *__tp) _GL_ARG_NONNULL ((1))); _GL_CXXALIAS_RPL (ctime, char *, (time_t const *__tp)); diff --git a/lib/time_r.c b/lib/time_r.c index c8143a6900a..97be4fd0544 100644 --- a/lib/time_r.c +++ b/lib/time_r.c @@ -1,7 +1,6 @@ /* Reentrant time functions like localtime_r. - Copyright (C) 2003, 2006-2007, 2010-2023 Free Software Foundation, - Inc. + Copyright (C) 2003, 2006-2007, 2010-2023 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lib/verify.h b/lib/verify.h index d4beccad96a..b63cb264321 100644 --- a/lib/verify.h +++ b/lib/verify.h @@ -37,7 +37,7 @@ && (4 < __GNUC__ + (6 <= __GNUC_MINOR__) || 5 <= __clang_major__))) # define _GL_HAVE__STATIC_ASSERT 1 # endif -# if (202000 <= __STDC_VERSION__ \ +# if (202311 <= __STDC_VERSION__ \ || (!defined __STRICT_ANSI__ && 9 <= __GNUC__)) # define _GL_HAVE__STATIC_ASSERT1 1 # endif @@ -223,8 +223,15 @@ template <int w> /* _GL_STATIC_ASSERT_H is defined if this code is copied into assert.h. */ #ifdef _GL_STATIC_ASSERT_H # if !defined _GL_HAVE__STATIC_ASSERT1 && !defined _Static_assert -# define _Static_assert(R, ...) \ - _GL_VERIFY ((R), "static assertion failed", -) +# if !defined _MSC_VER || defined __clang__ +# define _Static_assert(...) \ + _GL_VERIFY (__VA_ARGS__, "static assertion failed", -) +# else + /* Work around MSVC preprocessor incompatibility with ISO C; see + <https://stackoverflow.com/questions/5134523/>. */ +# define _Static_assert(R, ...) \ + _GL_VERIFY ((R), "static assertion failed", -) +# endif # endif # if (!defined static_assert \ && __STDC_VERSION__ < 202311 \ @@ -235,9 +242,8 @@ template <int w> /* MSVC 14 in C++ mode supports the two-arguments static_assert but not the one-argument static_assert, and it does not support _Static_assert. We have to play preprocessor tricks to distinguish the two cases. - Since the MSVC preprocessor is not ISO C compliant (cf. - <https://stackoverflow.com/questions/5134523/>), the solution is specific - to MSVC. */ + Since the MSVC preprocessor is not ISO C compliant (see above),. + the solution is specific to MSVC. */ # define _GL_EXPAND(x) x # define _GL_SA1(a1) static_assert ((a1), "static assertion failed") # define _GL_SA2 static_assert @@ -252,7 +258,9 @@ template <int w> /* @assert.h omit start@ */ -#if 3 < __GNUC__ + (3 < __GNUC_MINOR__ + (4 <= __GNUC_PATCHLEVEL__)) +#if defined __clang_major__ && __clang_major__ < 5 +# define _GL_HAS_BUILTIN_TRAP 0 +#elif 3 < __GNUC__ + (3 < __GNUC_MINOR__ + (4 <= __GNUC_PATCHLEVEL__)) # define _GL_HAS_BUILTIN_TRAP 1 #elif defined __has_builtin # define _GL_HAS_BUILTIN_TRAP __has_builtin (__builtin_trap) @@ -260,7 +268,9 @@ template <int w> # define _GL_HAS_BUILTIN_TRAP 0 #endif -#if 4 < __GNUC__ + (5 <= __GNUC_MINOR__) +#if defined __clang_major__ && __clang_major__ < 5 +# define _GL_HAS_BUILTIN_UNREACHABLE 0 +#elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__) # define _GL_HAS_BUILTIN_UNREACHABLE 1 #elif defined __has_builtin # define _GL_HAS_BUILTIN_UNREACHABLE __has_builtin (__builtin_unreachable) diff --git a/lib/xalloc-oversized.h b/lib/xalloc-oversized.h index 05ef7028137..5dbdfb5506a 100644 --- a/lib/xalloc-oversized.h +++ b/lib/xalloc-oversized.h @@ -1,7 +1,6 @@ /* xalloc-oversized.h -- memory allocation size checking - Copyright (C) 1990-2000, 2003-2004, 2006-2023 Free Software - Foundation, Inc. + Copyright (C) 1990-2000, 2003-2004, 2006-2023 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as diff --git a/lisp/abbrev.el b/lisp/abbrev.el index 550d956fb7b..ef8ef1ab5a6 100644 --- a/lisp/abbrev.el +++ b/lisp/abbrev.el @@ -501,7 +501,7 @@ PROPS is a list of properties." (defun abbrev-table-p (object) "Return non-nil if OBJECT is an abbrev table." (and (obarrayp object) - (numberp (ignore-error 'wrong-type-argument + (numberp (ignore-error wrong-type-argument (abbrev-table-get object :abbrev-table-modiff))))) (defun abbrev-table-empty-p (object &optional ignore-system) diff --git a/lisp/apropos.el b/lisp/apropos.el index 5d7fe6962a5..e95f45f1804 100644 --- a/lisp/apropos.el +++ b/lisp/apropos.el @@ -54,6 +54,8 @@ ;;; Code: +(eval-when-compile (require 'cl-lib)) + (defgroup apropos nil "Apropos commands for users and programmers." :group 'help @@ -193,9 +195,6 @@ property list, WIDGET-DOC is the widget docstring, FACE-DOC is the face docstring, and CUS-GROUP-DOC is the custom group docstring. Each docstring is either nil or a string.") -(defvar apropos-item () - "Current item in or for `apropos-accumulator'.") - (defvar apropos-synonyms '( ("find" "open" "edit") ("kill" "cut") @@ -906,6 +905,18 @@ Optional arg BUFFER (default: current buffer) is the buffer to check." ((symbolp def) (funcall f def)) ((eq 'defun (car-safe def)) (funcall f (cdr def))))))))) +(defun apropos--documentation-add (symbol doc pos) + (when (setq doc (apropos-documentation-internal doc)) + (let ((score (apropos-score-doc doc)) + (item (cdr (assq symbol apropos-accumulator)))) + (unless item + (push (cons symbol + (setq item (list (apropos-score-symbol symbol 2) + nil nil))) + apropos-accumulator)) + (setf (nth pos item) doc) + (setcar item (+ (car item) score))))) + ;;;###autoload (defun apropos-documentation (pattern &optional do-all) "Show symbols whose documentation contains matches for PATTERN. @@ -928,40 +939,28 @@ Returns list of symbols and documentation found." (setq apropos--current (list #'apropos-documentation pattern do-all)) (apropos-parse-pattern pattern t) (or do-all (setq do-all apropos-do-all)) - (setq apropos-accumulator () apropos-files-scanned ()) - (with-temp-buffer - (let ((standard-input (current-buffer)) - (apropos-sort-by-scores apropos-documentation-sort-by-scores) - f v sf sv) - (apropos-documentation-check-doc-file) - (funcall - (if do-all #'mapatoms #'apropos--map-preloaded-atoms) - (lambda (symbol) - (setq f (apropos-safe-documentation symbol) - v (get symbol 'variable-documentation)) - (if (integerp v) (setq v nil)) - (setq f (apropos-documentation-internal f) - v (apropos-documentation-internal v)) - (setq sf (apropos-score-doc f) - sv (apropos-score-doc v)) - (if (or f v) - (if (setq apropos-item - (cdr (assq symbol apropos-accumulator))) - (progn - (if f - (progn - (setcar (nthcdr 1 apropos-item) f) - (setcar apropos-item (+ (car apropos-item) sf)))) - (if v - (progn - (setcar (nthcdr 2 apropos-item) v) - (setcar apropos-item (+ (car apropos-item) sv))))) - (setq apropos-accumulator - (cons (list symbol - (+ (apropos-score-symbol symbol 2) sf sv) - f v) - apropos-accumulator)))))) - (apropos-print nil "\n----------------\n" nil t)))) + (let ((apropos-accumulator ()) + (apropos-files-scanned ()) + (delayed (make-hash-table :test #'equal))) + (with-temp-buffer + (let ((standard-input (current-buffer)) + (apropos-sort-by-scores apropos-documentation-sort-by-scores) + f v) + (apropos-documentation-check-doc-file) + (funcall + (if do-all #'mapatoms #'apropos--map-preloaded-atoms) + (lambda (symbol) + (setq f (apropos-safe-documentation symbol) + v (get symbol 'variable-documentation)) + (if (integerp v) (setq v nil)) + (if (consp f) + (push (list symbol (cdr f) 1) (gethash (car f) delayed)) + (apropos--documentation-add symbol f 1)) + (if (consp v) + (push (list symbol (cdr v) 2) (gethash (car v) delayed)) + (apropos--documentation-add symbol v 2)))) + (maphash #'apropos--documentation-add-from-elc delayed) + (apropos-print nil "\n----------------\n" nil t))))) (defun apropos-value-internal (predicate symbol function) @@ -982,11 +981,11 @@ Returns list of symbols and documentation found." symbol))) (defun apropos-documentation-internal (doc) + ;; By the time we get here, refs to DOC or to .elc files should have + ;; been converted into actual strings. + (cl-assert (not (or (consp doc) (integerp doc)))) (cond - ((consp doc) - (apropos-documentation-check-elc-file (car doc))) - ((and doc - ;; Sanity check in case bad data sneaked into the + ((and ;; Sanity check in case bad data sneaked into the ;; documentation slot. (stringp doc) (string-match apropos-all-words-regexp doc) @@ -1053,110 +1052,62 @@ non-nil." ;; So we exclude them. (cond ((= 3 type) (boundp symbol)) ((= 2 type) (fboundp symbol)))) - (or (and (setq apropos-item (assq symbol apropos-accumulator)) - (setcar (cdr apropos-item) - (apropos-score-doc doc))) - (setq apropos-item (list symbol - (+ (apropos-score-symbol symbol 2) - (apropos-score-doc doc)) - nil nil) - apropos-accumulator (cons apropos-item - apropos-accumulator))) - (when apropos-match-face - (setq doc (substitute-command-keys doc)) - (if (or (string-match apropos-pattern-quoted doc) - (string-match apropos-all-words-regexp doc)) - (put-text-property (match-beginning 0) - (match-end 0) - 'face apropos-match-face doc))) - (setcar (nthcdr type apropos-item) doc)))) + (let ((apropos-item (assq symbol apropos-accumulator))) + (or (and apropos-item + (setcar (cdr apropos-item) + (apropos-score-doc doc))) + (setq apropos-item (list symbol + (+ (apropos-score-symbol symbol 2) + (apropos-score-doc doc)) + nil nil) + apropos-accumulator (cons apropos-item + apropos-accumulator))) + (when apropos-match-face + (setq doc (substitute-command-keys doc)) + (if (or (string-match apropos-pattern-quoted doc) + (string-match apropos-all-words-regexp doc)) + (put-text-property (match-beginning 0) + (match-end 0) + 'face apropos-match-face doc))) + (setcar (nthcdr type apropos-item) doc))))) (setq sepa (goto-char sepb))))) -(defun apropos-documentation-check-elc-file (file) - ;; .elc files have the location of the file specified as #$, but for - ;; built-in files, that's a relative name (while for the rest, it's - ;; absolute). So expand the name in the former case. - (unless (file-name-absolute-p file) - (setq file (expand-file-name file lisp-directory))) - (if (or (member file apropos-files-scanned) - (not (file-exists-p file))) - nil - (let (symbol doc beg end this-is-a-variable) - (setq apropos-files-scanned (cons file apropos-files-scanned)) - (erase-buffer) - (insert-file-contents file) - (while (search-forward "#@" nil t) - ;; Read the comment length, and advance over it. - ;; This #@ may be a false positive, so don't get upset if - ;; it's not followed by the expected number of bytes to skip. - (when (and (setq end (ignore-errors (read))) (natnump end)) - (setq beg (1+ (point)) - end (+ (point) end -1)) - (forward-char) - (if (save-restriction - ;; match ^ and $ relative to doc string - (narrow-to-region beg end) - (re-search-forward apropos-all-words-regexp nil t)) - (progn - (goto-char (+ end 2)) - (setq doc (buffer-substring beg end) - end (- (match-end 0) beg) - beg (- (match-beginning 0) beg)) - (when (apropos-true-hit-doc doc) - (setq this-is-a-variable (looking-at "(def\\(var\\|const\\) ") - symbol (progn - (skip-chars-forward "(a-z") - (forward-char) - (read)) - symbol (if (consp symbol) - (nth 1 symbol) - symbol)) - (if (if this-is-a-variable - (get symbol 'variable-documentation) - (and (fboundp symbol) (apropos-safe-documentation symbol))) - (progn - (or (and (setq apropos-item (assq symbol apropos-accumulator)) - (setcar (cdr apropos-item) - (+ (cadr apropos-item) (apropos-score-doc doc)))) - (setq apropos-item (list symbol - (+ (apropos-score-symbol symbol 2) - (apropos-score-doc doc)) - nil nil) - apropos-accumulator (cons apropos-item - apropos-accumulator))) - (when apropos-match-face - (setq doc (substitute-command-keys doc)) - (if (or (string-match apropos-pattern-quoted doc) - (string-match apropos-all-words-regexp doc)) - (put-text-property (match-beginning 0) - (match-end 0) - 'face apropos-match-face doc))) - (setcar (nthcdr (if this-is-a-variable 3 2) - apropos-item) - doc))))))))))) - - +(defun apropos--documentation-add-from-elc (file defs) + (erase-buffer) + (insert-file-contents + (if (file-name-absolute-p file) file + (expand-file-name file lisp-directory))) + (pcase-dolist (`(,symbol ,begbyte ,pos) defs) + ;; We presume the file-bytes are the same as the buffer bytes, + ;; which should indeed be the case because .elc files use the + ;; `emacs-internal' encoding. + (let* ((beg (byte-to-position (+ (point-min) begbyte))) + (sizeend (1- beg)) + (size (save-excursion + (goto-char beg) + (skip-chars-backward " 0-9") + (cl-assert (looking-back "#@" (- (point) 2))) + (string-to-number (buffer-substring (point) sizeend)))) + (end (byte-to-position (+ begbyte size -1)))) + (when (save-restriction + ;; match ^ and $ relative to doc string + (narrow-to-region beg end) + (goto-char (point-min)) + (re-search-forward apropos-all-words-regexp nil t)) + (let ((doc (buffer-substring beg end))) + (when (apropos-true-hit-doc doc) + (apropos--documentation-add symbol doc pos))))))) (defun apropos-safe-documentation (function) "Like `documentation', except it avoids calling `get_doc_string'. Will return nil instead." - (while (and function (symbolp function)) - (setq function (symbol-function function))) - (if (eq (car-safe function) 'macro) - (setq function (cdr function))) - (setq function (if (byte-code-function-p function) - (if (> (length function) 4) - (aref function 4)) - (if (autoloadp function) - (nth 2 function) - (if (eq (car-safe function) 'lambda) - (if (stringp (nth 2 function)) - (nth 2 function) - (if (stringp (nth 3 function)) - (nth 3 function))))))) - (if (integerp function) - nil - function)) + (when (setq function (indirect-function function)) + ;; FIXME: `function-documentation' says not to call it, but `documentation' + ;; would turn (FILE . POS) references into strings too eagerly, so + ;; we do want to use the lower-level function. + (let ((doc (function-documentation function))) + ;; Docstrings from the DOC file are handled elsewhere. + (if (integerp doc) nil doc)))) (defcustom apropos-compact-layout nil "If non-nil, use a single line per binding." @@ -1262,14 +1213,16 @@ as a heading." (put-text-property (- (point) 3) (point) 'face 'apropos-keybinding))) (terpri)) - (apropos-print-doc 2 + (apropos-print-doc apropos-item + 2 (if (commandp symbol) 'apropos-command (if (macrop symbol) 'apropos-macro 'apropos-function)) (not nosubst)) - (apropos-print-doc 3 + (apropos-print-doc apropos-item + 3 (if (custom-variable-p symbol) 'apropos-user-option 'apropos-variable) @@ -1287,10 +1240,10 @@ as a heading." (lambda (_) (message "Value: %s" value)))) (insert "\n"))) - (apropos-print-doc 7 'apropos-group t) - (apropos-print-doc 6 'apropos-face t) - (apropos-print-doc 5 'apropos-widget t) - (apropos-print-doc 4 'apropos-plist nil)) + (apropos-print-doc apropos-item 7 'apropos-group t) + (apropos-print-doc apropos-item 6 'apropos-face t) + (apropos-print-doc apropos-item 5 'apropos-widget t) + (apropos-print-doc apropos-item 4 'apropos-plist nil)) (setq-local truncate-partial-width-windows t) (setq-local truncate-lines t))) (when help-window-select @@ -1298,7 +1251,7 @@ as a heading." (prog1 apropos-accumulator (setq apropos-accumulator ()))) ; permit gc -(defun apropos-print-doc (i type do-keys) +(defun apropos-print-doc (apropos-item i type do-keys) (let ((doc (nth i apropos-item))) (when (stringp doc) (if apropos-compact-layout diff --git a/lisp/bindings.el b/lisp/bindings.el index 34aa8399a96..99189d2e570 100644 --- a/lisp/bindings.el +++ b/lisp/bindings.el @@ -670,6 +670,8 @@ or not." "Return the value of symbol VAR if it is bound, else nil. Note that if `lexical-binding' is in effect, this function isn't meaningful if it refers to a lexically bound variable." + (unless (symbolp var) + (signal 'wrong-type-argument (list 'symbolp var))) `(and (boundp (quote ,var)) ,var)) ;; Use mode-line-mode-menu for local minor-modes only. diff --git a/lisp/bs.el b/lisp/bs.el index 60dc74fbfce..5f31530f068 100644 --- a/lisp/bs.el +++ b/lisp/bs.el @@ -420,9 +420,6 @@ naming a sort behavior. Default is \"by nothing\" which means no sorting." Non-nil means to show all buffers. Otherwise show buffers defined by current configuration `bs-current-configuration'.") -(defvar bs--window-config-coming-from nil - "Window configuration before starting Buffer Selection Menu.") - (defvar bs--intern-show-never "^ \\|\\*buffer-selection\\*" "Regular expression specifying which buffers never to show. A buffer whose name matches this regular expression will never be @@ -491,6 +488,23 @@ Used internally, only.") "<mouse-2>" #'bs-mouse-select "<mouse-3>" #'bs-mouse-select-other-frame) +(defcustom bs-default-action-list '((display-buffer-reuse-window + display-buffer-below-selected) + (reusable-frames . nil) + (window-height . window-min-height)) + "Default action list for showing the '*bs-selection*' buffer. + +This list will be passed to `pop-to-buffer' as its ACTION argument. +It should be a cons cell (FUNCTIONS . ALIST), where FUNCTIONS is +an action function or a list of action functions and ALIST is an +action alist. Each such action function should accept two +arguments: a buffer to display and an alist of the same form as +ALIST. See `display-buffer' for details." + :type display-buffer--action-custom-type + :risky t + :version "30.1" + :group 'bs) + ;; ---------------------------------------------------------------------- ;; Functions ;; ---------------------------------------------------------------------- @@ -590,21 +604,6 @@ in `bs-string-current' or `bs-string-current-marked'." (format "Show buffer by configuration %S" bs-current-configuration))) -(defun bs--track-window-changes (frame) - "Track window changes to refresh the buffer list. -Used from `window-size-change-functions'." - (let ((win (get-buffer-window "*buffer-selection*" frame))) - (when win - (with-selected-window win - (bs--set-window-height))))) - -(defun bs--remove-hooks () - "Remove `bs--track-window-changes' and auxiliary hooks." - (remove-hook 'window-size-change-functions 'bs--track-window-changes) - ;; Remove itself - (remove-hook 'kill-buffer-hook 'bs--remove-hooks t) - (remove-hook 'change-major-mode-hook 'bs--remove-hooks t)) - (put 'bs-mode 'mode-class 'special) (define-derived-mode bs-mode nil "Buffer-Selection-Menu" @@ -663,25 +662,13 @@ apply it. (setq-local font-lock-defaults '(bs-mode-font-lock-keywords t)) (setq-local font-lock-verbose nil) (setq-local font-lock-global-modes '(not bs-mode)) - (setq-local revert-buffer-function 'bs-refresh) - (add-hook 'window-size-change-functions 'bs--track-window-changes) - (add-hook 'kill-buffer-hook 'bs--remove-hooks nil t) - (add-hook 'change-major-mode-hook 'bs--remove-hooks nil t)) - -(defun bs--restore-window-config () - "Restore window configuration on the current frame." - (when bs--window-config-coming-from - (let ((frame (selected-frame))) - (unwind-protect - (set-window-configuration bs--window-config-coming-from) - (select-frame frame))) - (setq bs--window-config-coming-from nil))) + (setq-local revert-buffer-function 'bs-refresh)) (defun bs-kill () "Let buffer disappear and reset window configuration." (interactive) (bury-buffer (current-buffer)) - (bs--restore-window-config)) + (quit-window)) (defun bs-abort () "Ding and leave Buffer Selection Menu without a selection." @@ -705,7 +692,9 @@ Arguments are IGNORED (for `revert-buffer')." (defun bs--set-window-height () "Change the height of the selected window to suit the current buffer list." (unless (one-window-p t) - (fit-window-to-buffer (selected-window) bs-max-window-height))) + (fit-window-to-buffer (selected-window) bs-max-window-height nil nil nil + ;; preserve-size + t))) (defun bs--current-buffer () "Return buffer on current line. @@ -742,7 +731,7 @@ Leave Buffer Selection Menu." (interactive) (let ((buffer (bs--current-buffer))) (bury-buffer (current-buffer)) - (bs--restore-window-config) + (quit-window) (switch-to-buffer buffer) (when bs--marked-buffers ;; Some marked buffers for selection @@ -765,7 +754,7 @@ Leave Buffer Selection Menu." (interactive) (let ((buffer (bs--current-buffer))) (bury-buffer (current-buffer)) - (bs--restore-window-config) + (quit-window) (switch-to-buffer-other-window buffer))) (defun bs-tmp-select-other-window () @@ -781,7 +770,7 @@ Leave Buffer Selection Menu." (interactive) (let ((buffer (bs--current-buffer))) (bury-buffer (current-buffer)) - (bs--restore-window-config) + (quit-window) (switch-to-buffer-other-frame buffer))) (defun bs-mouse-select-other-frame (event) @@ -1165,7 +1154,18 @@ Select buffer *buffer-selection* and display buffers according to current configuration `bs-current-configuration'. Set window height, fontify buffer and move point to current buffer." (setq bs-current-list list) - (switch-to-buffer (get-buffer-create "*buffer-selection*")) + (let* ((window-combination-limit 'window-size) + (bs-buf (get-buffer-create "*buffer-selection*")) + (bs-win (progn + (pop-to-buffer bs-buf bs-default-action-list) + (selected-window)))) + ;; Delete other windows showing *buffer-selection*. + ;; Done after pop-to-buffer, instead of just calling delete-windows-on, + ;; to allow display-buffer-reuse(-mode)?-window to be used in ALIST. + (dolist (w (get-buffer-window-list bs-buf 'not t)) + (unless (eq w bs-win) + (with-demoted-errors "Error deleting window: %S" + (delete-window w))))) (bs-mode) (let* ((inhibit-read-only t) (map-fun (lambda (entry) @@ -1346,11 +1346,11 @@ ALL-BUFFERS is the list of buffers appearing in Buffer Selection Menu." 'help-echo "mouse-2: select this buffer, mouse-3: select in other frame" 'mouse-face 'highlight)) -(defun bs--get-mode-name (start-buffer _all-buffers) +(defun bs--get-mode-name (_start-buffer _all-buffers) "Return the name of mode of current buffer for Buffer Selection Menu. START-BUFFER is the buffer where we started buffer selection. ALL-BUFFERS is the list of buffers appearing in Buffer Selection Menu." - (format-mode-line mode-name nil nil start-buffer)) + (format-mode-line mode-name nil nil nil)) (defun bs--get-file-name (_start-buffer _all-buffers) "Return string for column `File' in Buffer Selection Menu. @@ -1435,21 +1435,8 @@ for buffer selection." ;; Only when not in buffer *buffer-selection* ;; we have to set the buffer we started the command (setq bs--buffer-coming-from (current-buffer))) - (let ((liste (bs-buffer-list)) - (active-window (get-window-with-predicate - (lambda (w) - (string= (buffer-name (window-buffer w)) - "*buffer-selection*")) - nil (selected-frame)))) - (if active-window - (select-window active-window) - (bs--restore-window-config) - (setq bs--window-config-coming-from (current-window-configuration)) - (when (> (window-height) 7) - ;; Errors would mess with the window configuration (bug#10882). - (ignore-errors (select-window (split-window-below))))) - (bs-show-in-buffer liste) - (bs-message-without-log "%s" (bs--current-config-message))))) + (bs-show-in-buffer (bs-buffer-list)) + (bs-message-without-log "%s" (bs--current-config-message)))) (defun bs--configuration-name-for-prefix-arg (prefix) "Convert prefix argument PREFIX to a name of a buffer configuration. diff --git a/lisp/calc/calc-units.el b/lisp/calc/calc-units.el index 5e21d506d74..988fef2fcd2 100644 --- a/lisp/calc/calc-units.el +++ b/lisp/calc/calc-units.el @@ -319,28 +319,28 @@ that the combined units table will be rebuilt.") (defvar math-unit-prefixes '( ( ?Q (^ 10 30) "quetta" ) ( ?R (^ 10 27) "ronna" ) - ( ?Y (^ 10 24) "Yotta" ) - ( ?Z (^ 10 21) "Zetta" ) - ( ?E (^ 10 18) "Exa" ) - ( ?P (^ 10 15) "Peta" ) - ( ?T (^ 10 12) "Tera" ) - ( ?G (^ 10 9) "Giga" ) - ( ?M (^ 10 6) "Mega" ) - ( ?k (^ 10 3) "Kilo" ) - ( ?K (^ 10 3) "Kilo" ) - ( ?h (^ 10 2) "Hecto" ) - ( ?H (^ 10 2) "Hecto" ) - ( ?D (^ 10 1) "Deka" ) + ( ?Y (^ 10 24) "yotta" ) + ( ?Z (^ 10 21) "zetta" ) + ( ?E (^ 10 18) "exa" ) + ( ?P (^ 10 15) "peta" ) + ( ?T (^ 10 12) "tera" ) + ( ?G (^ 10 9) "giga" ) + ( ?M (^ 10 6) "mega" ) + ( ?k (^ 10 3) "kilo" ) + ( ?K (^ 10 3) "kilo" ) + ( ?h (^ 10 2) "hecto" ) + ( ?H (^ 10 2) "hecto" ) + ( ?D (^ 10 1) "deka" ) ( 0 (^ 10 0) nil ) - ( ?d (^ 10 -1) "Deci" ) - ( ?c (^ 10 -2) "Centi" ) - ( ?m (^ 10 -3) "Milli" ) - ( ?u (^ 10 -6) "Micro" ) - ( ?μ (^ 10 -6) "Micro" ) - ( ?n (^ 10 -9) "Nano" ) - ( ?p (^ 10 -12) "Pico" ) - ( ?f (^ 10 -15) "Femto" ) - ( ?a (^ 10 -18) "Atto" ) + ( ?d (^ 10 -1) "deci" ) + ( ?c (^ 10 -2) "centi" ) + ( ?m (^ 10 -3) "milli" ) + ( ?u (^ 10 -6) "micro" ) + ( ?μ (^ 10 -6) "micro" ) + ( ?n (^ 10 -9) "nano" ) + ( ?p (^ 10 -12) "pico" ) + ( ?f (^ 10 -15) "femto" ) + ( ?a (^ 10 -18) "atto" ) ( ?z (^ 10 -21) "zepto" ) ( ?y (^ 10 -24) "yocto" ) ( ?r (^ 10 -27) "ronto" ) diff --git a/lisp/calendar/appt.el b/lisp/calendar/appt.el index a209623b65e..49597739446 100644 --- a/lisp/calendar/appt.el +++ b/lisp/calendar/appt.el @@ -409,7 +409,7 @@ displayed in a window: 'face 'mode-line-emphasis) " "))) ;; Reset count to 0 in case we display another appt on the next cycle. - (setq appt-display-count (if (eq '(0) min-list) 0 + (setq appt-display-count (if (equal '(0) min-list) 0 (1+ prev-appt-display-count)))) ;; If we have changed the mode line string, redisplay all mode lines. (and appt-display-mode-line diff --git a/lisp/calendar/cal-dst.el b/lisp/calendar/cal-dst.el index 75c29a38352..a96fb0adf7c 100644 --- a/lisp/calendar/cal-dst.el +++ b/lisp/calendar/cal-dst.el @@ -354,10 +354,10 @@ If the locale never uses daylight saving time, set this to 0." (if calendar-current-time-zone-cache (format-time-string "%z" 0 (* 60 (car calendar-current-time-zone-cache))) - "+0000") - (or (nth 2 calendar-current-time-zone-cache) "EST")) + "-0000") + (or (nth 2 calendar-current-time-zone-cache) "UTC")) "Abbreviated name of standard time zone at `calendar-location-name'. -For example, \"EST\" in New York City, \"PST\" for Los Angeles." +For example, \"-0500\" or \"EST\" in New York City." :type 'string :version "28.1" :set-after '(calendar-time-zone-style) @@ -368,10 +368,10 @@ For example, \"EST\" in New York City, \"PST\" for Los Angeles." (if calendar-current-time-zone-cache (format-time-string "%z" 0 (* 60 (cadr calendar-current-time-zone-cache))) - "+0000") - (or (nth 3 calendar-current-time-zone-cache) "EDT")) + "-0000") + (or (nth 3 calendar-current-time-zone-cache) "UTC")) "Abbreviated name of daylight saving time zone at `calendar-location-name'. -For example, \"EDT\" in New York City, \"PDT\" for Los Angeles." +For example, \"-0400\" or \"EDT\" in New York City." :type 'string :version "28.1" :set-after '(calendar-time-zone-style) diff --git a/lisp/calendar/diary-lib.el b/lisp/calendar/diary-lib.el index 44fb5eb5a86..946cf0e7236 100644 --- a/lisp/calendar/diary-lib.el +++ b/lisp/calendar/diary-lib.el @@ -339,7 +339,7 @@ Returns a string using match elements 1-5, where: (t "\\1 \\2 \\3"))) ; MDY "\n \\4 %s, \\5"))) ;; TODO Sometimes the time is in a different time-zone to the one you -;; are in. Eg in PST, you might still get an email referring to: +;; are in. E.g., in Los Angeles, you might still get an email referring to: ;; "7:00 PM-8:00 PM. Greenwich Standard Time". ;; Note that it doesn't use a standard abbreviation for the timezone, ;; or anything helpful like that. diff --git a/lisp/calendar/iso8601.el b/lisp/calendar/iso8601.el index cd3de62afdb..d7d064d9c2a 100644 --- a/lisp/calendar/iso8601.el +++ b/lisp/calendar/iso8601.el @@ -129,7 +129,7 @@ well as variants like \"2008W32\" (week number) and See `decode-time' for the meaning of FORM." (if (not (iso8601-valid-p string)) - (signal 'wrong-type-argument string) + (signal 'wrong-type-argument (list string)) (let* ((date-string (match-string 1 string)) (time-string (match-string 2 string)) (zone-string (match-string 3 string)) @@ -217,7 +217,7 @@ See `decode-time' for the meaning of FORM." ((iso8601--match "---\\([0-9][0-9]\\)" string) (iso8601--decoded-time :day (string-to-number (match-string 1 string)))) (t - (signal 'wrong-type-argument string)))) + (signal 'wrong-type-argument (list string))))) (defun iso8601-parse-time (string &optional form) "Parse STRING, which should be an ISO 8601 time string. @@ -226,11 +226,11 @@ hour/minute/seconds/zone fields filled in. See `decode-time' for the meaning of FORM." (if (not (iso8601--match iso8601--full-time-match string)) - (signal 'wrong-type-argument string) + (signal 'wrong-type-argument (list string)) (let ((time (match-string 1 string)) (zone (match-string 2 string))) (if (not (iso8601--match iso8601--time-match time)) - (signal 'wrong-type-argument string) + (signal 'wrong-type-argument (list string)) (let ((hour (string-to-number (match-string 1 time))) (minute (and (match-string 2 time) (string-to-number (match-string 2 time)))) @@ -274,7 +274,7 @@ See `decode-time' for the meaning of FORM." "Parse STRING, which should be an ISO 8601 time zone. Return the number of minutes." (if (not (iso8601--match iso8601--zone-match string)) - (signal 'wrong-type-argument string) + (signal 'wrong-type-argument (list string)) (if (match-string 2 string) ;; HH:MM-ish. (let ((hour (string-to-number (match-string 3 string))) @@ -314,14 +314,14 @@ Return the number of minutes." ((iso8601--match iso8601--duration-combined-match string) (iso8601-parse (substring string 1))) (t - (signal 'wrong-type-argument string)))) + (signal 'wrong-type-argument (list string))))) (defun iso8601-parse-interval (string) "Parse ISO 8601 intervals." (let ((bits (split-string string "/")) start end duration) (if (not (= (length bits) 2)) - (signal 'wrong-type-argument string) + (signal 'wrong-type-argument (list string)) ;; The intervals may be an explicit start/end times, or either a ;; start or an end, and an accompanying duration. (cond @@ -338,7 +338,7 @@ Return the number of minutes." (setq start (iso8601-parse (car bits)) end (iso8601-parse (cadr bits)))) (t - (signal 'wrong-type-argument string)))) + (signal 'wrong-type-argument (list string))))) (unless end (setq end (decoded-time-add start duration))) (unless start diff --git a/lisp/calendar/solar.el b/lisp/calendar/solar.el index 582a2b91ff6..d82215a6d35 100644 --- a/lisp/calendar/solar.el +++ b/lisp/calendar/solar.el @@ -839,12 +839,10 @@ This function is suitable for execution in an init file." "E" "W")))))) (calendar-standard-time-zone-name (if (< arg 16) calendar-standard-time-zone-name - (cond ((zerop calendar-time-zone) - (if (eq calendar-time-zone-style 'numeric) - "+0000" "UTC")) - ((< calendar-time-zone 0) - (format "UTC%dmin" calendar-time-zone)) - (t (format "UTC+%dmin" calendar-time-zone))))) + (if (and (zerop calendar-time-zone) + (not (eq calendar-time-zone-style 'numeric))) + "UTC" + (format-time-string "%z" 0 (* 60 calendar-time-zone))))) (calendar-daylight-savings-starts (if (< arg 16) calendar-daylight-savings-starts)) (calendar-daylight-savings-ends diff --git a/lisp/cedet/semantic/complete.el b/lisp/cedet/semantic/complete.el index 6f84b83ab75..84040b572bc 100644 --- a/lisp/cedet/semantic/complete.el +++ b/lisp/cedet/semantic/complete.el @@ -1731,7 +1731,7 @@ Display mechanism using tooltip for a list of possible completions.") ;; Add any tail info. (setq msg (concat msg msg-tail)) ;; Display tooltip. - (when (not (eq msg "")) + (when (not (equal msg "")) (semantic-displayer-tooltip-show msg))))) ;;; Compatibility diff --git a/lisp/cedet/semantic/decorate/include.el b/lisp/cedet/semantic/decorate/include.el index 156eac46659..c83de66ef0c 100644 --- a/lisp/cedet/semantic/decorate/include.el +++ b/lisp/cedet/semantic/decorate/include.el @@ -790,9 +790,7 @@ any decorated referring includes.") ;; This is a hack. Add in something better? (semanticdb-notify-references table (lambda (tab _me) - (semantic-decoration-unparsed-include-refrence-reset tab) - )) - )) + (semantic-decoration-unparsed-include-reference-reset tab))))) (cl-defmethod semanticdb-partial-synchronize ((cache semantic-decoration-unparsed-include-cache) new-tags) @@ -805,7 +803,7 @@ any decorated referring includes.") "Synchronize a CACHE with some NEW-TAGS." (semantic-reset cache)) -(defun semantic-decoration-unparsed-include-refrence-reset (table) +(defun semantic-decoration-unparsed-include-reference-reset (table) "Refresh any highlighting in buffers referred to by TABLE. If TABLE is not in a buffer, do nothing." ;; This cache removal may seem odd in that we are "creating one", but @@ -835,6 +833,8 @@ If TABLE is not in a buffer, do nothing." (semantic-decorate-add-decorations allinc) )))) +(define-obsolete-function-alias 'semantic-decoration-unparsed-include-refrence-reset + #'semantic-decoration-unparsed-include-reference-reset "30.1") (provide 'semantic/decorate/include) diff --git a/lisp/cedet/semantic/lex-spp.el b/lisp/cedet/semantic/lex-spp.el index b932cb999ba..6a16845ecf2 100644 --- a/lisp/cedet/semantic/lex-spp.el +++ b/lisp/cedet/semantic/lex-spp.el @@ -1243,7 +1243,7 @@ Finds the header file belonging to NAME, gets the macros from that file, and then merge the macros with our current symbol table." (when semantic-lex-spp-use-headers-flag - ;; @todo - do this someday, ok? + nil ; @todo - do this someday, ok? )) (defmacro define-lex-spp-include-analyzer (name doc regexp tokidx diff --git a/lisp/cedet/semantic/lex.el b/lisp/cedet/semantic/lex.el index c2d2e5e1668..5fd1fd45400 100644 --- a/lisp/cedet/semantic/lex.el +++ b/lisp/cedet/semantic/lex.el @@ -1108,7 +1108,7 @@ This can be done by using `semantic-lex-push-token'." (semantic-lex-analysis-bounds (cons (point) (point-max))) (semantic-lex-current-depth 0) (semantic-lex-maximum-depth semantic-lex-depth)) - (when ,condition ,@forms) + (when ,condition nil ,@forms) ; `nil' avoids an empty-body warning. semantic-lex-token-stream)))) (defmacro define-lex-regex-analyzer (name doc regexp &rest forms) diff --git a/lisp/comint.el b/lisp/comint.el index 682b555a33c..c5589324a14 100644 --- a/lisp/comint.el +++ b/lisp/comint.el @@ -4119,9 +4119,15 @@ function called, or nil, if no function was called (if BEG = END)." (save-restriction (let ((beg2 beg1) (end2 end1)) - (when (= beg2 beg) + (when (and (= beg2 beg) + (> beg2 (point-min)) + (eq is-output + (eq (get-text-property (1- beg2) 'field) 'output))) (setq beg2 (field-beginning beg2))) - (when (= end2 end) + (when (and (= end2 end) + (< end2 (point-max)) + (eq is-output + (eq (get-text-property (1+ end2) 'field) 'output))) (setq end2 (field-end end2))) ;; Narrow to the whole field surrounding the region (narrow-to-region beg2 end2)) diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el index 0373842de09..dbef5f47cd6 100644 --- a/lisp/cus-edit.el +++ b/lisp/cus-edit.el @@ -903,9 +903,9 @@ This also shows the saved values in the buffer." (defun custom-reset-standard-save-and-update () "Save settings and redraw after erasing customizations." (when (or (and custom-reset-standard-variables-list - (not (eq custom-reset-standard-variables-list '(t)))) + (not (equal custom-reset-standard-variables-list '(t)))) (and custom-reset-standard-faces-list - (not (eq custom-reset-standard-faces-list '(t))))) + (not (equal custom-reset-standard-faces-list '(t))))) ;; Save settings to file. (custom-save-all) ;; Set state of and redraw variables. @@ -1238,7 +1238,7 @@ Show the buffer in another window, but don't select it." (unless (eq symbol basevar) (message "`%s' is an alias for `%s'" symbol basevar)))) -(defvar customize-changed-options-previous-release "28.2" +(defvar customize-changed-options-previous-release "29.1" "Version for `customize-changed' to refer back to by default.") ;; Packages will update this variable, so make it available. diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 054683d7cf6..6ca7d7fcafd 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -310,6 +310,7 @@ Leaving \"Default\" unchecked is equivalent with specifying a default of (const :tag "Off" :value nil) (const :tag "On" :value t) (const :tag "Auto-raise" :value auto-raise)) "26.1") + (yes-or-no-prompt menu string "30.1") ;; fontset.c ;; FIXME nil is the initial value, fontset.el setqs it. (vertical-centering-font-regexp display diff --git a/lisp/descr-text.el b/lisp/descr-text.el index aea6b3e15b7..4834c2eb7ba 100644 --- a/lisp/descr-text.el +++ b/lisp/descr-text.el @@ -366,7 +366,7 @@ This function is semi-obsolete. Use `get-char-code-property'." ;; description is added to the category name as a tooltip (defsubst describe-char-categories (category-set) (let ((mnemonics (category-set-mnemonics category-set))) - (unless (eq mnemonics "") + (unless (equal mnemonics "") (list (mapconcat (lambda (x) (let* ((c (category-docstring x)) diff --git a/lisp/desktop.el b/lisp/desktop.el index 3d78c4cb6f8..6aacb85c12c 100644 --- a/lisp/desktop.el +++ b/lisp/desktop.el @@ -828,7 +828,7 @@ is nil, ask the user where to save the desktop." ;; If we own it, we don't anymore. (when (eq (emacs-pid) (desktop-owner)) ;; Allow exiting Emacs even if we can't delete the desktop file. - (ignore-error 'file-error + (ignore-error file-error (desktop-release-lock)))) ;; ---------------------------------------------------------------------------- diff --git a/lisp/dired-x.el b/lisp/dired-x.el index 560eefae024..5780f1353ad 100644 --- a/lisp/dired-x.el +++ b/lisp/dired-x.el @@ -816,7 +816,7 @@ otherwise." (defun dired-x--string-to-number (str) "Like `string-to-number' but recognize a trailing unit prefix. For example, 2K is expanded to 2048.0. The caller should make -sure that a trailing letter in STR is one of BKkMGTPEZY." +sure that a trailing letter in STR is one of BKkMGTPEZYRQ." (let* ((val (string-to-number str)) (u (unless (zerop val) (aref str (1- (length str)))))) @@ -831,7 +831,7 @@ sure that a trailing letter in STR is one of BKkMGTPEZY." (when (and u (> u ?9)) (when (= u ?k) (setq u ?K)) - (let ((units '(?B ?K ?M ?G ?T ?P ?E ?Z ?Y))) + (let ((units '(?B ?K ?M ?G ?T ?P ?E ?Z ?Y ?R ?Q))) (while (and units (/= (pop units) u)) (setq val (* 1024.0 val))))) val))) @@ -904,7 +904,7 @@ only in the active region if `dired-mark-region' is non-nil." ;; GNU ls -hs suffixes the block count with a unit and ;; prints it as a float, FreeBSD does neither. (dired-re-inode-size "\\=\\s *\\([0-9]+\\s +\\)?\ -\\(?:\\([0-9]+\\(?:\\.[0-9]*\\)?[BkKMGTPEZY]?\\)? ?\\)")) +\\(?:\\([0-9]+\\(?:\\.[0-9]*\\)?[BkKMGTPEZYRQ]?\\)? ?\\)")) (beginning-of-line) (forward-char 2) (search-forward-regexp dired-re-inode-size nil t) diff --git a/lisp/dired.el b/lisp/dired.el index 2bcb28a0e00..76499d0f520 100644 --- a/lisp/dired.el +++ b/lisp/dired.el @@ -530,7 +530,7 @@ The directory name must be absolute, but need not be fully expanded.") (put 'dired-actual-switches 'safe-local-variable 'dired-safe-switches-p) -(defvar dired-re-inode-size "[0-9 \t]*[.,0-9]*[BkKMGTPEZY]?[ \t]*" +(defvar dired-re-inode-size "[0-9 \t]*[.,0-9]*[BkKMGTPEZYRQ]?[ \t]*" "Regexp for optional initial inode and file size as made by `ls -i -s'.") ;; These regexps must be tested at beginning-of-line, but are also diff --git a/lisp/doc-view.el b/lisp/doc-view.el index 427da557d23..0303fec67a6 100644 --- a/lisp/doc-view.el +++ b/lisp/doc-view.el @@ -209,10 +209,10 @@ are available (see Info node `(emacs)Document View')." function) :version "24.4") -(defcustom doc-view-mupdf-use-svg nil - "Whether to use SVG images for PDF files." +(defcustom doc-view-mupdf-use-svg (image-type-available-p 'svg) + "Whether to use svg images for PDF files." :type 'boolean - :version "29.1") + :version "30.1") (defcustom doc-view-imenu-enabled (and (executable-find "mutool") t) "Whether to generate an imenu outline when \"mutool\" is available." diff --git a/lisp/elide-head.el b/lisp/elide-head.el index 11953299da9..f74c85fdfee 100644 --- a/lisp/elide-head.el +++ b/lisp/elide-head.el @@ -50,24 +50,41 @@ :group 'tools) (defcustom elide-head-headers-to-hide - `(;; GNU GPL - ("is free software[:;] you can redistribute it" . - ,(rx (or (seq "If not, see " (? "<") - "http" (? "s") "://www.gnu.org/licenses" - (? "/") (? ">") (? " ")) - (seq "Boston, MA " (? " ") - "0211" (or "1-1307" "0-1301") - (or " " ", ") "USA") - "675 Mass Ave, Cambridge, MA 02139, USA") - (? "."))) - ;; FreeBSD license / Modified BSD license (3-clause) - (,(rx (or "The Regents of the University of California. All rights reserved." - "Redistribution and use in source and binary")) - . "POSSIBILITY OF SUCH DAMAGE\\.") - ;; X11 and Expat - ("Permission is hereby granted, free of charge" . - ,(rx (or "authorization from the X Consortium." ; X11 - "THE USE OR OTHER DEALINGS IN THE SOFTWARE.")))) ; Expat + (rx-let ((delim + ;; A line break could be in a non-standard place, and the + ;; license could be in a comment. + (or + ;; Either just some spaces: + (+ " ") + ;; Or a newline and some comment starter: + (: (* (in " \t")) + "\n" + (* (in " \t")) + (* (or (syntax comment-start) (in ";#*-"))) + (* (in " \t")))))) + `(;; GNU GPL + ("is free software[:;] you can redistribute it" . + ,(rx (or (seq "If not, see " (? "<") + "http" (? "s") "://www.gnu.org/licenses" + (? "/") (? ">") (? " ")) + (seq "Boston," delim "MA" delim + (or "02111-1307" "02110-1301" "02111-1301") + (? ",") delim + "USA") + "675 Mass Ave, Cambridge, MA 02139, USA") + (? "."))) + ;; FreeBSD license / Modified BSD license (3-clause) + (,(rx (or "The Regents of the University of California. All rights reserved." + "Redistribution and use in source and binary")) + . "POSSIBILITY OF SUCH DAMAGE\\.") + ;; X11 and Expat + ("Permission is hereby granted, free of charge" . + ,(rx (or "authorization from the X Consortium." ; X11 + "THE USE OR OTHER DEALINGS IN THE SOFTWARE."))) ; Expat + ;; Apache + ("Licensed under the Apache License, Version 2.0" . + "limitations under the License.") + )) "Alist of regexps defining start and end of text to elide. The cars of elements of the list are searched for in order. Text is @@ -78,7 +95,7 @@ cdr. This affects `elide-head-mode'." :type '(alist :key-type (regexp :tag "Start regexp") :value-type (regexp :tag "End regexp")) - :version "29.1") + :version "30.1") (defvar-local elide-head-overlay nil) diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 937300cf0c0..4d39e28fc8e 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el @@ -410,7 +410,10 @@ for speeding up processing.") (`(condition-case ,var ,exp . ,clauses) `(,fn ,var ;Not evaluated. - ,(byte-optimize-form exp for-effect) + ,(byte-optimize-form exp + (if (assq :success clauses) + (null var) + for-effect)) ,@(mapcar (lambda (clause) (let ((byte-optimize--lexvars (and lexical-binding @@ -755,7 +758,8 @@ for speeding up processing.") ((eq head 'list) (cdr form)) ((memq head ;; FIXME: Replace this list with a function property? - '( length safe-length cons lambda + '( lambda internal-make-closure + length safe-length cons string unibyte-string make-string concat format format-message substring substring-no-properties string-replace @@ -971,6 +975,43 @@ for speeding up processing.") (t ;; Moving the constant to the end can enable some lapcode optimizations. (list (car form) (nth 2 form) (nth 1 form))))) +(defun byte-opt--nary-comparison (form) + "Optimise n-ary comparisons such as `=', `<' etc." + (let ((nargs (length (cdr form)))) + (cond + ((= nargs 1) + `(progn (cadr form) t)) + ((>= nargs 3) + ;; At least 3 arguments: transform to N-1 binary comparisons, + ;; since those have their own byte-ops which are particularly + ;; fast for fixnums. + (let* ((op (car form)) + (bindings nil) + (rev-args nil)) + (if (memq nil (mapcar #'macroexp-copyable-p (cddr form))) + ;; At least one arg beyond the first is non-constant non-variable: + ;; create temporaries for all args to guard against side-effects. + ;; The optimiser will eliminate trivial bindings later. + (let ((i 1)) + (dolist (arg (cdr form)) + (let ((var (make-symbol (format "arg%d" i)))) + (push var rev-args) + (push (list var arg) bindings) + (setq i (1+ i))))) + ;; All args beyond the first are copyable: no temporary variables + ;; required. + (setq rev-args (reverse (cdr form)))) + (let ((prev (car rev-args)) + (exprs nil)) + (dolist (arg (cdr rev-args)) + (push (list op arg prev) exprs) + (setq prev arg)) + (let ((and-expr (cons 'and exprs))) + (if bindings + (list 'let (nreverse bindings) and-expr) + and-expr))))) + (t form)))) + (defun byte-optimize-constant-args (form) (let ((ok t) (rest (cdr form))) @@ -1126,13 +1167,18 @@ See Info node `(elisp) Integer Basics'." (put 'max 'byte-optimizer #'byte-optimize-min-max) (put 'min 'byte-optimizer #'byte-optimize-min-max) -(put '= 'byte-optimizer #'byte-optimize-binary-predicate) (put 'eq 'byte-optimizer #'byte-optimize-eq) (put 'eql 'byte-optimizer #'byte-optimize-equal) (put 'equal 'byte-optimizer #'byte-optimize-equal) (put 'string= 'byte-optimizer #'byte-optimize-binary-predicate) (put 'string-equal 'byte-optimizer #'byte-optimize-binary-predicate) +(put '= 'byte-optimizer #'byte-opt--nary-comparison) +(put '< 'byte-optimizer #'byte-opt--nary-comparison) +(put '<= 'byte-optimizer #'byte-opt--nary-comparison) +(put '> 'byte-optimizer #'byte-opt--nary-comparison) +(put '>= 'byte-optimizer #'byte-opt--nary-comparison) + (put 'string-greaterp 'byte-optimizer #'byte-optimize-string-greaterp) (put 'string> 'byte-optimizer #'byte-optimize-string-greaterp) @@ -1297,11 +1343,8 @@ See Info node `(elisp) Integer Basics'." (if else `(progn ,condition ,@else) condition)) - ;; (if X nil t) -> (not X) - ((and (eq then nil) (eq else '(t))) - `(not ,condition)) - ;; (if X t [nil]) -> (not (not X)) - ((and (eq then t) (or (null else) (eq else '(nil)))) + ;; (if X t) -> (not (not X)) + ((and (eq then t) (null else)) `(not ,(byte-opt--negate condition))) ;; (if VAR VAR X...) -> (or VAR (progn X...)) ((and (symbolp condition) (eq condition then)) @@ -1379,6 +1422,9 @@ See Info node `(elisp) Integer Basics'." ;; (apply F ... (list X Y ...)) -> (funcall F ... X Y ...) ((eq (car-safe last) 'list) `(funcall ,fn ,@(butlast (cddr form)) ,@(cdr last))) + ;; (apply F ... (cons X Y)) -> (apply F ... X Y) + ((eq (car-safe last) 'cons) + (append (butlast form) (cdr last))) (t form))) form))) @@ -2223,18 +2269,12 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." ;; ;; goto ... --> goto <delete until TAG or end> ;; return ... --> return <delete until TAG or end> - ;; (unless a jump-table is being used, where deleting may affect - ;; other valid case bodies) ;; ((and (memq (car lap0) '(byte-goto byte-return)) - (not (memq (car lap1) '(TAG nil))) - ;; FIXME: Instead of deferring simply when jump-tables are - ;; being used, keep a list of tags used for switch tags and - ;; use them instead (see `byte-compile-inline-lapcode'). - (not byte-compile-jump-tables)) + (not (memq (car lap1) '(TAG nil)))) (setq tmp rest) (let ((i 0) - (opt-p (memq byte-optimize-log '(t lap))) + (opt-p (memq byte-optimize-log '(t byte))) str deleted) (while (and (setq tmp (cdr tmp)) (not (eq 'TAG (car (car tmp))))) diff --git a/lisp/emacs-lisp/byte-run.el b/lisp/emacs-lisp/byte-run.el index eb7d026b146..9345665eea8 100644 --- a/lisp/emacs-lisp/byte-run.el +++ b/lisp/emacs-lisp/byte-run.el @@ -262,7 +262,8 @@ This is used by `declare'.") (interactive-form nil) (warnings nil) (warn #'(lambda (msg form) - (push (macroexp-warn-and-return msg nil nil t form) + (push (macroexp-warn-and-return + (format-message msg) nil nil t form) warnings)))) (while (and body @@ -649,11 +650,11 @@ in `byte-compile-warning-types'; see the variable `byte-compile-warnings' for a fuller explanation of the warning types. The types that can be suppressed with this macro are `free-vars', `callargs', `redefine', `obsolete', -`interactive-only', `lexical', `mapcar', `constants' and -`suspicious'. +`interactive-only', `lexical', `mapcar', `constants', +`suspicious' and `empty-body'. For the `mapcar' case, only the `mapcar' function can be used in -the symbol list. For `suspicious', only `set-buffer' and `lsh' can be used." +the symbol list." ;; Note: during compilation, this definition is overridden by the one in ;; byte-compile-initial-macro-environment. (declare (debug (sexp body)) (indent 1)) @@ -679,11 +680,11 @@ Otherwise, return nil. For internal use only." ;; This is called from lread.c and therefore needs to be preloaded. (if lread--unescaped-character-literals (let ((sorted (sort lread--unescaped-character-literals #'<))) - (format-message "unescaped character literals %s detected, %s expected!" - (mapconcat (lambda (char) (format "`?%c'" char)) - sorted ", ") - (mapconcat (lambda (char) (format "`?\\%c'" char)) - sorted ", "))))) + (format "unescaped character literals %s detected, %s expected!" + (mapconcat (lambda (char) (format-message "`?%c'" char)) + sorted ", ") + (mapconcat (lambda (char) (format-message "`?\\%c'" char)) + sorted ", "))))) (defun byte-compile-info (string &optional message type) "Format STRING in a way that looks pleasing in the compilation output. diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 5df1205869c..e8a8fe37756 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el @@ -295,7 +295,8 @@ The information is logged to `byte-compile-log-buffer'." '(redefine callargs free-vars unresolved obsolete noruntime interactive-only make-local mapcar constants suspicious lexical lexical-dynamic - docstrings docstrings-non-ascii-quotes not-unused) + docstrings docstrings-non-ascii-quotes not-unused + empty-body) "The list of warning types used when `byte-compile-warnings' is t.") (defcustom byte-compile-warnings t "List of warnings that the byte-compiler should issue (t for almost all). @@ -326,6 +327,7 @@ Elements of the list may be: docstrings-non-ascii-quotes docstrings that have non-ASCII quotes. This depends on the `docstrings' warning type. suspicious constructs that usually don't do what the coder wanted. + empty-body body argument to a special form or macro is empty. If the list begins with `not', then the remaining elements specify warnings to suppress. For example, (not mapcar) will suppress warnings about mapcar. @@ -541,15 +543,19 @@ Return the compile-time value of FORM." ;; Later `internal--with-suppressed-warnings' binds it again, this ;; time in order to affect warnings emitted during the ;; compilation itself. - (let ((byte-compile--suppressed-warnings - (append warnings byte-compile--suppressed-warnings))) - ;; This function doesn't exist, but is just a placeholder - ;; symbol to hook up with the - ;; `byte-hunk-handler'/`byte-defop-compiler-1' machinery. - `(internal--with-suppressed-warnings - ',warnings - ,(macroexpand-all `(progn ,@body) - macroexpand-all-environment)))))) + (if body + (let ((byte-compile--suppressed-warnings + (append warnings byte-compile--suppressed-warnings))) + ;; This function doesn't exist, but is just a placeholder + ;; symbol to hook up with the + ;; `byte-hunk-handler'/`byte-defop-compiler-1' machinery. + `(internal--with-suppressed-warnings + ',warnings + ,(macroexpand-all `(progn ,@body) + macroexpand-all-environment))) + (macroexp-warn-and-return + (format-message "`with-suppressed-warnings' with empty body") + nil '(empty-body with-suppressed-warnings) t warnings))))) "The default macro-environment passed to macroexpand by the compiler. Placing a macro here will cause a macro to have different semantics when expanded by the compiler as when expanded by the interpreter.") @@ -1569,7 +1575,7 @@ extra args." "`%s' called with %d args to fill %d format field(s)" (car form) nargs nfields))))) -(dolist (elt '(format message error)) +(dolist (elt '(format message format-message error)) (put elt 'byte-compile-format-like t)) (defun byte-compile--suspicious-defcustom-choice (type) @@ -1766,10 +1772,16 @@ It is too wide if it has any lines longer than the largest of kind name col)) ;; There's a "naked" ' character before a symbol/list, so it ;; should probably be quoted with \=. - (when (string-match-p "\\( [\"#]\\|[ \t]\\|^\\)'[a-z(]" docs) + (when (string-match-p (rx (| (in " \t") bol) + (? (in "\"#")) + "'" + (in "A-Za-z" "(")) + docs) (byte-compile-warn-x - name "%s%sdocstring has wrong usage of unescaped single quotes (use \\= or different quoting)" - kind name)) + name + (concat "%s%sdocstring has wrong usage of unescaped single quotes" + " (use \\=%c or different quoting such as %c...%c)") + kind name ?' ?` ?')) ;; There's a "Unicode quote" in the string -- it should probably ;; be an ASCII one instead. (when (byte-compile-warning-enabled-p 'docstrings-non-ascii-quotes) @@ -3439,7 +3451,7 @@ lambda-expression." (t ".")))) (if (eq (car-safe (symbol-function (car form))) 'macro) (byte-compile-report-error - (format "`%s' defined after use in %S (missing `require' of a library file?)" + (format-message "`%s' defined after use in %S (missing `require' of a library file?)" (car form) form))) (if (and handler ;; Make sure that function exists. @@ -3736,7 +3748,7 @@ If it is nil, then the handler is \"byte-compile-SYMBOL.\"" '((0 . byte-compile-no-args) (1 . byte-compile-one-arg) (2 . byte-compile-two-args) - (2-and . byte-compile-and-folded) + (2-cmp . byte-compile-cmp) (3 . byte-compile-three-args) (0-1 . byte-compile-zero-or-one-arg) (1-2 . byte-compile-one-or-two-args) @@ -3815,11 +3827,11 @@ If it is nil, then the handler is \"byte-compile-SYMBOL.\"" (byte-defop-compiler cons 2) (byte-defop-compiler aref 2) (byte-defop-compiler set 2) -(byte-defop-compiler (= byte-eqlsign) 2-and) -(byte-defop-compiler (< byte-lss) 2-and) -(byte-defop-compiler (> byte-gtr) 2-and) -(byte-defop-compiler (<= byte-leq) 2-and) -(byte-defop-compiler (>= byte-geq) 2-and) +(byte-defop-compiler (= byte-eqlsign) 2-cmp) +(byte-defop-compiler (< byte-lss) 2-cmp) +(byte-defop-compiler (> byte-gtr) 2-cmp) +(byte-defop-compiler (<= byte-leq) 2-cmp) +(byte-defop-compiler (>= byte-geq) 2-cmp) (byte-defop-compiler get 2) (byte-defop-compiler nth 2) (byte-defop-compiler substring 1-3) @@ -3883,18 +3895,20 @@ If it is nil, then the handler is \"byte-compile-SYMBOL.\"" (byte-compile-form (nth 2 form)) (byte-compile-out (get (car form) 'byte-opcode) 0))) -(defun byte-compile-and-folded (form) - "Compile calls to functions like `<='. -These implicitly `and' together a bunch of two-arg bytecodes." - (let ((l (length form))) - (cond - ((< l 3) (byte-compile-form `(progn ,(nth 1 form) t))) - ((= l 3) (byte-compile-two-args form)) - ;; Don't use `cl-every' here (see comment where we require cl-lib). - ((not (memq nil (mapcar #'macroexp-copyable-p (nthcdr 2 form)))) - (byte-compile-form `(and (,(car form) ,(nth 1 form) ,(nth 2 form)) - (,(car form) ,@(nthcdr 2 form))))) - (t (byte-compile-normal-call form))))) +(defun byte-compile-cmp (form) + "Compile calls to numeric comparisons such as `<', `=' etc." + ;; Lisp-level transforms should already have reduced valid calls to 2 args. + (if (not (= (length form) 3)) + (byte-compile-subr-wrong-args form "1 or more") + (byte-compile-two-args + (if (macroexp-const-p (nth 1 form)) + ;; First argument is constant: flip it so that the constant + ;; is last, which may allow more lapcode optimisations. + (let* ((op (car form)) + (flipped-op (cdr (assq op '((< . >) (<= . >=) + (> . <) (>= . <=) (= . =)))))) + (list flipped-op (nth 2 form) (nth 1 form))) + form)))) (defun byte-compile-three-args (form) (if (not (= (length form) 4)) @@ -4049,9 +4063,15 @@ This function is never called when `lexical-binding' is nil." (byte-compile-constant 1) (byte-compile-out (get '* 'byte-opcode) 0)) (3 - (byte-compile-form (nth 1 form)) - (byte-compile-form (nth 2 form)) - (byte-compile-out (get (car form) 'byte-opcode) 0)) + (let ((arg1 (nth 1 form)) + (arg2 (nth 2 form))) + (when (and (memq (car form) '(+ *)) + (macroexp-const-p arg1)) + ;; Put constant argument last for better LAP optimisation. + (cl-rotatef arg1 arg2)) + (byte-compile-form arg1) + (byte-compile-form arg2) + (byte-compile-out (get (car form) 'byte-opcode) 0))) (_ ;; >2 args: compile as a single function call. (byte-compile-normal-call form)))) @@ -4835,6 +4855,11 @@ binding slots have been popped." (dolist (clause (reverse clauses)) (let ((condition (nth 1 clause))) + (when (and (eq (car-safe condition) 'quote) + (cdr condition) (null (cddr condition))) + (byte-compile-warn-x + condition "`condition-case' condition should not be quoted: %S" + condition)) (unless (consp condition) (setq condition (list condition))) (dolist (c condition) (unless (and c (symbolp c)) @@ -5487,6 +5512,83 @@ and corresponding effects." (eval form) form))) +;; Check for (in)comparable constant values in calls to `eq', `memq' etc. + +(defun bytecomp--dodgy-eq-arg-p (x number-ok) + "Whether X is a bad argument to `eq' (or `eql' if NUMBER-OK is non-nil)." + (pcase x + ((or `(quote ,(pred consp)) `(function (lambda . ,_))) t) + ((or (pred consp) (pred symbolp)) nil) + ((pred integerp) + (not (or (<= -536870912 x 536870911) number-ok))) + ((pred floatp) (not number-ok)) + (_ t))) + +(defun bytecomp--value-type-description (x) + (cond + ((proper-list-p x) "list") + ((recordp x) "record") + (t (symbol-name (type-of x))))) + +(defun bytecomp--arg-type-description (x) + (pcase x + (`(function (lambda . ,_)) "function") + (`(quote . ,val) (bytecomp--value-type-description val)) + (_ (bytecomp--value-type-description x)))) + +(defun bytecomp--warn-dodgy-eq-arg (form type parenthesis) + (macroexp-warn-and-return + (format-message "`%s' called with literal %s that may never match (%s)" + (car form) type parenthesis) + form (list 'suspicious (car form)) t)) + +(defun bytecomp--check-eq-args (form &optional a b &rest _ignore) + (let* ((number-ok (eq (car form) 'eql)) + (bad-arg (cond ((bytecomp--dodgy-eq-arg-p a number-ok) 1) + ((bytecomp--dodgy-eq-arg-p b number-ok) 2)))) + (if bad-arg + (bytecomp--warn-dodgy-eq-arg + form + (bytecomp--arg-type-description (nth bad-arg form)) + (format "arg %d" bad-arg)) + form))) + +(put 'eq 'compiler-macro #'bytecomp--check-eq-args) +(put 'eql 'compiler-macro #'bytecomp--check-eq-args) + +(defun bytecomp--check-memq-args (form &optional elem list &rest _ignore) + (let* ((fn (car form)) + (number-ok (eq fn 'memql))) + (cond + ((bytecomp--dodgy-eq-arg-p elem number-ok) + (bytecomp--warn-dodgy-eq-arg + form (bytecomp--arg-type-description elem) "arg 1")) + ((and (consp list) (eq (car list) 'quote) + (proper-list-p (cadr list))) + (named-let loop ((elts (cadr list)) (i 1)) + (if elts + (let* ((elt (car elts)) + (x (cond ((eq fn 'assq) (car-safe elt)) + ((eq fn 'rassq) (cdr-safe elt)) + (t elt)))) + (if (or (symbolp x) + (and (integerp x) + (or (<= -536870912 x 536870911) number-ok)) + (and (floatp x) number-ok)) + (loop (cdr elts) (1+ i)) + (bytecomp--warn-dodgy-eq-arg + form (bytecomp--value-type-description x) + (format "element %d of arg 2" i)))) + form))) + (t form)))) + +(put 'memq 'compiler-macro #'bytecomp--check-memq-args) +(put 'memql 'compiler-macro #'bytecomp--check-memq-args) +(put 'assq 'compiler-macro #'bytecomp--check-memq-args) +(put 'rassq 'compiler-macro #'bytecomp--check-memq-args) +(put 'remq 'compiler-macro #'bytecomp--check-memq-args) +(put 'delq 'compiler-macro #'bytecomp--check-memq-args) + (provide 'byte-compile) (provide 'bytecomp) diff --git a/lisp/emacs-lisp/cconv.el b/lisp/emacs-lisp/cconv.el index 0154716627f..e715bd90a00 100644 --- a/lisp/emacs-lisp/cconv.el +++ b/lisp/emacs-lisp/cconv.el @@ -236,9 +236,9 @@ Returns a form where all lambdas don't have any free variables." (not (intern-soft var)) (eq ?_ (aref (symbol-name var) 0))) (let ((suggestions (help-uni-confusable-suggestions (symbol-name var)))) - (format "Unused lexical %s `%S'%s" - varkind (bare-symbol var) - (if suggestions (concat "\n " suggestions) ""))))) + (format-message "Unused lexical %s `%S'%s" + varkind (bare-symbol var) + (if suggestions (concat "\n " suggestions) ""))))) (define-inline cconv--var-classification (binder form) (inline-quote diff --git a/lisp/emacs-lisp/cl-lib.el b/lisp/emacs-lisp/cl-lib.el index 152a1fe9434..95a51a4bdde 100644 --- a/lisp/emacs-lisp/cl-lib.el +++ b/lisp/emacs-lisp/cl-lib.el @@ -201,7 +201,7 @@ should return. Note that Emacs Lisp doesn't really support multiple values, so all this function does is return LIST." (unless (listp list) - (signal 'wrong-type-argument list)) + (signal 'wrong-type-argument (list list))) list) (defsubst cl-multiple-value-list (expression) diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index 43207ce7026..cffe8b09f53 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el @@ -2052,7 +2052,8 @@ info node `(cl) Function Bindings' for details. (dolist (binding bindings) (let ((var (make-symbol (format "--cl-%s--" (car binding)))) (args-and-body (cdr binding))) - (if (and (= (length args-and-body) 1) (symbolp (car args-and-body))) + (if (and (= (length args-and-body) 1) + (macroexp-copyable-p (car args-and-body))) ;; Optimize (cl-flet ((fun var)) body). (setq var (car args-and-body)) (push (list var (if (= (length args-and-body) 1) @@ -3175,8 +3176,9 @@ To see the documentation for a defined struct type, use (when (cl-oddp (length desc)) (push (macroexp-warn-and-return - (format "Missing value for option `%S' of slot `%s' in struct %s!" - (car (last desc)) slot name) + (format-message + "Missing value for option `%S' of slot `%s' in struct %s!" + (car (last desc)) slot name) nil nil nil (car (last desc))) forms) (when (and (keywordp (car defaults)) @@ -3184,8 +3186,9 @@ To see the documentation for a defined struct type, use (let ((kw (car defaults))) (push (macroexp-warn-and-return - (format " I'll take `%s' to be an option rather than a default value." - kw) + (format-message + " I'll take `%s' to be an option rather than a default value." + kw) nil nil nil kw) forms) (push kw desc) diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el index 7ba8e956fb2..d2e7d933f4f 100644 --- a/lisp/emacs-lisp/comp.el +++ b/lisp/emacs-lisp/comp.el @@ -1220,7 +1220,7 @@ clashes." (defun comp-decrypt-arg-list (x function-name) "Decrypt argument list X for FUNCTION-NAME." (unless (fixnump x) - (signal 'native-compiler-error-dyn-func function-name)) + (signal 'native-compiler-error-dyn-func (list function-name))) (let ((rest (not (= (logand x 128) 0))) (mandatory (logand x 127)) (nonrest (ash x -8))) @@ -1264,7 +1264,7 @@ clashes." 'pure)))) (when (byte-code-function-p f) (signal 'native-compiler-error - "can't native compile an already byte-compiled function")) + '("can't native compile an already byte-compiled function"))) (setf (comp-func-byte-func func) (byte-compile (comp-func-name func))) (let ((lap (byte-to-native-lambda-lap @@ -1288,7 +1288,7 @@ clashes." "Byte-compile FORM, spilling data from the byte compiler." (unless (eq (car-safe form) 'lambda) (signal 'native-compiler-error - "Cannot native-compile, form is not a lambda")) + '("Cannot native-compile, form is not a lambda"))) (unless (comp-ctxt-output comp-ctxt) (setf (comp-ctxt-output comp-ctxt) (make-temp-file "comp-lambda-" nil ".eln"))) @@ -1369,7 +1369,7 @@ clashes." (alist-get 'no-native-compile byte-native-qualities)) (throw 'no-native-compile nil)) (unless byte-to-native-top-level-forms - (signal 'native-compiler-error-empty-byte filename)) + (signal 'native-compiler-error-empty-byte (list filename))) (unless (comp-ctxt-output comp-ctxt) (setf (comp-ctxt-output comp-ctxt) (comp-el-to-eln-filename filename @@ -1740,7 +1740,7 @@ Return value is the fall-through block name." do (puthash ff-bb-name ff-bb (comp-func-blocks comp-func)) (setf (comp-limplify-curr-block comp-pass) ff-bb)))) (_ (signal 'native-ice - "missing previous setimm while creating a switch")))) + '("missing previous setimm while creating a switch"))))) (defun comp-emit-set-call-subr (subr-name sp-delta) "Emit a call for SUBR-NAME. @@ -2823,7 +2823,7 @@ blocks." (first-processed (l) (if-let ((p (cl-find-if (lambda (p) (comp-block-idom p)) l))) p - (signal 'native-ice "can't find first preprocessed")))) + (signal 'native-ice '("can't find first preprocessed"))))) (when-let ((blocks (comp-func-blocks comp-func)) (entry (gethash 'entry blocks)) @@ -3721,7 +3721,7 @@ Prepare every function for final compilation and drive the C back-end." (progn (delete-file temp-file) output) - (signal 'native-compiler-error (buffer-string))) + (signal 'native-compiler-error (list (buffer-string)))) (comp-log-to-buffer (buffer-string)))))))) @@ -3805,22 +3805,22 @@ Return the trampoline if found or nil otherwise." form nil ;; If we've disabled nativecomp, don't write the trampolines to ;; the eln cache (but create them). - (and (not inhibit-automatic-native-compilation) - (cl-loop - for dir in (if native-compile-target-directory - (list (expand-file-name comp-native-version-dir - native-compile-target-directory)) - (comp-eln-load-path-eff)) - for f = (expand-file-name - (comp-trampoline-filename subr-name) - dir) - unless (file-exists-p dir) - do (ignore-errors - (make-directory dir t) - (cl-return f)) - when (file-writable-p f) - do (cl-return f) - finally (error "Cannot find suitable directory for output in \ + (unless inhibit-automatic-native-compilation + (cl-loop + for dir in (if native-compile-target-directory + (list (expand-file-name comp-native-version-dir + native-compile-target-directory)) + (comp-eln-load-path-eff)) + for f = (expand-file-name + (comp-trampoline-filename subr-name) + dir) + unless (file-exists-p dir) + do (ignore-errors + (make-directory dir t) + (cl-return f)) + when (file-writable-p f) + do (cl-return f) + finally (error "Cannot find suitable directory for output in \ `native-comp-eln-load-path'")))))) diff --git a/lisp/emacs-lisp/easy-mmode.el b/lisp/emacs-lisp/easy-mmode.el index 5721470ad0d..77f4b26d9bb 100644 --- a/lisp/emacs-lisp/easy-mmode.el +++ b/lisp/emacs-lisp/easy-mmode.el @@ -250,7 +250,8 @@ INIT-VALUE LIGHTER KEYMAP. (warnwrap (if (or (null body) (keywordp (car body))) #'identity (lambda (exp) (macroexp-warn-and-return - "Use keywords rather than deprecated positional arguments to `define-minor-mode'" + (format-message + "Use keywords rather than deprecated positional arguments to `define-minor-mode'") exp)))) keyw keymap-sym tmp) @@ -417,6 +418,8 @@ No problems result if this variable is not bound. `(defvar ,keymap-sym (let ((m ,keymap)) (cond ((keymapp m) m) + ;; FIXME: `easy-mmode-define-keymap' is obsolete, + ;; so this form should also be obsolete somehow. ((listp m) (with-suppressed-warnings ((obsolete easy-mmode-define-keymap)) @@ -682,6 +685,7 @@ Valid keywords and arguments are: :group Ignored. :suppress Non-nil to call `suppress-keymap' on keymap, `nodigits' to suppress digits as prefix arguments." + (declare (obsolete define-keymap "29.1")) (let (inherit dense suppress) (while args (let ((key (pop args)) @@ -722,9 +726,7 @@ 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." - ;; 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)) + (declare (doc-string 3) (indent 1) (obsolete defvar-keymap "29.1")) `(defconst ,m (easy-mmode-define-keymap ,bs nil (if (boundp ',m) ,m) ,(cons 'list args)) ,doc)) diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el index 064a55f2727..9a1f5b9db0f 100644 --- a/lisp/emacs-lisp/eieio.el +++ b/lisp/emacs-lisp/eieio.el @@ -184,8 +184,9 @@ and reference them using the function `class-option'." (when (and initarg (eq alloc :class)) (push (cons sname - (format "Meaningless :initarg for class allocated slot '%S'" - sname)) + (format-message + "Meaningless :initarg for class allocated slot `%S'" + sname)) warnings)) (let ((init (plist-get soptions :initform))) diff --git a/lisp/emacs-lisp/gv.el b/lisp/emacs-lisp/gv.el index e307776252a..dad91e92a45 100644 --- a/lisp/emacs-lisp/gv.el +++ b/lisp/emacs-lisp/gv.el @@ -417,9 +417,9 @@ The return value is the last VAL in the list. (lambda (do key alist &optional default remove testfn) (macroexp-let2 macroexp-copyable-p k key (gv-letplace (getter setter) alist - (macroexp-let2 nil p `(if (and ,testfn (not (eq ,testfn 'eq))) - (assoc ,k ,getter ,testfn) - (assq ,k ,getter)) + (macroexp-let2 nil p (if (member testfn '(nil 'eq #'eq)) + `(assq ,k ,getter) + `(assoc ,k ,getter ,testfn)) (funcall do (if (null default) `(cdr ,p) `(if ,p (cdr ,p) ,default)) (lambda (v) diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el index 168de1bf180..c909ffb6933 100644 --- a/lisp/emacs-lisp/macroexp.el +++ b/lisp/emacs-lisp/macroexp.el @@ -291,10 +291,11 @@ It should normally be a symbol with position and it defaults to FORM." (setq arglist (cdr arglist))) (if values (macroexp-warn-and-return - (format (if (eq values 'too-few) - "attempt to open-code `%s' with too few arguments" - "attempt to open-code `%s' with too many arguments") - name) + (format-message + (if (eq values 'too-few) + "attempt to open-code `%s' with too few arguments" + "attempt to open-code `%s' with too many arguments") + name) form nil nil arglist) ;; The following leads to infinite recursion when loading a @@ -367,14 +368,14 @@ Assumes the caller has bound `macroexpand-all-environment'." (if (null body) (macroexp-unprogn (macroexp-warn-and-return - (format "Empty %s body" fun) - nil nil 'compile-only fun)) + (format-message "`%s' with empty body" fun) + nil (list 'empty-body fun) 'compile-only fun)) (macroexp--all-forms body)) (cdr form)) form))) (`(while) (macroexp-warn-and-return - "missing `while' condition" + (format-message "missing `while' condition") `(signal 'wrong-number-of-arguments '(while 0)) nil 'compile-only form)) (`(setq ,(and var (pred symbolp) @@ -392,7 +393,7 @@ Assumes the caller has bound `macroexpand-all-environment'." (let ((nargs (length args))) (if (/= (logand nargs 1) 0) (macroexp-warn-and-return - "odd number of arguments in `setq' form" + (format-message "odd number of arguments in `setq' form") `(signal 'wrong-number-of-arguments '(setq ,nargs)) nil 'compile-only fn) (let ((assignments nil)) @@ -457,12 +458,13 @@ Assumes the caller has bound `macroexpand-all-environment'." (let ((arg (nth funarg form))) (when (and (eq 'quote (car-safe arg)) (eq 'lambda (car-safe (cadr arg)))) - (setcar (nthcdr funarg form) - (macroexp-warn-and-return - (format "%S quoted with ' rather than with #'" - (let ((f (cadr arg))) - (if (symbolp f) f `(lambda ,(nth 1 f) ...)))) - arg nil nil (cadr arg)))))) + (setcar + (nthcdr funarg form) + (macroexp-warn-and-return + (format + "(lambda %s ...) quoted with ' rather than with #'" + (or (nth 1 (cadr arg)) "()")) + arg nil nil (cadr arg)))))) ;; Macro expand compiler macros. This cannot be delayed to ;; byte-optimize-form because the output of the compiler-macro can ;; use macros. @@ -486,7 +488,7 @@ Assumes the caller has bound `macroexpand-all-environment'." (setq form (macroexp--compiler-macro handler newform)) (if (eq newform form) newform - (macroexp--expand-all newform))) + (macroexp--expand-all form))) (macroexp--expand-all newform)))))) (_ form)))) (pop byte-compile-form-stack))) diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index f92afe56b76..09917cd29b1 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -4562,6 +4562,7 @@ will be signaled in that case." (package--print-email-button maint) (string-trim (substring-no-properties (buffer-string)))))))) +;;;###autoload (defun package-report-bug (desc) "Prepare a message to send to the maintainers of a package. DESC must be a `package-desc' object." diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el index 810b13f61d6..1c5ce5169ab 100644 --- a/lisp/emacs-lisp/pcase.el +++ b/lisp/emacs-lisp/pcase.el @@ -947,7 +947,7 @@ Otherwise, it defers to REST which is a list of branches of the form (let ((code (pcase--u1 matches code vars rest))) (if (eq upat '_) code (macroexp-warn-and-return - "Pattern t is deprecated. Use `_' instead" + (format-message "Pattern t is deprecated. Use `_' instead") code nil nil upat)))) ((eq upat 'pcase--dontcare) :pcase--dontcare) ((memq (car-safe upat) '(guard pred)) diff --git a/lisp/emacs-lisp/range.el b/lisp/emacs-lisp/range.el index 1165fcbbd7d..f441c240a27 100644 --- a/lisp/emacs-lisp/range.el +++ b/lisp/emacs-lisp/range.el @@ -194,7 +194,7 @@ these ranges." (nreverse result))))) (defun range-add-list (ranges list) - "Return a list of ranges that has all articles from both RANGES and LIST. + "Return a list of ranges that has all numbers from both RANGES and LIST. Note: LIST has to be sorted over `<'." (if (not ranges) (range-compress-list list) @@ -249,9 +249,9 @@ Note: LIST has to be sorted over `<'." out))) (defun range-remove (range1 range2) - "Return a range that has all articles from RANGE2 removed from RANGE1. + "Return a range that has all numbers from RANGE2 removed from RANGE1. The returned range is always a list. RANGE2 can also be a unsorted -list of articles. RANGE1 is modified by side effects, RANGE2 is not +list of numbers. RANGE1 is modified by side effects, RANGE2 is not modified." (if (or (null range1) (null range2)) range1 @@ -345,7 +345,7 @@ modified." (defun range-list-intersection (list ranges) "Return a list of numbers in LIST that are members of RANGES. -oLIST is a sorted list." +LIST is a sorted list." (setq ranges (range-normalize ranges)) (let (number result) (while (setq number (pop list)) diff --git a/lisp/emulation/viper-cmd.el b/lisp/emulation/viper-cmd.el index abadefb7105..0eb58565b37 100644 --- a/lisp/emulation/viper-cmd.el +++ b/lisp/emulation/viper-cmd.el @@ -194,9 +194,9 @@ viper-delete-backward-char viper-join-lines viper-delete-char)) - (memq (viper-event-key last-command-event) - '(up down left right (meta f) (meta b) - (control n) (control p) (control f) (control b))))) + (member (viper-event-key last-command-event) + '(up down left right (meta f) (meta b) + (control n) (control p) (control f) (control b))))) (defsubst viper-insert-state-pre-command-sentinel () (or (viper-preserve-cursor-color) diff --git a/lisp/eshell/em-alias.el b/lisp/eshell/em-alias.el index 1be070480b3..841982c3425 100644 --- a/lisp/eshell/em-alias.el +++ b/lisp/eshell/em-alias.el @@ -183,7 +183,9 @@ file named by `eshell-aliases-file'.") (pcomplete-here (eshell-alias-completions pcomplete-stub))) (defun eshell-read-aliases-list () - "Read in an aliases list from `eshell-aliases-file'." + "Read in an aliases list from `eshell-aliases-file'. +This is useful after manually editing the contents of the file." + (interactive) (let ((file eshell-aliases-file)) (when (file-readable-p file) (setq eshell-command-aliases-list diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el index ca51cee2558..acbf206a3c6 100644 --- a/lisp/eshell/em-cmpl.el +++ b/lisp/eshell/em-cmpl.el @@ -306,13 +306,19 @@ to writing a completion function." (insert-and-inherit "\t") (throw 'pcompleted t))) +(defun eshell-complete--eval-argument-form (arg) + "Evaluate a single Eshell argument form ARG for the purposes of completion." + (let ((result (eshell-do-eval `(eshell-commands ,arg) t))) + (cl-assert (eq (car result) 'quote)) + (cadr result))) + (defun eshell-complete-parse-arguments () "Parse the command line arguments for `pcomplete-argument'." (when (and eshell-no-completion-during-jobs (eshell-interactive-process-p)) (eshell--pcomplete-insert-tab)) (let ((end (point-marker)) - (begin (save-excursion (eshell-bol) (point))) + (begin (save-excursion (beginning-of-line) (point))) (posns (list t)) args delim) (when (and pcomplete-allow-modifications @@ -342,39 +348,57 @@ to writing a completion function." (setq pos (1+ pos)))) (setq posns (cdr posns)) (cl-assert (= (length args) (length posns))) - (let ((a args) - (i 0) - l) + (let ((a args) (i 0) new-start) (while a - (if (and (consp (car a)) - (eq (caar a) 'eshell-operator)) - (setq l i)) - (setq a (cdr a) i (1+ i))) - (and l - (setq args (nthcdr (1+ l) args) - posns (nthcdr (1+ l) posns)))) + ;; If there's an unreplaced `eshell-operator' sigil, consider + ;; the token after it the new start of our arguments. + (when (and (consp (car a)) + (eq (caar a) 'eshell-operator)) + (setq new-start i)) + (setq a (cdr a) + i (1+ i))) + (when new-start + (setq args (nthcdr (1+ new-start) args) + posns (nthcdr (1+ new-start) posns)))) (cl-assert (= (length args) (length posns))) (when (and args (eq (char-syntax (char-before end)) ? ) (not (eq (char-before (1- end)) ?\\))) (nconc args (list "")) (nconc posns (list (point)))) + ;; Evaluate and expand Eshell forms. + (let (evaled-args evaled-posns) + (cl-mapc + (lambda (arg posn) + (pcase arg + (`(eshell-splice-args ,val) + (dolist (subarg (eshell-complete--eval-argument-form val)) + (push subarg evaled-args) + (push posn evaled-posns))) + ((pred listp) + (push (eshell-complete--eval-argument-form arg) evaled-args) + (push posn evaled-posns)) + (_ + (push arg evaled-args) + (push posn evaled-posns)))) + args posns) + (setq args (nreverse evaled-args) + posns (nreverse evaled-posns))) + ;; Convert arguments to forms that Pcomplete can understand. (cons (mapcar (lambda (arg) - (let ((val - (if (listp arg) - (let ((result - (eshell-do-eval - (list 'eshell-commands arg) t))) - (cl-assert (eq (car result) 'quote)) - (cadr result)) - arg))) - (cond ((numberp val) - (setq val (number-to-string val))) - ;; expand .../ etc that only eshell understands to - ;; standard ../../ - ((and (stringp val)) (string-match "\\.\\.\\.+/" val) - (setq val (eshell-expand-multiple-dots val)))) - (or val ""))) + (pcase arg + ;; Expand ".../" etc that only Eshell understands to + ;; the standard "../../". + ((rx ".." (+ ".") "/") + (propertize (eshell-expand-multiple-dots arg) + 'pcomplete-arg-value arg)) + ((pred stringp) + arg) + ('nil + (propertize "" 'pcomplete-arg-value arg)) + (_ + (propertize (eshell-stringify arg) + 'pcomplete-arg-value arg)))) args) posns))) diff --git a/lisp/eshell/em-elecslash.el b/lisp/eshell/em-elecslash.el index 80bc0f031ef..2b003f58dc7 100644 --- a/lisp/eshell/em-elecslash.el +++ b/lisp/eshell/em-elecslash.el @@ -72,7 +72,7 @@ insertion." (delete-char -1) (let ((tilde-before (eq ?~ (char-before))) (command (save-excursion - (eshell-bol) + (beginning-of-line) (skip-syntax-forward " ") (thing-at-point 'sexp))) (prefix (file-remote-p default-directory))) diff --git a/lisp/eshell/em-hist.el b/lisp/eshell/em-hist.el index 05e9598f530..6e0e471d910 100644 --- a/lisp/eshell/em-hist.el +++ b/lisp/eshell/em-hist.el @@ -555,7 +555,7 @@ See also `eshell-read-history'." (defun eshell-hist-parse-arguments (&optional b e) "Parse current command arguments in a history-code-friendly way." (let ((end (or e (point))) - (begin (or b (save-excursion (eshell-bol) (point)))) + (begin (or b (save-excursion (beginning-of-line) (point)))) (posb (list t)) (pose (list t)) (textargs (list t)) @@ -913,7 +913,7 @@ If N is negative, search forwards for the -Nth following match." eshell-next-matching-input-from-input))) ;; Starting a new search (setq eshell-matching-input-from-input-string - (buffer-substring (save-excursion (eshell-bol) (point)) + (buffer-substring (save-excursion (beginning-of-line) (point)) (point)) eshell-history-index nil)) (eshell-previous-matching-input @@ -933,7 +933,7 @@ If N is negative, search backwards for the -Nth previous match." (if (get-text-property (point) 'history) (progn (beginning-of-line) t) (let ((before (point))) - (eshell-bol) + (beginning-of-line) (if (and (not (bolp)) (<= (point) before)) t diff --git a/lisp/eshell/em-prompt.el b/lisp/eshell/em-prompt.el index 575b5a595f1..b3a0fadf618 100644 --- a/lisp/eshell/em-prompt.el +++ b/lisp/eshell/em-prompt.el @@ -29,6 +29,8 @@ (require 'esh-mode) (eval-when-compile (require 'eshell)) +(require 'text-property-search) + ;;;###autoload (progn (defgroup eshell-prompt nil @@ -50,7 +52,7 @@ as is common with most shells." (defcustom eshell-prompt-function (lambda () (concat (abbreviate-file-name (eshell/pwd)) - (if (= (user-uid) 0) " # " " $ "))) + (if (= (file-user-uid) 0) " # " " $ "))) "A function that returns the Eshell prompt string. Make sure to update `eshell-prompt-regexp' so that it will match your prompt." @@ -58,11 +60,12 @@ prompt." :group 'eshell-prompt) (defcustom eshell-prompt-regexp "^[^#$\n]* [#$] " - "A regexp which fully matches your eshell prompt. -This setting is important, since it affects how eshell will interpret -the lines that are passed to it. -If this variable is changed, all Eshell buffers must be exited and -re-entered for it to take effect." + "A regexp which fully matches your Eshell prompt. +This is useful for navigating by paragraph using \ +\\[forward-paragraph] and \\[backward-paragraph]. + +If this variable is changed, all Eshell buffers must be exited +and re-entered for it to take effect." :type 'regexp :group 'eshell-prompt) @@ -123,7 +126,6 @@ arriving, or after." (if eshell-prompt-regexp (setq-local paragraph-start eshell-prompt-regexp)) - (setq-local eshell-skip-prompt-function #'eshell-skip-prompt) (eshell-prompt-mode))) (defun eshell-emit-prompt () @@ -134,72 +136,83 @@ arriving, or after." (if (not eshell-prompt-function) (set-marker eshell-last-output-end (point)) (let ((prompt (funcall eshell-prompt-function))) - (and eshell-highlight-prompt - (add-text-properties 0 (length prompt) - '(read-only t - font-lock-face eshell-prompt - front-sticky (font-lock-face read-only) - rear-nonsticky (font-lock-face read-only)) - prompt)) - (eshell-interactive-print prompt))) + (add-text-properties + 0 (length prompt) + (if eshell-highlight-prompt + '( read-only t + field prompt + font-lock-face eshell-prompt + front-sticky (read-only field font-lock-face) + rear-nonsticky (read-only field font-lock-face)) + '( field prompt + front-sticky (field) + rear-nonsticky (field))) + prompt) + (eshell-interactive-filter nil prompt))) (run-hooks 'eshell-after-prompt-hook)) -(defun eshell-backward-matching-input (regexp arg) - "Search backward through buffer for match for REGEXP. -Matches are searched for on lines that match `eshell-prompt-regexp'. -With prefix argument N, search for Nth previous match. -If N is negative, find the next or Nth next match." - (interactive (eshell-regexp-arg "Backward input matching (regexp): ")) - (let* ((re (concat eshell-prompt-regexp ".*" regexp)) - (pos (save-excursion (end-of-line (if (> arg 0) 0 1)) - (if (re-search-backward re nil t arg) - (point))))) - (if (null pos) - (progn (message "Not found") - (ding)) - (goto-char pos) - (eshell-bol)))) - (defun eshell-forward-matching-input (regexp arg) - "Search forward through buffer for match for REGEXP. -Matches are searched for on lines that match `eshell-prompt-regexp'. -With prefix argument N, search for Nth following match. -If N is negative, find the previous or Nth previous match." + "Search forward through buffer for command input that matches REGEXP. +With prefix argument N, search for Nth next match. If N is +negative, find the Nth previous match." (interactive (eshell-regexp-arg "Forward input matching (regexp): ")) - (eshell-backward-matching-input regexp (- arg))) + (let ((direction (if (> arg 0) 1 -1)) + (count (abs arg))) + (unless (catch 'found + (while (> count 0) + (eshell-next-prompt direction) + (when (and (string-match regexp (field-string)) + (= (setq count (1- count)) 0)) + (throw 'found t)))) + (message "Not found") + (ding)))) + +(defun eshell-backward-matching-input (regexp arg) + "Search backward through buffer for command input that matches REGEXP. +With prefix argument N, search for Nth previous match. If N is +negative, find the Nth next match." + (interactive (eshell-regexp-arg "Backward input matching (regexp): ")) + (eshell-forward-matching-input regexp (- arg))) (defun eshell-next-prompt (n) - "Move to end of Nth next prompt in the buffer. -See `eshell-prompt-regexp'." + "Move to end of Nth next prompt in the buffer." (interactive "p") - (if eshell-highlight-prompt - (progn - (while (< n 0) - (while (and (re-search-backward eshell-prompt-regexp nil t) - (not (get-text-property (match-beginning 0) 'read-only)))) - (setq n (1+ n))) - (while (> n 0) - (while (and (re-search-forward eshell-prompt-regexp nil t) - (not (get-text-property (match-beginning 0) 'read-only)))) - (setq n (1- n)))) - (re-search-forward eshell-prompt-regexp nil t n)) - (eshell-skip-prompt)) + (if (natnump n) + (while (and (> n 0) + (text-property-search-forward 'field 'prompt t)) + (setq n (1- n))) + (let (match this-match) + (forward-line 0) ; Don't count prompt on current line. + (while (and (< n 0) + (setq this-match (text-property-search-backward + 'field 'prompt t))) + (setq match this-match + n (1+ n))) + (when match + (goto-char (prop-match-end match)))))) (defun eshell-previous-prompt (n) - "Move to end of Nth previous prompt in the buffer. -See `eshell-prompt-regexp'." + "Move to end of Nth previous prompt in the buffer." (interactive "p") - (forward-line 0) ; Don't count prompt on current line. (eshell-next-prompt (- n))) (defun eshell-skip-prompt () "Skip past the text matching regexp `eshell-prompt-regexp'. If this takes us past the end of the current line, don't skip at all." + (declare (obsolete nil "30.1")) (let ((eol (line-end-position))) (if (and (looking-at eshell-prompt-regexp) (<= (match-end 0) eol)) (goto-char (match-end 0))))) +(defun eshell-bol-ignoring-prompt (arg) + "Move point to the beginning of the current line, past the prompt (if any). +With argument ARG not nil or 1, move forward ARG - 1 lines +first (see `move-beginning-of-line' for more information)." + (interactive "^p") + (let ((inhibit-field-text-motion t)) + (move-beginning-of-line arg))) + (provide 'em-prompt) ;; Local Variables: diff --git a/lisp/eshell/em-rebind.el b/lisp/eshell/em-rebind.el index 2c95d4fdffb..f147d432300 100644 --- a/lisp/eshell/em-rebind.el +++ b/lisp/eshell/em-rebind.el @@ -50,9 +50,7 @@ the behavior of normal shells while the user editing new input text." :group 'eshell-rebind) (defcustom eshell-rebind-keys-alist - '(([(control ?a)] . eshell-bol) - ([home] . eshell-bol) - ([(control ?d)] . eshell-delchar-or-maybe-eof) + '(([(control ?d)] . eshell-delchar-or-maybe-eof) ([backspace] . eshell-delete-backward-char) ([delete] . eshell-delete-backward-char) ([(control ?w)] . backward-kill-word) @@ -190,7 +188,7 @@ lock it at that." (and eshell-remap-previous-input (setq begin (save-excursion - (eshell-bol) + (beginning-of-line) (and (not (bolp)) (point)))) (>= pos begin) (<= pos (line-end-position)) diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el index f88a06d2e95..d550910f4f0 100644 --- a/lisp/eshell/em-unix.el +++ b/lisp/eshell/em-unix.el @@ -786,10 +786,14 @@ external command." (defun eshell-complete-host-reference () "If there is a host reference, complete it." - (let ((arg (pcomplete-actual-arg)) - index) - (when (setq index (string-match "@[a-z.]*\\'" arg)) - (setq pcomplete-stub (substring arg (1+ index)) + (let ((arg (pcomplete-actual-arg))) + (when (string-match + (rx ;; Match an "@", but not immediately following a "$". + (or string-start (not "$")) "@" + (group (* (any "a-z."))) + string-end) + arg) + (setq pcomplete-stub (substring arg (match-beginning 1)) pcomplete-last-completion-raw t) (throw 'pcomplete-completions (pcomplete-read-host-names))))) diff --git a/lisp/eshell/esh-arg.el b/lisp/eshell/esh-arg.el index 9aab3af9b47..6c882471aee 100644 --- a/lisp/eshell/esh-arg.el +++ b/lisp/eshell/esh-arg.el @@ -238,13 +238,53 @@ convert the result to a number as well." (eshell-convert-to-number result) result))) +(defun eshell-concat-groups (quoted &rest args) + "Concatenate groups of arguments in ARGS and return the result. +QUOTED is passed to `eshell-concat' (which see) and, if non-nil, +allows values to be converted to numbers where appropriate. + +ARGS should be a list of lists of arguments, such as that +produced by `eshell-prepare-slice'. \"Adjacent\" values of +consecutive arguments will be passed to `eshell-concat'. For +example, if ARGS is + + ((list a) (list b) (list c d e) (list f g)), + +then the result will be: + + ((eshell-concat QUOTED a b c) + d + (eshell-concat QUOTED e f) + g)." + (let (result current-arg) + (dolist (arg args) + (when arg + (push (car arg) current-arg) + (when (length> arg 1) + (push (apply #'eshell-concat quoted (nreverse current-arg)) + result) + (dolist (inner (butlast (cdr arg))) + (push inner result)) + (setq current-arg (list (car (last arg))))))) + (when current-arg + (push (apply #'eshell-concat quoted (nreverse current-arg)) + result)) + (nreverse result))) + (defun eshell-resolve-current-argument () "If there are pending modifications to be made, make them now." (when eshell-current-argument (when eshell-arg-listified - (setq eshell-current-argument - (append (list 'eshell-concat eshell-current-quoted) - eshell-current-argument)) + (if-let ((grouped-terms (eshell-prepare-splice + eshell-current-argument))) + (setq eshell-current-argument + `(eshell-splice-args + (eshell-concat-groups ,eshell-current-quoted + ,@grouped-terms))) + ;; If no terms are spliced, use a simpler command form. + (setq eshell-current-argument + (append (list 'eshell-concat eshell-current-quoted) + eshell-current-argument))) (setq eshell-arg-listified nil)) (while eshell-current-modifiers (setq eshell-current-argument @@ -261,7 +301,8 @@ argument list in place of the value of the current argument." (setq eshell-current-argument (car arguments)) (cl-assert (and (not eshell-arg-listified) (not eshell-current-modifiers))) - (setq eshell-current-argument (cons 'eshell-flatten-args arguments)))) + (setq eshell-current-argument + (cons 'eshell-splice-immediately arguments)))) (throw 'eshell-arg-done t)) (defun eshell-quote-argument (string) @@ -302,7 +343,8 @@ Point is left at the end of the arguments." (buffer-substring here (point-max)))) (when arg (nconc args - (if (eq (car-safe arg) 'eshell-flatten-args) + (if (eq (car-safe arg) + 'eshell-splice-immediately) (cdr arg) (list arg)))))))) (throw 'eshell-incomplete (if (listp delim) @@ -348,6 +390,10 @@ Point is left at the end of the arguments." "A stub function that generates an error if a floating operator is found." (error "Unhandled operator in input text")) +(defsubst eshell-splice-args (&rest _args) + "A stub function that generates an error if a floating splice is found." + (error "Splice operator is not permitted in this context")) + (defsubst eshell-looking-at-backslash-return (pos) "Test whether a backslash-return sequence occurs at POS." (and (eq (char-after pos) ?\\) @@ -377,20 +423,24 @@ after are both returned." (when (eshell-looking-at-backslash-return (point)) (throw 'eshell-incomplete ?\\)) (forward-char 2) ; Move one char past the backslash. - (if (eq (char-before) ?\n) - ;; Escaped newlines are extra-special: they expand to an empty - ;; token to allow for continuing Eshell commands across - ;; multiple lines. - 'eshell-empty-token - ;; If the char is in a quote, backslash only has special meaning - ;; if it is escaping a special char. - (if eshell-current-quoted - (if (memq (char-before) eshell-special-chars-inside-quoting) - (list 'eshell-escape-arg (char-to-string (char-before))) - (concat "\\" (char-to-string (char-before)))) - (if (memq (char-before) eshell-special-chars-outside-quoting) - (list 'eshell-escape-arg (char-to-string (char-before))) - (char-to-string (char-before))))))) + (let ((special-chars (if eshell-current-quoted + eshell-special-chars-inside-quoting + eshell-special-chars-outside-quoting))) + (cond + ;; Escaped newlines are extra-special: they expand to an empty + ;; token to allow for continuing Eshell commands across + ;; multiple lines. + ((eq (char-before) ?\n) + 'eshell-empty-token) + ((memq (char-before) special-chars) + (list 'eshell-escape-arg (char-to-string (char-before)))) + ;; If the char is in a quote, backslash only has special + ;; meaning if it is escaping a special char. Otherwise, the + ;; result is the literal string "\c". + (eshell-current-quoted + (concat "\\" (char-to-string (char-before)))) + (t + (char-to-string (char-before))))))) (defun eshell-parse-literal-quote () "Parse a literally quoted string. Nothing has special meaning!" @@ -496,5 +546,33 @@ If the form has no `type', the syntax is parsed as if `type' were (char-to-string (char-after))))) (goto-char end))))))) +(defun eshell-prepare-splice (args) + "Prepare a list of ARGS for splicing, if any arg requested a splice. +This looks for `eshell-splice-args' as the CAR of each argument, +and if found, returns a grouped list like: + + ((list arg-1) (list arg-2) spliced-arg-3 ...) + +This allows callers of this function to build the final spliced +list by concatenating each element together, e.g. with + + (apply #\\='append grouped-list) + +If no argument requested a splice, return nil." + (let* ((splicep nil) + ;; Group each arg like ((list arg-1) (list arg-2) ...), + ;; splicing in `eshell-splice-args' args. This lets us + ;; apply spliced args correctly elsewhere. + (grouped-args + (mapcar (lambda (i) + (if (eq (car-safe i) 'eshell-splice-args) + (progn + (setq splicep t) + (cadr i)) + `(list ,i))) + args))) + (when splicep + grouped-args))) + (provide 'esh-arg) ;;; esh-arg.el ends here diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index f4ac384ccc5..b5f1d60ff18 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -343,7 +343,7 @@ This only returns external (non-Lisp) processes." #'eshell-complete-lisp-symbols nil t))) (defun eshell-complete-lisp-symbols () - "If there is a user reference, complete it." + "If there is a Lisp symbol, complete it." (let ((arg (pcomplete-actual-arg))) (when (string-match (concat "\\`" eshell-lisp-regexp) arg) (setq pcomplete-stub (substring arg (match-end 0)) @@ -418,8 +418,11 @@ hooks should be run before and after the command." (eshell-separate-commands terms "[&;]" nil 'eshell--sep-terms)))) (let ((cmd commands)) (while cmd - (if (cdr cmd) - (setcar cmd `(eshell-commands ,(car cmd)))) + ;; Copy I/O handles so each full statement can manipulate them + ;; if they like. Steal the handles for the last command in + ;; the list; we won't use the originals again anyway. + (setcar cmd `(eshell-with-copied-handles + ,(car cmd) ,(not (cdr cmd)))) (setq cmd (cdr cmd)))) (if toplevel `(eshell-commands (progn @@ -480,11 +483,16 @@ hooks should be run before and after the command." (let ((sym (if eshell-in-pipeline-p 'eshell-named-command* 'eshell-named-command)) - (cmd (car terms)) - (args (cdr terms))) - (if args - (list sym cmd `(list ,@(cdr terms))) - (list sym cmd)))) + (grouped-terms (eshell-prepare-splice terms))) + (cond + (grouped-terms + `(let ((terms (nconc ,@grouped-terms))) + (,sym (car terms) (cdr terms)))) + ;; If no terms are spliced, use a simpler command form. + ((cdr terms) + (list sym (car terms) `(list ,@(cdr terms)))) + (t + (list sym (car terms)))))) (defvar eshell-command-body) (defvar eshell-test-body) @@ -783,16 +791,17 @@ this grossness will be made to disappear by using `call/cc'..." (defvar eshell-output-handle) ;Defined in esh-io.el. (defvar eshell-error-handle) ;Defined in esh-io.el. -(defmacro eshell-copy-handles (object) - "Duplicate current I/O handles, so OBJECT works with its own copy." +(defmacro eshell-with-copied-handles (object &optional steal-p) + "Duplicate current I/O handles, so OBJECT works with its own copy. +If STEAL-P is non-nil, these new handles will be stolen from the +current ones (see `eshell-duplicate-handles')." `(let ((eshell-current-handles - (eshell-create-handles - (car (aref eshell-current-handles - eshell-output-handle)) nil - (car (aref eshell-current-handles - eshell-error-handle)) nil))) + (eshell-duplicate-handles eshell-current-handles ,steal-p))) ,object)) +(define-obsolete-function-alias 'eshell-copy-handles + #'eshell-with-copied-handles "30.1") + (defmacro eshell-protect (object) "Protect I/O handles, so they aren't get closed after eval'ing OBJECT." `(progn @@ -803,7 +812,7 @@ this grossness will be made to disappear by using `call/cc'..." "Execute the commands in PIPELINE, connecting each to one another. This macro calls itself recursively, with NOTFIRST non-nil." (when (setq pipeline (cadr pipeline)) - `(eshell-copy-handles + `(eshell-with-copied-handles (progn ,(when (cdr pipeline) `(let ((nextproc @@ -828,7 +837,9 @@ This macro calls itself recursively, with NOTFIRST non-nil." (let ((proc ,(car pipeline))) (set headproc (or proc (symbol-value headproc))) (set tailproc (or (symbol-value tailproc) proc)) - proc)))))) + proc))) + ;; Steal handles if this is the last item in the pipeline. + ,(null (cdr pipeline))))) (defmacro eshell-do-pipelines-synchronously (pipeline) "Execute the commands in PIPELINE in sequence synchronously. @@ -875,11 +886,8 @@ This is used on systems where async subprocesses are not supported." (progn ,(if (fboundp 'make-process) `(eshell-do-pipelines ,pipeline) - `(let ((tail-handles (eshell-create-handles - (car (aref eshell-current-handles - ,eshell-output-handle)) nil - (car (aref eshell-current-handles - ,eshell-error-handle)) nil))) + `(let ((tail-handles (eshell-duplicate-handles + eshell-current-handles))) (eshell-do-pipelines-synchronously ,pipeline))) (eshell-process-identity (cons (symbol-value headproc) (symbol-value tailproc)))))) @@ -1019,7 +1027,9 @@ produced by `eshell-parse-command'." ;; We can just stick the new command at the end of the current ;; one, and everything will happen as it should. (setcdr (last (cdr eshell-current-command)) - (list `(let ((here (and (eobp) (point)))) + (list `(let ((here (and (eobp) (point))) + (eshell-command-body '(nil)) + (eshell-test-body '(nil))) ,(and input `(insert-and-inherit ,(concat input "\n"))) (if here diff --git a/lisp/eshell/esh-io.el b/lisp/eshell/esh-io.el index 26a8530fe54..cccdb49ce2a 100644 --- a/lisp/eshell/esh-io.el +++ b/lisp/eshell/esh-io.el @@ -74,6 +74,8 @@ (eval-when-compile (require 'cl-lib)) +(declare-function eshell-interactive-print "esh-mode" (string)) + (defgroup eshell-io nil "Eshell's I/O management code provides a scheme for treating many different kinds of objects -- symbols, files, buffers, etc. -- as @@ -116,16 +118,22 @@ from executing while Emacs is redisplaying." :group 'eshell-io) (defcustom eshell-virtual-targets - '(("/dev/eshell" eshell-interactive-print nil) + '(;; The literal string "/dev/null" is intentional here. It just + ;; provides compatibility so that users can redirect to + ;; "/dev/null" no matter the actual value of `null-device'. + ("/dev/null" (lambda (_mode) (throw 'eshell-null-device t)) t) + ("/dev/eshell" eshell-interactive-print nil) ("/dev/kill" (lambda (mode) - (if (eq mode 'overwrite) - (kill-new "")) - 'eshell-kill-append) t) + (when (eq mode 'overwrite) + (kill-new "")) + #'eshell-kill-append) + t) ("/dev/clip" (lambda (mode) - (if (eq mode 'overwrite) - (let ((select-enable-clipboard t)) - (kill-new ""))) - 'eshell-clipboard-append) t)) + (when (eq mode 'overwrite) + (let ((select-enable-clipboard t)) + (kill-new ""))) + #'eshell-clipboard-append) + t)) "Map virtual devices name to Emacs Lisp functions. If the user specifies any of the filenames above as a redirection target, the function in the second element will be called. @@ -138,10 +146,8 @@ function. The output function is then called repeatedly with single strings, which represents successive pieces of the output of the command, until nil -is passed, meaning EOF. - -NOTE: /dev/null is handled specially as a virtual target, and should -not be added to this variable." +is passed, meaning EOF." + :version "30.1" :type '(repeat (list (string :tag "Target") function @@ -291,25 +297,58 @@ describing the mode, e.g. for using with `eshell-get-target'.") (defun eshell-create-handles (stdout output-mode &optional stderr error-mode) "Create a new set of file handles for a command. -The default location for standard output and standard error will go to -STDOUT and STDERR, respectively. -OUTPUT-MODE and ERROR-MODE are either `overwrite', `append' or `insert'; -a nil value of mode defaults to `insert'." +The default target for standard output and standard error will +go to STDOUT and STDERR, respectively. OUTPUT-MODE and +ERROR-MODE are either `overwrite', `append' or `insert'; a nil +value of mode defaults to `insert'. + +The result is a vector of file handles. Each handle is of the form: + + ((TARGETS . REF-COUNT) DEFAULT) + +TARGETS is a list of destinations for output. REF-COUNT is the +number of references to this handle (initially 1); see +`eshell-protect-handles' and `eshell-close-handles'. DEFAULT is +non-nil if handle has its initial default value (always t after +calling this function)." (let* ((handles (make-vector eshell-number-of-handles nil)) - (output-target (eshell-get-target stdout output-mode)) - (error-target (if stderr - (eshell-get-target stderr error-mode) - output-target))) - (aset handles eshell-output-handle (cons output-target 1)) - (aset handles eshell-error-handle (cons error-target 1)) + (output-target + (let ((target (eshell-get-target stdout output-mode))) + (cons (when target (list target)) 1))) + (error-target + (if stderr + (let ((target (eshell-get-target stderr error-mode))) + (cons (when target (list target)) 1)) + (cl-incf (cdr output-target)) + output-target))) + (aset handles eshell-output-handle (list output-target t)) + (aset handles eshell-error-handle (list error-target t)) handles)) +(defun eshell-duplicate-handles (handles &optional steal-p) + "Create a duplicate of the file handles in HANDLES. +This uses the targets of each handle in HANDLES, incrementing its +reference count by one (unless STEAL-P is non-nil). These +targets are shared between the original set of handles and the +new one, so the targets are only closed when the reference count +drops to 0 (see `eshell-close-handles'). + +This function also sets the DEFAULT field for each handle to +t (see `eshell-create-handles'). Unlike the targets, this value +is not shared with the original handles." + (let ((dup-handles (make-vector eshell-number-of-handles nil))) + (dotimes (idx eshell-number-of-handles) + (when-let ((handle (aref handles idx))) + (unless steal-p + (cl-incf (cdar handle))) + (aset dup-handles idx (list (car handle) t)))) + dup-handles)) + (defun eshell-protect-handles (handles) "Protect the handles in HANDLES from a being closed." (dotimes (idx eshell-number-of-handles) - (when (aref handles idx) - (setcdr (aref handles idx) - (1+ (cdr (aref handles idx)))))) + (when-let ((handle (aref handles idx))) + (cl-incf (cdar handle)))) handles) (defun eshell-close-handles (&optional exit-code result handles) @@ -327,46 +366,56 @@ the value already set in `eshell-last-command-result'." (when result (cl-assert (eq (car result) 'quote)) (setq eshell-last-command-result (cadr result))) - (let ((handles (or handles eshell-current-handles))) + (let ((handles (or handles eshell-current-handles)) + (succeeded (= eshell-last-command-status 0))) (dotimes (idx eshell-number-of-handles) - (when-let ((handle (aref handles idx))) - (setcdr handle (1- (cdr handle))) - (when (= (cdr handle) 0) - (dolist (target (ensure-list (car (aref handles idx)))) - (eshell-close-target target (= eshell-last-command-status 0))) - (setcar handle nil)))))) + (eshell-close-handle (aref handles idx) succeeded)))) + +(defun eshell-close-handle (handle status) + "Close a single HANDLE, taking refcounts into account. +This will pass STATUS to each target for the handle, which should +be a non-nil value on successful termination." + (when handle + (cl-assert (> (cdar handle) 0) + "Attempted to close a handle with 0 references") + (when (and (> (cdar handle) 0) + (= (cl-decf (cdar handle)) 0)) + (dolist (target (caar handle)) + (eshell-close-target target status)) + (setcar (car handle) nil)))) (defun eshell-set-output-handle (index mode &optional target handles) "Set handle INDEX for the current HANDLES to point to TARGET using MODE. -If HANDLES is nil, use `eshell-current-handles'." +If HANDLES is nil, use `eshell-current-handles'. + +If the handle is currently set to its default value (see +`eshell-create-handles'), this will overwrite the targets with +the new target. Otherwise, it will append the new target to the +current list of targets." (when target - (let ((handles (or handles eshell-current-handles))) - (if (and (stringp target) - ;; The literal string "/dev/null" is intentional here. - ;; It just provides compatibility so that users can - ;; redirect to "/dev/null" no matter the actual value - ;; of `null-device'. - (string= target "/dev/null")) - (aset handles index nil) - (let ((where (eshell-get-target target mode)) - (current (car (aref handles index)))) - (if (listp current) - (unless (member where current) - (setq current (append current (list where)))) - (setq current (list where))) - (if (not (aref handles index)) - (aset handles index (cons nil 1))) - (setcar (aref handles index) current)))))) + (let* ((handles (or handles eshell-current-handles)) + (handle (or (aref handles index) + (aset handles index (list (cons nil 1) nil)))) + (defaultp (cadr handle))) + (when defaultp + (cl-decf (cdar handle)) + (setcar handle (cons nil 1))) + (catch 'eshell-null-device + (let ((current (caar handle)) + (where (eshell-get-target target mode))) + (unless (member where current) + (setcar (car handle) (append current (list where)))))) + (setcar (cdr handle) nil)))) (defun eshell-copy-output-handle (index index-to-copy &optional handles) "Copy the handle INDEX-TO-COPY to INDEX for the current HANDLES. If HANDLES is nil, use `eshell-current-handles'." (let* ((handles (or handles eshell-current-handles)) (handle-to-copy (car (aref handles index-to-copy)))) - (setcar (aref handles index) - (if (listp handle-to-copy) - (copy-sequence handle-to-copy) - handle-to-copy)))) + (when handle-to-copy + (cl-incf (cdr handle-to-copy))) + (eshell-close-handle (aref handles index) nil) + (setcar (aref handles index) handle-to-copy))) (defun eshell-set-all-output-handles (mode &optional target handles) "Set output and error HANDLES to point to TARGET using MODE. @@ -497,9 +546,9 @@ INDEX is the handle index to check. If nil, check (let ((handles (or handles eshell-current-handles)) (index (or index eshell-output-handle))) (if (eq index 'all) - (and (eq (car (aref handles eshell-output-handle)) t) - (eq (car (aref handles eshell-error-handle)) t)) - (eq (car (aref handles index)) t)))) + (and (equal (caar (aref handles eshell-output-handle)) '(t)) + (equal (caar (aref handles eshell-error-handle)) '(t))) + (equal (caar (aref handles index)) '(t))))) (defvar eshell-print-queue nil) (defvar eshell-print-queue-count -1) @@ -550,8 +599,6 @@ after all printing is over with no argument." (eshell-print object) (eshell-print "\n")) -(autoload 'eshell-output-filter "esh-mode") - (defun eshell-output-object-to-target (object target) "Insert OBJECT into TARGET. Returns what was actually sent, or nil if nothing was sent." @@ -561,7 +608,7 @@ Returns what was actually sent, or nil if nothing was sent." ((symbolp target) (if (eq target t) ; means "print to display" - (eshell-output-filter nil (eshell-stringify object)) + (eshell-interactive-print (eshell-stringify object)) (if (not (symbol-value target)) (set target object) (setq object (eshell-stringify object)) @@ -606,15 +653,10 @@ Returns what was actually sent, or nil if nothing was sent." If HANDLE-INDEX is nil, output to `eshell-output-handle'. HANDLES is the set of file handles to use; if nil, use `eshell-current-handles'." - (let ((target (car (aref (or handles eshell-current-handles) - (or handle-index eshell-output-handle))))) - (if (listp target) - (while target - (eshell-output-object-to-target object (car target)) - (setq target (cdr target))) - (eshell-output-object-to-target object target) - ;; Explicitly return nil to match the list case above. - nil))) + (let ((targets (caar (aref (or handles eshell-current-handles) + (or handle-index eshell-output-handle))))) + (dolist (target targets) + (eshell-output-object-to-target object target)))) (provide 'esh-io) ;;; esh-io.el ends here diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el index d80f1d1f390..503d9ba1b63 100644 --- a/lisp/eshell/esh-mode.el +++ b/lisp/eshell/esh-mode.el @@ -155,7 +155,8 @@ number, if the function `eshell-truncate-buffer' is on eshell-watch-for-password-prompt) "Functions to call before output is displayed. These functions are only called for output that is displayed -interactively, and not for output which is redirected." +interactively (see `eshell-interactive-filter'), and not for +output which is redirected." :type 'hook) (defcustom eshell-preoutput-filter-functions nil @@ -175,6 +176,8 @@ This is used by `eshell-watch-for-password-prompt'." "A function called from beginning of line to skip the prompt." :type '(choice (const nil) function)) +(make-obsolete-variable 'eshell-skip-prompt-function nil "30.1") + (defcustom eshell-status-in-mode-line t "If non-nil, let the user know a command is running in the mode line." :type 'boolean) @@ -261,14 +264,13 @@ This is used by `eshell-watch-for-password-prompt'." "C-c" 'eshell-command-map "RET" #'eshell-send-input "M-RET" #'eshell-queue-input - "C-M-l" #'eshell-show-output - "C-a" #'eshell-bol) + "C-M-l" #'eshell-show-output) (defvar-keymap eshell-command-map :prefix 'eshell-command-map "M-o" #'eshell-mark-output "M-d" #'eshell-toggle-direct-send - "C-a" #'eshell-bol + "C-a" #'move-beginning-of-line "C-b" #'eshell-backward-argument "C-e" #'eshell-show-maximum-output "C-f" #'eshell-forward-argument @@ -471,7 +473,7 @@ and the hook `eshell-exit-hook'." (defun eshell-move-argument (limit func property arg) "Move forward ARG arguments." (catch 'eshell-incomplete - (eshell-parse-arguments (save-excursion (eshell-bol) (point)) + (eshell-parse-arguments (save-excursion (beginning-of-line) (point)) (line-end-position))) (let ((pos (save-excursion (funcall func 1) @@ -504,12 +506,7 @@ and the hook `eshell-exit-hook'." (kill-ring-save begin (point)) (yank))) -(defun eshell-bol () - "Go to the beginning of line, then skip past the prompt, if any." - (interactive) - (beginning-of-line) - (and eshell-skip-prompt-function - (funcall eshell-skip-prompt-function))) +(define-obsolete-function-alias 'eshell-bol #'beginning-of-line "30.1") (defsubst eshell-push-command-mark () "Push a mark at the end of the last input text." @@ -525,9 +522,13 @@ Putting this function on `eshell-pre-command-hook' will mimic Plan 9's (custom-add-option 'eshell-pre-command-hook #'eshell-goto-input-start) -(defsubst eshell-interactive-print (string) +(defun eshell-interactive-print (string) "Print STRING to the eshell display buffer." - (eshell-output-filter nil string)) + (when string + (add-text-properties 0 (length string) + '(field command-output rear-nonsticky (field)) + string) + (eshell-interactive-filter nil string))) (defsubst eshell-begin-on-new-line () "This function outputs a newline if not at beginning of line." @@ -687,14 +688,14 @@ newline." (custom-add-option 'eshell-input-filter-functions 'eshell-kill-new) -(defun eshell-output-filter (process string) - "Send the output from PROCESS (STRING) to the interactive display. +(defun eshell-interactive-filter (buffer string) + "Send output (STRING) to the interactive display, using BUFFER. This is done after all necessary filtering has been done." - (let ((oprocbuf (if process (process-buffer process) - (current-buffer))) - (inhibit-modification-hooks t)) - (when (and string oprocbuf (buffer-name oprocbuf)) - (with-current-buffer oprocbuf + (unless buffer + (setq buffer (current-buffer))) + (when (and string (buffer-live-p buffer)) + (let ((inhibit-modification-hooks t)) + (with-current-buffer buffer (let ((functions eshell-preoutput-filter-functions)) (while (and functions string) (setq string (funcall (car functions) string)) @@ -851,7 +852,7 @@ With a prefix argument, narrows region to last command output." (if (> (point) eshell-last-output-end) (kill-region eshell-last-output-end (point)) (let ((here (point))) - (eshell-bol) + (beginning-of-line) (kill-region (point) here)))) (defun eshell-show-maximum-output (&optional interactive) @@ -879,17 +880,18 @@ If SCROLLBACK is non-nil, clear the scrollback contents." (erase-buffer))) (defun eshell-get-old-input (&optional use-current-region) - "Return the command input on the current line." + "Return the command input on the current line. +If USE-CURRENT-REGION is non-nil, return the current region." (if use-current-region (buffer-substring (min (point) (mark)) (max (point) (mark))) (save-excursion - (beginning-of-line) - (and eshell-skip-prompt-function - (funcall eshell-skip-prompt-function)) - (let ((beg (point))) - (end-of-line) - (buffer-substring beg (point)))))) + (let ((inhibit-field-text-motion t)) + (end-of-line)) + (let ((inhibit-field-text-motion) + (end (point))) + (beginning-of-line) + (buffer-substring (point) end))))) (defun eshell-copy-old-input () "Insert after prompt old input at point as new input to be edited." diff --git a/lisp/eshell/esh-opt.el b/lisp/eshell/esh-opt.el index e8da847e184..9253f9a4a7d 100644 --- a/lisp/eshell/esh-opt.el +++ b/lisp/eshell/esh-opt.el @@ -132,7 +132,7 @@ This code doesn't really need to be macro expanded everywhere." (setq args (eshell--process-args name args options)) nil)))) (when usage-msg - (error "%s" usage-msg)))))) + (user-error "%s" usage-msg)))))) (if ext-command (throw 'eshell-external (eshell-external-command ext-command orig-args)) @@ -237,7 +237,7 @@ 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 +\(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) diff --git a/lisp/eshell/esh-proc.el b/lisp/eshell/esh-proc.el index fcd59ab9f37..27cd521e82e 100644 --- a/lisp/eshell/esh-proc.el +++ b/lisp/eshell/esh-proc.el @@ -309,7 +309,7 @@ Used only on systems which do not support async subprocesses.") :name (concat (file-name-nondirectory command) "-stderr") :buffer (current-buffer) :filter (if (eshell-interactive-output-p eshell-error-handle) - #'eshell-output-filter + #'eshell-interactive-process-filter #'eshell-insertion-filter) :sentinel #'eshell-sentinel)) (eshell-record-process-properties stderr-proc eshell-error-handle)) @@ -325,7 +325,7 @@ Used only on systems which do not support async subprocesses.") :buffer (current-buffer) :command (cons command args) :filter (if (eshell-interactive-output-p) - #'eshell-output-filter + #'eshell-interactive-process-filter #'eshell-insertion-filter) :sentinel #'eshell-sentinel :connection-type conn-type @@ -386,7 +386,7 @@ Used only on systems which do not support async subprocesses.") line (buffer-substring-no-properties lbeg lend)) (set-buffer oldbuf) (if interact-p - (eshell-output-filter nil line) + (eshell-interactive-process-filter nil line) (eshell-output-object line)) (setq lbeg lend) (set-buffer proc-buf)) @@ -407,6 +407,22 @@ Used only on systems which do not support async subprocesses.") (setq proc t)))) proc)) +(defun eshell-interactive-process-filter (process string) + "Send the output from PROCESS (STRING) to the interactive display. +This is done after all necessary filtering has been done." + (when string + (add-text-properties 0 (length string) + '(field command-output rear-nonsticky (field)) + string) + (require 'esh-mode) + (declare-function eshell-interactive-filter "esh-mode" (buffer string)) + (eshell-interactive-filter (if process (process-buffer process) + (current-buffer)) + string))) + +(define-obsolete-function-alias 'eshell-output-filter + #'eshell-interactive-process-filter "30.1") + (defun eshell-insertion-filter (proc string) "Insert a string into the eshell buffer, or a process/file/buffer. PROC is the process for which we're inserting output. STRING is the @@ -472,7 +488,7 @@ PROC is the process that's exiting. STRING is the exit message." (if (process-get proc :eshell-busy) (run-at-time 0 nil finish-io) (when data - (ignore-error 'eshell-pipe-broken + (ignore-error eshell-pipe-broken (eshell-output-object data index handles))) (eshell-close-handles diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el index d003148dc96..9549e7f1a10 100644 --- a/lisp/eshell/esh-util.el +++ b/lisp/eshell/esh-util.el @@ -94,13 +94,6 @@ a non-nil value, will be passed strings, not numbers, even when an argument matches `eshell-number-regexp'." :type 'boolean) -(defcustom eshell-number-regexp "-?\\([0-9]*\\.\\)?[0-9]+\\(e[-0-9.]+\\)?" - "Regular expression used to match numeric arguments. -If `eshell-convert-numeric-arguments' is non-nil, and an argument -matches this regexp, it will be converted to a Lisp number, using the -function `string-to-number'." - :type 'regexp) - (defcustom eshell-ange-ls-uids nil "List of user/host/id strings, used to determine remote ownership." :type '(repeat (cons :tag "Host for User/UID map" @@ -111,6 +104,22 @@ function `string-to-number'." ;;; Internal Variables: +(defvar eshell-number-regexp + (rx (? "-") + (or (seq (+ digit) (? "." (* digit))) + (seq (* digit) "." (+ digit))) + ;; Optional exponent + (? (or "e" "E") + (or "+INF" "+NaN" + (seq (? (or "+" "-")) (+ digit))))) + "Regular expression used to match numeric arguments. +If `eshell-convert-numeric-arguments' is non-nil, and an argument +matches this regexp, it will be converted to a Lisp number, using the +function `string-to-number'.") + +(defvar eshell-integer-regexp (rx (? "-") (+ digit)) + "Regular expression used to match integer arguments.") + (defvar eshell-group-names nil "A cache to hold the names of groups.") @@ -362,9 +371,13 @@ Prepend remote identification of `default-directory', if any." "Convert each element of ARGS into a string value." (mapcar #'eshell-stringify args)) +(defsubst eshell-list-to-string (list) + "Convert LIST into a single string separated by spaces." + (mapconcat #'eshell-stringify list " ")) + (defsubst eshell-flatten-and-stringify (&rest args) "Flatten and stringify all of the ARGS into a single string." - (mapconcat #'eshell-stringify (flatten-tree args) " ")) + (eshell-list-to-string (flatten-tree args))) (defsubst eshell-directory-files (regexp &optional directory) "Return a list of files in the given DIRECTORY matching REGEXP." diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el index dfc52083acb..60aab92b33e 100644 --- a/lisp/eshell/esh-var.el +++ b/lisp/eshell/esh-var.el @@ -86,6 +86,13 @@ ;; Returns the length of the value of $EXPR. This could also be ;; done using the `length' Lisp function. ;; +;; $@EXPR +;; +;; Splices the value of $EXPR in-place into the current list of +;; arguments. This is analogous to the `,@' token in Elisp +;; backquotes, and works as if the user typed '$EXPR[0] $EXPR[1] +;; ... $EXPR[N]'. +;; ;; There are also a few special variables defined by Eshell. '$$' is ;; the value of the last command (t or nil, in the case of an external ;; command). This makes it possible to chain results: @@ -155,6 +162,7 @@ if they are quoted with a backslash." ("COLUMNS" ,(lambda () (window-body-width nil 'remap)) t t) ("LINES" ,(lambda () (window-body-height nil 'remap)) t t) ("INSIDE_EMACS" eshell-inside-emacs t) + ("UID" ,(lambda () (file-user-uid)) nil t) ;; for esh-ext.el ("PATH" (,(lambda () (string-join (eshell-get-path t) (path-separator))) @@ -320,10 +328,9 @@ copied (a.k.a. \"exported\") to the environment of created subprocesses." "Parse a variable interpolation. This function is explicit for adding to `eshell-parse-argument-hook'." (when (and (eq (char-after) ?$) - (/= (1+ (point)) (point-max))) + (/= (1+ (point)) (point-max))) (forward-char) - (list 'eshell-escape-arg - (eshell-parse-variable)))) + (eshell-parse-variable))) (defun eshell/define (var-alias definition) "Define a VAR-ALIAS using DEFINITION." @@ -453,18 +460,24 @@ Its purpose is to call `eshell-parse-variable-ref', and then to process any indices that come after the variable reference." (let* ((get-len (when (eq (char-after) ?#) (forward-char) t)) + (splice (when (eq (char-after) ?@) + (forward-char) t)) value indices) (setq value (eshell-parse-variable-ref get-len) indices (and (not (eobp)) (eq (char-after) ?\[) (eshell-parse-indices)) - ;; This is an expression that will be evaluated by `eshell-do-eval', - ;; which only support let-binding of dynamically-scoped vars - value `(let ((indices (eshell-eval-indices ',indices))) ,value)) + value `(let ((indices ,(eshell-prepare-indices indices))) ,value)) (when get-len (setq value `(length ,value))) (when eshell-current-quoted - (setq value `(eshell-stringify ,value))) + (if splice + (setq value `(eshell-list-to-string ,value) + splice nil) + (setq value `(eshell-stringify ,value)))) + (setq value `(eshell-escape-arg ,value)) + (when splice + (setq value `(eshell-splice-args ,value))) value)) (defun eshell-parse-variable-ref (&optional modifier-p) @@ -481,7 +494,7 @@ Possible variable references are: NAME an environment or Lisp variable value \"LONG-NAME\" disambiguates the length of the name - `LONG-NAME' as above + \\='LONG-NAME\\=' as above {COMMAND} result of command is variable's value (LISP-FORM) result of Lisp form is variable's value <COMMAND> write the output of command to a temporary file; @@ -574,9 +587,12 @@ Possible variable references are: (defun eshell-parse-indices () "Parse and return a list of index-lists. +This produces a series of Lisp forms to be processed by +`eshell-prepare-indices' and ultimately evaluated by +`eshell-do-eval'. For example, \"[0 1][2]\" becomes: - ((\"0\" \"1\") (\"2\")." + ((\"0\" \"1\") (\"2\"))." (let (indices) (while (eq (char-after) ?\[) (let ((end (eshell-find-delimiter ?\[ ?\]))) @@ -592,10 +608,46 @@ For example, \"[0 1][2]\" becomes: (goto-char (1+ end))))) (nreverse indices))) +(defun eshell-parse-index (index) + "Parse a single INDEX in string form. +If INDEX looks like a number, return that number. + +If INDEX looks like \"[BEGIN]..[END]\", where BEGIN and END look +like integers, return a cons cell of BEGIN and END as numbers; +BEGIN and/or END can be omitted here, in which case their value +in the cons is nil. + +Otherwise (including if INDEX is not a string), return +the original value of INDEX." + (save-match-data + (cond + ((and (stringp index) (get-text-property 0 'number index)) + (string-to-number index)) + ((and (stringp index) + (not (text-property-any 0 (length index) 'escaped t index)) + (string-match (rx string-start + (group-n 1 (? (regexp eshell-integer-regexp))) + ".." + (group-n 2 (? (regexp eshell-integer-regexp))) + string-end) + index)) + (let ((begin (match-string 1 index)) + (end (match-string 2 index))) + (cons (unless (string-empty-p begin) (string-to-number begin)) + (unless (string-empty-p end) (string-to-number end))))) + (t + index)))) + (defun eshell-eval-indices (indices) "Evaluate INDICES, a list of index-lists generated by `eshell-parse-indices'." + (declare (obsolete eshell-prepare-indices "30.1")) (mapcar (lambda (i) (mapcar #'eval i)) indices)) +(defun eshell-prepare-indices (indices) + "Prepare INDICES to be evaluated by Eshell. +INDICES is a list of index-lists generated by `eshell-parse-indices'." + `(list ,@(mapcar (lambda (idx-list) (cons 'list idx-list)) indices))) + (defun eshell-get-variable (name &optional indices quoted) "Get the value for the variable NAME. INDICES is a list of index-lists (see `eshell-parse-indices'). @@ -697,67 +749,77 @@ For example, to retrieve the second element of a user's record in '/etc/passwd', the variable reference would look like: ${grep johnw /etc/passwd}[: 2]" - (while indices - (let ((refs (car indices))) - (when (stringp value) - (let (separator (index (caar indices))) - (when (and (stringp index) - (not (get-text-property 0 'number index))) - (setq separator index - refs (cdr refs))) - (setq value (split-string value separator)) - (unless quoted - (setq value (mapcar #'eshell-convert-to-number value))))) - (cond - ((< (length refs) 0) - (error "Invalid array variable index: %s" - (eshell-stringify refs))) - ((= (length refs) 1) - (setq value (eshell-index-value value (car refs)))) - (t - (let ((new-value (list t))) - (while refs - (nconc new-value - (list (eshell-index-value value - (car refs)))) - (setq refs (cdr refs))) - (setq value (cdr new-value)))))) - (setq indices (cdr indices))) - value) + (dolist (refs indices value) + ;; For string values, check if the first index looks like a + ;; regexp, and if so, use that to split the string. + (when (stringp value) + (let (separator (first (car refs))) + (when (stringp (eshell-parse-index first)) + (setq separator first + refs (cdr refs))) + (setq value (split-string value separator)) + (unless quoted + (setq value (mapcar #'eshell-convert-to-number value))))) + (cond + ((< (length refs) 0) + (error "Invalid array variable index: %s" + (eshell-stringify refs))) + ((= (length refs) 1) + (setq value (eshell-index-value value (car refs)))) + (t + (let (new-value) + (dolist (ref refs) + (push (eshell-index-value value ref) new-value)) + (setq value (nreverse new-value))))))) + +(pcase-defmacro eshell-index-range (start end) + "A pattern that matches an Eshell index range. +EXPVAL should be a cons cell, with each slot containing either an +integer or nil. If this matches, bind the values of the sltos to +START and END." + (list '\` (cons (list '\, `(and (or (pred integerp) (pred null)) ,start)) + (list '\, `(and (or (pred integerp) (pred null)) ,end))))) (defun eshell-index-value (value index) "Reference VALUE using the given INDEX." - (when (and (stringp index) (get-text-property 0 'number index)) - (setq index (string-to-number index))) - (if (integerp index) - (cond - ((ring-p value) - (if (> index (ring-length value)) - (error "Index exceeds length of ring") - (ring-ref value index))) - ((listp value) - (if (> index (length value)) - (error "Index exceeds length of list") - (nth index value))) - ((vectorp value) - (if (> index (length value)) - (error "Index exceeds length of vector") - (aref value index))) - (t - (error "Invalid data type for indexing"))) - ;; INDEX is some non-integer value, so treat VALUE as an alist. - (cdr (assoc index value)))) + (let ((parsed-index (eshell-parse-index index))) + (if (ring-p value) + (pcase parsed-index + ((pred integerp) + (ring-ref value parsed-index)) + ((eshell-index-range start end) + (let* ((len (ring-length value)) + (real-start (mod (or start 0) len)) + (real-end (mod (or end len) len))) + (when (and (eq real-end 0) + (not (eq end 0))) + (setq real-end len)) + (ring-convert-sequence-to-ring + (seq-subseq (ring-elements value) real-start real-end)))) + (_ + (error "Invalid index for ring: %s" index))) + (pcase parsed-index + ((pred integerp) + (when (< parsed-index 0) + (setq parsed-index (+ parsed-index (length value)))) + (seq-elt value parsed-index)) + ((eshell-index-range start end) + (seq-subseq value (or start 0) end)) + (_ + ;; INDEX is some non-integer value, so treat VALUE as an alist. + (cdr (assoc parsed-index value))))))) ;;;_* Variable name completion (defun eshell-complete-variable-reference () "If there is a variable reference, complete it." - (let ((arg (pcomplete-actual-arg)) index) - (when (setq index - (string-match - (concat "\\$\\(" eshell-variable-name-regexp - "\\)?\\'") arg)) - (setq pcomplete-stub (substring arg (1+ index))) + (let ((arg (pcomplete-actual-arg))) + (when (string-match + (rx "$" (? (or "#" "@")) + (? (group (regexp eshell-variable-name-regexp))) + string-end) + arg) + (setq pcomplete-stub (substring arg (match-beginning 1))) (throw 'pcomplete-completions (eshell-variables-list))))) (defun eshell-variables-list () diff --git a/lisp/files.el b/lisp/files.el index 0d24852358e..9da82446112 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -6199,11 +6199,11 @@ instance of such commands." (rename-buffer (generate-new-buffer-name base-name)) (force-mode-line-update)))) -(defun files--ensure-directory (mkdir dir) - "Use function MKDIR to make directory DIR if it is not already a directory. +(defun files--ensure-directory (dir) + "Make directory DIR if it is not already a directory. Return non-nil if DIR is already a directory." (condition-case err - (funcall mkdir dir) + (make-directory-internal dir) (error (or (file-directory-p dir) (signal (car err) (cdr err)))))) @@ -6229,32 +6229,27 @@ Signal an error if unsuccessful." ;; If default-directory is a remote directory, ;; make sure we find its make-directory handler. (setq dir (expand-file-name dir)) - (let ((mkdir (if-let ((handler (find-file-name-handler dir 'make-directory))) - #'(lambda (dir) - ;; Use 'ignore' since the handler might be designed for - ;; Emacs 28-, so it might return an (undocumented) - ;; non-nil value, whereas the Emacs 29+ convention is - ;; to return nil here. - (ignore (funcall handler 'make-directory dir))) - #'make-directory-internal))) - (if (not parents) - (funcall mkdir dir) - (let ((dir (directory-file-name (expand-file-name dir))) - already-dir create-list parent) - (while (progn - (setq parent (directory-file-name - (file-name-directory dir))) - (condition-case () - (ignore (setq already-dir - (files--ensure-directory mkdir dir))) - (error - ;; Do not loop if root does not exist (Bug#2309). - (not (string= dir parent))))) - (setq create-list (cons dir create-list) - dir parent)) - (dolist (dir create-list) - (setq already-dir (files--ensure-directory mkdir dir))) - already-dir)))) + (let ((handler (find-file-name-handler dir 'make-directory))) + (if handler + (funcall handler 'make-directory dir parents) + (if (not parents) + (make-directory-internal dir) + (let ((dir (directory-file-name (expand-file-name dir))) + already-dir create-list parent) + (while (progn + (setq parent (directory-file-name + (file-name-directory dir))) + (condition-case () + (ignore (setq already-dir + (files--ensure-directory dir))) + (error + ;; Do not loop if root does not exist (Bug#2309). + (not (string= dir parent))))) + (setq create-list (cons dir create-list) + dir parent)) + (dolist (dir create-list) + (setq already-dir (files--ensure-directory dir))) + already-dir))))) (defun make-empty-file (filename &optional parents) "Create an empty file FILENAME. @@ -6347,6 +6342,12 @@ RECURSIVE if DIRECTORY is nonempty." directory-exists)) (files--force recursive #'delete-directory-internal directory)))))) +(defcustom remote-file-name-inhibit-delete-by-moving-to-trash nil + "Whether remote files shall be moved to the Trash. +This overrules any setting of `delete-by-moving-to-trash'." + :version "30.1" + :type 'boolean) + (defun file-equal-p (file1 file2) "Return non-nil if files FILE1 and FILE2 name the same file. If FILE1 or FILE2 does not exist, the return value is unspecified." @@ -7099,10 +7100,11 @@ specifies the list of buffers to kill, asking for approval for each one." (setq list (cdr list)))) (defun kill-matching-buffers (regexp &optional internal-too no-ask) - "Kill buffers whose name matches the specified REGEXP. -Ignores buffers whose name starts with a space, unless optional -prefix argument INTERNAL-TOO is non-nil. Asks before killing -each buffer, unless NO-ASK is non-nil." + "Kill buffers whose names match the regular expression REGEXP. +Interactively, prompt for REGEXP. +Ignores buffers whose names start with a space, unless optional +prefix argument INTERNAL-TOO(interactively, the prefix argument) +is non-nil. Asks before killing each buffer, unless NO-ASK is non-nil." (interactive "sKill buffers matching this regular expression: \nP") (dolist (buffer (buffer-list)) (let ((name (buffer-name buffer))) @@ -7111,6 +7113,17 @@ each buffer, unless NO-ASK is non-nil." (string-match regexp name)) (funcall (if no-ask 'kill-buffer 'kill-buffer-ask) buffer))))) +(defun kill-matching-buffers-no-ask (regexp &optional internal-too) + "Kill buffers whose names match the regular expression REGEXP. +Interactively, prompt for REGEXP. +Like `kill-matching-buffers', but doesn't ask for confirmation +before killing each buffer. +Ignores buffers whose names start with a space, unless the +optional argument INTERNAL-TOO (interactively, the prefix argument) +is non-nil." + (interactive "sKill buffers matching this regular expression: \nP") + (kill-matching-buffers regexp internal-too t)) + (defun rename-auto-save-file () "Adjust current buffer's auto save file name for current conditions. @@ -7656,7 +7669,7 @@ If DIR's free space cannot be obtained, this function returns nil." ;; This avoids recognizing `1 may 1997' as a date in the line: ;; -r--r--r-- 1 may 1997 1168 Oct 19 16:49 README - ;; The "[BkKMGTPEZY]?" below supports "ls -alh" output. + ;; The "[BkKMGTPEZYRQ]?" below supports "ls -alh" output. ;; For non-iso date formats, we add the ".*" in order to find ;; the last possible match. This avoids recognizing @@ -7668,8 +7681,8 @@ If DIR's free space cannot be obtained, this function returns nil." ;; parentheses: ;; -rw-r--r-- (modified) 2005-10-22 21:25 files.el ;; This is not supported yet. - (purecopy (concat "\\([0-9][BkKMGTPEZY]? " iso - "\\|.*[0-9][BkKMGTPEZY]? " + (purecopy (concat "\\([0-9][BkKMGTPEZYRQ]? " iso + "\\|.*[0-9][BkKMGTPEZYRQ]? " "\\(" western "\\|" western-comma "\\|" DD-MMM-YYYY "\\|" east-asian "\\)" "\\) +"))) diff --git a/lisp/frame.el b/lisp/frame.el index af95a047c38..fa376788eb0 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -1188,7 +1188,7 @@ e.g. (mapc \\='frame-set-background-mode (frame-list))." (defvar inhibit-frame-set-background-mode nil) -(defun frame--current-backround-mode (frame) +(defun frame--current-background-mode (frame) (let* ((frame-default-bg-mode (frame-terminal-default-bg-mode frame)) (bg-color (frame-parameter frame 'background-color)) (tty-type (tty-type frame)) @@ -1218,7 +1218,7 @@ If optional arg KEEP-FACE-SPECS is non-nil, don't recalculate face specs for the new background mode." (unless inhibit-frame-set-background-mode (let* ((bg-mode - (frame--current-backround-mode frame)) + (frame--current-background-mode frame)) (display-type (cond ((null (window-system frame)) (if (tty-display-color-p frame) 'color 'mono)) @@ -1297,7 +1297,7 @@ the `background-mode' terminal parameter." ;; :global t ;; :group 'faces ;; (when (eq dark-mode -;; (eq 'light (frame--current-backround-mode (selected-frame)))) +;; (eq 'light (frame--current-background-mode (selected-frame)))) ;; ;; FIXME: Change the face's SPEC instead? ;; (set-face-attribute 'default nil ;; :foreground (face-attribute 'default :background) @@ -3105,6 +3105,9 @@ If FRAME isn't maximized, show the title bar." frame 'undecorated (eq (alist-get 'fullscreen (frame-parameters frame)) 'maximized))) +(define-obsolete-function-alias 'frame--current-backround-mode + #'frame--current-background-mode "30.1") + (provide 'frame) ;;; frame.el ends here diff --git a/lisp/gnus/gnus-registry.el b/lisp/gnus/gnus-registry.el index 45771e7a204..d9834031b80 100644 --- a/lisp/gnus/gnus-registry.el +++ b/lisp/gnus/gnus-registry.el @@ -394,7 +394,7 @@ This is not required after changing `gnus-registry-cache-file'." (with-no-warnings (eieio-persistent-read file 'registry-db)) ;; Older EIEIO versions do not check the class name. - ('wrong-number-of-arguments + (wrong-number-of-arguments (eieio-persistent-read file))))) (gnus-message 5 "Reading Gnus registry from %s...done" file)) diff --git a/lisp/gnus/gnus-search.el b/lisp/gnus/gnus-search.el index 27c71fa6c6a..22c84bc39cf 100644 --- a/lisp/gnus/gnus-search.el +++ b/lisp/gnus/gnus-search.el @@ -1330,9 +1330,10 @@ elements are present." (1- nyear) nyear)) (setq dmonth 1)))) - (format-time-string - "%e-%b-%Y" - (encode-time 0 0 0 dday dmonth dyear)))) + (with-locale-environment "C" + (format-time-string + "%e-%b-%Y" + (encode-time 0 0 0 dday dmonth dyear))))) (cl-defmethod gnus-search-imap-handle-string ((engine gnus-search-imap) (str string)) diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el index 60ee5d82e18..6025ca7e72a 100644 --- a/lisp/gnus/mml.el +++ b/lisp/gnus/mml.el @@ -1484,10 +1484,12 @@ Ask for type, description or disposition according to (setq disposition (mml-minibuffer-read-disposition type nil file))) (mml-attach-file file type description disposition))))) -(defun mml-attach-buffer (buffer &optional type description disposition) +(defun mml-attach-buffer (buffer &optional type description disposition filename) "Attach a buffer to the outgoing MIME message. BUFFER is the name of the buffer to attach. See -`mml-attach-file' for details of operation." +`mml-attach-file' regarding TYPE, DESCRIPTION and DISPOSITION. +FILENAME is a suggested file name for the attachment should a +recipient wish to save a copy separate from the message." (interactive (let* ((buffer (read-buffer "Attach buffer: ")) (type (mml-minibuffer-read-type buffer "text/plain")) @@ -1497,9 +1499,10 @@ BUFFER is the name of the buffer to attach. See ;; If in the message header, attach at the end and leave point unchanged. (let ((head (unless (message-in-body-p) (point)))) (if head (goto-char (point-max))) - (mml-insert-empty-tag 'part 'type type 'buffer buffer - 'disposition disposition - 'description description) + (apply #'mml-insert-empty-tag + 'part 'type type 'buffer buffer + 'disposition disposition 'description description + (and filename `(filename ,filename))) ;; When using Mail mode, make sure it does the mime encoding ;; when you send the message. (or (eq mail-user-agent 'message-user-agent) diff --git a/lisp/gnus/nndiary.el b/lisp/gnus/nndiary.el index c7a75105c08..be2bdc9bb15 100644 --- a/lisp/gnus/nndiary.el +++ b/lisp/gnus/nndiary.el @@ -339,8 +339,15 @@ all. This may very well take some time.") ;; for this header) or one list (specifying all the possible values for this ;; header). In the latter case, the list does NOT include the unspecified ;; spec (*). + ;; For time zone values, we have symbolic time zone names associated with ;; the (relative) number of seconds ahead GMT. + ;; The list of time zone values is obsolescent, and new code should + ;; not rely on it. Many of the time zone abbreviations are wrong; + ;; in particular, all single-letter abbreviations other than "Z" have + ;; been wrong since Internet RFC 2822 (2001). However, the + ;; abbreviations have not been changed due to backward compatibility + ;; concerns. ) (defsubst nndiary-schedule () diff --git a/lisp/help-fns.el b/lisp/help-fns.el index a81051cee03..8bf8af73d30 100644 --- a/lisp/help-fns.el +++ b/lisp/help-fns.el @@ -2004,8 +2004,8 @@ variable with value KEYMAP." (mapatoms (lambda (symb) (when (and (boundp symb) (eq (symbol-value symb) keymap) - (not (eq symb 'keymap)) - (throw 'found-keymap symb))))) + (not (eq symb 'keymap))) + (throw 'found-keymap symb)))) nil))) ;; Follow aliasing. (or (ignore-errors (indirect-variable name)) name)))) diff --git a/lisp/image-mode.el b/lisp/image-mode.el index 1820defa195..fa28c1bf7a5 100644 --- a/lisp/image-mode.el +++ b/lisp/image-mode.el @@ -1086,7 +1086,7 @@ Otherwise, display the image by calling `image-mode'." (unwind-protect (progn (setq-local image-fit-to-window-lock t) - (ignore-error 'remote-file-error + (ignore-error remote-file-error (image-toggle-display-image))) (setq image-fit-to-window-lock nil))))))))))) diff --git a/lisp/image.el b/lisp/image.el index 29c39c5dd55..2372fd1ce09 100644 --- a/lisp/image.el +++ b/lisp/image.el @@ -444,7 +444,7 @@ type if we can't otherwise guess it." (require 'image-converter) (image-convert-p source)))))) (unless type - (signal 'unknown-image-type "Cannot determine image type"))) + (signal 'unknown-image-type '("Cannot determine image type")))) (when (and (not (eq type 'image-convert)) (not (memq type (and (boundp 'image-types) image-types)))) (error "Invalid image type `%s'" type)) diff --git a/lisp/image/exif.el b/lisp/image/exif.el index c561ea729af..50428c3a31a 100644 --- a/lisp/image/exif.el +++ b/lisp/image/exif.el @@ -151,7 +151,7 @@ If the orientation isn't present in the data, return nil." (defun exif--parse-jpeg () (unless (= (exif--read-number-be 2) #xffd8) ; SOI (start of image) - (signal 'exif-error "Not a valid JPEG file")) + (signal 'exif-error '("Not a valid JPEG file"))) (cl-loop for segment = (exif--read-number-be 2) for size = (exif--read-number-be 2) ;; Stop parsing when we get to SOS (start of stream); @@ -168,7 +168,7 @@ If the orientation isn't present in the data, return nil." ;; The Exif data is in the APP1 JPEG chunk and starts with ;; "Exif\0\0". (unless (equal (exif--read-chunk 6) (string ?E ?x ?i ?f ?\0 ?\0)) - (signal 'exif-error "Not a valid Exif chunk")) + (signal 'exif-error '("Not a valid Exif chunk"))) (delete-region (point-min) (point)) (let* ((endian-marker (exif--read-chunk 2)) (le (cond @@ -180,14 +180,15 @@ If the orientation isn't present in the data, return nil." t) (t (signal 'exif-error - (format "Invalid endian-ness %s" endian-marker)))))) + (list (format "Invalid endian-ness %s" + endian-marker))))))) ;; Another magical number. (unless (= (exif--read-number 2 le) #x002a) - (signal 'exif-error "Invalid TIFF header length")) + (signal 'exif-error '("Invalid TIFF header length"))) (let ((offset (exif--read-number 4 le))) ;; Jump to where the IFD (directory) starts and parse it. (when (> (1+ offset) (point-max)) - (signal 'exif-error "Invalid IFD (directory) offset")) + (signal 'exif-error '("Invalid IFD (directory) offset"))) (goto-char (1+ offset)) (exif--parse-directory le))))) @@ -230,7 +231,7 @@ If the orientation isn't present in the data, return nil." (when (> (+ (1+ value) length) (point-max)) (signal 'exif-error - "Premature end of file")) + '("Premature end of file"))) (buffer-substring (1+ value) (+ (1+ value) length))) @@ -248,7 +249,7 @@ If the orientation isn't present in the data, return nil." ;; keep parsing. (progn (when (> (1+ next) (point-max)) - (signal 'exif-error "Invalid IFD (directory) next-offset")) + (signal 'exif-error '("Invalid IFD (directory) next-offset"))) (goto-char (1+ next)) (nconc dir (exif--parse-directory le))) ;; We've reached the end of the directories. @@ -283,7 +284,7 @@ VALUE is an integer representing BYTES characters." (defun exif--read-chunk (bytes) "Return BYTES octets from the buffer and advance point that much." (when (> (+ (point) bytes) (point-max)) - (signal 'exif-error "Premature end of file")) + (signal 'exif-error '("Premature end of file"))) (prog1 (buffer-substring (point) (+ (point) bytes)) (forward-char bytes))) @@ -292,7 +293,7 @@ VALUE is an integer representing BYTES characters." "Read BYTES octets from the buffer as a chunk of big-endian bytes. Advance point to after the read bytes." (when (> (+ (point) bytes) (point-max)) - (signal 'exif-error "Premature end of file")) + (signal 'exif-error '("Premature end of file"))) (let ((sum 0)) (dotimes (_ bytes) (setq sum (+ (* sum 256) (following-char))) @@ -303,7 +304,7 @@ Advance point to after the read bytes." "Read BYTES octets from the buffer as a chunk of low-endian bytes. Advance point to after the read bytes." (when (> (+ (point) bytes) (point-max)) - (signal 'exif-error "Premature end of file")) + (signal 'exif-error '("Premature end of file"))) (let ((sum 0)) (dotimes (i bytes) (setq sum (+ (* (following-char) (expt 256 i)) sum)) diff --git a/lisp/ldefs-boot.el b/lisp/ldefs-boot.el index dfb076e52df..73d47804e5d 100644 --- a/lisp/ldefs-boot.el +++ b/lisp/ldefs-boot.el @@ -2021,7 +2021,7 @@ other modes. See `override-global-mode'. (fn &rest ARGS)" nil t) (autoload 'describe-personal-keybindings "bind-key" "\ Display all the personal keybindings defined by `bind-key'." t) -(register-definition-prefixes "bind-key" '("bind-key" "compare-keybindings" "get-binding-description" "override-global-m" "personal-keybindings")) +(register-definition-prefixes "bind-key" '("bind-key" "override-global-m" "personal-keybindings")) ;;; Generated autoloads from emacs-lisp/bindat.el @@ -8253,6 +8253,7 @@ Valid keywords and arguments are: `nodigits' to suppress digits as prefix arguments. (fn BS &optional NAME M ARGS)") +(make-obsolete 'easy-mmode-define-keymap 'define-keymap "29.1") (autoload 'easy-mmode-defmap "easy-mmode" "\ 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 @@ -8263,6 +8264,7 @@ 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) +(make-obsolete 'easy-mmode-defmap 'defvar-keymap "29.1") (autoload 'easy-mmode-defsyntax "easy-mmode" "\ Define variable ST as a syntax-table. CSS contains a list of syntax specifications of the form (CHAR . SYNTAX). @@ -11315,8 +11317,10 @@ For more information, see Info node `(eww) Top'. (defalias 'browse-web 'eww) (autoload 'eww-open-file "eww" "\ Render FILE using EWW. +If NEW-BUFFER is non-nil (interactively, the prefix arg), use a +new buffer instead of reusing the default EWW buffer. -(fn FILE)" t) +(fn FILE &optional NEW-BUFFER)" t) (autoload 'eww-search-words "eww" "\ Search the web for the text in the region. If region is active (and not whitespace), search the web for @@ -14402,6 +14406,8 @@ Add the window configuration CONF to `gnus-buffer-configuration'. (autoload 'go-ts-mode "go-ts-mode" "\ Major mode for editing Go, powered by tree-sitter. +\\{go-ts-mode-map} + (fn)" t) (autoload 'go-mod-ts-mode "go-ts-mode" "\ Major mode for editing go.mod files, powered by tree-sitter. @@ -16234,6 +16240,15 @@ values. (register-definition-prefixes "semantic/html" '("semantic-")) +;;; Generated autoloads from textmodes/html-ts-mode.el + +(autoload 'html-ts-mode "html-ts-mode" "\ +Major mode for editing Html, powered by tree-sitter. + +(fn)" t) +(register-definition-prefixes "html-ts-mode" '("html-ts-mode-")) + + ;;; Generated autoloads from htmlfontify.el (push (purecopy '(htmlfontify 0 21)) package--builtin-versions) @@ -23466,6 +23481,11 @@ the `Version:' header.") (defcustom package-quickstart-file (locate-user-emacs-file "package-quickstart.el") "\ Location of the file used to speed up activation of packages at startup." :type 'file :group 'applications :initialize #'custom-initialize-delay :version "27.1") (custom-autoload 'package-quickstart-file "package" t) +(autoload 'package-report-bug "package" "\ +Prepare a message to send to the maintainers of a package. +DESC must be a `package-desc' object. + +(fn DESC)" '(package-menu-mode)) (register-definition-prefixes "package" '("bad-signature" "define-package" "describe-package-1" "package-")) @@ -28317,29 +28337,17 @@ With ARG non-nil, silently save all file-visiting buffers, then kill. If emacsclient was started with a list of filenames to edit, then only these files will be asked to be saved. +When running Emacs as a daemon and with +`server-stop-automatically' (which see) set to `kill-terminal' or +`delete-frame', this function may call `save-buffers-kill-emacs' +if there are no other active clients. + (fn ARG)") (autoload 'server-stop-automatically "server" "\ -Automatically stop server as specified by ARG. - -If ARG is the symbol `empty', stop the server when it has no -remaining clients, no remaining unsaved file-visiting buffers, -and no running processes with a `query-on-exit' flag. - -If ARG is the symbol `delete-frame', ask the user when the last -frame is deleted whether each unsaved file-visiting buffer must -be saved and each running process with a `query-on-exit' flag -can be stopped, and if so, stop the server itself. +Automatically stop the Emacs server as specified by VALUE. +This sets the variable `server-stop-automatically' (which see). -If ARG is the symbol `kill-terminal', ask the user when the -terminal is killed with \\[save-buffers-kill-terminal] whether each unsaved file-visiting -buffer must be saved and each running process with a `query-on-exit' -flag can be stopped, and if so, stop the server itself. - -Any other value of ARG will cause this function to signal an error. - -This function is meant to be called from the user init file. - -(fn ARG)") +(fn VALUE)") (register-definition-prefixes "server" '("server-")) @@ -32676,7 +32684,7 @@ It must be supported by libarchive(3).") List of suffixes which indicate a compressed file. It must be supported by libarchive(3).") (defmacro tramp-archive-autoload-file-name-regexp nil "\ -Regular expression matching archive file names." (if (<= emacs-major-version 26) '(concat "\\`" "\\(" ".+" "\\." (regexp-opt tramp-archive-suffixes) "\\(?:" "\\." (regexp-opt tramp-archive-compression-suffixes) "\\)*" "\\)" "\\(" "/" ".*" "\\)" "\\'") `(rx bos (group (+ nonl) "." (| ,@tramp-archive-suffixes) (32 "." (| ,@tramp-archive-compression-suffixes))) (group "/" (* nonl)) eos))) +Regular expression matching archive file names." `(rx bos (group (+ nonl) "." (| ,@tramp-archive-suffixes) (32 "." (| ,@tramp-archive-compression-suffixes))) (group "/" (* nonl)) eos)) (defun tramp-archive-autoload-file-name-handler (operation &rest args) "\ Load Tramp archive file name handler, and perform OPERATION." (defvar tramp-archive-autoload) (let ((default-directory temporary-file-directory) (tramp-archive-autoload tramp-archive-enabled)) (apply #'tramp-autoload-file-name-handler operation args))) (defun tramp-register-archive-autoload-file-name-handler nil "\ @@ -32698,7 +32706,6 @@ Add archive file name handler to `file-name-handler-alist'." (when (and tramp-ar ;;; Generated autoloads from net/tramp-compat.el - (defalias 'tramp-compat-rx #'rx) (register-definition-prefixes "tramp-compat" '("tramp-")) @@ -32764,7 +32771,7 @@ Add archive file name handler to `file-name-handler-alist'." (when (and tramp-ar ;;; Generated autoloads from net/trampver.el -(push (purecopy '(tramp 2 6 0 29 1)) package--builtin-versions) +(push (purecopy '(tramp 2 7 0 -1)) package--builtin-versions) (register-definition-prefixes "trampver" '("tramp-")) @@ -34519,7 +34526,7 @@ revision, with SUBJECT derived from each revision subject. When invoked with a numerical prefix argument, use the last N revisions. When invoked interactively in a Log View buffer with -marked revisions, use those these. +marked revisions, use those. (fn ADDRESSEE SUBJECT REVISIONS)" t) (register-definition-prefixes "vc" '("vc-" "with-vc-properties")) @@ -34788,7 +34795,7 @@ Key bindings: ;;; Generated autoloads from progmodes/verilog-mode.el -(push (purecopy '(verilog-mode 2021 10 14 127365406)) package--builtin-versions) +(push (purecopy '(verilog-mode 2022 12 18 181110314)) package--builtin-versions) (autoload 'verilog-mode "verilog-mode" "\ Major mode for editing Verilog code. \\<verilog-mode-map> @@ -34822,6 +34829,11 @@ Variables controlling indentation/edit style: function keyword. `verilog-indent-level-directive' (default 1) Indentation of \\=`ifdef/\\=`endif blocks. + `verilog-indent-ignore-multiline-defines' (default t) + Non-nil means ignore indentation on lines that are part of a multiline + define. + `verilog-indent-ignore-regexp' (default nil + Regexp that matches lines that should be ignored for indentation. `verilog-cexp-indent' (default 1) Indentation of Verilog statements broken across lines i.e.: if (a) @@ -34845,6 +34857,9 @@ Variables controlling indentation/edit style: otherwise you get: if (a) begin + `verilog-indent-class-inside-pkg' (default t) + Non-nil means indent classes inside packages. + Otherwise, classes have zero indentation. `verilog-auto-endcomments' (default t) Non-nil means a comment /* ... */ is set after the ends which ends cases, tasks, functions and modules. @@ -34854,6 +34869,17 @@ Variables controlling indentation/edit style: will be inserted. Setting this variable to zero results in every end acquiring a comment; the default avoids too many redundant comments in tight quarters. + `verilog-align-decl-expr-comments' (default t) + Non-nil means align declaration and expressions comments. + `verilog-align-comment-distance' (default 1) + Distance (in spaces) between longest declaration and comments. + Only works if `verilog-align-decl-expr-comments' is non-nil. + `verilog-align-assign-expr' (default nil) + Non-nil means align expressions of continuous assignments. + `verilog-align-typedef-regexp' (default nil) + Regexp that matches user typedefs for declaration alignment. + `verilog-align-typedef-words' (default nil) + List of words that match user typedefs for declaration alignment. `verilog-auto-lineup' (default `declarations') List of contexts where auto lineup of code should be done. @@ -34877,17 +34903,20 @@ Some other functions are: \\[verilog-mark-defun] Mark function. \\[verilog-beg-of-defun] Move to beginning of current function. \\[verilog-end-of-defun] Move to end of current function. - \\[verilog-label-be] Label matching begin ... end, fork ... join, etc statements. + \\[verilog-label-be] Label matching begin ... end, fork ... join, etc + statements. \\[verilog-comment-region] Put marked area in a comment. - \\[verilog-uncomment-region] Uncomment an area commented with \\[verilog-comment-region]. + \\[verilog-uncomment-region] Uncomment an area commented with + \\[verilog-comment-region]. \\[verilog-insert-block] Insert begin ... end. \\[verilog-star-comment] Insert /* ... */. \\[verilog-sk-always] Insert an always @(AS) begin .. end block. \\[verilog-sk-begin] Insert a begin .. end block. \\[verilog-sk-case] Insert a case block, prompting for details. - \\[verilog-sk-for] Insert a for (...) begin .. end block, prompting for details. + \\[verilog-sk-for] Insert a for (...) begin .. end block, prompting for + details. \\[verilog-sk-generate] Insert a generate .. endgenerate block. \\[verilog-sk-header] Insert a header block at the top of file. \\[verilog-sk-initial] Insert an initial begin .. end block. @@ -34910,14 +34939,17 @@ Some other functions are: \\[verilog-sk-else-if] Insert an else if (..) begin .. end block. \\[verilog-sk-comment] Insert a comment block. \\[verilog-sk-assign] Insert an assign .. = ..; statement. - \\[verilog-sk-function] Insert a function .. begin .. end endfunction block. + \\[verilog-sk-function] Insert a function .. begin .. end endfunction + block. \\[verilog-sk-input] Insert an input declaration, prompting for details. \\[verilog-sk-output] Insert an output declaration, prompting for details. - \\[verilog-sk-state-machine] Insert a state machine definition, prompting for details. + \\[verilog-sk-state-machine] Insert a state machine definition, prompting + for details. \\[verilog-sk-inout] Insert an inout declaration, prompting for details. \\[verilog-sk-wire] Insert a wire declaration, prompting for details. \\[verilog-sk-reg] Insert a register declaration, prompting for details. - \\[verilog-sk-define-signal] Define signal under point as a register at the top of the module. + \\[verilog-sk-define-signal] Define signal under point as a register at + the top of the module. All key bindings can be seen in a Verilog-buffer with \\[describe-bindings]. Key bindings specific to `verilog-mode-map' are: @@ -36036,6 +36068,7 @@ The mode's hook is called both when the mode is enabled and when it is disabled. (fn &optional ARG)" t) +(put 'global-whitespace-mode 'globalized-minor-mode t) (defvar global-whitespace-mode nil "\ Non-nil if Global Whitespace mode is enabled. See the `global-whitespace-mode' command @@ -36045,25 +36078,18 @@ either customize it (see the info node `Easy Customization') or call the function `global-whitespace-mode'.") (custom-autoload 'global-whitespace-mode "whitespace" nil) (autoload 'global-whitespace-mode "whitespace" "\ -Toggle whitespace visualization globally (Global Whitespace mode). - -See also `whitespace-style', `whitespace-newline' and -`whitespace-display-mappings'. - -This is a global minor mode. If called interactively, toggle the -`Global Whitespace mode' mode. If the prefix argument is -positive, enable the mode, and if it is zero or negative, disable -the mode. +Toggle Whitespace mode in all buffers. +With prefix ARG, enable Global Whitespace mode if ARG is positive; +otherwise, disable it. -If called from Lisp, toggle the mode if ARG is `toggle'. Enable -the mode if ARG is nil, omitted, or is a positive number. +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 \\='global-whitespace-mode)'. +Whitespace mode is enabled in all buffers where +`whitespace-turn-on-if-enabled' would do it. -The mode's hook is called both when the mode is enabled and when -it is disabled. +See `whitespace-mode' for more information on Whitespace mode. (fn &optional ARG)" t) (defvar global-whitespace-newline-mode nil "\ diff --git a/lisp/mail/rmail.el b/lisp/mail/rmail.el index 659649b5d42..c56f4ce62dc 100644 --- a/lisp/mail/rmail.el +++ b/lisp/mail/rmail.el @@ -4580,6 +4580,9 @@ Argument MIME is non-nil if this is a mime message." (current-buffer)))) (error nil)) + ;; Decode any base64-encoded material in what we just decrypted. + (rmail-epa-decode armor-start after-end) + (list armor-start (- (point-max) after-end) mime armor-end-regexp (buffer-substring armor-start (- (point-max) after-end))))) @@ -4622,9 +4625,6 @@ Argument MIME is non-nil if this is a mime message." "> ") (push (rmail-epa-decrypt-1 mime) decrypts)))) - ;; Decode any base64-encoded mime sections. - (rmail-epa-decode) - (when (and decrypts (rmail-buffers-swapped-p)) (when (y-or-n-p "Replace the original message? ") (when (eq major-mode 'rmail-mode) @@ -4689,12 +4689,14 @@ Argument MIME is non-nil if this is a mime message." (unless decrypts (error "Nothing to decrypt"))))) -;; Decode all base64-encoded mime sections, so that this change -;; is made in the Rmail file, not just in the viewing buffer. -(defun rmail-epa-decode () +;; Decode all base64-encoded mime sections from BEG to (Z - BACK-FROM-END), +;; so that we save the decoding permanently in the Rmail buffer +;; if we permanently save the decryption. +(defun rmail-epa-decode (beg back-from-end) (save-excursion - (goto-char (point-min)) - (while (re-search-forward "--------------[0-9a-zA-Z]+\n" nil t) + (goto-char beg) + (while (re-search-forward "--------------[0-9a-zA-Z]+\n" + (- (point-max) back-from-end) t) ;; The ending delimiter is a start delimiter if another section follows. ;; Otherwise it is an end delimiter, with -- affixed. (let ((delim (concat (substring (match-string 0) 0 -1) "\\(\\|--\\)\n"))) diff --git a/lisp/mail/rmailout.el b/lisp/mail/rmailout.el index d0c0efec53b..6d61dcd8208 100644 --- a/lisp/mail/rmailout.el +++ b/lisp/mail/rmailout.el @@ -327,15 +327,14 @@ Replaces the From line with a \"Mail-from\" header. Adds \"Date\" and "Date: \\2, \\4 \\3 \\9 \\5 " ;; The timezone could be matched by group 7 or group 10. - ;; If neither of them matched, assume EST, since only - ;; Easterners would be so sloppy. + ;; If neither matched, use "-0000" for an unknown zone. ;; It's a shame the substitution can't use "\\10". (cond ((/= (match-beginning 7) (match-end 7)) "\\7") ((/= (match-beginning 10) (match-end 10)) (buffer-substring (match-beginning 10) (match-end 10))) - (t "EST")) + (t "-0000")) "\n")) ;; Keep and reformat the sender if we don't ;; have a From: field. diff --git a/lisp/mh-e/mh-identity.el b/lisp/mh-e/mh-identity.el index 502036f78b7..307c7fcf9c7 100644 --- a/lisp/mh-e/mh-identity.el +++ b/lisp/mh-e/mh-identity.el @@ -141,7 +141,7 @@ See `mh-identity-list'." (cons '("None") (mapcar #'list (mapcar #'car mh-identity-list))) nil t default nil default)) - (if (eq identity "None") + (if (equal identity "None") nil identity))) diff --git a/lisp/mouse.el b/lisp/mouse.el index d93594deb04..9c1a72bb368 100644 --- a/lisp/mouse.el +++ b/lisp/mouse.el @@ -105,6 +105,15 @@ point at the click position." :type 'boolean :version "22.1") +(defcustom mouse-1-double-click-prefer-symbols nil + "If non-nil, double-clicking Mouse-1 attempts to select the symbol at click. + +If nil, the default, double-clicking Mouse-1 on a word-constituent +character will select only the word at click location, which could +select fewer characters than the symbol at click." + :type 'boolean + :version "30.1") + (defcustom mouse-drag-and-drop-region-scroll-margin nil "If non-nil, the scroll margin inside a window when dragging text. If the mouse moves this many lines close to the top or bottom of @@ -1800,10 +1809,17 @@ The region will be defined with mark and point." ;; Commands to handle xterm-style multiple clicks. (defun mouse-skip-word (dir) "Skip over word, over whitespace, or over identical punctuation. +If `mouse-1-double-click-prefer-symbols' is non-nil, skip over symbol. If DIR is positive skip forward; if negative, skip backward." (let* ((char (following-char)) - (syntax (char-to-string (char-syntax char)))) - (cond ((string= syntax "w") + (syntax (char-to-string (char-syntax char))) + sym) + (cond ((and mouse-1-double-click-prefer-symbols + (setq sym (bounds-of-thing-at-point 'symbol))) + (goto-char (if (< dir 0) + (car sym) + (cdr sym)))) + ((string= syntax "w") ;; Here, we can't use skip-syntax-forward/backward because ;; they don't pay attention to word-separating-categories, ;; and thus they will skip over a true word boundary. So, diff --git a/lisp/net/ange-ftp.el b/lisp/net/ange-ftp.el index 4bf87c14f31..e21367135d3 100644 --- a/lisp/net/ange-ftp.el +++ b/lisp/net/ange-ftp.el @@ -3534,7 +3534,8 @@ system TYPE.") (setq file (expand-file-name file)) (let ((parsed (ange-ftp-ftp-name file))) (if parsed - (if (and delete-by-moving-to-trash trash) + (if (and delete-by-moving-to-trash trash + (not remote-file-name-inhibit-delete-by-moving-to-trash)) (move-file-to-trash file) (let* ((host (nth 0 parsed)) (user (nth 1 parsed)) @@ -4129,7 +4130,7 @@ directory, so that Emacs will know its current contents." (or (file-exists-p parent) (ange-ftp-make-directory parent parents)))) (if (file-exists-p dir) - (unless parents + (if parents t (signal 'file-already-exists (list "Cannot make directory: file already exists" dir))) @@ -4158,7 +4159,8 @@ directory, so that Emacs will know its current contents." (format "Could not make directory %s: %s" dir (cdr result)))) - (ange-ftp-add-file-entry dir t)) + (ange-ftp-add-file-entry dir t) + nil) (ange-ftp-real-make-directory dir))))) (defun ange-ftp-delete-directory (dir &optional recursive trash) @@ -4377,6 +4379,10 @@ NEWNAME should be the name to give the new compressed or uncompressed file.") ;; or return nil meaning don't make a backup. (if ange-ftp-make-backup-files (ange-ftp-real-find-backup-file-name fn))) + +(defun ange-ftp-file-user-uid () + ;; Return "don't know" value. + -1) ;;; Define the handler for special file names ;;; that causes ange-ftp to be invoked. @@ -4498,6 +4504,28 @@ NEWNAME should be the name to give the new compressed or uncompressed file.") (put 'process-file 'ange-ftp 'ange-ftp-process-file) (put 'start-file-process 'ange-ftp 'ignore) (put 'shell-command 'ange-ftp 'ange-ftp-shell-command) + +;; Do not execute system information functions. +(put 'file-system-info 'ange-ftp 'ignore) +(put 'list-system-processes 'ange-ftp 'ignore) +(put 'memory-info 'ange-ftp 'ignore) +(put 'process-attributes 'ange-ftp 'ignore) + +;; There aren't ACLs. `file-selinux-context' shall return '(nil nil +;; nil nil) if the file is nonexistent, so we let the default file +;; name handler do the job. +(put 'file-acl 'ange-ftp 'ignore) +;; (put 'file-selinux-context 'ange-ftp 'ignore) +(put 'set-file-acl 'ange-ftp 'ignore) +(put 'set-file-selinux-context 'ange-ftp 'ignore) + +;; There aren't file notifications. +(put 'file-notify-add-watch 'ange-ftp 'ignore) +(put 'file-notify-rm-watch 'ange-ftp 'ignore) +(put 'file-notify-valid-p 'ange-ftp 'ignore) + +;; Return the "don't know' value for remote user uid. +(put 'file-user-uid 'ange-ftp 'ange-ftp-file-user-uid) ;;; Define ways of getting at unmodified Emacs primitives, ;;; turning off our handler. diff --git a/lisp/net/eww.el b/lisp/net/eww.el index 859a9b44bcb..73d11c0ef52 100644 --- a/lisp/net/eww.el +++ b/lisp/net/eww.el @@ -488,14 +488,17 @@ For more information, see Info node `(eww) Top'." ;;;###autoload (defalias 'browse-web 'eww) ;;;###autoload -(defun eww-open-file (file) - "Render FILE using EWW." - (interactive "fFile: ") +(defun eww-open-file (file &optional new-buffer) + "Render FILE using EWW. +If NEW-BUFFER is non-nil (interactively, the prefix arg), use a +new buffer instead of reusing the default EWW buffer." + (interactive "fFile: \nP") (let ((url-allow-non-local-files t)) (eww (concat "file://" (and (memq system-type '(windows-nt ms-dos)) "/") - (expand-file-name file))))) + (expand-file-name file)) + new-buffer))) (defun eww--file-buffer (file) (with-current-buffer (generate-new-buffer " *eww file*") @@ -2498,10 +2501,10 @@ Otherwise, the restored buffer will contain a prompt to do so by using (when (plist-get eww-data :url) (cl-case eww-restore-desktop ((t auto) (eww (plist-get eww-data :url))) - ((zerop (buffer-size)) - (let ((inhibit-read-only t)) - (insert (substitute-command-keys - eww-restore-reload-prompt))))))) + ((nil) (when (zerop (buffer-size)) + (let ((inhibit-read-only t)) + (insert (substitute-command-keys + eww-restore-reload-prompt)))))))) ;; . (current-buffer))) diff --git a/lisp/net/gnutls.el b/lisp/net/gnutls.el index f7361f38130..36b1654222a 100644 --- a/lisp/net/gnutls.el +++ b/lisp/net/gnutls.el @@ -262,6 +262,7 @@ For the meaning of the rest of the parameters, see `gnutls-boot-parameters'." &key type hostname priority-string trustfiles crlfiles keylist min-prime-bits verify-flags verify-error verify-hostname-error + pass flags &allow-other-keys) "Return a keyword list of parameters suitable for passing to `gnutls-boot'. @@ -278,6 +279,13 @@ default. VERIFY-HOSTNAME-ERROR is a backwards compatibility option for putting `:hostname' in VERIFY-ERROR. +PASS is a string, the password of the key. It may also be nil, +for a NULL password. + +FLAGS is a list of symbols corresponding to the equivalent ORed +bitflag of the gnutls_pkcs_encrypt_flags_t enum of GnuTLS. The +empty list corresponds to the bitflag with value 0. + When VERIFY-ERROR is t or a list containing `:trustfiles', an error will be raised when the peer certificate verification fails as per GnuTLS' gnutls_certificate_verify_peers2. Otherwise, only @@ -355,6 +363,8 @@ defaults to GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT." :keylist ,keylist :verify-flags ,verify-flags :verify-error ,verify-error + :pass ,pass + :flags ,flags :callbacks nil))) (defun gnutls--get-files (files) diff --git a/lisp/net/newst-backend.el b/lisp/net/newst-backend.el index 1afcd1db3c4..a68a6bf1a24 100644 --- a/lisp/net/newst-backend.el +++ b/lisp/net/newst-backend.el @@ -1623,7 +1623,7 @@ Sat, 07 Sep 2002 00:00:01 GMT ":\\([0-9]\\{2\\}\\)" ;; second "\\(:\\([0-9]\\{2\\}\\)\\)?" - ;; zone -- fixme + ;; zone "\\(\\s-+\\(" "UT\\|GMT\\|EST\\|EDT\\|CST\\|CDT\\|MST\\|MDT\\|PST\\|PDT" "\\|\\([-+]\\)\\([0-9]\\{2\\}\\)\\([0-9]\\{2\\}\\)" @@ -1642,16 +1642,26 @@ Sat, 07 Sep 2002 00:00:01 GMT (offset-hour (read (or (match-string 14 rfc822-string) "0"))) (offset-minute (read (or (match-string 15 rfc822-string) - "0"))) - ;;FIXME - ) + "0")))) (when zone (cond ((string= sign "+") (setq hour (- hour offset-hour)) (setq minute (- minute offset-minute))) ((string= sign "-") (setq hour (+ hour offset-hour)) - (setq minute (+ minute offset-minute))))) + (setq minute (+ minute offset-minute))) + ((or (string= zone "UT") (string= zone "GMT")) + nil) + ((string= zone "EDT") + (setq hour (+ hour 4))) + ((or (string= zone "EST") (string= zone "CDT")) + (setq hour (+ hour 5))) + ((or (string= zone "CST") (string= zone "MDT")) + (setq hour (+ hour 6))) + ((or (string= zone "MST") (string= zone "PDT")) + (setq hour (+ hour 7))) + ((string= zone "PST") + (setq hour (+ hour 8))))) (condition-case error-data (let ((i 1)) (dolist (m '("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" diff --git a/lisp/net/newst-ticker.el b/lisp/net/newst-ticker.el index 5477ad946ba..064b72f02c2 100644 --- a/lisp/net/newst-ticker.el +++ b/lisp/net/newst-ticker.el @@ -44,8 +44,10 @@ "Last message that the newsticker displayed.") (defvar newsticker--scrollable-text "" "The text which is scrolled smoothly in the echo area.") +(defvar newsticker--ticker-period-timer nil + "Timer for newsticker ticker display.") (defvar newsticker--ticker-timer nil - "Timer for newsticker ticker.") + "Timer for newsticker ticker scrolling.") ;;;###autoload (defun newsticker-ticker-running-p () @@ -77,7 +79,7 @@ value effective." (defcustom newsticker-ticker-interval 0.3 - "Time interval for displaying news items in the echo area (seconds). + "Time interval for scrolling news items in the echo area (seconds). If equal or less than 0 no messages are shown in the echo area. For smooth display (see `newsticker-scroll-smoothly') a value of 0.3 seems reasonable. For non-smooth display a value of 10 is a good starting @@ -86,6 +88,17 @@ point." :set #'newsticker--set-customvar-ticker :group 'newsticker-ticker) +(defcustom newsticker-ticker-period + 0 + "Time interval for displaying news items in the echo area (seconds). +If equal or less than 0 messages are shown continuously. In order not +to miss new items, a value of equal or less than the shortest feed +retrieval interval (or the global `newsticker-retrieval-interval`) is +recommended." + :type 'number + :set #'newsticker--set-customvar-ticker + :group 'newsticker-ticker) + (defcustom newsticker-scroll-smoothly t "Decides whether to flash or scroll news items. @@ -129,9 +142,16 @@ If t the echo area will not show obsolete items. See also "Called from the display timer. This function calls a display function, according to the variable `newsticker-scroll-smoothly'." - (if newsticker-scroll-smoothly - (newsticker--display-scroll) - (newsticker--display-jump))) + (when (not newsticker--ticker-timer) + (if newsticker-scroll-smoothly + (setq newsticker--ticker-timer + (run-at-time 1 + newsticker-ticker-interval + #'newsticker--display-scroll)) + (setq newsticker--ticker-timer + (run-at-time nil + newsticker-ticker-interval + #'newsticker--display-jump))))) (defsubst newsticker--echo-area-clean-p () "Check whether somebody is using the echo area / minibuffer. @@ -149,7 +169,12 @@ there is another message displayed or the minibuffer is active." (when (newsticker--echo-area-clean-p) (setq newsticker--item-position (1+ newsticker--item-position)) (when (>= newsticker--item-position (length newsticker--item-list)) - (setq newsticker--item-position 0)) + (setq newsticker--item-position 0) + (when (> newsticker-ticker-period 0) + (cancel-timer newsticker--ticker-timer) + (setq newsticker--ticker-timer nil) + (run-at-time newsticker-ticker-interval nil + (lambda () (message ""))))) (setq newsticker--prev-message (nth newsticker--item-position newsticker--item-list)) (message "%s" newsticker--prev-message)))) @@ -192,7 +217,12 @@ there is another message displayed or the minibuffer is active." (setq newsticker--prev-message subtext) (setq newsticker--item-position (1+ i)) (when (>= newsticker--item-position l) - (setq newsticker--item-position 0)))))) + (setq newsticker--item-position 0) + (when (> newsticker-ticker-period 0) + (cancel-timer newsticker--ticker-timer) + (setq newsticker--ticker-timer nil) + (run-at-time newsticker-ticker-interval nil + (lambda () (message ""))))))))) ;;;###autoload (defun newsticker-start-ticker () @@ -200,19 +230,26 @@ there is another message displayed or the minibuffer is active." Start display timer for the actual ticker if wanted and not running already." (interactive) - (if (and (> newsticker-ticker-interval 0) - (not newsticker--ticker-timer)) - (setq newsticker--ticker-timer - (run-at-time newsticker-ticker-interval - newsticker-ticker-interval - #'newsticker--display-tick)))) + (when (and (> newsticker-ticker-interval 0) + (not newsticker--ticker-period-timer) + (not newsticker--ticker-timer)) + (if (> newsticker-ticker-period 0) + (setq newsticker--ticker-period-timer + (run-at-time nil + newsticker-ticker-period + #'newsticker--display-tick)) + (newsticker--display-tick)))) (defun newsticker-stop-ticker () "Stop newsticker's ticker (but not the news retrieval)." (interactive) - (when newsticker--ticker-timer - (cancel-timer newsticker--ticker-timer) - (setq newsticker--ticker-timer nil))) + (progn + (when newsticker--ticker-timer + (cancel-timer newsticker--ticker-timer) + (setq newsticker--ticker-timer nil)) + (when newsticker--ticker-period-timer + (cancel-timer newsticker--ticker-period-timer) + (setq newsticker--ticker-period-timer nil)))) ;; ====================================================================== ;;; Manipulation of ticker text diff --git a/lisp/net/rcirc.el b/lisp/net/rcirc.el index 97a314eb8ab..5e4aa5e1198 100644 --- a/lisp/net/rcirc.el +++ b/lisp/net/rcirc.el @@ -1396,10 +1396,10 @@ inserted." (interactive "P") (rcirc-format "\^_" replace)) -(defun rcirc-format-strike-trough (replace) - "Insert strike-trough formatting. +(defun rcirc-format-strike-through (replace) + "Insert strike-through formatting. If REPLACE is non-nil or a prefix argument is given, any prior -formatting will be replaced before the strike-trough formatting +formatting will be replaced before the strike-through formatting is inserted." (interactive "P") (rcirc-format "\^^" replace)) @@ -1421,7 +1421,7 @@ inserted." "C-c C-f C-b" #'rcirc-format-bold "C-c C-f C-i" #'rcirc-format-italic "C-c C-f C-u" #'rcirc-format-underline - "C-c C-f C-s" #'rcirc-format-strike-trough + "C-c C-f C-s" #'rcirc-format-strike-through "C-c C-f C-f" #'rcirc-format-fixed-width "C-c C-f C-t" #'rcirc-format-fixed-width ;as in AucTeX "C-c C-f C-d" #'rcirc-unformat @@ -1807,7 +1807,7 @@ extracted." "C-c C-f C-b" #'rcirc-format-bold "C-c C-f C-i" #'rcirc-format-italic "C-c C-f C-u" #'rcirc-format-underline - "C-c C-f C-s" #'rcirc-format-strike-trough + "C-c C-f C-s" #'rcirc-format-strike-through "C-c C-f C-f" #'rcirc-format-fixed-width "C-c C-f C-t" #'rcirc-format-fixed-width ;as in AucTeX "C-c C-f C-d" #'rcirc-unformat @@ -2370,9 +2370,11 @@ This function does not alter the INPUT string." "C-c C-@" #'rcirc-next-active-buffer "C-c C-SPC" #'rcirc-next-active-buffer) -(defcustom rcirc-track-abbrevate-flag t +(define-obsolete-variable-alias 'rcirc-track-abbrevate-flag + 'rcirc-track-abbreviate-flag "30.1") +(defcustom rcirc-track-abbreviate-flag t "Non-nil means `rcirc-track-minor-mode' should abbreviate names." - :version "28.1" + :version "30.1" :type 'boolean) ;;;###autoload @@ -2558,7 +2560,7 @@ activity. Only run if the buffer is not visible and (funcall rcirc-channel-filter (replace-regexp-in-string "@.*?\\'" "" - (or (and rcirc-track-abbrevate-flag + (or (and rcirc-track-abbreviate-flag rcirc-short-buffer-name) (buffer-name)))))) @@ -4001,6 +4003,9 @@ PROCESS is the process object for the current connection." (string-equal (downcase (car setting)) parameter)) return (cadr setting))) +(define-obsolete-function-alias 'rcirc-format-strike-trough + 'rcirc-format-strike-through "30.1") + (provide 'rcirc) ;;; rcirc.el ends here diff --git a/lisp/net/sieve-manage.el b/lisp/net/sieve-manage.el index 4866f788bff..5bee4f4c4ad 100644 --- a/lisp/net/sieve-manage.el +++ b/lisp/net/sieve-manage.el @@ -168,25 +168,19 @@ Valid states are `closed', `initial', `nonauth', and `auth'.") ;; Internal utility functions (defun sieve-manage--append-to-log (&rest args) - "Append ARGS to `sieve-manage-log' buffer. + "Append ARGS to sieve-manage log buffer. ARGS can be a string or a list of strings. -The buffer to use for logging is specifified via `sieve-manage-log'. -If it is nil, logging is disabled. - -When the `sieve-manage-log' buffer doesn't exist, it gets created (and -configured with some initial settings)." +The buffer to use for logging is specifified via +`sieve-manage-log'. If it is nil, logging is disabled." (when sieve-manage-log - (let* ((existing-log-buffer (get-buffer sieve-manage-log)) - (log-buffer (or existing-log-buffer - (get-buffer-create sieve-manage-log)))) - (with-current-buffer log-buffer - (unless existing-log-buffer - ;; Do this only once, when creating the log buffer. - (set-buffer-multibyte nil) - (buffer-disable-undo)) - (goto-char (point-max)) - (apply #'insert args))))) + (with-current-buffer (or (get-buffer sieve-manage-log) + (with-current-buffer + (get-buffer-create sieve-manage-log) + (set-buffer-multibyte nil) + (buffer-disable-undo))) + (goto-char (point-max)) + (apply #'insert args)))) (defun sieve-manage--message (format-string &rest args) "Wrapper around `message' which also logs to sieve manage log. diff --git a/lisp/net/soap-client.el b/lisp/net/soap-client.el index 73974f864b3..e4b8bbd9cb5 100644 --- a/lisp/net/soap-client.el +++ b/lisp/net/soap-client.el @@ -1317,7 +1317,7 @@ See also `soap-wsdl-resolve-references'." "Validate VALUE against the basic type TYPE." (let* ((kind (soap-xs-basic-type-kind type))) (cl-case kind - ((anyType Array byte[]) + ((anyType Array byte\[\]) value) (t (let ((convert (get kind 'rng-xsd-convert))) diff --git a/lisp/net/tramp-adb.el b/lisp/net/tramp-adb.el index 4578f1fe073..38fd8a4e258 100644 --- a/lisp/net/tramp-adb.el +++ b/lisp/net/tramp-adb.el @@ -55,7 +55,7 @@ It is used for TCP/IP devices." (defconst tramp-adb-method "adb" "When this method name is used, forward all calls to Android Debug Bridge.") -(defcustom tramp-adb-prompt (rx bol (* (not (any "#$\n\r"))) (any "#$") blank) +(defcustom tramp-adb-prompt (rx bol (* (not (any "#$\r\n"))) (any "#$") blank) "Regexp used as prompt in almquist shell." :type 'regexp :version "28.1" @@ -71,14 +71,14 @@ It is used for TCP/IP devices." "Regexp for date time format in ls output.")) (defconst tramp-adb-ls-date-regexp - (tramp-compat-rx + (rx blank (regexp tramp-adb-ls-date-year-regexp) blank (regexp tramp-adb-ls-date-time-regexp) blank) "Regexp for date format in ls output.") (defconst tramp-adb-ls-toolbox-regexp - (tramp-compat-rx + (rx bol (* blank) (group (+ (any ".-" alpha))) ; \1 permissions (? (+ blank) (+ digit)) ; links (Android 7/toybox) (* blank) (group (+ (not blank))) ; \2 username @@ -153,6 +153,7 @@ It is used for TCP/IP devices." (file-symlink-p . tramp-handle-file-symlink-p) (file-system-info . tramp-adb-handle-file-system-info) (file-truename . tramp-handle-file-truename) + (file-user-uid . tramp-handle-file-user-uid) (file-writable-p . tramp-adb-handle-file-writable-p) (find-backup-file-name . tramp-handle-find-backup-file-name) ;; `get-file-buffer' performed by default handler. @@ -327,8 +328,7 @@ arguments to pass to the OPERATION." (tramp-shell-quote-argument (tramp-compat-file-name-concat localname "..")))) (tramp-compat-replace-regexp-in-region - (tramp-compat-rx (literal (tramp-compat-file-name-unquote - (file-name-as-directory localname)))) + (rx (literal (file-name-unquote (file-name-as-directory localname)))) "" (point-min)) (widen))) (tramp-adb-sh-fix-ls-output) @@ -366,14 +366,12 @@ Emacs dired can't find files." (goto-char (point-min)) (while (search-forward-regexp - (tramp-compat-rx - blank (group blank (regexp tramp-adb-ls-date-year-regexp) blank)) + (rx blank (group blank (regexp tramp-adb-ls-date-year-regexp) blank)) nil t) (replace-match "0\\1" "\\1" nil) ;; Insert missing "/". (when (looking-at-p - (tramp-compat-rx - (regexp tramp-adb-ls-date-time-regexp) (+ blank) eol)) + (rx (regexp tramp-adb-ls-date-time-regexp) (+ blank) eol)) (end-of-line) (insert "/"))) ;; Sort entries. @@ -393,12 +391,10 @@ Emacs dired can't find files." (defun tramp-adb-ls-output-time-less-p (a b) "Sort \"ls\" output by time, descending." (let (time-a time-b) - ;; Once we can assume Emacs 27 or later, the two calls - ;; (apply #'encode-time X) can be replaced by (encode-time X). (string-match tramp-adb-ls-date-regexp a) - (setq time-a (apply #'encode-time (parse-time-string (match-string 0 a)))) + (setq time-a (encode-time (parse-time-string (match-string 0 a)))) (string-match tramp-adb-ls-date-regexp b) - (setq time-b (apply #'encode-time (parse-time-string (match-string 0 b)))) + (setq time-b (encode-time (parse-time-string (match-string 0 b)))) (time-less-p time-b time-a))) (defun tramp-adb-ls-output-name-less-p (a b) @@ -411,20 +407,11 @@ Emacs dired can't find files." (defun tramp-adb-handle-make-directory (dir &optional parents) "Like `make-directory' for Tramp files." - (setq dir (expand-file-name dir)) - (with-parsed-tramp-file-name dir nil - (when (and (null parents) (file-exists-p dir)) - (tramp-error v 'file-already-exists dir)) - (when parents - (let ((par (expand-file-name ".." dir))) - (unless (file-directory-p par) - (make-directory par parents)))) - (tramp-flush-directory-properties v localname) - (unless (or (tramp-adb-send-command-and-check - v (format "mkdir -m %#o %s" - (default-file-modes) - (tramp-shell-quote-argument localname))) - (and parents (file-directory-p dir))) + (tramp-skeleton-make-directory dir parents + (unless (tramp-adb-send-command-and-check + v (format "mkdir -m %#o %s" + (default-file-modes) + (tramp-shell-quote-argument localname))) (tramp-error v 'file-error "Couldn't make directory %s" dir)))) (defun tramp-adb-handle-delete-directory (directory &optional recursive trash) @@ -438,14 +425,10 @@ Emacs dired can't find files." (defun tramp-adb-handle-delete-file (filename &optional trash) "Like `delete-file' for Tramp files." - (setq filename (expand-file-name filename)) - (with-parsed-tramp-file-name filename nil - (tramp-flush-file-properties v localname) - (if (and delete-by-moving-to-trash trash) - (move-file-to-trash filename) - (tramp-adb-barf-unless-okay - v (format "rm %s" (tramp-shell-quote-argument localname)) - "Couldn't delete %s" filename)))) + (tramp-skeleton-delete-file filename trash + (tramp-adb-barf-unless-okay + v (format "rm %s" (tramp-shell-quote-argument localname)) + "Couldn't delete %s" filename))) (defun tramp-adb-handle-file-name-all-completions (filename directory) "Like `file-name-all-completions' for Tramp files." @@ -483,7 +466,7 @@ Emacs dired can't find files." ;; "adb pull ..." does not always return an error code. (unless (and (tramp-adb-execute-adb-command - v "pull" (tramp-compat-file-name-unquote localname) tmpfile) + v "pull" (file-name-unquote localname) tmpfile) (file-exists-p tmpfile)) (ignore-errors (delete-file tmpfile)) (tramp-error @@ -563,8 +546,7 @@ Emacs dired can't find files." "Moving tmp file `%s' to `%s'" tmpfile filename) (unwind-protect (unless (tramp-adb-execute-adb-command - v "push" tmpfile - (tramp-compat-file-name-unquote localname)) + v "push" tmpfile (file-name-unquote localname)) (tramp-error v 'file-error "Cannot write: `%s'" filename)) (delete-file tmpfile))))))) @@ -579,11 +561,7 @@ Emacs dired can't find files." (defun tramp-adb-handle-set-file-times (filename &optional time flag) "Like `set-file-times' for Tramp files." (tramp-skeleton-set-file-modes-times-uid-gid filename - (let ((time (if (or (null time) - (tramp-compat-time-equal-p time tramp-time-doesnt-exist) - (tramp-compat-time-equal-p time tramp-time-dont-know)) - (current-time) - time)) + (let ((time (tramp-defined-time time)) (nofollow (if (eq flag 'nofollow) "-h" "")) (quoted-name (tramp-shell-quote-argument localname))) ;; Older versions of toybox 'touch' mishandle nanoseconds and/or @@ -669,8 +647,8 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (tramp-flush-file-properties v localname) (unless (tramp-adb-execute-adb-command v "push" - (tramp-compat-file-name-unquote filename) - (tramp-compat-file-name-unquote localname)) + (file-name-unquote filename) + (file-name-unquote localname)) (tramp-error v 'file-error "Cannot copy `%s' `%s'" filename newname))))))))) @@ -736,11 +714,6 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." "Strings to return by `process-file' in case of signals." (with-tramp-connection-property vec "signal-strings" (let ((default-directory (tramp-make-tramp-file-name vec 'noloc)) - ;; `shell-file-name' and `shell-command-switch' are needed - ;; for Emacs < 27.1, which doesn't support connection-local - ;; variables in `shell-command'. - (shell-file-name "/system/bin/sh") - (shell-command-switch "-c") process-file-return-signal-string signals result) (dotimes (i 128) (push (format "Signal %d" i) result)) (setq result (reverse result) @@ -773,7 +746,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." ;; Determine input. (if (null infile) (setq input (tramp-get-remote-null-device v)) - (setq infile (tramp-compat-file-name-unquote (expand-file-name infile))) + (setq infile (file-name-unquote (expand-file-name infile))) (if (tramp-equal-remote default-directory infile) ;; INFILE is on the same remote host. (setq input (tramp-unquote-file-local-name infile)) @@ -949,7 +922,7 @@ implementation will be used." (i 0) p) - (when (string-match-p (tramp-compat-rx multibyte) command) + (when (string-match-p (rx multibyte) command) (tramp-error v 'file-error "Cannot apply multi-byte command `%s'" command)) @@ -1032,17 +1005,19 @@ implementation will be used." ;; file will exist until the process is ;; deleted. (when (bufferp stderr) - (with-current-buffer stderr - (insert-file-contents-literally - remote-tmpstderr 'visit)) + (ignore-errors + (with-current-buffer stderr + (insert-file-contents-literally + remote-tmpstderr 'visit))) ;; Delete tmpstderr file. (add-function :after (process-sentinel p) (lambda (_proc _msg) - (with-current-buffer stderr - (insert-file-contents-literally - remote-tmpstderr 'visit nil nil 'replace)) - (delete-file remote-tmpstderr)))) + (ignore-errors + (with-current-buffer stderr + (insert-file-contents-literally + remote-tmpstderr 'visit nil nil 'replace)) + (delete-file remote-tmpstderr))))) ;; Return process. p)))) @@ -1106,11 +1081,12 @@ E.g. a host name \"192.168.1.1#5555\" returns \"192.168.1.1:5555\" (format "%s:%s" host port)) ;; An empty host name shall be mapped as well, when there ;; is exactly one entry in `devices'. - ((and (zerop (length host)) (= (length devices) 1)) + ((and (tramp-string-empty-or-nil-p host) + (tramp-compat-length= devices 1)) (car devices)) ;; Try to connect device. ((and tramp-adb-connect-if-not-connected - (not (zerop (length host))) + (tramp-compat-length> host 0) (tramp-adb-execute-adb-command vec "connect" (tramp-compat-string-replace @@ -1127,7 +1103,7 @@ E.g. a host name \"192.168.1.1#5555\" returns \"192.168.1.1:5555\" "Execute an adb command. Insert the result into the connection buffer. Return nil on error and non-nil on success." - (when (and (> (length (tramp-file-name-host vec)) 0) + (when (and (tramp-compat-length> (tramp-file-name-host vec) 0) ;; The -s switch is only available for ADB device commands. (not (member (car args) '("connect" "disconnect")))) (setq args (append (list "-s" (tramp-adb-get-device vec)) args))) @@ -1141,7 +1117,7 @@ error and non-nil on success." (defun tramp-adb-send-command (vec command &optional neveropen nooutput) "Send the COMMAND to connection VEC." - (if (string-match-p (tramp-compat-rx multibyte) command) + (if (string-match-p (rx multibyte) command) ;; Multibyte codepoints with four bytes are not supported at ;; least by toybox. @@ -1165,7 +1141,7 @@ error and non-nil on success." ;; We can't use stty to disable echo of command. stty is said ;; to be added to toybox 0.7.6. busybox shall have it, but this ;; isn't used any longer for Android. - (delete-matching-lines (tramp-compat-rx bol (literal command) eol)) + (delete-matching-lines (rx bol (literal command) eol)) ;; When the local machine is W32, there are still trailing ^M. ;; There must be a better solution by setting the correct coding ;; system, but this requires changes in core Tramp. @@ -1254,7 +1230,7 @@ connection if a previous connection has died for some reason." (unless (process-live-p p) (save-match-data (when (and p (processp p)) (delete-process p)) - (if (zerop (length device)) + (if (tramp-string-empty-or-nil-p device) (tramp-error vec 'file-error "Device %s not connected" host)) (with-tramp-progress-reporter vec 3 "Opening adb shell connection" (let* ((coding-system-for-read 'utf-8-dos) ; Is this correct? @@ -1288,7 +1264,7 @@ connection if a previous connection has died for some reason." ;; Change prompt. (tramp-set-connection-property - p "prompt" (tramp-compat-rx "///" (literal prompt) "#$")) + p "prompt" (rx "///" (literal prompt) "#$")) (tramp-adb-send-command vec (format "PS1=\"///\"\"%s\"\"#$\"" prompt)) diff --git a/lisp/net/tramp-archive.el b/lisp/net/tramp-archive.el index 36992014e13..97adb36c4af 100644 --- a/lisp/net/tramp-archive.el +++ b/lisp/net/tramp-archive.el @@ -110,12 +110,7 @@ ;;; Code: (eval-when-compile (require 'cl-lib)) -;; Sometimes, compilation fails with "Variable binding depth exceeds -;; max-specpdl-size". Shall be fixed in Emacs 27. -(with-no-warnings ;; max-specpdl-size - (eval-and-compile - (let ((max-specpdl-size (* 2 max-specpdl-size))) - (require 'tramp-gvfs)))) +(require 'tramp-gvfs) (autoload 'dired-uncache "dired") (autoload 'url-tramp-convert-url-to-tramp "url-tramp") @@ -183,20 +178,9 @@ It must be supported by libarchive(3).") ;; The definition of `tramp-archive-file-name-regexp' contains calls ;; to `regexp-opt', which cannot be autoloaded while loading ;; loaddefs.el. So we use a macro, which is evaluated only when needed. -;; Emacs 26 and earlier cannot use the autoload form -;; `tramp-compat-rx'. So we refrain from using `rx'. ;;;###autoload (progn (defmacro tramp-archive-autoload-file-name-regexp () "Regular expression matching archive file names." - (if (<= emacs-major-version 26) - '(concat - "\\`" "\\(" ".+" "\\." - ;; Default suffixes ... - (regexp-opt tramp-archive-suffixes) - ;; ... with compression. - "\\(?:" "\\." (regexp-opt tramp-archive-compression-suffixes) "\\)*" - "\\)" ;; \1 - "\\(" "/" ".*" "\\)" "\\'") ;; \2 `(rx bos ;; This group is used in `tramp-archive-file-name-archive'. @@ -208,13 +192,10 @@ It must be supported by libarchive(3).") (? "." (| ,@tramp-archive-compression-suffixes))) ;; This group is used in `tramp-archive-file-name-localname'. (group "/" (* nonl)) - eos)))) + eos))) (put #'tramp-archive-autoload-file-name-regexp 'tramp-autoload t) -;; In older Emacs (prior 27.1), `tramp-archive-autoload-file-name-regexp' -;; is not autoloaded. So we cannot expect it to be known in -;; tramp-loaddefs.el. But it exists, when tramp-archive.el is loaded. ;; We must wrap it into `eval-when-compile'. Otherwise, there could ;; be an "Eager macro-expansion failure" when unloading/reloading Tramp. ;;;###tramp-autoload @@ -222,11 +203,6 @@ It must be supported by libarchive(3).") (eval-when-compile (ignore-errors (tramp-archive-autoload-file-name-regexp))) "Regular expression matching archive file names.") -;; The value above is nil for Emacs 26. Set it now. -(if (<= emacs-major-version 26) - (setq tramp-archive-file-name-regexp - (ignore-errors (tramp-archive-autoload-file-name-regexp)))) - ;;;###tramp-autoload (defconst tramp-archive-method "archive" "Method name for archives in GVFS.") @@ -289,6 +265,7 @@ It must be supported by libarchive(3).") (file-symlink-p . tramp-handle-file-symlink-p) (file-system-info . tramp-archive-handle-file-system-info) (file-truename . tramp-archive-handle-file-truename) + (file-user-uid . tramp-archive-handle-file-user-uid) (file-writable-p . ignore) (find-backup-file-name . ignore) ;; `get-file-buffer' performed by default handler. @@ -299,7 +276,7 @@ It must be supported by libarchive(3).") (lock-file . ignore) (make-auto-save-file-name . ignore) (make-directory . tramp-archive-handle-not-implemented) - (make-directory-internal . tramp-archive-handle-not-implemented) + (make-directory-internal . ignore) (make-lock-file-name . ignore) (make-nearby-temp-file . tramp-handle-make-nearby-temp-file) (make-process . ignore) @@ -360,13 +337,9 @@ arguments to pass to the OPERATION." (tramp-register-file-name-handlers) (tramp-archive-run-real-handler operation args)) - (with-no-warnings ;; max-specpdl-size (let* ((filename (apply #'tramp-archive-file-name-for-operation operation args)) - (archive (tramp-archive-file-name-archive filename)) - ;; Sometimes, it fails with "Variable binding depth exceeds - ;; max-specpdl-size". Shall be fixed in Emacs 27. - (max-specpdl-size (* 2 max-specpdl-size))) + (archive (tramp-archive-file-name-archive filename))) ;; `filename' could be a quoted file name. Or the file ;; archive could be a directory, see Bug#30293. @@ -394,7 +367,7 @@ arguments to pass to the OPERATION." (setq args (cons operation args))) (if fn (save-match-data (apply (cdr fn) args)) - (tramp-archive-run-real-handler operation args)))))))) + (tramp-archive-run-real-handler operation args))))))) ;;;###autoload (progn (defun tramp-archive-autoload-file-name-handler (operation &rest args) @@ -432,10 +405,6 @@ arguments to pass to the OPERATION." (remove-hook 'after-init-hook #'tramp-register-archive-autoload-file-name-handler)))) -;; In older Emacsen (prior 27.1), the autoload above does not exist. -;; So we call it again; it doesn't hurt. -(tramp-register-archive-autoload-file-name-handler) - ;; Mark `operations' the handler is responsible for. (put #'tramp-archive-file-name-handler 'operations (mapcar #'car tramp-archive-file-name-handler-alist)) @@ -458,7 +427,7 @@ arguments to pass to the OPERATION." "Return t if NAME is a string with archive file name syntax." (and (stringp name) ;; `tramp-archive-file-name-regexp' does not suppress quoted file names. - (not (tramp-compat-file-name-quoted-p name t)) + (not (file-name-quoted-p name t)) ;; We cannot use `string-match-p', the matches are used. (string-match tramp-archive-file-name-regexp name) t)) @@ -511,7 +480,6 @@ name is kept in slot `hop'" ;; http://... ((and url-handler-mode - tramp-compat-use-url-tramp-p (string-match-p url-handler-regexp archive) (string-match-p "https?" (url-type (url-generic-parse-url archive)))) @@ -631,7 +599,7 @@ offered." (defun tramp-archive-handle-directory-file-name (directory) "Like `directory-file-name' for file archives." (with-parsed-tramp-archive-file-name directory nil - (if (and (not (zerop (length localname))) + (if (and (tramp-compat-length> localname 0) (eq (aref localname (1- (length localname))) ?/) (not (string= localname "/"))) (substring directory 0 -1) @@ -643,23 +611,22 @@ offered." (defun tramp-archive-handle-directory-files (directory &optional full match nosort count) "Like `directory-files' for Tramp files." - (unless (file-exists-p directory) - (tramp-error (tramp-dissect-file-name directory) 'file-missing directory)) - (when (file-directory-p directory) - (setq directory (file-name-as-directory (expand-file-name directory))) - (let ((temp (nreverse (file-name-all-completions "" directory))) - result item) - - (while temp - (setq item (directory-file-name (pop temp))) - (when (or (null match) (string-match-p match item)) - (push (if full (concat directory item) item) - result))) - (unless nosort - (setq result (sort result #'string<))) - (when (and (natnump count) (> count 0)) - (setq result (tramp-compat-ntake count result))) - result))) + (tramp-barf-if-file-missing (tramp-dissect-file-name directory) directory + (when (file-directory-p directory) + (setq directory (file-name-as-directory (expand-file-name directory))) + (let ((temp (nreverse (file-name-all-completions "" directory))) + result item) + + (while temp + (setq item (directory-file-name (pop temp))) + (when (or (null match) (string-match-p match item)) + (push (if full (concat directory item) item) + result))) + (unless nosort + (setq result (sort result #'string<))) + (when (and (natnump count) (> count 0)) + (setq result (tramp-compat-ntake count result))) + result)))) (defun tramp-archive-handle-dired-uncache (dir) "Like `dired-uncache' for file archives." @@ -702,6 +669,13 @@ offered." (setq local (expand-file-name local (file-name-directory localname)))) (concat (file-truename archive) local)))) +(defun tramp-archive-handle-file-user-uid () + "Like `user-uid' for file archives." + (with-parsed-tramp-archive-file-name default-directory nil + (let ((default-directory (file-name-directory archive))) + ;; `file-user-uid' exists since Emacs 30.1. + (tramp-compat-funcall 'file-user-uid)))) + (defun tramp-archive-handle-insert-directory (filename switches &optional wildcard full-directory-p) "Like `insert-directory' for file archives." diff --git a/lisp/net/tramp-cache.el b/lisp/net/tramp-cache.el index 09e43a99039..c5864e7fa5e 100644 --- a/lisp/net/tramp-cache.el +++ b/lisp/net/tramp-cache.el @@ -267,8 +267,7 @@ Return VALUE." (defun tramp-flush-directory-properties (key directory) "Remove all properties of DIRECTORY in the cache context of KEY. Remove also properties of all files in subdirectories." - (let* ((directory - (directory-file-name (tramp-compat-file-name-unquote directory))) + (let* ((directory (directory-file-name (file-name-unquote directory))) (truename (tramp-get-file-property key directory "file-truename"))) (tramp-message key 8 "%s" directory) (dolist (key (hash-table-keys tramp-cache-data)) @@ -677,4 +676,8 @@ for all methods. Resulting data are derived from connection history." (provide 'tramp-cache) +;;; TODO: +;; +;; * Use multisession.el, starting with Emacs 29.1. + ;;; tramp-cache.el ends here diff --git a/lisp/net/tramp-cmds.el b/lisp/net/tramp-cmds.el index bf7d45d2a5a..6627ef47ee2 100644 --- a/lisp/net/tramp-cmds.el +++ b/lisp/net/tramp-cmds.el @@ -127,7 +127,7 @@ When called interactively, a Tramp connection has to be selected." (or (not keep-processes) (eq key (tramp-get-process vec)))) (tramp-flush-connection-properties key) - (delete-process key))) + (ignore-errors (delete-process key)))) ;; Remove buffers. (dolist @@ -359,7 +359,7 @@ The remote connection identified by SOURCE is flushed by (dir (tramp-rename-read-file-name-dir default)) (init (tramp-rename-read-file-name-init default)) (tramp-ignored-file-name-regexp - (tramp-compat-rx (literal (file-remote-p source))))) + (rx (literal (file-remote-p source))))) (read-file-name-default "Enter new Tramp connection: " dir default 'confirm init #'file-directory-p))))) @@ -470,7 +470,7 @@ For details, see `tramp-rename-files'." (dir (tramp-rename-read-file-name-dir default)) (init (tramp-rename-read-file-name-init default)) (tramp-ignored-file-name-regexp - (tramp-compat-rx (literal (file-remote-p source))))) + (rx (literal (file-remote-p source))))) (read-file-name-default (format "Change Tramp connection `%s': " source) dir default 'confirm init #'file-directory-p))))) @@ -625,7 +625,7 @@ buffer in your bug report. (unless (hash-table-p val) ;; Remove string quotation. (when (looking-at - (tramp-compat-rx + (rx bol (group (* anychar)) "\"" ;; \1 " (group "(base64-decode-string ") "\\" ;; \2 \ (group "\"" (* anychar)) "\\" ;; \3 \ diff --git a/lisp/net/tramp-compat.el b/lisp/net/tramp-compat.el index f176476a73a..01f1c38988c 100644 --- a/lisp/net/tramp-compat.el +++ b/lisp/net/tramp-compat.el @@ -23,9 +23,9 @@ ;;; Commentary: -;; Tramp's main Emacs version for development is Emacs 29. This -;; package provides compatibility functions for Emacs 26, Emacs 27 and -;; Emacs 28. +;; Tramp's main Emacs version for development is Emacs 30. This +;; package provides compatibility functions for Emacs 27, Emacs 28 and +;; Emacs 29. ;;; Code: @@ -36,9 +36,7 @@ (require 'shell) (require 'subr-x) -(declare-function tramp-compat-rx "tramp") (declare-function tramp-error "tramp") -(declare-function tramp-file-name-handler "tramp") (declare-function tramp-tramp-file-p "tramp") (defvar tramp-temp-name-prefix) @@ -85,153 +83,6 @@ Add the extension of F, if existing." tramp-temp-name-prefix tramp-compat-temporary-file-directory) dir-flag (file-name-extension f t))) -;; `file-name-quoted-p', `file-name-quote' and `file-name-unquote' got -;; a second argument in Emacs 27.1. -;;;###tramp-autoload -(defalias 'tramp-compat-file-name-quoted-p - (if (equal (func-arity #'file-name-quoted-p) '(1 . 2)) - #'file-name-quoted-p - (lambda (name &optional top) - "Whether NAME is quoted with prefix \"/:\". -If NAME is a remote file name and TOP is nil, check the local part of NAME." - (let ((file-name-handler-alist (unless top file-name-handler-alist))) - (string-prefix-p "/:" (file-local-name name)))))) - -(defalias 'tramp-compat-file-name-quote - (if (equal (func-arity #'file-name-quote) '(1 . 2)) - #'file-name-quote - (lambda (name &optional top) - "Add the quotation prefix \"/:\" to file NAME. -If NAME is a remote file name and TOP is nil, the local part of NAME is quoted." - (let ((file-name-handler-alist (unless top file-name-handler-alist))) - (if (tramp-compat-file-name-quoted-p name top) - name - (concat (file-remote-p name) "/:" (file-local-name name))))))) - -(defalias 'tramp-compat-file-name-unquote - (if (equal (func-arity #'file-name-unquote) '(1 . 2)) - #'file-name-unquote - (lambda (name &optional top) - "Remove quotation prefix \"/:\" from file NAME. -If NAME is a remote file name and TOP is nil, the local part of -NAME is unquoted." - (let* ((file-name-handler-alist (unless top file-name-handler-alist)) - (localname (file-local-name name))) - (when (tramp-compat-file-name-quoted-p localname top) - (setq - localname (if (= (length localname) 2) "/" (substring localname 2)))) - (concat (file-remote-p name) localname))))) - -;; `tramp-syntax' has changed its meaning in Emacs 26.1. We still -;; support old settings. -(defsubst tramp-compat-tramp-syntax () - "Return proper value of `tramp-syntax'." - (defvar tramp-syntax) - (cond ((eq tramp-syntax 'ftp) 'default) - ((eq tramp-syntax 'sep) 'separate) - (t tramp-syntax))) - -;; The signature of `tramp-make-tramp-file-name' has been changed. -;; Therefore, we cannot use `url-tramp-convert-url-to-tramp' prior -;; Emacs 26.1. We use `temporary-file-directory' as indicator. -(defconst tramp-compat-use-url-tramp-p (fboundp 'temporary-file-directory) - "Whether to use url-tramp.el.") - -;; `exec-path' is new in Emacs 27.1. -(defalias 'tramp-compat-exec-path - (if (fboundp 'exec-path) - #'exec-path - (lambda () - "List of directories to search programs to run in remote subprocesses." - (if (tramp-tramp-file-p default-directory) - (tramp-file-name-handler 'exec-path) - exec-path)))) - -;; `time-equal-p' has appeared in Emacs 27.1. -(defalias 'tramp-compat-time-equal-p - (if (fboundp 'time-equal-p) - #'time-equal-p - (lambda (t1 t2) - "Return non-nil if time value T1 is equal to time value T2. -A nil value for either argument stands for the current time." - (equal (or t1 (current-time)) (or t2 (current-time)))))) - -;; `flatten-tree' has appeared in Emacs 27.1. -(defalias 'tramp-compat-flatten-tree - (if (fboundp 'flatten-tree) - #'flatten-tree - (lambda (tree) - "Take TREE and \"flatten\" it." - (let (elems) - (setq tree (list tree)) - (while (let ((elem (pop tree))) - (cond ((consp elem) - (setq tree (cons (car elem) (cons (cdr elem) tree)))) - (elem - (push elem elems))) - tree)) - (nreverse elems))))) - -;; `progress-reporter-update' got argument SUFFIX in Emacs 27.1. -(defalias 'tramp-compat-progress-reporter-update - (if (equal (func-arity #'progress-reporter-update) '(1 . 3)) - #'progress-reporter-update - (lambda (reporter &optional value _suffix) - (progress-reporter-update reporter value)))) - -;; `ignore-error' is new in Emacs 27.1. -(defmacro tramp-compat-ignore-error (condition &rest body) - "Execute BODY; if the error CONDITION occurs, return nil. -Otherwise, return result of last form in BODY. - -CONDITION can also be a list of error conditions." - (declare (debug t) (indent 1)) - `(condition-case nil (progn ,@body) (,condition nil))) - -;; `rx' in Emacs 26 doesn't know the `literal', `anychar' and -;; `multibyte' constructs. The `not' construct requires an `any' -;; construct as argument. The `regexp' construct requires a literal -;; string. -(defvar tramp-compat-rx--runtime-params) - -(defun tramp-compat-rx--transform-items (items) - (mapcar #'tramp-compat-rx--transform-item items)) - -;; There is an error in Emacs 26. `(rx "a" (? ""))' => "a?". -;; We must protect the string in regexp and literal, therefore. -(defun tramp-compat-rx--transform-item (item) - (pcase item - ('anychar 'anything) - ('multibyte 'nonascii) - (`(not ,expr) - (if (consp expr) item (list 'not (list 'any expr)))) - (`(regexp ,expr) - (setq tramp-compat-rx--runtime-params t) - `(regexp ,(list '\, `(concat "\\(?:" ,expr "\\)")))) - (`(literal ,expr) - (setq tramp-compat-rx--runtime-params t) - `(regexp ,(list '\, `(concat "\\(?:" (regexp-quote ,expr) "\\)")))) - (`(eval . ,_) item) - (`(,head . ,rest) (cons head (tramp-compat-rx--transform-items rest))) - (_ item))) - -(defun tramp-compat-rx--transform (items) - (let* ((tramp-compat-rx--runtime-params nil) - (new-rx (cons ': (tramp-compat-rx--transform-items items)))) - (if tramp-compat-rx--runtime-params - `(rx-to-string ,(list '\` new-rx) t) - (rx-to-string new-rx t)))) - -(if (ignore-errors (rx-to-string '(literal "a"))) ;; Emacs 27+. - (defalias 'tramp-compat-rx #'rx) - (defmacro tramp-compat-rx (&rest items) - (tramp-compat-rx--transform items))) - -;; This is needed for compilation in the Emacs source tree. -;;;###autoload (defalias 'tramp-compat-rx #'rx) - -(put #'tramp-compat-rx 'tramp-autoload t) - ;; `file-modes', `set-file-modes' and `set-file-times' got argument ;; FLAG in Emacs 28.1. (defalias 'tramp-compat-file-modes @@ -326,6 +177,48 @@ CONDITION can also be a list of error conditions." (car components)) (cdr components))))))) +;; Function `replace-regexp-in-region' is new in Emacs 28.1. +(defalias 'tramp-compat-replace-regexp-in-region + (if (fboundp 'replace-regexp-in-region) + #'replace-regexp-in-region + (lambda (regexp replacement &optional start end) + (if start + (when (< start (point-min)) + (error "Start before start of buffer")) + (setq start (point))) + (if end + (when (> end (point-max)) + (error "End after end of buffer")) + (setq end (point-max))) + (save-excursion + (let ((matches 0) + (case-fold-search nil)) + (goto-char start) + (while (re-search-forward regexp end t) + (replace-match replacement t) + (setq matches (1+ matches))) + (and (not (zerop matches)) + matches)))))) + +;; `length<', `length>' and `length=' are added to Emacs 28.1. +(defalias 'tramp-compat-length< + (if (fboundp 'length<) + #'length< + (lambda (sequence length) + (< (length sequence) length)))) + +(defalias 'tramp-compat-length> + (if (fboundp 'length>) + #'length> + (lambda (sequence length) + (> (length sequence) length)))) + +(defalias 'tramp-compat-length= + (if (fboundp 'length=) + #'length= + (lambda (sequence length) + (= (length sequence) length)))) + ;; `permission-denied' is introduced in Emacs 29.1. (defconst tramp-permission-denied (if (get 'permission-denied 'error-conditions) 'permission-denied 'file-error) @@ -353,7 +246,7 @@ CONDITION can also be a list of error conditions." #'take (lambda (n list) (when (and (natnump n) (> n 0)) - (if (>= n (length list)) + (if (tramp-compat-length< list n) list (butlast list (- (length list) n))))))) ;; Function `ntake' is new in Emacs 29.1. @@ -362,7 +255,7 @@ CONDITION can also be a list of error conditions." #'ntake (lambda (n list) (when (and (natnump n) (> n 0)) - (if (>= n (length list)) + (if (tramp-compat-length< list n) list (nbutlast list (- (length list) n))))))) ;; Function `string-equal-ignore-case' is new in Emacs 29.1. @@ -382,29 +275,6 @@ CONDITION can also be a list of error conditions." (autoload 'netrc-parse "netrc") (netrc-parse file)))) -;; Function `replace-regexp-in-region' is new in Emacs 28.1. -(defalias 'tramp-compat-replace-regexp-in-region - (if (fboundp 'replace-regexp-in-region) - #'replace-regexp-in-region - (lambda (regexp replacement &optional start end) - (if start - (when (< start (point-min)) - (error "Start before start of buffer")) - (setq start (point))) - (if end - (when (> end (point-max)) - (error "End after end of buffer")) - (setq end (point-max))) - (save-excursion - (let ((matches 0) - (case-fold-search nil)) - (goto-char start) - (while (re-search-forward regexp end t) - (replace-match replacement t) - (setq matches (1+ matches))) - (and (not (zerop matches)) - matches)))))) - (dolist (elt (all-completions "tramp-compat-" obarray 'functionp)) (put (intern elt) 'tramp-suppress-trace t)) @@ -419,8 +289,5 @@ CONDITION can also be a list of error conditions." ;; ;; * Starting with Emacs 27.1, there's no need to escape open ;; parentheses with a backslash in docstrings anymore. -;; -;; * Starting with Emacs 27.1, there's `make-empty-file'. Could be -;; used instead of `(write-region "" ...)'. ;;; tramp-compat.el ends here diff --git a/lisp/net/tramp-container.el b/lisp/net/tramp-container.el index 6cdd6c654ea..5ae9ebaefb2 100644 --- a/lisp/net/tramp-container.el +++ b/lisp/net/tramp-container.el @@ -41,6 +41,7 @@ ;; CONTAINER is the container to connect to ;; ;; +;; ;; Open file in a Kubernetes container: ;; ;; C-x C-f /kubernetes:POD:/path/to/file @@ -54,6 +55,18 @@ ;; namespace, use this command to change it: ;; ;; "kubectl config set-context --current --namespace=<name>" +;; +;; +;; +;; Open a file on an existing toolbox container via Toolbox: +;; +;; C-x C-f /toolbox:CONTAINER:/path/to/file +;; +;; Where: +;; CONTAINER is the container to connect to (optional) +;; +;; If the container is not running, it is started. If no container is +;; specified, the default Toolbox container is used. ;;; Code: @@ -84,6 +97,14 @@ (string))) ;;;###tramp-autoload +(defcustom tramp-toolbox-program "toolbox" + "Name of the Toolbox client program." + :group 'tramp + :version "30.1" + :type '(choice (const "toolbox") + (string))) + +;;;###tramp-autoload (defconst tramp-docker-method "docker" "Tramp method name to use to connect to Docker containers.") @@ -96,15 +117,20 @@ "Tramp method name to use to connect to Kubernetes containers.") ;;;###tramp-autoload -(defun tramp-docker--completion-function (&rest _args) - "List Docker-like containers available for connection. +(defconst tramp-toolbox-method "toolbox" + "Tramp method name to use to connect to Toolbox containers.") + +;;;###tramp-autoload +(defun tramp-container--completion-function (program) + "List running containers available for connection. +PROGRAM is the program to be run for \"ps\", either +`tramp-docker-program' or `tramp-podman-program'. This function is used by `tramp-set-completion-function', please see its function help for a description of the format." (when-let ((default-directory tramp-compat-temporary-file-directory) (raw-list (shell-command-to-string - (concat tramp-docker-program - " ps --format '{{.ID}}\t{{.Names}}'"))) + (concat program " ps --format '{{.ID}}\t{{.Names}}'"))) (lines (split-string raw-list "\n" 'omit)) (names (mapcar (lambda (line) @@ -114,7 +140,7 @@ see its function help for a description of the format." line) (or (match-string 2 line) (match-string 1 line)))) lines))) - (mapcar (lambda (m) (list nil m)) (delq nil names)))) + (mapcar (lambda (name) (list nil name)) (delq nil names)))) ;;;###tramp-autoload (defun tramp-kubernetes--completion-function (&rest _args) @@ -128,9 +154,7 @@ see its function help for a description of the format." " get pods --no-headers " "-o custom-columns=NAME:.metadata.name"))) (names (split-string raw-list "\n" 'omit))) - (mapcar (lambda (name) - (list nil name)) - names))) + (mapcar (lambda (name) (list nil name)) (delq nil names)))) (defun tramp-kubernetes--current-context-data (vec) "Return Kubernetes current context data as JSON string." @@ -151,6 +175,27 @@ see its function help for a description of the format." (buffer-string)))))) ;;;###tramp-autoload +(defun tramp-toolbox--completion-function (&rest _args) + "List Toolbox containers available for connection. + +This function is used by `tramp-set-completion-function', please +see its function help for a description of the format." + (when-let ((default-directory tramp-compat-temporary-file-directory) + (raw-list (shell-command-to-string + (concat tramp-toolbox-program " list -c"))) + ;; Ignore header line. + (lines (cdr (split-string raw-list "\n" 'omit))) + (names (mapcar + (lambda (line) + (when (string-match + (rx bol (1+ (not space)) + (1+ space) (group (1+ (not space))) space) + line) + (match-string 1 line))) + lines))) + (mapcar (lambda (name) (list nil name)) (delq nil names)))) + +;;;###tramp-autoload (defvar tramp-default-remote-shell) ;; Silence byte compiler. ;;;###tramp-autoload @@ -167,6 +212,7 @@ see its function help for a description of the format." (tramp-remote-shell ,tramp-default-remote-shell) (tramp-remote-shell-login ("-l")) (tramp-remote-shell-args ("-i" "-c")))) + (add-to-list 'tramp-methods `(,tramp-podman-method (tramp-login-program ,tramp-podman-program) @@ -179,6 +225,7 @@ see its function help for a description of the format." (tramp-remote-shell ,tramp-default-remote-shell) (tramp-remote-shell-login ("-l")) (tramp-remote-shell-args ("-i" "-c")))) + (add-to-list 'tramp-methods `(,tramp-kubernetes-method (tramp-login-program ,tramp-kubernetes-program) @@ -193,17 +240,36 @@ see its function help for a description of the format." (tramp-remote-shell-login ("-l")) (tramp-remote-shell-args ("-i" "-c")))) + (add-to-list 'tramp-methods + `(,tramp-toolbox-method + (tramp-login-program ,tramp-toolbox-program) + (tramp-login-args (("run") + ("-c" "%h") + ("%l"))) + (tramp-direct-async (,tramp-default-remote-shell "-c")) + (tramp-remote-shell ,tramp-default-remote-shell) + (tramp-remote-shell-login ("-l")) + (tramp-remote-shell-args ("-c")))) + + (add-to-list 'tramp-default-host-alist `(,tramp-toolbox-method nil "")) + (tramp-set-completion-function tramp-docker-method - '((tramp-docker--completion-function ""))) + `((tramp-container--completion-function + ,(executable-find tramp-docker-program)))) (tramp-set-completion-function tramp-podman-method - '((tramp-docker--completion-function ""))) + `((tramp-container--completion-function + ,(executable-find tramp-podman-program)))) (tramp-set-completion-function tramp-kubernetes-method - '((tramp-kubernetes--completion-function "")))) + '((tramp-kubernetes--completion-function ""))) + + (tramp-set-completion-function + tramp-toolbox-method + '((tramp-toolbox--completion-function "")))) (add-hook 'tramp-unload-hook (lambda () diff --git a/lisp/net/tramp-crypt.el b/lisp/net/tramp-crypt.el index c7696a51dae..afd3166d161 100644 --- a/lisp/net/tramp-crypt.el +++ b/lisp/net/tramp-crypt.el @@ -146,7 +146,7 @@ They are completed by \"M-x TAB\" only when encryption support is enabled." If NAME doesn't belong to an encrypted remote directory, return nil." (catch 'crypt-file-name-p (and tramp-crypt-enabled (stringp name) - (not (tramp-compat-file-name-quoted-p name)) + (not (file-name-quoted-p name)) (not (string-suffix-p tramp-crypt-encfs-config name)) (dolist (dir tramp-crypt-directories) (and (string-prefix-p @@ -204,6 +204,7 @@ If NAME doesn't belong to an encrypted remote directory, return nil." (file-symlink-p . tramp-handle-file-symlink-p) (file-system-info . tramp-crypt-handle-file-system-info) ;; `file-truename' performed by default handler. + ;; `file-user-uid' performed by default-handler. (file-writable-p . tramp-crypt-handle-file-writable-p) (find-backup-file-name . tramp-handle-find-backup-file-name) ;; `get-file-buffer' performed by default handler. @@ -497,7 +498,7 @@ directory. File names will be also encrypted." (tramp-user-error nil "Feature is not enabled.")) (unless (and (tramp-tramp-file-p name) (file-directory-p name)) (tramp-user-error nil "%s must be an existing remote directory." name)) - (when (tramp-compat-file-name-quoted-p name) + (when (file-name-quoted-p name) (tramp-user-error nil "%s must not be quoted." name)) (setq name (file-name-as-directory (expand-file-name name))) (unless (member name tramp-crypt-directories) @@ -556,7 +557,7 @@ localname." (defun tramp-crypt-handle-access-file (filename string) "Like `access-file' for Tramp files." (let* ((encrypt-filename (tramp-crypt-encrypt-file-name filename)) - (encrypt-regexp (tramp-compat-rx (literal encrypt-filename) eos)) + (encrypt-regexp (rx (literal encrypt-filename) eos)) tramp-crypt-enabled) (condition-case err (access-file encrypt-filename string) @@ -689,17 +690,17 @@ absolute file names." (directory &optional recursive _trash) "Like `delete-directory' for Tramp files." (with-parsed-tramp-file-name (expand-file-name directory) nil - (tramp-flush-directory-properties v localname) (let (tramp-crypt-enabled) - (delete-directory (tramp-crypt-encrypt-file-name directory) recursive)))) + (delete-directory (tramp-crypt-encrypt-file-name directory) recursive)) + (tramp-flush-directory-properties v localname))) ;; Encrypted files won't be trashed. (defun tramp-crypt-handle-delete-file (filename &optional _trash) "Like `delete-file' for Tramp files." (with-parsed-tramp-file-name (expand-file-name filename) nil - (tramp-flush-file-properties v localname) (let (tramp-crypt-enabled) - (delete-file (tramp-crypt-encrypt-file-name filename))))) + (delete-file (tramp-crypt-encrypt-file-name filename))) + (tramp-flush-file-properties v localname))) (defun tramp-crypt-handle-directory-files (directory &optional full match nosort count) @@ -709,8 +710,7 @@ absolute file names." (mapcar (lambda (x) (replace-regexp-in-string - (tramp-compat-rx bos (literal directory)) "" - (tramp-crypt-decrypt-file-name x))) + (rx bos (literal directory)) "" (tramp-crypt-decrypt-file-name x))) (directory-files (tramp-crypt-encrypt-file-name directory) 'full))))) (defun tramp-crypt-handle-file-attributes (filename &optional id-format) @@ -756,9 +756,7 @@ absolute file names." (defun tramp-crypt-handle-file-system-info (filename) "Like `file-system-info' for Tramp files." (let (tramp-crypt-enabled) - ;; `file-system-info' exists since Emacs 27.1. - (tramp-compat-funcall - 'file-system-info (tramp-crypt-encrypt-file-name filename)))) + (file-system-info (tramp-crypt-encrypt-file-name filename)))) (defun tramp-crypt-handle-file-writable-p (filename) "Like `file-writable-p' for Tramp files." @@ -769,27 +767,26 @@ absolute file names." (filename switches &optional wildcard full-directory-p) "Like `insert-directory' for Tramp files. WILDCARD is not supported." - ;; This package has been added to Emacs 27.1. - (when (load "text-property-search" 'noerror 'nomessage) - (let (tramp-crypt-enabled) - (tramp-handle-insert-directory - (tramp-crypt-encrypt-file-name filename) - switches wildcard full-directory-p) - (let* ((filename (file-name-as-directory filename)) - (enc (tramp-crypt-encrypt-file-name filename)) - match string) - (goto-char (point-min)) - (while (setq match (text-property-search-forward 'dired-filename t t)) - (setq string - (buffer-substring - (prop-match-beginning match) (prop-match-end match)) - string (if (file-name-absolute-p string) - (tramp-crypt-decrypt-file-name string) - (substring - (tramp-crypt-decrypt-file-name (concat enc string)) - (length filename)))) - (delete-region (prop-match-beginning match) (prop-match-end match)) - (insert (propertize string 'dired-filename t))))))) + (require 'text-property-search) + (let (tramp-crypt-enabled) + (tramp-handle-insert-directory + (tramp-crypt-encrypt-file-name filename) + switches wildcard full-directory-p) + (let* ((filename (file-name-as-directory filename)) + (enc (tramp-crypt-encrypt-file-name filename)) + match string) + (goto-char (point-min)) + (while (setq match (text-property-search-forward 'dired-filename t t)) + (setq string + (buffer-substring + (prop-match-beginning match) (prop-match-end match)) + string (if (file-name-absolute-p string) + (tramp-crypt-decrypt-file-name string) + (substring + (tramp-crypt-decrypt-file-name (concat enc string)) + (length filename)))) + (delete-region (prop-match-beginning match) (prop-match-end match)) + (insert (propertize string 'dired-filename t)))))) (defun tramp-crypt-handle-lock-file (filename) "Like `lock-file' for Tramp files." @@ -800,16 +797,9 @@ WILDCARD is not supported." (defun tramp-crypt-handle-make-directory (dir &optional parents) "Like `make-directory' for Tramp files." - (with-parsed-tramp-file-name (expand-file-name dir) nil - (when (and (null parents) (file-exists-p dir)) - (tramp-error v 'file-already-exists dir)) + (tramp-skeleton-make-directory dir parents (let (tramp-crypt-enabled) - (make-directory (tramp-crypt-encrypt-file-name dir) parents)) - ;; When PARENTS is non-nil, DIR could be a chain of non-existent - ;; directories a/b/c/... Instead of checking, we simply flush the - ;; whole cache. - (tramp-flush-directory-properties - v (if parents "/" (file-name-directory localname))))) + (make-directory (tramp-crypt-encrypt-file-name dir) parents)))) (defun tramp-crypt-handle-rename-file (filename newname &optional ok-if-already-exists) diff --git a/lisp/net/tramp-fuse.el b/lisp/net/tramp-fuse.el index e1ad0c2e5d2..b846caadc18 100644 --- a/lisp/net/tramp-fuse.el +++ b/lisp/net/tramp-fuse.el @@ -34,15 +34,13 @@ (defun tramp-fuse-handle-delete-directory (directory &optional recursive trash) "Like `delete-directory' for Tramp files." - (with-parsed-tramp-file-name (expand-file-name directory) nil - (tramp-flush-directory-properties v localname) + (tramp-skeleton-delete-directory directory recursive trash (delete-directory (tramp-fuse-local-file-name directory) recursive trash))) (defun tramp-fuse-handle-delete-file (filename &optional trash) "Like `delete-file' for Tramp files." - (with-parsed-tramp-file-name (expand-file-name filename) nil - (delete-file (tramp-fuse-local-file-name filename) trash) - (tramp-flush-file-properties v localname))) + (tramp-skeleton-delete-file filename trash + (delete-file (tramp-fuse-local-file-name filename) trash))) (defvar tramp-fuse-remove-hidden-files nil "Remove hidden files from directory listings.") @@ -69,15 +67,15 @@ (tramp-fuse-local-file-name directory)))))))) (if full ;; Massage the result. - (let ((local (tramp-compat-rx + (let ((local (rx bol (literal (tramp-fuse-mount-point (tramp-dissect-file-name directory))))) (remote (directory-file-name (funcall - (if (tramp-compat-file-name-quoted-p directory) - #'tramp-compat-file-name-quote #'identity) + (if (file-name-quoted-p directory) + #'file-name-quote #'identity) (file-remote-p directory))))) (mapcar (lambda (x) (replace-regexp-in-string local remote x)) @@ -127,14 +125,8 @@ (defun tramp-fuse-handle-make-directory (dir &optional parents) "Like `make-directory' for Tramp files." - (with-parsed-tramp-file-name (expand-file-name dir) nil - (make-directory (tramp-fuse-local-file-name dir) parents) - ;; When PARENTS is non-nil, DIR could be a chain of non-existent - ;; directories a/b/c/... Instead of checking, we simply flush the - ;; whole file cache. - (tramp-flush-file-properties v localname) - (tramp-flush-directory-properties - v (if parents "/" (file-name-directory localname))))) + (tramp-skeleton-make-directory dir parents + (make-directory (tramp-fuse-local-file-name dir) parents))) ;; File name helper functions. @@ -180,8 +172,7 @@ It has the same meaning as `remote-file-name-inhibit-cache'.") (tramp-set-file-property vec "/" "mounted" (when (string-match - (tramp-compat-rx - bol (group (literal (tramp-fuse-mount-spec vec))) blank) + (rx bol (group (literal (tramp-fuse-mount-spec vec))) blank) mount) (match-string 1 mount))))))) @@ -211,7 +202,7 @@ It has the same meaning as `remote-file-name-inhibit-cache'.") (defun tramp-fuse-local-file-name (filename) "Return local mount name of FILENAME." - (setq filename (tramp-compat-file-name-unquote (expand-file-name filename))) + (setq filename (file-name-unquote (expand-file-name filename))) (with-parsed-tramp-file-name filename nil ;; As long as we call `tramp-*-maybe-open-connection' here, ;; we cache the result. @@ -220,10 +211,10 @@ It has the same meaning as `remote-file-name-inhibit-cache'.") (intern (format "tramp-%s-maybe-open-connection" (tramp-file-name-method v))) v) - (let ((quoted (tramp-compat-file-name-quoted-p localname)) - (localname (tramp-compat-file-name-unquote localname))) + (let ((quoted (file-name-quoted-p localname)) + (localname (file-name-unquote localname))) (funcall - (if quoted #'tramp-compat-file-name-quote #'identity) + (if quoted #'file-name-quote #'identity) (expand-file-name (if (file-name-absolute-p localname) (substring localname 1) localname) diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el index 0273c28beca..02ceb2979f7 100644 --- a/lisp/net/tramp-gvfs.el +++ b/lisp/net/tramp-gvfs.el @@ -414,7 +414,7 @@ It has been changed in GVFS 1.14.") ;; </interface> (defconst tramp-goa-identity-regexp - (tramp-compat-rx + (rx bol (? (group (regexp tramp-user-regexp))) "@" (? (group (regexp tramp-host-regexp))) (? ":" (group (regexp tramp-port-regexp)))) @@ -716,13 +716,13 @@ It has been changed in GVFS 1.14.") "GVFS file attributes.")) (defconst tramp-gvfs-file-attributes-with-gvfs-ls-regexp - (tramp-compat-rx + (rx blank (group (regexp (regexp-opt tramp-gvfs-file-attributes))) "=" (group (+? nonl))) "Regexp to parse GVFS file attributes with `gvfs-ls'.") (defconst tramp-gvfs-file-attributes-with-gvfs-info-regexp - (tramp-compat-rx + (rx bol (* blank) (group (regexp (regexp-opt tramp-gvfs-file-attributes))) ":" (+ blank) (group (* nonl)) eol) "Regexp to parse GVFS file attributes with `gvfs-info'.") @@ -734,7 +734,7 @@ It has been changed in GVFS 1.14.") "GVFS file system attributes.") (defconst tramp-gvfs-file-system-attributes-regexp - (tramp-compat-rx + (rx bol (* blank) (group (regexp (regexp-opt tramp-gvfs-file-system-attributes))) ":" (+ blank) (group (* nonl)) eol) @@ -744,7 +744,7 @@ It has been changed in GVFS 1.14.") "Default prefix for owncloud / nextcloud methods.") (defconst tramp-gvfs-nextcloud-default-prefix-regexp - (tramp-compat-rx (literal tramp-gvfs-nextcloud-default-prefix) eol) + (rx (literal tramp-gvfs-nextcloud-default-prefix) eol) "Regexp of default prefix for owncloud / nextcloud methods.") @@ -798,6 +798,7 @@ It has been changed in GVFS 1.14.") (file-symlink-p . tramp-handle-file-symlink-p) (file-system-info . tramp-gvfs-handle-file-system-info) (file-truename . tramp-handle-file-truename) + (file-user-uid . tramp-handle-file-user-uid) (file-writable-p . tramp-handle-file-writable-p) (find-backup-file-name . tramp-handle-find-backup-file-name) ;; `get-file-buffer' performed by default handler. @@ -1139,25 +1140,23 @@ file names." (defun tramp-gvfs-handle-delete-file (filename &optional trash) "Like `delete-file' for Tramp files." - (with-parsed-tramp-file-name (expand-file-name filename) nil - (tramp-flush-file-properties v localname) - (if (and delete-by-moving-to-trash trash) - (move-file-to-trash filename) - (unless (and (tramp-gvfs-send-command - v "gvfs-rm" (tramp-gvfs-url-file-name filename)) - (not (tramp-gvfs-info filename))) - ;; Propagate the error. - (with-current-buffer (tramp-get-connection-buffer v) - (goto-char (point-min)) - (tramp-error-with-buffer - nil v 'file-error "Couldn't delete %s" filename)))))) + (tramp-skeleton-delete-file filename trash + (unless (and (tramp-gvfs-send-command + v "gvfs-rm" (tramp-gvfs-url-file-name filename)) + (not (tramp-gvfs-info filename))) + ;; Propagate the error. + (with-current-buffer (tramp-get-connection-buffer v) + (goto-char (point-min)) + (tramp-error-with-buffer + nil v 'file-error "Couldn't delete %s" filename))))) (defun tramp-gvfs-handle-expand-file-name (name &optional dir) "Like `expand-file-name' for Tramp files." ;; If DIR is not given, use DEFAULT-DIRECTORY or "/". (setq dir (or dir default-directory "/")) ;; Handle empty NAME. - (when (zerop (length name)) (setq name ".")) + (when (string-empty-p name) + (setq name ".")) ;; Unless NAME is absolute, concat DIR and NAME. (unless (file-name-absolute-p name) (setq name (tramp-compat-file-name-concat dir name))) @@ -1168,12 +1167,11 @@ file names." (with-parsed-tramp-file-name name nil ;; If there is a default location, expand tilde. (when (string-match - (tramp-compat-rx bos "~" (group (* (not "/"))) (group (* nonl)) eos) - localname) + (rx bos "~" (group (* (not "/"))) (group (* nonl)) eos) localname) (let ((uname (match-string 1 localname)) (fname (match-string 2 localname)) hname) - (when (zerop (length uname)) + (when (tramp-string-empty-or-nil-p uname) (setq uname user)) (when (setq hname (tramp-get-home-directory v uname)) (setq localname (concat hname fname))))) @@ -1186,8 +1184,7 @@ file names." ;; We do not pass "/..". (if (string-match-p (rx bos (| "afp" (: "dav" (? "s")) "smb") eos) method) (when (string-match - (tramp-compat-rx bos "/" (+ (not "/")) (group "/.." (? "/"))) - localname) + (rx bos "/" (+ (not "/")) (group "/.." (? "/"))) localname) (setq localname (replace-match "/" t t localname 1))) (when (string-match (rx bol "/.." (? "/")) localname) (setq localname (replace-match "/" t t localname)))) @@ -1222,7 +1219,7 @@ file names." (with-current-buffer (tramp-get-connection-buffer v) (goto-char (point-min)) (while (looking-at - (tramp-compat-rx + (rx bol (group (+ nonl)) blank (group (+ digit)) blank "(" (group (+? nonl)) ")" @@ -1232,7 +1229,7 @@ file names." (cons "name" (match-string 1))))) (goto-char (1+ (match-end 3))) (while (looking-at - (tramp-compat-rx + (rx (regexp tramp-gvfs-file-attributes-with-gvfs-ls-regexp) (group (| (regexp @@ -1281,11 +1278,10 @@ If FILE-SYSTEM is non-nil, return file system attributes." "Return GVFS attributes association list of FILENAME." (setq filename (directory-file-name (expand-file-name filename))) (with-parsed-tramp-file-name filename nil - (setq localname (tramp-compat-file-name-unquote localname)) + (setq localname (file-name-unquote localname)) (if (or (and (string-match-p (rx bol (| "afp" (: "dav" (? "s")) "smb") eol) method) - (string-match-p - (tramp-compat-rx bol (? "/") (+ (not "/")) eol) localname)) + (string-match-p (rx bol (? "/") (+ (not "/")) eol) localname)) (string-equal localname "/")) (tramp-gvfs-get-root-attributes filename) (assoc @@ -1485,7 +1481,7 @@ If FILE-SYSTEM is non-nil, return file system attributes." (let* ((events (process-get proc 'events)) (rest-string (process-get proc 'rest-string)) (dd (tramp-get-default-directory (process-buffer proc))) - (ddu (tramp-compat-rx (literal (tramp-gvfs-url-file-name dd))))) + (ddu (rx (literal (tramp-gvfs-url-file-name dd))))) (when rest-string (tramp-message proc 10 "Previous string:\n%s" rest-string)) (tramp-message proc 6 "%S\n%s" proc string) @@ -1504,7 +1500,7 @@ If FILE-SYSTEM is non-nil, return file system attributes." (delete-process proc)) (while (string-match - (tramp-compat-rx + (rx bol (+ nonl) ":" blank (group (+ nonl)) ":" blank (group (regexp (regexp-opt tramp-gio-events))) @@ -1536,7 +1532,7 @@ If FILE-SYSTEM is non-nil, return file system attributes." 'file-notify-callback (list proc action file file1))))) ;; Save rest of the string. - (when (zerop (length string)) (setq string nil)) + (when (string-empty-p string) (setq string nil)) (when string (tramp-message proc 10 "Rest string:\n%s" string)) (process-put proc 'rest-string string))) @@ -1560,27 +1556,13 @@ If FILE-SYSTEM is non-nil, return file system attributes." (defun tramp-gvfs-handle-make-directory (dir &optional parents) "Like `make-directory' for Tramp files." - (setq dir (directory-file-name (expand-file-name dir))) - (with-parsed-tramp-file-name dir nil - (when (and (null parents) (file-exists-p dir)) - (tramp-error v 'file-already-exists dir)) - (tramp-flush-directory-properties v localname) + (tramp-skeleton-make-directory dir parents (save-match-data - (let ((ldir (file-name-directory dir))) - ;; Make missing directory parts. "gvfs-mkdir -p ..." does not - ;; work robust. - (when (and parents (not (file-directory-p ldir))) - (make-directory ldir parents)) - ;; Just do it. - (or (when-let ((mkdir-succeeded - (and - (tramp-gvfs-send-command - v "gvfs-mkdir" (tramp-gvfs-url-file-name dir)) - (tramp-gvfs-info dir)))) - (set-file-modes dir (default-file-modes)) - mkdir-succeeded) - (and parents (file-directory-p dir)) - (tramp-error v 'file-error "Couldn't make directory %s" dir)))))) + (if (and (tramp-gvfs-send-command + v "gvfs-mkdir" (tramp-gvfs-url-file-name dir)) + (tramp-gvfs-info dir)) + (set-file-modes dir (default-file-modes)) + (tramp-error v 'file-error "Couldn't make directory %s" dir))))) (defun tramp-gvfs-handle-rename-file (filename newname &optional ok-if-already-exists) @@ -1621,12 +1603,7 @@ If FILE-SYSTEM is non-nil, return file system attributes." (tramp-gvfs-set-attribute v (if (eq flag 'nofollow) "-nt" "-t") "uint64" (tramp-gvfs-url-file-name filename) "time::modified" - (format-time-string - "%s" (if (or (null time) - (tramp-compat-time-equal-p time tramp-time-doesnt-exist) - (tramp-compat-time-equal-p time tramp-time-dont-know)) - nil - time))))) + (format-time-string "%s" (tramp-defined-time time))))) (defun tramp-gvfs-handle-get-home-directory (vec &optional _user) "The remote home directory for connection VEC as local file name. @@ -1636,7 +1613,7 @@ VEC or USER, or if there is no home directory, return nil." (let ((localname (tramp-get-connection-property vec "default-location")) result) (cond - ((zerop (length localname)) + ((tramp-string-empty-or-nil-p localname) (tramp-get-connection-property (tramp-get-process vec) "share")) ;; Google-drive. ((not (string-prefix-p "/" localname)) @@ -1719,7 +1696,7 @@ ID-FORMAT valid values are `string' and `integer'." (defun tramp-gvfs-url-file-name (filename) "Return FILENAME in URL syntax." - (setq filename (tramp-compat-file-name-unquote filename)) + (setq filename (file-name-unquote filename)) (let* (;; "/" must NOT be hexified. (url-unreserved-chars (cons ?/ url-unreserved-chars)) (result @@ -1739,8 +1716,7 @@ ID-FORMAT valid values are `string' and `integer'." "Retrieve file name from D-Bus OBJECT-PATH." (dbus-unescape-from-identifier (replace-regexp-in-string - (tramp-compat-rx bol (* nonl) "/" (group (+ (not "/"))) eol) "\\1" - object-path))) + (rx bol (* nonl) "/" (group (+ (not "/"))) eol) "\\1" object-path))) (defun tramp-gvfs-url-host (url) "Return the host name part of URL, a string. @@ -1769,11 +1745,11 @@ a downcased host name only." (condition-case nil (with-parsed-tramp-file-name filename l - (when (and (zerop (length user)) + (when (and (tramp-string-empty-or-nil-p user) (not (zerop (logand flags tramp-gvfs-password-need-username)))) (setq user (read-string "User name: "))) - (when (and (zerop (length domain)) + (when (and (tramp-string-empty-or-nil-p domain) (not (zerop (logand flags tramp-gvfs-password-need-domain)))) (setq domain (read-string "Domain name: "))) @@ -2016,7 +1992,7 @@ Their full names are \"org.gtk.vfs.MountTracker.mounted\" and (string-equal host (tramp-file-name-host vec)) (string-equal port (tramp-file-name-port vec)) (string-match-p - (tramp-compat-rx bol "/" (literal (or share ""))) + (rx bol "/" (literal (or share ""))) (tramp-file-name-unquote-localname vec))) ;; Set mountpoint and location. (tramp-set-file-property vec "/" "fuse-mountpoint" fuse-mountpoint) @@ -2061,8 +2037,7 @@ It was \"a(say)\", but has changed to \"a{sv})\"." (tramp-media-device-port media) (tramp-file-name-port vec))) (localname (tramp-file-name-unquote-localname vec)) (share (when (string-match - (tramp-compat-rx bol (? "/") (group (+ (not "/")))) - localname) + (rx bol (? "/") (group (+ (not "/")))) localname) (match-string 1 localname))) (ssl (if (string-match-p (rx bol (| "davs" "nextcloud")) method) "true" "false")) @@ -2105,8 +2080,7 @@ It was \"a(say)\", but has changed to \"a{sv})\"." (list (tramp-gvfs-mount-spec-entry "port" port))))) (mount-pref (if (and (string-match-p (rx bol "dav") method) - (string-match - (tramp-compat-rx bol (? "/") (+ (not "/"))) localname)) + (string-match (rx bol (? "/") (+ (not "/"))) localname)) (match-string 0 localname) (tramp-gvfs-get-remote-prefix vec)))) @@ -2212,7 +2186,7 @@ connection if a previous connection has died for some reason." (with-tramp-progress-reporter vec 3 - (if (zerop (length user)) + (if (tramp-string-empty-or-nil-p user) (format "Opening connection for %s using %s" host method) (format "Opening connection for %s@%s using %s" user host method)) @@ -2262,7 +2236,7 @@ connection if a previous connection has died for some reason." (with-timeout ((or (tramp-get-method-parameter vec 'tramp-connection-timeout) tramp-connection-timeout) - (if (zerop (length (tramp-file-name-user vec))) + (if (tramp-string-empty-or-nil-p (tramp-file-name-user vec)) (tramp-error vec 'file-error "Timeout reached mounting %s using %s" host method) @@ -2441,7 +2415,7 @@ VEC is used only for traces." ;; Adapt default host name, supporting /mtp:: when possible. (setq tramp-default-host-alist (append - `(("mtp" nil ,(if (= (length devices) 1) (car devices) ""))) + `(("mtp" nil ,(if (tramp-compat-length= devices 1) (car devices) ""))) (delete (assoc "mtp" tramp-default-host-alist) tramp-default-host-alist))))) @@ -2506,12 +2480,8 @@ This uses \"avahi-browse\" in case D-Bus is not enabled in Avahi." result)))) (when tramp-gvfs-enabled - (with-no-warnings ;; max-specpdl-size ;; Suppress D-Bus error messages and Tramp traces. - (let (;; Sometimes, it fails with "Variable binding depth exceeds - ;; max-specpdl-size". Shall be fixed in Emacs 27. - (max-specpdl-size (* 2 max-specpdl-size)) - (tramp-verbose 0) + (let ((tramp-verbose 0) tramp-gvfs-dbus-event-vector fun) ;; Add completion functions for services announced by DNS-SD. ;; See <http://www.dns-sd.org/ServiceTypes.html> for valid service types. @@ -2564,7 +2534,7 @@ This uses \"avahi-browse\" in case D-Bus is not enabled in Avahi." "mtp" (mapcar (lambda (method) `(tramp-parse-media-names ,(format "_%s._tcp" method))) - tramp-media-methods))))) + tramp-media-methods)))) (add-hook 'tramp-unload-hook (lambda () diff --git a/lisp/net/tramp-integration.el b/lisp/net/tramp-integration.el index cff0877555e..c7877c9824d 100644 --- a/lisp/net/tramp-integration.el +++ b/lisp/net/tramp-integration.el @@ -133,8 +133,7 @@ been set up by `rfn-eshadow-setup-minibuffer'." ;; Use `path-separator' as it does eshell. (setq eshell-path-env (if (file-remote-p default-directory) - (mapconcat - #'identity (butlast (tramp-compat-exec-path)) path-separator) + (mapconcat #'identity (butlast (exec-path)) path-separator) (getenv "PATH")))) (with-eval-after-load 'esh-util diff --git a/lisp/net/tramp-rclone.el b/lisp/net/tramp-rclone.el index 2360abfb1dd..9eb2a54cdcf 100644 --- a/lisp/net/tramp-rclone.el +++ b/lisp/net/tramp-rclone.el @@ -118,6 +118,7 @@ (file-symlink-p . tramp-handle-file-symlink-p) (file-system-info . tramp-rclone-handle-file-system-info) (file-truename . tramp-handle-file-truename) + (file-user-uid . tramp-handle-file-user-uid) (file-writable-p . tramp-handle-file-writable-p) (find-backup-file-name . tramp-handle-find-backup-file-name) ;; `get-file-buffer' performed by default handler. @@ -337,7 +338,7 @@ file names." (defun tramp-rclone-remote-file-name (filename) "Return FILENAME as used in the `rclone' command." - (setq filename (tramp-compat-file-name-unquote (expand-file-name filename))) + (setq filename (file-name-unquote (expand-file-name filename))) (if (tramp-rclone-file-name-p filename) (with-parsed-tramp-file-name filename nil ;; As long as we call `tramp-rclone-maybe-open-connection' here, @@ -361,7 +362,7 @@ connection if a previous connection has died for some reason." (let ((host (tramp-file-name-host vec))) (when (rassoc `(,host) (tramp-rclone-parse-device-names nil)) - (if (zerop (length host)) + (if (tramp-string-empty-or-nil-p host) (tramp-error vec 'file-error "Storage %s not connected" host)) ;; We need a process bound to the connection buffer. Therefore, ;; we create a dummy process. Maybe there is a better solution? diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index ec8437176db..48d91bd733e 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -411,7 +411,7 @@ The string is used in `tramp-methods'.") (add-to-list 'tramp-default-method-alist `(,tramp-local-host-regexp - ,(tramp-compat-rx bos (literal tramp-root-id-string) eos) "su")) + ,(rx bos (literal tramp-root-id-string) eos) "su")) (add-to-list 'tramp-default-user-alist `(,(rx bos (| "su" "sudo" "doas" "ksu") eos) @@ -1086,6 +1086,7 @@ Format specifiers \"%s\" are replaced before the script is used.") (file-symlink-p . tramp-handle-file-symlink-p) (file-system-info . tramp-sh-handle-file-system-info) (file-truename . tramp-sh-handle-file-truename) + (file-user-uid . tramp-handle-file-user-uid) (file-writable-p . tramp-sh-handle-file-writable-p) (find-backup-file-name . tramp-handle-find-backup-file-name) ;; `get-file-buffer' performed by default handler. @@ -1131,121 +1132,55 @@ Operations not mentioned here will be handled by the normal Emacs functions.") (defun tramp-sh-handle-make-symbolic-link (target linkname &optional ok-if-already-exists) - "Like `make-symbolic-link' for Tramp files. -If TARGET is a non-Tramp file, it is used verbatim as the target -of the symlink. If TARGET is a Tramp file, only the localname -component is used as the target of the symlink." - (with-parsed-tramp-file-name (expand-file-name linkname) nil - ;; If TARGET is a Tramp name, use just the localname component. - ;; Don't check for a proper method. - (let ((non-essential t)) - (when (and (tramp-tramp-file-p target) - (tramp-file-name-equal-p v (tramp-dissect-file-name target))) - (setq target (tramp-file-local-name (expand-file-name target)))) - ;; There could be a cyclic link. - (tramp-flush-file-properties - v (expand-file-name target (tramp-file-local-name default-directory)))) - - ;; If TARGET is still remote, quote it. - (if (tramp-tramp-file-p target) - (make-symbolic-link - (tramp-compat-file-name-quote target 'top) - linkname ok-if-already-exists) - - (let ((ln (tramp-get-remote-ln v)) - (cwd (tramp-run-real-handler - #'file-name-directory (list localname)))) - (unless ln - (tramp-error - v 'file-error - (concat "Making a symbolic link. " - "ln(1) does not exist on the remote host."))) - - ;; Do the 'confirm if exists' thing. - (when (file-exists-p linkname) - ;; What to do? - (if (or (null ok-if-already-exists) ; not allowed to exist - (and (numberp ok-if-already-exists) - (not - (yes-or-no-p - (format - "File %s already exists; make it a link anyway?" - localname))))) - (tramp-error v 'file-already-exists localname) - (delete-file linkname))) - - (tramp-flush-file-properties v localname) - - ;; Right, they are on the same host, regardless of user, - ;; method, etc. We now make the link on the remote machine. - ;; This will occur as the user that TARGET belongs to. - (and (tramp-send-command-and-check - v (format "cd %s" (tramp-shell-quote-argument cwd))) - (tramp-send-command-and-check - v (format - "%s -sf %s %s" ln - (tramp-shell-quote-argument target) - ;; The command could exceed PATH_MAX, so we use - ;; relative file names. However, relative file names - ;; could start with "-". - ;; `tramp-shell-quote-argument' does not handle this, - ;; we must do it ourselves. - (tramp-shell-quote-argument - (concat "./" (file-name-nondirectory localname)))))))))) + "Like `make-symbolic-link' for Tramp files." + (let ((v (tramp-dissect-file-name (expand-file-name linkname)))) + (unless (tramp-get-remote-ln v) + (tramp-error + v 'file-error + (concat "Making a symbolic link. " + "ln(1) does not exist on the remote host.")))) + + (tramp-skeleton-handle-make-symbolic-link target linkname ok-if-already-exists + (and (tramp-send-command-and-check + v (format + "cd %s" + (tramp-shell-quote-argument (file-name-directory localname)))) + (tramp-send-command-and-check + v (format + "%s -sf %s %s" (tramp-get-remote-ln v) + (tramp-shell-quote-argument target) + ;; The command could exceed PATH_MAX, so we use relative + ;; file names. + (tramp-shell-quote-argument + (concat "./" (file-name-nondirectory localname)))))))) (defun tramp-sh-handle-file-truename (filename) "Like `file-truename' for Tramp files." - ;; Preserve trailing "/". - (funcall - (if (directory-name-p filename) #'file-name-as-directory #'identity) - ;; Quote properly. - (funcall - (if (tramp-compat-file-name-quoted-p filename) - #'tramp-compat-file-name-quote #'identity) - (with-parsed-tramp-file-name - (tramp-compat-file-name-unquote (expand-file-name filename)) nil - (tramp-make-tramp-file-name - v - (with-tramp-file-property v localname "file-truename" - (tramp-message v 4 "Finding true name for `%s'" filename) - (let ((result - (cond - ;; Use GNU readlink --canonicalize-missing where available. - ((tramp-get-remote-readlink v) - (tramp-send-command-and-check - v (format "%s --canonicalize-missing %s" - (tramp-get-remote-readlink v) - (tramp-shell-quote-argument localname))) - (with-current-buffer (tramp-get-connection-buffer v) - (goto-char (point-min)) - (buffer-substring (point-min) (line-end-position)))) - - ;; Use Perl implementation. - ((and (tramp-get-remote-perl v) - (tramp-get-connection-property v "perl-file-spec") - (tramp-get-connection-property v "perl-cwd-realpath")) - (tramp-maybe-send-script - v tramp-perl-file-truename "tramp_perl_file_truename") - (tramp-send-command-and-read - v (format "tramp_perl_file_truename %s" - (tramp-shell-quote-argument localname)))) - - ;; Do it yourself. - (t (tramp-file-local-name - (tramp-handle-file-truename filename)))))) - - ;; Detect cycle. - (when (and (file-symlink-p filename) - (string-equal result localname)) - (tramp-error - v 'file-error - "Apparent cycle of symbolic links for %s" filename)) - ;; If the resulting localname looks remote, we must quote it - ;; for security reasons. - (when (file-remote-p result) - (setq result (tramp-compat-file-name-quote result 'top))) - (tramp-message v 4 "True name of `%s' is `%s'" localname result) - result))))))) + (tramp-skeleton-file-truename filename + (cond + ;; Use GNU readlink --canonicalize-missing where available. + ((tramp-get-remote-readlink v) + (tramp-send-command-and-check + v (format "%s --canonicalize-missing %s" + (tramp-get-remote-readlink v) + (tramp-shell-quote-argument localname))) + (with-current-buffer (tramp-get-connection-buffer v) + (goto-char (point-min)) + (buffer-substring (point-min) (line-end-position)))) + + ;; Use Perl implementation. + ((and (tramp-get-remote-perl v) + (tramp-get-connection-property v "perl-file-spec") + (tramp-get-connection-property v "perl-cwd-realpath")) + (tramp-maybe-send-script + v tramp-perl-file-truename "tramp_perl_file_truename") + (tramp-send-command-and-read + v (format "tramp_perl_file_truename %s" + (tramp-shell-quote-argument localname)))) + + ;; Do it yourself. + (t (tramp-file-local-name + (tramp-handle-file-truename filename)))))) ;; Basic functions. @@ -1438,7 +1373,7 @@ component is used as the target of the symlink." (modtime (or (file-attribute-modification-time attr) tramp-time-doesnt-exist))) (setq coding-system-used last-coding-system-used) - (if (not (tramp-compat-time-equal-p modtime tramp-time-dont-know)) + (if (not (time-equal-p modtime tramp-time-dont-know)) (tramp-run-real-handler #'set-visited-file-modtime (list modtime)) (progn (tramp-send-command @@ -1478,9 +1413,7 @@ of." (cond ;; File exists, and has a known modtime. - ((and attr - (not - (tramp-compat-time-equal-p modtime tramp-time-dont-know))) + ((and attr (not (time-equal-p modtime tramp-time-dont-know))) (< (abs (tramp-time-diff modtime mt)) 2)) ;; Modtime has the don't know value. (attr @@ -1497,7 +1430,7 @@ of." v localname "visited-file-modtime-ild" ""))) ;; If file does not exist, say it is not modified if and ;; only if that agrees with the buffer's record. - (t (tramp-compat-time-equal-p mt tramp-time-doesnt-exist))))))))) + (t (time-equal-p mt tramp-time-doesnt-exist))))))))) (defun tramp-sh-handle-set-file-modes (filename mode &optional flag) "Like `set-file-modes' for Tramp files." @@ -1519,21 +1452,17 @@ of." "Like `set-file-times' for Tramp files." (tramp-skeleton-set-file-modes-times-uid-gid filename (when (tramp-get-remote-touch v) - (let ((time - (if (or (null time) - (tramp-compat-time-equal-p time tramp-time-doesnt-exist) - (tramp-compat-time-equal-p time tramp-time-dont-know)) - nil - time))) - (tramp-send-command-and-check - v (format - "env TZ=UTC0 %s %s %s %s" - (tramp-get-remote-touch v) - (if (tramp-get-connection-property v "touch-t") - (format "-t %s" (format-time-string "%Y%m%d%H%M.%S" time t)) - "") - (if (eq flag 'nofollow) "-h" "") - (tramp-shell-quote-argument localname))))))) + (tramp-send-command-and-check + v (format + "env TZ=UTC0 %s %s %s %s" + (tramp-get-remote-touch v) + (if (tramp-get-connection-property v "touch-t") + (format + "-t %s" + (format-time-string "%Y%m%d%H%M.%S" (tramp-defined-time time) t)) + "") + (if (eq flag 'nofollow) "-h" "") + (tramp-shell-quote-argument localname)))))) (defun tramp-sh-handle-get-home-directory (vec &optional user) "The remote home directory for connection VEC as local file name. @@ -1631,7 +1560,7 @@ ID-FORMAT valid values are `string' and `integer'." (with-parsed-tramp-file-name (expand-file-name filename) nil (with-tramp-file-property v localname "file-selinux-context" (let ((context '(nil nil nil nil)) - (regexp (tramp-compat-rx + (regexp (rx (group (+ (any "_" alnum))) ":" (group (+ (any "_" alnum))) ":" (group (+ (any "_" alnum))) ":" @@ -1744,7 +1673,7 @@ ID-FORMAT valid values are `string' and `integer'." ;; Sometimes, when a connection is not established yet, it is ;; desirable to return t immediately for "/method:foo:". It can ;; be expected that this is always a directory. - (or (zerop (length localname)) + (or (tramp-string-empty-or-nil-p localname) (with-tramp-file-property v localname "file-directory-p" (if-let ((truename (tramp-get-file-property v localname "file-truename")) @@ -2357,7 +2286,7 @@ The method used must be an out-of-band method." copy-program copy-args copy-env copy-keep-date listener spec options source target remote-copy-program remote-copy-args p) - (if (and v1 v2 (zerop (length (tramp-scp-direct-remote-copying v1 v2)))) + (if (and v1 v2 (string-empty-p (tramp-scp-direct-remote-copying v1 v2))) ;; Both are Tramp files. We cannot use direct remote copying. (let* ((dir-flag (file-directory-p filename)) @@ -2389,10 +2318,10 @@ The method used must be an out-of-band method." #'identity) (if v1 (tramp-make-copy-program-file-name v1) - (tramp-compat-file-name-unquote filename))) + (file-name-unquote filename))) target (if v2 (tramp-make-copy-program-file-name v2) - (tramp-compat-file-name-unquote newname))) + (file-name-unquote newname))) ;; Check for listener port. (when (tramp-get-method-parameter v 'tramp-remote-copy-args) @@ -2436,7 +2365,7 @@ The method used must be an out-of-band method." ;; `tramp-ssh-controlmaster-options' is a string instead ;; of a list. Unflatten it. copy-args - (tramp-compat-flatten-tree + (flatten-tree (mapcar (lambda (x) (if (tramp-compat-string-search " " x) (split-string x) x)) @@ -2557,19 +2486,10 @@ The method used must be an out-of-band method." (defun tramp-sh-handle-make-directory (dir &optional parents) "Like `make-directory' for Tramp files." - (setq dir (expand-file-name dir)) - (with-parsed-tramp-file-name dir nil - (when (and (null parents) (file-exists-p dir)) - (tramp-error v 'file-already-exists dir)) - ;; When PARENTS is non-nil, DIR could be a chain of non-existent - ;; directories a/b/c/... Instead of checking, we simply flush the - ;; whole cache. - (tramp-flush-directory-properties - v (if parents "/" (file-name-directory localname))) + (tramp-skeleton-make-directory dir parents (tramp-barf-unless-okay v (format "%s -m %#o %s" - (if parents "mkdir -p" "mkdir") - (default-file-modes) + "mkdir" (default-file-modes) (tramp-shell-quote-argument localname)) "Couldn't make directory %s" dir))) @@ -2584,14 +2504,10 @@ The method used must be an out-of-band method." (defun tramp-sh-handle-delete-file (filename &optional trash) "Like `delete-file' for Tramp files." - (setq filename (expand-file-name (expand-file-name filename))) - (with-parsed-tramp-file-name filename nil - (if (and delete-by-moving-to-trash trash) - (move-file-to-trash filename) - (tramp-barf-unless-okay - v (format "rm -f %s" (tramp-shell-quote-argument localname)) - "Couldn't delete %s" filename)) - (tramp-flush-file-properties v localname))) + (tramp-skeleton-delete-file filename trash + (tramp-barf-unless-okay + v (format "rm -f %s" (tramp-shell-quote-argument localname)) + "Couldn't delete %s" filename))) ;; Dired. @@ -2705,9 +2621,9 @@ The method used must be an out-of-band method." (tramp-get-ls-command v) switches (if (or wildcard - (zerop (length - (tramp-run-real-handler - #'file-name-nondirectory (list localname))))) + (tramp-string-empty-or-nil-p + (tramp-run-real-handler + #'file-name-nondirectory (list localname)))) "" (tramp-shell-quote-argument (tramp-run-real-handler @@ -2824,14 +2740,14 @@ the result will be a local, non-Tramp, file name." ;; If DIR is not given, use `default-directory' or "/". (setq dir (or dir default-directory "/")) ;; Handle empty NAME. - (when (zerop (length name)) (setq name ".")) + (when (string-empty-p name) + (setq name ".")) ;; On MS Windows, some special file names are not returned properly ;; by `file-name-absolute-p'. If `tramp-syntax' is `simplified', ;; there could be the false positive "/:". (if (or (and (eq system-type 'windows-nt) (string-match-p - (tramp-compat-rx bol (| (: alpha ":") (: (literal null-device) eol))) - name)) + (rx bol (| (: alpha ":") (: (literal null-device) eol))) name)) (and (not (tramp-tramp-file-p name)) (not (tramp-tramp-file-p dir)))) (tramp-run-real-handler #'expand-file-name (list name dir)) @@ -2850,9 +2766,7 @@ the result will be a local, non-Tramp, file name." ;; supposed to find such a shell on the remote host. Please ;; tell me about it when this doesn't work on your system. (when (string-match - (tramp-compat-rx - bos "~" (group (* (not "/"))) (group (* nonl)) eos) - localname) + (rx bos "~" (group (* (not "/"))) (group (* nonl)) eos) localname) (let ((uname (match-string 1 localname)) (fname (match-string 2 localname)) hname) @@ -2862,7 +2776,7 @@ the result will be a local, non-Tramp, file name." ;; the default user name for tilde expansion is not ;; appropriate either, because ssh and companions might ;; use a user name from the config file. - (when (and (zerop (length uname)) + (when (and (tramp-string-empty-or-nil-p uname) (string-match-p (rx bos "su" (? "do") eos) method)) (setq uname user)) (when (setq hname (tramp-get-home-directory v uname)) @@ -2963,7 +2877,7 @@ implementation will be used." (heredoc (and (not (bufferp stderr)) (stringp program) (string-match-p (rx "sh" eol) program) - (= (length args) 2) + (tramp-compat-length= args 2) (string-equal "-c" (car args)) ;; Don't if there is a quoted string. (not @@ -2973,7 +2887,7 @@ implementation will be used." ;; When PROGRAM is nil, we just provide a tty. (args (if (not heredoc) args (let ((i 250)) - (while (and (< i (length (cadr args))) + (while (and (not (tramp-compat-length< (cadr args) i)) (string-match " " (cadr args) i)) (setcdr args @@ -3244,7 +3158,7 @@ implementation will be used." ;; Determine input. (if (null infile) (setq input (tramp-get-remote-null-device v)) - (setq infile (tramp-compat-file-name-unquote (expand-file-name infile))) + (setq infile (file-name-unquote (expand-file-name infile))) (if (tramp-equal-remote default-directory infile) ;; INFILE is on the same remote host. (setq input (tramp-unquote-file-local-name infile)) @@ -3925,7 +3839,7 @@ Fall back to normal file name handler if no Tramp handler exists." (setq string (tramp-compat-string-replace "\n\n" "\n" string)) (while (string-match - (tramp-compat-rx + (rx bol (+ (not ":")) ":" blank (group (+ (not ":"))) ":" blank (group (regexp (regexp-opt tramp-gio-events))) @@ -3955,7 +3869,7 @@ Fall back to normal file name handler if no Tramp handler exists." ;; Save rest of the string. (while (string-match (rx bol "\n") string) (setq string (replace-match "" nil nil string))) - (when (zerop (length string)) (setq string nil)) + (when (string-empty-p string) (setq string nil)) (when string (tramp-message proc 10 "Rest string:\n%s" string)) (process-put proc 'rest-string string))) @@ -3963,7 +3877,7 @@ Fall back to normal file name handler if no Tramp handler exists." "Read output from \"inotifywait\" and add corresponding `file-notify' events." (let ((events (process-get proc 'events))) (tramp-message proc 6 "%S\n%s" proc string) - (dolist (line (split-string string "[\n\r]+" 'omit)) + (dolist (line (split-string string (rx (+ (any "\r\n"))) 'omit)) ;; Check, whether there is a problem. (unless (string-match (rx bol (+ (not blank)) (+ blank) (group (+ (not blank))) @@ -4028,66 +3942,55 @@ commands. \"%n\" is replaced by \"2>/dev/null\", and \"%t\" is replaced by a temporary file name. If VEC is nil, the respective local commands are used. If there is a format specifier which cannot be expanded, this function returns nil." - (if (not (string-match-p - (tramp-compat-rx (| bol (not "%")) "%" (any "ahlnoprsty")) script)) + (if (not (string-match-p (rx (| bol (not "%")) "%" (any "ahlnoprsty")) script)) script (catch 'wont-work - (let ((awk (when (string-match-p - (tramp-compat-rx (| bol (not "%")) "%a") script) + (let ((awk (when (string-match-p (rx (| bol (not "%")) "%a") script) (or (if vec (tramp-get-remote-awk vec) (executable-find "awk")) (throw 'wont-work nil)))) - (hdmp (when (string-match-p - (tramp-compat-rx (| bol (not "%")) "%h") script) + (hdmp (when (string-match-p (rx (| bol (not "%")) "%h") script) (or (if vec (tramp-get-remote-hexdump vec) (executable-find "hexdump")) (throw 'wont-work nil)))) - (dev (when (string-match-p - (tramp-compat-rx (| bol (not "%")) "%n") script) + (dev (when (string-match-p (rx (| bol (not "%")) "%n") script) (or (if vec (concat "2>" (tramp-get-remote-null-device vec)) (if (eq system-type 'windows-nt) "" (concat "2>" null-device))) (throw 'wont-work nil)))) - (ls (when (string-match-p - (tramp-compat-rx (| bol (not "%")) "%l") script) + (ls (when (string-match-p (rx (| bol (not "%")) "%l") script) (format "%s %s" (or (tramp-get-ls-command vec) (throw 'wont-work nil)) (tramp-sh--quoting-style-options vec)))) - (od (when (string-match-p - (tramp-compat-rx (| bol (not "%")) "%o") script) + (od (when (string-match-p (rx (| bol (not "%")) "%o") script) (or (if vec (tramp-get-remote-od vec) (executable-find "od")) (throw 'wont-work nil)))) - (perl (when (string-match-p - (tramp-compat-rx (| bol (not "%")) "%p") script) + (perl (when (string-match-p (rx (| bol (not "%")) "%p") script) (or (if vec (tramp-get-remote-perl vec) (executable-find "perl")) (throw 'wont-work nil)))) - (python (when (string-match-p - (tramp-compat-rx (| bol (not "%")) "%y") script) - (or - (if vec - (tramp-get-remote-python vec) - (executable-find "python")) - (throw 'wont-work nil)))) - (readlink (when (string-match-p - (tramp-compat-rx (| bol (not "%")) "%r") script) + (python (when (string-match-p (rx (| bol (not "%")) "%y") script) + (or + (if vec + (tramp-get-remote-python vec) + (executable-find "python")) + (throw 'wont-work nil)))) + (readlink (when (string-match-p (rx (| bol (not "%")) "%r") script) (or (if vec - (tramp-get-remote-readlink vec) - (executable-find "readlink")) - (throw 'wont-work nil)))) - (stat (when (string-match-p - (tramp-compat-rx (| bol (not "%")) "%s") script) + (tramp-get-remote-readlink vec) + (executable-find "readlink")) + (throw 'wont-work nil)))) + (stat (when (string-match-p (rx (| bol (not "%")) "%s") script) (or (if vec (tramp-get-remote-stat vec) (executable-find "stat")) (throw 'wont-work nil)))) - (tmp (when (string-match-p - (tramp-compat-rx (| bol (not "%")) "%t") script) + (tmp (when (string-match-p (rx (| bol (not "%")) "%t") script) (or (if vec (tramp-file-local-name (tramp-make-tramp-temp-name vec)) @@ -4211,7 +4114,7 @@ variable PATH." 'noerror))) tmpfile chunk chunksize) (tramp-message vec 5 "Setting $PATH environment variable") - (if (< (length command) pipe-buf) + (if (tramp-compat-length< command pipe-buf) (tramp-send-command vec command) ;; Use a temporary file. We cannot use `write-region' because ;; setting the remote path happens in the early connection @@ -4348,8 +4251,7 @@ file exists and nonzero exit status otherwise." "Couldn't find remote shell prompt for %s" shell) (unless (tramp-check-for-regexp - (tramp-get-connection-process vec) - (tramp-compat-rx (literal tramp-end-of-output))) + (tramp-get-connection-process vec) (rx (literal tramp-end-of-output))) (tramp-wait-for-output (tramp-get-connection-process vec)) (tramp-message vec 5 "Setting shell prompt") (tramp-send-command @@ -4390,8 +4292,7 @@ file exists and nonzero exit status otherwise." (tramp-send-command vec (format "echo ~%s" tramp-root-id-string) t) (if (or (string-match-p - (tramp-compat-rx - bol "~" (literal tramp-root-id-string) eol) + (rx bol "~" (literal tramp-root-id-string) eol) (buffer-string)) ;; The default shell (ksh93) of OpenSolaris ;; and Solaris is buggy. We've got reports @@ -4430,7 +4331,7 @@ seconds. If not, it produces an error message with the given ERROR-ARGS." (condition-case nil (tramp-wait-for-regexp proc timeout - (tramp-compat-rx + (rx (| (regexp shell-prompt-pattern) (regexp tramp-shell-prompt-pattern)) eos)) (error @@ -4602,7 +4503,7 @@ process to set up. VEC specifies the connection." ;; Set `remote-tty' process property. (let ((tty (tramp-send-command-and-read vec "echo \\\"`tty`\\\"" 'noerror))) - (unless (zerop (length tty)) + (unless (string-empty-p tty) (process-put proc 'remote-tty tty) (tramp-set-connection-property proc "remote-tty" tty))) @@ -4817,7 +4718,7 @@ Goes through the list `tramp-local-coding-commands' and (with-current-buffer (tramp-get-connection-buffer vec) (goto-char (point-min)) - (unless (looking-at-p (tramp-compat-rx (literal magic))) + (unless (looking-at-p (rx (literal magic))) (throw 'wont-work-remote nil))) ;; `rem-enc' and `rem-dec' could be a string meanwhile. @@ -4903,7 +4804,7 @@ Goes through the list `tramp-inline-compress-commands'." nil t)) (throw 'next nil)) (goto-char (point-min)) - (unless (looking-at-p (tramp-compat-rx (literal magic))) + (unless (looking-at-p (rx (literal magic))) (throw 'next nil))) (tramp-message vec 5 @@ -4914,7 +4815,7 @@ Goes through the list `tramp-inline-compress-commands'." (throw 'next nil)) (with-current-buffer (tramp-get-buffer vec) (goto-char (point-min)) - (unless (looking-at-p (tramp-compat-rx (literal magic))) + (unless (looking-at-p (rx (literal magic))) (throw 'next nil))) (setq found t))) @@ -5175,7 +5076,7 @@ connection if a previous connection has died for some reason." (unless (process-live-p p) (with-tramp-progress-reporter vec 3 - (if (zerop (length (tramp-file-name-user vec))) + (if (tramp-string-empty-or-nil-p (tramp-file-name-user vec)) (format "Opening connection %s for %s using %s" process-name (tramp-file-name-host vec) @@ -5259,7 +5160,7 @@ connection if a previous connection has died for some reason." (tramp-get-method-parameter hop 'tramp-remote-shell)) (extra-args (tramp-get-sh-extra-args remote-shell)) (async-args - (tramp-compat-flatten-tree + (flatten-tree (tramp-get-method-parameter hop 'tramp-async-args))) (connection-timeout (tramp-get-method-parameter @@ -5403,7 +5304,7 @@ function waits for output unless NOOUTPUT is set." ;; Busyboxes built with the EDITING_ASK_TERMINAL config ;; option send also escape sequences, which must be ;; ignored. - (regexp (tramp-compat-rx + (regexp (rx (* (not (any "#$\n"))) (literal tramp-end-of-output) (? (regexp tramp-device-escape-sequence-regexp)) @@ -5411,7 +5312,7 @@ function waits for output unless NOOUTPUT is set." ;; Sometimes, the commands do not return a newline but a ;; null byte before the shell prompt, for example "git ;; ls-files -c -z ...". - (regexp1 (tramp-compat-rx (| bol "\000") (regexp regexp))) + (regexp1 (rx (| bol "\000") (regexp regexp))) (found (tramp-wait-for-regexp proc timeout regexp1))) (if found (let ((inhibit-read-only t)) @@ -5451,8 +5352,7 @@ the exit status." (let (cmd data) (if (and (stringp command) (string-match - (tramp-compat-rx - (* nonl) "<<'" (literal tramp-end-of-heredoc) "'" (* nonl)) + (rx (* nonl) "<<'" (literal tramp-end-of-heredoc) "'" (* nonl)) command)) (setq cmd (match-string 0 command) data (substring command (match-end 0))) @@ -5549,7 +5449,7 @@ raises an error." (cond ((tramp-get-method-parameter vec 'tramp-remote-copy-program) localname) - ((zerop (length user)) (format "%s:%s" host localname)) + ((tramp-string-empty-or-nil-p user) (format "%s:%s" host localname)) (t (format "%s@%s:%s" user host localname))))) (defun tramp-method-out-of-band-p (vec size) @@ -5622,7 +5522,7 @@ Nonexistent directories are removed from spec." (tramp-get-method-parameter vec 'tramp-remote-shell-args) " ") (tramp-shell-quote-argument tramp-end-of-heredoc)) - 'noerror (tramp-compat-rx (literal tramp-end-of-heredoc))) + 'noerror (rx (literal tramp-end-of-heredoc))) (progn (tramp-message vec 2 "Could not retrieve `tramp-own-remote-path'") @@ -5672,8 +5572,7 @@ Nonexistent directories are removed from spec." (while candidates (goto-char (point-min)) (if (string-match-p - (tramp-compat-rx bol (literal (car candidates)) (? "\r") eol) - (buffer-string)) + (rx bol (literal (car candidates)) (? "\r") eol) (buffer-string)) (setq locale (car candidates) candidates nil) (setq candidates (cdr candidates))))) @@ -5751,7 +5650,7 @@ Nonexistent directories are removed from spec." vec (format "( %s / -nt / )" (tramp-get-test-command vec))) (with-current-buffer (tramp-get-buffer vec) (goto-char (point-min)) - (when (looking-at-p (tramp-compat-rx (literal tramp-end-of-output))) + (when (looking-at-p (rx (literal tramp-end-of-output))) (format "%s %%s -nt %%s" (tramp-get-test-command vec))))) (progn (tramp-send-command @@ -5834,14 +5733,6 @@ Nonexistent directories are removed from spec." vec (format "%s --canonicalize-missing /" result))) result)))) -(defun tramp-get-remote-trash (vec) - "Determine remote `trash' command. -This command is returned only if `delete-by-moving-to-trash' is non-nil." - (and delete-by-moving-to-trash - (with-tramp-connection-property vec "trash" - (tramp-message vec 5 "Finding a suitable `trash' command") - (tramp-find-executable vec "trash" (tramp-get-remote-path vec))))) - (defun tramp-get-remote-touch (vec) "Determine remote `touch' command." (with-tramp-connection-property vec "touch" diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el index cad6cb335cc..b2272f804e0 100644 --- a/lisp/net/tramp-smb.el +++ b/lisp/net/tramp-smb.el @@ -53,7 +53,7 @@ ;;;###tramp-autoload (tramp--with-startup (add-to-list 'tramp-default-user-alist - `(,(tramp-compat-rx bos (literal tramp-smb-method) eos) nil nil)) + `(,(rx bos (literal tramp-smb-method) eos) nil nil)) ;; Add completion function for SMB method. (tramp-set-completion-function @@ -92,9 +92,9 @@ this variable \"client min protocol=NT1\"." "Version string of the SMB client.") (defconst tramp-smb-server-version - (tramp-compat-rx "Domain=[" (* (not "]")) "] " - "OS=[" (* (not "]")) "] " - "Server=[" (* (not "]")) "]") + (rx "Domain=[" (* (not "]")) "] " + "OS=[" (* (not "]")) "] " + "Server=[" (* (not "]")) "]") "Regexp of SMB server identification.") (defconst tramp-smb-prompt @@ -269,6 +269,7 @@ See `tramp-actions-before-shell' for more info.") (file-symlink-p . tramp-handle-file-symlink-p) (file-system-info . tramp-smb-handle-file-system-info) (file-truename . tramp-handle-file-truename) + (file-user-uid . tramp-handle-file-user-uid) (file-writable-p . tramp-smb-handle-file-writable-p) (find-backup-file-name . tramp-handle-find-backup-file-name) ;; `get-file-buffer' performed by default handler. @@ -487,9 +488,9 @@ arguments to pass to the OPERATION." (args (list (concat "//" host "/" share) "-E")) (options tramp-smb-options)) - (if (not (zerop (length user))) - (setq args (append args (list "-U" user))) - (setq args (append args (list "-N")))) + (if (tramp-string-empty-or-nil-p user) + (setq args (append args (list "-N"))) + (setq args (append args (list "-U" user)))) (when domain (setq args (append args (list "-W" domain)))) (when port (setq args (append args (list "-p" port)))) @@ -695,31 +696,25 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (defun tramp-smb-handle-delete-file (filename &optional trash) "Like `delete-file' for Tramp files." - (setq filename (expand-file-name filename)) - (when (file-exists-p filename) - (with-parsed-tramp-file-name filename nil - ;; We must also flush the cache of the directory, because - ;; `file-attributes' reads the values from there. - (tramp-flush-file-properties v localname) - (if (and delete-by-moving-to-trash trash) - (move-file-to-trash filename) - (unless (tramp-smb-send-command - v (format - "%s %s" - (if (tramp-smb-get-cifs-capabilities v) "posix_unlink" "rm") - (tramp-smb-shell-quote-localname v))) - ;; Error. - (with-current-buffer (tramp-get-connection-buffer v) - (goto-char (point-min)) - (search-forward-regexp tramp-smb-errors nil t) - (tramp-error v 'file-error "%s `%s'" (match-string 0) filename))))))) + (tramp-skeleton-delete-file filename trash + (unless (tramp-smb-send-command + v (format + "%s %s" + (if (tramp-smb-get-cifs-capabilities v) "posix_unlink" "rm") + (tramp-smb-shell-quote-localname v))) + ;; Error. + (with-current-buffer (tramp-get-connection-buffer v) + (goto-char (point-min)) + (search-forward-regexp tramp-smb-errors nil t) + (tramp-error v 'file-error "%s `%s'" (match-string 0) filename))))) (defun tramp-smb-handle-expand-file-name (name &optional dir) "Like `expand-file-name' for Tramp files." ;; If DIR is not given, use DEFAULT-DIRECTORY or "/". (setq dir (or dir default-directory "/")) ;; Handle empty NAME. - (when (zerop (length name)) (setq name ".")) + (when (string-empty-p name) + (setq name ".")) ;; Unless NAME is absolute, concat DIR and NAME. (unless (file-name-absolute-p name) (setq name (tramp-compat-file-name-concat dir name))) @@ -730,12 +725,11 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (with-parsed-tramp-file-name name nil ;; Tilde expansion if necessary. (when (string-match - (tramp-compat-rx bos "~" (group (* (not "/"))) (group (* nonl)) eos) - localname) + (rx bos "~" (group (* (not "/"))) (group (* nonl)) eos) localname) (let ((uname (match-string 1 localname)) (fname (match-string 2 localname)) hname) - (when (zerop (length uname)) + (when (tramp-string-empty-or-nil-p uname) (setq uname user)) (when (setq hname (tramp-get-home-directory v uname)) (setq localname (concat hname fname))))) @@ -789,9 +783,9 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (args (list (concat "//" host "/" share) "-E")) (options tramp-smb-options)) - (if (not (zerop (length user))) - (setq args (append args (list "-U" user))) - (setq args (append args (list "-N")))) + (if (tramp-string-empty-or-nil-p user) + (setq args (append args (list "-N"))) + (setq args (append args (list "-U" user)))) (when domain (setq args (append args (list "-W" domain)))) (when port (setq args (append args (list "-p" port)))) @@ -1079,12 +1073,11 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (setq entries (delq nil - (if (or wildcard (zerop (length base))) + (if (or wildcard (string-empty-p base)) ;; Check for matching entries. (mapcar (lambda (x) - (when (string-match-p - (tramp-compat-rx bol (literal base)) (nth 0 x)) + (when (string-match-p (rx bol (literal base)) (nth 0 x)) x)) entries) ;; We just need the only and only entry FILENAME. @@ -1105,7 +1098,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (when (tramp-compat-string-search "F" switches) (mapc (lambda (x) - (unless (zerop (length (car x))) + (unless (string-empty-p (car x)) (cond ((char-equal ?d (string-to-char (nth 1 x))) (setcar x (concat (car x) "/"))) @@ -1125,7 +1118,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." ;; Print entries. (mapc (lambda (x) - (unless (zerop (length (nth 0 x))) + (unless (string-empty-p (nth 0 x)) (let ((attr (when (tramp-smb-get-stat-capability v) (ignore-errors @@ -1172,98 +1165,31 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (defun tramp-smb-handle-make-directory (dir &optional parents) "Like `make-directory' for Tramp files." - (setq dir (directory-file-name (expand-file-name dir))) - (unless (file-name-absolute-p dir) - (setq dir (expand-file-name dir default-directory))) - (with-parsed-tramp-file-name dir nil - (when (and (null parents) (file-exists-p dir)) - (tramp-error v 'file-already-exists dir)) - (let* ((ldir (file-name-directory dir))) - ;; Make missing directory parts. - (when (and parents - (tramp-smb-get-share v) - (not (file-directory-p ldir))) - (make-directory ldir parents)) - ;; Just do it. - (when (file-directory-p ldir) - (tramp-smb-send-command - v (if (tramp-smb-get-cifs-capabilities v) - (format "posix_mkdir %s %o" - (tramp-smb-shell-quote-localname v) (default-file-modes)) - (format "mkdir %s" (tramp-smb-shell-quote-localname v)))) - ;; We must also flush the cache of the directory, because - ;; `file-attributes' reads the values from there. - (tramp-flush-file-properties v localname)) - (unless (file-directory-p dir) - (tramp-error v 'file-error "Couldn't make directory %s" dir))))) - -;; This is not used anymore. -(defun tramp-smb-handle-make-directory-internal (directory) - "Like `make-directory-internal' for Tramp files." - (declare (obsolete nil "29.1")) - (setq directory (directory-file-name (expand-file-name directory))) - (unless (file-name-absolute-p directory) - (setq directory (expand-file-name directory default-directory))) - (with-parsed-tramp-file-name directory nil - (when (file-directory-p (file-name-directory directory)) - (tramp-smb-send-command - v (if (tramp-smb-get-cifs-capabilities v) - (format "posix_mkdir %s %o" - (tramp-smb-shell-quote-localname v) (default-file-modes)) - (format "mkdir %s" (tramp-smb-shell-quote-localname v)))) - ;; We must also flush the cache of the directory, because - ;; `file-attributes' reads the values from there. - (tramp-flush-file-properties v localname)) - (unless (file-directory-p directory) - (tramp-error v 'file-error "Couldn't make directory %s" directory)))) + (tramp-skeleton-make-directory dir parents + (tramp-smb-send-command + v (if (tramp-smb-get-cifs-capabilities v) + (format "posix_mkdir %s %o" + (tramp-smb-shell-quote-localname v) (default-file-modes)) + (format "mkdir %s" (tramp-smb-shell-quote-localname v)))) + (unless (file-directory-p dir) + (tramp-error v 'file-error "Couldn't make directory %s" dir)))) (defun tramp-smb-handle-make-symbolic-link - (target linkname &optional ok-if-already-exists) - "Like `make-symbolic-link' for Tramp files. -If TARGET is a non-Tramp file, it is used verbatim as the target -of the symlink. If TARGET is a Tramp file, only the localname -component is used as the target of the symlink." - (with-parsed-tramp-file-name linkname nil - ;; If TARGET is a Tramp name, use just the localname component. - ;; Don't check for a proper method. - (let ((non-essential t)) - (when (and (tramp-tramp-file-p target) - (tramp-file-name-equal-p v (tramp-dissect-file-name target))) - (setq target (tramp-file-local-name (expand-file-name target))))) - - ;; If TARGET is still remote, quote it. - (if (tramp-tramp-file-p target) - (make-symbolic-link - (tramp-compat-file-name-quote target 'top) - linkname ok-if-already-exists) - - ;; Do the 'confirm if exists' thing. - (when (file-exists-p linkname) - ;; What to do? - (if (or (null ok-if-already-exists) ; not allowed to exist - (and (numberp ok-if-already-exists) - (not (yes-or-no-p - (format - "File %s already exists; make it a link anyway?" - localname))))) - (tramp-error v 'file-already-exists localname) - (delete-file linkname))) - - (unless (tramp-smb-get-cifs-capabilities v) - (tramp-error v 'file-error "make-symbolic-link not supported")) - - ;; We must also flush the cache of the directory, because - ;; `file-attributes' reads the values from there. - (tramp-flush-file-properties v localname) - - (unless (tramp-smb-send-command - v (format "symlink %s %s" - (tramp-smb-shell-quote-argument target) - (tramp-smb-shell-quote-localname v))) - (tramp-error - v 'file-error - "error with make-symbolic-link, see buffer `%s' for details" - (tramp-get-connection-buffer v)))))) + (target linkname &optional ok-if-already-exists) + "Like `make-symbolic-link' for Tramp files." + (let ((v (tramp-dissect-file-name (expand-file-name linkname)))) + (unless (tramp-smb-get-cifs-capabilities v) + (tramp-error v 'file-error "make-symbolic-link not supported"))) + + (tramp-skeleton-handle-make-symbolic-link target linkname ok-if-already-exists + (unless (tramp-smb-send-command + v (format "symlink %s %s" + (tramp-smb-shell-quote-argument target) + (tramp-smb-shell-quote-localname v))) + (tramp-error + v 'file-error + "error with make-symbolic-link, see buffer `%s' for details" + (tramp-get-connection-buffer v))))) (defun tramp-smb-handle-process-file (program &optional infile destination display &rest args) @@ -1280,7 +1206,7 @@ component is used as the target of the symlink." ;; Determine input. (when infile - (setq infile (tramp-compat-file-name-unquote (expand-file-name infile))) + (setq infile (file-name-unquote (expand-file-name infile))) (if (tramp-equal-remote default-directory infile) ;; INFILE is on the same remote host. (setq input (tramp-unquote-file-local-name infile)) @@ -1455,9 +1381,9 @@ component is used as the target of the symlink." "\n" "," acl-string))) (options tramp-smb-options)) - (if (not (zerop (length user))) - (setq args (append args (list "-U" user))) - (setq args (append args (list "-N")))) + (if (tramp-string-empty-or-nil-p user) + (setq args (append args (list "-N"))) + (setq args (append args (list "-U" user)))) (when domain (setq args (append args (list "-W" domain)))) (when port (setq args (append args (list "-p" port)))) @@ -1588,7 +1514,7 @@ component is used as the target of the symlink." \"//\" substitutes only in the local filename part. Catches errors for shares like \"C$/\", which are common in Microsoft Windows." ;; Check, whether the local part is a quoted file name. - (if (tramp-compat-file-name-quoted-p filename) + (if (file-name-quoted-p filename) filename (with-parsed-tramp-file-name filename nil ;; Ignore in LOCALNAME everything before "//". @@ -1607,7 +1533,7 @@ If USER is a string, return its home directory instead of the user identified by VEC. If there is no user specified in either VEC or USER, or if there is no home directory, return nil." (let ((user (or user (tramp-file-name-user vec)))) - (unless (zerop (length user)) + (unless (tramp-string-empty-or-nil-p user) (concat "/" user)))) (defun tramp-smb-handle-write-region @@ -1639,8 +1565,7 @@ VEC or USER, or if there is no home directory, return nil." "Return the share name of LOCALNAME." (save-match-data (let ((localname (tramp-file-name-unquote-localname vec))) - (when (string-match - (tramp-compat-rx bol (? "/") (group (+ (not "/"))) "/") localname) + (when (string-match (rx bol (? "/") (group (+ (not "/"))) "/") localname) (match-string 1 localname))))) (defun tramp-smb-get-localname (vec) @@ -1651,8 +1576,7 @@ If VEC has no cifs capabilities, exchange \"/\" by \"\\\\\"." (setq localname (if (string-match - (tramp-compat-rx bol (? "/") (+ (not "/")) (group "/" (* nonl))) - localname) + (rx bol (? "/") (+ (not "/")) (group "/" (* nonl))) localname) ;; There is a share, separated by "/". (if (not (tramp-smb-get-cifs-capabilities vec)) (mapconcat @@ -1660,8 +1584,7 @@ If VEC has no cifs capabilities, exchange \"/\" by \"\\\\\"." (match-string 1 localname) "") (match-string 1 localname)) ;; There is just a share. - (if (string-match - (tramp-compat-rx bol (? "/") (group (+ (not "/"))) eol) localname) + (if (string-match (rx bol (? "/") (group (+ (not "/"))) eol) localname) (match-string 1 localname) ""))) @@ -1789,8 +1712,7 @@ are listed. Result is the list (LOCALNAME MODE SIZE MTIME)." (if (not share) ;; Read share entries. - (when (string-match - (tramp-compat-rx bol "Disk|" (group (+ (not "|"))) "|") line) + (when (string-match (rx bol "Disk|" (group (+ (not "|"))) "|") line) (setq localname (match-string 1 line) mode "dr-xr-xr-x" size 0)) @@ -1956,7 +1878,7 @@ If ARGUMENT is non-nil, use it as argument for (setq tramp-smb-version (shell-command-to-string command)) (tramp-message vec 6 command) (tramp-message vec 6 "\n%s" tramp-smb-version) - (if (string-match (rx (+ (any " \t\n\r")) eos) tramp-smb-version) + (if (string-match (rx (+ (any " \t\r\n")) eos) tramp-smb-version) (setq tramp-smb-version (replace-match "" nil nil tramp-smb-version)))) @@ -2009,9 +1931,9 @@ If ARGUMENT is non-nil, use it as argument for (t (setq args (list "-g" "-L" host )))) - (if (not (zerop (length user))) - (setq args (append args (list "-U" user))) - (setq args (append args (list "-N")))) + (if (tramp-string-empty-or-nil-p user) + (setq args (append args (list "-N"))) + (setq args (append args (list "-U" user)))) (when domain (setq args (append args (list "-W" domain)))) (when port (setq args (append args (list "-p" port)))) @@ -2026,7 +1948,8 @@ If ARGUMENT is non-nil, use it as argument for (with-tramp-progress-reporter vec 3 (format "Opening connection for //%s%s/%s" - (if (not (zerop (length user))) (concat user "@") "") + (if (tramp-string-empty-or-nil-p user) + "" (concat user "@")) host (or share "")) (let* (coding-system-for-read diff --git a/lisp/net/tramp-sshfs.el b/lisp/net/tramp-sshfs.el index 2d3c436632f..65c4bf23c38 100644 --- a/lisp/net/tramp-sshfs.el +++ b/lisp/net/tramp-sshfs.el @@ -124,6 +124,7 @@ (file-symlink-p . tramp-handle-file-symlink-p) (file-system-info . tramp-sshfs-handle-file-system-info) (file-truename . tramp-handle-file-truename) + (file-user-uid . tramp-handle-file-user-uid) (file-writable-p . tramp-sshfs-handle-file-writable-p) (find-backup-file-name . tramp-handle-find-backup-file-name) ;; `get-file-buffer' performed by default handler. @@ -228,8 +229,7 @@ arguments to pass to the OPERATION." (defun tramp-sshfs-handle-file-system-info (filename) "Like `file-system-info' for Tramp files." - ;;`file-system-info' exists since Emacs 27.1. - (tramp-compat-funcall 'file-system-info (tramp-fuse-local-file-name filename))) + (file-system-info (tramp-fuse-local-file-name filename))) (defun tramp-sshfs-handle-file-writable-p (filename) "Like `file-writable-p' for Tramp files." @@ -266,7 +266,7 @@ arguments to pass to the OPERATION." ;; Determine input. (if (null infile) (setq input (tramp-get-remote-null-device v)) - (setq infile (tramp-compat-file-name-unquote (expand-file-name infile))) + (setq infile (file-name-unquote (expand-file-name infile))) (if (tramp-equal-remote default-directory infile) ;; INFILE is on the same remote host. (setq input (tramp-unquote-file-local-name infile)) diff --git a/lisp/net/tramp-sudoedit.el b/lisp/net/tramp-sudoedit.el index 88dacdc7893..1f646253579 100644 --- a/lisp/net/tramp-sudoedit.el +++ b/lisp/net/tramp-sudoedit.el @@ -49,7 +49,7 @@ (tramp-password-previous-hop t))) (add-to-list 'tramp-default-user-alist - `(,(tramp-compat-rx bos (literal tramp-sudoedit-method) eos) + `(,(rx bos (literal tramp-sudoedit-method) eos) nil ,tramp-root-id-string)) (tramp-set-completion-function @@ -114,6 +114,7 @@ See `tramp-actions-before-shell' for more info.") (file-symlink-p . tramp-handle-file-symlink-p) (file-system-info . tramp-sudoedit-handle-file-system-info) (file-truename . tramp-sudoedit-handle-file-truename) + (file-user-uid . tramp-handle-file-user-uid) (file-writable-p . tramp-sudoedit-handle-file-writable-p) (find-backup-file-name . tramp-handle-find-backup-file-name) ;; `get-file-buffer' performed by default handler. @@ -212,8 +213,8 @@ arguments to pass to the OPERATION." (unless (tramp-sudoedit-send-command v1 "ln" - (tramp-compat-file-name-unquote v1-localname) - (tramp-compat-file-name-unquote v2-localname)) + (file-name-unquote v1-localname) + (file-name-unquote v2-localname)) (tramp-error v1 'file-error "error with add-name-to-file, see buffer `%s' for details" @@ -342,22 +343,19 @@ absolute file names." (tramp-skeleton-delete-directory directory recursive trash (unless (tramp-sudoedit-send-command v (if recursive '("rm" "-rf") "rmdir") - (tramp-compat-file-name-unquote localname)) + (file-name-unquote localname)) (tramp-error v 'file-error "Couldn't delete %s" directory)))) (defun tramp-sudoedit-handle-delete-file (filename &optional trash) "Like `delete-file' for Tramp files." - (with-parsed-tramp-file-name (expand-file-name filename) nil - (tramp-flush-file-properties v localname) - (if (and delete-by-moving-to-trash trash) - (move-file-to-trash filename) - (unless (tramp-sudoedit-send-command - v "rm" "-f" (tramp-compat-file-name-unquote localname)) - ;; Propagate the error. - (with-current-buffer (tramp-get-connection-buffer v) - (goto-char (point-min)) - (tramp-error-with-buffer - nil v 'file-error "Couldn't delete %s" filename)))))) + (tramp-skeleton-delete-file filename trash + (unless (tramp-sudoedit-send-command + v "rm" "-f" (file-name-unquote localname)) + ;; Propagate the error. + (with-current-buffer (tramp-get-connection-buffer v) + (goto-char (point-min)) + (tramp-error-with-buffer + nil v 'file-error "Couldn't delete %s" filename))))) (defun tramp-sudoedit-handle-expand-file-name (name &optional dir) "Like `expand-file-name' for Tramp files. @@ -366,7 +364,8 @@ the result will be a local, non-Tramp, file name." ;; If DIR is not given, use `default-directory' or "/". (setq dir (or dir default-directory "/")) ;; Handle empty NAME. - (when (zerop (length name)) (setq name ".")) + (when (string-empty-p name) + (setq name ".")) ;; Unless NAME is absolute, concat DIR and NAME. (unless (file-name-absolute-p name) (setq name (tramp-compat-file-name-concat dir name))) @@ -377,17 +376,16 @@ the result will be a local, non-Tramp, file name." ;; Tilde expansion if necessary. We cannot accept "~/", because ;; under sudo "~/" is expanded to the local user home directory ;; but to the root home directory. - (when (zerop (length localname)) + (when (tramp-string-empty-or-nil-p localname) (setq localname "~")) (unless (file-name-absolute-p localname) (setq localname (format "~%s/%s" user localname))) (when (string-match - (tramp-compat-rx bos "~" (group (* (not "/"))) (group (* nonl)) eos) - localname) + (rx bos "~" (group (* (not "/"))) (group (* nonl)) eos) localname) (let ((uname (match-string 1 localname)) (fname (match-string 2 localname)) hname) - (when (zerop (length uname)) + (when (tramp-string-empty-or-nil-p uname) (setq uname user)) (when (setq hname (tramp-get-home-directory v uname)) (setq localname (concat hname fname))))) @@ -413,7 +411,7 @@ the result will be a local, non-Tramp, file name." (let ((result (and (tramp-sudoedit-remote-acl-p v) (tramp-sudoedit-send-command-string v "getfacl" "-acp" - (tramp-compat-file-name-unquote localname))))) + (file-name-unquote localname))))) ;; The acl string must have a trailing \n, which is not ;; provided by `tramp-sudoedit-send-command-string'. Add it. (and (stringp result) (concat result "\n")))))) @@ -440,8 +438,7 @@ the result will be a local, non-Tramp, file name." (tramp-convert-file-attributes v localname id-format (tramp-sudoedit-send-command-and-read v "env" "QUOTING_STYLE=locale" "stat" "-c" - tramp-sudoedit-file-attributes - (tramp-compat-file-name-unquote localname))))) + tramp-sudoedit-file-attributes (file-name-unquote localname))))) (defun tramp-sudoedit-handle-file-executable-p (filename) "Like `file-executable-p' for Tramp files." @@ -453,7 +450,7 @@ the result will be a local, non-Tramp, file name." (or (tramp-check-cached-permissions v ?x) (tramp-check-cached-permissions v ?s)) (tramp-sudoedit-send-command - v "test" "-x" (tramp-compat-file-name-unquote localname)))))) + v "test" "-x" (file-name-unquote localname)))))) (defun tramp-sudoedit-handle-file-exists-p (filename) "Like `file-exists-p' for Tramp files." @@ -466,7 +463,7 @@ the result will be a local, non-Tramp, file name." (if (tramp-file-property-p v localname "file-attributes") (not (null (tramp-get-file-property v localname "file-attributes"))) (tramp-sudoedit-send-command - v "test" "-e" (tramp-compat-file-name-unquote localname))))))) + v "test" "-e" (file-name-unquote localname))))))) (defun tramp-sudoedit-handle-file-name-all-completions (filename directory) "Like `file-name-all-completions' for Tramp files." @@ -476,11 +473,11 @@ the result will be a local, non-Tramp, file name." (with-tramp-file-property v localname "file-name-all-completions" (tramp-sudoedit-send-command v "ls" "-a1" "--quoting-style=literal" "--show-control-chars" - (if (zerop (length localname)) - "" (tramp-compat-file-name-unquote localname))) + (if (tramp-string-empty-or-nil-p localname) + "" (file-name-unquote localname))) (mapcar (lambda (f) - (if (file-directory-p (expand-file-name f directory)) + (if (ignore-errors (file-directory-p (expand-file-name f directory))) (file-name-as-directory f) f)) (delq @@ -500,7 +497,7 @@ the result will be a local, non-Tramp, file name." (if (tramp-file-property-p v localname "file-attributes") (tramp-handle-file-readable-p filename) (tramp-sudoedit-send-command - v "test" "-r" (tramp-compat-file-name-unquote localname)))))) + v "test" "-r" (file-name-unquote localname)))))) (defun tramp-sudoedit-handle-set-file-modes (filename mode &optional flag) "Like `set-file-modes' for Tramp files." @@ -508,8 +505,7 @@ the result will be a local, non-Tramp, file name." (unless (and (eq flag 'nofollow) (file-symlink-p filename)) (tramp-skeleton-set-file-modes-times-uid-gid filename (unless (tramp-sudoedit-send-command - v "chmod" (format "%o" mode) - (tramp-compat-file-name-unquote localname)) + v "chmod" (format "%o" mode) (file-name-unquote localname)) (tramp-error v 'file-error "Error while changing file's mode %s" filename))))) @@ -523,15 +519,14 @@ the result will be a local, non-Tramp, file name." (with-parsed-tramp-file-name (expand-file-name filename) nil (with-tramp-file-property v localname "file-selinux-context" (let ((context '(nil nil nil nil)) - (regexp (tramp-compat-rx + (regexp (rx (group (+ (any "_" alnum))) ":" (group (+ (any "_" alnum))) ":" (group (+ (any "_" alnum))) ":" (group (+ (any "_" alnum)))))) (when (and (tramp-sudoedit-remote-selinux-p v) (tramp-sudoedit-send-command - v "ls" "-d" "-Z" - (tramp-compat-file-name-unquote localname))) + v "ls" "-d" "-Z" (file-name-unquote localname))) (with-current-buffer (tramp-get-connection-buffer v) (goto-char (point-min)) (when (re-search-forward regexp (line-end-position) t) @@ -547,7 +542,7 @@ the result will be a local, non-Tramp, file name." (tramp-message v 5 "file system info: %s" localname) (when (tramp-sudoedit-send-command v "df" "--block-size=1" "--output=size,used,avail" - (tramp-compat-file-name-unquote localname)) + (file-name-unquote localname)) (with-current-buffer (tramp-get-connection-buffer v) (goto-char (point-min)) (forward-line) @@ -565,48 +560,17 @@ the result will be a local, non-Tramp, file name." (defun tramp-sudoedit-handle-set-file-times (filename &optional time flag) "Like `set-file-times' for Tramp files." (tramp-skeleton-set-file-modes-times-uid-gid filename - (let ((time - (if (or (null time) - (tramp-compat-time-equal-p time tramp-time-doesnt-exist) - (tramp-compat-time-equal-p time tramp-time-dont-know)) - nil - time))) - (tramp-sudoedit-send-command - v "env" "TZ=UTC0" "touch" "-t" - (format-time-string "%Y%m%d%H%M.%S" time t) - (if (eq flag 'nofollow) "-h" "") - (tramp-compat-file-name-unquote localname))))) + (tramp-sudoedit-send-command + v "env" "TZ=UTC0" "touch" "-t" + (format-time-string "%Y%m%d%H%M.%S" (tramp-defined-time time) t) + (if (eq flag 'nofollow) "-h" "") + (file-name-unquote localname)))) (defun tramp-sudoedit-handle-file-truename (filename) "Like `file-truename' for Tramp files." - ;; Preserve trailing "/". - (funcall - (if (directory-name-p filename) #'file-name-as-directory #'identity) - ;; Quote properly. - (funcall - (if (tramp-compat-file-name-quoted-p filename) - #'tramp-compat-file-name-quote #'identity) - (with-parsed-tramp-file-name - (tramp-compat-file-name-unquote (expand-file-name filename)) nil - (tramp-make-tramp-file-name - v - (with-tramp-file-property v localname "file-truename" - (let (result) - (tramp-message v 4 "Finding true name for `%s'" filename) - (setq result (tramp-sudoedit-send-command-string - v "readlink" "--canonicalize-missing" localname)) - ;; Detect cycle. - (when (and (file-symlink-p filename) - (string-equal result localname)) - (tramp-error - v 'file-error - "Apparent cycle of symbolic links for %s" filename)) - ;; If the resulting localname looks remote, we must quote it - ;; for security reasons. - (when (file-remote-p result) - (setq result (tramp-compat-file-name-quote result 'top))) - (tramp-message v 4 "True name of `%s' is `%s'" localname result) - result))))))) + (tramp-skeleton-file-truename filename + (tramp-sudoedit-send-command-string + v "readlink" "--canonicalize-missing" localname))) (defun tramp-sudoedit-handle-file-writable-p (filename) "Like `file-writable-p' for Tramp files." @@ -618,7 +582,7 @@ the result will be a local, non-Tramp, file name." ;; be satisfied without remote operation. (tramp-check-cached-permissions v ?w) (tramp-sudoedit-send-command - v "test" "-w" (tramp-compat-file-name-unquote localname))) + v "test" "-w" (file-name-unquote localname))) ;; If file doesn't exist, check if directory is writable. (and (file-directory-p (file-name-directory filename)) @@ -626,59 +590,20 @@ the result will be a local, non-Tramp, file name." (defun tramp-sudoedit-handle-make-directory (dir &optional parents) "Like `make-directory' for Tramp files." - (setq dir (expand-file-name dir)) - (with-parsed-tramp-file-name dir nil - (when (and (null parents) (file-exists-p dir)) - (tramp-error v 'file-already-exists "Directory already exists %s" dir)) - ;; When PARENTS is non-nil, DIR could be a chain of non-existent - ;; directories a/b/c/... Instead of checking, we simply flush the - ;; whole cache. - (tramp-flush-directory-properties - v (if parents "/" (file-name-directory localname))) + (tramp-skeleton-make-directory dir parents (unless (tramp-sudoedit-send-command - v (if parents '("mkdir" "-p") "mkdir") - "-m" (format "%#o" (default-file-modes)) - (tramp-compat-file-name-unquote localname)) + v "mkdir" "-m" (format "%#o" (default-file-modes)) + (file-name-unquote localname)) (tramp-error v 'file-error "Couldn't make directory %s" dir)))) (defun tramp-sudoedit-handle-make-symbolic-link (target linkname &optional ok-if-already-exists) - "Like `make-symbolic-link' for Tramp files. -If TARGET is a non-Tramp file, it is used verbatim as the target -of the symlink. If TARGET is a Tramp file, only the localname -component is used as the target of the symlink." - (with-parsed-tramp-file-name (expand-file-name linkname) nil - ;; If TARGET is a Tramp name, use just the localname component. - ;; Don't check for a proper method. - (let ((non-essential t)) - (when (and (tramp-tramp-file-p target) - (tramp-file-name-equal-p v (tramp-dissect-file-name target))) - (setq target (tramp-file-local-name (expand-file-name target))))) - - ;; If TARGET is still remote, quote it. - (if (tramp-tramp-file-p target) - (make-symbolic-link - (tramp-compat-file-name-quote target 'top) - linkname ok-if-already-exists) - - ;; Do the 'confirm if exists' thing. - (when (file-exists-p linkname) - ;; What to do? - (if (or (null ok-if-already-exists) ; not allowed to exist - (and (numberp ok-if-already-exists) - (not - (yes-or-no-p - (format - "File %s already exists; make it a link anyway?" - localname))))) - (tramp-error v 'file-already-exists localname) - (delete-file linkname))) - - (tramp-flush-file-properties v localname) - (tramp-sudoedit-send-command - v "ln" "-sf" - (tramp-compat-file-name-unquote target) - (tramp-compat-file-name-unquote localname))))) + "Like `make-symbolic-link' for Tramp files." + (tramp-skeleton-handle-make-symbolic-link target linkname ok-if-already-exists + (tramp-sudoedit-send-command + v "ln" "-sf" + (file-name-unquote target) + (file-name-unquote localname)))) (defun tramp-sudoedit-handle-rename-file (filename newname &optional ok-if-already-exists) @@ -702,8 +627,7 @@ component is used as the target of the symlink." (setq acl-string (string-join (split-string acl-string "\n" 'omit) ",")) (prog1 (tramp-sudoedit-send-command - v "setfacl" "-m" - acl-string (tramp-compat-file-name-unquote localname)) + v "setfacl" "-m" acl-string (file-name-unquote localname)) (tramp-flush-file-property v localname "file-acl"))))) (defun tramp-sudoedit-handle-set-file-selinux-context (filename context) @@ -721,7 +645,7 @@ component is used as the target of the symlink." (when role (format "--role=%s" role)) (when type (format "--type=%s" type)) (when range (format "--range=%s" range)) - (tramp-compat-file-name-unquote localname)) + (file-name-unquote localname)) (if (and user role type range) (tramp-set-file-property v localname "file-selinux-context" context) @@ -829,7 +753,7 @@ in case of error, t otherwise." vec 'tramp-sudo-login ?h (or (tramp-file-name-host vec) "") ?u (or (tramp-file-name-user vec) "")) - (tramp-compat-flatten-tree args)))) + (flatten-tree args)))) ;; We suppress the messages `Waiting for prompts from remote shell'. (tramp-verbose (if (= tramp-verbose 3) 2 tramp-verbose)) ;; The password shall be cached also in case of "emacs -Q". diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index eaddc36b54a..21dbd40b1d2 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -82,6 +82,7 @@ (progn (defvar tramp--startup-hook nil "Forms to be executed at the end of tramp.el.") + (put 'tramp--startup-hook 'tramp-suppress-trace t) (defmacro tramp--with-startup (&rest body) @@ -443,9 +444,7 @@ See `tramp-methods' for a list of possibilities for METHOD." (defcustom tramp-default-user nil "Default user to use for transferring files. It is nil by default; otherwise settings in configuration files like -\"~/.ssh/config\" would be overwritten. Also see `tramp-default-user-alist'. - -This variable is regarded as obsolete, and will be removed soon." +\"~/.ssh/config\" would be overwritten. Also see `tramp-default-user-alist'." :type '(choice (const nil) string)) ;;;###tramp-autoload @@ -525,7 +524,7 @@ interpreted as a regular expression which always matches." (defcustom tramp-restricted-shell-hosts-alist (when (and (eq system-type 'windows-nt) (not (string-match-p (rx "sh" eol) tramp-encoding-shell))) - (list (tramp-compat-rx + (list (rx bos (| (literal (downcase tramp-system-name)) (literal (upcase tramp-system-name))) eos))) @@ -539,7 +538,7 @@ host runs a restricted shell, it shall be added to this list, too." ;;;###tramp-autoload (defcustom tramp-local-host-regexp - (tramp-compat-rx + (rx bos (| (literal tramp-system-name) (| "localhost" "localhost4" "localhost6" "127.0.0.1" "::1")) @@ -640,7 +639,7 @@ This regexp must match both `tramp-initial-end-of-output' and :type 'regexp) (defcustom tramp-password-prompt-regexp - (tramp-compat-rx + (rx bol (* nonl) (group (regexp (regexp-opt password-word-equivalents))) (* nonl) (any "::៖") (? "\^@") (* blank)) @@ -659,14 +658,13 @@ The `sudo' program appears to insert a `^@' character into the prompt." (defcustom tramp-wrong-passwd-regexp (rx bol (* nonl) (| "Permission denied" - (: "Login " (| "Incorrect" "incorrect")) - "Connection refused" - "Connection closed" "Timeout, server not responding." "Sorry, try again." "Name or service not known" "Host key verification failed." "No supported authentication methods left to try!" + (: "Login " (| "Incorrect" "incorrect")) + (: "Connection " (| "refused" "closed")) (: "Received signal " (+ digit))) (* nonl)) "Regexp matching a `login failed' message. @@ -789,6 +787,7 @@ It shall be used in combination with `generate-new-buffer-name'.") (defvar tramp-temp-buffer-file-name nil "File name of a persistent local temporary file. Useful for \"rsync\" like methods.") + (make-variable-buffer-local 'tramp-temp-buffer-file-name) (put 'tramp-temp-buffer-file-name 'permanent-local t) @@ -899,18 +898,17 @@ Used in `tramp-make-tramp-file-name'.") (defun tramp-build-prefix-regexp () "Return `tramp-prefix-regexp'." - (tramp-compat-rx bol (literal (tramp-build-prefix-format)))) + (rx bol (literal (tramp-build-prefix-format)))) (defvar tramp-prefix-regexp nil ; Initialized when defining `tramp-syntax'! "Regexp matching the very beginning of Tramp file names. Should always start with \"^\". Derived from `tramp-prefix-format'.") (defconst tramp-method-regexp-alist - `((default . ,(tramp-compat-rx - (| (literal tramp-default-method-marker) (>= 2 alnum)))) + `((default . ,(rx (| (literal tramp-default-method-marker) (>= 2 alnum)))) (simplified . "") - (separate . ,(tramp-compat-rx - (? (| (literal tramp-default-method-marker) (>= 2 alnum)))))) + (separate + . ,(rx (? (| (literal tramp-default-method-marker) (>= 2 alnum)))))) "Alist mapping Tramp syntax to regexps matching methods identifiers.") (defun tramp-build-method-regexp () @@ -938,7 +936,7 @@ Used in `tramp-make-tramp-file-name'.") (defun tramp-build-postfix-method-regexp () "Return `tramp-postfix-method-regexp'." - (tramp-compat-rx (literal (tramp-build-postfix-method-format)))) + (rx (literal (tramp-build-postfix-method-format)))) (defvar tramp-postfix-method-regexp nil ; Init'd when defining `tramp-syntax'! "Regexp matching delimiter between method and user or host names. @@ -950,8 +948,7 @@ Derived from `tramp-postfix-method-format'.") (defconst tramp-prefix-domain-format "%" "String matching delimiter between user and domain names.") -(defconst tramp-prefix-domain-regexp - (tramp-compat-rx (literal tramp-prefix-domain-format)) +(defconst tramp-prefix-domain-regexp (rx (literal tramp-prefix-domain-format)) "Regexp matching delimiter between user and domain names. Derived from `tramp-prefix-domain-format'.") @@ -959,7 +956,7 @@ Derived from `tramp-prefix-domain-format'.") "Regexp matching domain names.") (defconst tramp-user-with-domain-regexp - (tramp-compat-rx + (rx (group (regexp tramp-user-regexp)) (regexp tramp-prefix-domain-regexp) (group (regexp tramp-domain-regexp))) @@ -969,8 +966,7 @@ Derived from `tramp-prefix-domain-format'.") "String matching delimiter between user and host names. Used in `tramp-make-tramp-file-name'.") -(defconst tramp-postfix-user-regexp - (tramp-compat-rx (literal tramp-postfix-user-format)) +(defconst tramp-postfix-user-regexp (rx (literal tramp-postfix-user-format)) "Regexp matching delimiter between user and host names. Derived from `tramp-postfix-user-format'.") @@ -993,7 +989,7 @@ Used in `tramp-make-tramp-file-name'.") (defun tramp-build-prefix-ipv6-regexp () "Return `tramp-prefix-ipv6-regexp'." - (tramp-compat-rx (literal tramp-prefix-ipv6-format))) + (rx (literal tramp-prefix-ipv6-format))) (defvar tramp-prefix-ipv6-regexp nil ; Initialized when defining `tramp-syntax'! "Regexp matching left hand side of IPv6 addresses. @@ -1021,7 +1017,7 @@ Used in `tramp-make-tramp-file-name'.") (defun tramp-build-postfix-ipv6-regexp () "Return `tramp-postfix-ipv6-regexp'." - (tramp-compat-rx (literal tramp-postfix-ipv6-format))) + (rx (literal tramp-postfix-ipv6-format))) (defvar tramp-postfix-ipv6-regexp nil ; Initialized when defining `tramp-syntax'! "Regexp matching right hand side of IPv6 addresses. @@ -1030,8 +1026,7 @@ Derived from `tramp-postfix-ipv6-format'.") (defconst tramp-prefix-port-format "#" "String matching delimiter between host names and port numbers.") -(defconst tramp-prefix-port-regexp - (tramp-compat-rx (literal tramp-prefix-port-format)) +(defconst tramp-prefix-port-regexp (rx (literal tramp-prefix-port-format)) "Regexp matching delimiter between host names and port numbers. Derived from `tramp-prefix-port-format'.") @@ -1039,7 +1034,7 @@ Derived from `tramp-prefix-port-format'.") "Regexp matching port numbers.") (defconst tramp-host-with-port-regexp - (tramp-compat-rx + (rx (group (regexp tramp-host-regexp)) (regexp tramp-prefix-port-regexp) (group (regexp tramp-port-regexp))) @@ -1048,8 +1043,7 @@ Derived from `tramp-prefix-port-format'.") (defconst tramp-postfix-hop-format "|" "String matching delimiter after ad-hoc hop definitions.") -(defconst tramp-postfix-hop-regexp - (tramp-compat-rx (literal tramp-postfix-hop-format)) +(defconst tramp-postfix-hop-regexp (rx (literal tramp-postfix-hop-format)) "Regexp matching delimiter after ad-hoc hop definitions. Derived from `tramp-postfix-hop-format'.") @@ -1069,7 +1063,7 @@ Used in `tramp-make-tramp-file-name'.") (defun tramp-build-postfix-host-regexp () "Return `tramp-postfix-host-regexp'." - (tramp-compat-rx (literal tramp-postfix-host-format))) + (rx (literal tramp-postfix-host-format))) (defvar tramp-postfix-host-regexp nil ; Initialized when defining `tramp-syntax'! "Regexp matching delimiter between host names and localnames. @@ -1096,7 +1090,7 @@ Derived from `tramp-postfix-host-format'.") (defun tramp-build-remote-file-name-spec-regexp () "Construct a regexp matching a Tramp file name for a Tramp syntax. It is expected, that `tramp-syntax' has the proper value." - (tramp-compat-rx + (rx ;; Method. (group (regexp tramp-method-regexp)) (regexp tramp-postfix-method-regexp) ;; Optional user. This includes domain. @@ -1118,7 +1112,7 @@ It is expected, that `tramp-syntax' has the proper value." It is expected, that `tramp-syntax' has the proper value. See `tramp-file-name-structure'." (list - (tramp-compat-rx + (rx (regexp tramp-prefix-regexp) (? (group (+ (regexp tramp-remote-file-name-spec-regexp) (regexp tramp-postfix-hop-regexp)))) @@ -1178,11 +1172,9 @@ initial value is overwritten by the car of `tramp-file-name-structure'.") ;; `tramp-method-regexp' needs at least two characters, in order to ;; distinguish from volume letter. This is in the way when completing. (defconst tramp-completion-method-regexp-alist - `((default . ,(tramp-compat-rx - (| (literal tramp-default-method-marker) (+ alnum)))) + `((default . ,(rx (| (literal tramp-default-method-marker) (+ alnum)))) (simplified . "") - (separate . ,(tramp-compat-rx - (| (literal tramp-default-method-marker) (* alnum))))) + (separate . ,(rx (| (literal tramp-default-method-marker) (* alnum))))) "Alist mapping Tramp syntax to regexps matching completion methods.") (defun tramp-build-completion-method-regexp () @@ -1198,8 +1190,8 @@ The `ftp' syntax does not support methods.") "Return `tramp-completion-file-name-regexp' according to `tramp-syntax'." (if (eq tramp-syntax 'separate) ;; FIXME: This shouldn't be necessary. - (tramp-compat-rx bos "/" (? "[" (* (not "]"))) eos) - (tramp-compat-rx + (rx bos "/" (? "[" (* (not "]"))) eos) + (rx bos ;; `file-name-completion' uses absolute paths for matching. ;; This means that on W32 systems, something like @@ -1402,20 +1394,6 @@ based on the Tramp and Emacs versions, and should not be set here." :version "26.1" :type '(repeat string)) -(defcustom tramp-completion-reread-directory-timeout 10 - "Defines seconds since last remote command before rereading a directory. -A remote directory might have changed its contents. In order to -make it visible during file name completion in the minibuffer, -Tramp flushes its cache and rereads the directory contents when -more than `tramp-completion-reread-directory-timeout' seconds -have been gone since last remote command execution. A value of t -would require an immediate reread during filename completion, nil -means to use always cached values for the directory contents." - :type '(choice (const nil) (const t) integer)) -(make-obsolete-variable - 'tramp-completion-reread-directory-timeout - 'remote-file-name-inhibit-cache "27.2") - ;;; Internal Variables: (defvar tramp-current-connection nil @@ -1427,6 +1405,7 @@ the (optional) timestamp of last activity on this connection.") "Password save function. Will be called once the password has been verified by successful authentication.") + (put 'tramp-password-save-function 'tramp-suppress-trace t) (defvar tramp-password-prompt-not-unique nil @@ -1525,8 +1504,7 @@ same connection. Make a copy in order to avoid side effects." (setq vec (copy-tramp-file-name vec)) (setf (tramp-file-name-localname vec) (and (stringp localname) - (tramp-compat-file-name-unquote - (directory-file-name localname))) + (file-name-unquote (directory-file-name localname))) (tramp-file-name-hop vec) nil)) vec)) @@ -1559,7 +1537,7 @@ entry does not exist, return nil." ;; The localname can be quoted with "/:". Extract this. (defun tramp-file-name-unquote-localname (vec) "Return unquoted localname component of VEC." - (tramp-compat-file-name-unquote (tramp-file-name-localname vec))) + (file-name-unquote (tramp-file-name-localname vec))) ;;;###tramp-autoload (defun tramp-tramp-file-p (name) @@ -1597,7 +1575,7 @@ of `process-file', `start-file-process', or `shell-command'." ;; The localname can be quoted with "/:". Extract this. (defun tramp-unquote-file-local-name (name) "Return unquoted localname of NAME." - (tramp-compat-file-name-unquote (tramp-file-local-name name))) + (file-name-unquote (tramp-file-local-name name))) (defun tramp-find-method (method user host) "Return the right method string to use depending on USER and HOST. @@ -1654,7 +1632,7 @@ This is USER, if non-nil. Otherwise, do a lookup in This is HOST, if non-nil. Otherwise, do a lookup in `tramp-default-host-alist' and `tramp-default-host'." (let ((result - (or (and (> (length host) 0) host) + (or (and (tramp-compat-length> host 0) host) (let ((choices tramp-default-host-alist) lhost item) (while choices @@ -1666,7 +1644,7 @@ This is HOST, if non-nil. Otherwise, do a lookup in lhost) tramp-default-host))) ;; We must mark, whether a default value has been used. - (if (or (> (length host) 0) (null result)) + (if (or (tramp-compat-length> host 0) (null result)) result (propertize result 'tramp-default t)))) @@ -1759,7 +1737,7 @@ See `tramp-dissect-file-name' for details." (let ((v (tramp-dissect-file-name (concat tramp-prefix-format (replace-regexp-in-string - (tramp-compat-rx (regexp tramp-postfix-hop-regexp) eos) + (rx (regexp tramp-postfix-hop-regexp) eos) tramp-postfix-host-format name)) nodefault))) ;; Only some methods from tramp-sh.el do support multi-hops. @@ -1772,14 +1750,18 @@ See `tramp-dissect-file-name' for details." (put #'tramp-dissect-hop-name 'tramp-suppress-trace t) +(defsubst tramp-string-empty-or-nil-p (string) + "Check whether STRING is empty or nil." + (or (null string) (string= string ""))) + (defun tramp-buffer-name (vec) "A name for the connection buffer VEC." (let ((method (tramp-file-name-method vec)) (user-domain (tramp-file-name-user-domain vec)) (host-port (tramp-file-name-host-port vec))) - (if (not (zerop (length user-domain))) - (format "*tramp/%s %s@%s*" method user-domain host-port) - (format "*tramp/%s %s*" method host-port)))) + (if (tramp-string-empty-or-nil-p user-domain) + (format "*tramp/%s %s*" method host-port) + (format "*tramp/%s %s@%s*" method user-domain host-port)))) (put #'tramp-buffer-name 'tramp-suppress-trace t) @@ -1824,23 +1806,23 @@ the form (METHOD USER DOMAIN HOST PORT LOCALNAME &optional HOP)." hop (nth 6 args)))) ;; Unless `tramp-syntax' is `simplified', we need a method. - (when (and (not (zerop (length tramp-postfix-method-format))) - (zerop (length method))) + (when (and (not (string-empty-p tramp-postfix-method-format)) + (tramp-string-empty-or-nil-p method)) (signal 'wrong-type-argument (list #'stringp method))) (concat tramp-prefix-format hop - (unless (zerop (length tramp-postfix-method-format)) + (unless (string-empty-p tramp-postfix-method-format) (concat method tramp-postfix-method-format)) user - (unless (zerop (length domain)) + (unless (tramp-string-empty-or-nil-p domain) (concat tramp-prefix-domain-format domain)) - (unless (zerop (length user)) + (unless (tramp-string-empty-or-nil-p user) tramp-postfix-user-format) (when host (if (string-match-p tramp-ipv6-regexp host) (concat tramp-prefix-ipv6-format host tramp-postfix-ipv6-format) host)) - (unless (zerop (length port)) + (unless (tramp-string-empty-or-nil-p port) (concat tramp-prefix-port-format port)) tramp-postfix-host-format localname))) @@ -1855,8 +1837,7 @@ the form (METHOD USER DOMAIN HOST PORT LOCALNAME &optional HOP)." (replace-regexp-in-string tramp-prefix-regexp "" (replace-regexp-in-string - (tramp-compat-rx - (regexp tramp-postfix-host-regexp) eos) + (rx (regexp tramp-postfix-host-regexp) eos) tramp-postfix-hop-format (tramp-make-tramp-file-name vec 'noloc))))) @@ -1865,12 +1846,12 @@ the form (METHOD USER DOMAIN HOST PORT LOCALNAME &optional HOP)." It must not be a complete Tramp file name, but as long as there are necessary only. This function will be used in file name completion." (concat tramp-prefix-format - (unless (or (zerop (length method)) - (zerop (length tramp-postfix-method-format))) + (unless (or (tramp-string-empty-or-nil-p method) + (string-empty-p tramp-postfix-method-format)) (concat method tramp-postfix-method-format)) - (unless (zerop (length user)) + (unless (tramp-string-empty-or-nil-p user) (concat user tramp-postfix-user-format)) - (unless (zerop (length host)) + (unless (tramp-string-empty-or-nil-p host) (concat (if (string-match-p tramp-ipv6-regexp host) (concat @@ -1965,9 +1946,9 @@ of `current-buffer'." (let ((method (tramp-file-name-method vec)) (user-domain (tramp-file-name-user-domain vec)) (host-port (tramp-file-name-host-port vec))) - (if (not (zerop (length user-domain))) - (format "*debug tramp/%s %s@%s*" method user-domain host-port) - (format "*debug tramp/%s %s*" method host-port)))) + (if (tramp-string-empty-or-nil-p user-domain) + (format "*debug tramp/%s %s*" method host-port) + (format "*debug tramp/%s %s@%s*" method user-domain host-port)))) (put #'tramp-debug-buffer-name 'tramp-suppress-trace t) @@ -1986,7 +1967,7 @@ of `current-buffer'." ;; Also, in `font-lock-defaults' you can specify a function name for ;; the "KEYWORDS" part, so font-lock calls it to get the actual keywords! '(list - (tramp-compat-rx bol (regexp tramp-debug-outline-regexp) (+ nonl)) + (rx bol (regexp tramp-debug-outline-regexp) (+ nonl)) '(1 font-lock-warning-face t t) '(0 (outline-font-lock-face) keep t)) "Used for highlighting Tramp debug buffers in `outline-mode'.") @@ -2320,12 +2301,12 @@ the resulting error message." (progn ,@body) (error (tramp-message ,vec-or-proc 3 ,format ,err) nil)))) -;; This macro shall optimize the cases where an `file-exists-p' call -;; is invoked first. Often, the file exists, so the remote command is +;; This macro shall optimize the cases where a `file-exists-p' call is +;; invoked first. Often, the file exists, so the remote command is ;; superfluous. (defmacro tramp-barf-if-file-missing (vec filename &rest body) "Execute BODY and return the result. -In case if an error, raise a `file-missing' error if FILENAME +In case of an error, raise a `file-missing' error if FILENAME does not exist, otherwise propagate the error." (declare (indent 2) (debug (symbolp form body))) (let ((err (make-symbol "err"))) @@ -2400,7 +2381,7 @@ If VAR is nil, then we bind `v' to the structure and `method', `user', (let* ((parameters (cdr reporter)) (message (aref parameters 3))) (when (tramp-compat-string-search message (or (current-message) "")) - (tramp-compat-progress-reporter-update reporter value suffix)))) + (progress-reporter-update reporter value suffix)))) (defmacro with-tramp-progress-reporter (vec level message &rest body) "Execute BODY, spinning a progress reporter with MESSAGE in interactive mode. @@ -2438,13 +2419,12 @@ locally on a remote file name. When the local system is a W32 system but the remote system is Unix, this introduces a superfluous drive letter into the file name. This function removes it." (save-match-data - (let ((quoted (tramp-compat-file-name-quoted-p name 'top)) - (result (tramp-compat-file-name-unquote name 'top))) + (let ((quoted (file-name-quoted-p name 'top)) + (result (file-name-unquote name 'top))) (setq result (replace-regexp-in-string - (tramp-compat-rx (regexp tramp-volume-letter-regexp) "/") - "/" result)) - (if quoted (tramp-compat-file-name-quote result 'top) result)))) + (rx (regexp tramp-volume-letter-regexp) "/") "/" result)) + (if quoted (file-name-quote result 'top) result)))) ;;; Config Manipulation Functions: @@ -2478,13 +2458,14 @@ Example: (setcdr v (delete (car v) (cdr v)))) ;; Check for function and file or registry key. (unless (and (functionp (nth 0 (car v))) + (stringp (nth 1 (car v))) (cond ;; Windows registry. ((string-prefix-p "HKEY_CURRENT_USER" (nth 1 (car v))) (and (memq system-type '(cygwin windows-nt)) (zerop (tramp-call-process - v "reg" nil nil nil "query" (nth 1 (car v)))))) + nil "reg" nil nil nil "query" (nth 1 (car v)))))) ;; DNS-SD service type. ((string-match-p tramp-dns-sd-service-regexp (nth 1 (car v)))) @@ -2552,7 +2533,7 @@ coding system might not be determined. This function repairs it." ;; We found a matching entry in `file-coding-system-alist'. ;; So we add a similar entry, but with the temporary file name ;; as regexp. - (push (cons (tramp-compat-rx (literal tmpname)) (cdr elt)) result))))) + (push (cons (rx (literal tmpname)) (cdr elt)) result))))) (defun tramp-run-real-handler (operation args) "Invoke normal file name handler for OPERATION. @@ -2602,15 +2583,13 @@ Must be handled by the callers." file-name-nondirectory file-name-sans-versions file-notify-add-watch file-ownership-preserved-p file-readable-p file-regular-p file-remote-p - file-selinux-context file-symlink-p file-truename - file-writable-p find-backup-file-name get-file-buffer - insert-directory insert-file-contents load - make-directory set-file-acl set-file-modes + file-selinux-context file-symlink-p file-system-info + file-truename file-writable-p find-backup-file-name + get-file-buffer insert-directory insert-file-contents + load make-directory set-file-acl set-file-modes set-file-selinux-context set-file-times substitute-in-file-name unhandled-file-name-directory vc-registered - ;; Emacs 27+ only. - file-system-info ;; Emacs 28- only. make-directory-internal ;; Emacs 28+ only. @@ -2653,12 +2632,12 @@ Must be handled by the callers." (if (bufferp (nth 0 args)) (nth 0 args) (current-buffer)))) ;; COMMAND. ((member operation - '(make-nearby-temp-file process-file shell-command - start-file-process temporary-file-directory - ;; Emacs 27+ only. - exec-path make-process + '(exec-path make-nearby-temp-file make-process process-file + shell-command start-file-process temporary-file-directory ;; Emacs 29+ only. - list-system-processes memory-info process-attributes)) + list-system-processes memory-info process-attributes + ;; Emacs 30+ only. + file-user-uid)) default-directory) ;; PROC. ((member operation '(file-notify-rm-watch file-notify-valid-p)) @@ -2837,7 +2816,7 @@ remote file names." #'file-name-sans-extension (directory-files dir nil (rx bos "tramp" (+ nonl) ".el" (? "c") eos))))) - (files-regexp (tramp-compat-rx bol (regexp (regexp-opt files)) eol))) + (files-regexp (rx bol (regexp (regexp-opt files)) eol))) (mapatoms (lambda (atom) (when (and (functionp atom) @@ -2874,7 +2853,7 @@ remote file names." (put #'tramp-completion-file-name-handler 'operations (mapcar #'car tramp-completion-file-name-handler-alist)) - ;; Integrated in Emacs 27. + ;; After unloading, `tramp-archive-enabled' might not be defined. (when (bound-and-true-p tramp-archive-enabled) (add-to-list 'file-name-handler-alist (cons tramp-archive-file-name-regexp @@ -2972,10 +2951,10 @@ not in completion mode." (tramp-drop-volume-letter (expand-file-name filename directory))) ;; When `tramp-syntax' is `simplified', we need a default method. (tramp-default-method - (and (zerop (length tramp-postfix-method-format)) + (and (string-empty-p tramp-postfix-method-format) tramp-default-method)) (tramp-default-method-alist - (and (zerop (length tramp-postfix-method-format)) + (and (string-empty-p tramp-postfix-method-format) tramp-default-method-alist)) tramp-default-user tramp-default-user-alist tramp-default-host tramp-default-host-alist @@ -2983,7 +2962,7 @@ not in completion mode." ;; Suppress hop from completion. (when (string-match - (tramp-compat-rx + (rx (regexp tramp-prefix-regexp) (group (+ (regexp tramp-remote-file-name-spec-regexp) (regexp tramp-postfix-hop-regexp)))) @@ -3076,14 +3055,14 @@ They are collected by `tramp-completion-dissect-file-name1'." (let (;; "/method" "/[method" (tramp-completion-file-name-structure1 (list - (tramp-compat-rx + (rx (regexp tramp-prefix-regexp) (group (? (regexp tramp-completion-method-regexp))) eol) 1 nil nil nil)) ;; "/method:user" "/[method/user" (tramp-completion-file-name-structure2 (list - (tramp-compat-rx + (rx (regexp tramp-prefix-regexp) (group (regexp tramp-method-regexp)) (regexp tramp-postfix-method-regexp) @@ -3092,7 +3071,7 @@ They are collected by `tramp-completion-dissect-file-name1'." ;; "/method:host" "/[method/host" (tramp-completion-file-name-structure3 (list - (tramp-compat-rx + (rx (regexp tramp-prefix-regexp) (group (regexp tramp-method-regexp)) (regexp tramp-postfix-method-regexp) @@ -3101,7 +3080,7 @@ They are collected by `tramp-completion-dissect-file-name1'." ;; "/method:[ipv6" "/[method/ipv6" (tramp-completion-file-name-structure4 (list - (tramp-compat-rx + (rx (regexp tramp-prefix-regexp) (group (regexp tramp-method-regexp)) (regexp tramp-postfix-method-regexp) @@ -3111,7 +3090,7 @@ They are collected by `tramp-completion-dissect-file-name1'." ;; "/method:user@host" "/[method/user@host" (tramp-completion-file-name-structure5 (list - (tramp-compat-rx + (rx (regexp tramp-prefix-regexp) (group (regexp tramp-method-regexp)) (regexp tramp-postfix-method-regexp) @@ -3122,7 +3101,7 @@ They are collected by `tramp-completion-dissect-file-name1'." ;; "/method:user@[ipv6" "/[method/user@ipv6" (tramp-completion-file-name-structure6 (list - (tramp-compat-rx + (rx (regexp tramp-prefix-regexp) (group (regexp tramp-method-regexp)) (regexp tramp-postfix-method-regexp) @@ -3255,7 +3234,7 @@ Either user or host may be nil." Either user or host may be nil." (let (result (regexp - (tramp-compat-rx + (rx bol (group (regexp tramp-host-regexp)) (? (+ blank) (group (regexp tramp-user-regexp)))))) (when (re-search-forward regexp (line-end-position) t) @@ -3271,8 +3250,7 @@ User is always nil." (defun tramp-parse-shosts-group () "Return a (user host) tuple allowed to access. User is always nil." - (tramp-parse-group - (tramp-compat-rx bol (group (regexp tramp-host-regexp))) 1 ",")) + (tramp-parse-group (rx bol (group (regexp tramp-host-regexp))) 1 ",")) (defun tramp-parse-sconfig (filename) "Return a list of (user host) tuples allowed to access. @@ -3283,7 +3261,7 @@ User is always nil." "Return a (user host) tuple allowed to access. User is always nil." (tramp-parse-group - (tramp-compat-rx + (rx (| (: bol (* blank) "Host") (: bol (+ nonl)) ;; ??? (group (regexp tramp-host-regexp)))) @@ -3308,15 +3286,14 @@ User is always nil." User is always nil." (tramp-parse-shostkeys-sknownhosts dirname - (tramp-compat-rx - bol "key_" (+ digit) "_" (group (regexp tramp-host-regexp)) ".pub" eol))) + (rx bol "key_" (+ digit) "_" (group (regexp tramp-host-regexp)) ".pub" eol))) (defun tramp-parse-sknownhosts (dirname) "Return a list of (user host) tuples allowed to access. User is always nil." (tramp-parse-shostkeys-sknownhosts dirname - (tramp-compat-rx + (rx bol (group (regexp tramp-host-regexp)) ".ssh-" (| "dss" "rsa") ".pub" eol))) (defun tramp-parse-hosts (filename) @@ -3328,8 +3305,7 @@ User is always nil." "Return a (user host) tuple allowed to access. User is always nil." (tramp-parse-group - (tramp-compat-rx - bol (group (| (regexp tramp-ipv6-regexp) (regexp tramp-host-regexp)))) + (rx bol (group (| (regexp tramp-ipv6-regexp) (regexp tramp-host-regexp)))) 1 (rx blank))) (defun tramp-parse-passwd (filename) @@ -3348,7 +3324,7 @@ Host is always \"localhost\"." "Return a (user host) tuple allowed to access. Host is always \"localhost\"." (let (result - (regexp (tramp-compat-rx bol (group (regexp tramp-user-regexp)) ":"))) + (regexp (rx bol (group (regexp tramp-user-regexp)) ":"))) (when (re-search-forward regexp (line-end-position) t) (setq result (list (match-string 1) "localhost"))) (forward-line 1) @@ -3399,14 +3375,13 @@ User is always nil." (tramp-parse-putty-group registry-or-dirname))))) ;; UNIX case. (tramp-parse-shostkeys-sknownhosts - registry-or-dirname - (tramp-compat-rx bol (group (regexp tramp-host-regexp)) eol)))) + registry-or-dirname (rx bol (group (regexp tramp-host-regexp)) eol)))) (defun tramp-parse-putty-group (registry) "Return a (user host) tuple allowed to access. User is always nil." (let (result - (regexp (tramp-compat-rx (literal registry) "\\" (group (+ nonl))))) + (regexp (rx (literal registry) "\\" (group (+ nonl))))) (when (re-search-forward regexp (line-end-position) t) (setq result (list nil (match-string 1)))) (forward-line 1) @@ -3433,15 +3408,35 @@ BODY is the backend specific code." BODY is the backend specific code." (declare (indent 3) (debug t)) `(with-parsed-tramp-file-name (expand-file-name ,directory) nil - (if (and delete-by-moving-to-trash ,trash) - ;; Move non-empty dir to trash only if recursive deletion was - ;; requested. - (if (not (or ,recursive (tramp-compat-directory-empty-p ,directory))) - (tramp-error - v 'file-error "Directory is not empty, not moving to trash") - (move-file-to-trash ,directory)) - ,@body) - (tramp-flush-directory-properties v localname))) + (let ((delete-by-moving-to-trash + (and delete-by-moving-to-trash + ;; This variable exists since Emacs 30.1. + (not (bound-and-true-p + remote-file-name-inhibit-delete-by-moving-to-trash))))) + (if (and delete-by-moving-to-trash ,trash) + ;; Move non-empty dir to trash only if recursive deletion was + ;; requested. + (if (not (or ,recursive (tramp-compat-directory-empty-p ,directory))) + (tramp-error + v 'file-error "Directory is not empty, not moving to trash") + (move-file-to-trash ,directory)) + ,@body) + (tramp-flush-directory-properties v localname)))) + +(defmacro tramp-skeleton-delete-file (filename &optional trash &rest body) + "Skeleton for `tramp-*-handle-delete-file'. +BODY is the backend specific code." + (declare (indent 2) (debug t)) + `(with-parsed-tramp-file-name (expand-file-name ,filename) nil + (let ((delete-by-moving-to-trash + (and delete-by-moving-to-trash + ;; This variable exists since Emacs 30.1. + (not (bound-and-true-p + remote-file-name-inhibit-delete-by-moving-to-trash))))) + (if (and delete-by-moving-to-trash ,trash) + (move-file-to-trash ,filename) + ,@body) + (tramp-flush-file-properties v localname)))) (defmacro tramp-skeleton-directory-files (directory &optional full match nosort count &rest body) @@ -3537,6 +3532,99 @@ BODY is the backend specific code." ;; Trigger the `file-missing' error. (signal 'error nil))))) +(defmacro tramp-skeleton-file-truename (filename &rest body) + "Skeleton for `tramp-*-handle-file-truename'. +BODY is the backend specific code." + (declare (indent 1) (debug (form body))) + ;; Preserve trailing "/". + `(funcall + (if (directory-name-p ,filename) #'file-name-as-directory #'identity) + ;; Quote properly. + (funcall + (if (file-name-quoted-p ,filename) #'file-name-quote #'identity) + (with-parsed-tramp-file-name + (file-name-unquote (expand-file-name ,filename)) nil + (tramp-make-tramp-file-name + v + (with-tramp-file-property v localname "file-truename" + (let (result) + (setq result (progn ,@body)) + ;; Detect cycle. + (when (and (file-symlink-p ,filename) + (string-equal result localname)) + (tramp-error + v 'file-error + "Apparent cycle of symbolic links for %s" ,filename)) + ;; If the resulting localname looks remote, we must quote + ;; it for security reasons. + (when (file-remote-p result) + (setq result (file-name-quote result 'top))) + result))))))) + +(defmacro tramp-skeleton-make-directory (dir &optional parents &rest body) + "Skeleton for `tramp-*-handle-make-directory'. +BODY is the backend specific code." + ;; Since Emacs 29.1, PARENTS isn't propagated to the handlers + ;; anymore. And the return values are specified since then as well. + (declare (indent 2) (debug t)) + `(let* ((dir (directory-file-name (expand-file-name ,dir))) + (par (file-name-directory dir))) + (with-parsed-tramp-file-name dir nil + (when (and (null ,parents) (file-exists-p dir)) + (tramp-error v 'file-already-exists dir)) + ;; Make missing directory parts. + (when ,parents + (unless (file-directory-p par) + (make-directory par ,parents))) + ;; Just do it. + (if (file-exists-p dir) t + (tramp-flush-file-properties v localname) + ,@body + nil)))) + +(defmacro tramp-skeleton-handle-make-symbolic-link + (target linkname &optional ok-if-already-exists &rest body) + "Skeleton for `tramp-*-handle-make-symbolic-link'. +BODY is the backend specific code. +If TARGET is a non-Tramp file, it is used verbatim as the target +of the symlink. If TARGET is a Tramp file, only the localname +component is used as the target of the symlink if it is located +on the same host. Otherwise, TARGET is quoted." + (declare (indent 3) (debug t)) + `(with-parsed-tramp-file-name (expand-file-name ,linkname) nil + ;; If TARGET is a Tramp name, use just the localname component. + ;; Don't check for a proper method. + (let ((non-essential t)) + (when (and (tramp-tramp-file-p ,target) + (tramp-file-name-equal-p v (tramp-dissect-file-name ,target))) + (setq ,target (tramp-file-local-name (expand-file-name ,target)))) + ;; There could be a cyclic link. + (tramp-flush-file-properties + v (expand-file-name ,target (tramp-file-local-name default-directory)))) + + ;; If TARGET is still remote, quote it. + (if (tramp-tramp-file-p ,target) + (make-symbolic-link + (file-name-quote ,target 'top) ,linkname ,ok-if-already-exists) + + ;; Do the 'confirm if exists' thing. + (when (file-exists-p ,linkname) + ;; What to do? + (if (or (null ,ok-if-already-exists) ; not allowed to exist + (and (numberp ,ok-if-already-exists) + (not (yes-or-no-p + (format + "File %s already exists; make it a link anyway?" + localname))))) + (tramp-error v 'file-already-exists localname) + (delete-file ,linkname))) + + ;; We must also flush the cache of the directory, because + ;; `file-attributes' reads the values from there. + (tramp-flush-file-properties v localname) + + ,@body))) + (defmacro tramp-skeleton-set-file-modes-times-uid-gid (filename &rest body) "Skeleton for `tramp-*-set-file-{modes,times,uid-gid}'. @@ -3703,6 +3791,15 @@ Let-bind it when necessary.") vec (concat "~" (substring filename (match-beginning 1)))) (tramp-make-tramp-file-name (tramp-dissect-file-name filename))))) +(defun tramp-handle-file-user-uid () + "Like `user-uid' for Tramp files." + (let ((v (tramp-dissect-file-name default-directory))) + (or (tramp-get-remote-uid v 'integer) + ;; Some handlers for `tramp-get-remote-uid' return nil if they + ;; can't get the UID; always return -1 in this case for + ;; consistency. + -1))) + (defun tramp-handle-access-file (filename string) "Like `access-file' for Tramp files." (setq filename (file-truename filename)) @@ -3761,7 +3858,7 @@ Let-bind it when necessary.") ;; Otherwise, remove any trailing slash from localname component. ;; Method, host, etc, are unchanged. (while (with-parsed-tramp-file-name directory nil - (and (not (zerop (length localname))) + (and (tramp-compat-length> localname 0) (eq (aref localname (1- (length localname))) ?/) (not (string= localname "/")))) (setq directory (substring directory 0 -1))) @@ -3792,7 +3889,8 @@ Let-bind it when necessary.") ;; If DIR is not given, use DEFAULT-DIRECTORY or "/". (setq dir (or dir default-directory "/")) ;; Handle empty NAME. - (when (zerop (length name)) (setq name ".")) + (when (string-empty-p name) + (setq name ".")) ;; Unless NAME is absolute, concat DIR and NAME. (unless (file-name-absolute-p name) (setq name (tramp-compat-file-name-concat dir name))) @@ -3807,12 +3905,11 @@ Let-bind it when necessary.") ;; not support tilde expansion. But users could declare a ;; respective connection property. (Bug#53847) (when (string-match - (tramp-compat-rx bos "~" (group (* (not "/"))) (group (* nonl)) eos) - localname) + (rx bos "~" (group (* (not "/"))) (group (* nonl)) eos) localname) (let ((uname (match-string 1 localname)) (fname (match-string 2 localname)) hname) - (when (zerop (length uname)) + (when (tramp-string-empty-or-nil-p uname) (setq uname user)) (when (setq hname (tramp-get-home-directory v uname)) (setq localname (concat hname fname))))) @@ -3841,9 +3938,10 @@ Let-bind it when necessary.") (defun tramp-handle-file-directory-p (filename) "Like `file-directory-p' for Tramp files." ;; `file-truename' could raise an error, for example due to a cyclic - ;; symlink. - (ignore-errors - (eq (file-attribute-type (file-attributes (file-truename filename))) t))) + ;; symlink. We don't protect this despite it, because other errors + ;; might be worth to be visible, for example impossibility to mount + ;; in tramp-gvfs.el. + (eq (file-attribute-type (file-attributes (file-truename filename))) t)) (defun tramp-handle-file-equal-p (filename1 filename2) "Like `file-equalp-p' for Tramp files." @@ -3895,7 +3993,7 @@ Let-bind it when necessary.") ;; Run the command on the localname portion only unless we are in ;; completion mode. (tramp-make-tramp-file-name - v (or (and (zerop (length (tramp-file-name-localname v))) + v (or (and (tramp-string-empty-or-nil-p (tramp-file-name-localname v)) (not (tramp-connectable-p file))) (tramp-run-real-handler #'file-name-as-directory @@ -3958,7 +4056,8 @@ Let-bind it when necessary.") ;; "." and ".." are never interesting as completions, and are ;; actually in the way in a directory with only one file. See ;; file_name_completion() in dired.c. - (when (and (consp fnac) (= (length (delete "./" (delete "../" fnac))) 1)) + (when (and (consp fnac) + (tramp-compat-length= (delete "./" (delete "../" fnac)) 1)) (setq fnac (delete "./" (delete "../" fnac)))) (or (try-completion @@ -3969,9 +4068,7 @@ Let-bind it when necessary.") (and completion-ignored-extensions (string-match-p - (tramp-compat-rx - (regexp (regexp-opt completion-ignored-extensions)) eos) - x) + (rx (regexp (regexp-opt completion-ignored-extensions)) eos) x) ;; We remember the hit. (push x hits-ignored-extensions)))))) ;; No match. So we try again for ignored files. @@ -4002,18 +4099,11 @@ Let-bind it when necessary.") ((not (file-exists-p file2)) t) ;; Tramp reads and writes timestamps on second level. So we round ;; the timestamps to seconds without fractions. - ;; `time-convert' has been introduced with Emacs 27.1. - ((fboundp 'time-convert) - (time-less-p - (tramp-compat-funcall - 'time-convert - (file-attribute-modification-time (file-attributes file2)) 'integer) - (tramp-compat-funcall - 'time-convert - (file-attribute-modification-time (file-attributes file1)) 'integer))) (t (time-less-p - (file-attribute-modification-time (file-attributes file2)) - (file-attribute-modification-time (file-attributes file1)))))) + (time-convert + (file-attribute-modification-time (file-attributes file2)) 'integer) + (time-convert + (file-attribute-modification-time (file-attributes file1)) 'integer))))) (defun tramp-handle-file-readable-p (filename) "Like `file-readable-p' for Tramp files." @@ -4077,14 +4167,8 @@ Let-bind it when necessary.") (defun tramp-handle-file-truename (filename) "Like `file-truename' for Tramp files." - ;; Preserve trailing "/". - (funcall - (if (directory-name-p filename) #'file-name-as-directory #'identity) - ;; Quote properly. - (funcall - (if (tramp-compat-file-name-quoted-p filename) - #'tramp-compat-file-name-quote #'identity) - (let ((result (tramp-compat-file-name-unquote (expand-file-name filename))) + (tramp-skeleton-file-truename filename + (let ((result (directory-file-name localname)) (numchase 0) ;; Don't make the following value larger than necessary. ;; People expect an error message in a timely fashion when @@ -4094,31 +4178,21 @@ Let-bind it when necessary.") ;; Unquoting could enable encryption. tramp-crypt-enabled symlink-target) - (with-parsed-tramp-file-name result v1 - ;; We cache only the localname. - (tramp-make-tramp-file-name - v1 - (with-tramp-file-property v1 v1-localname "file-truename" - (while (and (setq symlink-target (file-symlink-p result)) - (< numchase numchase-limit)) - (setq numchase (1+ numchase) - result - (with-parsed-tramp-file-name (expand-file-name result) v2 - (tramp-make-tramp-file-name - v2 - (if (stringp symlink-target) - (if (file-remote-p symlink-target) - (tramp-compat-file-name-quote symlink-target 'top) - (tramp-drop-volume-letter - (expand-file-name - symlink-target - (file-name-directory v2-localname)))) - v2-localname)))) - (when (>= numchase numchase-limit) - (tramp-error - v1 'file-error - "Maximum number (%d) of symlinks exceeded" numchase-limit))) - (tramp-file-local-name (directory-file-name result))))))))) + (while (and (setq symlink-target + (file-symlink-p (tramp-make-tramp-file-name v result))) + (< numchase numchase-limit)) + (setq numchase (1+ numchase) + result + (if (file-remote-p symlink-target) + (file-name-quote symlink-target 'top) + (tramp-drop-volume-letter + (expand-file-name + symlink-target (file-name-directory result))))) + (when (>= numchase numchase-limit) + (tramp-error + v 'file-error + "Maximum number (%d) of symlinks exceeded" numchase-limit))) + (directory-file-name result)))) (defun tramp-handle-file-writable-p (filename) "Like `file-writable-p' for Tramp files." @@ -4418,53 +4492,49 @@ Parsing the remote \"ps\" output is controlled by It is not guaranteed, that all process attributes as described in `process-attributes' are returned. The additional attribute `pid' shall be returned always." - ;; Since Emacs 27.1. - (when (fboundp 'connection-local-criteria-for-default-directory) - (with-tramp-file-property vec "/" "process-attributes" - (ignore-errors - (with-temp-buffer - (hack-connection-local-variables-apply - (connection-local-criteria-for-default-directory)) - ;; (pop-to-buffer (current-buffer)) - (when (zerop - (apply - #'process-file - "ps" nil t nil tramp-process-attributes-ps-args)) - (let (result res) - (goto-char (point-min)) - (while (not (eobp)) - ;; (tramp-test-message - ;; "%s" (buffer-substring (point) (line-end-position))) - (when (save-excursion - (search-forward-regexp - (rx digit) (line-end-position) 'noerror)) - (setq res nil) - (dolist (elt tramp-process-attributes-ps-format) - (push - (cons - (car elt) - (cond - ((eq (cdr elt) 'number) (read (current-buffer))) - ((eq (cdr elt) 'string) - (search-forward-regexp (rx (+ (not blank)))) - (match-string 0)) - ((numberp (cdr elt)) - (search-forward-regexp (rx (+ blank))) - (search-forward-regexp - (rx (+ nonl)) (+ (point) (cdr elt))) - (string-trim (match-string 0))) - ((fboundp (cdr elt)) - (funcall (cdr elt))) - ((null (cdr elt)) - (search-forward-regexp (rx (+ blank))) - (buffer-substring (point) (line-end-position))))) - res)) - ;; `nice' could be `-'. - (setq res (rassq-delete-all '- res)) - (push (append res) result)) - (forward-line)) - ;; Return result. - result))))))) + (with-tramp-file-property vec "/" "process-attributes" + (ignore-errors + (with-temp-buffer + (hack-connection-local-variables-apply + (connection-local-criteria-for-default-directory)) + ;; (pop-to-buffer (current-buffer)) + (when (zerop + (apply + #'process-file "ps" nil t nil tramp-process-attributes-ps-args)) + (let (result res) + (goto-char (point-min)) + (while (not (eobp)) + ;; (tramp-test-message + ;; "%s" (buffer-substring (point) (line-end-position))) + (when (save-excursion + (search-forward-regexp + (rx digit) (line-end-position) 'noerror)) + (setq res nil) + (dolist (elt tramp-process-attributes-ps-format) + (push + (cons + (car elt) + (cond + ((eq (cdr elt) 'number) (read (current-buffer))) + ((eq (cdr elt) 'string) + (search-forward-regexp (rx (+ (not blank)))) + (match-string 0)) + ((numberp (cdr elt)) + (search-forward-regexp (rx (+ blank))) + (search-forward-regexp (rx (+ nonl)) (+ (point) (cdr elt))) + (string-trim (match-string 0))) + ((fboundp (cdr elt)) + (funcall (cdr elt))) + ((null (cdr elt)) + (search-forward-regexp (rx (+ blank))) + (buffer-substring (point) (line-end-position))))) + res)) + ;; `nice' could be `-'. + (setq res (rassq-delete-all '- res)) + (push (append res) result)) + (forward-line)) + ;; Return result. + result)))))) (defun tramp-handle-list-system-processes () "Like `list-system-processes' for Tramp files." @@ -4625,9 +4695,9 @@ Do not set it manually, it is used buffer-local in `tramp-get-lock-pid'.") tramp-prefix-format proxy tramp-postfix-host-format)) (entry (list (and (stringp host-port) - (tramp-compat-rx bol (literal host-port) eol)) + (rx bol (literal host-port) eol)) (and (stringp user-domain) - (tramp-compat-rx bol (literal user-domain) eol)) + (rx bol (literal user-domain) eol)) (propertize proxy 'tramp-ad-hoc t)))) (tramp-message vec 5 "Add %S to `tramp-default-proxies-alist'" entry) ;; Add the hop. @@ -4700,14 +4770,14 @@ Do not set it manually, it is used buffer-local in `tramp-get-lock-pid'.") (or ;; The host name is used for the remote shell command. (member - "%h" (tramp-compat-flatten-tree + "%h" (flatten-tree (tramp-get-method-parameter item 'tramp-login-args))) ;; The host name must match previous hop. (string-match-p previous-host host)) (setq tramp-default-proxies-alist saved-tdpa) (tramp-user-error vec "Host name `%s' does not match `%s'" host previous-host)) - (setq previous-host (tramp-compat-rx bol (literal host) eol))))) + (setq previous-host (rx bol (literal host) eol))))) ;; Result. target-alist)) @@ -4721,7 +4791,7 @@ substitution. SPEC-LIST is a list of char/value pairs used for (let ((args (tramp-get-method-parameter vec parameter)) (spec (apply 'format-spec-make spec-list))) ;; Expand format spec. - (tramp-compat-flatten-tree + (flatten-tree (mapcar (lambda (x) (setq x (mapcar (lambda (y) (format-spec y spec)) x)) @@ -4739,7 +4809,7 @@ substitution. SPEC-LIST is a list of char/value pairs used for (tramp-get-connection-property v "direct-async-process") ;; There's no multi-hop. (or (not (tramp-multi-hop-p v)) - (= (length (tramp-compute-multi-hops v)) 1)) + (null (cdr (tramp-compute-multi-hops v)))) ;; There's no remote stdout or stderr file. (or (not (stringp buffer)) (not (tramp-tramp-file-p buffer))) (or (not (stringp stderr)) (not (tramp-tramp-file-p stderr)))))) @@ -4858,9 +4928,8 @@ substitution. SPEC-LIST is a list of char/value pairs used for (setq login-args (append - (tramp-compat-flatten-tree - (tramp-get-method-parameter v 'tramp-async-args)) - (tramp-compat-flatten-tree + (flatten-tree (tramp-get-method-parameter v 'tramp-async-args)) + (flatten-tree (mapcar (lambda (x) (split-string x " ")) (tramp-expand-args @@ -5062,19 +5131,11 @@ support symbolic links." (when current-buffer-p (barf-if-buffer-read-only) (push-mark nil t)) - ;; `shell-command-save-pos-or-erase' has been introduced with - ;; Emacs 27.1. - (if (fboundp 'shell-command-save-pos-or-erase) - (tramp-compat-funcall - 'shell-command-save-pos-or-erase current-buffer-p) - (setq buffer-read-only nil) - (erase-buffer))) + (shell-command-save-pos-or-erase current-buffer-p)) (if (integerp asynchronous) (let ((tramp-remote-process-environment - ;; `async-shell-command-width' has been introduced with - ;; Emacs 27.1. - (if (natnump (bound-and-true-p async-shell-command-width)) + (if (natnump async-shell-command-width) (cons (format "COLUMNS=%d" (bound-and-true-p async-shell-command-width)) tramp-remote-process-environment) @@ -5095,17 +5156,19 @@ support symbolic links." (add-function :after (process-sentinel p) (lambda (_proc _string) - (with-current-buffer error-buffer - (insert-file-contents-literally - error-file nil nil nil 'replace)) - (delete-file error-file)))) + (ignore-errors + (with-current-buffer error-buffer + (insert-file-contents-literally + error-file nil nil nil 'replace)) + (delete-file error-file))))) (display-buffer output-buffer '(nil (allow-no-window . t))))) ;; Insert error messages if they were separated. (when (and error-file (not (process-live-p p))) - (with-current-buffer error-buffer - (insert-file-contents-literally error-file)) - (delete-file error-file)))) + (ignore-errors + (with-current-buffer error-buffer + (insert-file-contents-literally error-file)) + (delete-file error-file))))) ;; Synchronous case. (prog1 @@ -5113,9 +5176,10 @@ support symbolic links." (process-file-shell-command command nil buffer) ;; Insert error messages if they were separated. (when error-file - (with-current-buffer error-buffer - (insert-file-contents-literally error-file)) - (delete-file error-file)) + (ignore-errors + (with-current-buffer error-buffer + (insert-file-contents-literally error-file)) + (delete-file error-file))) (if current-buffer-p ;; This is like exchange-point-and-mark, but doesn't ;; activate the mark. It is cleaner to avoid activation, @@ -5125,11 +5189,7 @@ support symbolic links." (goto-char (prog1 (mark t) (set-marker (mark-marker) (point) (current-buffer)))) - ;; `shell-command-set-point-after-cmd' has been - ;; introduced with Emacs 27.1. - (if (fboundp 'shell-command-set-point-after-cmd) - (tramp-compat-funcall - 'shell-command-set-point-after-cmd))) + (shell-command-set-point-after-cmd)) ;; There's some output, display it. (when (with-current-buffer output-buffer (> (point-max) (point-min))) (display-message-or-buffer output-buffer))))))) @@ -5137,10 +5197,7 @@ support symbolic links." (defun tramp-handle-start-file-process (name buffer program &rest args) "Like `start-file-process' for Tramp files. BUFFER might be a list, in this case STDERR is separated." - ;; `make-process' knows the `:file-handler' argument since Emacs - ;; 27.1 only. Therefore, we invoke it via `tramp-file-name-handler'. - (tramp-file-name-handler - 'make-process + (make-process :name name :buffer (if (consp buffer) (car buffer) buffer) :command (and program (cons program args)) @@ -5153,7 +5210,7 @@ BUFFER might be a list, in this case STDERR is separated." "Like `substitute-in-file-name' for Tramp files. \"//\" and \"/~\" substitute only in the local filename part." ;; Check, whether the local part is a quoted file name. - (if (tramp-compat-file-name-quoted-p filename) + (if (file-name-quoted-p filename) filename ;; First, we must replace environment variables. (setq filename (tramp-replace-environment-variables filename)) @@ -5184,6 +5241,12 @@ BUFFER might be a list, in this case STDERR is separated." (defconst tramp-time-doesnt-exist '(-1 65535) "An invalid time value, used as \"Doesn't exist\" value.") +(defsubst tramp-defined-time (time) + "Return TIME or nil (when TIME is not a time spec)." + (unless (or (time-equal-p time tramp-time-doesnt-exist) + (time-equal-p time tramp-time-dont-know)) + time)) + (defun tramp-handle-set-visited-file-modtime (&optional time-list) "Like `set-visited-file-modtime' for Tramp files." (unless (buffer-file-name) @@ -5195,7 +5258,7 @@ BUFFER might be a list, in this case STDERR is separated." (or (file-attribute-modification-time (file-attributes (buffer-file-name))) tramp-time-doesnt-exist)))) - (unless (tramp-compat-time-equal-p time-list tramp-time-dont-know) + (unless (time-equal-p time-list tramp-time-dont-know) (tramp-run-real-handler #'set-visited-file-modtime (list time-list)))) (defun tramp-handle-verify-visited-file-modtime (&optional buf) @@ -5221,14 +5284,13 @@ of." (cond ;; File exists, and has a known modtime. - ((and attr - (not (tramp-compat-time-equal-p modtime tramp-time-dont-know))) + ((and attr (not (time-equal-p modtime tramp-time-dont-know))) (< (abs (tramp-time-diff modtime mt)) 2)) ;; Modtime has the don't know value. (attr t) ;; If file does not exist, say it is not modified if and ;; only if that agrees with the buffer's record. - (t (tramp-compat-time-equal-p mt tramp-time-doesnt-exist)))))))) + (t (time-equal-p mt tramp-time-doesnt-exist)))))))) (defun tramp-handle-write-region (start end filename &optional append visit lockname mustbenew) @@ -5425,7 +5487,7 @@ Wait, until the connection buffer changes." ;; Hide message in buffer. (narrow-to-region (point-max) (point-max)) ;; Wait for new output. - (while (not (tramp-compat-ignore-error 'file-error + (while (not (ignore-error file-error (tramp-wait-for-regexp proc 0.1 tramp-security-key-confirmed-regexp))) (when (tramp-check-for-regexp proc tramp-security-key-timeout-regexp) @@ -5757,8 +5819,7 @@ the remote host use line-endings as defined in the variable (tramp-flush-directory-properties vec "/")) (when (buffer-live-p buf) (with-current-buffer buf - (when (and prompt - (tramp-search-regexp (tramp-compat-rx (literal prompt)))) + (when (and prompt (tramp-search-regexp (rx (literal prompt)))) (delete-region (point) (point-max)))))))) (defun tramp-get-inode (vec) @@ -5943,9 +6004,7 @@ ID-FORMAT valid values are `string' and `integer'." (with-tramp-connection-property nil (format "gid-%s" id-format) (cond ((equal id-format 'integer) (group-gid)) - ;; `group-name' has been introduced with Emacs 27.1. - ((and (fboundp 'group-name) (equal id-format 'string)) - (tramp-compat-funcall 'group-name (group-gid))) + ((equal id-format 'string) (group-name (group-gid))) ((file-attribute-group-id (file-attributes "~/" id-format)))))) (defun tramp-get-local-locale (&optional vec) @@ -5962,7 +6021,7 @@ VEC is used for tracing." (while candidates (goto-char (point-min)) (if (string-match-p - (tramp-compat-rx bol (literal (car candidates)) (? "\r") eol) + (rx bol (literal (car candidates)) (? "\r") eol) (buffer-string)) (setq locale (car candidates) candidates nil) @@ -6293,7 +6352,7 @@ this file, if that variable is non-nil." ("|" . "__") ("[" . "_l") ("]" . "_r")) - (tramp-compat-file-name-unquote (buffer-file-name))) + (file-name-unquote (buffer-file-name))) tramp-auto-save-directory))) result) (prog1 ;; Run plain `make-auto-save-file-name'. @@ -6322,7 +6381,7 @@ ALIST is of the form ((FROM . TO) ...)." (let* ((pr (car alist)) (from (car pr)) (to (cdr pr))) - (while (string-match (tramp-compat-rx (literal from)) string) + (while (string-match (rx (literal from)) string) (setq string (replace-match to t t string))) (setq alist (cdr alist)))) string)) @@ -6351,6 +6410,7 @@ It always returns a return code. The Lisp error raised when PROGRAM is nil is trapped also, returning 1. Furthermore, traces are written with verbosity of 6." (let ((default-directory tramp-compat-temporary-file-directory) + (temporary-file-directory tramp-compat-temporary-file-directory) (process-environment (default-toplevel-value 'process-environment)) (destination (if (eq destination t) (current-buffer) destination)) (vec (or vec (car tramp-current-connection))) @@ -6371,7 +6431,7 @@ are written with verbosity of 6." (error (setq error (error-message-string err) result 1))) - (if (zerop (length error)) + (if (tramp-string-empty-or-nil-p error) (tramp-message vec 6 "%s\n%s" result output) (tramp-message vec 6 "%s\n%s\n%s" result output error)) result)) @@ -6383,6 +6443,7 @@ It always returns a return code. The Lisp error raised when PROGRAM is nil is trapped also, returning 1. Furthermore, traces are written with verbosity of 6." (let ((default-directory tramp-compat-temporary-file-directory) + (temporary-file-directory tramp-compat-temporary-file-directory) (process-environment (default-toplevel-value 'process-environment)) (buffer (if (eq buffer t) (current-buffer) buffer)) result) @@ -6507,7 +6568,7 @@ Consults the auth-source package." ;; Workaround. Prior Emacs 28.1, auth-source has saved empty ;; passwords. See discussion in Bug#50399. - (when (zerop (length auth-passwd)) + (when (tramp-string-empty-or-nil-p auth-passwd) (setq tramp-password-save-function nil)) (tramp-set-connection-property vec "first-password-request" nil) @@ -6557,7 +6618,7 @@ T1 and T2 are time values (as returned by `current-time' for example)." Suppress `shell-file-name'. This is needed on w32 systems, which would use a wrong quoting for local file names. See `w32-shell-name'." (let (shell-file-name) - (shell-quote-argument (tramp-compat-file-name-unquote s)))) + (shell-quote-argument (file-name-unquote s)))) ;; Currently (as of Emacs 20.5), the function `shell-quote-argument' ;; does not deal well with newline characters. Newline is replaced by @@ -6590,7 +6651,7 @@ Only works for Bourne-like shells." (string= (substring result 0 2) "\\~")) (setq result (substring result 1))) (replace-regexp-in-string - (tramp-compat-rx "\\" (literal tramp-rsh-end-of-line)) + (rx "\\" (literal tramp-rsh-end-of-line)) (format "'%s'" tramp-rsh-end-of-line) result))))) ;;; Signal handling. This works for remote processes, which have set diff --git a/lisp/net/trampver.el b/lisp/net/trampver.el index fa4604103c5..9b271a7cfbd 100644 --- a/lisp/net/trampver.el +++ b/lisp/net/trampver.el @@ -7,8 +7,8 @@ ;; Maintainer: Michael Albinus <michael.albinus@gmx.de> ;; Keywords: comm, processes ;; Package: tramp -;; Version: 2.6.0.29.1 -;; Package-Requires: ((emacs "26.1")) +;; Version: 2.7.0-pre +;; Package-Requires: ((emacs "27.1")) ;; Package-Type: multi ;; URL: https://www.gnu.org/software/tramp/ @@ -40,7 +40,7 @@ ;; ./configure" to change them. ;;;###tramp-autoload -(defconst tramp-version "2.6.0.29.1" +(defconst tramp-version "2.7.0-pre" "This version of Tramp.") ;;;###tramp-autoload @@ -55,11 +55,9 @@ (dir (or (locate-dominating-file (locate-library "tramp") ".git") source-directory)) debug-on-error) - ;; `emacs-repository-get-branch' has been introduced with Emacs 27.1. - (with-no-warnings - (and (stringp dir) (file-directory-p dir) - (executable-find "git") - (emacs-repository-get-branch dir))))) + (and (stringp dir) (file-directory-p dir) + (executable-find "git") + (emacs-repository-get-branch dir)))) "The repository branch of the Tramp sources.") (defconst tramp-repository-version @@ -76,9 +74,9 @@ "The repository revision of the Tramp sources.") ;; Check for Emacs version. -(let ((x (if (not (string-version-lessp emacs-version "26.1")) +(let ((x (if (not (string-version-lessp emacs-version "27.1")) "ok" - (format "Tramp 2.6.0.29.1 is not fit for %s" + (format "Tramp 2.7.0-pre is not fit for %s" (replace-regexp-in-string "\n" "" (emacs-version)))))) (unless (string-equal "ok" x) (error "%s" x))) diff --git a/lisp/proced.el b/lisp/proced.el index a9c7ef9ef3d..03a7f1bebdf 100644 --- a/lisp/proced.el +++ b/lisp/proced.el @@ -656,6 +656,14 @@ Important: the match ends just after the marker.") ) (put 'proced-mark :advertised-binding "m") +(defvar-local proced-refinements nil + "Information about the current buffer refinements. + +It should be a list of elements of the form (REFINER PID KEY GRAMMAR), where +REFINER and GRAMMAR are as described in `proced-grammar-alist', PID is the +process ID of the process used to create the refinement, and KEY the attribute +of the process. A value of nil indicates that there are no active refinements.") + (easy-menu-define proced-menu proced-mode-map "Proced Menu." `("Proced" @@ -784,6 +792,52 @@ Return nil if point is not on a process line." (if (looking-at "^. .") (get-text-property (match-end 0) 'proced-pid)))) +(defun proced--position-info (pos) + "Return information of the process at POS. + +The returned information will have the form `(PID KEY COLUMN)' where +PID is the process ID of the process at point, KEY is the value of the +proced-key text property at point, and COLUMN is the column for which the +current value of the proced-key text property starts, or 0 if KEY is nil." + ;; If point is on a field, we try to return point to that field. + ;; Otherwise we try to return to the same column + (save-excursion + (goto-char pos) + (let ((pid (proced-pid-at-point)) + (key (get-text-property (point) 'proced-key))) + (list pid key ; can both be nil + (if key + (if (get-text-property (1- (point)) 'proced-key) + (- (point) (previous-single-property-change + (point) 'proced-key)) + 0) + (current-column)))))) + +(defun proced--determine-pos (key column) + "Return position of point in the current line using KEY and COLUMN. + +Attempt to find the first position on the current line where the +text property proced-key is equal to KEY. If this is not possible, return +the position of point of column COLUMN on the current line." + (save-excursion + (let (new-pos) + (if key + (let ((limit (line-end-position)) pos) + (while (and (not new-pos) + (setq pos (next-property-change (point) nil limit))) + (goto-char pos) + (when (eq key (get-text-property (point) 'proced-key)) + (forward-char (min column (- (next-property-change (point)) + (point)))) + (setq new-pos (point)))) + (unless new-pos + ;; we found the process, but the field of point + ;; is not listed anymore + (setq new-pos (proced-move-to-goal-column)))) + (setq new-pos (min (+ (line-beginning-position) column) + (line-end-position)))) + new-pos))) + ;; proced mode (define-derived-mode proced-mode special-mode "Proced" @@ -839,6 +893,7 @@ normal hook `proced-post-display-hook'. (setq-local revert-buffer-function #'proced-revert) (setq-local font-lock-defaults '(proced-font-lock-keywords t nil nil beginning-of-line)) + (setq-local switch-to-buffer-preserve-window-point nil) (if (and (not proced-auto-update-timer) proced-auto-update-interval) (setq proced-auto-update-timer (run-at-time t proced-auto-update-interval @@ -1337,20 +1392,7 @@ a certain refinement, consider defining a new filter in `proced-filter-alist'." (let* ((grammar (assq key proced-grammar-alist)) (refiner (nth 7 grammar))) (when refiner - (cond ((functionp (car refiner)) - (setq proced-process-alist (funcall (car refiner) pid))) - ((consp refiner) - (let ((predicate (nth 4 grammar)) - (ref (cdr (assq key (cdr (assq pid proced-process-alist))))) - val new-alist) - (dolist (process proced-process-alist) - (setq val (funcall predicate (cdr (assq key (cdr process))) ref)) - (if (cond ((not val) (nth 2 refiner)) - ((eq val 'equal) (nth 1 refiner)) - (val (car refiner))) - (push process new-alist))) - (setq proced-process-alist new-alist)))) - ;; Do not revert listing. + (add-to-list 'proced-refinements (list refiner pid key grammar) t) (proced-update))) (message "No refiner defined here.")))) @@ -1859,10 +1901,29 @@ After updating a displayed Proced buffer run the normal hook "Updating process display..."))) (if revert ;; evaluate all processes (setq proced-process-alist (proced-process-attributes))) - ;; filtering and sorting + ;; filtering + (setq proced-process-alist (proced-filter proced-process-alist proced-filter)) + ;; refinements + (pcase-dolist (`(,refiner ,pid ,key ,grammar) proced-refinements) + ;; It's possible the process has exited since the refinement was made + (when (assq pid proced-process-alist) + (cond ((functionp (car refiner)) + (setq proced-process-alist (funcall (car refiner) pid))) + ((consp refiner) + (let ((predicate (nth 4 grammar)) + (ref (cdr (assq key (cdr (assq pid proced-process-alist))))) + val new-alist) + (dolist (process proced-process-alist) + (setq val (funcall predicate (cdr (assq key (cdr process))) ref)) + (when (cond ((not val) (nth 2 refiner)) + ((eq val 'equal) (nth 1 refiner)) + (val (car refiner))) + (push process new-alist))) + (setq proced-process-alist new-alist)))))) + + ;; sorting (setq proced-process-alist - (proced-sort (proced-filter proced-process-alist proced-filter) - proced-sort proced-descend)) + (proced-sort proced-process-alist proced-sort proced-descend)) ;; display as process tree? (setq proced-process-alist @@ -1875,17 +1936,10 @@ After updating a displayed Proced buffer run the normal hook (if (consp buffer-undo-list) (setq buffer-undo-list nil)) (let ((buffer-undo-list t) - ;; If point is on a field, we try to return point to that field. - ;; Otherwise we try to return to the same column - (old-pos (let ((pid (proced-pid-at-point)) - (key (get-text-property (point) 'proced-key))) - (list pid key ; can both be nil - (if key - (if (get-text-property (1- (point)) 'proced-key) - (- (point) (previous-single-property-change - (point) 'proced-key)) - 0) - (current-column))))) + (window-pos-infos + (mapcar (lambda (w) `(,w . ,(proced--position-info (window-point w)))) + (get-buffer-window-list (current-buffer) nil t))) + (old-pos (proced--position-info (point))) buffer-read-only mp-list) ;; remember marked processes (whatever the mark was) (goto-char (point-min)) @@ -1918,7 +1972,8 @@ After updating a displayed Proced buffer run the normal hook ;; Sometimes this puts point in the middle of the proced buffer ;; where it is not interesting. Is there a better / more flexible solution? (goto-char (point-min)) - (let (pid mark new-pos) + + (let (pid mark new-pos win-points) (if (or mp-list (car old-pos)) (while (not (eobp)) (setq pid (proced-pid-at-point)) @@ -1927,28 +1982,25 @@ After updating a displayed Proced buffer run the normal hook (delete-char 1) (beginning-of-line)) (when (eq (car old-pos) pid) - (if (nth 1 old-pos) - (let ((limit (line-end-position)) pos) - (while (and (not new-pos) - (setq pos (next-property-change (point) nil limit))) - (goto-char pos) - (when (eq (nth 1 old-pos) - (get-text-property (point) 'proced-key)) - (forward-char (min (nth 2 old-pos) - (- (next-property-change (point)) - (point)))) - (setq new-pos (point)))) - (unless new-pos - ;; we found the process, but the field of point - ;; is not listed anymore - (setq new-pos (proced-move-to-goal-column)))) - (setq new-pos (min (+ (line-beginning-position) (nth 2 old-pos)) - (line-end-position))))) + (setq new-pos (proced--determine-pos (nth 1 old-pos) + (nth 2 old-pos)))) + (mapc (lambda (w-pos) + (when (eq (cadr w-pos) pid) + (push `(,(car w-pos) . ,(proced--determine-pos + (nth 1 (cdr w-pos)) + (nth 2 (cdr w-pos)))) + win-points))) + window-pos-infos) (forward-line))) - (if new-pos - (goto-char new-pos) - (goto-char (point-min)) - (proced-move-to-goal-column))) + (let ((fallback (save-excursion (goto-char (point-min)) + (proced-move-to-goal-column) + (point)))) + (goto-char (or new-pos fallback)) + ;; Update window points + (mapc (lambda (w-pos) + (set-window-point (car w-pos) + (alist-get (car w-pos) win-points fallback))) + window-pos-infos))) ;; update mode line ;; Does the long `mode-name' clutter the mode line? It would be nice ;; to have some other location for displaying the values of the various @@ -1976,7 +2028,9 @@ After updating a displayed Proced buffer run the normal hook (defun proced-revert (&rest _args) "Reevaluate the process listing based on the currently running processes. -Preserves point and marks." +Preserves point and marks, but not refinements (see `proced-refine' for +information on refinements)." + (setq proced-refinements nil) (proced-update t)) (defun proced-marked-processes () diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 195c23d28c9..884fe6c3f15 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -723,6 +723,37 @@ the semicolon. This function skips the semicolon." (setq-local treesit-defun-skipper #'c-ts-mode--defun-skipper) (setq-local treesit-defun-name-function #'c-ts-mode--defun-name) + (setq-local treesit-sentence-type-regexp + ;; compound_statement makes us jump over too big units + ;; of code, so skip that one, and include the other + ;; statements. + (regexp-opt '("preproc" + "declaration" + "specifier" + "attributed_statement" + "labeled_statement" + "expression_statement" + "if_statement" + "switch_statement" + "do_statement" + "while_statement" + "for_statement" + "return_statement" + "break_statement" + "continue_statement" + "goto_statement" + "case_statement"))) + + (setq-local treesit-sexp-type-regexp + (regexp-opt '("preproc" + "declarator" + "qualifier" + "type" + "parameter" + "expression" + "literal" + "string"))) + ;; Nodes like struct/enum/union_specifier can appear in ;; function_definitions, so we need to find the top-level node. (setq-local treesit-defun-prefer-top-level t) @@ -814,15 +845,23 @@ in your configuration." :group 'c++ (when (treesit-ready-p 'cpp) + (setq-local treesit-text-type-regexp + (regexp-opt '("comment" + "raw_string_literal"))) + (treesit-parser-create 'cpp) + ;; Syntax. (setq-local syntax-propertize-function #'c-ts-mode--syntax-propertize) + ;; Indent. (setq-local treesit-simple-indent-rules (c-ts-mode--get-indent-style 'cpp)) + ;; Font-lock. (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'cpp)) + (treesit-major-mode-setup))) ;; We could alternatively use parsers, but if this works well, I don't diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el index 2631c24f8db..f1e93c1c23c 100644 --- a/lisp/progmodes/cc-engine.el +++ b/lisp/progmodes/cc-engine.el @@ -8288,10 +8288,17 @@ multi-line strings (but not C++, for example)." (setq c-record-ref-identifiers (cons range c-record-ref-identifiers)))))) -(defmacro c-forward-keyword-prefixed-id (type) +(defmacro c-forward-keyword-prefixed-id (type &optional stop-at-end) ;; Used internally in `c-forward-keyword-clause' to move forward ;; over a type (if TYPE is 'type) or a name (otherwise) which ;; possibly is prefixed by keywords and their associated clauses. + ;; Point should be at the type/name or a preceding keyword at the start of + ;; the macro, and it is left at the first token following the type/name, + ;; or (when STOP-AT-END is non-nil) immediately after that type/name. + ;; + ;; Note that both parameters are evaluated at compile time, not run time, + ;; so they must be constants. + ;; ;; Try with a type/name first to not trip up on those that begin ;; with a keyword. Return t if a known or found type is moved ;; over. The point is clobbered if nil is returned. If range @@ -8300,51 +8307,84 @@ multi-line strings (but not C++, for example)." ;; ;; This macro might do hidden buffer changes. (declare (debug t)) - `(let (res) + `(let (res pos) (setq c-last-identifier-range nil) (while (if (setq res ,(if (eq type 'type) - '(c-forward-type) - '(c-forward-name))) - nil - (cond ((looking-at c-keywords-regexp) - (c-forward-keyword-clause 1)) - ((and c-opt-cpp-prefix - (looking-at c-noise-macro-with-parens-name-re)) - (c-forward-noise-clause))))) + `(c-forward-type nil ,stop-at-end) + `(c-forward-name ,stop-at-end))) + (progn + (setq pos (point)) + nil) + (and + (cond ((looking-at c-keywords-regexp) + (c-forward-keyword-clause 1 t)) + ((and c-opt-cpp-prefix + (looking-at c-noise-macro-with-parens-name-re)) + (c-forward-noise-clause t))) + (progn + (setq pos (point)) + (c-forward-syntactic-ws) + t)))) (when (memq res '(t known found prefix maybe)) (when c-record-type-identifiers - ,(if (eq type 'type) - '(c-record-type-id c-last-identifier-range) - '(c-record-ref-id c-last-identifier-range))) + ,(if (eq type 'type) + '(c-record-type-id c-last-identifier-range) + '(c-record-ref-id c-last-identifier-range))) + (when pos + (goto-char pos) + ,(unless stop-at-end + `(c-forward-syntactic-ws))) t))) -(defmacro c-forward-id-comma-list (type update-safe-pos) +(defmacro c-forward-id-comma-list (type update-safe-pos &optional stop-at-end) ;; Used internally in `c-forward-keyword-clause' to move forward ;; over a comma separated list of types or names using - ;; `c-forward-keyword-prefixed-id'. + ;; `c-forward-keyword-prefixed-id'. Point should start at the first token + ;; after the already scanned type/name, or (if STOP-AT-END is non-nil) + ;; immediately after that type/name. Point is left either before or + ;; after the whitespace following the last type/name in the list, depending + ;; on whether STOP-AT-END is non-nil or nil. The return value is without + ;; significance. + ;; + ;; Note that all three parameters are evaluated at compile time, not run + ;; time, so they must be constants. ;; ;; This macro might do hidden buffer changes. (declare (debug t)) - `(while (and (progn - ,(when update-safe-pos - '(setq safe-pos (point))) - (eq (char-after) ?,)) - (progn - (forward-char) - (c-forward-syntactic-ws) - (c-forward-keyword-prefixed-id ,type))))) + `(let ((pos (point))) + (while (and (progn + ,(when update-safe-pos + `(setq safe-pos (point))) + (setq pos (point)) + (c-forward-syntactic-ws) + (eq (char-after) ?,)) + (progn + (forward-char) + (setq pos (point)) + (c-forward-syntactic-ws) + (c-forward-keyword-prefixed-id ,type t)))) + (goto-char pos) + ,(unless stop-at-end + `(c-forward-syntactic-ws)))) -(defun c-forward-noise-clause () +(defun c-forward-noise-clause (&optional stop-at-end) ;; Point is at a c-noise-macro-with-parens-names macro identifier. Go ;; forward over this name, any parenthesis expression which follows it, and - ;; any syntactic WS, ending up at the next token or EOB. If there is an + ;; any syntactic WS, ending up either at the next token or EOB or (when + ;; STOP-AT-END is non-nil) directly after the clause. If there is an ;; unbalanced paren expression, leave point at it. Always Return t. - (or (zerop (c-forward-token-2)) - (goto-char (point-max))) - (if (and (eq (char-after) ?\() - (c-go-list-forward)) + (let (pos) + (or (c-forward-over-token) + (goto-char (point-max))) + (setq pos (point)) + (c-forward-syntactic-ws) + (when (and (eq (char-after) ?\() + (c-go-list-forward)) + (setq pos (point))) + (goto-char pos) + (unless stop-at-end (c-forward-syntactic-ws)) - t) + t)) (defun c-forward-noise-clause-not-macro-decl (maybe-parens) ;; Point is at a noise macro identifier, which, when MAYBE-PARENS is @@ -8378,11 +8418,12 @@ multi-line strings (but not C++, for example)." (goto-char here) nil))) -(defun c-forward-keyword-clause (match) +(defun c-forward-keyword-clause (match &optional stop-at-end) ;; Submatch MATCH in the current match data is assumed to surround a ;; token. If it's a keyword, move over it and any immediately - ;; following clauses associated with it, stopping at the start of - ;; the next token. t is returned in that case, otherwise the point + ;; following clauses associated with it, stopping either at the start + ;; of the next token, or (when STOP-AT-END is non-nil) at the end + ;; of the clause. t is returned in that case, otherwise the point ;; stays and nil is returned. The kind of clauses that are ;; recognized are those specified by `c-type-list-kwds', ;; `c-ref-list-kwds', `c-colon-type-list-kwds', @@ -8412,19 +8453,23 @@ multi-line strings (but not C++, for example)." (when kwd-sym (goto-char (match-end match)) - (c-forward-syntactic-ws) (setq safe-pos (point)) + (c-forward-syntactic-ws) (cond ((and (c-keyword-member kwd-sym 'c-type-list-kwds) - (c-forward-keyword-prefixed-id type)) + (c-forward-keyword-prefixed-id type t)) ;; There's a type directly after a keyword in `c-type-list-kwds'. - (c-forward-id-comma-list type t)) + (setq safe-pos (point)) + (c-forward-syntactic-ws) + (c-forward-id-comma-list type t t)) ((and (c-keyword-member kwd-sym 'c-ref-list-kwds) - (c-forward-keyword-prefixed-id ref)) + (c-forward-keyword-prefixed-id ref t)) ;; There's a name directly after a keyword in `c-ref-list-kwds'. - (c-forward-id-comma-list ref t)) + (setq safe-pos (point)) + (c-forward-syntactic-ws) + (c-forward-id-comma-list ref t t)) ((and (c-keyword-member kwd-sym 'c-paren-any-kwds) (eq (char-after) ?\()) @@ -8444,20 +8489,20 @@ multi-line strings (but not C++, for example)." (goto-char (match-end 0))))) (goto-char pos) - (c-forward-syntactic-ws) - (setq safe-pos (point)))) + (setq safe-pos (point))) + (c-forward-syntactic-ws)) ((and (c-keyword-member kwd-sym 'c-<>-sexp-kwds) (eq (char-after) ?<) (c-forward-<>-arglist (c-keyword-member kwd-sym 'c-<>-type-kwds))) - (c-forward-syntactic-ws) - (setq safe-pos (point))) + (setq safe-pos (point)) + (c-forward-syntactic-ws)) ((and (c-keyword-member kwd-sym 'c-nonsymbol-sexp-kwds) (not (looking-at c-symbol-start)) (c-safe (c-forward-sexp) t)) - (c-forward-syntactic-ws) - (setq safe-pos (point))) + (setq safe-pos (point)) + (c-forward-syntactic-ws)) ((and (c-keyword-member kwd-sym 'c-protection-kwds) (or (null c-post-protection-token) @@ -8467,8 +8512,8 @@ multi-line strings (but not C++, for example)." (not (c-end-of-current-token)))))) (if c-post-protection-token (goto-char (match-end 0))) - (c-forward-syntactic-ws) - (setq safe-pos (point)))) + (setq safe-pos (point)) + (c-forward-syntactic-ws))) (when (c-keyword-member kwd-sym 'c-colon-type-list-kwds) (if (eq (char-after) ?:) @@ -8477,8 +8522,10 @@ multi-line strings (but not C++, for example)." (progn (forward-char) (c-forward-syntactic-ws) - (when (c-forward-keyword-prefixed-id type) - (c-forward-id-comma-list type t))) + (when (c-forward-keyword-prefixed-id type t) + (setq safe-pos (point)) + (c-forward-syntactic-ws) + (c-forward-id-comma-list type t t))) ;; Not at the colon, so stop here. But the identifier ;; ranges in the type list later on should still be ;; recorded. @@ -8488,15 +8535,18 @@ multi-line strings (but not C++, for example)." ;; this one, we move forward to the colon following the ;; clause matched above. (goto-char safe-pos) + (c-forward-syntactic-ws) (c-forward-over-colon-type-list)) (progn (c-forward-syntactic-ws) - (c-forward-keyword-prefixed-id type)) + (c-forward-keyword-prefixed-id type t)) ;; There's a type after the `c-colon-type-list-re' match ;; after a keyword in `c-colon-type-list-kwds'. (c-forward-id-comma-list type nil)))) (goto-char safe-pos) + (unless stop-at-end + (c-forward-syntactic-ws)) t))) ;; cc-mode requires cc-fonts. @@ -8827,11 +8877,12 @@ multi-line strings (but not C++, for example)." (/= (point) start)))) -(defun c-forward-name () - ;; Move forward over a complete name if at the beginning of one, - ;; stopping at the next following token. A keyword, as such, - ;; doesn't count as a name. If the point is not at something that - ;; is recognized as a name then it stays put. +(defun c-forward-name (&optional stop-at-end) + ;; Move forward over a complete name if at the beginning of one, stopping + ;; either at the next following token or (when STOP-AT-END is non-nil) at + ;; the end of the name. A keyword, as such, doesn't count as a name. If + ;; the point is not at something that is recognized as a name then it stays + ;; put. ;; ;; A name could be something as simple as "foo" in C or something as ;; complex as "X<Y<class A<int>::B, BIT_MAX >> b>, ::operator<> :: @@ -8853,7 +8904,7 @@ multi-line strings (but not C++, for example)." ;; ;; This function might do hidden buffer changes. - (let ((pos (point)) (start (point)) res id-start id-end + (let ((pos (point)) pos2 pos3 (start (point)) res id-start id-end ;; Turn off `c-promote-possible-types' here since we might ;; call `c-forward-<>-arglist' and we don't want it to promote ;; every suspect thing in the arglist to a type. We're @@ -8895,7 +8946,7 @@ multi-line strings (but not C++, for example)." (c-forward-syntactic-ws lim+) (cond ((eq (char-before id-end) ?e) ;; Got "... ::template". - (let ((subres (c-forward-name))) + (let ((subres (c-forward-name t))) (when subres (setq pos (point) res subres)))) @@ -8907,7 +8958,7 @@ multi-line strings (but not C++, for example)." (and (eq (c-forward-token-2) 0) (not (eq (char-after) ?\()))))) ;; Got a cast operator. - (when (c-forward-type) + (when (c-forward-type nil t) (setq pos (point) res 'operator) ;; Now we should match a sequence of either @@ -8931,8 +8982,8 @@ multi-line strings (but not C++, for example)." (forward-char) t))))) (while (progn - (c-forward-syntactic-ws lim+) (setq pos (point)) + (c-forward-syntactic-ws lim+) (and (<= (point) lim+) (looking-at c-opt-type-modifier-key))) @@ -8947,30 +8998,34 @@ multi-line strings (but not C++, for example)." ;; operator"" has an (?)optional tag after it. (progn (goto-char (match-end 0)) + (setq pos2 (point)) (c-forward-syntactic-ws lim+) (when (c-on-identifier) - (c-forward-token-2 1 nil lim+))) - (goto-char (match-end 0)) - (c-forward-syntactic-ws lim+)) - (setq pos (point) + (c-forward-over-token nil lim+))) + (goto-char (match-end 0)) + (setq pos2 (point)) + (c-forward-syntactic-ws lim+)) + (setq pos pos2 res 'operator))) nil) ;; `id-start' is equal to `id-end' if we've jumped over ;; an identifier that doesn't end with a symbol token. - ;; That can occur e.g. for Java import directives on the + ;; That can occur e.g. for Java import directives of the ;; form "foo.bar.*". (when (and id-start (/= id-start id-end)) (setq c-last-identifier-range (cons id-start id-end))) (goto-char id-end) + (setq pos (point)) (c-forward-syntactic-ws lim+) - (setq pos (point) - res t))) + (setq res t))) (progn (goto-char pos) + (c-forward-syntactic-ws lim+) + (setq pos3 (point)) (when (or c-opt-identifier-concat-key c-recognize-<>-arglists) @@ -8981,7 +9036,6 @@ multi-line strings (but not C++, for example)." ;; cases with tricky syntactic whitespace that aren't ;; covered in `c-identifier-key'. (goto-char (match-end 0)) - (c-forward-syntactic-ws lim+) t) ((and c-recognize-<>-arglists @@ -8993,11 +9047,12 @@ multi-line strings (but not C++, for example)." ;; `lim+'. (setq lim+ (c-determine-+ve-limit 500)) + (setq pos2 (point)) (c-forward-syntactic-ws lim+) (unless (eq (char-after) ?\() (setq c-last-identifier-range nil) - (c-add-type start (1+ pos))) - (setq pos (point)) + (c-add-type start (1+ pos3))) + (setq pos pos2) (if (and c-opt-identifier-concat-key (looking-at c-opt-identifier-concat-key)) @@ -9007,7 +9062,7 @@ multi-line strings (but not C++, for example)." (progn (when (and c-record-type-identifiers id-start) (c-record-ref-id (cons id-start id-end))) - (forward-char 2) + (goto-char (match-end 0)) (c-forward-syntactic-ws lim+) t) @@ -9019,11 +9074,14 @@ multi-line strings (but not C++, for example)." ))))) (goto-char pos) + (unless stop-at-end + (c-forward-syntactic-ws lim+)) res)) -(defun c-forward-type (&optional brace-block-too) +(defun c-forward-type (&optional brace-block-too stop-at-end) ;; Move forward over a type spec if at the beginning of one, - ;; stopping at the next following token. The keyword "typedef" + ;; stopping at the next following token (if STOP-AT-END is nil) or + ;; at the end of the type spec (otherwise). The keyword "typedef" ;; isn't part of a type spec here. ;; ;; BRACE-BLOCK-TOO, when non-nil, means move over the brace block in @@ -9072,6 +9130,7 @@ multi-line strings (but not C++, for example)." (when (looking-at c-no-type-key) (setq res 'no-id))) (goto-char (match-end 1)) + (setq pos (point)) (c-forward-syntactic-ws) (or (eq res 'no-id) (setq res 'prefix)))) @@ -9080,32 +9139,41 @@ multi-line strings (but not C++, for example)." (cond ((looking-at c-typeof-key) ; e.g. C++'s "decltype". (goto-char (match-end 1)) + (setq pos (point)) (c-forward-syntactic-ws) (setq res (and (eq (char-after) ?\() (c-safe (c-forward-sexp)) 'decltype)) (if res - (c-forward-syntactic-ws) + (progn + (setq pos (point)) + (c-forward-syntactic-ws)) (goto-char start))) ((looking-at c-type-prefix-key) ; e.g. "struct", "class", but NOT ; "typedef". (goto-char (match-end 1)) + (setq pos (point)) (c-forward-syntactic-ws) (while (cond ((looking-at c-decl-hangon-key) - (c-forward-keyword-clause 1)) + (c-forward-keyword-clause 1 t) + (setq pos (point)) + (c-forward-syntactic-ws)) ((looking-at c-pack-key) (goto-char (match-end 1)) + (setq pos (point)) (c-forward-syntactic-ws)) ((and c-opt-cpp-prefix (looking-at c-noise-macro-with-parens-name-re)) - (c-forward-noise-clause)))) + (c-forward-noise-clause t) + (setq pos (point)) + (c-forward-syntactic-ws)))) + (setq id-start (point)) + (setq name-res (c-forward-name t)) (setq pos (point)) - - (setq name-res (c-forward-name)) (setq res (not (null name-res))) (when (eq name-res t) ;; With some keywords the name can be used without the prefix, so we @@ -9113,21 +9181,21 @@ multi-line strings (but not C++, for example)." (when (save-excursion (goto-char post-prefix-pos) (looking-at c-self-contained-typename-key)) - (c-add-type pos (save-excursion - (c-backward-syntactic-ws) - (point)))) + (c-add-type id-start + (point))) (when (and c-record-type-identifiers c-last-identifier-range) (c-record-type-id c-last-identifier-range))) + (c-forward-syntactic-ws) (when (and brace-block-too (memq res '(t nil)) (eq (char-after) ?\{) (save-excursion (c-safe (progn (c-forward-sexp) - (c-forward-syntactic-ws) (setq pos (point)))))) (goto-char pos) + (c-forward-syntactic-ws) (setq res t)) (unless res (goto-char start))) ; invalid syntax @@ -9141,7 +9209,7 @@ multi-line strings (but not C++, for example)." (if (looking-at c-identifier-start) (save-excursion (setq id-start (point) - name-res (c-forward-name)) + name-res (c-forward-name t)) (when name-res (setq id-end (point) id-range c-last-identifier-range)))) @@ -9154,8 +9222,9 @@ multi-line strings (but not C++, for example)." (>= (save-excursion (save-match-data (goto-char (match-end 1)) + (setq pos (point)) (c-forward-syntactic-ws) - (setq pos (point)))) + pos)) id-end) (setq res nil))))) ;; Looking at a primitive or known type identifier. We've @@ -9173,35 +9242,41 @@ multi-line strings (but not C++, for example)." (looking-at c-opt-type-component-key))) ;; There might be more keywords for the type. (let (safe-pos) - (c-forward-keyword-clause 1) + (c-forward-keyword-clause 1 t) (while (progn (setq safe-pos (point)) + (c-forward-syntactic-ws) (looking-at c-opt-type-component-key)) (when (and c-record-type-identifiers (looking-at c-primitive-type-key)) (c-record-type-id (cons (match-beginning 1) (match-end 1)))) - (c-forward-keyword-clause 1)) + (c-forward-keyword-clause 1 t)) (if (looking-at c-primitive-type-key) (progn (when c-record-type-identifiers (c-record-type-id (cons (match-beginning 1) (match-end 1)))) - (c-forward-keyword-clause 1) + (c-forward-keyword-clause 1 t) (setq res t)) (goto-char safe-pos) - (setq res 'prefix))) - (unless (save-match-data (c-forward-keyword-clause 1)) + (setq res 'prefix)) + (setq pos (point))) + (if (save-match-data (c-forward-keyword-clause 1 t)) + (setq pos (point)) (if pos (goto-char pos) (goto-char (match-end 1)) - (c-forward-syntactic-ws))))) + (setq pos (point))))) + (c-forward-syntactic-ws)) ((and (eq name-res t) (eq res 'prefix) (c-major-mode-is 'c-mode) (save-excursion (goto-char id-end) + (setq pos (point)) + (c-forward-syntactic-ws) (and (not (looking-at c-symbol-start)) (not (looking-at c-type-decl-prefix-key))))) ;; A C specifier followed by an implicit int, e.g. @@ -9213,13 +9288,11 @@ multi-line strings (but not C++, for example)." (cond ((eq name-res t) ;; A normal identifier. (goto-char id-end) + (setq pos (point)) (if (or res c-promote-possible-types) (progn (when (not (eq c-promote-possible-types 'just-one)) - (c-add-type id-start (save-excursion - (goto-char id-end) - (c-backward-syntactic-ws) - (point)))) + (c-add-type id-start id-end)) (when (and c-record-type-identifiers id-range) (c-record-type-id id-range)) (unless res @@ -9233,6 +9306,7 @@ multi-line strings (but not C++, for example)." ((eq name-res 'template) ;; A template is sometimes a type. (goto-char id-end) + (setq pos (point)) (c-forward-syntactic-ws) (setq res (if (eq (char-after) ?\() @@ -9258,6 +9332,7 @@ multi-line strings (but not C++, for example)." (when c-opt-type-modifier-key (while (looking-at c-opt-type-modifier-key) ; e.g. "const", "volatile" (goto-char (match-end 1)) + (setq pos (point)) (c-forward-syntactic-ws) (setq res t))) @@ -9268,11 +9343,13 @@ multi-line strings (but not C++, for example)." (when c-opt-type-suffix-key ; e.g. "..." (while (looking-at c-opt-type-suffix-key) (goto-char (match-end 1)) + (setq pos (point)) (c-forward-syntactic-ws))) ;; Skip any "WS" identifiers (e.g. "final" or "override" in C++) (while (looking-at c-type-decl-suffix-ws-ids-key) (goto-char (match-end 1)) + (setq pos (point)) (c-forward-syntactic-ws) (setq res t)) @@ -9296,7 +9373,8 @@ multi-line strings (but not C++, for example)." (progn (goto-char (match-end 1)) (c-forward-syntactic-ws) - (setq subres (c-forward-type)))) + (setq subres (c-forward-type nil t)) + (setq pos (point)))) (progn ;; If either operand certainly is a type then both are, but we @@ -9332,9 +9410,11 @@ multi-line strings (but not C++, for example)." ;; `nconc' doesn't mind that the tail of ;; `c-record-found-types' is t. (nconc c-record-found-types - c-record-type-identifiers)))) + c-record-type-identifiers))))))) - (goto-char pos)))) + (goto-char pos) + (unless stop-at-end + (c-forward-syntactic-ws)) (when (and c-record-found-types (memq res '(known found)) id-range) (setq c-record-found-types @@ -9737,7 +9817,7 @@ point unchanged and return nil." ;; (e.g. "," or ";" or "}"). (let ((here (point)) id-start id-end brackets-after-id paren-depth decorated - got-init arglist double-double-quote) + got-init arglist double-double-quote pos) (or limit (setq limit (point-max))) (if (and (< (point) limit) @@ -9771,6 +9851,7 @@ point unchanged and return nil." (eq (char-after (1+ (point))) ?\")) (setq double-double-quote t)) (goto-char (match-end 0)) + (setq pos (point)) (c-forward-syntactic-ws limit) (setq got-identifier t) nil) @@ -9783,7 +9864,10 @@ point unchanged and return nil." ;; prefix only if it specifies a member pointer. (progn (setq id-start (point)) - (when (c-forward-name) + (when (c-forward-name t) + (setq pos (point)) + (c-forward-syntactic-ws limit) + (if (save-match-data (looking-at "\\(::\\)")) ;; We only check for a trailing "::" and @@ -9812,10 +9896,12 @@ point unchanged and return nil." (setq id-start (point))) (cond ((or got-identifier - (c-forward-name)) - (save-excursion - (c-backward-syntactic-ws) - (setq id-end (point)))) + (c-forward-name t)) + (setq id-end + (or pos + (point))) + (c-forward-syntactic-ws limit) + t) (accept-anon (setq id-start nil id-end nil) t) @@ -10569,11 +10655,11 @@ This function might do hidden buffer changes." (or got-identifier (and (looking-at c-identifier-start) (setq pos (point)) - (setq got-identifier (c-forward-name)) + (setq got-identifier (c-forward-name t)) (save-excursion - (c-backward-syntactic-ws) (c-simple-skip-symbol-backward) (setq identifier-start (point))) + (progn (c-forward-syntactic-ws) t) (setq name-start pos)) (when (looking-at "[0-9]") (setq got-number t)) ; We probably have an arithmetic expression. @@ -10796,8 +10882,7 @@ This function might do hidden buffer changes." type-start (progn (goto-char type-start) - (c-forward-type) - (c-backward-syntactic-ws) + (c-forward-type nil t) (point))))))))) ;; Got a declaration of the form "foo bar (gnu);" or "bar ;; (gnu);" where we've recognized "bar" as the type and "gnu" @@ -11121,8 +11206,7 @@ This function might do hidden buffer changes." (space-after-type (save-excursion (goto-char type-start) - (and (c-forward-type) - (progn (c-backward-syntactic-ws) t) + (and (c-forward-type nil t) (or (eolp) (memq (char-after) '(?\ ?\t))))))) (when (not (eq (not space-before-id) diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el index 852e893dc25..063cfffe1da 100644 --- a/lisp/progmodes/csharp-mode.el +++ b/lisp/progmodes/csharp-mode.el @@ -910,6 +910,11 @@ Key bindings: ;; Comments. (c-ts-common-comment-setup) + (setq-local treesit-text-type-regexp + (regexp-opt '("comment" + "verbatim_string-literal" + "interpolated_verbatim_string-text"))) + ;; Indent. (setq-local treesit-simple-indent-rules csharp-ts-mode--indent-rules) diff --git a/lisp/progmodes/dockerfile-ts-mode.el b/lisp/progmodes/dockerfile-ts-mode.el index f2f30cf2617..c9125bc6cbd 100644 --- a/lisp/progmodes/dockerfile-ts-mode.el +++ b/lisp/progmodes/dockerfile-ts-mode.el @@ -173,6 +173,10 @@ the subtrees." (setq-local treesit-simple-indent-rules dockerfile-ts-mode--indent-rules) + ;; Navigation + (setq-local treesit-sentence-type-regexp + "instruction") + ;; Font-lock. (setq-local treesit-font-lock-settings dockerfile-ts-mode--font-lock-settings) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 3fc1d68422a..4fa886bc788 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -182,7 +182,7 @@ chosen (interactively or automatically)." when probe return (cons probe args) finally (funcall err))))))) -(defvar eglot-server-programs `(((rust-ts-mode rust-mode) . ,(eglot-alternatives '("rust-analyzer" "rls"))) +(defvar eglot-server-programs `(((rust-ts-mode rust-mode) . ("rust-analyzer")) ((cmake-mode cmake-ts-mode) . ("cmake-language-server")) (vimrc-mode . ("vim-language-server" "--stdio")) ((python-mode python-ts-mode) diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el index 6f293acca5e..a352adbba19 100644 --- a/lisp/progmodes/flymake.el +++ b/lisp/progmodes/flymake.el @@ -1635,6 +1635,7 @@ buffer." (define-derived-mode flymake-diagnostics-buffer-mode tabulated-list-mode "Flymake diagnostics" "A mode for listing Flymake diagnostics." + :interactive nil (setq tabulated-list-format flymake--diagnostics-base-tabulated-list-format) (setq tabulated-list-entries 'flymake--diagnostics-buffer-entries) @@ -1692,6 +1693,7 @@ some of this variable's contents the diagnostic listings.") (define-derived-mode flymake-project-diagnostics-mode tabulated-list-mode "Flymake diagnostics" "A mode for listing Flymake diagnostics." + :interactive nil (setq tabulated-list-format (vconcat [("File" 25 t)] flymake--diagnostics-base-tabulated-list-format)) diff --git a/lisp/progmodes/gdb-mi.el b/lisp/progmodes/gdb-mi.el index 8b157dd3333..2edaf9e2593 100644 --- a/lisp/progmodes/gdb-mi.el +++ b/lisp/progmodes/gdb-mi.el @@ -1113,13 +1113,13 @@ no input, and GDB is waiting for input." (process-live-p proc) (not gud-running) (= (point) (marker-position (process-mark proc)))) - ;; Sending an EOF does not work with GDB-MI; submit an - ;; explicit quit command. - (progn - (if (> gdb-control-level 0) - (process-send-eof proc) - (insert "quit") - (comint-send-input t t))) + ;; Exit a recursive reading loop or quit. + (if (> gdb-control-level 0) + (process-send-eof proc) + ;; Sending an EOF does not work with GDB-MI; submit an + ;; explicit quit command. + (insert "quit") + (comint-send-input t t)) (delete-char arg)))) (defvar gdb-define-alist nil "Alist of #define directives for GUD tooltips.") @@ -4355,6 +4355,24 @@ member." :group 'gud :version "29.1") +(defcustom gdb-locals-table-row-config `((name . 20) + (type . 20) + (value . ,gdb-locals-value-limit)) + "Configuration for table rows in the local variable display. + +An alist that controls the display of the name, type and value of +local variables inside the currently active stack-frame. The key +controls which column to change whereas the value determines the +maximum number of characters to display in each column. A value +of 0 means there is no limit. + +Additionally, the order the element in the alist determines the +left-to-right display order of the properties." + :type '(alist :key-type symbol :value-type integer) + :group 'gud + :version "30.1") + + (defvar gdb-locals-values-table (make-hash-table :test #'equal) "Mapping of local variable names to a string with their value.") @@ -4384,12 +4402,9 @@ member." (defun gdb-locals-value-filter (value) "Filter function for the local variable VALUE." - (let* ((no-nl (replace-regexp-in-string "\n" " " value)) - (str (replace-regexp-in-string "[[:space:]]+" " " no-nl)) - (limit gdb-locals-value-limit)) - (if (>= (length str) limit) - (concat (substring str 0 limit) "...") - str))) + (let* ((no-nl (replace-regexp-in-string "\n" " " (or value "<Unknown>"))) + (str (replace-regexp-in-string "[[:space:]]+" " " no-nl))) + str)) (defun gdb-edit-locals-value (&optional event) "Assign a value to a variable displayed in the locals buffer." @@ -4403,6 +4418,22 @@ member." (gud-basic-call (concat "-gdb-set variable " var " = " value))))) + +(defun gdb-locals-table-columns-list (alist) + "Format and arrange the columns in locals display based on ALIST." + (let (columns) + (dolist (config gdb-locals-table-row-config columns) + (let* ((key (car config)) + (max (cdr config)) + (prop (alist-get key alist))) + (when prop + (if (and (> max 0) (length> prop max)) + (push (propertize (string-truncate-left prop max) 'help-echo prop) + columns) + (push prop columns))))) + (nreverse columns))) + + ;; Complex data types are looked up in `gdb-locals-values-table'. (defun gdb-locals-handler-custom () "Handler to rebuild the local variables table buffer." @@ -4431,12 +4462,14 @@ member." help-echo "mouse-2: edit value" local-map ,gdb-edit-locals-map-1) value)) + (setf (gdb-table-right-align table) t) + (setq name (propertize name 'font-lock-face font-lock-variable-name-face)) + (setq type (propertize type 'font-lock-face font-lock-type-face)) (gdb-table-add-row table - (list - (propertize type 'font-lock-face font-lock-type-face) - (propertize name 'font-lock-face font-lock-variable-name-face) - value) + (gdb-locals-table-columns-list `((name . ,name) + (type . ,type) + (value . ,value))) `(gdb-local-variable ,local)))) (insert (gdb-table-string table " ")) (setq mode-name @@ -5124,6 +5157,8 @@ This arrangement depends on the values of variable (defun gdb-reset () "Exit a debugging session cleanly. Kills the gdb buffers, and resets variables and the source buffers." + ;; Save GDB history + (comint-write-input-ring) ;; The gdb-inferior buffer has a pty hooked up to the main gdb ;; process. This pty must be deleted explicitly. (let ((pty (get-process "gdb-inferior"))) diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el index 5f3e1ea3e68..7dafe9b2e3d 100644 --- a/lisp/progmodes/go-ts-mode.el +++ b/lisp/progmodes/go-ts-mode.el @@ -35,6 +35,7 @@ (declare-function treesit-node-child "treesit.c") (declare-function treesit-node-child-by-field-name "treesit.c") (declare-function treesit-node-start "treesit.c") +(declare-function treesit-node-end "treesit.c") (declare-function treesit-node-type "treesit.c") (declare-function treesit-search-subtree "treesit.c") @@ -176,9 +177,16 @@ '((ERROR) @font-lock-warning-face)) "Tree-sitter font-lock settings for `go-ts-mode'.") +(defvar-keymap go-ts-mode-map + :doc "Keymap used in Go mode, powered by tree-sitter" + :parent prog-mode-map + "C-c C-d" #'go-ts-mode-docstring) + ;;;###autoload (define-derived-mode go-ts-mode prog-mode "Go" - "Major mode for editing Go, powered by tree-sitter." + "Major mode for editing Go, powered by tree-sitter. + +\\{go-ts-mode-map}" :group 'go :syntax-table go-ts-mode--syntax-table @@ -276,6 +284,32 @@ Return nil if there is no name or if NODE is not a defun node." (not (go-ts-mode--struct-node-p node)) (not (go-ts-mode--alias-node-p node)))) +(defun go-ts-mode-docstring () + "Add a docstring comment for the current defun. +The added docstring is prefilled with the defun's name. If the +comment already exists, jump to it." + (interactive) + (when-let ((defun-node (treesit-defun-at-point))) + (goto-char (treesit-node-start defun-node)) + (if (go-ts-mode--comment-on-previous-line-p) + ;; go to top comment line + (while (go-ts-mode--comment-on-previous-line-p) + (forward-line -1)) + (insert "// " (treesit-defun-name defun-node)) + (newline) + (backward-char)))) + +(defun go-ts-mode--comment-on-previous-line-p () + "Return t if the previous line is a comment." + (when-let ((point (- (pos-bol) 1)) + ((> point 0)) + (node (treesit-node-at point))) + (and + ;; check point is actually inside the found node + ;; treesit-node-at can return nodes after point + (<= (treesit-node-start node) point (treesit-node-end node)) + (string-equal "comment" (treesit-node-type node))))) + ;; go.mod support. (defvar go-mod-ts-mode--syntax-table diff --git a/lisp/progmodes/gud.el b/lisp/progmodes/gud.el index 3b792354cbc..92e018aaec1 100644 --- a/lisp/progmodes/gud.el +++ b/lisp/progmodes/gud.el @@ -159,143 +159,96 @@ Used to gray out relevant toolbar icons.") (t (comint-interrupt-subjob))))) -(easy-mmode-defmap gud-menu-map - '(([help] "Info (debugger)" . gud-goto-info) - ([tooltips] menu-item "Show GUD tooltips" gud-tooltip-mode - :enable (and (not emacs-basic-display) - (display-graphic-p) - (fboundp 'x-show-tip)) - :visible (memq gud-minor-mode - '(gdbmi guiler dbx sdb xdb pdb)) - :button (:toggle . gud-tooltip-mode)) - ([refresh] "Refresh" . gud-refresh) - ([run] menu-item "Run" gud-run - :enable (not gud-running) - :visible (or (memq gud-minor-mode '(gdb dbx jdb)) - (and (eq gud-minor-mode 'gdbmi) - (or (not (gdb-show-run-p)) - (bound-and-true-p - gdb-active-process))))) - ([go] . (menu-item (if (bound-and-true-p gdb-active-process) - "Continue" "Run") - gud-go - :visible (and (eq gud-minor-mode 'gdbmi) - (gdb-show-run-p)))) - ([stop] menu-item "Stop" gud-stop-subjob - :visible (or (not (memq gud-minor-mode '(gdbmi pdb))) - (and (eq gud-minor-mode 'gdbmi) - (gdb-show-stop-p)))) - ([until] menu-item "Continue to selection" gud-until - :enable (not gud-running) - :visible (and (memq gud-minor-mode '(gdbmi gdb perldb)) - (gud-tool-bar-item-visible-no-fringe))) - ([remove] menu-item "Remove Breakpoint" gud-remove - :enable (not gud-running) - :visible (gud-tool-bar-item-visible-no-fringe)) - ([tbreak] menu-item "Temporary Breakpoint" gud-tbreak - :enable (not gud-running) - :visible (memq gud-minor-mode - '(gdbmi gdb sdb xdb))) - ([break] menu-item "Set Breakpoint" gud-break - :enable (not gud-running) - :visible (gud-tool-bar-item-visible-no-fringe)) - ([up] menu-item "Up Stack" gud-up - :enable (not gud-running) - :visible (memq gud-minor-mode - '(gdbmi gdb guiler dbx xdb jdb pdb))) - ([down] menu-item "Down Stack" gud-down - :enable (not gud-running) - :visible (memq gud-minor-mode - '(gdbmi gdb guiler dbx xdb jdb pdb))) - ([pp] menu-item "Print S-expression" gud-pp - :enable (and (not gud-running) - (bound-and-true-p gdb-active-process)) - :visible (and (string-equal - (buffer-local-value - 'gud-target-name gud-comint-buffer) - "emacs") - (eq gud-minor-mode 'gdbmi))) - ([print*] . (menu-item (if (eq gud-minor-mode 'jdb) - "Dump object" - "Print Dereference") - gud-pstar - :enable (not gud-running) - :visible (memq gud-minor-mode '(gdbmi gdb jdb)))) - ([print] menu-item "Print Expression" gud-print - :enable (not gud-running)) - ([watch] menu-item "Watch Expression" gud-watch - :enable (not gud-running) - :visible (eq gud-minor-mode 'gdbmi)) - ([finish] menu-item "Finish Function" gud-finish - :enable (not gud-running) - :visible (memq gud-minor-mode - '(gdbmi gdb guiler xdb jdb pdb))) - ([stepi] menu-item "Step Instruction" gud-stepi - :enable (not gud-running) - :visible (memq gud-minor-mode '(gdbmi gdb dbx))) - ([nexti] menu-item "Next Instruction" gud-nexti - :enable (not gud-running) - :visible (memq gud-minor-mode '(gdbmi gdb dbx))) - ([step] menu-item "Step Line" gud-step - :enable (not gud-running)) - ([next] menu-item "Next Line" gud-next - :enable (not gud-running)) - ([cont] menu-item "Continue" gud-cont - :enable (not gud-running) - :visible (not (eq gud-minor-mode 'gdbmi)))) - "Menu for `gud-mode'." - :name "Gud") - -(easy-mmode-defmap gud-minor-mode-map - (append - `(([menu-bar debug] . ("Gud" . ,gud-menu-map))) - ;; Get tool bar like functionality from the menu bar on a text only - ;; terminal. - (unless window-system - `(([menu-bar down] - . (,(propertize "down" 'face 'font-lock-doc-face) . gud-down)) - ([menu-bar up] - . (,(propertize "up" 'face 'font-lock-doc-face) . gud-up)) - ([menu-bar finish] - . (,(propertize "finish" 'face 'font-lock-doc-face) . gud-finish)) - ([menu-bar step] - . (,(propertize "step" 'face 'font-lock-doc-face) . gud-step)) - ([menu-bar next] - . (,(propertize "next" 'face 'font-lock-doc-face) . gud-next)) - ([menu-bar until] menu-item - ,(propertize "until" 'face 'font-lock-doc-face) gud-until - :visible (memq gud-minor-mode '(gdbmi gdb perldb))) - ([menu-bar cont] menu-item - ,(propertize "cont" 'face 'font-lock-doc-face) gud-cont - :visible (not (eq gud-minor-mode 'gdbmi))) - ([menu-bar run] menu-item - ,(propertize "run" 'face 'font-lock-doc-face) gud-run - :visible (memq gud-minor-mode '(gdbmi gdb dbx jdb))) - ([menu-bar go] menu-item - ,(propertize " go " 'face 'font-lock-doc-face) gud-go - :visible (and (eq gud-minor-mode 'gdbmi) - (gdb-show-run-p))) - ([menu-bar stop] menu-item - ,(propertize "stop" 'face 'font-lock-doc-face) gud-stop-subjob - :visible (or (and (eq gud-minor-mode 'gdbmi) - (gdb-show-stop-p)) - (not (eq gud-minor-mode 'gdbmi)))) - ([menu-bar print] - . (,(propertize "print" 'face 'font-lock-doc-face) . gud-print)) - ([menu-bar tools] . undefined) - ([menu-bar buffer] . undefined) - ([menu-bar options] . undefined) - ([menu-bar edit] . undefined) - ([menu-bar file] . undefined)))) - "Map used in visited files.") +(defvar-keymap gud-mode-map + ;; Will inherit from comint-mode via define-derived-mode. + :doc "`gud-mode' keymap.") -(setf (alist-get 'gud-minor-mode minor-mode-map-alist) - gud-minor-mode-map) +(defvar-keymap gud-minor-mode-map + :parent gud-mode-map) -(defvar gud-mode-map - ;; Will inherit from comint-mode via define-derived-mode. - (make-sparse-keymap) - "`gud-mode' keymap.") +(easy-menu-define gud-menu-map gud-mode-map + "Menu for `gud-mode'." + '("Gud" + ["Continue" gud-cont + :enable (not gud-running) + :visible (not (eq gud-minor-mode 'gdbmi))] + ["Next Line" gud-next + :enable (not gud-running)] + ["Step Line" gud-step + :enable (not gud-running)] + ["Next Instruction" gud-nexti + :enable (not gud-running) + :visible (memq gud-minor-mode '(gdbmi gdb dbx))] + ["Step Instruction" gud-stepi + :enable (not gud-running) + :visible (memq gud-minor-mode '(gdbmi gdb dbx))] + ["Finish Function" gud-finish + :enable (not gud-running) + :visible (memq gud-minor-mode '(gdbmi gdb guiler xdb jdb pdb))] + ["Watch Expression" gud-watch + :enable (not gud-running) + :visible (eq gud-minor-mode 'gdbmi)] + ["Print Expression" gud-print + :enable (not gud-running)] + ["Dump object-Derefenrece" gud-pstar + :label (if (eq gud-minor-mode 'jdb) + "Dump object" + "Print Dereference") + :enable (not gud-running) + :visible (memq gud-minor-mode '(gdbmi gdb jdb))] + ["Print S-expression" gud-pp + :enable (and (not gud-running) + (bound-and-true-p gdb-active-process)) + :visible (and (string-equal + (buffer-local-value + 'gud-target-name gud-comint-buffer) + "emacs") + (eq gud-minor-mode 'gdbmi))] + ["Down Stack" gud-down + :enable (not gud-running) + :visible (memq gud-minor-mode '(gdbmi gdb guiler dbx xdb jdb pdb))] + ["Up Stack" gud-up + :enable (not gud-running) + :visible (memq gud-minor-mode + '(gdbmi gdb guiler dbx xdb jdb pdb))] + ["Set Breakpoint" gud-break + :enable (not gud-running) + :visible (gud-tool-bar-item-visible-no-fringe)] + ["Temporary Breakpoint" gud-tbreak + :enable (not gud-running) + :visible (memq gud-minor-mode '(gdbmi gdb sdb xdb))] + ["Remove Breakpoint" gud-remove + :enable (not gud-running) + :visible (gud-tool-bar-item-visible-no-fringe)] + ["Continue to selection" gud-until + :enable (not gud-running) + :visible (and (memq gud-minor-mode '(gdbmi gdb perldb)) + (gud-tool-bar-item-visible-no-fringe))] + ["Stop" gud-stop-subjob + :visible (or (not (memq gud-minor-mode '(gdbmi pdb))) + (and (eq gud-minor-mode 'gdbmi) + (gdb-show-stop-p)))] + ["Continue-Run" gud-go + :label (if (bound-and-true-p gdb-active-process) + "Continue" "Run") + :visible (and (eq gud-minor-mode 'gdbmi) + (gdb-show-run-p))] + ["Run" gud-run + :enable (not gud-running) + :visible (or (memq gud-minor-mode '(gdb dbx jdb)) + (and (eq gud-minor-mode 'gdbmi) + (or (not (gdb-show-run-p)) + (bound-and-true-p + gdb-active-process))))] + ["Refresh" gud-refresh] + ["Show GUD tooltips" gud-tooltip-mode + :enable (and (not emacs-basic-display) + (display-graphic-p) + (fboundp 'x-show-tip)) + :visible (memq gud-minor-mode + '(gdbmi guiler dbx sdb xdb pdb)) + :button (:toggle . gud-tooltip-mode)] + ["Info (debugger)" gud-goto-info])) (setf (alist-get 'gud-minor-mode minor-mode-map-alist) gud-minor-mode-map) diff --git a/lisp/progmodes/hideif.el b/lisp/progmodes/hideif.el index 30893638f0d..836db83c2f3 100644 --- a/lisp/progmodes/hideif.el +++ b/lisp/progmodes/hideif.el @@ -113,6 +113,7 @@ ;; Various floating point types and operations are also supported but the ;; actual precision is limited by the Emacs internal floating representation, ;; which is the C data type "double" or IEEE binary64 format. +;; C99 and GNU style variadic arguments support is completed in 2022/E. ;;; Code: @@ -392,8 +393,10 @@ If there is a marked region from START to END it only shows the symbols within." (add-hook 'after-revert-hook 'hif-after-revert-function) (defun hif-end-of-line () + "Find the end-point of line concatenation." (end-of-line) - (while (= (logand 1 (skip-chars-backward "\\\\")) 1) + (while (progn (skip-chars-backward " \t" (line-beginning-position)) + (= ?\\ (char-before))) (end-of-line 2))) (defun hif-merge-ifdef-region (start end) @@ -536,10 +539,10 @@ that form should be displayed.") ;;===%%SF%% parsing (Start) === ;;; The code that understands what ifs and ifdef in files look like. -(defconst hif-cpp-prefix "\\(^\\|\r\\)[ \t]*#[ \t]*") +(defconst hif-cpp-prefix "\\(^\\|\r\\)?[ \t]*#[ \t]*") (defconst hif-ifxdef-regexp (concat hif-cpp-prefix "if\\(n\\)?def")) (defconst hif-ifndef-regexp (concat hif-cpp-prefix "ifndef")) -(defconst hif-ifx-regexp (concat hif-cpp-prefix "if\\(n?def\\)?[ \t]+")) +(defconst hif-ifx-regexp (concat hif-cpp-prefix "if\\((\\|\\(n?def\\)?[ \t]+\\)")) (defconst hif-elif-regexp (concat hif-cpp-prefix "elif")) (defconst hif-else-regexp (concat hif-cpp-prefix "else")) (defconst hif-endif-regexp (concat hif-cpp-prefix "endif")) @@ -547,18 +550,23 @@ that form should be displayed.") (concat hif-ifx-regexp "\\|" hif-elif-regexp "\\|" hif-else-regexp "\\|" hif-endif-regexp)) (defconst hif-macro-expr-prefix-regexp - (concat hif-cpp-prefix "\\(if\\(n?def\\)?\\|elif\\|define\\)[ \t]+")) + (concat hif-cpp-prefix "\\(if(\\|if\\(n?def\\)?[ \t]+\\|elif\\|define[ \t]+\\)")) -(defconst hif-white-regexp "[ \t]*") +(defconst hif-line-concat "\\\\[ \t]*[\n\r]") +;; If `hif-white-regexp' is modified, `hif-tokenize' might need to be modified +;; accordingly. +(defconst hif-white-regexp (concat "\\(?:[ \t]\\|/\\*.*?\\*/" + "\\|\\(?:" hif-line-concat "\\)\\)*")) (defconst hif-define-regexp (concat hif-cpp-prefix "\\(define\\|undef\\)")) (defconst hif-id-regexp (concat "[[:alpha:]_][[:alnum:]_]*")) +(defconst hif-etc-regexp "\\.\\.\\.") (defconst hif-macroref-regexp (concat hif-white-regexp "\\(" hif-id-regexp "\\)" "\\(" "(" hif-white-regexp "\\(" hif-id-regexp "\\)?" hif-white-regexp "\\(" "," hif-white-regexp hif-id-regexp hif-white-regexp "\\)*" - "\\(\\.\\.\\.\\)?" hif-white-regexp + "\\(" "," hif-white-regexp "\\)?" "\\(" hif-etc-regexp "\\)?" hif-white-regexp ")" "\\)?" )) @@ -936,7 +944,11 @@ Assuming we've just performed a `hif-token-regexp' lookup." (defun hif-tokenize (start end) "Separate string between START and END into a list of tokens." (let ((token-list nil) - (white-regexp "[ \t]+") + ;; Similar to `hif-white-regexp' but keep the spaces if there are + (white-regexp (concat "\\(?:" + "\\([ \t]+\\)\\|/\\*.*?\\*/" + "\\|\\(?:" hif-line-concat "\\)" + "\\)*")) token) (setq hif-simple-token-only t) (with-syntax-table hide-ifdef-syntax-table @@ -956,29 +968,31 @@ Assuming we've just performed a `hif-token-regexp' lookup." (forward-char 2)) ((looking-at hif-string-literal-regexp) - (setq token (substring-no-properties (match-string 1))) + (setq token (match-string-no-properties 1)) (goto-char (match-end 0)) (when (looking-at white-regexp) - (add-text-properties 0 1 '(hif-space t) token) + (if (not (zerop (length (match-string-no-properties 1)))) + (add-text-properties 0 1 '(hif-space t) token)) (goto-char (match-end 0))) (push token token-list)) ((looking-at hif-token-regexp) (goto-char (match-end 0)) - (setq token (hif-strtok - (substring-no-properties (match-string 0)))) + (setq token (hif-strtok (match-string-no-properties 0))) (push token token-list) (when (looking-at white-regexp) - ;; We can't just append a space to the token string, otherwise - ;; `0xf0 ' ## `01' will become `0xf0 01' instead of the expected - ;; `0xf001', hence a standalone `hif-space' is placed instead. - (push 'hif-space token-list) + (if (not (zerop (length (match-string-no-properties 1)))) + ;; We can't just append a space to the token string, + ;; otherwise `0xf0 ' ## `01' will become `0xf0 01' instead + ;; of the expected `0xf001', hence a standalone `hif-space' + ;; is placed instead. + (push 'hif-space token-list)) (goto-char (match-end 0)))) ((looking-at "\r") ; Sometimes MS-Windows user will leave CR in (forward-char 1)) ; the source code. Let's not get stuck here. - (t (error "Bad #if expression: %s" (buffer-string))))))) + (t (error "Bad preprocessor expression: %s" (buffer-string))))))) (if (eq 'hif-space (car token-list)) (setq token-list (cdr token-list))) ;; remove trailing white space (nreverse token-list)))) @@ -1126,7 +1140,7 @@ this is to emulate the stringification behavior of C++ preprocessor." (and (eq (car remains) 'hif-space) (eq (cadr remains) 'hif-lparen) (setq remains (cdr remains))))) - ;; No argument, no invocation + ;; No argument list, no invocation tok ;; Argumented macro, get arguments and invoke it. ;; Dynamically bind `hif-token-list' and `hif-token' @@ -1369,8 +1383,9 @@ factor : `!' factor | `~' factor | `(' exprlist `)' | `defined(' id `)' | (parmlist nil) ; A "token" list of parameters, will later be parsed (parm nil)) - (while (or (not (eq (hif-nexttoken keep-space) 'hif-rparen)) - (/= nest 0)) + (while (and (or (not (eq (hif-nexttoken keep-space) 'hif-rparen)) + (/= nest 0)) + hif-token) (if (eq (car (last parm)) 'hif-comma) (setq parm nil)) (cond @@ -1384,6 +1399,8 @@ factor : `!' factor | `~' factor | `(' exprlist `)' | `defined(' id `)' | (setq parm nil))) (push hif-token parm)) + (if (equal parm '(hif-comma)) ;; missing the last argument + (setq parm '(nil))) (push (nreverse parm) parmlist) ; Okay even if PARM is nil (hif-nexttoken keep-space) ; Drop the `hif-rparen', get next token (nreverse parmlist))) @@ -1609,11 +1626,21 @@ and `+='...)." ;; no need to reassemble the list if no `##' presents l)) -(defun hif-delimit (lis atom) - (nconc (mapcan (lambda (l) (list l atom)) +(defun hif-delimit (lis elem) + (nconc (mapcan (lambda (l) (list l elem)) (butlast lis)) (last lis))) +(defun hif-delete-nth (n lst) + "Non-destructively delete the nth item from a list." + (if (zerop n) + (cdr lst) + ;; non-destructive + (let* ((duplst (copy-sequence lst)) + (node (nthcdr (1- n) duplst))) + (setcdr node (cddr node)) + duplst))) + ;; Perform token replacement: (defun hif-macro-supply-arguments (macro-name actual-parms) "Expand a macro call, replace ACTUAL-PARMS in the macro body." @@ -1633,49 +1660,160 @@ and `+='...)." ;; For each actual parameter, evaluate each one and associate it ;; with an actual parameter, put it into local table and finally ;; evaluate the macro body. - (if (setq etc (eq (car formal-parms) 'hif-etc)) + (if (setq etc (or (eq (car formal-parms) 'hif-etc) + (and (eq (car formal-parms) 'hif-etc-c99) 'c99))) ;; Take care of `hif-etc' first. Prefix `hif-comma' back if needed. (setq formal-parms (cdr formal-parms))) (setq formal-count (length formal-parms) actual-count (length actual-parms)) - (if (> formal-count actual-count) - (error "Too few parameters for macro %S" macro-name) - (if (< formal-count actual-count) - (or etc - (error "Too many parameters for macro %S" macro-name)))) + ;; Fix empty arguments applied + (if (and (= formal-count 1) + (null (car formal-parms))) + (setq formal-parms nil + formal-count (1- formal-count))) + (if (and (= actual-count 1) + (or (null (car actual-parms)) + ;; white space as the only argument + (equal '(hif-space) (car actual-parms)))) + (setq actual-parms nil + actual-count (1- actual-count))) + + ;; Basic error checking + (if etc + (if (eq etc 'c99) + (if (and (> formal-count 1) ; f(a,b,...) + (< actual-count formal-count)) + (error "C99 variadic argument macro %S need at least %d arguments" + macro-name formal-count)) + ;; GNU style variadic argument + (if (and (> formal-count 1) + (< actual-count (1- formal-count))) + (error "GNU variadic argument macro %S need at least %d arguments" + macro-name (1- formal-count)))) + (if (> formal-count actual-count) + (error "Too few parameters for macro %S; %d instead of %d" + macro-name actual-count formal-count) + (if (< formal-count actual-count) + (error "Too many parameters for macro %S; %d instead of %d" + macro-name actual-count formal-count)))) ;; Perform token replacement on the MACRO-BODY with the parameters - (while (setq formal (pop formal-parms)) - ;; Prevent repetitive substitution, thus cannot use `subst' - ;; for example: - ;; #define mac(a,b) (a+b) - ;; #define testmac mac(b,y) - ;; testmac should expand to (b+y): replace of argument a and b - ;; occurs simultaneously, not sequentially. If sequentially, - ;; according to the argument order, it will become: - ;; 1. formal parm #1 'a' replaced by actual parm 'b', thus (a+b) - ;; becomes (b+b) - ;; 2. formal parm #2 'b' replaced by actual parm 'y', thus (b+b) - ;; becomes (y+y). - (setq macro-body - ;; Unlike `subst', `substitute' replace only the top level - ;; instead of the whole tree; more importantly, it's not - ;; destructive. - (cl-substitute (if (and etc (null formal-parms)) - (hif-delimit actual-parms 'hif-comma) - (car actual-parms)) - formal macro-body)) - (setq actual-parms (cdr actual-parms))) - - ;; Replacement completed, stringifiy and concatenate the token list. - ;; Stringification happens must take place before flattening, otherwise - ;; only the first token will be stringified. - (setq macro-body - (flatten-tree (hif-token-stringification macro-body))) - - ;; Token concatenation happens here, keep single 'hif-space - (hif-keep-single (hif-token-concatenation macro-body) 'hif-space)))) + + ;; Every substituted argument in the macro-body must be in list form so + ;; that it won't again be substituted incorrectly in later iterations. + ;; Finally we will flatten the list to fix that. + (cl-loop + do + ;; Note that C99 '...' and GNU 'x...' allow empty match + (setq formal (pop formal-parms)) + ;; + ;; Prevent repetitive substitution, thus cannot use `subst' + ;; for example: + ;; #define mac(a,b) (a+b) + ;; #define testmac mac(b,y) + ;; testmac should expand to (b+y): replace of argument a and b + ;; occurs simultaneously, not sequentially. If sequentially, + ;; according to the argument order, it will become: + ;; 1. formal parm #1 'a' replaced by actual parm 'b', thus (a+b) + ;; becomes (b+b) + ;; 2. formal parm #2 'b' replaced by actual parm 'y', thus (b+b) + ;; becomes (y+y). + ;; Unlike `subst', `cl-substitute' replace only the top level + ;; instead of the whole tree; more importantly, it's not + ;; destructive. + ;; + (if (not (and (null formal-parms) etc)) + ;; One formal with one actual + (setq macro-body + (cl-substitute (car actual-parms) formal macro-body)) + ;; `formal-parms' used up, now take care of '...' + (cond + + ((eq etc 'c99) ; C99 __VA_ARGS__ style '...' + (when formal + (setq macro-body + (cl-substitute (car actual-parms) formal macro-body)) + ;; Now the whole __VA_ARGS__ represents the whole + ;; remaining actual params + (pop actual-parms)) + ;; Replace if __VA_ARGS__ presents: + ;; if yes, see if it's prefixed with ", ##" or not, + ;; if yes, remove the "##", then if actual-params is + ;; exhausted, remove the prefixed ',' as well. + ;; Prepare for destructive operation + (let ((rem-body (copy-sequence macro-body)) + new-body va left part) + ;; Find each __VA_ARGS__ and remove its immediate prefixed '##' + ;; and comma if presents and if `formal_param' is exhausted + (while (setq va (cl-position '__VA_ARGS__ rem-body)) + ;; Split REM-BODY @ __VA_ARGS__ into LEFT and right + (setq part nil) + (if (zerop va) + (setq left nil ; __VA_ARGS__ trimed + rem-body (cdr rem-body)) + (setq left rem-body + rem-body (cdr (nthcdr va rem-body))) ; _V_ removed + (setcdr (nthcdr va left) nil) ; now _V_ be the last in LEFT + ;; now LEFT=(, w? ## w? _V_) rem=(W X Y) where w = white space + (setq left (cdr (nreverse left)))) ; left=(w? ## w? ,) + + ;; Try to recognize w?##w? and remove ", ##" if found + ;; (remember head = __VA_ARGS__ is temporarily removed) + (while (and left (eq 'hif-space (car left))) ; skip whites + (setq part (cons 'hif-space part) + left (cdr left))) + + (if (eq (car left) 'hif-token-concat) ; match '##' + (if actual-parms + ;; Keep everything + (setq part (append part (cdr left))) + ;; `actual-params' exhausted, delete ',' if presents + (while (and left (eq 'hif-space (car left))) ; skip whites + (setq part (cons 'hif-space part) + left (cdr left))) + (setq part + (append part + (if (eq (car left) 'hif-comma) ; match ',' + (cdr left) + left)))) + ;; No immediate '##' found + (setq part (append part left))) + + ;; Insert __VA_ARGS__ as a list + (push (hif-delimit actual-parms 'hif-comma) part) + ;; Reverse `left' back + (setq left (nreverse part) + new-body (append new-body left))) + + ;; Replacement of __VA_ARGS__ done here, add rem-body back + (setq macro-body (append new-body rem-body) + actual-parms nil))) + + (etc ; GNU style '...', substitute last argument + (if (null actual-parms) + ;; Must be non-destructive otherwise the original function + ;; definition defined in `hide-ifdef-env' will be destroyed. + (setq macro-body (remove formal macro-body)) + (setq macro-body + (cl-substitute (hif-delimit actual-parms 'hif-comma) + formal macro-body) + actual-parms nil))) + + (t + (error "Interal error: impossible case.")))) + + (pop actual-parms) + while actual-parms) ; end cl-loop + + ;; Replacement completed, stringifiy and concatenate the token list. + ;; Stringification happens must take place before flattening, otherwise + ;; only the first token will be stringified. + (setq macro-body + (flatten-tree (hif-token-stringification macro-body)))) + + ;; Token concatenation happens here, keep single 'hif-space + (hif-keep-single (hif-token-concatenation macro-body) 'hif-space))) (defun hif-invoke (macro-name actual-parms) "Invoke a macro by expanding it, reparse macro-body and finally invoke it." @@ -1710,7 +1848,9 @@ and `+='...)." Do this when cursor is at the beginning of `regexp' (i.e. #ifX)." (let ((case-fold-search nil)) (save-excursion - (re-search-forward regexp) + (if (re-search-forward regexp) + (if (= ?\( (char-before)) ;; "#if(" found + (goto-char (1- (point))))) (let* ((curr-regexp (match-string 0)) (defined (string-match hif-ifxdef-regexp curr-regexp)) (negate (and defined @@ -1724,29 +1864,48 @@ Do this when cursor is at the beginning of `regexp' (i.e. #ifX)." (setq tokens (list 'hif-not tokens))) (hif-parse-exp tokens))))) +(defun hif-is-in-comment () + "Check if we're currently within a C(++) comment." + (or (nth 4 (syntax-ppss)) + (looking-at "/[/*]"))) + +(defun hif-search-ifX-regexp (hif-regexp &optional backward) + "Search for a valid ifX regexp defined in hideif." + (let ((start (point)) + (re-search-func (if backward + #'re-search-backward + #'re-search-forward)) + (limit (if backward (point-min) (point-max))) + found) + (while (and (setq found + (funcall re-search-func hif-regexp limit t)) + (hif-is-in-comment))) + ;; Jump to the pattern if found + (if found + (unless backward + (setq found + (goto-char (- (point) (length (match-string 0)))))) + (goto-char start)) + found)) + (defun hif-find-any-ifX () "Move to next #if..., or #ifndef, at point or after." ;; (message "find ifX at %d" (point)) - (prog1 - (re-search-forward hif-ifx-regexp (point-max) t) - (beginning-of-line))) - + (hif-search-ifX-regexp hif-ifx-regexp)) (defun hif-find-next-relevant () "Move to next #if..., #elif..., #else, or #endif, after the current line." ;; (message "hif-find-next-relevant at %d" (point)) (end-of-line) - ;; Avoid infinite recursion by only going to line-beginning if match found - (if (re-search-forward hif-ifx-else-endif-regexp (point-max) t) - (beginning-of-line))) + ;; Avoid infinite recursion by going to the pattern only if a match is found + (hif-search-ifX-regexp hif-ifx-else-endif-regexp)) (defun hif-find-previous-relevant () "Move to previous #if..., #else, or #endif, before the current line." ;; (message "hif-find-previous-relevant at %d" (point)) (beginning-of-line) - ;; Avoid infinite recursion by only going to line-beginning if match found - (if (re-search-backward hif-ifx-else-endif-regexp (point-min) t) - (beginning-of-line))) + ;; Avoid infinite recursion by going to the pattern only if a match is found + (hif-search-ifX-regexp hif-ifx-else-endif-regexp 't)) (defun hif-looking-at-ifX () @@ -1931,6 +2090,7 @@ Point is left unchanged." ((hif-looking-at-else) (setq else (point))) (t + (beginning-of-line) ; otherwise #endif line will be hidden (setq end (point))))) ;; If found #else, look for #endif. (when else @@ -1940,6 +2100,7 @@ Point is left unchanged." (hif-ifdef-to-endif)) (if (hif-looking-at-else) (error "Found two elses in a row? Broken!")) + (beginning-of-line) ; otherwise #endif line will be hidden (setq end (point))) ; (line-end-position) (hif-make-range start end else elif)))) @@ -2085,16 +2246,20 @@ Refer to `hide-ifdef-expand-reinclusion-guard' for more details." (eq (car def) 'hif-define-macro)) (let ((cdef (concat "#define " name)) (parmlist (cadr def)) - s) + p s etc) (setq def (caddr def)) ;; parmlist (when parmlist (setq cdef (concat cdef "(")) - (while (car parmlist) - (setq cdef (concat cdef (symbol-name (car parmlist)) - (if (cdr parmlist) ",")) + (if (setq etc (or (eq (setq p (car parmlist)) 'hif-etc) + (and (eq p 'hif-etc-c99) 'c99))) + (pop parmlist)) + (while (setq p (car parmlist)) + (setq cdef (concat cdef (symbol-name p) (if (cdr parmlist) ",")) parmlist (cdr parmlist))) - (setq cdef (concat cdef ")"))) + (setq cdef (concat cdef + (if etc (concat (if (eq etc 'c99) ",") "...")) + ")"))) (setq cdef (concat cdef " ")) ;; body (while def @@ -2221,25 +2386,38 @@ however, when this command is prefixed, it will display the error instead." result)))) (defun hif-parse-macro-arglist (str) - "Parse argument list formatted as `( arg1 [ , argn] [...] )'. + "Parse argument list formatted as `( arg1 [ , argn] [,] [...] )'. The `...' is also included. Return a list of the arguments, if `...' exists the first arg will be `hif-etc'." (let* ((hif-simple-token-only nil) ; Dynamic binding var for `hif-tokenize' (tokenlist (cdr (hif-tokenize (- (point) (length str)) (point)))) ; Remove `hif-lparen' - etc result token) - (while (not (eq (setq token (pop tokenlist)) 'hif-rparen)) + etc result token prevtok prev2tok) + (while (not (eq (setq prev2tok prevtok + prevtok token + token (pop tokenlist)) 'hif-rparen)) (cond ((eq token 'hif-etc) - (setq etc t)) + ;; GNU type "..." or C99 type + (setq etc (if (or (null prevtok) + (eq prevtok 'hif-comma) + (and (eq prevtok 'hif-space) + (eq prev2tok 'hif-comma))) + 'c99 t))) ((eq token 'hif-comma) - t) + (if etc + (error "Syntax error: no comma allowed after `...'."))) (t (push token result)))) - (if etc - (cons 'hif-etc (nreverse result)) - (nreverse result)))) + (setq result (nreverse result)) + (cond + ((eq etc 'c99) + (cons 'hif-etc-c99 result)) + ((eq etc t) + (cons 'hif-etc result)) + (t + result)))) ;; The original version of hideif evaluates the macro early and store the ;; final values for the defined macro into the symbol database (aka @@ -2280,9 +2458,11 @@ first arg will be `hif-etc'." (let* ((defining (string= "define" (match-string 2))) (name (and (re-search-forward hif-macroref-regexp max t) (match-string 1))) - (parmlist (or (and (match-string 3) ; First arg id found + (parmlist (or (and (or (match-string 3) ; First arg id found + (match-string 6)) ; '...' found (delq 'hif-space - (hif-parse-macro-arglist (match-string 2)))) + (hif-parse-macro-arglist + (match-string 2)))) (and (match-string 2) ; empty arglist (list nil))))) (if defining @@ -2325,7 +2505,8 @@ first arg will be `hif-etc'." (expr (and tokens ;; `hif-simple-token-only' is checked only ;; here. - (or (and hif-simple-token-only + (or (and (null parmlist) + hif-simple-token-only (listp tokens) (= (length tokens) 1) (hif-parse-exp tokens)) @@ -2354,13 +2535,22 @@ first arg will be `hif-etc'." (save-excursion (save-restriction ;; (mark-region min max) ;; for debugging + (and min (goto-char min)) (setq hif-verbose-define-count 0) (forward-comment (point-max)) - (while (hif-find-define min max) - (forward-comment (point-max)) - (setf min (point))) + (setq min (point)) + (let ((breakloop nil)) + (while (and (not breakloop) + (hif-find-define min max)) + (forward-comment (point-max)) + (if (and max + (> (point) max)) + (setq max (point) + breakloop t)) + (setq min (point)))) (if max (goto-char max) - (goto-char (point-max)))))) + (goto-char (point-max)) + nil)))) (defun hide-ifdef-guts () "Does most of the work of `hide-ifdefs'. @@ -2376,7 +2566,7 @@ It does not do the work that's pointless to redo on a recursive entry." min max) (setq hif-__COUNTER__ 0) (goto-char (point-min)) - (setf min (point)) + (setq min (point)) ;; Without this `condition-case' it would be easier to see which ;; operation went wrong thru the backtrace `iff' user realize ;; the underlying meaning of all hif-* operation; for example, @@ -2384,11 +2574,11 @@ It does not do the work that's pointless to redo on a recursive entry." ;; operation arguments would be invalid. (condition-case err (cl-loop do - (setf max (hif-find-any-ifX)) - (hif-add-new-defines min max) + (setq max (hif-find-any-ifX)) + (setq max (hif-add-new-defines min max)) (if max (hif-possibly-hide expand-header)) - (setf min (point)) + (setq min (point)) while max) (error (error "Error: failed at line %d %S" (line-number-at-pos) err)))))) diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el index fc264f448af..e4153725efd 100644 --- a/lisp/progmodes/java-ts-mode.el +++ b/lisp/progmodes/java-ts-mode.el @@ -298,6 +298,11 @@ Return nil if there is no name or if NODE is not a defun node." ;; Comments. (c-ts-common-comment-setup) + (setq-local treesit-text-type-regexp + (regexp-opt '("line_comment" + "block_comment" + "text_block"))) + ;; Indent. (setq-local treesit-simple-indent-rules java-ts-mode--indent-rules) @@ -318,6 +323,29 @@ Return nil if there is no name or if NODE is not a defun node." "constructor_declaration"))) (setq-local treesit-defun-name-function #'java-ts-mode--defun-name) + (setq-local treesit-sentence-type-regexp + (regexp-opt '("statement" + "local_variable_declaration" + "field_declaration" + "module_declaration" + "package_declaration" + "import_declaration"))) + + (setq-local treesit-sexp-type-regexp + (regexp-opt '("annotation" + "parenthesized_expression" + "argument_list" + "identifier" + "modifiers" + "block" + "body" + "literal" + "access" + "reference" + "_type" + "true" + "false"))) + ;; Font-lock. (setq-local treesit-font-lock-settings java-ts-mode--font-lock-settings) (setq-local treesit-font-lock-feature-list diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index 05d69c314bb..6ae325c0657 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -3801,6 +3801,54 @@ Currently there are `js-mode' and `js-ts-mode'." ;;(syntax-propertize (point-max)) ) +(defvar js--treesit-sentence-nodes + '("import_statement" + "debugger_statement" + "expression_statement" + "if_statement" + "switch_statement" + "for_statement" + "for_in_statement" + "while_statement" + "do_statement" + "try_statement" + "with_statement" + "break_statement" + "continue_statement" + "return_statement" + "throw_statement" + "empty_statement" + "labeled_statement" + "variable_declaration" + "lexical_declaration" + "jsx_element" + "jsx_self_closing_element") + "Nodes that designate sentences in JavaScript. +See `treesit-sentence-type-regexp' for more information.") + +(defvar js--treesit-sexp-nodes + '("expression" + "pattern" + "array" + "function" + "string" + "escape" + "template" + "regex" + "number" + "identifier" + "this" + "super" + "true" + "false" + "null" + "undefined" + "arguments" + "pair" + "jsx") + "Nodes that designate sexps in JavaScript. +See `treesit-sexp-type-regexp' for more information.") + ;;;###autoload (define-derived-mode js-ts-mode js-base-mode "JavaScript" "Major mode for editing JavaScript. @@ -3817,6 +3865,11 @@ Currently there are `js-mode' and `js-ts-mode'." ;; Comment. (c-ts-common-comment-setup) (setq-local comment-multi-line t) + + (setq-local treesit-text-type-regexp + (regexp-opt '("comment" + "template_string"))) + ;; Electric-indent. (setq-local electric-indent-chars (append "{}():;," electric-indent-chars)) ;FIXME: js2-mode adds "[]*". @@ -3835,6 +3888,13 @@ Currently there are `js-mode' and `js-ts-mode'." "function_declaration" "lexical_declaration"))) (setq-local treesit-defun-name-function #'js--treesit-defun-name) + + (setq-local treesit-sentence-type-regexp + (regexp-opt js--treesit-sentence-nodes)) + + (setq-local treesit-sexp-type-regexp + (regexp-opt js--treesit-sexp-nodes)) + ;; Fontification. (setq-local treesit-font-lock-settings js--treesit-font-lock-settings) (setq-local treesit-font-lock-feature-list diff --git a/lisp/progmodes/json-ts-mode.el b/lisp/progmodes/json-ts-mode.el index f54d0187f98..6bd9d30328e 100644 --- a/lisp/progmodes/json-ts-mode.el +++ b/lisp/progmodes/json-ts-mode.el @@ -147,6 +147,8 @@ Return nil if there is no name or if NODE is not a defun node." (rx (or "pair" "object"))) (setq-local treesit-defun-name-function #'json-ts-mode--defun-name) + (setq-local treesit-sentence-type-regexp "pair") + ;; Font-lock. (setq-local treesit-font-lock-settings json-ts-mode--font-lock-settings) (setq-local treesit-font-lock-feature-list diff --git a/lisp/progmodes/prog-mode.el b/lisp/progmodes/prog-mode.el index 0f3a477abe5..04071703184 100644 --- a/lisp/progmodes/prog-mode.el +++ b/lisp/progmodes/prog-mode.el @@ -30,7 +30,12 @@ ;;; Code: (eval-when-compile (require 'cl-lib) - (require 'subr-x)) + (require 'subr-x) + (require 'treesit)) + +(declare-function treesit-available-p "treesit.c") +(declare-function treesit-parser-list "treesit.c") +(declare-function treesit-node-type "treesit.c") (defgroup prog-mode nil "Generic programming mode, from which others derive." @@ -102,7 +107,8 @@ (defvar-keymap prog-mode-map :doc "Keymap used for programming modes." - "C-M-q" #'prog-indent-sexp) + "C-M-q" #'prog-indent-sexp + "M-q" #'prog-fill-reindent-defun) (defvar prog-indentation-context nil "When non-nil, provides context for indenting embedded code chunks. @@ -140,6 +146,31 @@ instead." (end (progn (forward-sexp 1) (point)))) (indent-region start end nil)))) +(defun prog-fill-reindent-defun (&optional argument) + "Refill or reindent the paragraph or defun that contains point. + +If the point is in a string or a comment, fill the paragraph that +contains point or follows point. + +Otherwise, reindent the function definition that contains point +or follows point." + (interactive "P") + (save-excursion + (let ((treesit-text-node + (and (treesit-available-p) + (treesit-parser-list) + (string-match-p + treesit-text-type-regexp + (treesit-node-type (treesit-node-at (point))))))) + (if (or treesit-text-node + (nth 8 (syntax-ppss)) + (re-search-forward "\\s-*\\s<" (line-end-position) t)) + (fill-paragraph argument (region-active-p)) + (beginning-of-defun) + (let ((start (point))) + (end-of-defun) + (indent-region start (point) nil)))))) + (defun prog-first-column () "Return the indentation column normally used for top-level constructs." (or (car prog-indentation-context) 0)) diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index 60215978176..1144caf79b6 100644 --- a/lisp/progmodes/ruby-ts-mode.el +++ b/lisp/progmodes/ruby-ts-mode.el @@ -1032,6 +1032,20 @@ leading double colon is not added." ;; Navigation. (setq-local treesit-defun-type-regexp ruby-ts--method-regex) + (setq-local treesit-sexp-type-regexp + (regexp-opt '("class" + "module" + "method" + "argument_list" + "array" + "hash" + "parenthesized_statements" + "if" + "case" + "block" + "do_block" + "begin"))) + ;; AFAIK, Ruby can not nest methods (setq-local treesit-defun-prefer-top-level nil) diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el index 4c06efc8146..17c22ff4751 100644 --- a/lisp/progmodes/sh-script.el +++ b/lisp/progmodes/sh-script.el @@ -1623,6 +1623,10 @@ not written in Bash or sh." ( bracket delimiter misc-punctuation operator))) (setq-local treesit-font-lock-settings sh-mode--treesit-settings) + (setq-local treesit-text-type-regexp + (regexp-opt '("comment" + "heredoc_start" + "heredoc_body"))) (setq-local treesit-defun-type-regexp "function_definition") (treesit-major-mode-setup))) diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index 561b90deedd..3437ea43505 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -314,6 +314,52 @@ Argument LANGUAGE is either `typescript' or `tsx'." :override t '((escape_sequence) @font-lock-escape-face))) +(defvar typescript-ts-mode--sentence-nodes + '("import_statement" + "debugger_statement" + "expression_statement" + "if_statement" + "switch_statement" + "for_statement" + "for_in_statement" + "while_statement" + "do_statement" + "try_statement" + "with_statement" + "break_statement" + "continue_statement" + "return_statement" + "throw_statement" + "empty_statement" + "labeled_statement" + "variable_declaration" + "lexical_declaration" + "property_signature") + "Nodes that designate sentences in TypeScript. +See `treesit-sentence-type-regexp' for more information.") + +(defvar typescript-ts-mode--sexp-nodes + '("expression" + "pattern" + "array" + "function" + "string" + "escape" + "template" + "regex" + "number" + "identifier" + "this" + "super" + "true" + "false" + "null" + "undefined" + "arguments" + "pair") + "Nodes that designate sexps in TypeScript. +See `treesit-sexp-type-regexp' for more information.") + ;;;###autoload (define-derived-mode typescript-ts-base-mode prog-mode "TypeScript" "Major mode for editing TypeScript." @@ -322,6 +368,11 @@ Argument LANGUAGE is either `typescript' or `tsx'." ;; Comments. (c-ts-common-comment-setup) + (setq-local treesit-defun-prefer-top-level t) + + (setq-local treesit-text-type-regexp + (regexp-opt '("comment" + "template_string"))) ;; Electric (setq-local electric-indent-chars @@ -335,6 +386,12 @@ Argument LANGUAGE is either `typescript' or `tsx'." "lexical_declaration"))) (setq-local treesit-defun-name-function #'js--treesit-defun-name) + (setq-local treesit-sentence-type-regexp + (regexp-opt typescript-ts-mode--sentence-nodes)) + + (setq-local treesit-sexp-type-regexp + (regexp-opt typescript-ts-mode--sexp-nodes)) + ;; Imenu (same as in `js-ts-mode'). (setq-local treesit-simple-imenu-settings `(("Function" "\\`function_declaration\\'" nil nil) @@ -396,6 +453,18 @@ Argument LANGUAGE is either `typescript' or `tsx'." (setq-local treesit-simple-indent-rules (typescript-ts-mode--indent-rules 'tsx)) + ;; Navigation + (setq-local treesit-sentence-type-regexp + (regexp-opt (append + typescript-ts-mode--sentence-nodes + '("jsx_element" + "jsx_self_closing_element")))) + + (setq-local treesit-sexp-type-regexp + (regexp-opt (append + typescript-ts-mode--sexp-nodes + '("jsx")))) + ;; Font-lock. (setq-local treesit-font-lock-settings (typescript-ts-mode--font-lock-settings 'tsx)) diff --git a/lisp/progmodes/verilog-mode.el b/lisp/progmodes/verilog-mode.el index 3134a09c44f..2989d7ddb61 100644 --- a/lisp/progmodes/verilog-mode.el +++ b/lisp/progmodes/verilog-mode.el @@ -9,7 +9,7 @@ ;; Keywords: languages ;; The "Version" is the date followed by the decimal rendition of the Git ;; commit hex. -;; Version: 2021.10.14.127365406 +;; Version: 2022.12.18.181110314 ;; Yoni Rabkin <yoni@rabkins.net> contacted the maintainer of this ;; file on 19/3/2008, and the maintainer agreed that when a bug is @@ -124,7 +124,7 @@ ;; ;; This variable will always hold the version number of the mode -(defconst verilog-mode-version "2021-10-14-797711e-vpo-GNU" +(defconst verilog-mode-version "2022-12-18-acb862a-vpo-GNU" "Version of this Verilog mode.") (defconst verilog-mode-release-emacs t "If non-nil, this version of Verilog mode was released with Emacs itself.") @@ -455,11 +455,11 @@ This function may be removed when Emacs 21 is no longer supported." last-command-event))) (defvar verilog-no-change-functions nil - "True if `after-change-functions' is disabled. + "Non-nil if `after-change-functions' is disabled. Use of `syntax-ppss' may break, as ppss's cache may get corrupted.") (defvar verilog-in-hooks nil - "True when within a `verilog-run-hooks' block.") + "Non-nil when within a `verilog-run-hooks' block.") (defmacro verilog-run-hooks (&rest hooks) "Run each hook in HOOKS using `run-hooks'. @@ -505,8 +505,14 @@ Set `verilog-in-hooks' during this time, to assist AUTO caches." (defvar verilog-debug nil "Non-nil means enable debug messages for `verilog-mode' internals.") -(defvar verilog-warn-fatal nil - "Non-nil means `verilog-warn-error' warnings are fatal `error's.") +(defcustom verilog-warn-fatal nil + "Non-nil means `verilog-warn-error' warnings are fatal `error's." + :group 'verilog-mode-auto + :type 'boolean) +(put 'verilog-warn-fatal 'safe-local-variable #'verilog-booleanp) + +;; Internal use similar to `verilog-warn-fatal' +(defvar verilog-warn-fatal-internal t) (defcustom verilog-linter "echo 'No verilog-linter set, see \"M-x describe-variable verilog-linter\"'" @@ -679,6 +685,18 @@ Set to 0 to have all directives start at the left side of the screen." :type 'integer) (put 'verilog-indent-level-directive 'safe-local-variable #'integerp) +(defcustom verilog-indent-ignore-multiline-defines t + "Non-nil means ignore indentation on lines that are part of a multiline define." + :group 'verilog-mode-indent + :type 'boolean) +(put 'verilog-indent-ignore-multiline-defines 'safe-local-variable #'verilog-booleanp) + +(defcustom verilog-indent-ignore-regexp nil + "Regexp that matches lines that should be ignored for indentation." + :group 'verilog-mode-indent + :type 'boolean) +(put 'verilog-indent-ignore-regexp 'safe-local-variable #'stringp) + (defcustom verilog-cexp-indent 2 "Indentation of Verilog statements split across lines." :group 'verilog-mode-indent @@ -723,6 +741,13 @@ Otherwise, line them up." :type 'boolean) (put 'verilog-indent-begin-after-if 'safe-local-variable #'verilog-booleanp) +(defcustom verilog-indent-class-inside-pkg t + "Non-nil means indent classes inside packages. +Otherwise, classes have zero indentation." + :group 'verilog-mode-indent + :type 'boolean) +(put 'verilog-indent-class-inside-pkg 'safe-local-variable #'verilog-booleanp) + (defcustom verilog-align-ifelse nil "Non-nil means align `else' under matching `if'. Otherwise else is lined up with first character on line holding matching if." @@ -730,6 +755,38 @@ Otherwise else is lined up with first character on line holding matching if." :type 'boolean) (put 'verilog-align-ifelse 'safe-local-variable #'verilog-booleanp) +(defcustom verilog-align-decl-expr-comments t + "Non-nil means align declaration and expressions comments." + :group 'verilog-mode-indent + :type 'boolean) +(put 'verilog-align-decl-expr-comments 'safe-local-variable #'verilog-booleanp) + +(defcustom verilog-align-comment-distance 1 + "Distance (in spaces) between longest declaration/expression and comments. +Only works if `verilog-align-decl-expr-comments' is non-nil." + :group 'verilog-mode-indent + :type 'integer) +(put 'verilog-align-comment-distance 'safe-local-variable #'integerp) + +(defcustom verilog-align-assign-expr nil + "Non-nil means align expressions of continuous assignments." + :group 'verilog-mode-indent + :type 'boolean) +(put 'verilog-align-assign-expr 'safe-local-variable #'verilog-booleanp) + +(defcustom verilog-align-typedef-regexp nil + "Regexp that matches user typedefs for declaration alignment." + :group 'verilog-mode-indent + :type '(choice (regexp :tag "Regexp") + (const :tag "None" nil))) +(put 'verilog-align-typedef-regexp 'safe-local-variable #'stringp) + +(defcustom verilog-align-typedef-words nil + "List of words that match user typedefs for declaration alignment." + :group 'verilog-mode-indent + :type '(repeat string)) +(put 'verilog-align-typedef-words 'safe-local-variable #'listp) + (defcustom verilog-minimum-comment-distance 10 "Minimum distance (in lines) between begin and end required before a comment. Setting this variable to zero results in every end acquiring a comment; the @@ -876,6 +933,12 @@ always be saved." :type 'boolean) (put 'verilog-auto-star-save 'safe-local-variable #'verilog-booleanp) +(defcustom verilog-fontify-variables t + "Non-nil means fontify declaration variables." + :group 'verilog-mode-actions + :type 'boolean) +(put 'verilog-fontify-variables 'safe-local-variable #'verilog-booleanp) + (defvar verilog-auto-update-tick nil "Modification tick at which autos were last performed.") @@ -1052,7 +1115,7 @@ You might want these defined in each file; put at the *END* of your file something like: // Local Variables: - // verilog-library-files:(\"/some/path/technology.v\" \"/some/path/tech2.v\") + // verilog-library-files:(\"/path/technology.v\" \"/path2/tech2.v\") // End: Verilog-mode attempts to detect changes to this local variable, but they @@ -1124,7 +1187,7 @@ those temporaries reset. See example in `verilog-auto-reset'." (put 'verilog-auto-reset-blocking-in-non 'safe-local-variable #'verilog-booleanp) (defcustom verilog-auto-reset-widths t - "True means AUTORESET should determine the width of signals. + "Non-nil means AUTORESET should determine the width of signals. This is then used to set the width of the zero (32'h0 for example). This is required by some lint tools that aren't smart enough to ignore widths of the constant zero. This may result in ugly code when parameters determine @@ -1264,7 +1327,7 @@ See `verilog-auto-inst-param-value'." Also affects AUTOINSTPARAM. Declaration order is the default for backward compatibility, and as some teams prefer signals that are declared together to remain together. Sorted order reduces -changes when declarations are moved around in a file. Sorting is +changes when declarations are moved around in a file. Sorting is within input/output/inout groupings, there is intentionally no option to intermix between input/output/inouts. @@ -1275,7 +1338,7 @@ See also `verilog-auto-arg-sort'." (put 'verilog-auto-inst-sort 'safe-local-variable #'verilog-booleanp) (defcustom verilog-auto-inst-vector t - "True means when creating default ports with AUTOINST, use bus subscripts. + "Non-nil means when creating default ports with AUTOINST, use bus subscripts. If nil, skip the subscript when it matches the entire bus as declared in the module (AUTOWIRE signals always are subscripted, you must manually declare the wire to have the subscripts removed.) Setting this to nil may @@ -1515,10 +1578,9 @@ If set will become buffer local.") (define-key map "\C-c/" #'verilog-star-comment) (define-key map "\C-c\C-c" #'verilog-comment-region) (define-key map "\C-c\C-u" #'verilog-uncomment-region) - (when (featurep 'xemacs) - (define-key map [(meta control h)] #'verilog-mark-defun) - (define-key map "\M-\C-a" #'verilog-beg-of-defun) - (define-key map "\M-\C-e" #'verilog-end-of-defun)) + (define-key map "\M-\C-h" #'verilog-mark-defun) + (define-key map "\M-\C-a" #'verilog-beg-of-defun) + (define-key map "\M-\C-e" #'verilog-end-of-defun) (define-key map "\C-c\C-d" #'verilog-goto-defun) (define-key map "\C-c\C-k" #'verilog-delete-auto) (define-key map "\C-c\C-a" #'verilog-auto) @@ -2028,11 +2090,11 @@ Where __FLAGS__ appears in the string `verilog-current-flags' will be substituted. Where __FILE__ appears in the string, the current buffer's file-name, without the directory portion, will be substituted." - (setq command (verilog-string-replace-matches + (setq command (verilog-string-replace-matches ;; Note \\b only works if under verilog syntax table "\\b__FLAGS__\\b" (verilog-current-flags) t t command)) - (setq command (verilog-string-replace-matches + (setq command (verilog-string-replace-matches "\\b__FILE__\\b" (file-name-nondirectory (or (buffer-file-name) "")) t t command)) @@ -2468,13 +2530,8 @@ find the errors." ;; ;; Regular expressions used to calculate indent, etc. ;; -(defconst verilog-symbol-re "\\<[a-zA-Z_][a-zA-Z_0-9.]*\\>") -;; Want to match -;; aa : -;; aa,bb : -;; a[34:32] : -;; a, -;; b : +(defconst verilog-identifier-re "[a-zA-Z_][a-zA-Z_0-9]*") +(defconst verilog-identifier-sym-re (concat "\\<" verilog-identifier-re "\\>")) (defconst verilog-assignment-operator-re (eval-when-compile (verilog-regexp-opt @@ -2492,12 +2549,11 @@ find the errors." ) 't ))) (defconst verilog-assignment-operation-re - (concat - ;; "\\(^\\s-*[A-Za-z0-9_]+\\(\\[\\([A-Za-z0-9_]+\\)\\]\\)*\\s-*\\)" - ;; "\\(^\\s-*[^=<>+-*/%&|^:\\s-]+[^=<>+-*/%&|^\n]*?\\)" - "\\(^.*?\\)" "\\B" verilog-assignment-operator-re "\\B" )) + (concat "\\(^.*?\\)" verilog-assignment-operator-re)) +(defconst verilog-assignment-operation-re-2 + (concat "\\(.*?\\)" verilog-assignment-operator-re)) -(defconst verilog-label-re (concat verilog-symbol-re "\\s-*:\\s-*")) +(defconst verilog-label-re (concat verilog-identifier-sym-re "\\s-*:\\s-*")) (defconst verilog-property-re (concat "\\(" verilog-label-re "\\)?" ;; "\\(assert\\|assume\\|cover\\)\\s-+property\\>" @@ -2732,6 +2788,9 @@ find the errors." "\\|\\(\\<clocking\\>\\)" ;17 "\\|\\(\\<`[ou]vm_[a-z_]+_begin\\>\\)" ;18 "\\|\\(\\<`vmm_[a-z_]+_member_begin\\>\\)" + "\\|\\(\\<`ifn?def\\>\\)" ;20, matched end can be: `else `elsif `endif + "\\|\\(\\<`else\\>\\)" ;21, matched end can be: `endif + "\\|\\(\\<`elsif\\>\\)" ;22, matched end can be: `else `endif ;; )) @@ -2817,40 +2876,54 @@ find the errors." "localparam" "parameter" "var" ;; misc "string" "event" "chandle" "virtual" "enum" "genvar" - "struct" "union" + "struct" "union" "type" ;; builtin classes "mailbox" "semaphore" )))) -(defconst verilog-declaration-re - (concat "\\(" verilog-declaration-prefix-re "\\s-*\\)?" verilog-declaration-core-re)) (defconst verilog-range-re "\\(\\[[^]]*\\]\\s-*\\)+") (defconst verilog-optional-signed-re "\\s-*\\(\\(un\\)?signed\\)?") (defconst verilog-optional-signed-range-re - (concat - "\\s-*\\(\\<\\(reg\\|wire\\)\\>\\s-*\\)?\\(\\<\\(un\\)?signed\\>\\s-*\\)?\\(" verilog-range-re "\\)?")) + (concat "\\s-*\\(\\<\\(reg\\|wire\\)\\>\\s-*\\)?\\(\\<\\(un\\)?signed\\>\\s-*\\)?\\(" verilog-range-re "\\)?")) (defconst verilog-macroexp-re "`\\sw+") - (defconst verilog-delay-re "#\\s-*\\(\\([0-9_]+\\('s?[hdxbo][0-9a-fA-F_xz]+\\)?\\)\\|\\(([^()]*)\\)\\|\\(\\sw+\\)\\)") -(defconst verilog-declaration-re-2-no-macro - (concat "\\s-*" verilog-declaration-re - "\\s-*\\(\\(" verilog-optional-signed-range-re "\\)\\|\\(" verilog-delay-re "\\)" - "\\)")) -(defconst verilog-declaration-re-2-macro - (concat "\\s-*" verilog-declaration-re - "\\s-*\\(\\(" verilog-optional-signed-range-re "\\)\\|\\(" verilog-delay-re "\\)" - "\\|\\(" verilog-macroexp-re "\\)" - "\\)")) -(defconst verilog-declaration-re-1-macro - (concat "^" verilog-declaration-re-2-macro)) - -(defconst verilog-declaration-re-1-no-macro (concat "^" verilog-declaration-re-2-no-macro)) +(defconst verilog-interface-modport-re "\\(\\s-*\\([a-zA-Z0-9`_$]+\\.[a-zA-Z0-9`_$]+\\)[ \t\f]+\\)") +(defconst verilog-comment-start-regexp "//\\|/\\*" "Dual comment value for `comment-start-regexp'.") +(defconst verilog-typedef-enum-re + (concat "^\\s-*\\(typedef\\s-+\\)?enum\\(\\s-+" verilog-declaration-core-re verilog-optional-signed-range-re "\\)?")) + +(defconst verilog-declaration-simple-re + (concat "\\(" verilog-declaration-prefix-re "\\s-*\\)?" verilog-declaration-core-re)) +(defconst verilog-declaration-re + (concat "\\s-*" verilog-declaration-simple-re + "\\s-*\\(\\(" verilog-optional-signed-range-re "\\)\\|\\(" verilog-delay-re "\\)\\)")) +(defconst verilog-declaration-re-macro + (concat "\\s-*" verilog-declaration-simple-re + "\\s-*\\(\\(" verilog-optional-signed-range-re "\\)\\|\\(" verilog-delay-re "\\)\\|\\(" verilog-macroexp-re "\\)\\)")) +(defconst verilog-declaration-or-iface-mp-re + (concat "\\(" verilog-declaration-re "\\)\\|\\(" verilog-interface-modport-re "\\)")) +(defconst verilog-declaration-embedded-comments-re + (concat "\\( " verilog-declaration-re "\\) ""\\s-*" "\\(" verilog-comment-start-regexp "\\)") + "Match expressions such as: input logic [7:0] /* auto enum sm_psm */ sm_psm;.") (defconst verilog-defun-re (eval-when-compile (verilog-regexp-words '("macromodule" "connectmodule" "module" "class" "program" "interface" "package" "primitive" "config")))) (defconst verilog-end-defun-re (eval-when-compile (verilog-regexp-words '("endconnectmodule" "endmodule" "endclass" "endprogram" "endinterface" "endpackage" "endprimitive" "endconfig")))) +(defconst verilog-defun-tf-re-beg + (eval-when-compile (verilog-regexp-words '("macromodule" "connectmodule" "module" "class" "program" "interface" "package" "primitive" "config" "function" "task")))) +(defconst verilog-defun-tf-re-end + (eval-when-compile (verilog-regexp-words '("endconnectmodule" "endmodule" "endclass" "endprogram" "endinterface" "endpackage" "endprimitive" "endconfig" "endfunction" "endtask")))) +(defconst verilog-defun-tf-re-all + (eval-when-compile (verilog-regexp-words '("macromodule" "connectmodule" "module" "class" "program" "interface" "package" "primitive" "config" "function" "task" + "endconnectmodule" "endmodule" "endclass" "endprogram" "endinterface" "endpackage" "endprimitive" "endconfig" "endfunction" "endtask")))) +(defconst verilog-defun-no-class-re + (eval-when-compile (verilog-regexp-words '("macromodule" "connectmodule" "module" "program" "interface" "package" "primitive" "config")))) +(defconst verilog-end-defun-no-class-re + (eval-when-compile (verilog-regexp-words '("endconnectmodule" "endmodule" "endprogram" "endinterface" "endpackage" "endprimitive" "endconfig")))) (defconst verilog-zero-indent-re (concat verilog-defun-re "\\|" verilog-end-defun-re)) +(defconst verilog-zero-indent-no-class-re + (concat verilog-defun-no-class-re "\\|" verilog-end-defun-no-class-re)) (defconst verilog-inst-comment-re (eval-when-compile (verilog-regexp-words '("Outputs" "Inouts" "Inputs" "Interfaces" "Interfaced")))) @@ -2983,19 +3056,38 @@ find the errors." (defconst verilog-extended-case-re "\\(\\(unique0?\\s-+\\|priority\\s-+\\)?case[xz]?\\|randcase\\)") (defconst verilog-extended-complete-re ;; verilog-beg-of-statement also looks backward one token to extend this match - (concat "\\(\\(\\<extern\\s-+\\|\\<\\(\\<\\(pure\\|context\\)\\>\\s-+\\)?virtual\\s-+\\|\\<protected\\s-+\\|\\<static\\s-+\\)*\\(\\<function\\>\\|\\<task\\>\\)\\)" + (concat "\\(\\(\\<extern\\s-+\\|\\<\\(\\<\\(pure\\|context\\)\\>\\s-+\\)?virtual\\s-+\\|\\<local\\s-+\\|\\<protected\\s-+\\|\\<static\\s-+\\)*\\(\\<function\\>\\|\\<task\\>\\)\\)" "\\|\\(\\(\\<typedef\\>\\s-+\\)*\\(\\<struct\\>\\|\\<union\\>\\|\\<class\\>\\)\\)" "\\|\\(\\(\\<\\(import\\|export\\)\\>\\s-+\\)?\\(\"DPI\\(-C\\)?\"\\s-+\\)?\\(\\<\\(pure\\|context\\)\\>\\s-+\\)?\\([A-Za-z_][A-Za-z0-9_]*\\s-*=\\s-*\\)?\\(function\\>\\|task\\>\\)\\)" "\\|" verilog-extended-case-re )) + +(eval-and-compile + (defconst verilog-basic-complete-words + '("always" "assign" "always_latch" "always_ff" "always_comb" "analog" "connectmodule" "constraint" + "import" "initial" "final" "module" "macromodule" "repeat" "randcase" "while" + "if" "for" "forever" "foreach" "else" "parameter" "do" "localparam" "assert" "default" "generate")) + (defconst verilog-basic-complete-words-expr + (let ((words verilog-basic-complete-words)) + (dolist (word '("default" "parameter" "localparam")) + (setq words (remove word words))) + words)) + (defconst verilog-basic-complete-words-expr-no-assign + (remove "assign" verilog-basic-complete-words-expr))) + (defconst verilog-basic-complete-re (eval-when-compile - (verilog-regexp-words - '( - "always" "assign" "always_latch" "always_ff" "always_comb" "analog" "connectmodule" "constraint" - "import" "initial" "final" "module" "macromodule" "repeat" "randcase" "while" - "if" "for" "forever" "foreach" "else" "parameter" "do" "localparam" "assert" - )))) -(defconst verilog-complete-reg + (verilog-regexp-words verilog-basic-complete-words))) + +(defconst verilog-basic-complete-expr-re + (eval-when-compile + (verilog-regexp-words verilog-basic-complete-words-expr))) + +(defconst verilog-basic-complete-expr-no-assign-re + (eval-when-compile + (verilog-regexp-words verilog-basic-complete-words-expr-no-assign))) + + +(defconst verilog-complete-re (concat verilog-extended-complete-re "\\|\\(" verilog-basic-complete-re "\\)")) @@ -3114,9 +3206,6 @@ find the errors." )) "List of Verilog keywords.") -(defconst verilog-comment-start-regexp "//\\|/\\*" - "Dual comment value for `comment-start-regexp'.") - (defvar verilog-mode-syntax-table (let ((table (make-syntax-table))) ;; Populate the syntax TABLE. @@ -3338,12 +3427,12 @@ See also `verilog-font-lock-extra-types'.") (list "\\<\\(\\(macro\\|connect\\)?module\\|primitive\\|class\\|program\\|interface\\|package\\|task\\)\\>\\s-*\\(\\sw+\\)" '(1 font-lock-keyword-face) - '(3 font-lock-function-name-face prepend)) + '(3 font-lock-function-name-face)) ;; Fontify function definitions (list (concat "\\<function\\>\\s-+\\(integer\\|real\\(time\\)?\\|time\\)\\s-+\\(\\sw+\\)" ) '(1 font-lock-keyword-face) - '(3 font-lock-constant-face prepend)) + '(3 font-lock-constant-face)) '("\\<function\\>\\s-+\\(\\[[^]]+\\]\\)\\s-+\\(\\sw+\\)" (1 font-lock-keyword-face) (2 font-lock-constant-face append)) @@ -3358,12 +3447,12 @@ See also `verilog-font-lock-extra-types'.") ;; Pre-form for this anchored matcher: ;; First, avoid declaration keywords written in comments, ;; which can also trigger this anchor. - '(if (not (verilog-in-comment-p)) + '(if (and (not (verilog-in-comment-p)) + (not (member (thing-at-point 'symbol) verilog-keywords))) (verilog-single-declaration-end verilog-highlight-max-lookahead) (point)) ;; => current declaration statement is of 0 length nil ;; Post-form: nothing to be done - '(0 font-lock-variable-name-face t t))) - ))) + '(0 font-lock-variable-name-face)))))) (setq verilog-font-lock-keywords-2 @@ -3617,7 +3706,7 @@ inserted using a single call to `verilog-insert'." (defun verilog-single-declaration-end (limit) "Return pos where current (single) declaration statement ends. Also, this function moves POINT forward to the start of a variable name -(skipping the range-part and whitespace). +\(skipping the range-part and whitespace). Function expected to be called with POINT just after a declaration keyword. LIMIT sets the max POINT for searching and moving to. No such limit if LIMIT is 0. @@ -3629,8 +3718,6 @@ Meaning of *single* declaration: and `output [1:0] y' is the other single declaration. In the 1st single declaration, POINT is moved to start of `clk'. And in the 2nd declaration, POINT is moved to `y'." - - (let (maxpoint old-point) ;; maxpoint = min(curr-point + limit, buffer-size) (setq maxpoint (if (eq limit 0) @@ -3651,7 +3738,7 @@ POINT is moved to `y'." (not (eq old-point (point))) (not (eq (char-after) ?\; )) (not (eq (char-after) ?\) )) - (not (looking-at verilog-declaration-re))) + (not (looking-at (verilog-get-declaration-re)))) (setq old-point (point)) (ignore-errors (forward-sexp) @@ -3669,31 +3756,28 @@ This function moves POINT to the next variable within the same declaration (if it exists). LIMIT is expected to be the pos at which current single-declaration ends, obtained using `verilog-single-declaration-end'." - - (let (found-var old-point) - - ;; Remove starting whitespace - (verilog-forward-ws&directives limit) - - (when (< (point) limit) ;; no matching if this is violated - - ;; Find the variable name (match-data is set here) - (setq found-var (re-search-forward verilog-symbol-re limit t)) - - ;; Walk to this variable's delimiter - (save-match-data - (verilog-forward-ws&directives limit) - (setq old-point nil) - (while (and (< (point) limit) - (not (member (char-after) '(?, ?\) ?\;))) - (not (eq old-point (point)))) - (setq old-point (point)) + (when (and verilog-fontify-variables + (not (member (thing-at-point 'symbol) verilog-keywords))) + (let (found-var old-point) + ;; Remove starting whitespace + (verilog-forward-ws&directives limit) + (when (< (point) limit) ;; no matching if this is violated + ;; Find the variable name (match-data is set here) + (setq found-var (re-search-forward verilog-identifier-sym-re limit t)) + ;; Walk to this variable's delimiter + (save-match-data (verilog-forward-ws&directives limit) - (forward-sexp) - (verilog-forward-ws&directives limit)) - ;; Only a comma or semicolon expected at this point - (skip-syntax-forward ".")) - found-var))) + (setq old-point nil) + (while (and (< (point) limit) + (not (member (char-after) '(?, ?\) ?\] ?\} ?\;))) + (not (eq old-point (point)))) + (setq old-point (point)) + (verilog-forward-ws&directives limit) + (forward-sexp) + (verilog-forward-ws&directives limit)) + ;; Only a comma or semicolon expected at this point + (skip-syntax-forward ".")) + found-var)))) (defun verilog-point-text (&optional pointnum) "Return text describing where POINTNUM or current point is (for errors). @@ -3728,9 +3812,14 @@ Use filename, if current buffer being edited shorten to just buffer name." (elsec 1) (found nil) (st (point))) - (if (not (looking-at "\\<")) - (forward-word-strictly -1)) + (unless (looking-at "\\<") + (forward-word-strictly -1)) (cond + ((save-excursion + (goto-char st) + (member (preceding-char) '(?\) ?\} ?\]))) + (goto-char st) + (backward-sexp 1)) ((verilog-skip-backward-comment-or-string)) ((looking-at "\\<else\\>") (setq reg (concat @@ -3754,7 +3843,17 @@ Use filename, if current buffer being edited shorten to just buffer name." (setq found 't)))))) ((looking-at verilog-end-block-re) (verilog-leap-to-head)) - ((looking-at "\\(endmodule\\>\\)\\|\\(\\<endprimitive\\>\\)\\|\\(\\<endclass\\>\\)\\|\\(\\<endprogram\\>\\)\\|\\(\\<endinterface\\>\\)\\|\\(\\<endpackage\\>\\)\\|\\(\\<endconnectmodule\\>\\)") + (;; Fallback, when current word does not match `verilog-end-block-re' + (looking-at (concat + "\\(\\<endmodule\\>\\)\\|" ; 1 + "\\(\\<endprimitive\\>\\)\\|" ; 2 + "\\(\\<endclass\\>\\)\\|" ; 3 + "\\(\\<endprogram\\>\\)\\|" ; 4 + "\\(\\<endinterface\\>\\)\\|" ; 5 + "\\(\\<endpackage\\>\\)\\|" ; 6 + "\\(\\<endconnectmodule\\>\\)\\|" ; 7 + "\\(\\<endchecker\\>\\)\\|" ; 8 + "\\(\\<endconfig\\>\\)")) ; 9 (cond ((match-end 1) (verilog-re-search-backward "\\<\\(macro\\)?module\\>" nil 'move)) @@ -3769,7 +3868,11 @@ Use filename, if current buffer being edited shorten to just buffer name." ((match-end 6) (verilog-re-search-backward "\\<package\\>" nil 'move)) ((match-end 7) - (verilog-re-search-backward "\\<connectmodule\\>" nil 'move)) + (verilog-re-search-backward "\\<connectmodule\\>" nil 'move)) + ((match-end 8) + (verilog-re-search-backward "\\<checker\\>" nil 'move)) + ((match-end 9) + (verilog-re-search-backward "\\<config\\>" nil 'move)) (t (goto-char st) (backward-sexp 1)))) @@ -3782,9 +3885,14 @@ Use filename, if current buffer being edited shorten to just buffer name." (md 2) (st (point)) (nest 'yes)) - (if (not (looking-at "\\<")) - (forward-word-strictly -1)) + (unless (looking-at "\\<") + (forward-word-strictly -1)) (cond + ((save-excursion + (goto-char st) + (member (following-char) '(?\( ?\{ ?\[))) + (goto-char st) + (forward-sexp 1)) ((verilog-skip-forward-comment-or-string) (verilog-forward-syntactic-ws)) ((looking-at verilog-beg-block-re-ordered) @@ -3843,22 +3951,31 @@ Use filename, if current buffer being edited shorten to just buffer name." ;; Search forward for matching endtask (setq reg "\\<endtask\\>" ) (setq nest 'no)) - ((match-end 12) + ((match-end 13) ;; Search forward for matching endgenerate (setq reg "\\(\\<generate\\>\\)\\|\\(\\<endgenerate\\>\\)" )) - ((match-end 13) + ((match-end 14) ;; Search forward for matching endgroup (setq reg "\\(\\<covergroup\\>\\)\\|\\(\\<endgroup\\>\\)" )) - ((match-end 14) + ((match-end 15) ;; Search forward for matching endproperty (setq reg "\\(\\<property\\>\\)\\|\\(\\<endproperty\\>\\)" )) - ((match-end 15) + ((match-end 16) ;; Search forward for matching endsequence (setq reg "\\(\\<\\(rand\\)?sequence\\>\\)\\|\\(\\<endsequence\\>\\)" ) (setq md 3)) ; 3 to get to endsequence in the reg above ((match-end 17) ;; Search forward for matching endclocking - (setq reg "\\(\\<clocking\\>\\)\\|\\(\\<endclocking\\>\\)" ))) + (setq reg "\\(\\<clocking\\>\\)\\|\\(\\<endclocking\\>\\)" )) + ((match-end 20) + ;; Search forward for matching `ifn?def, can be `else `elseif or `endif + (setq reg "\\(\\<`ifn?def\\>\\)\\|\\(\\<`endif\\>\\|\\<`else\\>\\|\\<`elsif\\>\\)" )) + ((match-end 21) + ;; Search forward for matching `else, can be `endif + (setq reg "\\(\\<`else\\>\\|\\<`ifn?def\\>\\)\\|\\(\\<`endif\\>\\)" )) + ((match-end 22) + ;; Search forward for matching `elsif, can be `else or `endif, DONT support `elsif + (setq reg "\\(\\<`elsif\\>\\|\\<`ifn?def\\>\\)\\|\\(\\<`endif\\>\\|\\<`else\\>\\)" ))) (if (and reg (forward-word-strictly 1)) (catch 'skip @@ -3867,15 +3984,26 @@ Use filename, if current buffer being edited shorten to just buffer name." here) (while (verilog-re-search-forward reg nil 'move) (cond - ((match-end md) ; a closer in regular expression, so we are climbing out + ((and (or (match-end md) + (and (member (match-string-no-properties 1) '("`else" "`elsif")) + (= 1 depth))) + (or (and (member (match-string-no-properties 2) '("`else" "`elsif")) + (= 1 depth)) + ;; stop at `else/`elsif which matching ifn?def (or `elsif with same depth) + ;; a closer in regular expression, so we are climbing out + (not (member (match-string-no-properties 2) '("`else" "`elsif"))))) (setq depth (1- depth)) (if (= 0 depth) ; we are out! (throw 'skip 1))) - ((match-end 1) ; an opener in the r-e, so we are in deeper now + ((and (match-end 1) ; an opener in the r-e, so we are in deeper now + (not (member (match-string-no-properties 1) '("`else" "`elsif")))) (setq here (point)) ; remember where we started (goto-char (match-beginning 1)) (cond - ((if (or + ((verilog-looking-back "\\(\\<typedef\\>\\s-+\\)" (point-at-bol)) + ;; avoid nesting for typedef class defs + (forward-word-strictly 1)) + ((if (or (looking-at verilog-disable-fork-re) (and (looking-at "fork") (progn @@ -3890,28 +4018,37 @@ Use filename, if current buffer being edited shorten to just buffer name." (throw 'skip 1)))))) ((looking-at (concat - "\\(\\<\\(macro\\)?module\\>\\)\\|" - "\\(\\<primitive\\>\\)\\|" - "\\(\\<class\\>\\)\\|" - "\\(\\<program\\>\\)\\|" - "\\(\\<interface\\>\\)\\|" - "\\(\\<package\\>\\)\\|" - "\\(\\<connectmodule\\>\\)")) + "\\(\\<\\(macro\\)?module\\>\\)\\|" ; 1,2 + "\\(\\<primitive\\>\\)\\|" ; 3 + "\\(\\(\\(interface\\|virtual\\)\\s-+\\)?\\<class\\>\\)\\|" ; 4,5,6 + "\\(\\<program\\>\\)\\|" ; 7 + "\\(\\<interface\\>\\)\\|" ; 8 + "\\(\\<package\\>\\)\\|" ; 9 + "\\(\\<connectmodule\\>\\)\\|" ; 10 + "\\(\\<generate\\>\\)\\|" ; 11 + "\\(\\<checker\\>\\)\\|" ; 12 + "\\(\\<config\\>\\)")) ; 13 (cond ((match-end 1) (verilog-re-search-forward "\\<endmodule\\>" nil 'move)) - ((match-end 2) - (verilog-re-search-forward "\\<endprimitive\\>" nil 'move)) ((match-end 3) - (verilog-re-search-forward "\\<endclass\\>" nil 'move)) + (verilog-re-search-forward "\\<endprimitive\\>" nil 'move)) ((match-end 4) + (verilog-re-search-forward "\\<endclass\\>" nil 'move)) + ((match-end 7) (verilog-re-search-forward "\\<endprogram\\>" nil 'move)) - ((match-end 5) + ((match-end 8) (verilog-re-search-forward "\\<endinterface\\>" nil 'move)) - ((match-end 6) + ((match-end 9) (verilog-re-search-forward "\\<endpackage\\>" nil 'move)) - ((match-end 7) - (verilog-re-search-forward "\\<endconnectmodule\\>" nil 'move)) + ((match-end 10) + (verilog-re-search-forward "\\<endconnectmodule\\>" nil 'move)) + ((match-end 11) + (verilog-re-search-forward "\\<endgenerate\\>" nil 'move)) + ((match-end 12) + (verilog-re-search-forward "\\<endchecker\\>" nil 'move)) + ((match-end 13) + (verilog-re-search-forward "\\<endconfig\\>" nil 'move)) (t (goto-char st) (if (= (following-char) ?\) ) @@ -3924,11 +4061,69 @@ Use filename, if current buffer being edited shorten to just buffer name." (forward-sexp 1)))))) (defun verilog-declaration-beg () - (verilog-re-search-backward verilog-declaration-re (bobp) t)) - -;; -;; -;; Mode + (verilog-re-search-backward (verilog-get-declaration-re) (bobp) t)) + +(defun verilog-align-typedef-enabled-p () + "Return non-nil if alignment of user typedefs is enabled. +This will be automatically set when either `verilog-align-typedef-regexp' +or `verilog-align-typedef-words' are non-nil." + (when (or verilog-align-typedef-regexp + verilog-align-typedef-words) + t)) + +(defun verilog-get-declaration-typedef-re () + "Return regexp of a user defined typedef. +See `verilog-align-typedef-regexp' and `verilog-align-typedef-words'." + (let (typedef-re words words-re re) + (when (verilog-align-typedef-enabled-p) + (setq typedef-re verilog-align-typedef-regexp) + (setq words verilog-align-typedef-words) + (setq words-re (verilog-regexp-words verilog-align-typedef-words)) + (cond ((and typedef-re (not words)) + (setq re typedef-re)) + ((and (not typedef-re) words) + (setq re words-re)) + ((and typedef-re words) + (setq re (concat verilog-align-typedef-regexp "\\|" words-re)))) + (concat "\\s-*" "\\(" verilog-declaration-prefix-re "\\s-*\\(" verilog-range-re "\\)?" "\\s-*\\)?" + (concat "\\(" re "\\)") + "\\(\\s-*" verilog-range-re "\\)?\\s-+")))) + +(defun verilog-get-declaration-re (&optional type) + "Return declaration regexp depending on customizable variables and TYPE." + (let ((re (cond ((equal type 'iface-mp) + verilog-declaration-or-iface-mp-re) + ((equal type 'embedded-comments) + verilog-declaration-embedded-comments-re) + (verilog-indent-declaration-macros + verilog-declaration-re-macro) + (t + verilog-declaration-re)))) + (when (and (verilog-align-typedef-enabled-p) + (or (string= re verilog-declaration-or-iface-mp-re) + (string= re verilog-declaration-re))) + (setq re (concat "\\(" (verilog-get-declaration-typedef-re) "\\)\\|\\(" re "\\)"))) + re)) + +(defun verilog-looking-at-decl-to-align () + "Return non-nil if pointing at a Verilog variable declaration that must be aligned." + (let* ((re (verilog-get-declaration-re)) + (valid-re (looking-at re)) + (id-pos (match-end 0))) + (and valid-re + (not (verilog-at-struct-decl-p)) + (not (verilog-at-enum-decl-p)) + (save-excursion + (goto-char id-pos) + (verilog-forward-syntactic-ws) + (and (not (looking-at ";")) + (not (member (thing-at-point 'symbol) verilog-keywords)) + (progn ; Avoid alignment of instances whose name match user defined types + (forward-word) + (verilog-forward-syntactic-ws) + (not (looking-at "(")))))))) + +;;; Mode: ;; (defvar verilog-which-tool 1) ;;;###autoload @@ -3965,6 +4160,11 @@ Variables controlling indentation/edit style: function keyword. `verilog-indent-level-directive' (default 1) Indentation of \\=`ifdef/\\=`endif blocks. + `verilog-indent-ignore-multiline-defines' (default t) + Non-nil means ignore indentation on lines that are part of a multiline + define. + `verilog-indent-ignore-regexp' (default nil + Regexp that matches lines that should be ignored for indentation. `verilog-cexp-indent' (default 1) Indentation of Verilog statements broken across lines i.e.: if (a) @@ -3988,6 +4188,9 @@ Variables controlling indentation/edit style: otherwise you get: if (a) begin + `verilog-indent-class-inside-pkg' (default t) + Non-nil means indent classes inside packages. + Otherwise, classes have zero indentation. `verilog-auto-endcomments' (default t) Non-nil means a comment /* ... */ is set after the ends which ends cases, tasks, functions and modules. @@ -3997,6 +4200,17 @@ Variables controlling indentation/edit style: will be inserted. Setting this variable to zero results in every end acquiring a comment; the default avoids too many redundant comments in tight quarters. + `verilog-align-decl-expr-comments' (default t) + Non-nil means align declaration and expressions comments. + `verilog-align-comment-distance' (default 1) + Distance (in spaces) between longest declaration and comments. + Only works if `verilog-align-decl-expr-comments' is non-nil. + `verilog-align-assign-expr' (default nil) + Non-nil means align expressions of continuous assignments. + `verilog-align-typedef-regexp' (default nil) + Regexp that matches user typedefs for declaration alignment. + `verilog-align-typedef-words' (default nil) + List of words that match user typedefs for declaration alignment. `verilog-auto-lineup' (default `declarations') List of contexts where auto lineup of code should be done. @@ -4020,17 +4234,20 @@ Some other functions are: \\[verilog-mark-defun] Mark function. \\[verilog-beg-of-defun] Move to beginning of current function. \\[verilog-end-of-defun] Move to end of current function. - \\[verilog-label-be] Label matching begin ... end, fork ... join, etc statements. + \\[verilog-label-be] Label matching begin ... end, fork ... join, etc + statements. \\[verilog-comment-region] Put marked area in a comment. - \\[verilog-uncomment-region] Uncomment an area commented with \\[verilog-comment-region]. + \\[verilog-uncomment-region] Uncomment an area commented with + \\[verilog-comment-region]. \\[verilog-insert-block] Insert begin ... end. \\[verilog-star-comment] Insert /* ... */. \\[verilog-sk-always] Insert an always @(AS) begin .. end block. \\[verilog-sk-begin] Insert a begin .. end block. \\[verilog-sk-case] Insert a case block, prompting for details. - \\[verilog-sk-for] Insert a for (...) begin .. end block, prompting for details. + \\[verilog-sk-for] Insert a for (...) begin .. end block, prompting for + details. \\[verilog-sk-generate] Insert a generate .. endgenerate block. \\[verilog-sk-header] Insert a header block at the top of file. \\[verilog-sk-initial] Insert an initial begin .. end block. @@ -4053,14 +4270,17 @@ Some other functions are: \\[verilog-sk-else-if] Insert an else if (..) begin .. end block. \\[verilog-sk-comment] Insert a comment block. \\[verilog-sk-assign] Insert an assign .. = ..; statement. - \\[verilog-sk-function] Insert a function .. begin .. end endfunction block. + \\[verilog-sk-function] Insert a function .. begin .. end endfunction + block. \\[verilog-sk-input] Insert an input declaration, prompting for details. \\[verilog-sk-output] Insert an output declaration, prompting for details. - \\[verilog-sk-state-machine] Insert a state machine definition, prompting for details. + \\[verilog-sk-state-machine] Insert a state machine definition, prompting + for details. \\[verilog-sk-inout] Insert an inout declaration, prompting for details. \\[verilog-sk-wire] Insert a wire declaration, prompting for details. \\[verilog-sk-reg] Insert a register declaration, prompting for details. - \\[verilog-sk-define-signal] Define signal under point as a register at the top of the module. + \\[verilog-sk-define-signal] Define signal under point as a register at + the top of the module. All key bindings can be seen in a Verilog-buffer with \\[describe-bindings]. Key bindings specific to `verilog-mode-map' are: @@ -4147,7 +4367,7 @@ Key bindings specific to `verilog-mode-map' are: ;; verilog-mode-hook call added by define-derived-mode ) -;;; Integration with the speedbar +;;; Integration with the speedbar: ;; ;; Avoid problems with XEmacs byte-compiles. @@ -4427,15 +4647,24 @@ following code fragment: "Mark the current Verilog function (or procedure). This puts the mark at the end, and point at the beginning." (interactive) - (if (featurep 'xemacs) - (progn - (push-mark) - (verilog-end-of-defun) - (push-mark) - (verilog-beg-of-defun) - (if (fboundp 'zmacs-activate-region) - (zmacs-activate-region))) - (mark-defun))) + (let (found) + (if (featurep 'xemacs) + (progn + (push-mark) + (verilog-end-of-defun) + (push-mark) + (verilog-beg-of-defun) + (if (fboundp 'zmacs-activate-region) + (zmacs-activate-region))) + ;; GNU Emacs + (when (verilog-beg-of-defun) + (setq found (point)) + (verilog-end-of-defun) + (end-of-line) + (push-mark) + (goto-char found) + (beginning-of-line) + (setq mark-active t))))) (defun verilog-comment-region (start end) ;; checkdoc-params: (start end) @@ -4514,7 +4743,21 @@ area. See also `verilog-comment-region'." (defun verilog-beg-of-defun () "Move backward to the beginning of the current function or procedure." (interactive) - (verilog-re-search-backward verilog-defun-re nil 'move)) + (let (found) + (save-excursion + (when (verilog-looking-back verilog-defun-tf-re-end (point-at-bol)) + (verilog-backward-sexp) + (setq found (point))) + (while (and (not found) + (verilog-re-search-backward verilog-defun-tf-re-all nil t)) + (cond ((verilog-looking-back "\\(\\<typedef\\>\\s-+\\)" (point-at-bol)) ; corner case, e.g. 'typedef class <id>;' + (backward-word)) + ((looking-at verilog-defun-tf-re-end) + (verilog-backward-sexp)) + ((looking-at verilog-defun-tf-re-beg) + (setq found (point)))))) + (when found + (goto-char found)))) (defun verilog-beg-of-defun-quick () "Move backward to the beginning of the current function or procedure. @@ -4525,7 +4768,10 @@ Uses `verilog-scan' cache." (defun verilog-end-of-defun () "Move forward to the end of the current function or procedure." (interactive) - (verilog-re-search-forward verilog-end-defun-re nil 'move)) + (when (or (looking-at verilog-defun-tf-re-beg) + (verilog-beg-of-defun)) + (verilog-forward-sexp) + (point))) (defun verilog-get-end-of-defun () (save-excursion @@ -4542,10 +4788,10 @@ Uses `verilog-scan' cache." (case-fold-search nil) (oldpos (point)) (b (progn - (verilog-beg-of-defun) + (verilog-re-search-backward verilog-defun-re nil 'move) (point-marker))) (e (progn - (verilog-end-of-defun) + (verilog-re-search-forward verilog-end-defun-re nil 'move) (point-marker)))) (goto-char (marker-position b)) (if (> (- e b) 200) @@ -4605,19 +4851,18 @@ Uses `verilog-scan' cache." (goto-char h))) ;; stop if we see an extended complete reg, perhaps a complete one (and - (looking-at verilog-complete-reg) + (looking-at verilog-complete-re) (let* ((p (point))) (while (and (looking-at verilog-extended-complete-re) (progn (setq p (point)) (verilog-backward-token) (/= p (point))))) (goto-char p))) - ;; stop if we see a complete reg (previous found extended ones) - (looking-at verilog-basic-complete-re) ;; stop if previous token is an ender (save-excursion (verilog-backward-token) - (looking-at verilog-end-block-re)))) + (or (looking-at verilog-end-block-re) + (verilog-in-directive-p))))) (verilog-backward-syntactic-ws) (verilog-backward-token)) ;; Now point is where the previous line ended. @@ -4634,28 +4879,23 @@ Uses `verilog-scan' cache." (verilog-backward-syntactic-ws)) (let ((pt (point))) (catch 'done - (while (not (looking-at verilog-complete-reg)) + (while (not (looking-at verilog-complete-re)) (setq pt (point)) (verilog-backward-syntactic-ws) (if (or (bolp) (= (preceding-char) ?\;) + (and (= (preceding-char) ?\{) + (save-excursion + (backward-char) + (verilog-at-struct-p))) (progn (verilog-backward-token) - (looking-at verilog-ends-re))) + (or (looking-at verilog-ends-re) + (looking-at "begin")))) (progn (goto-char pt) (throw 'done t))))) (verilog-forward-syntactic-ws))) -;; -;; (while (and -;; (not (looking-at verilog-complete-reg)) -;; (not (bolp)) -;; (not (= (preceding-char) ?\;))) -;; (verilog-backward-token) -;; (verilog-backward-syntactic-ws) -;; (setq pt (point))) -;; (goto-char pt) -;; ;(verilog-forward-syntactic-ws) (defun verilog-end-of-statement () "Move forward to end of current statement." @@ -4713,7 +4953,7 @@ Uses `verilog-scan' cache." pos))))) (defun verilog-in-case-region-p () - "Return true if in a case region. + "Return non-nil if in a case region. More specifically, point @ in the line foo : @ begin" (interactive) (save-excursion @@ -4758,37 +4998,29 @@ More specifically, point @ in the line foo : @ begin" (forward-sexp arg))) (defun verilog-in-generate-region-p () - "Return true if in a generate region. + "Return non-nil if in a generate region. More specifically, after a generate and before an endgenerate." (interactive) - (let ((nest 1)) - (save-excursion - (catch 'done - (while (and - (/= nest 0) - (verilog-re-search-backward - "\\<\\(module\\)\\|\\(connectmodule\\)\\|\\(generate\\)\\|\\(endgenerate\\)\\|\\(if\\)\\|\\(case\\)\\|\\(for\\)\\>" nil 'move) - (cond - ((match-end 1) ; module - we have crawled out - (throw 'done 1)) - ((match-end 2) ; connectmodule - we have crawled out - (throw 'done 1)) - ((match-end 3) ; generate - (setq nest (1- nest))) - ((match-end 4) ; endgenerate - (setq nest (1+ nest))) - ((match-end 5) ; if - (setq nest (1- nest))) - ((match-end 6) ; case - (setq nest (1- nest))) - ((match-end 7) ; for - (setq nest (1- nest)))))))) - (= nest 0) )) ; return nest + (let ((pos (point)) + gen-beg-point gen-end-point) + (save-match-data + (save-excursion + (and (verilog-re-search-backward "\\<\\(generate\\)\\>" nil t) + (forward-word) + (setq gen-beg-point (point)) + (verilog-forward-sexp) + (backward-word) + (setq gen-end-point (point))))) + (if (and gen-beg-point gen-end-point + (>= pos gen-beg-point) + (<= pos gen-end-point)) + t + nil))) (defun verilog-in-fork-region-p () - "Return true if between a fork and join." + "Return non-nil if between a fork and join." (interactive) - (let ((lim (save-excursion (verilog-beg-of-defun) (point))) + (let ((lim (save-excursion (verilog-re-search-backward verilog-defun-re nil 'move) (point))) (nest 1)) (save-excursion (while (and @@ -4802,7 +5034,7 @@ More specifically, after a generate and before an endgenerate." (= nest 0) )) ; return nest (defun verilog-in-deferred-immediate-final-p () - "Return true if inside an `assert/assume/cover final' statement." + "Return non-nil if inside an `assert/assume/cover final' statement." (interactive) (and (looking-at "final") (verilog-looking-back "\\<\\(?:assert\\|assume\\|cover\\)\\>\\s-+" nil)) @@ -5013,7 +5245,7 @@ primitive or interface named NAME." (insert str) (ding 't)) (let ((lim - (save-excursion (verilog-beg-of-defun) (point))) + (save-excursion (verilog-re-search-backward verilog-defun-re nil 'move) (point))) (here (point))) (cond (;-- handle named block differently @@ -5461,7 +5693,7 @@ For example: becomes: // surefire lint_line_off UDDONX" (interactive) - (let ((buff (if (boundp 'next-error-last-buffer) ;Added to Emacs-22.1 + (let ((buff (if (boundp 'next-error-last-buffer) ; Added to Emacs-22.1 next-error-last-buffer (verilog--suppressed-warnings ((obsolete compilation-last-buffer)) @@ -5585,13 +5817,14 @@ FILENAME to find directory to run in, or defaults to `buffer-file-name'." (defun verilog-warn-error (string &rest args) "Call `error' using STRING and optional ARGS. If `verilog-warn-fatal' is non-nil, call `verilog-warn' instead." - (apply (if verilog-warn-fatal #'error #'verilog-warn) + (apply (if (and verilog-warn-fatal verilog-warn-fatal-internal) + #'error #'verilog-warn) string args)) (defmacro verilog-batch-error-wrapper (&rest body) "Execute BODY and add error prefix to any errors found. This lets programs calling batch mode to easily extract error messages." - `(let ((verilog-warn-fatal nil)) + `(let ((verilog-warn-fatal-internal nil)) (condition-case err (progn ,@body) (error @@ -5721,7 +5954,7 @@ This sets up the appropriate Verilog mode environment, calls (string . 0))) (defun verilog-continued-line-1 (lim) - "Return true if this is a continued line. + "Return non-nil if this is a continued line. Set point to where line starts. Limit search to point LIM." (let ((continued 't)) (if (eq 0 (forward-line -1)) @@ -5774,7 +6007,6 @@ Return a list of two elements: (INDENT-TYPE INDENT-LEVEL)." ;; if we are in a parenthesized list, and the user likes to indent these, return. ;; unless we are in the newfangled coverpoint or constraint blocks (if (and - verilog-indent-lists (verilog-in-paren) (not (verilog-in-coverage-p)) ) @@ -5791,7 +6023,7 @@ Return a list of two elements: (INDENT-TYPE INDENT-LEVEL)." (looking-at verilog-in-constraint-re) )) ; may still get hosed if concat in constraint (let ((sp (point))) (if (and - (not (looking-at verilog-complete-reg)) + (not (looking-at verilog-complete-re)) (verilog-continued-line-1 lim)) (progn (goto-char sp) (throw 'nesting 'cexp)) @@ -5996,6 +6228,12 @@ Return a list of two elements: (INDENT-TYPE INDENT-LEVEL)." (goto-char here) ; or is clocking, starts a new block (throw 'nesting 'block))))) + ;; if find `ifn?def `else `elsif + ((or (match-end 20) + (match-end 21) + (match-end 22)) + (throw 'continue 'foo)) + ((looking-at "\\<class\\|struct\\|function\\|task\\>") ;; *sigh* These words have an optional prefix: ;; extern {virtual|protected}? function a(); @@ -6025,7 +6263,7 @@ Return a list of two elements: (INDENT-TYPE INDENT-LEVEL)." ;; {assert|assume|cover} property (); are complete ;; and could also be labeled: - foo: assert property ;; but - ;; property ID () ... needs end_property + ;; property ID () ... needs endproperty (verilog-beg-of-statement) (if (looking-at verilog-property-re) (throw 'continue 'statement) ; We don't need an endproperty for these @@ -6110,6 +6348,23 @@ of the appropriate enclosing block." (ding 't) (setq nest 0)))))) +(defun verilog-leap-to-class-head () + (let ((nest 1) + (class-re (concat "\\(\\<class\\>\\)\\|\\(\\<endclass\\>\\)"))) + (catch 'skip + (while (verilog-re-search-backward class-re nil 'move) + (cond + ((match-end 1) ; begin + (when (verilog-looking-back "\\(\\<interface\\>\\s-+\\)\\|\\(\\<virtual\\>\\s-+\\)" (point-at-bol)) + (goto-char (match-beginning 0))) + (unless (verilog-looking-back "\\<typedef\\>\\s-+" (point-at-bol)) + (setq nest (1- nest)) + (if (= 0 nest) + ;; Now previous line describes syntax + (throw 'skip 1)))) + ((match-end 2) ; end + (setq nest (1+ nest)))))))) + (defun verilog-leap-to-head () "Move point to the head of this block. Jump from end to matching begin, from endcase to matching case, and so on." @@ -6137,7 +6392,9 @@ Jump from end to matching begin, from endcase to matching case, and so on." (setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\(_any\\|_none\\)?\\>\\)" )) ((looking-at "\\<endclass\\>") ;; 5: Search back for matching class - (setq reg "\\(\\<class\\>\\)\\|\\(\\<endclass\\>\\)" )) + (catch 'nesting + (verilog-leap-to-class-head) + (setq reg nil))) ((looking-at "\\<endtable\\>") ;; 6: Search back for matching table (setq reg "\\(\\<table\\>\\)\\|\\(\\<endtable\\>\\)" )) @@ -6175,7 +6432,19 @@ Jump from end to matching begin, from endcase to matching case, and so on." (setq reg "\\(\\<\\(rand\\)?sequence\\>\\)\\|\\(\\<endsequence\\>\\)" )) ((looking-at "\\<endclocking\\>") ;; 12: Search back for matching clocking - (setq reg "\\(\\<clocking\\)\\|\\(\\<endclocking\\>\\)" ))) + (setq reg "\\(\\<clocking\\)\\|\\(\\<endclocking\\>\\)" )) + ;; Search back for matching package + ((looking-at "\\<endpackage\\>") + (setq reg "\\(\\<package\\>\\)" )) + ;; Search back for matching program + ((looking-at "\\<endprogram\\>") + (setq reg "\\(\\<program\\>\\)" )) + ((looking-at "\\<`endif\\>") + ;; Search back for matching `endif `else `elsif + (setq reg "\\(\\<`ifn?def\\>\\)\\|\\(\\<`endif\\>\\)" )) + ((looking-at "\\<`else\\>") + ;; Search back for matching `else `else `elsif + (setq reg "\\(\\<`ifn?def\\>\\|\\<`elsif\\>\\)\\|\\(\\<`else\\>\\)" ))) (if reg (catch 'skip (if (eq nesting 'yes) @@ -6221,7 +6490,7 @@ Jump from end to matching begin, from endcase to matching case, and so on." (throw 'skip 1))))))) (defun verilog-continued-line () - "Return true if this is a continued line. + "Return non-nil if this is a continued line. Set point to where line starts." (let ((continued 't)) (if (eq 0 (forward-line -1)) @@ -6394,10 +6663,10 @@ Optional BOUND limits search." (let ((state (save-excursion (verilog-syntax-ppss)))) (cond ((nth 7 state) ; in // comment - (verilog-re-search-backward "//" nil 'move) + (re-search-backward "//" nil 'move) (skip-chars-backward "/")) ((nth 4 state) ; in /* */ comment - (verilog-re-search-backward "/\\*" nil 'move)))) + (re-search-backward "/\\*" nil 'move)))) (narrow-to-region bound (point)) (while (/= here (point)) (setq here (point)) @@ -6450,13 +6719,60 @@ Optional BOUND limits search." (if jump (beginning-of-line 2)))))))) +(defun verilog-pos-at-beg-of-statement () + "Return point position at the beginning of current statement." + (save-excursion + (verilog-beg-of-statement) + (point))) + +(defun verilog-col-at-beg-of-statement () + "Return current column at the beginning of current statement." + (save-excursion + (verilog-beg-of-statement) + (current-column))) + +(defun verilog-pos-at-end-of-statement () + "Return point position at the end of current statement." + (save-excursion + (verilog-end-of-statement))) + +(defun verilog-col-at-end-of-statement () + "Return current column at the end of current statement." + (save-excursion + (verilog-end-of-statement) + (current-column))) + +(defun verilog-pos-at-forward-syntactic-ws () + "Return point position at next non whitespace/comment token." + (save-excursion + (verilog-forward-syntactic-ws) + (point))) + +(defun verilog-col-at-forward-syntactic-ws () + "Return current column at next non whitespace/comment token." + (save-excursion + (verilog-forward-syntactic-ws) + (current-column))) + +(defun verilog-pos-at-backward-syntactic-ws () + "Return point position at previous non whitespace/comment token." + (save-excursion + (verilog-backward-syntactic-ws) + (point))) + +(defun verilog-col-at-backward-syntactic-ws () + "Return current column at previous non whitespace/comment token." + (save-excursion + (verilog-backward-syntactic-ws) + (current-column))) + (defun verilog-in-comment-p () - "Return true if in a star or // comment." + "Return non-nil if in a star or // comment." (let ((state (save-excursion (verilog-syntax-ppss)))) (or (nth 4 state) (nth 7 state)))) (defun verilog-in-star-comment-p () - "Return true if in a star comment." + "Return non-nil if in a star comment." (let ((state (save-excursion (verilog-syntax-ppss)))) (and (nth 4 state) ; t if in a comment of style a // or b /**/ @@ -6465,40 +6781,39 @@ Optional BOUND limits search." )))) (defun verilog-in-slash-comment-p () - "Return true if in a slash comment." + "Return non-nil if in a slash comment." (let ((state (save-excursion (verilog-syntax-ppss)))) (nth 7 state))) (defun verilog-in-comment-or-string-p () - "Return true if in a string or comment." + "Return non-nil if in a string or comment." (let ((state (save-excursion (verilog-syntax-ppss)))) (or (nth 3 state) (nth 4 state) (nth 7 state)))) ; Inside string or comment) (defun verilog-in-attribute-p () - "Return true if point is in an attribute (* [] attribute *)." - (save-match-data - (save-excursion - (verilog-re-search-backward "\\((\\*\\)\\|\\(\\*)\\)" nil 'move) - (cond - ((match-end 1) - (progn (goto-char (match-end 1)) - (not (looking-at "\\s-*)"))) - nil) - ((match-end 2) - (progn (goto-char (match-beginning 2)) - (not (looking-at "(\\s-*"))) - nil) - (t nil))))) + "Return non-nil if point is in an attribute (* [] attribute *)." + (let ((pos (point))) + (save-match-data + (save-excursion + (and (verilog-re-search-backward "(\\*" nil 'move) + (progn (forward-sexp) + (skip-chars-backward "*)")) + (< pos (point))))))) (defun verilog-in-parameter-p () - "Return true if point is in a parameter assignment #( p1=1, p2=5)." + "Return non-nil if point is in a parameter assignment #( p1=1, p2=5)." (save-match-data (save-excursion - (verilog-re-search-backward "\\(#(\\)\\|\\()\\)" nil 'move) - (numberp (match-beginning 1))))) + (and (progn + (verilog-backward-up-list 1) + (verilog-backward-syntactic-ws) + (= (preceding-char) ?\#)) + (progn + (verilog-beg-of-statement-1) + (looking-at verilog-defun-re)))))) (defun verilog-in-escaped-name-p () - "Return true if in an escaped name." + "Return non-nil if in an escaped name." (save-excursion (backward-char) (skip-chars-backward "^ \t\n\f") @@ -6507,20 +6822,20 @@ Optional BOUND limits search." nil))) (defun verilog-in-directive-p () - "Return true if in a directive." + "Return non-nil if in a directive." (save-excursion (beginning-of-line) (looking-at verilog-directive-re-1))) (defun verilog-in-parenthesis-p () - "Return true if in a ( ) expression (but not { } or [ ])." + "Return non-nil if in a ( ) expression (but not { } or [ ])." (save-match-data (save-excursion (verilog-re-search-backward "\\((\\)\\|\\()\\)" nil 'move) (numberp (match-beginning 1))))) (defun verilog-in-paren () - "Return true if in a parenthetical expression. + "Return non-nil if in a parenthetical expression. May cache result using `verilog-syntax-ppss'." (let ((state (save-excursion (verilog-syntax-ppss)))) (> (nth 0 state) 0 ))) @@ -6534,7 +6849,7 @@ May cache result using `verilog-syntax-ppss'." 0 ))) (defun verilog-in-paren-quick () - "Return true if in a parenthetical expression. + "Return non-nil if in a parenthetical expression. Always starts from `point-min', to allow inserts with hooks disabled." ;; The -quick refers to its use alongside the other -quick functions, ;; not that it's likely to be faster than verilog-in-paren. @@ -6542,7 +6857,7 @@ Always starts from `point-min', to allow inserts with hooks disabled." (> (nth 0 state) 0 ))) (defun verilog-in-struct-p () - "Return true if in a struct declaration." + "Return non-nil if in a struct declaration." (interactive) (save-excursion (if (verilog-in-paren) @@ -6568,7 +6883,7 @@ Return >0 for nested struct." nil)))) (defun verilog-in-coverage-p () - "Return true if in a constraint or coverpoint expression." + "Return non-nil if in a constraint or coverpoint expression." (interactive) (save-excursion (if (verilog-in-paren) @@ -6608,7 +6923,7 @@ Also move point to constraint." (equal (char-before) ?\;) (equal (char-before) ?\})) ;; skip what looks like bus repetition operator {#{ - (not (string-match "^{\\s-*[()0-9a-zA-Z_\\]*\\s-*{" + (not (string-match "^{\\s-*[][()0-9a-zA-Z_,:\\]*\\s-*{" (buffer-substring p (point))))))))) (progn (let ( (pt (point)) (pass 0)) @@ -6625,7 +6940,7 @@ Also move point to constraint." )) ;; if first word token not keyword, it maybe the instance name ;; check next word token - (if (looking-at "\\<\\w+\\>\\|\\s-*(\\s-*\\S-+") + (if (looking-at "\\<\\w+\\>\\|\\s-*[[(}]\\s-*\\S-+") (progn (verilog-beg-of-statement) (if (and (not (string-match verilog-named-block-re (buffer-substring pt (point)))) ;; Abort if 'begin' keyword is found @@ -6674,13 +6989,39 @@ Also move point to constraint." (verilog-in-struct-p) (looking-at "}\\(?:\\s-*\\w+\\s-*\\(?:,\\s-*\\w+\\s-*\\)*\\)?;"))) +(defun verilog-at-struct-decl-p () + "Return non-nil if at a struct declaration." + (interactive) + (save-excursion + (verilog-re-search-forward "{" (point-at-eol) t) + (unless (bobp) + (backward-char)) + (verilog-at-struct-p))) + +(defun verilog-at-enum-p () + "If at the { of a enum, return true, not moving point." + (save-excursion + (when (equal (char-after) ?\{) + (verilog-beg-of-statement) + (beginning-of-line) + (when (verilog-re-search-forward verilog-typedef-enum-re (verilog-pos-at-end-of-statement) t) + t)))) + +(defun verilog-at-enum-decl-p () + "Return non-nil if at a enum declaration." + (interactive) + (save-excursion + (verilog-re-search-forward "{" (verilog-pos-at-end-of-statement) t) + (unless (bobp) + (backward-char)) + (verilog-at-enum-p))) + (defun verilog-parenthesis-depth () "Return non zero if in parenthetical-expression." (save-excursion (nth 1 (verilog-syntax-ppss)))) - (defun verilog-skip-forward-comment-or-string () - "Return true if in a string or comment." + "Return non-nil if in a string or comment." (let ((state (save-excursion (verilog-syntax-ppss)))) (cond ((nth 3 state) ;Inside string @@ -6695,7 +7036,7 @@ Also move point to constraint." nil)))) (defun verilog-skip-backward-comment-or-string () - "Return true if in a string or comment." + "Return non-nil if in a string or comment." (let ((state (save-excursion (verilog-syntax-ppss)))) (cond ((nth 3 state) ;Inside string @@ -6712,7 +7053,7 @@ Also move point to constraint." nil)))) (defun verilog-skip-backward-comments () - "Return true if a comment was skipped." + "Return non-nil if a comment was skipped." (let ((more t)) (while more (setq more @@ -6831,6 +7172,9 @@ Only look at a few lines to determine indent level." (let ((type (car indent-str)) (ind (car (cdr indent-str)))) (cond + (; handle indentation ignoring + (verilog-indent-ignore-p) + nil) (; handle continued exp (eq type 'cexp) (let ((here (point))) @@ -6840,14 +7184,14 @@ Only look at a few lines to determine indent level." (= (preceding-char) ?\,) (save-excursion (verilog-beg-of-statement-1) - (looking-at verilog-declaration-re))) + (verilog-looking-at-decl-to-align))) (let* ( fst (val (save-excursion (backward-char 1) (verilog-beg-of-statement-1) (setq fst (point)) - (if (looking-at verilog-declaration-re) + (if (looking-at (verilog-get-declaration-re)) (progn ; we have multiple words (goto-char (match-end 0)) (skip-chars-forward " \t") @@ -6869,9 +7213,9 @@ Only look at a few lines to determine indent level." (+ (current-column) verilog-cexp-indent)))))) (goto-char here) (indent-line-to val) - (if (and (not verilog-indent-lists) - (verilog-in-paren)) - (verilog-pretty-declarations-auto)) + (when (and (not verilog-indent-lists) + (verilog-in-paren)) + (verilog-pretty-declarations-auto)) )) ((= (preceding-char) ?\) ) (goto-char here) @@ -6897,21 +7241,17 @@ Only look at a few lines to determine indent level." (; handle inside parenthetical expressions (eq type 'cparenexp) - (let* ( here - (val (save-excursion - (verilog-backward-up-list 1) - (forward-char 1) - (if verilog-indent-lists - (skip-chars-forward " \t") - (verilog-forward-syntactic-ws)) + (let* ((val (verilog-cparenexp-indent-level)) + (here (save-excursion + (verilog-backward-up-list 1) + (forward-char 1) + (skip-chars-forward " \t") + (point))) + (decl (save-excursion + (goto-char here) + (verilog-forward-syntactic-ws) (setq here (point)) - (current-column))) - - (decl (save-excursion - (goto-char here) - (verilog-forward-syntactic-ws) - (setq here (point)) - (looking-at verilog-declaration-re)))) + (looking-at (verilog-get-declaration-re))))) (indent-line-to val) (if decl (verilog-pretty-declarations-auto)))) @@ -6938,17 +7278,20 @@ Only look at a few lines to determine indent level." (;-- defun (and (eq type 'defun) - (looking-at verilog-zero-indent-re)) + (or (and verilog-indent-class-inside-pkg + (looking-at verilog-zero-indent-no-class-re)) + (and (not verilog-indent-class-inside-pkg) + (looking-at verilog-zero-indent-re)))) (indent-line-to 0)) (;-- declaration (and (or (eq type 'defun) (eq type 'block)) - (looking-at verilog-declaration-re) + (verilog-looking-at-decl-to-align) ;; Do not consider "virtual function", "virtual task", "virtual class" ;; as declarations - (not (looking-at (concat verilog-declaration-re + (not (looking-at (concat (verilog-get-declaration-re) "\\s-+\\(function\\|task\\|class\\)\\b")))) (verilog-indent-declaration ind)) @@ -6994,6 +7337,81 @@ Do not count named blocks or case-statements." (t (current-column))))) +(defun verilog-cparenexp-indent-level () + "Return indent level for current line inside a parenthetical expression." + (let ((start-pos (point)) + (close-par (looking-at "[)}]")) + pos pos-arg-paren) + (save-excursion + (verilog-backward-up-list 1) + (if verilog-indent-lists + (progn + (forward-char 1) + (skip-chars-forward " \t") + (current-column)) + ;; Indentation with `verilog-indent-lists' set to nil + (verilog-beg-of-statement-1) + (when (looking-at "\\<\\(function\\|task\\)\\>") + (verilog-beg-of-statement)) ; find virtual/protected/static + (cond (;; 1) Closing ); of a module/function/task + (and close-par + (save-excursion + (verilog-beg-of-statement-1) + (or (looking-at verilog-complete-re) + (progn (beginning-of-line) + (not (looking-at verilog-assignment-operation-re)))))) + (current-column)) + (;; 2) if (condition) + (looking-at "(") + (forward-char 1) + (skip-chars-forward " \t\f" (point-at-eol)) + (current-column)) + (;; 3) Inside a module/defun param list or function/task argument list + (or (looking-at verilog-defun-level-re) + (looking-at "\\(\\<\\(virtual\\|protected\\|static\\)\\>\\s-+\\)?\\(\\<task\\>\\|\\<function\\>\\)")) + (setq pos-arg-paren (save-excursion + (goto-char start-pos) + (verilog-backward-up-list 1) + (forward-char) + (skip-chars-forward " \t") + (when (not (eolp)) + (current-column)))) + (or pos-arg-paren + ;; arg in next line after ( + (+ (current-column) verilog-indent-level))) + (;; 4) Assignment operation + (save-excursion + (beginning-of-line) + (and (looking-at verilog-assignment-operation-re) + (save-excursion + (goto-char (match-beginning 2)) + (not (verilog-within-string))) + (progn (verilog-forward-syntactic-ws) + (not (looking-at verilog-complete-re))))) + (goto-char (match-end 2)) + (skip-chars-forward " \t\f" (point-at-eol)) + (skip-chars-forward "{(" (1+ (point))) + (skip-chars-forward " \t\f" (point-at-eol)) + (current-column)) + (;; 5) Typedef enum declaration + (verilog-at-enum-decl-p) + (verilog-re-search-forward "{" (verilog-pos-at-end-of-statement) t) + (if (> (verilog-pos-at-forward-syntactic-ws) (point-at-eol)) + (+ (verilog-col-at-beg-of-statement) verilog-indent-level) + (verilog-col-at-forward-syntactic-ws))) + (;; 6) Long reporting strings (e.g. $display or $sformatf inside `uvm_info) + (save-excursion + (goto-char start-pos) + (verilog-backward-up-list 1) + (setq pos (1+ (point))) + (backward-word) + (or (looking-at (concat "\\$" verilog-identifier-re)) ; System function/task + (looking-at verilog-uvm-statement-re))) ; `uvm_* macros + (goto-char pos) + (current-column)) + (t ;; 7) Default + (+ (current-column) verilog-indent-level))))))) + (defun verilog-indent-comment () "Indent current line as comment." (let* ((stcol @@ -7053,90 +7471,137 @@ _ARG is ignored, for `comment-indent-function' compatibility." ;; +(defun verilog-align-comments (startpos endpos) + "Align inline comments between STARTPOS and ENDPOS." + (let (comm-ind e) + (when verilog-align-decl-expr-comments + (setq comm-ind (verilog-get-comment-align-indent (marker-position startpos) endpos)) + (save-excursion + (goto-char (marker-position startpos)) + (while (progn (setq e (marker-position endpos)) + (< (point) e)) + (when (verilog-search-comment-in-declaration e) + (goto-char (match-beginning 0)) + (delete-horizontal-space) + (indent-to (1- (+ comm-ind verilog-align-comment-distance))))))))) + (defun verilog-pretty-declarations-auto (&optional quiet) "Call `verilog-pretty-declarations' QUIET based on `verilog-auto-lineup'." (when (or (eq 'all verilog-auto-lineup) (eq 'declarations verilog-auto-lineup)) (verilog-pretty-declarations quiet))) +(defun verilog--pretty-declarations-find-end (&optional reg-end) + "Find end position for current alignment of declarations. +If region is active, use arg REG-END to set a limit on the alignment." + (let (e) + (if (and (verilog-parenthesis-depth) + (not (verilog-in-struct-p))) + ;; In an argument list or parameter block + (progn + (verilog-backward-up-list -1) + (forward-char -1) + (verilog-backward-syntactic-ws) + (if (region-active-p) + (min reg-end (point)) + (point))) + ;; In a declaration block (not in argument list) + (verilog-end-of-statement) + (setq e (point)) ; Might be on last line + (verilog-forward-syntactic-ws) + (while (verilog-looking-at-decl-to-align) + (verilog-end-of-statement) + (setq e (point)) + (verilog-forward-syntactic-ws)) + (if (region-active-p) + (min reg-end e) + e)))) + +(defun verilog--pretty-declarations-find-base-ind () + "Find base indentation for current alignment of declarations." + (if (and (verilog-parenthesis-depth) + (not (verilog-in-struct-p))) + ;; In an argument list or parameter block + (progn + (unless (or (verilog-looking-back "(" (point-at-bol)) + (bolp)) + (forward-char 1)) + (skip-chars-forward " \t") + (current-column)) + ;; In a declaration block (not in argument list) + (progn + (verilog-do-indent (verilog-calculate-indent)) + (verilog-forward-ws&directives) + (current-column)))) + (defun verilog-pretty-declarations (&optional quiet) "Line up declarations around point. Be verbose about progress unless optional QUIET set." (interactive) - (let* ((m1 (make-marker)) - (e (point)) - el - r - (here (point)) - ind - start - startpos - end - endpos - base-ind - ) + (let ((m1 (make-marker)) + (e (point)) + (here (point)) + el r ind start startpos end endpos base-ind rstart rend) (save-excursion + (when (region-active-p) + (setq rstart (region-beginning)) + (setq rend (region-end)) + (goto-char rstart)) ; Shrinks the region but ensures that start is a valid declaration (if (progn - ;; (verilog-beg-of-statement-1) + ;; Check if alignment can be performed (beginning-of-line) (verilog-forward-syntactic-ws) - (and (not (verilog-in-directive-p)) ; could have `define input foo - (looking-at verilog-declaration-re))) - (progn - (if (verilog-parenthesis-depth) - ;; in an argument list or parameter block - (setq el (verilog-backward-up-list -1) - start (progn - (goto-char e) - (verilog-backward-up-list 1) - (forward-line) ; ignore ( input foo, - (verilog-re-search-forward verilog-declaration-re el 'move) - (goto-char (match-beginning 0)) + (or (and (not (verilog-in-directive-p)) ; could have `define input foo + (verilog-looking-at-decl-to-align)) + (and (verilog-parenthesis-depth) + (looking-at verilog-interface-modport-re)))) + ;; Find boundaries of alignment + (progn + (cond (;; Using region + (region-active-p) + (setq start rstart + startpos (set-marker (make-marker) start) + end (progn (goto-char start) + (verilog--pretty-declarations-find-end rend)) + endpos (set-marker (make-marker) end) + base-ind (progn (goto-char start) + (verilog--pretty-declarations-find-base-ind)))) + (;; In an argument list or parameter block + (and (verilog-parenthesis-depth) + (not (verilog-in-struct-p))) + (setq el (verilog-backward-up-list -1) + start (progn + (goto-char e) + (verilog-backward-up-list 1) + (verilog-re-search-forward (verilog-get-declaration-re 'iface-mp) el 'move) + (goto-char (match-beginning 0)) + (skip-chars-backward " \t") + (point)) + startpos (set-marker (make-marker) start) + end (progn (goto-char start) + (verilog--pretty-declarations-find-end)) + endpos (set-marker (make-marker) end) + base-ind (progn (goto-char start) + (verilog--pretty-declarations-find-base-ind)))) + (;; In a declaration block (not in argument list) + t + (setq + start (progn + (verilog-beg-of-statement-1) + (while (and (verilog-looking-at-decl-to-align) + (not (bobp))) (skip-chars-backward " \t") - (point)) - startpos (set-marker (make-marker) start) - end (progn - (goto-char start) - (verilog-backward-up-list -1) - (forward-char -1) - (verilog-backward-syntactic-ws) - (point)) - endpos (set-marker (make-marker) end) - base-ind (progn - (goto-char start) - (forward-char 1) - (skip-chars-forward " \t") - (current-column))) - ;; in a declaration block (not in argument list) - (setq - start (progn - (verilog-beg-of-statement-1) - (while (and (looking-at verilog-declaration-re) - (not (bobp))) - (skip-chars-backward " \t") - (setq e (point)) - (beginning-of-line) - (verilog-backward-syntactic-ws) - (backward-char) - (verilog-beg-of-statement-1)) - e) - startpos (set-marker (make-marker) start) - end (progn - (goto-char here) - (verilog-end-of-statement) - (setq e (point)) ;Might be on last line - (verilog-forward-syntactic-ws) - (while (looking-at verilog-declaration-re) - (verilog-end-of-statement) - (setq e (point)) - (verilog-forward-syntactic-ws)) - e) - endpos (set-marker (make-marker) end) - base-ind (progn - (goto-char start) - (verilog-do-indent (verilog-calculate-indent)) - (verilog-forward-ws&directives) - (current-column)))) + (setq e (point)) + (verilog-backward-syntactic-ws) + (backward-char) + (verilog-beg-of-statement-1)) + e) + startpos (set-marker (make-marker) start) + end (progn (goto-char here) + (verilog--pretty-declarations-find-end)) + endpos (set-marker (make-marker) end) + base-ind (progn (goto-char start) + (verilog--pretty-declarations-find-base-ind))))) ;; OK, start and end are set (goto-char (marker-position startpos)) (if (and (not quiet) @@ -7152,12 +7617,13 @@ Be verbose about progress unless optional QUIET set." (indent-line-to base-ind) (verilog-forward-ws&directives) (if (< (point) e) - (verilog-re-search-forward "[ \t\n\f]" e 'move))) + (verilog-re-search-forward "[ \t\n\f]" (marker-position endpos) 'move))) (t - (just-one-space) - (verilog-re-search-forward "[ \t\n\f]" e 'move))) - ;;(forward-line) - ) + (unless (verilog-looking-back "(" (point-at-bol)) + (just-one-space)) + (if (looking-at verilog-comment-start-regexp) + (verilog-forward-syntactic-ws) + (verilog-re-search-forward "[ \t\n\f]" e 'move))))) ;; Now find biggest prefix (setq ind (verilog-get-lineup-indent (marker-position startpos) endpos)) ;; Now indent each line. @@ -7167,27 +7633,27 @@ Be verbose about progress unless optional QUIET set." (> r 0)) (setq e (point)) (unless quiet (message "%d" r)) - ;; (verilog-do-indent (verilog-calculate-indent))) (verilog-forward-ws&directives) (cond - ((or (and verilog-indent-declaration-macros - (looking-at verilog-declaration-re-2-macro)) - (looking-at verilog-declaration-re-2-no-macro)) - (let ((p (match-end 0))) - (set-marker m1 p) - (if (verilog-re-search-forward "[[#`]" p 'move) - (progn - (forward-char -1) - (just-one-space) - (goto-char (marker-position m1)) + ((looking-at (verilog-get-declaration-re 'iface-mp)) + (unless (looking-at (verilog-get-declaration-re 'embedded-comments)) + (let ((p (match-end 0))) + (set-marker m1 p) + (if (verilog-re-search-forward "[[#`]" p 'move) + (progn + (forward-char -1) + (just-one-space) + (goto-char (marker-position m1)) + (delete-horizontal-space) + (indent-to ind 1)) + (progn (delete-horizontal-space) - (indent-to ind 1)) - (progn - (delete-horizontal-space) - (indent-to ind 1))))) + (indent-to ind 1)))))) ((verilog-continued-line-1 (marker-position startpos)) (goto-char e) - (indent-line-to ind)) + (unless (and (verilog-in-parenthesis-p) + (looking-at (concat "\\s-*" verilog-identifier-sym-re "\\s-+" verilog-identifier-sym-re "\\s-*"))) + (indent-line-to ind))) ((verilog-in-struct-p) ;; could have a declaration of a user defined item (goto-char e) @@ -7197,104 +7663,202 @@ Be verbose about progress unless optional QUIET set." (verilog-forward-ws&directives) (forward-line -1))) (forward-line 1)) - (unless quiet (message ""))))))) + ;; Align comments if enabled + (when verilog-align-decl-expr-comments + (verilog-align-comments startpos endpos))) + ;; Exit + (unless quiet (message "")))))) + +(defun verilog--pretty-expr-assignment-found (&optional discard-re) + "Return non-nil if point is at a valid assignment operation to be aligned. +Ensure cursor is not over DISCARD-RE (e.g. Verilog keywords). +If returned non-nil, update match data according to `verilog-assignment-operation-re'." + ;; Not looking at a verilog keyword sentence (i.e looking at a potential assignment) + (and (if discard-re + (not (looking-at discard-re)) + t) + ;; Corner case to filter first parameter on param lists + (save-excursion + (if (and (verilog-re-search-forward verilog-assignment-operation-re (point-at-eol) 'move) + (verilog-in-parenthesis-p)) + (progn (verilog-backward-up-list 1) + (forward-char 1) + (not (eq 0 (string-match discard-re (buffer-substring-no-properties (point) (point-at-eol)))))) + t)) + ;; Don't work on multiline assignments unless they are continued lines + ;; e.g, multiple parameters or variable declarations in the same statement + (if (save-excursion + (and (not (verilog-in-parameter-p)) + (verilog-continued-line) + (not (looking-at verilog-basic-complete-re)))) + (save-excursion + (verilog-beg-of-statement-1) + (looking-at (verilog-get-declaration-re))) + t) + ;; Ensure it's not any kind of logical comparison + (save-excursion + (unless (and (not (verilog-in-parameter-p)) + (verilog-re-search-forward (verilog-regexp-words '("if" "for" "assert" "with")) (point-at-eol) 'move)) + t)) + ;; Looking at an assignment (last check, provides match data) + (looking-at verilog-assignment-operation-re))) + +(defun verilog--pretty-expr-find-end (&optional discard-re reg-end) + "Find end position for current alignment of expressions. +Use optional arg DISCARD-RE when aligning expressions outside of an +argument list and REG-END to set a limit on the alignment when the +region is active." + (if (verilog-in-parenthesis-p) + ;; Limit end in argument list + (progn + (verilog-backward-up-list -1) + (forward-char -1) + (verilog-backward-syntactic-ws) + (if (region-active-p) + (min reg-end (point)) + (point))) + ;; Limit end in non-argument list + (save-excursion ; EOL of the last line of the assignment block + (end-of-line) + (let ((pt (point))) ; Might be on last line + (verilog-forward-syntactic-ws) + (beginning-of-line) + (while (and (verilog--pretty-expr-assignment-found discard-re) + (progn + (end-of-line) + (not (eq pt (point))))) + (setq pt (point)) + (verilog-forward-syntactic-ws) + (beginning-of-line)) + (if (region-active-p) + (min reg-end pt) + pt))))) (defun verilog-pretty-expr (&optional quiet) "Line up expressions around point. If QUIET is non-nil, do not print messages showing the progress of line-up." (interactive) - (unless (verilog-in-comment-or-string-p) + (let* ((basic-complete-pretty-expr-re (if verilog-align-assign-expr + verilog-basic-complete-expr-no-assign-re + verilog-basic-complete-expr-re)) + (complete-pretty-expr-re (concat verilog-extended-complete-re "\\|\\(" basic-complete-pretty-expr-re "\\)")) + (discard-re (concat "^\\s-*\\(" complete-pretty-expr-re "\\)")) + rstart rend) (save-excursion - (let ((regexp (concat "^\\s-*" verilog-complete-reg)) - (regexp1 (concat "^\\s-*" verilog-basic-complete-re))) + (when (region-active-p) + (setq rstart (region-beginning)) + (setq rend (region-end)) + (goto-char rstart)) + (unless (verilog-in-comment-or-string-p) (beginning-of-line) - (when (and (not (looking-at regexp)) - (looking-at verilog-assignment-operation-re) + (when (and (verilog--pretty-expr-assignment-found discard-re) (save-excursion (goto-char (match-end 2)) (and (not (verilog-in-attribute-p)) - (not (verilog-in-parameter-p)) (not (verilog-in-comment-or-string-p))))) - (let* ((start (save-excursion ; BOL of the first line of the assignment block - (beginning-of-line) - (let ((pt (point))) - (verilog-backward-syntactic-ws) - (beginning-of-line) - (while (and (not (looking-at regexp1)) - (looking-at verilog-assignment-operation-re) - (not (bobp))) - (setq pt (point)) - (verilog-backward-syntactic-ws) - (beginning-of-line)) ; Ack, need to grok `define - pt))) - (end (save-excursion ; EOL of the last line of the assignment block - (end-of-line) - (let ((pt (point))) ; Might be on last line - (verilog-forward-syntactic-ws) - (beginning-of-line) - (while (and - (not (looking-at regexp1)) - (looking-at verilog-assignment-operation-re) - (progn - (end-of-line) - (not (eq pt (point))))) - (setq pt (point)) - (verilog-forward-syntactic-ws) - (beginning-of-line)) - pt))) - (contains-2-char-operator (string-match "<=" (buffer-substring-no-properties start end))) - (endmark (set-marker (make-marker) end))) - (goto-char start) - (verilog-do-indent (verilog-calculate-indent)) + (let* ((start (cond (;; Using region + (region-active-p) + rstart) + (;; Parameter list + (verilog-in-parenthesis-p) + (progn + (verilog-backward-up-list 1) + (forward-char) + (verilog-re-search-forward verilog-assignment-operation-re-2 nil 'move) + (goto-char (match-beginning 0)) + (point))) + (t ;; Declarations + (save-excursion ; BOL of the first line of the assignment block + (beginning-of-line) + (let ((pt (point))) + (verilog-backward-syntactic-ws) + (beginning-of-line) + (while (and (verilog--pretty-expr-assignment-found discard-re) + (not (bobp))) + (setq pt (point)) + (verilog-backward-syntactic-ws) + (beginning-of-line)) ; Ack, need to grok `define + pt))))) + (startpos (set-marker (make-marker) start)) + (end (cond (;; Using region + (region-active-p) + (verilog--pretty-expr-find-end discard-re rend)) + (;; Parameter list + (verilog-in-parenthesis-p) + (verilog--pretty-expr-find-end)) + (t ;; Declarations + (verilog--pretty-expr-find-end discard-re)))) + (endpos (set-marker (make-marker) end)) + (contains-2-char-operator (string-match "<=" (buffer-substring-no-properties start end)))) + ;; Start with alignment + (goto-char startpos) + (unless (save-excursion + (beginning-of-line) + (looking-at discard-re)) + (verilog-do-indent (verilog-calculate-indent))) (when (and (not quiet) - (> (- end start) 100)) + (> (- (marker-position endpos) (marker-position startpos)) 100)) (message "Lining up expressions.. (please stand by)")) - ;; Set indent to minimum throughout region ;; Rely on mark rather than on point as the indentation changes can ;; make the older point reference obsolete - (while (< (point) (marker-position endmark)) + (while (< (point) (marker-position endpos)) (beginning-of-line) (save-excursion - (verilog-just-one-space verilog-assignment-operation-re)) + (if (looking-at verilog-complete-re) + (progn (goto-char (marker-position startpos)) + (verilog-just-one-space verilog-assignment-operation-re-2)) + (verilog-just-one-space verilog-assignment-operation-re))) (verilog-do-indent (verilog-calculate-indent)) (end-of-line) (verilog-forward-syntactic-ws)) - (let ((ind (verilog-get-lineup-indent-2 verilog-assignment-operation-re start (marker-position endmark))) ; Find the biggest prefix + (let ((ind (verilog-get-lineup-indent-2 verilog-assignment-operation-re (marker-position startpos) (marker-position endpos))) ; Find the biggest prefix e) ;; Now indent each line. - (goto-char start) + (goto-char (marker-position startpos)) (while (progn - (setq e (marker-position endmark)) + (setq e (marker-position endpos)) (> e (point))) (unless quiet (message " verilog-pretty-expr: %d" (- e (point)))) (setq e (point)) (cond - ((looking-at verilog-assignment-operation-re) + ((or (looking-at verilog-assignment-operation-re) + (and (verilog-in-parenthesis-p) + (looking-at verilog-assignment-operation-re-2))) (goto-char (match-beginning 2)) - (unless (or (verilog-in-parenthesis-p) ; Leave attributes and comparisons alone + (unless (or (and (verilog-in-parenthesis-p) ; Leave attributes and comparisons alone + (save-excursion ; Allow alignment of some expressions inside param/port list + (verilog-backward-up-list 1) + (verilog-beg-of-statement-1) + (not (looking-at verilog-defun-level-re)))) (verilog-in-coverage-p)) (if (and contains-2-char-operator (eq (char-after) ?=)) (indent-to (1+ ind)) ; Line up the = of the <= with surrounding = - (indent-to ind)))) - ((verilog-continued-line-1 start) + (indent-to ind))) + (forward-line 1)) + ((and (save-excursion + (verilog-forward-syntactic-ws) + (not (looking-at verilog-complete-re))) + (verilog-continued-line-1 (marker-position startpos))) (goto-char e) - (indent-line-to ind)) - (t ; Must be comment or white space + (indent-line-to ind) + (forward-line 1)) + (t ; Must be comment, white space or syntax error (goto-char e) - (verilog-forward-ws&directives) - (forward-line -1))) - (forward-line 1)) + (forward-line 1)))) + ;; Align comments if enabled + (when verilog-align-decl-expr-comments + (verilog-align-comments startpos endpos)) (unless quiet (message ""))))))))) (defun verilog-just-one-space (myre) "Remove extra spaces around regular expression MYRE." (interactive) - (if (and (not(looking-at verilog-complete-reg)) + (if (and (not(looking-at verilog-complete-re)) (looking-at myre)) (let ((p1 (match-end 1)) (p2 (match-end 2))) @@ -7312,59 +7876,63 @@ BASEIND is the base indent to offset everything." ;; `ind' is used in expressions stored in `verilog-indent-alist'. (verilog--suppressed-warnings ((lexical ind)) (defvar ind)) (let ((pos (point-marker)) - (lim (save-excursion - ;; (verilog-re-search-backward verilog-declaration-opener nil 'move) - (verilog-re-search-backward "\\(\\<begin\\>\\)\\|\\(\\<\\(connect\\)?module\\>\\)\\|\\(\\<task\\>\\)" nil 'move) - (point))) - (ind) - (val) - (m1 (make-marker))) - (setq val - (+ baseind (eval (cdr (assoc 'declaration verilog-indent-alist))))) + (m1 (make-marker)) + (in-paren (verilog-parenthesis-depth)) + (val (+ baseind (eval (cdr (assoc 'declaration verilog-indent-alist))))) + ind) (indent-line-to val) - ;; Use previous declaration (in this module) as template. - (if (or (eq 'all verilog-auto-lineup) - (eq 'declarations verilog-auto-lineup)) - (if (verilog-re-search-backward - (or (and verilog-indent-declaration-macros - verilog-declaration-re-1-macro) - verilog-declaration-re-1-no-macro) - lim t) - (progn - (goto-char (match-end 0)) - (skip-chars-forward " \t") - (setq ind (current-column)) - (goto-char pos) - (setq val - (+ baseind - (eval (cdr (assoc 'declaration verilog-indent-alist))))) - (indent-line-to val) - (if (and verilog-indent-declaration-macros - (looking-at verilog-declaration-re-2-macro)) - (let ((p (match-end 0))) - (set-marker m1 p) - (if (verilog-re-search-forward "[[#`]" p 'move) - (progn - (forward-char -1) - (just-one-space) - (goto-char (marker-position m1)) - (delete-horizontal-space) - (indent-to ind 1)) - (delete-horizontal-space) - (indent-to ind 1))) - (if (looking-at verilog-declaration-re-2-no-macro) - (let ((p (match-end 0))) - (set-marker m1 p) - (if (verilog-re-search-forward "[[`#]" p 'move) - (progn - (forward-char -1) - (just-one-space) - (goto-char (marker-position m1)) - (delete-horizontal-space) - (indent-to ind 1)) - (delete-horizontal-space) - (indent-to ind 1)))))))) + (when (and (or (eq 'all verilog-auto-lineup) + (eq 'declarations verilog-auto-lineup)) + ;; Limit alignment to consecutive statements + (progn + (verilog-backward-syntactic-ws) + (backward-char) + (looking-at ";")) + (progn + (verilog-beg-of-statement) + (looking-at (verilog-get-declaration-re))) + ;; Make sure that we don't jump to an argument list or parameter block if + ;; we were in a declaration block (not in argument list) + (or (and in-paren + (verilog-parenthesis-depth)) + (and (not in-paren) + (not (verilog-parenthesis-depth)))) + ;; Skip variable declarations inside functions/tasks + (skip-chars-backward " \t\f") + (bolp)) + (goto-char (match-end 0)) + (skip-chars-forward " \t") + (setq ind (current-column)) + (goto-char pos) + (setq val + (+ baseind + (eval (cdr (assoc 'declaration verilog-indent-alist))))) + (indent-line-to val) + (if (looking-at (verilog-get-declaration-re)) + (let ((p (match-end 0))) + (set-marker m1 p) + (if (verilog-re-search-forward "[[#`]" p 'move) + (progn + (forward-char -1) + (just-one-space) + (goto-char (marker-position m1)) + (delete-horizontal-space) + (indent-to ind 1)) + (delete-horizontal-space) + (indent-to ind 1))) + (when (looking-at (verilog-get-declaration-re)) + (let ((p (match-end 0))) + (set-marker m1 p) + (if (verilog-re-search-forward "[[`#]" p 'move) + (progn + (forward-char -1) + (just-one-space) + (goto-char (marker-position m1)) + (delete-horizontal-space) + (indent-to ind 1)) + (delete-horizontal-space) + (indent-to ind 1)))))) (goto-char pos))) (defun verilog-get-lineup-indent (b edpos) @@ -7376,16 +7944,13 @@ Region is defined by B and EDPOS." ;; Get rightmost position (while (progn (setq e (marker-position edpos)) (< (point) e)) - (if (verilog-re-search-forward - (or (and verilog-indent-declaration-macros - verilog-declaration-re-1-macro) - verilog-declaration-re-1-no-macro) e 'move) - (progn - (goto-char (match-end 0)) - (verilog-backward-syntactic-ws) - (if (> (current-column) ind) - (setq ind (current-column))) - (goto-char (match-end 0))))) + (when (verilog-re-search-forward (verilog-get-declaration-re 'iface-mp) e 'move) + (goto-char (match-end 0)) + (verilog-backward-syntactic-ws) + (if (> (current-column) ind) + (setq ind (current-column))) + (goto-char (match-end 0)) + (forward-line 1))) (if (> ind 0) (1+ ind) ;; No lineup-string found @@ -7402,12 +7967,13 @@ BEG and END." (save-excursion (let ((ind 0)) (goto-char beg) + (beginning-of-line) ;; Get rightmost position (while (< (point) end) (when (and (verilog-re-search-forward regexp end 'move) (not (verilog-in-attribute-p))) ; skip attribute exprs (goto-char (match-beginning 2)) - (verilog-backward-syntactic-ws) + (skip-chars-backward " \t") (if (> (current-column) ind) (setq ind (current-column))) (goto-char (match-end 0)))) @@ -7420,6 +7986,32 @@ BEG and END." (1+ (current-column)))) ind))) +(defun verilog-search-comment-in-declaration (bound) + "Move cursor to position of comment in declaration and return point. +BOUND is a buffer position that bounds the search." + (and (verilog-re-search-forward (verilog-get-declaration-re 'iface-mp) bound 'move) + (not (looking-at (concat "\\s-*" verilog-comment-start-regexp))) + (re-search-forward verilog-comment-start-regexp (point-at-eol) :noerror))) + +(defun verilog-get-comment-align-indent (b endpos) + "Return the indent level that will line up comments within the region. +Region is defined by B and ENDPOS." + (save-excursion + (let ((ind 0) + e comm-ind) + (goto-char b) + ;; Get rightmost position + (while (progn (setq e (marker-position endpos)) + (< (point) e)) + (when (verilog-search-comment-in-declaration e) + (end-of-line) + (verilog-backward-syntactic-ws) + (setq comm-ind (1+ (current-column))) + (when (> comm-ind ind) + (setq ind comm-ind))) + (forward-line 1)) + ind))) + (defun verilog-comment-depth (type val) "A useful mode debugging aide. TYPE and VAL are comments for insertion." (save-excursion @@ -7439,6 +8031,19 @@ BEG and END." (insert (format "%s %d" type val)))) +(defun verilog-indent-ignore-p () + "Return non-nil if current line should ignore indentation." + (or (and verilog-indent-ignore-multiline-defines + ;; Line with multiline define, ends with "\" or "\" plus trailing whitespace + (or (looking-at ".*\\\\\\s-*$") + (save-excursion ; Last line after multiline define + (verilog-backward-syntactic-ws) + (unless (bobp) + (backward-char)) + (looking-at "\\\\")))) + (and verilog-indent-ignore-regexp ; Ignore lines according to specified regexp + (looking-at verilog-indent-ignore-regexp)))) + ;;; Completion: ;; @@ -7446,7 +8051,7 @@ BEG and END." (defvar verilog-all nil) (defvar verilog-buffer-to-use nil) (defvar verilog-toggle-completions nil - "True means \\<verilog-mode-map>\\[verilog-complete-word] should try all possible completions one by one. + "Non-nil means \\<verilog-mode-map>\\[verilog-complete-word] should try all possible completions one by one. Repeated use of \\[verilog-complete-word] will show you all of them. Normally, when there is more than one possible completion, it displays a list of all possible completions.") @@ -7598,16 +8203,14 @@ TYPE is `module', `tf' for task or function, or t if unknown." (defun verilog-get-completion-decl (end) "Macro for searching through current declaration (var, type or const) for matches of `str' and adding the occurrence tp `all' through point END." - (let ((re (or (and verilog-indent-declaration-macros - verilog-declaration-re-2-macro) - verilog-declaration-re-2-no-macro)) + (let ((re (verilog-get-declaration-re)) decl-end match) ;; Traverse lines (while (and (< (point) end) (verilog-re-search-forward re end t)) ;; Traverse current line (setq decl-end (save-excursion (verilog-declaration-end))) - (while (and (verilog-re-search-forward verilog-symbol-re decl-end t) + (while (and (verilog-re-search-forward verilog-identifier-sym-re decl-end t) (not (match-end 1))) (setq match (buffer-substring (match-beginning 0) (match-end 0))) (if (string-match (concat "\\<" verilog-str) match) @@ -7619,7 +8222,7 @@ for matches of `str' and adding the occurrence tp `all' through point END." "Calculate all possible completions for variables (or constants)." (let ((start (point))) ;; Search for all reachable var declarations - (verilog-beg-of-defun) + (verilog-re-search-backward verilog-defun-re nil 'move) (save-excursion ;; Check var declarations (verilog-get-completion-decl start)))) @@ -8765,6 +9368,11 @@ Return an array of [outputs inouts inputs wire reg assign const gparam intf]." (t ; Bit width (setq vec (verilog-string-replace-matches "\\s-+" "" nil nil keywd))))) + ;; int'(a) is cast, not declaration of a + ((and (looking-at "'") + (not rvalue)) + (forward-char 1) + (setq expect-signal nil rvalue nil)) ;; Normal or escaped identifier -- note we remember the \ if escaped ((looking-at "\\s-*\\([a-zA-Z0-9`_$]+\\|\\\\[^ \t\n\f]+\\)") (goto-char (match-end 0)) @@ -9702,9 +10310,9 @@ resolve it. If optional RECURSE is non-nil, recurse through \\=`includes. Localparams must be simple assignments to constants, or have their own \"localparam\" label rather than a list of localparams. Thus: - localparam X = 5, Y = 10; // Ok - localparam X = {1\\='b1, 2\\='h2}; // Ok - localparam X = {1\\='b1, 2\\='h2}, Y = 10; // Bad, make into 2 localparam lines + localparam X = 5, Y = 10; // Ok + localparam X = {1\\='b1, 2\\='h2}; // Ok + localparam X = {1\\='b1, 2\\='h2}, Y = 10; // Bad, make into 2 localparam lines Defines must be simple text substitutions, one on a line, starting at the beginning of the line. Any ifdefs or multiline comments around the @@ -9827,8 +10435,7 @@ variable over and over when many modules are compiled together, put a test around the inside each include file: foo.v (an include file): - \\=`ifdef _FOO_V // include if not already included - \\=`else + \\=`ifndef _FOO_V // include if not already included \\=`define _FOO_V ... contents of file \\=`endif // _FOO_V" @@ -10066,7 +10673,7 @@ Results are cached if inside `verilog-preserve-dir-cache'." ;; (prin1 (verilog-dir-files ".")) nil) (defun verilog-dir-file-exists-p (filename) - "Return true if FILENAME exists. + "Return non-nil if FILENAME exists. Like `file-exists-p' but results are cached if inside `verilog-preserve-dir-cache'." (let* ((dirname (file-name-directory filename)) @@ -10105,7 +10712,7 @@ Allows version control to check out the file if need be." modi))))) (defun verilog-is-number (symbol) - "Return true if SYMBOL is number-like." + "Return non-nil if SYMBOL is number-like." (or (string-match "^[0-9 \t:]+$" symbol) (string-match "^[---]*[0-9]+$" symbol) (string-match "^[0-9 \t]+'s?[hdxbo][0-9a-fA-F_xz? \t]*$" symbol))) @@ -10177,7 +10784,7 @@ Or, just the existing dirnames themselves if there are no wildcards." (unless dirnames (error "`verilog-library-directories' should include at least `.'")) (save-match-data - (setq dirnames (reverse dirnames)) ; not nreverse + (setq dirnames (reverse dirnames)) ; not nreverse (let ((dirlist nil) pattern dirfile dirfiles dirname root filename rest basefile) (setq dirnames (mapcar #'substitute-in-file-name dirnames)) @@ -10885,12 +11492,12 @@ This repairs those mis-inserted by an AUTOARG." (if (equal (match-string 3 out) ">>") (int-to-string (ash (string-to-number (match-string 2 out)) (* -1 (string-to-number (match-string 4 out)))))) - (if (equal (match-string 3 out) "<<") - (int-to-string (ash (string-to-number (match-string 2 out)) - (string-to-number (match-string 4 out))))) (if (equal (match-string 3 out) ">>>") (int-to-string (ash (string-to-number (match-string 2 out)) (* -1 (string-to-number (match-string 4 out)))))) + (if (equal (match-string 3 out) "<<") + (int-to-string (ash (string-to-number (match-string 2 out)) + (string-to-number (match-string 4 out))))) (if (equal (match-string 3 out) "<<<") (int-to-string (ash (string-to-number (match-string 2 out)) (string-to-number (match-string 4 out))))) @@ -10920,7 +11527,7 @@ This repairs those mis-inserted by an AUTOARG." (ceiling (/ (log value) (log 2))))) (defun verilog-typedef-name-p (variable-name) - "Return true if the VARIABLE-NAME is a type definition." + "Return non-nil if the VARIABLE-NAME is a type definition." (when verilog-typedef-regexp (verilog-string-match-fold verilog-typedef-regexp variable-name))) @@ -11678,7 +12285,7 @@ If PAR-VALUES replace final strings with these parameter values." (concat "." vl-modport) "") dflt-bits)) ;; Find template - (cond (tpl-ass ; Template of exact port name + (cond (tpl-ass ; Template of exact port name (setq tpl-net (nth 1 tpl-ass))) ((nth 1 tpl-list) ; Wildcards in template, search them (let ((wildcards (nth 1 tpl-list))) @@ -12240,7 +12847,9 @@ For more information see the \\[verilog-faq] and forums at URL (cond ((not verilog-auto-inst-first-any) (re-search-backward "," pt t) (delete-char 1) - (insert ");") + (when (looking-at " ") + (delete-char 1)) ; so we can align // Templated comments + (insert ");") (search-forward "\n") ; Added by inst-port (delete-char -1) (if (search-forward ")" nil t) ; From user, moved up a line @@ -14645,7 +15254,7 @@ and the case items." (if (not (member v1 verilog-keywords)) (save-excursion (setq verilog-sk-signal v1) - (verilog-beg-of-defun) + (verilog-re-search-backward verilog-defun-re nil 'move) (verilog-end-of-statement) (verilog-forward-syntactic-ws) (verilog-sk-def-reg) @@ -14897,7 +15506,12 @@ Files are checked based on `verilog-library-flags'." '( verilog-active-low-regexp verilog-after-save-font-hook + verilog-align-assign-expr + verilog-align-comment-distance + verilog-align-decl-expr-comments verilog-align-ifelse + verilog-align-typedef-regexp + verilog-align-typedef-words verilog-assignment-delay verilog-auto-arg-sort verilog-auto-declare-nettype @@ -14942,13 +15556,17 @@ Files are checked based on `verilog-library-flags'." verilog-compiler verilog-coverage verilog-delete-auto-hook + verilog-fontify-variables verilog-getopt-flags-hook verilog-highlight-grouping-keywords verilog-highlight-includes verilog-highlight-modules verilog-highlight-translate-off verilog-indent-begin-after-if + verilog-indent-class-inside-pkg verilog-indent-declaration-macros + verilog-indent-ignore-multiline-defines + verilog-indent-ignore-regexp verilog-indent-level verilog-indent-level-behavioral verilog-indent-level-declaration diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index 916d83d407b..4db0df6c3b8 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -568,7 +568,8 @@ This can be used from `xref-after-jump-hook', for instance.") (dolist (l (list (car history) (cdr history))) (dolist (m l) (set-marker m nil nil))) - (setq history (cons nil nil))) + (setcar history nil) + (setcdr history nil)) nil) ;;;###autoload diff --git a/lisp/reveal.el b/lisp/reveal.el index 8a1239e1aa2..5ebc5f7c6c3 100644 --- a/lisp/reveal.el +++ b/lisp/reveal.el @@ -118,17 +118,13 @@ Each element has the form (WINDOW . OVERLAY).") ;; overlay. Always reveal invisible text, but only reveal ;; display properties if `reveal-toggle-invisible' is ;; present. - (let ((inv (overlay-get ol 'invisible)) - (disp (and (overlay-get ol 'display) - (overlay-get ol 'reveal-toggle-invisible))) - open) - (when (and (or (and inv - ;; There's an `invisible' property. - ;; Make sure it's actually invisible, - ;; and ellipsized. - (and (consp buffer-invisibility-spec) - (cdr (assq inv buffer-invisibility-spec)))) - disp) + (let* ((inv (overlay-get ol 'invisible)) + (disp (and (overlay-get ol 'display) + (overlay-get ol 'reveal-toggle-invisible))) + (hidden (invisible-p inv)) + (ellipsis (and hidden (not (eq t hidden)))) + open) + (when (and (or ellipsis disp) (or (setq open (or (overlay-get ol 'reveal-toggle-invisible) (and (symbolp inv) diff --git a/lisp/server.el b/lisp/server.el index eaf24a770e4..35b38ef8fa6 100644 --- a/lisp/server.el +++ b/lisp/server.el @@ -273,6 +273,11 @@ If nil, no instructions are displayed." :version "28.1" :type 'boolean) +(defvar server-stop-automatically) ; Defined below to avoid recursive load. + +(defvar server-stop-automatically--timer nil + "The timer object for `server-stop-automatically--maybe-kill-emacs'.") + ;; We do not use `temporary-file-directory' here, because emacsclient ;; does not read the init file. (defvar server-socket-dir @@ -636,7 +641,8 @@ anyway." (setq stopped-p t server-process nil server-mode nil - global-minor-modes (delq 'server-mode global-minor-modes))) + global-minor-modes (delq 'server-mode global-minor-modes)) + (server-apply-stop-automatically)) (unwind-protect ;; Delete the socket files made by previous server ;; invocations. @@ -757,6 +763,7 @@ the `server-process' variable." (list :family 'local :service server-file :plist '(:authenticated t))))) + (server-apply-stop-automatically) (unless server-process (error "Could not start server process")) (server-log "Started server") (process-put server-process :server-file server-file) @@ -1769,9 +1776,6 @@ be a cons cell (LINENUMBER . COLUMNNUMBER)." (when server-raise-frame (select-frame-set-input-focus (window-frame))))) -(defvar server-stop-automatically nil - "Internal status variable for `server-stop-automatically'.") - ;;;###autoload (defun server-save-buffers-kill-terminal (arg) ;; Called from save-buffers-kill-terminal in files.el. @@ -1779,11 +1783,19 @@ be a cons cell (LINENUMBER . COLUMNNUMBER)." With ARG non-nil, silently save all file-visiting buffers, then kill. If emacsclient was started with a list of filenames to edit, then -only these files will be asked to be saved." - (let ((proc (frame-parameter nil 'client))) +only these files will be asked to be saved. + +When running Emacs as a daemon and with +`server-stop-automatically' (which see) set to `kill-terminal' or +`delete-frame', this function may call `save-buffers-kill-emacs' +if there are no other active clients." + (let ((stop-automatically + (and (daemonp) + (memq server-stop-automatically '(kill-terminal delete-frame)))) + (proc (frame-parameter nil 'client))) (cond ((eq proc 'nowait) ;; Nowait frames have no client buffer list. - (if (length> (frame-list) (if server-stop-automatically 2 1)) + (if (length> (frame-list) (if stop-automatically 2 1)) ;; If there are any other frames, only delete this one. ;; When `server-stop-automatically' is set, don't count ;; the daemon frame. @@ -1792,7 +1804,7 @@ only these files will be asked to be saved." ;; If we're the last frame standing, kill Emacs. (save-buffers-kill-emacs arg))) ((processp proc) - (if (or (not server-stop-automatically) + (if (or (not stop-automatically) (length> server-clients 1) (seq-some (lambda (frame) @@ -1818,31 +1830,14 @@ only these files will be asked to be saved." (save-buffers-kill-emacs arg))) (t (error "Invalid client frame"))))) -(defun server-stop-automatically--handle-delete-frame (frame) - "Handle deletion of FRAME when `server-stop-automatically' is used." - (when server-stop-automatically - (if (if (and (processp (frame-parameter frame 'client)) - (eq this-command 'save-buffers-kill-terminal)) - (progn - (dolist (f (frame-list)) - (when (and (eq (frame-parameter frame 'client) - (frame-parameter f 'client)) - (not (eq frame f))) - (set-frame-parameter f 'client nil) - (let ((server-stop-automatically nil)) - (delete-frame f)))) - (if (cddr (frame-list)) - (let ((server-stop-automatically nil)) - (delete-frame frame) - nil) - t)) - (null (cddr (frame-list)))) - (let ((server-stop-automatically nil)) - (save-buffers-kill-emacs) - (delete-frame frame))))) +(defun server-stop-automatically--handle-delete-frame (_frame) + "Handle deletion of FRAME when `server-stop-automatically' is `delete-frame'." + (when (null (cddr (frame-list))) + (let ((server-stop-automatically nil)) + (save-buffers-kill-emacs)))) (defun server-stop-automatically--maybe-kill-emacs () - "Handle closing of Emacs daemon when `server-stop-automatically' is used." + "Handle closing of Emacs daemon when `server-stop-automatically' is `empty'." (unless (cdr (frame-list)) (when (and (not (memq t (mapcar (lambda (b) @@ -1856,41 +1851,70 @@ only these files will be asked to be saved." (process-list))))) (kill-emacs)))) -;;;###autoload -(defun server-stop-automatically (arg) - "Automatically stop server as specified by ARG. - -If ARG is the symbol `empty', stop the server when it has no +(defun server-apply-stop-automatically () + "Apply the current value of `server-stop-automatically'. +This function adds or removes the necessary helpers to manage +stopping the Emacs server automatically, depending on the whether +the server is running or not. This function only applies when +running Emacs as a daemon." + (when (daemonp) + (let (empty-timer-p delete-frame-p) + (when server-process + (pcase server-stop-automatically + ('empty (setq empty-timer-p t)) + ('delete-frame (setq delete-frame-p t)))) + ;; Start or stop the timer. + (if empty-timer-p + (unless server-stop-automatically--timer + (setq server-stop-automatically--timer + (run-with-timer + 10 2 + #'server-stop-automatically--maybe-kill-emacs))) + (when server-stop-automatically--timer + (cancel-timer server-stop-automatically--timer) + (setq server-stop-automatically--timer nil))) + ;; Add or remove the delete-frame hook. + (if delete-frame-p + (add-hook 'delete-frame-functions + #'server-stop-automatically--handle-delete-frame) + (remove-hook 'delete-frame-functions + #'server-stop-automatically--handle-delete-frame)))) + ;; Return the current value of `server-stop-automatically'. + server-stop-automatically) + +(defcustom server-stop-automatically nil + "If non-nil, stop the server under the requested conditions. + +If this is the symbol `empty', stop the server when it has no remaining clients, no remaining unsaved file-visiting buffers, and no running processes with a `query-on-exit' flag. -If ARG is the symbol `delete-frame', ask the user when the last +If this is the symbol `delete-frame', ask the user when the last frame is deleted whether each unsaved file-visiting buffer must be saved and each running process with a `query-on-exit' flag can be stopped, and if so, stop the server itself. -If ARG is the symbol `kill-terminal', ask the user when the +If this is the symbol `kill-terminal', ask the user when the terminal is killed with \\[save-buffers-kill-terminal] \ whether each unsaved file-visiting buffer must be saved and each running process with a `query-on-exit' -flag can be stopped, and if so, stop the server itself. - -Any other value of ARG will cause this function to signal an error. +flag can be stopped, and if so, stop the server itself." + :type '(choice + (const :tag "Never" nil) + (const :tag "When no clients, unsaved files, or processes" + empty) + (const :tag "When killing last terminal" kill-terminal) + (const :tag "When killing last terminal or frame" delete-frame)) + :set (lambda (symbol value) + (set-default symbol value) + (server-apply-stop-automatically)) + :version "29.1") -This function is meant to be called from the user init file." - (when (daemonp) - (setq server-stop-automatically arg) - (cond - ((eq arg 'empty) - (setq server-stop-automatically nil) - (run-with-timer 10 2 - #'server-stop-automatically--maybe-kill-emacs)) - ((eq arg 'delete-frame) - (add-hook 'delete-frame-functions - #'server-stop-automatically--handle-delete-frame)) - ((eq arg 'kill-terminal)) - (t - (error "Unexpected argument"))))) +;;;###autoload +(defun server-stop-automatically (value) + "Automatically stop the Emacs server as specified by VALUE. +This sets the variable `server-stop-automatically' (which see)." + (setopt server-stop-automatically value)) (define-key ctl-x-map "#" 'server-edit) diff --git a/lisp/simple.el b/lisp/simple.el index 861fe193fb8..7bda368d85d 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -2709,7 +2709,16 @@ function as needed." (let ((doc (car body))) (when (funcall docstring-p doc) doc))) - (_ (signal 'invalid-function (list function)))))) + ((pred symbolp) + (let ((f (indirect-function function))) + (if f (function-documentation f) + (signal 'void-function (list function))))) + (`(macro . ,f) (function-documentation f)) + (_ + (let ((doc (internal-subr-documentation function))) + (if (eq t doc) + (signal 'invalid-function (list function)) + doc)))))) (cl-defmethod function-documentation ((function accessor)) (oclosure--accessor-docstring function)) ;; FIXME: η-reduce! @@ -3852,16 +3861,14 @@ whether (MARKER . ADJUSTMENT) undo elements are in the region, because markers can be arbitrarily relocated. Instead, pass the marker adjustment's corresponding (TEXT . POS) element." (cond ((integerp undo-elt) - (and (>= undo-elt start) - (<= undo-elt end))) + (<= start undo-elt end)) ((eq undo-elt nil) t) ((atom undo-elt) nil) ((stringp (car undo-elt)) ;; (TEXT . POSITION) - (and (>= (abs (cdr undo-elt)) start) - (<= (abs (cdr undo-elt)) end))) + (<= start (abs (cdr undo-elt)) end)) ((and (consp undo-elt) (markerp (car undo-elt))) ;; (MARKER . ADJUSTMENT) (<= start (car undo-elt) end)) @@ -4726,6 +4733,18 @@ Also see the `async-shell-command-buffer' variable." action)) (user-error "Shell command in progress")))) +(defun file-user-uid () + "Return the connection-local effective uid. +This is similar to `user-uid', but may invoke a file name handler +based on `default-directory'. See Info node `(elisp)Magic File +Names'. + +If a file name handler is unable to retrieve the effective uid, +this function will instead return -1." + (if-let ((handler (find-file-name-handler default-directory 'file-user-uid))) + (funcall handler 'file-user-uid) + (user-uid))) + (defun max-mini-window-lines (&optional frame) "Compute maximum number of lines for echo area in FRAME. As defined by `max-mini-window-height'. FRAME defaults to the @@ -6482,7 +6501,7 @@ If the Unicode tables are not yet available, e.g. during bootstrap, then gives correct answers only for ASCII characters." (cond ((unicode-property-table-internal 'lowercase) (characterp (get-char-code-property char 'lowercase))) - ((and (>= char ?A) (<= char ?Z))))) + ((<= ?A char ?Z)))) (defun zap-to-char (arg char &optional interactive) "Kill up to and including ARGth occurrence of CHAR. @@ -8501,6 +8520,45 @@ are interchanged." (interactive "*p") (transpose-subr 'forward-word arg)) +(defun transpose-sexps-default-function (arg) + "Default method to locate a pair of points for transpose-sexps." + ;; Here we should try to simulate the behavior of + ;; (cons (progn (forward-sexp x) (point)) + ;; (progn (forward-sexp (- x)) (point))) + ;; Except that we don't want to rely on the second forward-sexp + ;; putting us back to where we want to be, since forward-sexp-function + ;; might do funny things like infix-precedence. + (if (if (> arg 0) + (looking-at "\\sw\\|\\s_") + (and (not (bobp)) + (save-excursion + (forward-char -1) + (looking-at "\\sw\\|\\s_")))) + ;; Jumping over a symbol. We might be inside it, mind you. + (progn (funcall (if (> arg 0) + #'skip-syntax-backward #'skip-syntax-forward) + "w_") + (cons (save-excursion (forward-sexp arg) (point)) (point))) + ;; Otherwise, we're between sexps. Take a step back before jumping + ;; to make sure we'll obey the same precedence no matter which + ;; direction we're going. + (funcall (if (> arg 0) #'skip-syntax-backward #'skip-syntax-forward) + " .") + (cons (save-excursion (forward-sexp arg) (point)) + (progn (while (or (forward-comment (if (> arg 0) 1 -1)) + (not (zerop (funcall (if (> arg 0) + #'skip-syntax-forward + #'skip-syntax-backward) + "."))))) + (point))))) + +(defvar transpose-sexps-function #'transpose-sexps-default-function + "If non-nil, `transpose-sexps' delegates to this function. + +This function takes one argument ARG, a number. Its expected +return value is a position pair, which is a cons (BEG . END), +where BEG and END are buffer positions.") + (defun transpose-sexps (arg &optional interactive) "Like \\[transpose-chars] (`transpose-chars'), but applies to sexps. Unlike `transpose-words', point must be between the two sexps and not @@ -8516,38 +8574,7 @@ report errors as appropriate for this kind of usage." (condition-case nil (transpose-sexps arg nil) (scan-error (user-error "Not between two complete sexps"))) - (transpose-subr - (lambda (arg) - ;; Here we should try to simulate the behavior of - ;; (cons (progn (forward-sexp x) (point)) - ;; (progn (forward-sexp (- x)) (point))) - ;; Except that we don't want to rely on the second forward-sexp - ;; putting us back to where we want to be, since forward-sexp-function - ;; might do funny things like infix-precedence. - (if (if (> arg 0) - (looking-at "\\sw\\|\\s_") - (and (not (bobp)) - (save-excursion - (forward-char -1) - (looking-at "\\sw\\|\\s_")))) - ;; Jumping over a symbol. We might be inside it, mind you. - (progn (funcall (if (> arg 0) - 'skip-syntax-backward 'skip-syntax-forward) - "w_") - (cons (save-excursion (forward-sexp arg) (point)) (point))) - ;; Otherwise, we're between sexps. Take a step back before jumping - ;; to make sure we'll obey the same precedence no matter which - ;; direction we're going. - (funcall (if (> arg 0) 'skip-syntax-backward 'skip-syntax-forward) - " .") - (cons (save-excursion (forward-sexp arg) (point)) - (progn (while (or (forward-comment (if (> arg 0) 1 -1)) - (not (zerop (funcall (if (> arg 0) - 'skip-syntax-forward - 'skip-syntax-backward) - "."))))) - (point))))) - arg 'special))) + (transpose-subr transpose-sexps-function arg 'special))) (defun transpose-lines (arg) "Exchange current line and previous line, leaving point after both. @@ -8572,13 +8599,15 @@ With argument 0, interchanges line point is in with line mark is in." ;; FIXME document SPECIAL. (defun transpose-subr (mover arg &optional special) "Subroutine to do the work of transposing objects. -Works for lines, sentences, paragraphs, etc. MOVER is a function that -moves forward by units of the given object (e.g. `forward-sentence', -`forward-paragraph'). If ARG is zero, exchanges the current object -with the one containing mark. If ARG is an integer, moves the -current object past ARG following (if ARG is positive) or -preceding (if ARG is negative) objects, leaving point after the -current object." +Works for lines, sentences, paragraphs, etc. MOVER is a function +that moves forward by units of the given +object (e.g. `forward-sentence', `forward-paragraph'), or a +function calculating a cons of buffer positions. + + If ARG is zero, exchanges the current object with the one +containing mark. If ARG is an integer, moves the current object +past ARG following (if ARG is positive) or preceding (if ARG is +negative) objects, leaving point after the current object." (let ((aux (if special mover (lambda (x) (cons (progn (funcall mover x) (point)) @@ -8605,6 +8634,8 @@ current object." (goto-char (+ (car pos2) (- (cdr pos1) (car pos1)))))))) (defun transpose-subr-1 (pos1 pos2) + (unless (and pos1 pos2) + (error "Don't have two things to transpose")) (when (> (car pos1) (cdr pos1)) (setq pos1 (cons (cdr pos1) (car pos1)))) (when (> (car pos2) (cdr pos2)) (setq pos2 (cons (cdr pos2) (car pos2)))) (when (> (car pos1) (car pos2)) @@ -10114,8 +10145,7 @@ PREFIX is the string that represents this modifier in an event type symbol." ((eq symbol 'shift) ;; FIXME: Should we also apply this "upcase" behavior of shift ;; to non-ascii letters? - (if (and (<= (downcase event) ?z) - (>= (downcase event) ?a)) + (if (<= ?a (downcase event) ?z) (upcase event) (logior (ash 1 lshiftby) event))) (t diff --git a/lisp/startup.el b/lisp/startup.el index bb6250d3968..06783a77c1e 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -2921,7 +2921,7 @@ nil default-directory" name) (when (looking-at "#!") (forward-line)) (let (value form) - (while (ignore-error 'end-of-file + (while (ignore-error end-of-file (setq form (read (current-buffer)))) (setq value (eval form t))) (kill-emacs (if (numberp value) diff --git a/lisp/subr.el b/lisp/subr.el index 0f754fcd31f..f909b63aabe 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -280,14 +280,20 @@ change the list." When COND yields non-nil, eval BODY forms sequentially and return value of last one, or nil if there are none." (declare (indent 1) (debug t)) - (list 'if cond (cons 'progn body))) + (if body + (list 'if cond (cons 'progn body)) + (macroexp-warn-and-return (format-message "`when' with empty body") + cond '(empty-body when) t))) (defmacro unless (cond &rest body) "If COND yields nil, do BODY, else return nil. When COND yields nil, eval BODY forms sequentially and return value of last one, or nil if there are none." (declare (indent 1) (debug t)) - (cons 'if (cons cond (cons nil body)))) + (if body + (cons 'if (cons cond (cons nil body))) + (macroexp-warn-and-return (format-message "`unless' with empty body") + cond '(empty-body unless) t))) (defsubst subr-primitive-p (object) "Return t if OBJECT is a built-in primitive function." @@ -380,9 +386,24 @@ without silencing all errors." "Execute BODY; if the error CONDITION occurs, return nil. Otherwise, return result of last form in BODY. -CONDITION can also be a list of error conditions." +CONDITION can also be a list of error conditions. +The CONDITION argument is not evaluated. Do not quote it." (declare (debug t) (indent 1)) - `(condition-case nil (progn ,@body) (,condition nil))) + (cond + ((and (eq (car-safe condition) 'quote) + (cdr condition) (null (cddr condition))) + (macroexp-warn-and-return + (format-message + "`ignore-error' condition argument should not be quoted: %S" + condition) + `(condition-case nil (progn ,@body) (,(cadr condition) nil)) + nil t condition)) + (body + `(condition-case nil (progn ,@body) (,condition nil))) + (t + (macroexp-warn-and-return (format-message "`ignore-error' with empty body") + nil '(empty-body ignore-error) t condition)))) + ;;;; Basic Lisp functions. @@ -510,8 +531,9 @@ This function is provided for compatibility. In new code, use `ash' instead." (declare (compiler-macro (lambda (form) - (macroexp-warn-and-return "avoid `lsh'; use `ash' instead" - form '(suspicious lsh) t form)))) + (macroexp-warn-and-return + (format-message "avoid `lsh'; use `ash' instead") + form '(suspicious lsh) t form)))) (when (and (< value 0) (< count 0)) (when (< value most-negative-fixnum) (signal 'args-out-of-range (list value count))) @@ -3282,7 +3304,7 @@ floating point support." (lambda (form) (if (not (or (numberp nodisp) obsolete)) form (macroexp-warn-and-return - "Obsolete calling convention for 'sit-for'" + (format-message "Obsolete calling convention for `sit-for'") `(,(car form) (+ ,seconds (/ (or ,nodisp 0) 1000.0)) ,obsolete) '(obsolete sit-for)))))) ;; This used to be implemented in C until the following discussion: @@ -4851,6 +4873,7 @@ but that should be robust in the unexpected case that an error is signaled." (declare (debug t) (indent 1)) (let* ((err (make-symbol "err")) (orig-body body) + (orig-format format) (format (if (and (stringp format) body) format (prog1 "Error: %S" (if format (push format body))))) @@ -4861,7 +4884,10 @@ but that should be robust in the unexpected case that an error is signaled." (if (eq orig-body body) exp ;; The use without `format' is obsolete, let's warn when we bump ;; into any such remaining uses. - (macroexp-warn-and-return "Missing format argument" exp nil nil format)))) + (macroexp-warn-and-return + (format-message "Missing format argument in `with-demote-errors'") + exp nil nil + orig-format)))) (defmacro combine-after-change-calls (&rest body) "Execute BODY, but don't call the after-change functions till the end. @@ -4942,21 +4968,20 @@ the function `undo--wrap-and-run-primitive-undo'." beg (marker-position end-marker) #'undo--wrap-and-run-primitive-undo - beg (marker-position end-marker) buffer-undo-list)) + beg (marker-position end-marker) + ;; We will truncate this list by side-effect below. + buffer-undo-list)) (ptr buffer-undo-list)) (if (not (eq buffer-undo-list old-bul)) (progn (while (and (not (eq (cdr ptr) old-bul)) ;; In case garbage collection has removed OLD-BUL. - (cdr ptr)) - (if (and (consp (cdr ptr)) - (consp (cadr ptr)) - (eq (caadr ptr) t)) - ;; Don't include a timestamp entry. - (setcdr ptr (cddr ptr)) - (setq ptr (cdr ptr)))) - (unless (cdr ptr) - (message "combine-change-calls: buffer-undo-list broken")) + (or (cdr ptr) + (progn + (message "combine-change-calls: buffer-undo-list broken") + nil))) + (setq ptr (cdr ptr))) + ;; Truncate the list that's in the `apply' entry. (setcdr ptr nil) (push ap-elt buffer-undo-list) (setcdr buffer-undo-list old-bul))))) @@ -6087,14 +6112,8 @@ command is called from a keyboard macro?" ;; Skip special forms (from non-compiled code). (and frame (null (car frame))) ;; Skip also `interactive-p' (because we don't want to know if - ;; interactive-p was called interactively but if it's caller was) - ;; and `byte-code' (idem; this appears in subexpressions of things - ;; like condition-case, which are wrapped in a separate bytecode - ;; chunk). - ;; FIXME: For lexical-binding code, this is much worse, - ;; because the frames look like "byte-code -> funcall -> #[...]", - ;; which is not a reliable signature. - (memq (nth 1 frame) '(interactive-p 'byte-code)) + ;; interactive-p was called interactively but if it's caller was). + (eq (nth 1 frame) 'interactive-p) ;; Skip package-specific stack-frames. (let ((skip (run-hook-with-args-until-success 'called-interactively-p-functions diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index 119a243d6b3..9f53b649efd 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el @@ -105,7 +105,7 @@ For easier selection of tabs by their numbers, consider customizing (const hyper) (const super) (const alt)) - :initialize 'custom-initialize-default + :initialize #'custom-initialize-default :set (lambda (sym val) (set-default sym val) ;; Reenable the tab-bar with new keybindings @@ -116,23 +116,23 @@ For easier selection of tabs by their numbers, consider customizing :version "27.1") (defun tab-bar--define-keys () - "Install key bindings for switching between tabs if the user has configured them." + "Install key bindings to switch between tabs if so configured." (when tab-bar-select-tab-modifiers (global-set-key (vector (append tab-bar-select-tab-modifiers (list ?0))) - 'tab-recent) + #'tab-recent) (dotimes (i 8) (global-set-key (vector (append tab-bar-select-tab-modifiers (list (+ i 1 ?0)))) - 'tab-bar-select-tab)) + #'tab-bar-select-tab)) (global-set-key (vector (append tab-bar-select-tab-modifiers (list ?9))) - 'tab-last)) + #'tab-last)) ;; Don't override user customized key bindings (unless (global-key-binding [(control tab)]) - (global-set-key [(control tab)] 'tab-next)) + (global-set-key [(control tab)] #'tab-next)) (unless (global-key-binding [(control shift tab)]) - (global-set-key [(control shift tab)] 'tab-previous)) + (global-set-key [(control shift tab)] #'tab-previous)) (unless (global-key-binding [(control shift iso-lefttab)]) - (global-set-key [(control shift iso-lefttab)] 'tab-previous)) + (global-set-key [(control shift iso-lefttab)] #'tab-previous)) ;; Replace default value with a condition that supports displaying ;; global-mode-string in the tab bar instead of the mode line. @@ -157,6 +157,9 @@ For easier selection of tabs by their numbers, consider customizing (defun tab-bar--load-buttons () "Load the icons for the tab buttons." (require 'icons) + (declare-function icon-string "icons" (name)) + (declare-function iconp "icons" (object)) + (declare-function icons--register "icons") (unless (iconp 'tab-bar-new) (define-icon tab-bar-new nil `((image "tabs/new.xpm" @@ -227,7 +230,8 @@ a list of frames to update." ;; Update `default-frame-alist' (when (eq frames t) (setq default-frame-alist - (cons (cons 'tab-bar-lines (if (and tab-bar-mode (eq tab-bar-show t)) 1 0)) + (cons (cons 'tab-bar-lines + (if (and tab-bar-mode (eq tab-bar-show t)) 1 0)) (assq-delete-all 'tab-bar-lines default-frame-alist))))) (define-minor-mode tab-bar-mode @@ -279,7 +283,8 @@ It returns a list of the form (KEY KEY-BINDING CLOSE-P), where: ;; This code is used when you click the mouse in the tab bar ;; on a console which has no window system but does have a mouse. (let* ((x-position (car (posn-x-y posn))) - (keymap (lookup-key (cons 'keymap (nreverse (current-active-maps))) [tab-bar])) + (keymap (lookup-key (cons 'keymap (nreverse (current-active-maps))) + [tab-bar])) (column 0)) (when x-position (catch 'done @@ -478,7 +483,7 @@ you can use the command `toggle-frame-tab-bar'." :type '(choice (const :tag "Always" t) (const :tag "When more than one tab" 1) (const :tag "Never" nil)) - :initialize 'custom-initialize-default + :initialize #'custom-initialize-default :set (lambda (sym val) (set-default sym val) (if val @@ -529,7 +534,7 @@ to get the group name." "If non-nil, show the \"New tab\" button in the tab bar. When this is nil, you can create new tabs with \\[tab-new]." :type 'boolean - :initialize 'custom-initialize-default + :initialize #'custom-initialize-default :set (lambda (sym val) (set-default sym val) (force-mode-line-update)) @@ -550,7 +555,7 @@ If nil, don't show it at all." (const :tag "On selected tab" selected) (const :tag "On non-selected tabs" non-selected) (const :tag "None" nil)) - :initialize 'custom-initialize-default + :initialize #'custom-initialize-default :set (lambda (sym val) (set-default sym val) (force-mode-line-update)) @@ -574,7 +579,7 @@ If nil, don't show it at all." This helps to select the tab by its number using `tab-bar-select-tab' and `tab-bar-select-tab-modifiers'." :type 'boolean - :initialize 'custom-initialize-default + :initialize #'custom-initialize-default :set (lambda (sym val) (set-default sym val) (force-mode-line-update)) @@ -604,7 +609,7 @@ from all windows in the window configuration." (const :tag "All window buffers" tab-bar-tab-name-all) (function :tag "Function")) - :initialize 'custom-initialize-default + :initialize #'custom-initialize-default :set (lambda (sym val) (set-default sym val) (force-mode-line-update)) @@ -704,7 +709,7 @@ Function gets one argument: a tab." Function gets two arguments, the tab and its number, and should return the formatted tab name to display in the tab bar." :type 'function - :initialize 'custom-initialize-default + :initialize #'custom-initialize-default :set (lambda (sym val) (set-default sym val) (force-mode-line-update)) @@ -753,7 +758,7 @@ of the mode line. Replacing `tab-bar-format-tabs' with tab-bar-format-add-tab tab-bar-format-align-right tab-bar-format-global) - :initialize 'custom-initialize-default + :initialize #'custom-initialize-default :set (lambda (sym val) (set-default sym val) (force-mode-line-update)) @@ -815,7 +820,8 @@ You can hide these buttons by customizing `tab-bar-format' and removing ,(alist-get 'binding tab) :help "Click to visit tab")))) (when (alist-get 'close-binding tab) - `((,(if (eq (car tab) 'current-tab) 'C-current-tab (intern (format "C-tab-%i" i))) + `((,(if (eq (car tab) 'current-tab) 'C-current-tab + (intern (format "C-tab-%i" i))) menu-item "" ,(alist-get 'close-binding tab)))))) @@ -832,7 +838,7 @@ You can hide these buttons by customizing `tab-bar-format' and removing "Function to get a tab group name. Function gets one argument: a tab." :type 'function - :initialize 'custom-initialize-default + :initialize #'custom-initialize-default :set (lambda (sym val) (set-default sym val) (force-mode-line-update)) @@ -848,7 +854,7 @@ Function gets three arguments, a tab with a group name, its number, and an optional value that is non-nil when the tab is from the current group. It should return the formatted tab group name to display in the tab bar." :type 'function - :initialize 'custom-initialize-default + :initialize #'custom-initialize-default :set (lambda (sym val) (set-default sym val) (force-mode-line-update)) @@ -919,7 +925,8 @@ when the tab is current. Return the result as a keymap." (when (and (not (equal previous-group tab-group)) tab-group) (tab-bar--format-tab-group tab i t)) ;; Override default tab faces to use group faces - (let ((tab-bar-tab-face-function tab-bar-tab-group-face-function)) + (let ((tab-bar-tab-face-function + tab-bar-tab-group-face-function)) (tab-bar--format-tab tab i)))) ;; Show first tab of other groups with a group name ((not (equal previous-group tab-group)) @@ -948,7 +955,8 @@ when the tab is current. Return the result as a keymap." ;; when windows are split horizontally (bug#59620) (if (window-system) `(space :align-to (- right (,hpos))) - `(space :align-to (,(- (frame-inner-width) hpos))))))) + `(space :align-to (,(- (frame-inner-width) + hpos))))))) `((align-right menu-item ,str ignore)))) (defun tab-bar-format-global () @@ -1018,7 +1026,7 @@ This variable has effect only when `tab-bar-auto-width' is non-nil." (const :tag "No limit" nil) (list (integer :tag "Max width (pixels)" :value 220) (integer :tag "Max width (chars)" :value 20))) - :initialize 'custom-initialize-default + :initialize #'custom-initialize-default :set (lambda (sym val) (set-default sym val) (setq tab-bar--auto-width-hash nil)) @@ -1087,12 +1095,14 @@ tab bar might wrap to the second line when it shouldn't.") curr-width) (cond ((< prev-width width) - (let* ((space (apply 'propertize " " + (let* ((space (apply #'propertize " " (text-properties-at 0 name))) (ins-pos (- len (if close-p 1 0))) (prev-name name)) (while continue - (setf (substring name ins-pos ins-pos) space) + (setq name (concat (substring name 0 ins-pos) + space + (substring name ins-pos))) (setq curr-width (string-pixel-width name)) (if (and (< curr-width width) (> curr-width prev-width)) @@ -1105,7 +1115,9 @@ tab bar might wrap to the second line when it shouldn't.") (let ((del-pos1 (if close-p -2 -1)) (del-pos2 (if close-p -1 nil))) (while continue - (setf (substring name del-pos1 del-pos2) "") + (setq name (concat (substring name 0 del-pos1) + (and del-pos2 + (substring name del-pos2)))) (setq curr-width (string-pixel-width name)) (if (and (> curr-width width) (< curr-width prev-width)) @@ -1309,11 +1321,13 @@ Negative TAB-NUMBER counts tabs from the end of the tab bar." (when tab-bar-history-mode (puthash (selected-frame) - (and (window-configuration-p (alist-get 'wc (car wc-history-back))) + (and (window-configuration-p + (alist-get 'wc (car wc-history-back))) wc-history-back) tab-bar-history-back) (puthash (selected-frame) - (and (window-configuration-p (alist-get 'wc (car wc-history-forward))) + (and (window-configuration-p + (alist-get 'wc (car wc-history-forward))) wc-history-forward) tab-bar-history-forward)))) @@ -1339,7 +1353,8 @@ Negative TAB-NUMBER counts tabs from the end of the tab bar." (when from-index (setf (nth from-index tabs) from-tab)) - (setf (nth to-index tabs) (tab-bar--current-tab-make (nth to-index tabs))) + (setf (nth to-index tabs) + (tab-bar--current-tab-make (nth to-index tabs))) (unless tab-bar-mode (message "Selected tab '%s'" (alist-get 'name to-tab)))) @@ -1406,7 +1421,7 @@ and rename it to NAME." (tab-bar-new-tab) (tab-bar-rename-tab name)))) -(defalias 'tab-bar-select-tab-by-name 'tab-bar-switch-to-tab) +(defalias 'tab-bar-select-tab-by-name #'tab-bar-switch-to-tab) (defun tab-bar-move-tab-to (to-number &optional from-number) @@ -1421,7 +1436,8 @@ where argument addressing is relative." (from-number (or from-number (1+ (tab-bar--current-tab-index tabs)))) (from-tab (nth (1- from-number) tabs)) (to-number (if to-number (prefix-numeric-value to-number) 1)) - (to-number (if (< to-number 0) (+ (length tabs) (1+ to-number)) to-number)) + (to-number (if (< to-number 0) (+ (length tabs) (1+ to-number)) + to-number)) (to-index (max 0 (min (1- to-number) (1- (length tabs)))))) (setq tabs (delq from-tab tabs)) (cl-pushnew from-tab (nthcdr to-index tabs)) @@ -1447,7 +1463,8 @@ Like `tab-bar-move-tab', but moves in the opposite direction." (interactive "p") (tab-bar-move-tab (- (or arg 1)))) -(defun tab-bar-move-tab-to-frame (arg &optional from-frame from-number to-frame to-number) +(defun tab-bar-move-tab-to-frame (arg &optional from-frame from-number + to-frame to-number) "Move tab from FROM-NUMBER position to new position at TO-NUMBER. FROM-NUMBER defaults to the current tab number. FROM-NUMBER and TO-NUMBER count from 1. @@ -1463,7 +1480,8 @@ to which to move the tab; ARG defaults to 1." (setq to-frame (next-frame to-frame)))) (unless (eq from-frame to-frame) (let* ((from-tabs (funcall tab-bar-tabs-function from-frame)) - (from-number (or from-number (1+ (tab-bar--current-tab-index from-tabs)))) + (from-number (or from-number + (1+ (tab-bar--current-tab-index from-tabs)))) (from-tab (nth (1- from-number) from-tabs)) (to-tabs (funcall tab-bar-tabs-function to-frame)) (to-index (max 0 (min (1- (or to-number 1)) (1- (length to-tabs)))))) @@ -1485,7 +1503,8 @@ to which to move the tab; ARG defaults to 1." FROM-NUMBER defaults to the current tab (which happens interactively)." (interactive (list (1+ (tab-bar--current-tab-index)))) (let* ((tabs (funcall tab-bar-tabs-function)) - (tab-index (1- (or from-number (1+ (tab-bar--current-tab-index tabs))))) + (tab-index (1- (or from-number + (1+ (tab-bar--current-tab-index tabs))))) (tab-name (alist-get 'name (nth tab-index tabs))) ;; On some window managers, `make-frame' selects the new frame, ;; so previously selected frame is saved to `from-frame'. @@ -1748,7 +1767,8 @@ for the last tab on a frame is determined by ;; Select another tab before deleting the current tab (let ((to-index (or (if to-number (1- to-number)) (pcase tab-bar-close-tab-select - ('left (1- (if (< current-index 1) 2 current-index))) + ('left (1- (if (< current-index 1) 2 + current-index))) ('right (if (> (length tabs) (1+ current-index)) (1+ current-index) (1- current-index))) @@ -1773,7 +1793,8 @@ for the last tab on a frame is determined by (force-mode-line-update) (unless tab-bar-mode - (message "Deleted tab and switched to %s" tab-bar-close-tab-select)))))) + (message "Deleted tab and switched to %s" + tab-bar-close-tab-select)))))) (defun tab-bar-close-tab-by-name (name) "Close the tab given its NAME. @@ -1864,7 +1885,8 @@ If NAME is the empty string, then use the automatic name function `tab-bar-tab-name-function'." (interactive (let* ((tabs (funcall tab-bar-tabs-function)) - (tab-number (or current-prefix-arg (1+ (tab-bar--current-tab-index tabs)))) + (tab-number (or current-prefix-arg + (1+ (tab-bar--current-tab-index tabs)))) (tab-name (alist-get 'name (nth (1- tab-number) tabs)))) (list (read-from-minibuffer "New name for tab (leave blank for automatic naming): " @@ -2129,10 +2151,10 @@ and can restore them." :version "29.1")) (setq tab-bar-forward-button (icon-string 'tab-bar-forward)) - (add-hook 'pre-command-hook 'tab-bar--history-pre-change) - (add-hook 'window-configuration-change-hook 'tab-bar--history-change)) - (remove-hook 'pre-command-hook 'tab-bar--history-pre-change) - (remove-hook 'window-configuration-change-hook 'tab-bar--history-change))) + (add-hook 'pre-command-hook #'tab-bar--history-pre-change) + (add-hook 'window-configuration-change-hook #'tab-bar--history-change)) + (remove-hook 'pre-command-hook #'tab-bar--history-pre-change) + (remove-hook 'window-configuration-change-hook #'tab-bar--history-change))) ;;; Non-graphical access to frame-local tabs (named window configurations) @@ -2172,8 +2194,9 @@ For more information, see the function `tab-switcher'." (tabs (sort tabs (lambda (a b) (< (alist-get 'time b) (alist-get 'time a)))))) (with-current-buffer (get-buffer-create - (format " *Tabs*<%s>" (or (frame-parameter nil 'window-id) - (frame-parameter nil 'name)))) + (format " *Tabs*<%s>" + (or (frame-parameter nil 'window-id) + (frame-parameter nil 'name)))) (setq buffer-read-only nil) (erase-buffer) (tab-switcher-mode) @@ -2188,7 +2211,8 @@ For more information, see the function `tab-switcher'." (propertize (alist-get 'name tab) 'mouse-face 'highlight - 'help-echo "mouse-2: select this window configuration")) + 'help-echo + "mouse-2: select this window configuration")) 'tab tab))) (goto-char (point-min)) (goto-char (or (next-single-property-change (point) 'tab) (point-min))) @@ -2264,8 +2288,8 @@ Interactively, ARG is the prefix numeric argument and defaults to 1." (move-to-column tab-switcher-column)) (defun tab-switcher-unmark (&optional backup) - "Cancel requested operations on window configuration on this line and move down. -With prefix arg, move up instead." + "Cancel operations on window configuration on this line and move down. +With prefix arg BACKUP, move up instead." (interactive "P") (beginning-of-line) (move-to-column tab-switcher-column) @@ -2276,7 +2300,7 @@ With prefix arg, move up instead." (move-to-column tab-switcher-column)) (defun tab-switcher-backup-unmark () - "Move up one line and cancel requested operations on window configuration there." + "Move up one line and cancel operations on window configuration there." (interactive) (forward-line -1) (tab-switcher-unmark) @@ -2284,9 +2308,10 @@ With prefix arg, move up instead." (move-to-column tab-switcher-column)) (defun tab-switcher-delete (&optional arg) - "Mark window configuration on this line to be deleted by \\<tab-switcher-mode-map>\\[tab-switcher-execute] command. + "Mark window configuration on this line to be deleted. Prefix arg says how many window configurations to delete. -Negative arg means delete backwards." +Negative arg means delete backwards. +The deletion will be done by the \\<tab-switcher-mode-map>\\[tab-switcher-execute] command." (interactive "p") (let ((buffer-read-only nil)) (if (or (null arg) (= arg 0)) @@ -2304,8 +2329,9 @@ Negative arg means delete backwards." (move-to-column tab-switcher-column))) (defun tab-switcher-delete-backwards (&optional arg) - "Mark window configuration on this line to be deleted by \\<tab-switcher-mode-map>\\[tab-switcher-execute] command. -Then move up one line. Prefix arg means move that many lines." + "Mark window configuration on this line to be deleted. +Then move up one line. Prefix arg means move that many lines. +The deletion will be done by the \\<tab-switcher-mode-map>\\[tab-switcher-execute] command." (interactive "p") (tab-switcher-delete (- (or arg 1)))) @@ -2318,7 +2344,9 @@ Then move up one line. Prefix arg means move that many lines." (tab-bar-tabs-set (delq tab (funcall tab-bar-tabs-function)))) (defun tab-switcher-execute () - "Delete window configurations marked with \\<tab-switcher-mode-map>\\[tab-switcher-delete] commands." + "Delete the marked window configurations. +Use the \\<tab-switcher-mode-map>\\[tab-switcher-delete] commands +to set those marks." (interactive) (save-excursion (goto-char (point-min)) @@ -2364,7 +2392,8 @@ with those specified by the selected window configuration." ((framep all-frames) (list all-frames)) (t (list (selected-frame))))) -(defun tab-bar-get-buffer-tab (buffer-or-name &optional all-frames ignore-current-tab all-tabs) +(defun tab-bar-get-buffer-tab (buffer-or-name + &optional all-frames ignore-current-tab all-tabs) "Return the tab that owns the window whose buffer is BUFFER-OR-NAME. BUFFER-OR-NAME may be a buffer or a buffer name, and defaults to the current buffer. @@ -2540,7 +2569,7 @@ files will be visited." (progn (setq value (nreverse value)) (switch-to-buffer-other-tab (car value)) - (mapc 'switch-to-buffer (cdr value)) + (mapc #'switch-to-buffer (cdr value)) value) (switch-to-buffer-other-tab value)))) @@ -2582,26 +2611,26 @@ When `switch-to-buffer-obey-display-actions' is non-nil, ;;; Short aliases and keybindings -(defalias 'tab-new 'tab-bar-new-tab) -(defalias 'tab-new-to 'tab-bar-new-tab-to) -(defalias 'tab-duplicate 'tab-bar-duplicate-tab) -(defalias 'tab-detach 'tab-bar-detach-tab) -(defalias 'tab-window-detach 'tab-bar-move-window-to-tab) -(defalias 'tab-close 'tab-bar-close-tab) -(defalias 'tab-close-other 'tab-bar-close-other-tabs) -(defalias 'tab-close-group 'tab-bar-close-group-tabs) -(defalias 'tab-undo 'tab-bar-undo-close-tab) -(defalias 'tab-select 'tab-bar-select-tab) -(defalias 'tab-switch 'tab-bar-switch-to-tab) -(defalias 'tab-next 'tab-bar-switch-to-next-tab) -(defalias 'tab-previous 'tab-bar-switch-to-prev-tab) -(defalias 'tab-last 'tab-bar-switch-to-last-tab) -(defalias 'tab-recent 'tab-bar-switch-to-recent-tab) -(defalias 'tab-move 'tab-bar-move-tab) -(defalias 'tab-move-to 'tab-bar-move-tab-to) -(defalias 'tab-rename 'tab-bar-rename-tab) -(defalias 'tab-group 'tab-bar-change-tab-group) -(defalias 'tab-list 'tab-switcher) +(defalias 'tab-new #'tab-bar-new-tab) +(defalias 'tab-new-to #'tab-bar-new-tab-to) +(defalias 'tab-duplicate #'tab-bar-duplicate-tab) +(defalias 'tab-detach #'tab-bar-detach-tab) +(defalias 'tab-window-detach #'tab-bar-move-window-to-tab) +(defalias 'tab-close #'tab-bar-close-tab) +(defalias 'tab-close-other #'tab-bar-close-other-tabs) +(defalias 'tab-close-group #'tab-bar-close-group-tabs) +(defalias 'tab-undo #'tab-bar-undo-close-tab) +(defalias 'tab-select #'tab-bar-select-tab) +(defalias 'tab-switch #'tab-bar-switch-to-tab) +(defalias 'tab-next #'tab-bar-switch-to-next-tab) +(defalias 'tab-previous #'tab-bar-switch-to-prev-tab) +(defalias 'tab-last #'tab-bar-switch-to-last-tab) +(defalias 'tab-recent #'tab-bar-switch-to-recent-tab) +(defalias 'tab-move #'tab-bar-move-tab) +(defalias 'tab-move-to #'tab-bar-move-tab-to) +(defalias 'tab-rename #'tab-bar-rename-tab) +(defalias 'tab-group #'tab-bar-change-tab-group) +(defalias 'tab-list #'tab-switcher) (keymap-set tab-prefix-map "n" #'tab-duplicate) (keymap-set tab-prefix-map "N" #'tab-new-to) diff --git a/lisp/textmodes/html-ts-mode.el b/lisp/textmodes/html-ts-mode.el new file mode 100644 index 00000000000..58dcc7d8cad --- /dev/null +++ b/lisp/textmodes/html-ts-mode.el @@ -0,0 +1,134 @@ +;;; html-ts-mode.el --- tree-sitter support for HTML -*- lexical-binding: t; -*- + +;; Copyright (C) 2023 Free Software Foundation, Inc. + +;; Author : Theodor Thornhill <theo@thornhill.no> +;; Maintainer : Theodor Thornhill <theo@thornhill.no> +;; Created : January 2023 +;; Keywords : html languages tree-sitter + +;; 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: +;; + +;;; Code: + +(require 'treesit) +(require 'sgml-mode) + +(declare-function treesit-parser-create "treesit.c") +(declare-function treesit-node-type "treesit.c") + +(defcustom html-ts-mode-indent-offset 2 + "Number of spaces for each indentation step in `html-ts-mode'." + :version "29.1" + :type 'integer + :safe 'integerp + :group 'html) + +(defvar html-ts-mode--indent-rules + `((html + ((parent-is "fragment") point-min 0) + ((node-is "/>") parent-bol 0) + ((node-is ">") parent-bol 0) + ((node-is "end_tag") parent-bol 0) + ((parent-is "comment") prev-adaptive-prefix 0) + ((parent-is "element") parent-bol html-ts-mode-indent-offset) + ((parent-is "script_element") parent-bol html-ts-mode-indent-offset) + ((parent-is "style_element") parent-bol html-ts-mode-indent-offset) + ((parent-is "start_tag") parent-bol html-ts-mode-indent-offset) + ((parent-is "self_closing_tag") parent-bol html-ts-mode-indent-offset))) + "Tree-sitter indent rules.") + +(defvar html-ts-mode--font-lock-settings + (treesit-font-lock-rules + :language 'html + :override t + :feature 'comment + `((comment) @font-lock-comment-face) + :language 'html + :override t + :feature 'keyword + `("doctype" @font-lock-keyword-face) + :language 'html + :override t + :feature 'definition + `((tag_name) @font-lock-function-name-face) + :language 'html + :override t + :feature 'string + `((quoted_attribute_value) @font-lock-string-face) + :language 'html + :override t + :feature 'property + `((attribute_name) @font-lock-variable-name-face)) + "Tree-sitter font-lock settings for `html-ts-mode'.") + +(defun html-ts-mode--defun-name (node) + "Return the defun name of NODE. +Return nil if there is no name or if NODE is not a defun node." + (when (equal (treesit-node-type node) "tag_name") + (treesit-node-text node t))) + +;;;###autoload +(define-derived-mode html-ts-mode html-mode "HTML" + "Major mode for editing Html, powered by tree-sitter." + :group 'html + + (unless (treesit-ready-p 'html) + (error "Tree-sitter for HTML isn't available")) + + (treesit-parser-create 'html) + + ;; Comments. + (setq-local treesit-text-type-regexp + (regexp-opt '("comment" "text"))) + + ;; Indent. + (setq-local treesit-simple-indent-rules html-ts-mode--indent-rules) + + ;; Navigation. + (setq-local treesit-defun-type-regexp "element") + + (setq-local treesit-defun-name-function #'html-ts-mode--defun-name) + + (setq-local treesit-sentence-type-regexp "tag") + + (setq-local treesit-sexp-type-regexp + (regexp-opt '("element" + "text" + "attribute" + "value"))) + + ;; Font-lock. + (setq-local treesit-font-lock-settings html-ts-mode--font-lock-settings) + (setq-local treesit-font-lock-feature-list + '((comment keyword definition) + (property string) + () ())) + + ;; Imenu. + (setq-local treesit-simple-imenu-settings + '(("Element" "\\`tag_name\\'" nil nil))) + (treesit-major-mode-setup)) + +(if (treesit-ready-p 'html) + (add-to-list 'auto-mode-alist '("\\.html\\'" . html-ts-mode))) + +(provide 'html-ts-mode) + +;;; html-ts-mode.el ends here diff --git a/lisp/textmodes/paragraphs.el b/lisp/textmodes/paragraphs.el index 73abb155aaa..bf249fdcdfb 100644 --- a/lisp/textmodes/paragraphs.el +++ b/lisp/textmodes/paragraphs.el @@ -441,13 +441,12 @@ the current paragraph with the one containing the mark." (if (< (point) (point-max)) (end-of-paragraph-text)))))) -(defun forward-sentence (&optional arg) +(defun forward-sentence-default-function (&optional arg) "Move forward to next end of sentence. With argument, repeat. When ARG is negative, move backward repeatedly to start of sentence. The variable `sentence-end' is a regular expression that matches ends of sentences. Also, every paragraph boundary terminates sentences as well." - (interactive "^p") (or arg (setq arg 1)) (let ((opoint (point)) (sentence-end (sentence-end))) @@ -480,6 +479,18 @@ sentences. Also, every paragraph boundary terminates sentences as well." (let ((npoint (constrain-to-field nil opoint t))) (not (= npoint opoint))))) +(defvar forward-sentence-function #'forward-sentence-default-function + "Function to be used to calculate sentence movements. +See `forward-sentence' for a description of its behavior.") + +(defun forward-sentence (&optional arg) + "Move forward to next end of sentence. With argument ARG, repeat. +If ARG is negative, move backward repeatedly to start of +sentence. Delegates its work to `forward-sentence-function'." + (interactive "^p") + (or arg (setq arg 1)) + (funcall forward-sentence-function arg)) + (defun count-sentences (start end) "Count sentences in current buffer from START to END." (let ((sentences 0) diff --git a/lisp/transient.el b/lisp/transient.el index cd8640a7d74..0b41bc44adb 100644 --- a/lisp/transient.el +++ b/lisp/transient.el @@ -2211,7 +2211,7 @@ value. Otherwise return CHILDREN as is." (delayed (if transient--exitp (apply-partially #'transient--post-exit this-command) #'transient--resume-override)) - post-command abort-minibuffer) + outside-interactive post-command abort-minibuffer) (unless abort-only (setq post-command (lambda () "@transient--delay-post-command" @@ -2223,7 +2223,9 @@ value. Otherwise return CHILDREN as is." (equal (ignore-errors (string-to-multibyte (this-command-keys))) - (format "\M-x%s\r" this-command)))))) + (format "\M-x%s\r" this-command)) + ;; Minibuffer used outside `interactive'. + (and outside-interactive 'post-cmd))))) (transient--debug 'post-command-hook "act: %s" act) (when act (remove-hook 'transient--post-command-hook post-command) @@ -2232,12 +2234,15 @@ value. Otherwise return CHILDREN as is." (add-hook 'transient--post-command-hook post-command)) (setq abort-minibuffer (lambda () "@transient--delay-post-command" - (let ((act (and (or (memq this-command transient--abort-commands) - (equal (this-command-keys) "")) - (= (minibuffer-depth) depth)))) + (let ((act (and (= (minibuffer-depth) depth) + (or (memq this-command transient--abort-commands) + (equal (this-command-keys) "") + (prog1 nil + (setq outside-interactive t)))))) (transient--debug 'abort-minibuffer - "mini: %s|%s, act %s" (minibuffer-depth) depth act) + "mini: %s|%s, act: %s" (minibuffer-depth) depth + (or act (and outside-interactive '->post-cmd))) (when act (remove-hook 'transient--post-command-hook post-command) (remove-hook 'minibuffer-exit-hook abort-minibuffer) diff --git a/lisp/treesit.el b/lisp/treesit.el index 98f446a1456..d11e57fef8a 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -1662,6 +1662,47 @@ BACKWARD and ALL are the same as in `treesit-search-forward'." (goto-char current-pos))) node)) +(defvar-local treesit-sexp-type-regexp nil + "A regexp that matches the node type of sexp nodes. + +A sexp node is a node that is bigger than punctuation, and +delimits medium sized statements in the source code. It is, +however, smaller in scope than sentences. This is used by +`treesit-forward-sexp' and friends.") + +(defun treesit-forward-sexp (&optional arg) + (interactive "^p") + (or arg (setq arg 1)) + (funcall + (if (> arg 0) #'treesit-end-of-thing #'treesit-beginning-of-thing) + treesit-sexp-type-regexp (abs arg))) + +(defun treesit-transpose-sexps (&optional arg) + "Tree-sitter `transpose-sexps' function. +Arg is the same as in `transpose-sexps'. + +Locate the node closest to POINT, and transpose that node with +its sibling node ARG nodes away. + +Return a pair of positions as described by +`transpose-sexps-function' for use in `transpose-subr' and +friends." + (let* ((parent (treesit-node-parent (treesit-node-at (point)))) + (child (treesit-node-child parent 0 t))) + (named-let loop ((prev child) + (next (treesit-node-next-sibling child t))) + (when (and prev next) + (if (< (point) (treesit-node-end next)) + (if (= arg -1) + (cons (treesit-node-start prev) + (treesit-node-end prev)) + (when-let ((n (treesit-node-child + parent (+ arg (treesit-node-index prev t)) t))) + (cons (treesit-node-end n) + (treesit-node-start n)))) + (loop (treesit-node-next-sibling prev t) + (treesit-node-next-sibling next t))))))) + ;;; Navigation, defun, things ;; ;; Emacs lets you define "things" by a regexp that matches the type of @@ -1804,6 +1845,40 @@ this function depends on `treesit-defun-type-regexp' and (when treesit-defun-skipper (funcall treesit-defun-skipper)))) +(defvar-local treesit-text-type-regexp "\\`comment\\'" + "A regexp that matches the node type of textual nodes. + +A textual node is a node that is not normal code, such as +comments and multiline string literals. For example, +\"(line|block)_comment\" in the case of a comment, or +\"text_block\" in the case of a string. This is used by +`prog-fill-reindent-defun' and friends.") + +(defvar-local treesit-sentence-type-regexp nil + "A regexp that matches the node type of sentence nodes. + +A sentence node is a node that is bigger than a sexp, and +delimits larger statements in the source code. It is, however, +smaller in scope than defuns. This is used by +`treesit-forward-sentence' and friends.") + +(defun treesit-forward-sentence (&optional arg) + "Tree-sitter `forward-sentence-function' function. + +ARG is the same as in `forward-sentence'. + +If inside comment or other nodes described in +`treesit-sentence-type-regexp', use +`forward-sentence-default-function', else move across nodes as +described by `treesit-sentence-type-regexp'." + (if (string-match-p + treesit-text-type-regexp + (treesit-node-type (treesit-node-at (point)))) + (funcall #'forward-sentence-default-function arg) + (funcall + (if (> arg 0) #'treesit-end-of-thing #'treesit-beginning-of-thing) + treesit-sentence-type-regexp (abs arg)))) + (defun treesit-default-defun-skipper () "Skips spaces after navigating a defun. This function tries to move to the beginning of a line, either by @@ -2266,6 +2341,13 @@ before calling this function." (when treesit-defun-name-function (setq-local add-log-current-defun-function #'treesit-add-log-current-defun)) + + (when treesit-sexp-type-regexp + (setq-local forward-sexp-function #'treesit-forward-sexp)) + (setq-local transpose-sexps-function #'treesit-transpose-sexps) + (when treesit-sentence-type-regexp + (setq-local forward-sentence-function #'treesit-forward-sentence)) + ;; Imenu. (when treesit-simple-imenu-settings (setq-local imenu-create-index-function diff --git a/lisp/url/url-future.el b/lisp/url/url-future.el index fc852ed7c0b..9b528835a7b 100644 --- a/lisp/url/url-future.el +++ b/lisp/url/url-future.el @@ -53,7 +53,7 @@ (define-inline url-future-errored-p (url-future) (inline-quote (eq (url-future-status ,url-future) 'error))) -(define-inline url-future-cancelled-p (url-future) +(define-inline url-future-canceled-p (url-future) (inline-quote (eq (url-future-status ,url-future) 'cancel))) (defun url-future-finish (url-future &optional status) @@ -96,5 +96,8 @@ (signal 'error 'url-future-already-done) (url-future-finish url-future 'cancel))) +(define-obsolete-function-alias 'url-future-cancelled-p + #'url-future-canceled-p "30.1") + (provide 'url-future) ;;; url-future.el ends here diff --git a/lisp/use-package/bind-key.el b/lisp/use-package/bind-key.el index 0ab72eafce2..b216c668d83 100644 --- a/lisp/use-package/bind-key.el +++ b/lisp/use-package/bind-key.el @@ -447,7 +447,7 @@ This binds keys in such a way that bindings are not overridden by other modes. See `override-global-mode'." (macroexp-progn (bind-keys-form args 'override-global-map))) -(defun get-binding-description (elem) +(defun bind-key--get-binding-description (elem) (cond ((listp elem) (cond @@ -474,7 +474,7 @@ other modes. See `override-global-mode'." (t "#<byte-compiled lambda>"))) -(defun compare-keybindings (l r) +(defun bind-key--compare-keybindings (l r) (let* ((regex bind-key-segregation-regexp) (lgroup (and (string-match regex (caar l)) (match-string 0 (caar l)))) @@ -517,7 +517,7 @@ other modes. See `override-global-mode'." (setq personal-keybindings (sort personal-keybindings (lambda (l r) - (car (compare-keybindings l r)))))) + (car (bind-key--compare-keybindings l r)))))) (if (not (eq (cdar last-binding) (cdar binding))) (princ (format "\n\n%s: %s\n%s\n\n" @@ -525,7 +525,7 @@ other modes. See `override-global-mode'." (make-string (+ 21 (car bind-key-column-widths) (cdr bind-key-column-widths)) ?-))) (if (and last-binding - (cdr (compare-keybindings last-binding binding))) + (cdr (bind-key--compare-keybindings last-binding binding))) (princ "\n"))) (let* ((key-name (caar binding)) @@ -534,10 +534,10 @@ other modes. See `override-global-mode'." (read-kbd-macro key-name))) (command (nth 1 binding)) (was-command (nth 2 binding)) - (command-desc (get-binding-description command)) + (command-desc (bind-key--get-binding-description command)) (was-command-desc (and was-command - (get-binding-description was-command))) - (at-present-desc (get-binding-description at-present))) + (bind-key--get-binding-description was-command))) + (at-present-desc (bind-key--get-binding-description at-present))) (let ((line (format (format "%%-%ds%%-%ds%%s\n" (car bind-key-column-widths) @@ -555,6 +555,11 @@ other modes. See `override-global-mode'." (setq last-binding binding))))) +(define-obsolete-function-alias 'get-binding-description + 'bind-key--get-binding-description "30.1") +(define-obsolete-function-alias 'compare-keybindings + 'bind-key--compare-keybindings "30.1") + (provide 'bind-key) ;; Local Variables: diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index 7ae763d2ee4..a3469b71386 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -136,12 +136,19 @@ If nil, use the value of `vc-annotate-switches'. If t, use no switches." ;;;###autoload(put 'vc-git-annotate-switches 'safe-local-variable (lambda (switches) (equal switches "-w"))) (defcustom vc-git-log-switches nil - "String or list of strings specifying switches for Git log under VC." + "String or list of strings giving Git log switches for non-shortlogs." :type '(choice (const :tag "None" nil) (string :tag "Argument String") (repeat :tag "Argument List" :value ("") string)) :version "28.1") +(defcustom vc-git-shortlog-switches nil + "String or list of strings giving Git log switches for shortlogs." + :type '(choice (const :tag "None" nil) + (string :tag "Argument String") + (repeat :tag "Argument List" :value ("") string)) + :version "30.1") + (defcustom vc-git-resolve-conflicts t "When non-nil, mark conflicted file as resolved upon saving. That is performed after all conflict markers in it have been @@ -308,6 +315,23 @@ Good example of file name that needs this: \"test[56].xx\".") (string-trim-right (match-string 1 version-string) "\\.") "0"))))) +(defun vc-git--git-path (&optional path) + "Resolve .git/PATH for the current working tree. +In particular, handle the case where this is a linked working +tree, such that .git is a plain file. + +See the --git-dir and --git-path options to git-rev-parse(1)." + (if (and path (not (string-empty-p path))) + ;; Canonicalize in this branch because --git-dir always returns + ;; an absolute file name. + (expand-file-name + (string-trim-right + (vc-git--run-command-string nil "rev-parse" + "--git-path" path))) + (concat (string-trim-right + (vc-git--run-command-string nil "rev-parse" "--git-dir")) + "/"))) + (defun vc-git--git-status-to-vc-state (code-list) "Convert CODE-LIST to a VC status. @@ -752,12 +776,32 @@ or an empty string if none." :help "Show the contents of the current stash")) map)) +(defun vc-git--cmds-in-progress () + "Return a list of Git commands in progress in this worktree." + (let ((gitdir (vc-git--git-path)) + cmds) + ;; See contrib/completion/git-prompt.sh in git.git. + (when (or (file-directory-p + (expand-file-name "rebase-merge" gitdir)) + (file-exists-p + (expand-file-name "rebase-apply/rebasing" gitdir))) + (push 'rebase cmds)) + (when (file-exists-p + (expand-file-name "rebase-apply/applying" gitdir)) + (push 'am cmds)) + (when (file-exists-p (expand-file-name "MERGE_HEAD" gitdir)) + (push 'merge cmds)) + (when (file-exists-p (expand-file-name "BISECT_START" gitdir)) + (push 'bisect cmds)) + cmds)) + (defun vc-git-dir-extra-headers (dir) (let ((str (with-output-to-string (with-current-buffer standard-output (vc-git--out-ok "symbolic-ref" "HEAD")))) (stash-list (vc-git-stash-list)) (default-directory dir) + (in-progress (vc-git--cmds-in-progress)) branch remote remote-url stash-button stash-string) (if (string-match "^\\(refs/heads/\\)?\\(.+\\)$" str) @@ -832,9 +876,9 @@ or an empty string if none." (propertize remote-url 'face 'vc-dir-header-value))) ;; For now just a heading, key bindings can be added later for various bisect actions - (when (file-exists-p (expand-file-name ".git/BISECT_START" (vc-git-root dir))) + (when (memq 'bisect in-progress) (propertize "\nBisect : in progress" 'face 'vc-dir-status-warning)) - (when (file-exists-p (expand-file-name ".git/rebase-apply" (vc-git-root dir))) + (when (memq 'rebase in-progress) (propertize "\nRebase : in progress" 'face 'vc-dir-status-warning)) (if stash-list (concat @@ -1015,13 +1059,26 @@ It is based on `log-edit-mode', and has Git-specific extensions." ;; message. Handle also remote files. (if (eq system-type 'windows-nt) (let ((default-directory (file-name-directory file1))) - (make-nearby-temp-file "git-msg"))))) + (make-nearby-temp-file "git-msg")))) + to-stash) (when vc-git-patch-string (unless (zerop (vc-git-command nil t nil "diff" "--cached" "--quiet")) - ;; Check that all staged changes also exist in the patch. - ;; This is needed to allow adding/removing files that are - ;; currently staged to the index. So remove the whole file diff - ;; from the patch because commit will take it from the index. + ;; Check that what's already staged is compatible with what + ;; we want to commit (bug#60126). + ;; + ;; 1. If the changes to a file in the index are identical to + ;; the changes to that file we want to commit, remove the + ;; changes from our patch, and let the commit take them + ;; from the index. This is necessary for adding and + ;; removing files to work. + ;; + ;; 2. If the changes to a file in the index are different to + ;; changes to that file we want to commit, then we have to + ;; unstage the changes or abort. + ;; + ;; 3. If there are changes to a file in the index but we don't + ;; want to commit any changes to that file, we need to + ;; stash those changes before committing. (with-temp-buffer ;; If the user has switches like -D, -M etc. in their ;; `vc-git-diff-switches', we must pass them here too, or @@ -1032,23 +1089,35 @@ It is based on `log-edit-mode', and has Git-specific extensions." ;; Following code doesn't understand plain diff(1) output. (user-error "Cannot commit patch with nil `vc-git-diff-switches'")) (goto-char (point-min)) - (let ((pos (point)) file-diff file-beg) + (let ((pos (point)) file-name file-header file-diff file-beg) (while (not (eobp)) + (when (and (looking-at "^diff --git a/\\(.+\\) b/\\(.+\\)") + (string= (match-string 1) (match-string 2))) + (setq file-name (match-string 1))) (forward-line 1) ; skip current "diff --git" line + (setq file-header (buffer-substring pos (point))) (search-forward "diff --git" nil 'move) (move-beginning-of-line 1) (setq file-diff (buffer-substring pos (point))) - (if (and (setq file-beg (string-search - file-diff vc-git-patch-string)) - ;; Check that file diff ends with an empty string - ;; or the beginning of the next file diff. - (string-match-p "\\`\\'\\|\\`diff --git" - (substring - vc-git-patch-string - (+ file-beg (length file-diff))))) - (setq vc-git-patch-string - (string-replace file-diff "" vc-git-patch-string)) - (user-error "Index not empty")) + (cond ((and (setq file-beg (string-search + file-diff vc-git-patch-string)) + ;; Check that file diff ends with an empty string + ;; or the beginning of the next file diff. + (string-match-p "\\`\\'\\|\\`diff --git" + (substring + vc-git-patch-string + (+ file-beg (length file-diff))))) + (setq vc-git-patch-string + (string-replace file-diff "" vc-git-patch-string))) + ((string-match (format "^%s" (regexp-quote file-header)) + vc-git-patch-string) + (if (and file-name + (yes-or-no-p + (format "Unstage already-staged changes to %s?" + file-name))) + (vc-git-command nil 0 file-name "reset" "-q" "--") + (user-error "Index not empty"))) + (t (push file-name to-stash))) (setq pos (point)))))) (unless (string-empty-p vc-git-patch-string) (let ((patch-file (make-nearby-temp-file "git-patch"))) @@ -1056,7 +1125,8 @@ It is based on `log-edit-mode', and has Git-specific extensions." (insert vc-git-patch-string)) (unwind-protect (vc-git-command nil 0 patch-file "apply" "--cached") - (delete-file patch-file))))) + (delete-file patch-file)))) + (when to-stash (vc-git--stash-staged-changes files))) (cl-flet ((boolean-arg-fn (argument) (lambda (value) (when (equal value "yes") (list argument))))) @@ -1082,7 +1152,58 @@ It is based on `log-edit-mode', and has Git-specific extensions." args) (unless vc-git-patch-string (if only (list "--only" "--") '("-a")))))) - (if (and msg-file (file-exists-p msg-file)) (delete-file msg-file)))) + (if (and msg-file (file-exists-p msg-file)) (delete-file msg-file)) + (when to-stash + (let ((cached (make-nearby-temp-file "git-cached"))) + (unwind-protect + (progn (with-temp-file cached + (vc-git-command t 0 nil "stash" "show" "-p")) + (vc-git-command nil 0 cached "apply" "--cached")) + (delete-file cached)) + (vc-git-command nil 0 nil "stash" "drop"))))) + +(defun vc-git--stash-staged-changes (files) + "Stash only the staged changes to FILES." + ;; This is necessary because even if you pass a list of file names + ;; to 'git stash push', it will stash any and all staged changes. + (unless (zerop + (vc-git-command nil t files "diff" "--cached" "--quiet")) + (cl-flet + ((git-string (&rest args) + (string-trim-right + (with-output-to-string + (apply #'vc-git-command standard-output 0 nil args))))) + (let ((cached (make-nearby-temp-file "git-cached")) + (message "Previously staged changes") + tree) + ;; Use a temporary index to create a tree object corresponding + ;; to the staged changes to FILES. + (unwind-protect + (progn + (with-temp-file cached + (vc-git-command t 0 files "diff" "--cached" "--")) + (let* ((index (make-nearby-temp-file "git-index")) + (process-environment + (cons (format "GIT_INDEX_FILE=%s" index) + process-environment))) + (unwind-protect + (progn + (vc-git-command nil 0 nil "read-tree" "HEAD") + (vc-git-command nil 0 cached "apply" "--cached") + (setq tree (git-string "write-tree"))) + (delete-file index)))) + (delete-file cached)) + ;; Prepare stash commit object, which has a special structure. + (let* ((tree-commit (git-string "commit-tree" "-m" message + "-p" "HEAD" tree)) + (stash-commit (git-string "commit-tree" "-m" message + "-p" "HEAD" "-p" tree-commit + tree))) + ;; Push the new stash entry. + (vc-git-command nil 0 nil "update-ref" "--create-reflog" + "-m" message "refs/stash" stash-commit) + ;; Unstage the changes we've now stashed. + (vc-git-command nil 0 files "reset" "--")))))) (defun vc-git-find-revision (file rev buffer) (let* (process-file-side-effects @@ -1193,8 +1314,7 @@ This prompts for a branch to merge from." (completing-read "Merge from branch: " (if (or (member "FETCH_HEAD" branches) (not (file-readable-p - (expand-file-name ".git/FETCH_HEAD" - root)))) + (vc-git--git-path "FETCH_HEAD")))) branches (cons "FETCH_HEAD" branches)) nil t))) @@ -1239,8 +1359,7 @@ This prompts for a branch to merge from." (unless (or (not (eq vc-git-resolve-conflicts 'unstage-maybe)) ;; Doing a merge, so bug#20292 doesn't apply. - (file-exists-p (expand-file-name ".git/MERGE_HEAD" - (vc-git-root buffer-file-name))) + (file-exists-p (vc-git--git-path "MERGE_HEAD")) (vc-git-conflicted-files (vc-git-root buffer-file-name))) (vc-git-command nil 0 nil "reset")) (vc-resynch-buffer buffer-file-name t t) @@ -1315,7 +1434,8 @@ If LIMIT is a revision string, use it as an end-revision." ,(format "--pretty=tformat:%s" (car vc-git-root-log-format)) "--abbrev-commit")) - (ensure-list vc-git-log-switches) + (ensure-list + (if shortlog vc-git-shortlog-switches vc-git-log-switches)) (when (numberp limit) (list "-n" (format "%s" limit))) (when start-revision @@ -1330,16 +1450,16 @@ If LIMIT is a revision string, use it as an end-revision." (defun vc-git-log-outgoing (buffer remote-location) (vc-setup-buffer buffer) - (vc-git-command - buffer 'async nil - "log" - "--no-color" "--graph" "--decorate" "--date=short" - (format "--pretty=tformat:%s" (car vc-git-root-log-format)) - "--abbrev-commit" - (concat (if (string= remote-location "") - "@{upstream}" - remote-location) - "..HEAD"))) + (apply #'vc-git-command buffer 'async nil + `("log" + "--no-color" "--graph" "--decorate" "--date=short" + ,(format "--pretty=tformat:%s" (car vc-git-root-log-format)) + "--abbrev-commit" + ,@(ensure-list vc-git-shortlog-switches) + ,(concat (if (string= remote-location "") + "@{upstream}" + remote-location) + "..HEAD")))) (defun vc-git-log-incoming (buffer remote-location) (vc-setup-buffer buffer) @@ -1349,15 +1469,15 @@ If LIMIT is a revision string, use it as an end-revision." ;; so remove everything except a repository name. (replace-regexp-in-string "/.*" "" remote-location))) - (vc-git-command - buffer 'async nil - "log" - "--no-color" "--graph" "--decorate" "--date=short" - (format "--pretty=tformat:%s" (car vc-git-root-log-format)) - "--abbrev-commit" - (concat "HEAD.." (if (string= remote-location "") - "@{upstream}" - remote-location)))) + (apply #'vc-git-command buffer 'async nil + `("log" + "--no-color" "--graph" "--decorate" "--date=short" + ,(format "--pretty=tformat:%s" (car vc-git-root-log-format)) + "--abbrev-commit" + ,@(ensure-list vc-git-shortlog-switches) + ,(concat "HEAD.." (if (string= remote-location "") + "@{upstream}" + remote-location))))) (defun vc-git-log-search (buffer pattern) "Search the log of changes for PATTERN and output results into BUFFER. @@ -1368,6 +1488,7 @@ Display all entries that match log messages in long format. With a prefix argument, ask for a command to run that will output log entries." (let ((args `("log" "--no-color" "-i" + ,@(ensure-list vc-git-log-switches) ,(format "--grep=%s" (or pattern ""))))) (when current-prefix-arg (setq args (cdr (split-string @@ -1415,11 +1536,11 @@ log entries." `((,log-view-message-re (1 'change-log-acknowledgment))) ;; Handle the case: ;; user: foo@bar - '(("^Author:[ \t]+\\([A-Za-z0-9_.+-]+@[A-Za-z0-9_.-]+\\)" + '(("^\\(?:Author\\|Commit\\):[ \t]+\\([A-Za-z0-9_.+-]+@[A-Za-z0-9_.-]+\\)" (1 'change-log-email)) ;; Handle the case: ;; user: FirstName LastName <foo@bar> - ("^Author:[ \t]+\\([^<(]+?\\)[ \t]*[(<]\\([A-Za-z0-9_.+-]+@[A-Za-z0-9_.-]+\\)[>)]" + ("^\\(?:Author\\|Commit\\):[ \t]+\\([^<(]+?\\)[ \t]*[(<]\\([A-Za-z0-9_.+-]+@[A-Za-z0-9_.-]+\\)[>)]" (1 'change-log-name) (2 'change-log-email)) ("^ +\\(?:\\(?:[Aa]cked\\|[Ss]igned-[Oo]ff\\)-[Bb]y:\\)[ \t]+\\([A-Za-z0-9_.+-]+@[A-Za-z0-9_.-]+\\)" @@ -1430,7 +1551,7 @@ log entries." ("^Merge: \\([0-9a-z]+\\) \\([0-9a-z]+\\)" (1 'change-log-acknowledgment) (2 'change-log-acknowledgment)) - ("^\\(?:Date: \\|AuthorDate: \\)\\(.+\\)" (1 'change-log-date)) + ("^\\(?:Date: \\|AuthorDate: \\|CommitDate: \\)\\(.+\\)" (1 'change-log-date)) ("^summary:[ \t]+\\(.+\\)" (1 'log-view-message))))))) @@ -1452,7 +1573,11 @@ or BRANCH^ (where \"^\" can be repeated)." (defun vc-git-expanded-log-entry (revision) (with-temp-buffer - (apply #'vc-git-command t nil nil (list "log" revision "-1" "--no-color" "--")) + (apply #'vc-git-command t nil nil + `("log" + ,revision + "-1" "--no-color" ,@(ensure-list vc-git-log-switches) + "--")) (goto-char (point-min)) (unless (eobp) ;; Indent the expanded log entry. @@ -1651,7 +1776,8 @@ This requires git 1.8.4 or later, for the \"-L\" option of \"git log\"." (if branchp "branch" "tag")))) (if branchp (vc-git-command nil 0 nil "checkout" "-b" name - (when (and start-point (not (eq start-point ""))) + (when (and start-point + (not (equal start-point ""))) start-point)) (vc-git-command nil 0 nil "tag" name))))) diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index a181765eac3..72160c35f57 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -3381,7 +3381,7 @@ If nil, no default will be used. This option may be set locally." (declare-function message--name-table "message" (orig-string)) (declare-function mml-attach-buffer "mml" - (buffer &optional type description disposition)) + (buffer &optional type description disposition filename)) (declare-function log-view-get-marked "log-view" ()) (defun vc-default-prepare-patch (_backend rev) @@ -3422,6 +3422,19 @@ of the current file." (and-let* ((file (buffer-file-name))) (vc-working-revision file))))) +(defun vc--subject-to-file-name (subject) + "Generate a file name for a patch with subject line SUBJECT." + (let* ((stripped + (replace-regexp-in-string "\\`\\[.*PATCH.*\\]\\s-*" "" + subject)) + (truncated (if (length> stripped 50) + (substring stripped 0 50) + stripped))) + (concat + (string-trim (replace-regexp-in-string "\\W" "-" truncated) + "-+" "-+") + ".patch"))) + ;;;###autoload (defun vc-prepare-patch (addressee subject revisions) "Compose an Email sending patches for REVISIONS to ADDRESSEE. @@ -3432,7 +3445,7 @@ revision, with SUBJECT derived from each revision subject. When invoked with a numerical prefix argument, use the last N revisions. When invoked interactively in a Log View buffer with -marked revisions, use those these." +marked revisions, use those." (interactive (let ((revs (vc-prepare-patch-prompt-revisions)) to) (require 'message) @@ -3478,11 +3491,17 @@ marked revisions, use those these." (rfc822-goto-eoh) (forward-line) (save-excursion - (dolist (patch patches) - (mml-attach-buffer (buffer-name (plist-get patch :buffer)) - "text/x-patch" - (plist-get patch :subject) - "attachment"))) + (let ((i 0)) + (dolist (patch patches) + (let* ((patch-subject (plist-get patch :subject)) + (filename + (vc--subject-to-file-name patch-subject))) + (mml-attach-buffer + (buffer-name (plist-get patch :buffer)) + "text/x-patch" + patch-subject + "attachment" + (format "%04d-%s" (cl-incf i) filename)))))) (open-line 2))))) (defun vc-default-responsible-p (_backend _file) @@ -3623,7 +3642,7 @@ it indicates a specific revision to check out." "Default `last-change' implementation. It returns the last revision that changed LINE number in FILE." (unless (file-exists-p file) - (signal 'file-error "File doesn't exist")) + (signal 'file-error '("File doesn't exist"))) (with-temp-buffer (vc-call-backend (vc-backend file) 'annotate-command file (current-buffer)) diff --git a/lisp/whitespace.el b/lisp/whitespace.el index 9995706a5da..86fc179396e 100644 --- a/lisp/whitespace.el +++ b/lisp/whitespace.el @@ -1014,34 +1014,11 @@ See also `whitespace-newline' and `whitespace-display-mappings'." ;;;###autoload -(define-minor-mode global-whitespace-mode - "Toggle whitespace visualization globally (Global Whitespace mode). - -See also `whitespace-style', `whitespace-newline' and -`whitespace-display-mappings'." - :lighter " WS" +(define-globalized-minor-mode global-whitespace-mode + whitespace-mode + whitespace-turn-on-if-enabled :init-value nil - :global t - :group 'whitespace - (cond - (noninteractive ; running a batch job - (setq global-whitespace-mode nil)) - (global-whitespace-mode ; global-whitespace-mode on - (save-current-buffer - (add-hook 'find-file-hook 'whitespace-turn-on-if-enabled) - (add-hook 'after-change-major-mode-hook 'whitespace-turn-on-if-enabled) - (dolist (buffer (buffer-list)) ; adjust all local mode - (set-buffer buffer) - (unless whitespace-mode - (whitespace-turn-on-if-enabled))))) - (t ; global-whitespace-mode off - (save-current-buffer - (remove-hook 'find-file-hook 'whitespace-turn-on-if-enabled) - (remove-hook 'after-change-major-mode-hook 'whitespace-turn-on-if-enabled) - (dolist (buffer (buffer-list)) ; adjust all local mode - (set-buffer buffer) - (unless whitespace-mode - (whitespace-turn-off))))))) + :group 'whitespace) (defvar whitespace-enable-predicate (lambda () @@ -1067,7 +1044,7 @@ This variable is normally modified via `add-function'.") (defun whitespace-turn-on-if-enabled () (when (funcall whitespace-enable-predicate) - (whitespace-turn-on))) + (whitespace-mode))) ;;;###autoload (define-minor-mode global-whitespace-newline-mode @@ -2511,7 +2488,7 @@ purposes)." (setq whitespace-display-table-was-local t) ;; Save the old table so we can restore it when ;; `whitespace-mode' is switched off again. - (when (or whitespace-mode global-whitespace-mode) + (when whitespace-mode (setq whitespace-display-table (copy-sequence buffer-display-table))) ;; Assure `buffer-display-table' is unique diff --git a/m4/acl.m4 b/m4/acl.m4 index 98362858ce5..dc9853a156d 100644 --- a/m4/acl.m4 +++ b/m4/acl.m4 @@ -1,5 +1,5 @@ # acl.m4 - check for access control list (ACL) primitives -# serial 24 +# serial 27 # Copyright (C) 2002, 2004-2023 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation @@ -17,7 +17,7 @@ AC_DEFUN([gl_FUNC_ACL_ARG], ]) -AC_DEFUN([gl_FUNC_ACL], +AC_DEFUN_ONCE([gl_FUNC_ACL], [ AC_REQUIRE([gl_FUNC_ACL_ARG]) AC_CHECK_FUNCS_ONCE([fchmod]) @@ -139,7 +139,9 @@ int type = ACL_TYPE_EXTENDED;]])], AC_MSG_WARN([AC_PACKAGE_NAME will be built without ACL support.]) fi fi - test -n "$gl_need_lib_has_acl" && LIB_HAS_ACL=$LIB_ACL + if test -n "$gl_need_lib_has_acl"; then + FILE_HAS_ACL_LIB=$LIB_ACL + fi AC_SUBST([LIB_ACL]) AC_DEFINE_UNQUOTED([USE_ACL], [$use_acl], [Define to nonzero if you want access control list support.]) @@ -197,15 +199,15 @@ AC_DEFUN([gl_FILE_HAS_ACL], [gl_cv_getxattr_with_posix_acls=yes])]) fi if test "$gl_cv_getxattr_with_posix_acls" = yes; then - LIB_HAS_ACL= + FILE_HAS_ACL_LIB= AC_DEFINE([GETXATTR_WITH_POSIX_ACLS], 1, [Define to 1 if getxattr works with XATTR_NAME_POSIX_ACL_ACCESS and XATTR_NAME_POSIX_ACL_DEFAULT.]) else dnl Set gl_need_lib_has_acl to a nonempty value, so that any - dnl later gl_FUNC_ACL call will set LIB_HAS_ACL=$LIB_ACL. + dnl later gl_FUNC_ACL call will set FILE_HAS_ACL_LIB=$LIB_ACL. gl_need_lib_has_acl=1 - LIB_HAS_ACL=$LIB_ACL + FILE_HAS_ACL_LIB=$LIB_ACL fi - AC_SUBST([LIB_HAS_ACL]) + AC_SUBST([FILE_HAS_ACL_LIB]) ]) diff --git a/m4/alloca.m4 b/m4/alloca.m4 index 75851875910..c685fac918a 100644 --- a/m4/alloca.m4 +++ b/m4/alloca.m4 @@ -1,6 +1,6 @@ # alloca.m4 serial 21 -dnl Copyright (C) 2002-2004, 2006-2007, 2009-2023 Free Software -dnl Foundation, Inc. +dnl Copyright (C) 2002-2004, 2006-2007, 2009-2023 Free Software Foundation, +dnl Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. diff --git a/m4/assert_h.m4 b/m4/assert_h.m4 index 6275f633a69..3801452ef0d 100644 --- a/m4/assert_h.m4 +++ b/m4/assert_h.m4 @@ -18,7 +18,7 @@ AC_DEFUN([gl_ASSERT_H], [AC_LANG_PROGRAM( [[#if defined __clang__ && __STDC_VERSION__ < 202311 #pragma clang diagnostic error "-Wc2x-extensions" - #pragma clang diagnostic error "-Wc++17-extensions" + #pragma clang diagnostic error "-Wc++1z-extensions" #endif #ifdef INCLUDE_ASSERT_H #include <assert.h> @@ -60,7 +60,7 @@ AC_DEFUN([gl_ASSERT_H], /* Solaris 11.4 <assert.h> defines static_assert as a macro with 2 arguments. We need it also to be invocable with a single argument. */ #if defined __sun && (__STDC_VERSION__ - 0 >= 201112L) && !defined __cplusplus - #undef static_assert + #undef/**/static_assert #define static_assert _Static_assert #endif #endif]) diff --git a/m4/clock_time.m4 b/m4/clock_time.m4 index 411e0710e7f..d624a73d35d 100644 --- a/m4/clock_time.m4 +++ b/m4/clock_time.m4 @@ -1,14 +1,14 @@ -# clock_time.m4 serial 11 +# clock_time.m4 serial 12 dnl Copyright (C) 2002-2006, 2009-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. # Check for clock_getres, clock_gettime and clock_settime, -# and set LIB_CLOCK_GETTIME. +# and set CLOCK_TIME_LIB. # For a program named, say foo, you should add a line like the following # in the corresponding Makefile.am file: -# foo_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) +# foo_LDADD = $(LDADD) $(CLOCK_TIME_LIB) AC_DEFUN([gl_CLOCK_TIME], [ @@ -21,12 +21,15 @@ AC_DEFUN([gl_CLOCK_TIME], # Save and restore LIBS so e.g., -lrt, isn't added to it. Otherwise, *all* # programs in the package would end up linked with that potentially-shared # library, inducing unnecessary run-time overhead. - LIB_CLOCK_GETTIME= - AC_SUBST([LIB_CLOCK_GETTIME]) + CLOCK_TIME_LIB= + AC_SUBST([CLOCK_TIME_LIB]) gl_saved_libs=$LIBS AC_SEARCH_LIBS([clock_gettime], [rt posix4], [test "$ac_cv_search_clock_gettime" = "none required" || - LIB_CLOCK_GETTIME=$ac_cv_search_clock_gettime]) + CLOCK_TIME_LIB=$ac_cv_search_clock_gettime]) AC_CHECK_FUNCS([clock_getres clock_gettime clock_settime]) LIBS=$gl_saved_libs + # For backward compatibility. + LIB_CLOCK_GETTIME="$CLOCK_TIME_LIB" + AC_SUBST([LIB_CLOCK_GETTIME]) ]) diff --git a/m4/d-type.m4 b/m4/d-type.m4 index 05eb8ac0cfa..3f63bbe78ee 100644 --- a/m4/d-type.m4 +++ b/m4/d-type.m4 @@ -5,8 +5,7 @@ dnl dnl Check whether struct dirent has a member named d_type. dnl -# Copyright (C) 1997, 1999-2004, 2006, 2009-2023 Free Software -# Foundation, Inc. +# Copyright (C) 1997, 1999-2004, 2006, 2009-2023 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/m4/dup2.m4 b/m4/dup2.m4 index 8a040d4c369..e1cc73e18db 100644 --- a/m4/dup2.m4 +++ b/m4/dup2.m4 @@ -1,6 +1,5 @@ #serial 27 -dnl Copyright (C) 2002, 2005, 2007, 2009-2023 Free Software Foundation, -dnl Inc. +dnl Copyright (C) 2002, 2005, 2007, 2009-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. diff --git a/m4/euidaccess.m4 b/m4/euidaccess.m4 index 0dc757820ee..f0eb5bde84a 100644 --- a/m4/euidaccess.m4 +++ b/m4/euidaccess.m4 @@ -1,4 +1,4 @@ -# euidaccess.m4 serial 15 +# euidaccess.m4 serial 16 dnl Copyright (C) 2002-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -41,12 +41,15 @@ AC_DEFUN([gl_PREREQ_EUIDACCESS], [ # Save and restore LIBS so -lgen isn't added to it. Otherwise, *all* # programs in the package would end up linked with that potentially-shared # library, inducing unnecessary run-time overhead. - LIB_EACCESS= - AC_SUBST([LIB_EACCESS]) + EUIDACCESS_LIBGEN= + AC_SUBST([EUIDACCESS_LIBGEN]) gl_saved_libs=$LIBS AC_SEARCH_LIBS([eaccess], [gen], [test "$ac_cv_search_eaccess" = "none required" || - LIB_EACCESS=$ac_cv_search_eaccess]) + EUIDACCESS_LIBGEN=$ac_cv_search_eaccess]) AC_CHECK_FUNCS([eaccess]) LIBS=$gl_saved_libs + # For backward compatibility. + LIB_EACCESS="$EUIDACCESS_LIBGEN" + AC_SUBST([LIB_EACCESS]) ]) diff --git a/m4/extensions.m4 b/m4/extensions.m4 index 6596e7efc06..5336b8daf7e 100644 --- a/m4/extensions.m4 +++ b/m4/extensions.m4 @@ -1,4 +1,4 @@ -# serial 22 -*- Autoconf -*- +# serial 23 -*- Autoconf -*- # Enable extensions on systems that normally disable them. # Copyright (C) 2003, 2006-2023 Free Software Foundation, Inc. @@ -31,7 +31,7 @@ m4_ifndef([AC_CHECK_INCLUDES_DEFAULT], # its dependencies. This will ensure that the gl_USE_SYSTEM_EXTENSIONS # invocation occurs in gl_EARLY, not in gl_INIT. -m4_version_prereq([2.70.1], [], [ +m4_version_prereq([2.72], [], [ # AC_USE_SYSTEM_EXTENSIONS # ------------------------ @@ -113,11 +113,15 @@ AH_VERBATIM([USE_SYSTEM_EXTENSIONS], #ifndef __STDC_WANT_IEC_60559_DFP_EXT__ # undef __STDC_WANT_IEC_60559_DFP_EXT__ #endif +/* Enable extensions specified by C23 Annex F. */ +#ifndef __STDC_WANT_IEC_60559_EXT__ +# undef __STDC_WANT_IEC_60559_EXT__ +#endif /* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ #ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ # undef __STDC_WANT_IEC_60559_FUNCS_EXT__ #endif -/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ +/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ # undef __STDC_WANT_IEC_60559_TYPES_EXT__ #endif @@ -187,6 +191,7 @@ dnl it should only be defined when necessary. AC_DEFINE([__STDC_WANT_IEC_60559_ATTRIBS_EXT__]) AC_DEFINE([__STDC_WANT_IEC_60559_BFP_EXT__]) AC_DEFINE([__STDC_WANT_IEC_60559_DFP_EXT__]) + AC_DEFINE([__STDC_WANT_IEC_60559_EXT__]) AC_DEFINE([__STDC_WANT_IEC_60559_FUNCS_EXT__]) AC_DEFINE([__STDC_WANT_IEC_60559_TYPES_EXT__]) AC_DEFINE([__STDC_WANT_LIB_EXT2__]) diff --git a/m4/filemode.m4 b/m4/filemode.m4 index 2fcc69d119b..3cafc5cd1e1 100644 --- a/m4/filemode.m4 +++ b/m4/filemode.m4 @@ -1,6 +1,5 @@ # filemode.m4 serial 9 -dnl Copyright (C) 2002, 2005-2006, 2009-2023 Free Software Foundation, -dnl Inc. +dnl Copyright (C) 2002, 2005-2006, 2009-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. diff --git a/m4/fsusage.m4 b/m4/fsusage.m4 index aeb3467a272..88f3ca817cb 100644 --- a/m4/fsusage.m4 +++ b/m4/fsusage.m4 @@ -1,8 +1,7 @@ # serial 35 # Obtaining file system usage information. -# Copyright (C) 1997-1998, 2000-2001, 2003-2023 Free Software -# Foundation, Inc. +# Copyright (C) 1997-1998, 2000-2001, 2003-2023 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/m4/getgroups.m4 b/m4/getgroups.m4 index d5a18ea88b0..241fec88e3c 100644 --- a/m4/getgroups.m4 +++ b/m4/getgroups.m4 @@ -3,8 +3,7 @@ dnl From Jim Meyering. dnl A wrapper around AC_FUNC_GETGROUPS. -# Copyright (C) 1996-1997, 1999-2004, 2008-2023 Free Software -# Foundation, Inc. +# Copyright (C) 1996-1997, 1999-2004, 2008-2023 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/m4/getloadavg.m4 b/m4/getloadavg.m4 index 7097e5dd512..79e420baae8 100644 --- a/m4/getloadavg.m4 +++ b/m4/getloadavg.m4 @@ -1,7 +1,7 @@ # Check for getloadavg. -# Copyright (C) 1992-1996, 1999-2000, 2002-2003, 2006, 2008-2023 Free -# Software Foundation, Inc. +# Copyright (C) 1992-1996, 1999-2000, 2002-2003, 2006, 2008-2023 Free Software +# Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/m4/getrandom.m4 b/m4/getrandom.m4 index 95111567d79..c508f1a55c3 100644 --- a/m4/getrandom.m4 +++ b/m4/getrandom.m4 @@ -1,4 +1,4 @@ -# getrandom.m4 serial 8 +# getrandom.m4 serial 10 dnl Copyright 2020-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -9,7 +9,13 @@ dnl Written by Paul Eggert. AC_DEFUN([gl_FUNC_GETRANDOM], [ AC_REQUIRE([gl_SYS_RANDOM_H_DEFAULTS]) - AC_CHECK_FUNCS_ONCE([getrandom]) + gl_CHECK_FUNCS_ANDROID([getrandom], + [[/* Additional includes are needed before <sys/random.h> on uClibc + and Mac OS X. */ + #include <sys/types.h> + #include <stdlib.h> + #include <sys/random.h> + ]]) if test "$ac_cv_func_getrandom" != yes; then HAVE_GETRANDOM=0 else @@ -56,13 +62,16 @@ AC_DEFUN([gl_FUNC_GETRANDOM], if test $gl_cv_lib_assume_bcrypt = yes; then AC_DEFINE([HAVE_LIB_BCRYPT], [1], [Define to 1 if the bcrypt library is guaranteed to be present.]) - LIB_GETRANDOM='-lbcrypt' + GETRANDOM_LIB='-lbcrypt' else - LIB_GETRANDOM='-ladvapi32' + GETRANDOM_LIB='-ladvapi32' fi ;; *) - LIB_GETRANDOM= ;; + GETRANDOM_LIB= ;; esac + AC_SUBST([GETRANDOM_LIB]) + dnl For backward compatibility. + LIB_GETRANDOM="$GETRANDOM_LIB" AC_SUBST([LIB_GETRANDOM]) ]) diff --git a/m4/gettime.m4 b/m4/gettime.m4 index 39067be6fa8..7e353fcd00e 100644 --- a/m4/gettime.m4 +++ b/m4/gettime.m4 @@ -1,6 +1,5 @@ -# gettime.m4 serial 12 -dnl Copyright (C) 2002, 2004-2006, 2009-2023 Free Software Foundation, -dnl Inc. +# gettime.m4 serial 13 +dnl Copyright (C) 2002, 2004-2006, 2009-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. @@ -27,17 +26,24 @@ AC_DEFUN([gl_CHECK_FUNC_TIMESPEC_GET], dnl We can't use AC_CHECK_FUNC here, because timespec_get() is defined as a dnl static inline function in <time.h> on MSVC 14. - AC_CACHE_CHECK([for timespec_get], [gl_cv_func_timespec_get], - [AC_LINK_IFELSE( - [AC_LANG_PROGRAM( - [[#include <time.h> - struct timespec ts; - ]], - [[return timespec_get (&ts, 0);]]) - ], - [gl_cv_func_timespec_get=yes], - [gl_cv_func_timespec_get=no]) - ]) + dnl But at the same time, we need to notice a missing declaration, like + dnl gl_CHECK_FUNCS_ANDROID does. + AC_CHECK_DECL([timespec_get], , , [[#include <time.h>]]) + if test $ac_cv_have_decl_timespec_get = yes; then + AC_CACHE_CHECK([for timespec_get], [gl_cv_func_timespec_get], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[#include <time.h> + struct timespec ts; + ]], + [[return timespec_get (&ts, 0);]]) + ], + [gl_cv_func_timespec_get=yes], + [gl_cv_func_timespec_get=no]) + ]) + else + gl_cv_func_timespec_get=no + fi ]) AC_DEFUN([gl_GETTIME_RES], diff --git a/m4/gettimeofday.m4 b/m4/gettimeofday.m4 index 66231e0174f..5051d61cc87 100644 --- a/m4/gettimeofday.m4 +++ b/m4/gettimeofday.m4 @@ -1,7 +1,6 @@ # serial 29 -# Copyright (C) 2001-2003, 2005, 2007, 2009-2023 Free Software -# Foundation, Inc. +# Copyright (C) 2001-2003, 2005, 2007, 2009-2023 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. diff --git a/m4/gnulib-common.m4 b/m4/gnulib-common.m4 index 70e9105bee1..2db3376b01e 100644 --- a/m4/gnulib-common.m4 +++ b/m4/gnulib-common.m4 @@ -1,4 +1,4 @@ -# gnulib-common.m4 serial 74 +# gnulib-common.m4 serial 76 dnl Copyright (C) 2007-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -71,7 +71,7 @@ AC_DEFUN([gl_COMMON_BODY], [ && (!defined __clang_minor__ \ || (defined __apple_build_version__ \ ? 6000000 <= __apple_build_version__ \ - : 3 < __clang_major__ + (5 <= __clang_minor__)))) + : 5 <= __clang_major__))) # define _GL_HAS_ATTRIBUTE(attr) __has_attribute (__##attr##__) #else # define _GL_HAS_ATTRIBUTE(attr) _GL_ATTR_##attr @@ -105,14 +105,10 @@ AC_DEFUN([gl_COMMON_BODY], [ # define _GL_ATTR_warn_unused_result _GL_GNUC_PREREQ (3, 4) #endif -#ifdef __has_c_attribute -# if ((defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) <= 201710 \ - && _GL_GNUC_PREREQ (4, 6)) -# pragma GCC diagnostic ignored "-Wpedantic" -# endif -# define _GL_HAS_C_ATTRIBUTE(attr) __has_c_attribute (__##attr##__) -#else -# define _GL_HAS_C_ATTRIBUTE(attr) 0 +/* Disable GCC -Wpedantic if using __has_c_attribute and this is not C23+. */ +#if (defined __has_c_attribute && _GL_GNUC_PREREQ (4, 6) \ + && (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) <= 201710) +# pragma GCC diagnostic ignored "-Wpedantic" #endif ]dnl There is no _GL_ATTRIBUTE_ALIGNED; use stdalign's alignas instead. @@ -191,7 +187,14 @@ AC_DEFUN([gl_COMMON_BODY], [ to use this earlier definition, since <stdlib.h> may not have been included yet. */ #ifndef _GL_ATTRIBUTE_DEALLOC_FREE -# define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (free, 1) +# if defined __cplusplus && defined __GNUC__ && !defined __clang__ +/* Work around GCC bug <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108231> */ +# define _GL_ATTRIBUTE_DEALLOC_FREE \ + _GL_ATTRIBUTE_DEALLOC ((void (*) (void *)) free, 1) +# else +# define _GL_ATTRIBUTE_DEALLOC_FREE \ + _GL_ATTRIBUTE_DEALLOC (free, 1) +# endif #endif /* _GL_ATTRIBUTE_DEPRECATED: Declares that an entity is deprecated. @@ -202,11 +205,15 @@ AC_DEFUN([gl_COMMON_BODY], [ - enumeration, enumeration item, - typedef, in C++ also: namespace, class, template specialization. */ -#if _GL_HAS_C_ATTRIBUTE (deprecated) -# define _GL_ATTRIBUTE_DEPRECATED [[__deprecated__]] -#elif _GL_HAS_ATTRIBUTE (deprecated) +#ifdef __has_c_attribute +# if __has_c_attribute (__deprecated__) +# define _GL_ATTRIBUTE_DEPRECATED [[__deprecated__]] +# endif +#endif +#if !defined _GL_ATTRIBUTE_DEPRECATED && _GL_HAS_ATTRIBUTE (deprecated) # define _GL_ATTRIBUTE_DEPRECATED __attribute__ ((__deprecated__)) -#else +#endif +#ifndef _GL_ATTRIBUTE_DEPRECATED # define _GL_ATTRIBUTE_DEPRECATED #endif @@ -240,11 +247,15 @@ AC_DEFUN([gl_COMMON_BODY], [ 'default' label. The compiler should not warn in this case. */ /* Applies to: Empty statement (;), inside a 'switch' statement. */ /* Always expands to something. */ -#if _GL_HAS_C_ATTRIBUTE (fallthrough) -# define _GL_ATTRIBUTE_FALLTHROUGH [[__fallthrough__]] -#elif _GL_HAS_ATTRIBUTE (fallthrough) +#ifdef __has_c_attribute +# if __has_c_attribute (__fallthrough__) +# define _GL_ATTRIBUTE_FALLTHROUGH [[__fallthrough__]] +# endif +#endif +#if !defined _GL_ATTRIBUTE_FALLTHROUGH && _GL_HAS_ATTRIBUTE (fallthrough) # define _GL_ATTRIBUTE_FALLTHROUGH __attribute__ ((__fallthrough__)) -#else +#endif +#ifndef _GL_ATTRIBUTE_FALLTHROUGH # define _GL_ATTRIBUTE_FALLTHROUGH ((void) 0) #endif @@ -305,12 +316,15 @@ AC_DEFUN([gl_COMMON_BODY], [ - enumeration, enumeration item, - typedef, in C++ also: class. */ -/* In C++ and C2x, this is spelled [[__maybe_unused__]]. +/* In C++ and C23, this is spelled [[__maybe_unused__]]. GCC's syntax is __attribute__ ((__unused__)). clang supports both syntaxes. */ -#if _GL_HAS_C_ATTRIBUTE (maybe_unused) -# define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]] -#else +#ifdef __has_c_attribute +# if __has_c_attribute (__maybe_unused__) +# define _GL_ATTRIBUTE_MAYBE_UNUSED [[__maybe_unused__]] +# endif +#endif +#ifndef _GL_ATTRIBUTE_MAYBE_UNUSED # define _GL_ATTRIBUTE_MAYBE_UNUSED _GL_ATTRIBUTE_UNUSED #endif /* Alternative spelling of this macro, for convenience and for @@ -323,11 +337,15 @@ AC_DEFUN([gl_COMMON_BODY], [ discard the return value. The compiler may warn if the caller does not use the return value, unless the caller uses something like ignore_value. */ /* Applies to: function, enumeration, class. */ -#if _GL_HAS_C_ATTRIBUTE (nodiscard) -# define _GL_ATTRIBUTE_NODISCARD [[__nodiscard__]] -#elif _GL_HAS_ATTRIBUTE (warn_unused_result) +#ifdef __has_c_attribute +# if __has_c_attribute (__nodiscard__) +# define _GL_ATTRIBUTE_NODISCARD [[__nodiscard__]] +# endif +#endif +#if !defined _GL_ATTRIBUTE_NODISCARD && _GL_HAS_ATTRIBUTE (warn_unused_result) # define _GL_ATTRIBUTE_NODISCARD __attribute__ ((__warn_unused_result__)) -#else +#endif +#ifndef _GL_ATTRIBUTE_NODISCARD # define _GL_ATTRIBUTE_NODISCARD #endif @@ -1005,6 +1023,30 @@ AC_DEFUN([gl_CONDITIONAL_HEADER], m4_popdef([gl_header_name]) ]) +dnl gl_CHECK_FUNCS_ANDROID([func], [[#include <foo.h>]]) +dnl is like AC_CHECK_FUNCS([func]), taking into account a portability problem +dnl on Android. +dnl Namely, if func was added to Android API level, say, 28, then the libc.so +dnl has the symbol func always, whereas the header file <foo.h> declares func +dnl conditionally: +dnl #if __ANDROID_API__ >= 28 +dnl ... func (...) __INTRODUCED_IN(28); +dnl #endif +dnl Thus, when compiling with "clang -target armv7a-unknown-linux-android28", +dnl the function func is declared and exists in libc. +dnl Whereas when compiling with "clang -target armv7a-unknown-linux-android27", +dnl the function func is not declared but exists in libc. We need to treat this +dnl case like the case where func does not exist. +AC_DEFUN([gl_CHECK_FUNCS_ANDROID], +[ + AC_CHECK_DECL([$1], , , [$2]) + if test $ac_cv_have_decl_[$1] = yes; then + AC_CHECK_FUNCS([$1]) + else + ac_cv_func_[$1]=no + fi +]) + dnl Expands to some code for use in .c programs that, on native Windows, defines dnl the Microsoft deprecated alias function names to the underscore-prefixed dnl actual function names. With this macro, these function names are available diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index e03946c94ca..10c74fa2392 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 @@ -82,7 +82,6 @@ AC_DEFUN([gl_EARLY], # Code from module errno: # Code from module euidaccess: # Code from module execinfo: - # Code from module explicit_bzero: # Code from module extensions: # Code from module extern-inline: # Code from module faccessat: @@ -124,7 +123,6 @@ AC_DEFUN([gl_EARLY], # Code from module intprops: # Code from module inttypes-incomplete: # Code from module largefile: - AC_REQUIRE([gl_YEAR2038_EARLY]) AC_REQUIRE([AC_SYS_LARGEFILE]) # Code from module lchmod: # Code from module libc-config: @@ -137,6 +135,7 @@ AC_DEFUN([gl_EARLY], # Code from module memmem-simple: # Code from module mempcpy: # Code from module memrchr: + # Code from module memset_explicit: # Code from module minmax: # Code from module mkostemp: # Code from module mktime: @@ -285,12 +284,6 @@ AC_DEFUN([gl_INIT], gl_CONDITIONAL_HEADER([execinfo.h]) AC_PROG_MKDIR_P gl_CONDITIONAL([GL_COND_OBJ_EXECINFO], [$GL_GENERATE_EXECINFO_H]) - gl_FUNC_EXPLICIT_BZERO - gl_CONDITIONAL([GL_COND_OBJ_EXPLICIT_BZERO], [test $HAVE_EXPLICIT_BZERO = 0]) - AM_COND_IF([GL_COND_OBJ_EXPLICIT_BZERO], [ - gl_PREREQ_EXPLICIT_BZERO - ]) - gl_STRING_MODULE_INDICATOR([explicit_bzero]) AC_REQUIRE([gl_EXTERN_INLINE]) gl_FUNC_FACCESSAT gl_CONDITIONAL([GL_COND_OBJ_FACCESSAT], @@ -422,6 +415,12 @@ AC_DEFUN([gl_INIT], gl_PREREQ_MEMRCHR ]) gl_STRING_MODULE_INDICATOR([memrchr]) + gl_FUNC_MEMSET_EXPLICIT + gl_CONDITIONAL([GL_COND_OBJ_MEMSET_EXPLICIT], [test $HAVE_MEMSET_EXPLICIT = 0]) + AM_COND_IF([GL_COND_OBJ_MEMSET_EXPLICIT], [ + gl_PREREQ_MEMSET_EXPLICIT + ]) + gl_STRING_MODULE_INDICATOR([memset_explicit]) gl_MINMAX gl_FUNC_MKOSTEMP gl_CONDITIONAL([GL_COND_OBJ_MKOSTEMP], [test $HAVE_MKOSTEMP = 0]) @@ -457,6 +456,14 @@ AC_DEFUN([gl_INIT], gl_PREREQ_PTHREAD_SIGMASK ]) gl_SIGNAL_MODULE_INDICATOR([pthread_sigmask]) + gl_FUNC_XATTR + AC_REQUIRE([gl_FUNC_ACL]) + if test "$use_xattr" = yes; then + QCOPY_ACL_LIB="$LIB_XATTR" + else + QCOPY_ACL_LIB="$LIB_ACL" + fi + AC_SUBST([QCOPY_ACL_LIB]) gl_FUNC_READLINK gl_CONDITIONAL([GL_COND_OBJ_READLINK], [test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1]) @@ -1248,7 +1255,6 @@ AC_DEFUN([gl_FILE_LIST], [ lib/euidaccess.c lib/execinfo.c lib/execinfo.in.h - lib/explicit_bzero.c lib/faccessat.c lib/fchmodat.c lib/fcntl.c @@ -1318,6 +1324,7 @@ AC_DEFUN([gl_FILE_LIST], [ lib/memmem.c lib/mempcpy.c lib/memrchr.c + lib/memset_explicit.c lib/mini-gmp-gnulib.c lib/mini-gmp.c lib/mini-gmp.h @@ -1432,7 +1439,6 @@ AC_DEFUN([gl_FILE_LIST], [ m4/errno_h.m4 m4/euidaccess.m4 m4/execinfo.m4 - m4/explicit_bzero.m4 m4/extensions.m4 m4/extern-inline.m4 m4/faccessat.m4 @@ -1476,6 +1482,7 @@ AC_DEFUN([gl_FILE_LIST], [ m4/memmem.m4 m4/mempcpy.m4 m4/memrchr.m4 + m4/memset_explicit.m4 m4/minmax.m4 m4/mkostemp.m4 m4/mktime.m4 @@ -1544,6 +1551,6 @@ AC_DEFUN([gl_FILE_LIST], [ m4/warnings.m4 m4/wchar_t.m4 m4/wint_t.m4 - m4/year2038.m4 + m4/xattr.m4 m4/zzgnulib.m4 ]) diff --git a/m4/group-member.m4 b/m4/group-member.m4 index 6e860c6189d..7c56ee3de7d 100644 --- a/m4/group-member.m4 +++ b/m4/group-member.m4 @@ -1,7 +1,6 @@ # serial 14 -# Copyright (C) 1999-2001, 2003-2007, 2009-2023 Free Software -# Foundation, Inc. +# Copyright (C) 1999-2001, 2003-2007, 2009-2023 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/m4/largefile.m4 b/m4/largefile.m4 index bc8a2b93534..7fb81b864af 100644 --- a/m4/largefile.m4 +++ b/m4/largefile.m4 @@ -12,8 +12,7 @@ # and ftello in C++ mode as well. # Fixed in Autoconf 2.72, which has AC_SYS_YEAR2038. AC_DEFUN([gl_SET_LARGEFILE_SOURCE], -[ - m4_ifndef([AC_SYS_YEAR2038], [ + m4_ifndef([AC_SYS_YEAR2038], [[ AC_REQUIRE([AC_CANONICAL_HOST]) AC_FUNC_FSEEKO case "$host_os" in @@ -22,11 +21,10 @@ AC_DEFUN([gl_SET_LARGEFILE_SOURCE], [Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2).]) ;; esac - ]) -]) + ]]) +) -# Work around a problem in Autoconf through 2.71 on glibc 2.34+ -# with _TIME_BITS. Also, work around a problem in autoconf <= 2.69: +# Work around a problem in autoconf <= 2.69: # AC_SYS_LARGEFILE does not configure for large inodes on Mac OS X 10.5, # or configures them incorrectly in some cases. m4_version_prereq([2.70], [], [ @@ -46,34 +44,258 @@ m4_define([_AC_SYS_LARGEFILE_TEST_INCLUDES], ]) ])# m4_version_prereq 2.70 +# Support AC_SYS_YEAR2038, even if Autoconf 2.71 or earlier. +# This code is taken from Autoconf master. m4_ifndef([AC_SYS_YEAR2038], [ -# _AC_SYS_LARGEFILE_MACRO_VALUE(C-MACRO, VALUE, -# CACHE-VAR, -# DESCRIPTION, -# PROLOGUE, [FUNCTION-BODY]) -# -------------------------------------------------------- -m4_define([_AC_SYS_LARGEFILE_MACRO_VALUE], -[AC_CACHE_CHECK([for $1 value needed for large files], [$3], -[while :; do - m4_ifval([$6], [AC_LINK_IFELSE], [AC_COMPILE_IFELSE])( - [AC_LANG_PROGRAM([$5], [$6])], - [$3=no; break]) - m4_ifval([$6], [AC_LINK_IFELSE], [AC_COMPILE_IFELSE])( - [AC_LANG_PROGRAM([#undef $1 -#define $1 $2 -$5], [$6])], - [$3=$2; break]) - $3=unknown - break -done]) -case $$3 in #( - no | unknown) ;; - *) AC_DEFINE_UNQUOTED([$1], [$$3], [$4]);; -esac -rm -rf conftest*[]dnl -])# _AC_SYS_LARGEFILE_MACRO_VALUE +# _AC_SYS_YEAR2038_TEST_CODE +# -------------------------- +# C code used to probe for time_t that can represent time points more +# than 2**31 - 1 seconds after the epoch. With the usual Unix epoch, +# these correspond to dates after 2038-01-18 22:14:07 +0000 (Gregorian), +# hence the name. +AC_DEFUN([_AC_SYS_YEAR2038_TEST_CODE], +[[ + #include <time.h> + /* Check that time_t can represent 2**32 - 1 correctly. */ + #define LARGE_TIME_T \\ + ((time_t) (((time_t) 1 << 30) - 1 + 3 * ((time_t) 1 << 30))) + int verify_time_t_range[(LARGE_TIME_T / 65537 == 65535 + && LARGE_TIME_T % 65537 == 0) + ? 1 : -1]; +]]) + +# _AC_SYS_YEAR2038_OPTIONS +# ------------------------ +# List of known ways to enable support for large time_t. If you change +# this list you probably also need to change the AS_CASE at the end of +# _AC_SYS_YEAR2038_PROBE. +m4_define([_AC_SYS_YEAR2038_OPTIONS], m4_normalize( + ["none needed"] dnl 64-bit and newer 32-bit Unix + ["-D_TIME_BITS=64"] dnl glibc 2.34 with some 32-bit ABIs + ["-D__MINGW_USE_VC2005_COMPAT"] dnl 32-bit MinGW + ["-U_USE_32_BIT_TIME_T -D__MINGW_USE_VC2005_COMPAT"] + dnl 32-bit MinGW (misconfiguration) +)) + +# _AC_SYS_YEAR2038_PROBE([IF-NOT-DETECTED]) +# ----------------------------------------- +# Subroutine of AC_SYS_YEAR2038. Probe for time_t that can represent +# time points more than 2**31 - 1 seconds after the epoch (dates after +# 2038-01-18, see above) and set the cache variable ac_cv_sys_year2038_opts +# to one of the values in the _AC_SYS_YEAR2038_OPTIONS list, or to +# "support not detected" if none of them worked. Then, set compilation +# options and #defines as necessary to enable large time_t support. +# +# Note that we do not test whether mktime, localtime, etc. handle +# large values of time_t correctly, as that would require use of +# AC_TRY_RUN. Note also that some systems only support large time_t +# together with large off_t. +# +# If support is not detected, the behavior depends on which of the +# top-level AC_SYS_YEAR2038 macros was used (see below). +# +# If you change this macro you may also need to change +# _AC_SYS_YEAR2038_OPTIONS. +AC_DEFUN([_AC_SYS_YEAR2038_PROBE], +[AC_CACHE_CHECK([for $CC option to enable timestamps after Jan 2038], + [ac_cv_sys_year2038_opts], + [ac_save_CPPFLAGS="$CPPFLAGS" + ac_opt_found=no + for ac_opt in _AC_SYS_YEAR2038_OPTIONS; do + AS_IF([test x"$ac_opt" != x"none needed"], + [CPPFLAGS="$ac_save_CPPFLAGS $ac_opt"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([_AC_SYS_YEAR2038_TEST_CODE])], + [ac_cv_sys_year2038_opts="$ac_opt" + ac_opt_found=yes]) + test $ac_opt_found = no || break + done + CPPFLAGS="$ac_save_CPPFLAGS" + test $ac_opt_found = yes || ac_cv_sys_year2038_opts="support not detected"]) + +ac_have_year2038=yes +AS_CASE([$ac_cv_sys_year2038_opts], + ["none needed"], [], + ["support not detected"], + [ac_have_year2038=no + AS_CASE([$enable_year2038], + [yes], + [# If we're not cross compiling and 'touch' works with a large + # timestamp, then we can presume the system supports wider time_t + # *somehow* and we just weren't able to detect it. One common + # case that we deliberately *don't* probe for is a system that + # supports both 32- and 64-bit ABIs but only the 64-bit ABI offers + # wide time_t. (It would be inappropriate for us to override an + # intentional use of -m32.) Error out, demanding use of + # --disable-year2038 if this is intentional. + AS_IF([test $cross_compiling = no], + [AS_IF([TZ=UTC0 touch -t 210602070628.15 conftest.time 2>/dev/null], + [AS_CASE([`TZ=UTC0 LC_ALL=C ls -l conftest.time 2>/dev/null`], + [*'Feb 7 2106'* | *'Feb 7 17:10'*], + [AC_MSG_FAILURE(m4_text_wrap( + [this system appears to support timestamps after January 2038, + but no mechanism for enabling wide 'time_t' was detected. + Did you mean to build a 64-bit binary? (e.g. 'CC="${CC} -m64"'.) + To proceed with 32-bit time_t, configure with '--disable-year2038'.], + [], [], [55]))])])])])], + + ["-D_TIME_BITS=64"], + [AC_DEFINE([_TIME_BITS], [64], + [Number of bits in time_t, on hosts where this is settable.])], + + ["-D__MINGW_USE_VC2005_COMPAT=1"], + [AC_DEFINE([__MINGW_USE_VC2005_COMPAT], [1], + [Define to 1 on platforms where this makes time_t a 64-bit type.])], + + ["-U_USE_32_BIT_TIME_T"*], + [AC_MSG_FAILURE(m4_text_wrap( + [the 'time_t' type is currently forced to be 32-bit. + It will stop working after January 2038. + Remove _USE_32BIT_TIME_T from the compiler flags.], + [], [], [55]))], + + [AC_MSG_ERROR( + [internal error: bad value for \$ac_cv_sys_year2038_opts])]) +]) + +# _AC_SYS_YEAR2038_ENABLE +# ----------------------- +# Subroutine of AC_SYS_YEAR2038 and _AC_SYS_YEAR2038_OPT_IN. +# Depending on which of the YEAR2038 macros was used, add either an +# --enable-year2038, or a --disable-year2038, or no option at all to +# the configure script. Note that this is expanded very late and +# therefore there cannot be any code in the AC_ARG_ENABLE. The +# default value for enable_year2038 is emitted unconditionally +# because the generated code always looks at this variable. +m4_define([_AC_SYS_YEAR2038_ENABLE], +[m4_divert_text([DEFAULTS], + m4_provide_if([AC_SYS_YEAR2038], + [enable_year2038=yes], + [enable_year2038=no]))]dnl +[AC_ARG_ENABLE([year2038], + m4_provide_if([AC_SYS_YEAR2038], + [AS_HELP_STRING([--disable-year2038], + [do not support timestamps after 2038])], + [AS_HELP_STRING([--enable-year2038], + [support timestamps after 2038])]))]) + +# _AC_SYS_YEAR2038_OPT_IN +# ----------------------- +# If the --enable-year2038 option is given to configure, attempt to +# detect and activate support for large time_t on 32-bit systems. +# This macro is automatically invoked by AC_SYS_LARGEFILE when large +# *file* support is detected. It does not AC_REQUIRE AC_SYS_LARGEFILE +# to avoid a dependency loop, and is therefore unsafe to expose as a +# documented macro. +AC_DEFUN([_AC_SYS_YEAR2038_OPT_IN], +[m4_provide_if([_AC_SYS_YEAR2038_PROBE], [], [dnl + AS_IF([test "$enable_year2038" != no], [_AC_SYS_YEAR2038_PROBE]) + AC_CONFIG_COMMANDS_PRE([_AC_SYS_YEAR2038_ENABLE]) +])]) + +# AC_SYS_YEAR2038 +# --------------- +# Attempt to detect and activate support for large time_t. +# On systems where time_t is not always 64 bits, this probe can be +# skipped by passing the --disable-year2038 option to configure. +AC_DEFUN([AC_SYS_YEAR2038], +[AC_REQUIRE([AC_SYS_LARGEFILE])]dnl +[m4_provide_if([_AC_SYS_YEAR2038_PROBE], [], [dnl + AS_IF([test "$enable_year2038" != no], [_AC_SYS_YEAR2038_PROBE]) + AC_CONFIG_COMMANDS_PRE([_AC_SYS_YEAR2038_ENABLE]) +])]) + +# _AC_SYS_LARGEFILE_TEST_CODE +# --------------------------- +# C code used to probe for large file support. +m4_define([_AC_SYS_LARGEFILE_TEST_CODE], +[@%:@include <sys/types.h> + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +@%:@define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) + int off_t_is_large[[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]];[]dnl +]) + +# _AC_SYS_LARGEFILE_OPTIONS +# ------------------------- +# List of known ways to enable support for large files. If you change +# this list you probably also need to change the AS_CASE at the end of +# _AC_SYS_LARGEFILE_PROBE. +m4_define([_AC_SYS_LARGEFILE_OPTIONS], m4_normalize( + ["none needed"] dnl Most current systems + ["-D_FILE_OFFSET_BITS=64"] dnl X/Open LFS spec + ["-D_LARGE_FILES=1"] dnl AIX (which versions?) + ["-n32"] dnl Irix 6.2 w/ SGI compiler +)) + +# _AC_SYS_LARGEFILE_PROBE +# ----------------------- +# Subroutine of AC_SYS_LARGEFILE. Probe for large file support and set +# the cache variable ac_cv_sys_largefile_opts to one of the values in +# the _AC_SYS_LARGEFILE_OPTIONS list, or to "support not detected" if +# none of the options in that list worked. Then, set compilation +# options and #defines as necessary to enable large file support. +# +# If large file support is not detected, the behavior depends on which of +# the top-level AC_SYS_LARGEFILE macros was used (see below). +# +# If you change this macro you may also need to change +# _AC_SYS_LARGEFILE_OPTIONS. +AC_DEFUN([_AC_SYS_LARGEFILE_PROBE], +[AC_CACHE_CHECK([for $CC option to enable large file support], + [ac_cv_sys_largefile_opts], + [ac_save_CC="$CC" + ac_opt_found=no + for ac_opt in _AC_SYS_LARGEFILE_OPTIONS; do + AS_IF([test x"$ac_opt" != x"none needed"], + [CC="$ac_save_CC $ac_opt"]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([_AC_SYS_LARGEFILE_TEST_CODE])], + [ac_cv_sys_largefile_opts="$ac_opt" + ac_opt_found=yes]) + test $ac_opt_found = no || break + done + CC="$ac_save_CC" + test $ac_opt_found = yes || ac_cv_sys_largefile_opts="support not detected"]) + +ac_have_largefile=yes +AS_CASE([$ac_cv_sys_largefile_opts], + ["none needed"], [], + ["support not detected"], + [ac_have_largefile=no], + + ["-D_FILE_OFFSET_BITS=64"], + [AC_DEFINE([_FILE_OFFSET_BITS], [64], + [Number of bits in a file offset, on hosts where this is settable.])], + + ["-D_LARGE_FILES=1"], + [AC_DEFINE([_LARGE_FILES], [1], + [Define to 1 on platforms where this makes off_t a 64-bit type.])], + + ["-n32"], + [CC="$CC -n32"], + + [AC_MSG_ERROR( + [internal error: bad value for \$ac_cv_sys_largefile_opts])]) + +_AC_SYS_YEAR2038_OPT_IN +]) +# _AC_SYS_LARGEFILE_ENABLE +# ------------------------ +# Subroutine of AC_SYS_LARGEFILE. Note that this +# is expanded very late and therefore there cannot be any code in the +# AC_ARG_ENABLE. The default value for enable_largefile is emitted +# unconditionally because the generated shell code always looks at +# this variable. +m4_define([_AC_SYS_LARGEFILE_ENABLE], +[m4_divert_text([DEFAULTS], + enable_largefile=yes)]dnl +[AC_ARG_ENABLE([largefile], + [AS_HELP_STRING([--disable-largefile], [omit support for large files])])]) # AC_SYS_LARGEFILE # ---------------- @@ -84,44 +306,13 @@ rm -rf conftest*[]dnl # Additionally, on Linux file systems with 64-bit inodes a file that happens # to have a 64-bit inode number cannot be accessed by 32-bit applications on # Linux x86/x86_64. This can occur with file systems such as XFS and NFS. +# This macro allows configuration to continue if the system doesn't support +# large files. AC_DEFUN([AC_SYS_LARGEFILE], -[AC_ARG_ENABLE(largefile, - [ --disable-largefile omit support for large files]) -AS_IF([test "$enable_largefile" != no], - [AC_CACHE_CHECK([for special C compiler options needed for large files], - ac_cv_sys_largefile_CC, - [ac_cv_sys_largefile_CC=no - if test "$GCC" != yes; then - ac_save_CC=$CC - while :; do - # IRIX 6.2 and later do not support large files by default, - # so use the C compiler's -n32 option if that helps. - AC_LANG_CONFTEST([AC_LANG_PROGRAM([_AC_SYS_LARGEFILE_TEST_INCLUDES])]) - AC_COMPILE_IFELSE([], [break]) - CC="$CC -n32" - AC_COMPILE_IFELSE([], [ac_cv_sys_largefile_CC=' -n32'; break]) - break - done - CC=$ac_save_CC - rm -f conftest.$ac_ext - fi]) - if test "$ac_cv_sys_largefile_CC" != no; then - CC=$CC$ac_cv_sys_largefile_CC - fi - - _AC_SYS_LARGEFILE_MACRO_VALUE(_FILE_OFFSET_BITS, 64, - ac_cv_sys_file_offset_bits, - [Number of bits in a file offset, on hosts where this is settable.], - [_AC_SYS_LARGEFILE_TEST_INCLUDES]) - AS_CASE([$ac_cv_sys_file_offset_bits], - [unknown], - [_AC_SYS_LARGEFILE_MACRO_VALUE([_LARGE_FILES], [1], - [ac_cv_sys_large_files], - [Define for large files, on AIX-style hosts.], - [_AC_SYS_LARGEFILE_TEST_INCLUDES])], - [64], - [gl_YEAR2038_BODY([])])]) -])# AC_SYS_LARGEFILE +[m4_provide_if([_AC_SYS_LARGEFILE_PROBE], [], [dnl + AS_IF([test "$enable_largefile" != no], [_AC_SYS_LARGEFILE_PROBE]) + AC_CONFIG_COMMANDS_PRE([_AC_SYS_LARGEFILE_ENABLE]) +])]) ])# m4_ifndef AC_SYS_YEAR2038 # Enable large files on systems where this is implemented by Gnulib, not by the diff --git a/m4/mempcpy.m4 b/m4/mempcpy.m4 index 3ac8a305bde..55bee2ab7a2 100644 --- a/m4/mempcpy.m4 +++ b/m4/mempcpy.m4 @@ -1,6 +1,6 @@ # mempcpy.m4 serial 12 -dnl Copyright (C) 2003-2004, 2006-2007, 2009-2023 Free Software -dnl Foundation, Inc. +dnl Copyright (C) 2003-2004, 2006-2007, 2009-2023 Free Software Foundation, +dnl Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. diff --git a/m4/memrchr.m4 b/m4/memrchr.m4 index ed750b7bdf1..7611ac7e3ac 100644 --- a/m4/memrchr.m4 +++ b/m4/memrchr.m4 @@ -1,6 +1,6 @@ # memrchr.m4 serial 11 -dnl Copyright (C) 2002-2003, 2005-2007, 2009-2023 Free Software -dnl Foundation, Inc. +dnl Copyright (C) 2002-2003, 2005-2007, 2009-2023 Free Software Foundation, +dnl Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. diff --git a/m4/memset_explicit.m4 b/m4/memset_explicit.m4 new file mode 100644 index 00000000000..9dcd89a758a --- /dev/null +++ b/m4/memset_explicit.m4 @@ -0,0 +1,20 @@ +dnl Copyright 2022-2023 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_MEMSET_EXPLICIT], +[ + AC_REQUIRE([gl_STRING_H_DEFAULTS]) + + AC_CHECK_FUNCS_ONCE([memset_explicit]) + if test $ac_cv_func_memset_explicit = no; then + HAVE_MEMSET_EXPLICIT=0 + fi +]) + +AC_DEFUN([gl_PREREQ_MEMSET_EXPLICIT], +[ + AC_CHECK_FUNCS([explicit_memset]) + AC_CHECK_FUNCS_ONCE([memset_s]) +]) diff --git a/m4/mktime.m4 b/m4/mktime.m4 index 604dd766f5d..e9d31f35a46 100644 --- a/m4/mktime.m4 +++ b/m4/mktime.m4 @@ -1,6 +1,6 @@ # serial 37 -dnl Copyright (C) 2002-2003, 2005-2007, 2009-2023 Free Software -dnl Foundation, Inc. +dnl Copyright (C) 2002-2003, 2005-2007, 2009-2023 Free Software Foundation, +dnl Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. diff --git a/m4/nanosleep.m4 b/m4/nanosleep.m4 index 21ee5a21daf..e21a3e343cb 100644 --- a/m4/nanosleep.m4 +++ b/m4/nanosleep.m4 @@ -1,4 +1,4 @@ -# serial 42 +# serial 43 dnl From Jim Meyering. dnl Check for the nanosleep function. @@ -25,11 +25,11 @@ AC_DEFUN([gl_FUNC_NANOSLEEP], # Solaris 2.5.1 needs -lposix4 to get the nanosleep function. # Solaris 7 prefers the library name -lrt to the obsolescent name -lposix4. - LIB_NANOSLEEP= - AC_SUBST([LIB_NANOSLEEP]) + NANOSLEEP_LIB= + AC_SUBST([NANOSLEEP_LIB]) AC_SEARCH_LIBS([nanosleep], [rt posix4], [test "$ac_cv_search_nanosleep" = "none required" || - LIB_NANOSLEEP=$ac_cv_search_nanosleep]) + NANOSLEEP_LIB=$ac_cv_search_nanosleep]) if test "x$ac_cv_search_nanosleep" != xno; then dnl The system has a nanosleep function. @@ -143,4 +143,8 @@ AC_DEFUN([gl_FUNC_NANOSLEEP], HAVE_NANOSLEEP=0 fi LIBS=$nanosleep_save_libs + + # For backward compatibility. + LIB_NANOSLEEP="$NANOSLEEP_LIB" + AC_SUBST([LIB_NANOSLEEP]) ]) diff --git a/m4/nstrftime.m4 b/m4/nstrftime.m4 index 45b89f752a5..04c0b63fbd0 100644 --- a/m4/nstrftime.m4 +++ b/m4/nstrftime.m4 @@ -1,7 +1,6 @@ # serial 37 -# Copyright (C) 1996-1997, 1999-2007, 2009-2023 Free Software -# Foundation, Inc. +# Copyright (C) 1996-1997, 1999-2007, 2009-2023 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/m4/pathmax.m4 b/m4/pathmax.m4 index 5b7fa4242bc..6d47d2c026e 100644 --- a/m4/pathmax.m4 +++ b/m4/pathmax.m4 @@ -1,6 +1,6 @@ # pathmax.m4 serial 11 -dnl Copyright (C) 2002-2003, 2005-2006, 2009-2023 Free Software -dnl Foundation, Inc. +dnl Copyright (C) 2002-2003, 2005-2006, 2009-2023 Free Software Foundation, +dnl Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. diff --git a/m4/pthread_sigmask.m4 b/m4/pthread_sigmask.m4 index 5110668155e..27795282bee 100644 --- a/m4/pthread_sigmask.m4 +++ b/m4/pthread_sigmask.m4 @@ -1,4 +1,4 @@ -# pthread_sigmask.m4 serial 21 +# pthread_sigmask.m4 serial 22 dnl Copyright (C) 2011-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -24,7 +24,7 @@ AC_DEFUN([gl_FUNC_PTHREAD_SIGMASK], [gl_cv_func_pthread_sigmask_macro=no]) ]) - LIB_PTHREAD_SIGMASK= + PTHREAD_SIGMASK_LIB= if test $gl_cv_func_pthread_sigmask_macro = yes; then dnl pthread_sigmask is a dummy macro. @@ -62,7 +62,7 @@ AC_DEFUN([gl_FUNC_PTHREAD_SIGMASK], ]) if test $gl_cv_func_pthread_sigmask_in_LIBMULTITHREAD = yes; then dnl pthread_sigmask is available with -pthread or -lpthread. - LIB_PTHREAD_SIGMASK="$LIBMULTITHREAD" + PTHREAD_SIGMASK_LIB="$LIBMULTITHREAD" else dnl pthread_sigmask is not available at all. HAVE_PTHREAD_SIGMASK=0 @@ -101,6 +101,9 @@ AC_DEFUN([gl_FUNC_PTHREAD_SIGMASK], ]) fi + AC_SUBST([PTHREAD_SIGMASK_LIB]) + dnl For backward compatibility. + LIB_PTHREAD_SIGMASK="$PTHREAD_SIGMASK_LIB" AC_SUBST([LIB_PTHREAD_SIGMASK]) dnl We don't need a variable LTLIB_PTHREAD_SIGMASK, because when dnl "$gl_threads_api" = posix, $LTLIBMULTITHREAD and $LIBMULTITHREAD are the @@ -114,7 +117,7 @@ AC_DEFUN([gl_FUNC_PTHREAD_SIGMASK], dnl On FreeBSD 13.0, MidnightBSD 1.1, HP-UX 11.31, Solaris 9, in programs dnl that are not linked with -lpthread, the pthread_sigmask() function dnl always returns 0 and has no effect. - if test -z "$LIB_PTHREAD_SIGMASK"; then + if test -z "$PTHREAD_SIGMASK_LIB"; then case " $LIBS " in *' -pthread '*) ;; *' -lpthread '*) ;; @@ -162,7 +165,7 @@ AC_DEFUN([gl_FUNC_PTHREAD_SIGMASK], [gl_cv_func_pthread_sigmask_return_works], [ gl_save_LIBS="$LIBS" - LIBS="$LIBS $LIB_PTHREAD_SIGMASK" + LIBS="$LIBS $PTHREAD_SIGMASK_LIB" AC_RUN_IFELSE( [AC_LANG_SOURCE([[ #include <pthread.h> @@ -208,7 +211,7 @@ int main () gl_cv_func_pthread_sigmask_unblock_works="guessing yes";; esac m4_ifdef([gl_][THREADLIB], - [dnl Link against $LIBMULTITHREAD, not only $LIB_PTHREAD_SIGMASK. + [dnl Link against $LIBMULTITHREAD, not only $PTHREAD_SIGMASK_LIB. dnl Otherwise we get a false positive on those platforms where dnl $gl_cv_func_pthread_sigmask_in_libc_works is "no". gl_save_LIBS=$LIBS diff --git a/m4/sig2str.m4 b/m4/sig2str.m4 index 7aad94a9616..aee18efeefd 100644 --- a/m4/sig2str.m4 +++ b/m4/sig2str.m4 @@ -1,6 +1,5 @@ # serial 7 -dnl Copyright (C) 2002, 2005-2006, 2009-2023 Free Software Foundation, -dnl Inc. +dnl Copyright (C) 2002, 2005-2006, 2009-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. diff --git a/m4/ssize_t.m4 b/m4/ssize_t.m4 index 1b45e9557cc..1c12c33ea09 100644 --- a/m4/ssize_t.m4 +++ b/m4/ssize_t.m4 @@ -1,6 +1,5 @@ # ssize_t.m4 serial 5 (gettext-0.18.2) -dnl Copyright (C) 2001-2003, 2006, 2010-2023 Free Software Foundation, -dnl Inc. +dnl Copyright (C) 2001-2003, 2006, 2010-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. diff --git a/m4/stat-time.m4 b/m4/stat-time.m4 index 5b6b8101098..40993d5731c 100644 --- a/m4/stat-time.m4 +++ b/m4/stat-time.m4 @@ -1,7 +1,7 @@ # Checks for stat-related time functions. -# Copyright (C) 1998-1999, 2001, 2003, 2005-2007, 2009-2023 Free -# Software Foundation, Inc. +# Copyright (C) 1998-1999, 2001, 2003, 2005-2007, 2009-2023 Free Software +# Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4 index 94271e11e78..07569961f8b 100644 --- a/m4/stdio_h.m4 +++ b/m4/stdio_h.m4 @@ -1,4 +1,4 @@ -# stdio_h.m4 serial 59 +# stdio_h.m4 serial 61 dnl Copyright (C) 2007-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -82,6 +82,16 @@ AC_DEFUN_ONCE([gl_STDIO_H], if test $ac_cv_have_decl_fcloseall = no; then HAVE_DECL_FCLOSEALL=0 fi + + AC_CHECK_DECLS_ONCE([getw]) + if test $ac_cv_have_decl_getw = no; then + HAVE_DECL_GETW=0 + fi + + AC_CHECK_DECLS_ONCE([putw]) + if test $ac_cv_have_decl_putw = no; then + HAVE_DECL_PUTW=0 + fi ]) # gl_STDIO_MODULE_INDICATOR([modulename]) @@ -178,7 +188,9 @@ AC_DEFUN([gl_STDIO_H_DEFAULTS], HAVE_DECL_FTELLO=1; AC_SUBST([HAVE_DECL_FTELLO]) HAVE_DECL_GETDELIM=1; AC_SUBST([HAVE_DECL_GETDELIM]) HAVE_DECL_GETLINE=1; AC_SUBST([HAVE_DECL_GETLINE]) + HAVE_DECL_GETW=1; AC_SUBST([HAVE_DECL_GETW]) HAVE_DECL_OBSTACK_PRINTF=1; AC_SUBST([HAVE_DECL_OBSTACK_PRINTF]) + HAVE_DECL_PUTW=1; AC_SUBST([HAVE_DECL_PUTW]) HAVE_DECL_SNPRINTF=1; AC_SUBST([HAVE_DECL_SNPRINTF]) HAVE_DECL_VSNPRINTF=1; AC_SUBST([HAVE_DECL_VSNPRINTF]) HAVE_DPRINTF=1; AC_SUBST([HAVE_DPRINTF]) diff --git a/m4/string_h.m4 b/m4/string_h.m4 index 15401e129cd..5da3cc25291 100644 --- a/m4/string_h.m4 +++ b/m4/string_h.m4 @@ -5,7 +5,7 @@ # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. -# serial 34 +# serial 35 # Written by Paul Eggert. @@ -21,7 +21,8 @@ AC_DEFUN_ONCE([gl_STRING_H], dnl guaranteed by C89. gl_WARN_ON_USE_PREPARE([[#include <string.h> ]], - [ffsl ffsll memmem mempcpy memrchr rawmemchr stpcpy stpncpy strchrnul + [explicit_bzero ffsl ffsll memmem mempcpy memrchr memset_explicit + rawmemchr stpcpy stpncpy strchrnul strdup strncat strndup strnlen strpbrk strsep strcasestr strtok_r strerror_r strerrorname_np sigabbrev_np sigdescr_np strsignal strverscmp]) @@ -54,6 +55,7 @@ AC_DEFUN([gl_STRING_H_REQUIRE_DEFAULTS], gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MEMMEM]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MEMPCPY]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MEMRCHR]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MEMSET_EXPLICIT]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RAWMEMCHR]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STPCPY]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STPNCPY]) @@ -107,6 +109,7 @@ AC_DEFUN([gl_STRING_H_DEFAULTS], HAVE_FFSLL=1; AC_SUBST([HAVE_FFSLL]) HAVE_DECL_MEMMEM=1; AC_SUBST([HAVE_DECL_MEMMEM]) HAVE_MEMPCPY=1; AC_SUBST([HAVE_MEMPCPY]) + HAVE_MEMSET_EXPLICIT=1; AC_SUBST([HAVE_MEMSET_EXPLICIT]) HAVE_DECL_MEMRCHR=1; AC_SUBST([HAVE_DECL_MEMRCHR]) HAVE_RAWMEMCHR=1; AC_SUBST([HAVE_RAWMEMCHR]) HAVE_STPCPY=1; AC_SUBST([HAVE_STPCPY]) diff --git a/m4/strnlen.m4 b/m4/strnlen.m4 index 60e8d81bf3b..d2cac59b6f2 100644 --- a/m4/strnlen.m4 +++ b/m4/strnlen.m4 @@ -1,6 +1,6 @@ # strnlen.m4 serial 14 -dnl Copyright (C) 2002-2003, 2005-2007, 2009-2023 Free Software -dnl Foundation, Inc. +dnl Copyright (C) 2002-2003, 2005-2007, 2009-2023 Free Software Foundation, +dnl Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. diff --git a/m4/strtoimax.m4 b/m4/strtoimax.m4 index 1c6ddd386a5..db5cfb7aa9d 100644 --- a/m4/strtoimax.m4 +++ b/m4/strtoimax.m4 @@ -1,6 +1,5 @@ # strtoimax.m4 serial 16 -dnl Copyright (C) 2002-2004, 2006, 2009-2023 Free Software Foundation, -dnl Inc. +dnl Copyright (C) 2002-2004, 2006, 2009-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. diff --git a/m4/strtoll.m4 b/m4/strtoll.m4 index 1e042175b18..ede630c6061 100644 --- a/m4/strtoll.m4 +++ b/m4/strtoll.m4 @@ -1,6 +1,5 @@ # strtoll.m4 serial 9 -dnl Copyright (C) 2002, 2004, 2006, 2008-2023 Free Software Foundation, -dnl Inc. +dnl Copyright (C) 2002, 2004, 2006, 2008-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. diff --git a/m4/time_h.m4 b/m4/time_h.m4 index fd4a469d192..f6bf3a4f30e 100644 --- a/m4/time_h.m4 +++ b/m4/time_h.m4 @@ -1,7 +1,6 @@ # Configure a more-standard replacement for <time.h>. -# Copyright (C) 2000-2001, 2003-2007, 2009-2023 Free Software -# Foundation, Inc. +# Copyright (C) 2000-2001, 2003-2007, 2009-2023 Free Software Foundation, Inc. # serial 20 diff --git a/m4/timer_time.m4 b/m4/timer_time.m4 index 4c2608b58e8..437d1dc5428 100644 --- a/m4/timer_time.m4 +++ b/m4/timer_time.m4 @@ -1,10 +1,10 @@ -# timer_time.m4 serial 5 +# timer_time.m4 serial 6 dnl Copyright (C) 2011-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. -# Check for timer_settime, and set LIB_TIMER_TIME. +# Check for timer_settime, and set TIMER_TIME_LIB. AC_DEFUN([gl_TIMER_TIME], [ @@ -21,13 +21,13 @@ AC_DEFUN([gl_TIMER_TIME], AC_CHECK_DECL([timer_settime], [], [], [[#include <time.h> ]]) - LIB_TIMER_TIME= - AC_SUBST([LIB_TIMER_TIME]) + TIMER_TIME_LIB= + AC_SUBST([TIMER_TIME_LIB]) AS_IF([test "$ac_cv_have_decl_timer_settime" = yes], [ gl_saved_libs=$LIBS AC_SEARCH_LIBS([timer_settime], [rt posix4], [test "$ac_cv_search_timer_settime" = "none required" || - LIB_TIMER_TIME=$ac_cv_search_timer_settime]) + TIMER_TIME_LIB=$ac_cv_search_timer_settime]) m4_ifdef([gl_][PTHREADLIB], [dnl GLIBC uses threads to emulate posix timers when kernel support dnl is not available (like Linux < 2.6 or when used with kFreeBSD) @@ -42,8 +42,11 @@ AC_DEFUN([gl_TIMER_TIME], #endif #endif ], - [LIB_TIMER_TIME="$LIB_TIMER_TIME $LIBPMULTITHREAD"])]) + [TIMER_TIME_LIB="$TIMER_TIME_LIB $LIBPMULTITHREAD"])]) AC_CHECK_FUNCS([timer_settime]) LIBS=$gl_saved_libs ]) + dnl For backward compatibility. + LIB_TIMER_TIME="$TIMER_TIME_LIB" + AC_SUBST([LIB_TIMER_TIME]) ]) diff --git a/m4/timespec.m4 b/m4/timespec.m4 index 354530319fe..95f475f2cc5 100644 --- a/m4/timespec.m4 +++ b/m4/timespec.m4 @@ -1,7 +1,6 @@ #serial 15 -# Copyright (C) 2000-2001, 2003-2007, 2009-2023 Free Software -# Foundation, Inc. +# Copyright (C) 2000-2001, 2003-2007, 2009-2023 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/m4/utimens.m4 b/m4/utimens.m4 index ae35ef789b8..c5d9b69e6f5 100644 --- a/m4/utimens.m4 +++ b/m4/utimens.m4 @@ -3,7 +3,7 @@ dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. -dnl serial 11 +dnl serial 12 AC_DEFUN([gl_UTIMENS], [ @@ -11,7 +11,9 @@ AC_DEFUN([gl_UTIMENS], AC_REQUIRE([gl_FUNC_UTIMES]) AC_REQUIRE([gl_CHECK_TYPE_STRUCT_TIMESPEC]) AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles - AC_CHECK_FUNCS_ONCE([futimes futimesat futimens utimensat lutimes]) + AC_CHECK_FUNCS_ONCE([futimens utimensat lutimes]) + gl_CHECK_FUNCS_ANDROID([futimes], [[#include <sys/time.h>]]) + gl_CHECK_FUNCS_ANDROID([futimesat], [[#include <sys/time.h>]]) if test $ac_cv_func_futimens = no && test $ac_cv_func_futimesat = yes; then dnl FreeBSD 8.0-rc2 mishandles futimesat(fd,NULL,time). It is not diff --git a/m4/xattr.m4 b/m4/xattr.m4 new file mode 100644 index 00000000000..0e179cc0d1d --- /dev/null +++ b/m4/xattr.m4 @@ -0,0 +1,53 @@ +# xattr.m4 - check for Extended Attributes (Linux) +# serial 6 + +# Copyright (C) 2003-2023 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_XATTR], +[ + AC_ARG_ENABLE([xattr], + AS_HELP_STRING([--disable-xattr], + [do not support extended attributes]), + [use_xattr=$enableval], [use_xattr=yes]) + + LIB_XATTR= + AC_SUBST([LIB_XATTR]) + + if test "$use_xattr" = yes; then + AC_CACHE_CHECK([for xattr library with ATTR_ACTION_PERMISSIONS], + [gl_cv_xattr_lib], + [gl_cv_xattr_lib=no + AC_LANG_CONFTEST( + [AC_LANG_PROGRAM( + [[#include <attr/error_context.h> + #include <attr/libattr.h> + static int + is_attr_permissions (const char *name, struct error_context *ctx) + { + return attr_copy_action (name, ctx) == ATTR_ACTION_PERMISSIONS; + } + ]], + [[return attr_copy_fd ("/", 0, "/", 0, is_attr_permissions, 0); + ]])]) + AC_LINK_IFELSE([], + [gl_cv_xattr_lib='none required'], + [xattr_saved_LIBS=$LIBS + LIBS="-lattr $LIBS" + AC_LINK_IFELSE([], [gl_cv_xattr_lib=-lattr]) + LIBS=$xattr_saved_LIBS])]) + if test "$gl_cv_xattr_lib" = no; then + AC_MSG_WARN([libattr development library was not found or not usable.]) + AC_MSG_WARN([AC_PACKAGE_NAME will be built without xattr support.]) + use_xattr=no + elif test "$gl_cv_xattr_lib" != 'none required'; then + LIB_XATTR=$gl_cv_xattr_lib + fi + fi + if test "$use_xattr" = yes; then + AC_DEFINE([USE_XATTR], [1], + [Define to 1 to use the Linux extended attributes library.]) + fi +]) diff --git a/msdos/autogen/Makefile.in b/msdos/autogen/Makefile.in index 7f44c9867fe..df9b7797989 100644 --- a/msdos/autogen/Makefile.in +++ b/msdos/autogen/Makefile.in @@ -921,13 +921,11 @@ LIBXT_OTHER = @LIBXT_OTHER@ LIBX_OTHER = @LIBX_OTHER@ LIBZ = @LIBZ@ LIB_ACL = @LIB_ACL@ -LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@ -LIB_EACCESS = @LIB_EACCESS@ +CLOCK_TIME_LIB = @CLOCK_TIME_LIB@ +EUIDACCESS_LIBGEN = @EUIDACCESS_LIBGEN@ LIB_EXECINFO = @LIB_EXECINFO@ -LIB_FDATASYNC = @LIB_FDATASYNC@ LIB_MATH = @LIB_MATH@ LIB_PTHREAD = @LIB_PTHREAD@ -LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@ LIB_TIMER_TIME = @LIB_TIMER_TIME@ LIB_WSOCK32 = @LIB_WSOCK32@ LN_S_FILEONLY = @LN_S_FILEONLY@ diff --git a/msdos/sed1v2.inp b/msdos/sed1v2.inp index 4d4c80a6b1a..162ccb3e8d8 100644 --- a/msdos/sed1v2.inp +++ b/msdos/sed1v2.inp @@ -48,9 +48,8 @@ s/\.h\.in/.h-in/ /^LIB_MATH *=/s/@LIB_MATH@/-lm/ /^LIB_PTHREAD *=/s/@LIB_PTHREAD@// /^LIB_ACL *=/s/@LIB_ACL@// -/^LIB_EACCESS *=/s/@LIB_EACCESS@// -/^LIB_FDATASYNC *=/s/@LIB_FDATASYNC@// -/^LIB_NANOSLEEP *=/s/@LIB_NANOSLEEP@// +/^EUIDACCESS_LIBGEN *=/s/@EUIDACCESS_LIBGEN@// +/^NANOSLEEP_LIB *=/s/@NANOSLEEP_LIB@// s/ *@LIBTIFF@// s/ *@LIBJPEG@// s/ *@LIBPNG@// @@ -140,7 +139,7 @@ s/ *@WEBP_LIBS@// /^LIBSELINUX_LIBS *=/s/@LIBSELINUX_LIBS@// /^LIBSYSTEMD_LIBS *=/s/@LIBSYSTEMD_LIBS@// /^LIBSYSTEMD_CFLAGS *=/s/@LIBSYSTEMD_CFLAGS@// -/^LIB_CLOCK_GETTIME *=/s/@[^@\n]*@//g +/^CLOCK_TIME_LIB *=/s/@[^@\n]*@//g /^LIB_TIMER_TIME *=/s/@[^@\n]*@//g /^LIB_EXECINFO *=/s/@[^@\n]*@//g /^LIBGNUTLS_LIBS *=/s/@[^@\n]*@// @@ -183,6 +182,7 @@ s/ *@WEBP_LIBS@// /^TREE_SITTER_CFLAGS *=/s/@TREE_SITTER_CFLAGS@// /^HARFBUZZ_CFLAGS *=/s/@HARFBUZZ_CFLAGS@// /^HARFBUZZ_LIBS *=/s/@HARFBUZZ_LIBS@// +/^QCOPY_ACL_LIB *=/s/@QCOPY_ACL_LIB@// /^LCMS2_CFLAGS *=/s/@LCMS2_CFLAGS@// /^LCMS2_LIBS *=/s/@LCMS2_LIBS@// /^LIBGMP *=/s/@LIBGMP@// diff --git a/msdos/sed2v2.inp b/msdos/sed2v2.inp index 9817c74403a..58c1663dda0 100644 --- a/msdos/sed2v2.inp +++ b/msdos/sed2v2.inp @@ -67,7 +67,7 @@ /^#undef PACKAGE_NAME/s/^.*$/#define PACKAGE_NAME ""/ /^#undef PACKAGE_STRING/s/^.*$/#define PACKAGE_STRING ""/ /^#undef PACKAGE_TARNAME/s/^.*$/#define PACKAGE_TARNAME ""/ -/^#undef PACKAGE_VERSION/s/^.*$/#define PACKAGE_VERSION "29.0.60"/ +/^#undef PACKAGE_VERSION/s/^.*$/#define PACKAGE_VERSION "30.0.50"/ /^#undef SYSTEM_TYPE/s/^.*$/#define SYSTEM_TYPE "ms-dos"/ /^#undef HAVE_DECL_GETENV/s/^.*$/#define HAVE_DECL_GETENV 1/ /^#undef SYS_SIGLIST_DECLARED/s/^.*$/#define SYS_SIGLIST_DECLARED 1/ diff --git a/msdos/sed3v2.inp b/msdos/sed3v2.inp index dc9eaff27c8..9688a27b066 100644 --- a/msdos/sed3v2.inp +++ b/msdos/sed3v2.inp @@ -32,9 +32,9 @@ /^LIBRESOLV *=/s/@[^@\n]*@//g /^LIBS_MAIL *=/s/@[^@\n]*@//g /^LIBS_SYSTEM *=/s/@[^@\n]*@//g -/^LIB_CLOCK_GETTIME *=/s/@[^@\n]*@//g +/^CLOCK_TIME_LIB *=/s/@[^@\n]*@//g /^LIB_TIMER_TIME *=/s/@[^@\n]*@//g -/^LIB_GETRANDOM *=/s/@[^@\n]*@//g +/^GETRANDOM_LIB *=/s/@[^@\n]*@//g /^CFLAGS *=/s!=.*$!=-O2 -g! /^CPPFLAGS *=/s/@CPPFLAGS@// /^LDFLAGS *=/s/@LDFLAGS@// @@ -49,7 +49,6 @@ /^ALLOCA *=/s!@ALLOCA@!! /^EXEEXT *=/s!@EXEEXT@!.exe! /^CLIENTW *=/s/@CLIENTW@// -/^LIB_FDATASYNC *=/s/@LIB_FDATASYNC@// /^LIB_WSOCK32 *=/s/@LIB_WSOCK32@// /^LIBS_ECLIENT *=/s/@LIBS_ECLIENT@// /^NTLIB *=/s/@NTLIB@// diff --git a/msdos/sedlibmk.inp b/msdos/sedlibmk.inp index 497aedb2096..634bf999e50 100644 --- a/msdos/sedlibmk.inp +++ b/msdos/sedlibmk.inp @@ -270,7 +270,6 @@ s/@PACKAGE@/emacs/ /^LDFLAGS *=/s/@[^@\n]*@// /^LD_FIRSTFLAG *=/s/@[^@\n]*@// /^LIB_PTHREAD *=/s/@[^@\n]*@// -/^LIB_PTHREAD_SIGMASK *=/s/@[^@\n]*@// /^LIBS *=/s/@[^@\n]*@// /^MAKEINFO *=/s/@MAKEINFO@/makeinfo/ # MKDIR_P lines are edited further below @@ -323,7 +322,7 @@ s/@PACKAGE@/emacs/ /^REPLACE_MKTIME *=/s/@[^@\n]*@/1/ # We don't want any other gnulib replacement functions /^REPLACE_[^ =]* *= *@/s/@[^@\n]*@/0/ -/^LIB_GETRANDOM[^ =]* *= *@/s/@[^@\n]*@// +/^GETRANDOM_LIB[^ =]* *= *@/s/@[^@\n]*@// /^SIG_ATOMIC_T_SUFFIX *=/s/@SIG_ATOMIC_T_SUFFIX@// /^SIZE_T_SUFFIX *=/s/@SIZE_T_SUFFIX@/u/ /^ASSERT_H *=/s/@[^@\n]*@/assert.h/ diff --git a/nt/README.W32 b/nt/README.W32 index 523f833ca24..da1ede1ea4d 100644 --- a/nt/README.W32 +++ b/nt/README.W32 @@ -1,7 +1,7 @@ Copyright (C) 2001-2023 Free Software Foundation, Inc. See the end of the file for license conditions. - Emacs version 29.0.60 for MS-Windows + Emacs version 30.0.50 for MS-Windows This README file describes how to set up and run a precompiled distribution of the latest version of GNU Emacs for MS-Windows. You diff --git a/src/Makefile.in b/src/Makefile.in index c29c3750e59..e08e5eead28 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -144,9 +144,10 @@ M17N_FLT_CFLAGS = @M17N_FLT_CFLAGS@ M17N_FLT_LIBS = @M17N_FLT_LIBS@ LIB_ACL=@LIB_ACL@ -LIB_CLOCK_GETTIME=@LIB_CLOCK_GETTIME@ -LIB_EACCESS=@LIB_EACCESS@ -LIB_NANOSLEEP=@LIB_NANOSLEEP@ +CLOCK_TIME_LIB=@CLOCK_TIME_LIB@ +EUIDACCESS_LIBGEN=@EUIDACCESS_LIBGEN@ +NANOSLEEP_LIB=@NANOSLEEP_LIB@ +QCOPY_ACL_LIB=@QCOPY_ACL_LIB@ LIB_TIMER_TIME=@LIB_TIMER_TIME@ DBUS_CFLAGS = @DBUS_CFLAGS@ @@ -558,9 +559,9 @@ lisp = $(addprefix ${lispsource}/,${shortlisp}) ## Construct full set of libraries to be linked. LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(PGTK_LIBS) $(LIBX_BASE) $(LIBIMAGE) \ $(LIBX_OTHER) $(LIBSOUND) \ - $(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_ACL) $(LIB_CLOCK_GETTIME) \ - $(LIB_NANOSLEEP) $(WEBKIT_LIBS) \ - $(LIB_EACCESS) $(LIB_TIMER_TIME) $(DBUS_LIBS) \ + $(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_ACL) $(CLOCK_TIME_LIB) \ + $(NANOSLEEP_LIB) $(QCOPY_ACL_LIB) $(WEBKIT_LIBS) \ + $(EUIDACCESS_LIBGEN) $(LIB_TIMER_TIME) $(DBUS_LIBS) \ $(LIB_EXECINFO) $(XRANDR_LIBS) $(XINERAMA_LIBS) $(XFIXES_LIBS) \ $(XDBE_LIBS) $(XSYNC_LIBS) \ $(LIBXML2_LIBS) $(LIBGPM) $(LIBS_SYSTEM) $(CAIRO_LIBS) \ diff --git a/src/alloc.c b/src/alloc.c index f7a0a4a80c8..a05e4aa5811 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -80,6 +80,37 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <valgrind/memcheck.h> #endif +/* AddressSanitizer exposes additional functions for manually marking + memory as poisoned/unpoisoned. When ASan is enabled and the needed + header is available, memory is poisoned when: + + * An ablock is freed (lisp_align_free), or ablocks are initially + allocated (lisp_align_malloc). + * An interval_block is initially allocated (make_interval). + * A dead INTERVAL is put on the interval free list + (sweep_intervals). + * A sdata is marked as dead (sweep_strings, pin_string). + * An sblock is initially allocated (allocate_string_data). + * A string_block is initially allocated (allocate_string). + * A dead string is put on string_free_list (sweep_strings). + * A float_block is initially allocated (make_float). + * A dead float is put on float_free_list. + * A cons_block is initially allocated (Fcons). + * A dead cons is put on cons_free_list (sweep_cons). + * A dead vector is put on vector_free_list (setup_on_free_list), + or a new vector block is allocated (allocate_vector_from_block). + Accordingly, objects reused from the free list are unpoisoned. + + This feature can be disabled wtih the run-time flag + `allow_user_poisoning' set to zero. */ +#if ADDRESS_SANITIZER && defined HAVE_SANITIZER_ASAN_INTERFACE_H \ + && !defined GC_ASAN_POISON_OBJECTS +# define GC_ASAN_POISON_OBJECTS 1 +# include <sanitizer/asan_interface.h> +#else +# define GC_ASAN_POISON_OBJECTS 0 +#endif + /* GC_CHECK_MARKED_OBJECTS means do sanity checks on allocated objects. We turn that on by default when ENABLE_CHECKING is defined; define GC_CHECK_MARKED_OBJECTS to zero to disable. */ @@ -1157,6 +1188,16 @@ struct ablocks (1 & (intptr_t) ABLOCKS_BUSY (abase) ? abase : ((void **) (abase))[-1]) #endif +#if GC_ASAN_POISON_OBJECTS +# define ASAN_POISON_ABLOCK(b) \ + __asan_poison_memory_region (&(b)->x, sizeof ((b)->x)) +# define ASAN_UNPOISON_ABLOCK(b) \ + __asan_unpoison_memory_region (&(b)->x, sizeof ((b)->x)) +#else +# define ASAN_POISON_ABLOCK(b) ((void) 0) +# define ASAN_UNPOISON_ABLOCK(b) ((void) 0) +#endif + /* The list of free ablock. */ static struct ablock *free_ablock; @@ -1235,6 +1276,7 @@ lisp_align_malloc (size_t nbytes, enum mem_type type) { abase->blocks[i].abase = abase; abase->blocks[i].x.next_free = free_ablock; + ASAN_POISON_ABLOCK (&abase->blocks[i]); free_ablock = &abase->blocks[i]; } intptr_t ialigned = aligned; @@ -1247,6 +1289,7 @@ lisp_align_malloc (size_t nbytes, enum mem_type type) eassert ((intptr_t) ABLOCKS_BUSY (abase) == aligned); } + ASAN_UNPOISON_ABLOCK (free_ablock); abase = ABLOCK_ABASE (free_ablock); ABLOCKS_BUSY (abase) = (struct ablocks *) (2 + (intptr_t) ABLOCKS_BUSY (abase)); @@ -1278,6 +1321,7 @@ lisp_align_free (void *block) #endif /* Put on free list. */ ablock->x.next_free = free_ablock; + ASAN_POISON_ABLOCK (ablock); free_ablock = ablock; /* Update busy count. */ intptr_t busy = (intptr_t) ABLOCKS_BUSY (abase) - 2; @@ -1290,9 +1334,12 @@ lisp_align_free (void *block) bool aligned = busy; struct ablock **tem = &free_ablock; struct ablock *atop = &abase->blocks[aligned ? ABLOCKS_SIZE : ABLOCKS_SIZE - 1]; - while (*tem) { +#if GC_ASAN_POISON_OBJECTS + __asan_unpoison_memory_region (&(*tem)->x, + sizeof ((*tem)->x)); +#endif if (*tem >= (struct ablock *) abase && *tem < atop) { i++; @@ -1421,6 +1468,24 @@ static int interval_block_index = INTERVAL_BLOCK_SIZE; static INTERVAL interval_free_list; +#if GC_ASAN_POISON_OBJECTS +# define ASAN_POISON_INTERVAL_BLOCK(b) \ + __asan_poison_memory_region ((b)->intervals, \ + sizeof ((b)->intervals)) +# define ASAN_UNPOISON_INTERVAL_BLOCK(b) \ + __asan_unpoison_memory_region ((b)->intervals, \ + sizeof ((b)->intervals)) +# define ASAN_POISON_INTERVAL(i) \ + __asan_poison_memory_region ((i), sizeof (*(i))) +# define ASAN_UNPOISON_INTERVAL(i) \ + __asan_unpoison_memory_region ((i), sizeof (*(i))) +#else +# define ASAN_POISON_INTERVAL_BLOCK(b) ((void) 0) +# define ASAN_UNPOISON_INTERVAL_BLOCK(b) ((void) 0) +# define ASAN_POISON_INTERVAL(i) ((void) 0) +# define ASAN_UNPOISON_INTERVAL(i) ((void) 0) +#endif + /* Return a new interval. */ INTERVAL @@ -1433,6 +1498,7 @@ make_interval (void) if (interval_free_list) { val = interval_free_list; + ASAN_UNPOISON_INTERVAL (val); interval_free_list = INTERVAL_PARENT (interval_free_list); } else @@ -1443,10 +1509,12 @@ make_interval (void) = lisp_malloc (sizeof *newi, false, MEM_TYPE_NON_LISP); newi->next = interval_block; + ASAN_POISON_INTERVAL_BLOCK (newi); interval_block = newi; interval_block_index = 0; } val = &interval_block->intervals[interval_block_index++]; + ASAN_UNPOISON_INTERVAL (val); } MALLOC_UNBLOCK_INPUT; @@ -1687,6 +1755,41 @@ init_strings (void) staticpro (&empty_multibyte_string); } +#if GC_ASAN_POISON_OBJECTS +/* Prepare s for denoting a free sdata struct, i.e, poison all bytes + in the flexible array member, except the first SDATA_OFFSET bytes. + This is only effective for strings of size n where n > sdata_size(n). + */ +# define ASAN_PREPARE_DEAD_SDATA(s, size) \ + do { \ + __asan_poison_memory_region ((s), sdata_size ((size))); \ + __asan_unpoison_memory_region (&(((s))->string), \ + sizeof (struct Lisp_String *)); \ + __asan_unpoison_memory_region (&SDATA_NBYTES ((s)), \ + sizeof (SDATA_NBYTES ((s)))); \ + } while (false) +/* Prepare s for storing string data for NBYTES bytes. */ +# define ASAN_PREPARE_LIVE_SDATA(s, nbytes) \ + __asan_unpoison_memory_region ((s), sdata_size ((nbytes))) +# define ASAN_POISON_SBLOCK_DATA(b, size) \ + __asan_poison_memory_region ((b)->data, (size)) +# define ASAN_POISON_STRING_BLOCK(b) \ + __asan_poison_memory_region ((b)->strings, STRING_BLOCK_SIZE) +# define ASAN_UNPOISON_STRING_BLOCK(b) \ + __asan_unpoison_memory_region ((b)->strings, STRING_BLOCK_SIZE) +# define ASAN_POISON_STRING(s) \ + __asan_poison_memory_region ((s), sizeof (*(s))) +# define ASAN_UNPOISON_STRING(s) \ + __asan_unpoison_memory_region ((s), sizeof (*(s))) +#else +# define ASAN_PREPARE_DEAD_SDATA(s, size) ((void) 0) +# define ASAN_PREPARE_LIVE_SDATA(s, nbytes) ((void) 0) +# define ASAN_POISON_SBLOCK_DATA(b, size) ((void) 0) +# define ASAN_POISON_STRING_BLOCK(b) ((void) 0) +# define ASAN_UNPOISON_STRING_BLOCK(b) ((void) 0) +# define ASAN_POISON_STRING(s) ((void) 0) +# define ASAN_UNPOISON_STRING(s) ((void) 0) +#endif #ifdef GC_CHECK_STRING_BYTES @@ -1805,12 +1908,14 @@ allocate_string (void) NEXT_FREE_LISP_STRING (s) = string_free_list; string_free_list = s; } + ASAN_POISON_STRING_BLOCK (b); } check_string_free_list (); /* Pop a Lisp_String off the free-list. */ s = string_free_list; + ASAN_UNPOISON_STRING (s); string_free_list = NEXT_FREE_LISP_STRING (s); MALLOC_UNBLOCK_INPUT; @@ -1870,6 +1975,7 @@ allocate_string_data (struct Lisp_String *s, #endif b = lisp_malloc (size + GC_STRING_EXTRA, clearit, MEM_TYPE_NON_LISP); + ASAN_POISON_SBLOCK_DATA (b, size); #ifdef DOUG_LEA_MALLOC if (!mmap_lisp_allowed_p ()) @@ -1891,6 +1997,8 @@ allocate_string_data (struct Lisp_String *s, { /* Not enough room in the current sblock. */ b = lisp_malloc (SBLOCK_SIZE, false, MEM_TYPE_NON_LISP); + ASAN_POISON_SBLOCK_DATA (b, SBLOCK_SIZE); + data = b->data; b->next = NULL; b->next_free = data; @@ -1903,10 +2011,19 @@ allocate_string_data (struct Lisp_String *s, } data = b->next_free; + if (clearit) - memset (SDATA_DATA (data), 0, nbytes); + { +#if GC_ASAN_POISON_OBJECTS + /* We are accessing SDATA_DATA (data) before it gets + * normally unpoisoned, so do it manually. */ + __asan_unpoison_memory_region (SDATA_DATA (data), nbytes); +#endif + memset (SDATA_DATA (data), 0, nbytes); + } } + ASAN_PREPARE_LIVE_SDATA (data, nbytes); data->string = s; b->next_free = (sdata *) ((char *) data + needed + GC_STRING_EXTRA); eassert ((uintptr_t) b->next_free % alignof (sdata) == 0); @@ -1998,12 +2115,16 @@ sweep_strings (void) int i, nfree = 0; struct Lisp_String *free_list_before = string_free_list; + ASAN_UNPOISON_STRING_BLOCK (b); + next = b->next; for (i = 0; i < STRING_BLOCK_SIZE; ++i) { struct Lisp_String *s = b->strings + i; + ASAN_UNPOISON_STRING (s); + if (s->u.s.data) { /* String was not on free-list before. */ @@ -2040,6 +2161,8 @@ sweep_strings (void) /* Put the string on the free-list. */ NEXT_FREE_LISP_STRING (s) = string_free_list; + ASAN_POISON_STRING (s); + ASAN_PREPARE_DEAD_SDATA (data, SDATA_NBYTES (data)); string_free_list = s; ++nfree; } @@ -2048,6 +2171,8 @@ sweep_strings (void) { /* S was on the free-list before. Put it there again. */ NEXT_FREE_LISP_STRING (s) = string_free_list; + ASAN_POISON_STRING (s); + string_free_list = s; ++nfree; } @@ -2174,6 +2299,7 @@ compact_small_strings (void) if (from != to) { eassert (tb != b || to < from); + ASAN_PREPARE_LIVE_SDATA (to, nbytes); memmove (to, from, size + GC_STRING_EXTRA); to->string->u.s.data = SDATA_DATA (to); } @@ -2525,6 +2651,7 @@ pin_string (Lisp_Object string) memcpy (s->u.s.data, data, size); old_sdata->string = NULL; SDATA_NBYTES (old_sdata) = size; + ASAN_PREPARE_DEAD_SDATA (old_sdata, size); } s->u.s.size_byte = -3; } @@ -2582,6 +2709,24 @@ struct float_block #define XFLOAT_UNMARK(fptr) \ UNSETMARKBIT (FLOAT_BLOCK (fptr), FLOAT_INDEX ((fptr))) +#if GC_ASAN_POISON_OBJECTS +# define ASAN_POISON_FLOAT_BLOCK(fblk) \ + __asan_poison_memory_region ((fblk)->floats, \ + sizeof ((fblk)->floats)) +# define ASAN_UNPOISON_FLOAT_BLOCK(fblk) \ + __asan_unpoison_memory_region ((fblk)->floats, \ + sizeof ((fblk)->floats)) +# define ASAN_POISON_FLOAT(p) \ + __asan_poison_memory_region ((p), sizeof (struct Lisp_Float)) +# define ASAN_UNPOISON_FLOAT(p) \ + __asan_unpoison_memory_region ((p), sizeof (struct Lisp_Float)) +#else +# define ASAN_POISON_FLOAT_BLOCK(fblk) ((void) 0) +# define ASAN_UNPOISON_FLOAT_BLOCK(fblk) ((void) 0) +# define ASAN_POISON_FLOAT(p) ((void) 0) +# define ASAN_UNPOISON_FLOAT(p) ((void) 0) +#endif + /* Current float_block. */ static struct float_block *float_block; @@ -2606,6 +2751,7 @@ make_float (double float_value) if (float_free_list) { XSETFLOAT (val, float_free_list); + ASAN_UNPOISON_FLOAT (float_free_list); float_free_list = float_free_list->u.chain; } else @@ -2616,9 +2762,11 @@ make_float (double float_value) = lisp_align_malloc (sizeof *new, MEM_TYPE_FLOAT); new->next = float_block; memset (new->gcmarkbits, 0, sizeof new->gcmarkbits); + ASAN_POISON_FLOAT_BLOCK (new); float_block = new; float_block_index = 0; } + ASAN_UNPOISON_FLOAT (&float_block->floats[float_block_index]); XSETFLOAT (val, &float_block->floats[float_block_index]); float_block_index++; } @@ -2690,6 +2838,19 @@ static int cons_block_index = CONS_BLOCK_SIZE; static struct Lisp_Cons *cons_free_list; +#if GC_ASAN_POISON_OBJECTS +# define ASAN_POISON_CONS_BLOCK(b) \ + __asan_poison_memory_region ((b)->conses, sizeof ((b)->conses)) +# define ASAN_POISON_CONS(p) \ + __asan_poison_memory_region ((p), sizeof (struct Lisp_Cons)) +# define ASAN_UNPOISON_CONS(p) \ + __asan_unpoison_memory_region ((p), sizeof (struct Lisp_Cons)) +#else +# define ASAN_POISON_CONS_BLOCK(b) ((void) 0) +# define ASAN_POISON_CONS(p) ((void) 0) +# define ASAN_UNPOISON_CONS(p) ((void) 0) +#endif + /* Explicitly free a cons cell by putting it on the free-list. */ void @@ -2700,6 +2861,7 @@ free_cons (struct Lisp_Cons *ptr) cons_free_list = ptr; ptrdiff_t nbytes = sizeof *ptr; tally_consing (-nbytes); + ASAN_POISON_CONS (ptr); } DEFUN ("cons", Fcons, Scons, 2, 2, 0, @@ -2712,6 +2874,7 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0, if (cons_free_list) { + ASAN_UNPOISON_CONS (cons_free_list); XSETCONS (val, cons_free_list); cons_free_list = cons_free_list->u.s.u.chain; } @@ -2722,10 +2885,12 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0, struct cons_block *new = lisp_align_malloc (sizeof *new, MEM_TYPE_CONS); memset (new->gcmarkbits, 0, sizeof new->gcmarkbits); + ASAN_POISON_CONS_BLOCK (new); new->next = cons_block; cons_block = new; cons_block_index = 0; } + ASAN_UNPOISON_CONS (&cons_block->conses[cons_block_index]); XSETCONS (val, &cons_block->conses[cons_block_index]); cons_block_index++; } @@ -2980,6 +3145,19 @@ static struct large_vector *large_vectors; Lisp_Object zero_vector; +#if GC_ASAN_POISON_OBJECTS +# define ASAN_POISON_VECTOR_CONTENTS(v, bytes) \ + __asan_poison_memory_region ((v)->contents, (bytes)) +# define ASAN_UNPOISON_VECTOR_CONTENTS(v, bytes) \ + __asan_unpoison_memory_region ((v)->contents, (bytes)) +# define ASAN_UNPOISON_VECTOR_BLOCK(b) \ + __asan_unpoison_memory_region ((b)->data, sizeof ((b)->data)) +#else +# define ASAN_POISON_VECTOR_CONTENTS(v, bytes) ((void) 0) +# define ASAN_UNPOISON_VECTOR_CONTENTS(v, bytes) ((void) 0) +# define ASAN_UNPOISON_VECTOR_BLOCK(b) ((void) 0) +#endif + /* Common shortcut to setup vector on a free list. */ static void @@ -2992,6 +3170,7 @@ setup_on_free_list (struct Lisp_Vector *v, ptrdiff_t nbytes) ptrdiff_t vindex = VINDEX (nbytes); eassert (vindex < VECTOR_MAX_FREE_LIST_INDEX); set_next_vector (v, vector_free_lists[vindex]); + ASAN_POISON_VECTOR_CONTENTS (v, nbytes - header_size); vector_free_lists[vindex] = v; } @@ -3039,6 +3218,7 @@ allocate_vector_from_block (ptrdiff_t nbytes) if (vector_free_lists[index]) { vector = vector_free_lists[index]; + ASAN_UNPOISON_VECTOR_CONTENTS (vector, nbytes - header_size); vector_free_lists[index] = next_vector (vector); return vector; } @@ -3052,12 +3232,18 @@ allocate_vector_from_block (ptrdiff_t nbytes) { /* This vector is larger than requested. */ vector = vector_free_lists[index]; + ASAN_UNPOISON_VECTOR_CONTENTS (vector, nbytes - header_size); vector_free_lists[index] = next_vector (vector); /* Excess bytes are used for the smaller vector, which should be set on an appropriate free list. */ restbytes = index * roundup_size + VBLOCK_BYTES_MIN - nbytes; eassert (restbytes % roundup_size == 0); +#if GC_ASAN_POISON_OBJECTS + /* Ensure that accessing excess bytes does not trigger ASan. */ + __asan_unpoison_memory_region (ADVANCE (vector, nbytes), + restbytes); +#endif setup_on_free_list (ADVANCE (vector, nbytes), restbytes); return vector; } @@ -3233,6 +3419,7 @@ sweep_vectors (void) for (vector = (struct Lisp_Vector *) block->data; VECTOR_IN_BLOCK (vector, block); vector = next) { + ASAN_UNPOISON_VECTOR_BLOCK (block); if (XVECTOR_MARKED_P (vector)) { XUNMARK_VECTOR (vector); @@ -3608,6 +3795,23 @@ struct symbol_block struct symbol_block *next; }; +#if GC_ASAN_POISON_OBJECTS +# define ASAN_POISON_SYMBOL_BLOCK(s) \ + __asan_poison_memory_region ((s)->symbols, sizeof ((s)->symbols)) +# define ASAN_UNPOISON_SYMBOL_BLOCK(s) \ + __asan_unpoison_memory_region ((s)->symbols, sizeof ((s)->symbols)) +# define ASAN_POISON_SYMBOL(sym) \ + __asan_poison_memory_region ((sym), sizeof (*(sym))) +# define ASAN_UNPOISON_SYMBOL(sym) \ + __asan_unpoison_memory_region ((sym), sizeof (*(sym))) + +#else +# define ASAN_POISON_SYMBOL_BLOCK(s) ((void) 0) +# define ASAN_UNPOISON_SYMBOL_BLOCK(s) ((void) 0) +# define ASAN_POISON_SYMBOL(sym) ((void) 0) +# define ASAN_UNPOISON_SYMBOL(sym) ((void) 0) +#endif + /* Current symbol block and index of first unused Lisp_Symbol structure in it. */ @@ -3661,6 +3865,7 @@ Its value is void, and its function definition and property list are nil. */) if (symbol_free_list) { + ASAN_UNPOISON_SYMBOL (symbol_free_list); XSETSYMBOL (val, symbol_free_list); symbol_free_list = symbol_free_list->u.s.next; } @@ -3670,10 +3875,13 @@ Its value is void, and its function definition and property list are nil. */) { struct symbol_block *new = lisp_malloc (sizeof *new, false, MEM_TYPE_SYMBOL); + ASAN_POISON_SYMBOL_BLOCK (new); new->next = symbol_block; symbol_block = new; symbol_block_index = 0; } + + ASAN_UNPOISON_SYMBOL (&symbol_block->symbols[symbol_block_index]); XSETSYMBOL (val, &symbol_block->symbols[symbol_block_index]); symbol_block_index++; } @@ -4561,6 +4769,11 @@ static struct Lisp_String * live_string_holding (struct mem_node *m, void *p) { eassert (m->type == MEM_TYPE_STRING); +#if GC_ASAN_POISON_OBJECTS + if (__asan_address_is_poisoned (p)) + return NULL; +#endif + struct string_block *b = m->start; char *cp = p; ptrdiff_t offset = cp - (char *) &b->strings[0]; @@ -4577,6 +4790,10 @@ live_string_holding (struct mem_node *m, void *p) || off == offsetof (struct Lisp_String, u.s.data)) { struct Lisp_String *s = p = cp -= off; +#if GC_ASAN_POISON_OBJECTS + if (__asan_region_is_poisoned (s, sizeof (*s))) + return NULL; +#endif if (s->u.s.data) return s; } @@ -4598,6 +4815,11 @@ static struct Lisp_Cons * live_cons_holding (struct mem_node *m, void *p) { eassert (m->type == MEM_TYPE_CONS); +#if GC_ASAN_POISON_OBJECTS + if (__asan_address_is_poisoned (p)) + return NULL; +#endif + struct cons_block *b = m->start; char *cp = p; ptrdiff_t offset = cp - (char *) &b->conses[0]; @@ -4615,6 +4837,10 @@ live_cons_holding (struct mem_node *m, void *p) || off == offsetof (struct Lisp_Cons, u.s.u.cdr)) { struct Lisp_Cons *s = p = cp -= off; +#if GC_ASAN_POISON_OBJECTS + if (__asan_region_is_poisoned (s, sizeof (*s))) + return NULL; +#endif if (!deadp (s->u.s.car)) return s; } @@ -4637,6 +4863,10 @@ static struct Lisp_Symbol * live_symbol_holding (struct mem_node *m, void *p) { eassert (m->type == MEM_TYPE_SYMBOL); +#if GC_ASAN_POISON_OBJECTS + if (__asan_address_is_poisoned (p)) + return NULL; +#endif struct symbol_block *b = m->start; char *cp = p; ptrdiff_t offset = cp - (char *) &b->symbols[0]; @@ -4662,6 +4892,10 @@ live_symbol_holding (struct mem_node *m, void *p) || off == offsetof (struct Lisp_Symbol, u.s.next)) { struct Lisp_Symbol *s = p = cp -= off; +#if GC_ASAN_POISON_OBJECTS + if (__asan_region_is_poisoned (s, sizeof (*s))) + return NULL; +#endif if (!deadp (s->u.s.function)) return s; } @@ -4684,6 +4918,11 @@ static struct Lisp_Float * live_float_holding (struct mem_node *m, void *p) { eassert (m->type == MEM_TYPE_FLOAT); +#if GC_ASAN_POISON_OBJECTS + if (__asan_address_is_poisoned (p)) + return NULL; +#endif + struct float_block *b = m->start; char *cp = p; ptrdiff_t offset = cp - (char *) &b->floats[0]; @@ -4698,8 +4937,12 @@ live_float_holding (struct mem_node *m, void *p) && (b != float_block || offset / sizeof b->floats[0] < float_block_index)) { - p = cp - off; - return p; + struct Lisp_Float *f = (struct Lisp_Float *) (cp - off); +#if GC_ASAN_POISON_OBJECTS + if (__asan_region_is_poisoned (f, sizeof (*f))) + return NULL; +#endif + return f; } } return NULL; @@ -6221,6 +6464,7 @@ garbage_collect (void) #ifdef HAVE_X_WINDOWS mark_xterm (); + mark_xselect (); #endif #ifdef HAVE_NS @@ -6554,7 +6798,7 @@ mark_buffer (struct buffer *buffer) if (!BUFFER_LIVE_P (buffer)) mark_object (BVAR (buffer, undo_list)); - if (buffer->overlays) + if (!itree_empty_p (buffer->overlays)) mark_overlays (buffer->overlays->root); /* If this is an indirect buffer, mark its base buffer. */ @@ -7180,11 +7424,13 @@ sweep_conses (void) struct Lisp_Cons *acons = &cblk->conses[pos]; if (!XCONS_MARKED_P (acons)) { + ASAN_UNPOISON_CONS (&cblk->conses[pos]); this_free++; cblk->conses[pos].u.s.u.chain = cons_free_list; cons_free_list = &cblk->conses[pos]; cons_free_list->u.s.car = dead_object (); - } + ASAN_POISON_CONS (&cblk->conses[pos]); + } else { num_used++; @@ -7202,6 +7448,7 @@ sweep_conses (void) { *cprev = cblk->next; /* Unhook from the free list. */ + ASAN_UNPOISON_CONS (&cblk->conses[0]); cons_free_list = cblk->conses[0].u.s.u.chain; lisp_align_free (cblk); } @@ -7228,6 +7475,7 @@ sweep_floats (void) for (struct float_block *fblk; (fblk = *fprev); ) { int this_free = 0; + ASAN_UNPOISON_FLOAT_BLOCK (fblk); for (int i = 0; i < lim; i++) { struct Lisp_Float *afloat = &fblk->floats[i]; @@ -7235,6 +7483,7 @@ sweep_floats (void) { this_free++; fblk->floats[i].u.chain = float_free_list; + ASAN_POISON_FLOAT (&fblk->floats[i]); float_free_list = &fblk->floats[i]; } else @@ -7251,7 +7500,8 @@ sweep_floats (void) { *fprev = fblk->next; /* Unhook from the free list. */ - float_free_list = fblk->floats[0].u.chain; + ASAN_UNPOISON_FLOAT (&fblk->floats[0]); + float_free_list = fblk->floats[0].u.chain; lisp_align_free (fblk); } else @@ -7277,13 +7527,14 @@ sweep_intervals (void) for (struct interval_block *iblk; (iblk = *iprev); ) { int this_free = 0; - + ASAN_UNPOISON_INTERVAL_BLOCK (iblk); for (int i = 0; i < lim; i++) { if (!iblk->intervals[i].gcmarkbit) { set_interval_parent (&iblk->intervals[i], interval_free_list); interval_free_list = &iblk->intervals[i]; + ASAN_POISON_INTERVAL (&iblk->intervals[i]); this_free++; } else @@ -7300,6 +7551,7 @@ sweep_intervals (void) { *iprev = iblk->next; /* Unhook from the free list. */ + ASAN_UNPOISON_INTERVAL (&iblk->intervals[0]); interval_free_list = INTERVAL_PARENT (&iblk->intervals[0]); lisp_free (iblk); } @@ -7329,6 +7581,8 @@ sweep_symbols (void) for (sblk = symbol_block; sblk; sblk = *sprev) { + ASAN_UNPOISON_SYMBOL_BLOCK (sblk); + int this_free = 0; struct Lisp_Symbol *sym = sblk->symbols; struct Lisp_Symbol *end = sym + lim; @@ -7350,7 +7604,8 @@ sweep_symbols (void) sym->u.s.next = symbol_free_list; symbol_free_list = sym; symbol_free_list->u.s.function = dead_object (); - ++this_free; + ASAN_POISON_SYMBOL (sym); + ++this_free; } else { @@ -7369,6 +7624,7 @@ sweep_symbols (void) { *sprev = sblk->next; /* Unhook from the free list. */ + ASAN_UNPOISON_SYMBOL (&sblk->symbols[0]); symbol_free_list = sblk->symbols[0].u.s.next; lisp_free (sblk); } diff --git a/src/buffer.h b/src/buffer.h index 23340b4c0ee..eb32d602ad6 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -1266,8 +1266,7 @@ set_buffer_intervals (struct buffer *b, INTERVAL i) INLINE bool buffer_has_overlays (void) { - return current_buffer->overlays - && (current_buffer->overlays->root != NULL); + return !itree_empty_p (current_buffer->overlays); } /* Functions for accessing a character or byte, diff --git a/src/coding.c b/src/coding.c index 49dcd8634f3..a2e0d7040f8 100644 --- a/src/coding.c +++ b/src/coding.c @@ -651,6 +651,12 @@ growable_destination (struct coding_system *coding) consumed_chars++; \ } while (0) +/* Suppress clang warnings about consumed_chars never being used. + Although correct, the warnings are too much trouble to code around. */ +#if 13 <= __clang_major__ - defined __apple_build_version__ +# pragma clang diagnostic ignored "-Wunused-but-set-variable" +#endif + /* Safely get two bytes from the source text pointed by SRC which ends at SRC_END, and set C1 and C2 to those bytes while skipping the heading multibyte characters. If there are not enough bytes in the diff --git a/src/comp.c b/src/comp.c index 10cf7962ba1..ba549155925 100644 --- a/src/comp.c +++ b/src/comp.c @@ -531,7 +531,7 @@ load_gccjit_if_necessary (bool mandatory) #define SETJMP_NAME SETJMP /* Max number function importable by native compiled code. */ -#define F_RELOC_MAX_SIZE 1500 +#define F_RELOC_MAX_SIZE 1600 typedef struct { void *link_table[F_RELOC_MAX_SIZE]; diff --git a/src/data.c b/src/data.c index bb4d1347d72..04ac2b09ac3 100644 --- a/src/data.c +++ b/src/data.c @@ -2619,6 +2619,7 @@ bool-vector. IDX starts at 0. */) } else if (RECORDP (array)) { + CHECK_IMPURE (array, XVECTOR (array)); if (idxval < 0 || idxval >= PVSIZE (array)) args_out_of_range (array, idx); ASET (array, idxval, newelt); diff --git a/src/dispnew.c b/src/dispnew.c index 87ec83acdf3..43306043a0c 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -3188,7 +3188,7 @@ DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "", Lisp_Object tail, frame; FOR_EACH_FRAME (tail, frame) - if (FRAME_VISIBLE_P (XFRAME (frame))) + if (FRAME_REDISPLAY_P (XFRAME (frame))) redraw_frame (XFRAME (frame)); return Qnil; diff --git a/src/doc.c b/src/doc.c index df57f84603e..174341523d7 100644 --- a/src/doc.c +++ b/src/doc.c @@ -330,19 +330,7 @@ string is passed through `substitute-command-keys'. */) xsignal1 (Qvoid_function, function); if (CONSP (fun) && EQ (XCAR (fun), Qmacro)) fun = XCDR (fun); -#ifdef HAVE_NATIVE_COMP - if (!NILP (Fsubr_native_elisp_p (fun))) - doc = native_function_doc (fun); - else -#endif - if (SUBRP (fun)) - doc = make_fixnum (XSUBR (fun)->doc); -#ifdef HAVE_MODULES - else if (MODULE_FUNCTIONP (fun)) - doc = module_function_documentation (XMODULE_FUNCTION (fun)); -#endif - else - doc = call1 (Qfunction_documentation, fun); + doc = call1 (Qfunction_documentation, fun); /* If DOC is 0, it's typically because of a dumped file missing from the DOC file (bug in src/Makefile.in). */ @@ -371,6 +359,25 @@ string is passed through `substitute-command-keys'. */) return doc; } +DEFUN ("internal-subr-documentation", Fsubr_documentation, Ssubr_documentation, 1, 1, 0, + doc: /* Return the raw documentation info of a C primitive. */) + (Lisp_Object function) +{ +#ifdef HAVE_NATIVE_COMP + if (!NILP (Fsubr_native_elisp_p (function))) + return native_function_doc (function); + else +#endif + if (SUBRP (function)) + return make_fixnum (XSUBR (function)->doc); +#ifdef HAVE_MODULES + else if (MODULE_FUNCTIONP (function)) + return module_function_documentation (XMODULE_FUNCTION (function)); +#endif + else + return Qt; +} + DEFUN ("documentation-property", Fdocumentation_property, Sdocumentation_property, 2, 3, 0, doc: /* Return the documentation string that is SYMBOL's PROP property. @@ -713,6 +720,7 @@ compute the correct value for the current terminal in the nil case. */); /* Initialized by ‘main’. */ defsubr (&Sdocumentation); + defsubr (&Ssubr_documentation); defsubr (&Sdocumentation_property); defsubr (&Ssnarf_documentation); defsubr (&Stext_quoting_style); diff --git a/src/emacs-module.h.in b/src/emacs-module.h.in index 6a23aa708e4..a455c41a5f1 100644 --- a/src/emacs-module.h.in +++ b/src/emacs-module.h.in @@ -183,6 +183,21 @@ struct emacs_env_29 @module_env_snippet_29@ }; +struct emacs_env_30 +{ +@module_env_snippet_25@ + +@module_env_snippet_26@ + +@module_env_snippet_27@ + +@module_env_snippet_28@ + +@module_env_snippet_29@ + +@module_env_snippet_30@ +}; + /* Every module should define a function as follows. */ extern int emacs_module_init (struct emacs_runtime *runtime) EMACS_NOEXCEPT diff --git a/src/eval.c b/src/eval.c index 2dd0c356e88..d42f7ffe894 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1367,7 +1367,7 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform, error ("Invalid condition handler: %s", SDATA (Fprin1_to_string (tem, Qt, Qnil))); if (CONSP (tem) && EQ (XCAR (tem), QCsuccess)) - success_handler = XCDR (tem); + success_handler = tem; else clausenb++; } @@ -1430,7 +1430,7 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform, if (!NILP (success_handler)) { if (NILP (var)) - return Fprogn (success_handler); + return Fprogn (XCDR (success_handler)); Lisp_Object handler_var = var; if (!NILP (Vinternal_interpreter_environment)) @@ -1442,7 +1442,7 @@ internal_lisp_condition_case (Lisp_Object var, Lisp_Object bodyform, specpdl_ref count = SPECPDL_INDEX (); specbind (handler_var, result); - return unbind_to (count, Fprogn (success_handler)); + return unbind_to (count, Fprogn (XCDR (success_handler))); } return result; } diff --git a/src/fileio.c b/src/fileio.c index f00c389a520..c672e0f7baf 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -134,6 +134,7 @@ static dev_t timestamp_file_system; is added here. */ static Lisp_Object Vwrite_region_annotation_buffers; +static Lisp_Object emacs_readlinkat (int, char const *); static Lisp_Object file_name_directory (Lisp_Object); static bool a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, Lisp_Object *, struct coding_system *); @@ -2219,7 +2220,7 @@ permissions. */) report_file_error ("Copying permissions to", newname); } #else /* not WINDOWSNT */ - ifd = emacs_open (SSDATA (encoded_file), O_RDONLY, 0); + ifd = emacs_open (SSDATA (encoded_file), O_RDONLY | O_NONBLOCK, 0); if (ifd < 0) report_file_error ("Opening input file", file); @@ -2705,31 +2706,19 @@ This is what happens in interactive use with M-x. */) } if (dirp) call4 (Qcopy_directory, file, newname, Qt, Qnil); - else - { - Lisp_Object symlink_target - = (S_ISLNK (file_st.st_mode) - ? check_emacs_readlinkat (AT_FDCWD, file, SSDATA (encoded_file)) - : Qnil); - if (!NILP (symlink_target)) - Fmake_symbolic_link (symlink_target, newname, ok_if_already_exists); - else if (S_ISFIFO (file_st.st_mode)) - { - /* If it's a FIFO, calling `copy-file' will hang if it's a - inter-file system move, so do it here. (It will signal - an error in that case, but it won't hang in any case.) */ - if (!NILP (ok_if_already_exists)) - barf_or_query_if_file_exists (newname, false, - "rename to it", - FIXNUMP (ok_if_already_exists), - false); - if (rename (SSDATA (encoded_file), SSDATA (encoded_newname)) != 0) - report_file_errno ("Renaming", list2 (file, newname), errno); - return Qnil; - } + else if (S_ISREG (file_st.st_mode)) + Fcopy_file (file, newname, ok_if_already_exists, Qt, Qt, Qt); + else if (S_ISLNK (file_st.st_mode)) + { + Lisp_Object target = emacs_readlinkat (AT_FDCWD, + SSDATA (encoded_file)); + if (!NILP (target)) + Fmake_symbolic_link (target, newname, ok_if_already_exists); else - Fcopy_file (file, newname, ok_if_already_exists, Qt, Qt, Qt); + report_file_error ("Renaming", list2 (file, newname)); } + else + report_file_errno ("Renaming", list2 (file, newname), rename_errno); specpdl_ref count = SPECPDL_INDEX (); specbind (Qdelete_by_moving_to_trash, Qnil); @@ -6345,24 +6334,6 @@ init_fileio (void) umask (realmask); valid_timestamp_file_system = 0; - - /* fsync can be a significant performance hit. Often it doesn't - suffice to make the file-save operation survive a crash. For - batch scripts, which are typically part of larger shell commands - that don't fsync other files, its effect on performance can be - significant so its utility is particularly questionable. - Hence, for now by default fsync is used only when interactive. - - For more on why fsync often fails to work on today's hardware, see: - Zheng M et al. Understanding the robustness of SSDs under power fault. - 11th USENIX Conf. on File and Storage Technologies, 2013 (FAST '13), 271-84 - https://www.usenix.org/system/files/conference/fast13/fast13-final80.pdf - - For more on why fsync does not suffice even if it works properly, see: - Roche X. Necessary step(s) to synchronize filename operations on disk. - Austin Group Defect 672, 2013-03-19 - https://austingroupbugs.net/view.php?id=672 */ - write_region_inhibit_fsync = noninteractive; } void @@ -6620,9 +6591,22 @@ file is usually more useful if it contains the deleted text. */); DEFVAR_BOOL ("write-region-inhibit-fsync", write_region_inhibit_fsync, doc: /* Non-nil means don't call fsync in `write-region'. This variable affects calls to `write-region' as well as save commands. -Setting this to nil may avoid data loss if the system loses power or -the operating system crashes. By default, it is non-nil in batch mode. */); - write_region_inhibit_fsync = 0; /* See also `init_fileio' above. */ +By default, it is non-nil. + +Although setting this to nil may avoid data loss if the system loses power, +it can be a significant performance hit in the usual case, and it doesn't +necessarily cause file-save operations to actually survive a crash. */); + + /* For more on why fsync often fails to work on today's hardware, see: + Zheng M et al. Understanding the robustness of SSDs under power fault. + 11th USENIX Conf. on File and Storage Technologies, 2013 (FAST '13), 271-84 + https://www.usenix.org/system/files/conference/fast13/fast13-final80.pdf + + For more on why fsync does not suffice even if it works properly, see: + Roche X. Necessary step(s) to synchronize filename operations on disk. + Austin Group Defect 672, 2013-03-19 + https://austingroupbugs.net/view.php?id=672 */ + write_region_inhibit_fsync = true; DEFVAR_BOOL ("delete-by-moving-to-trash", delete_by_moving_to_trash, doc: /* Specifies whether to use the system's trash can. diff --git a/src/fns.c b/src/fns.c index 3984e318feb..59d5b5c0850 100644 --- a/src/fns.c +++ b/src/fns.c @@ -501,8 +501,13 @@ Symbols are also allowed; their print names are used instead. */) int ws = sizeof (word_t); const word_t *w1 = (const word_t *) SDATA (string1); const word_t *w2 = (const word_t *) SDATA (string2); - while (b < nb - ws + 1 && w1[b / ws] == w2[b / ws]) - b += ws; + while (b < nb - ws + 1) + { + if (UNALIGNED_LOAD_SIZE (w1, b / ws) + != UNALIGNED_LOAD_SIZE (w2, b / ws)) + break; + b += ws; + } } /* Scan forward to the differing byte. */ @@ -3177,13 +3182,14 @@ DEFUN ("yes-or-no-p", Fyes_or_no_p, Syes_or_no_p, 1, 1, 0, Return t if answer is yes, and nil if the answer is no. PROMPT is the string to display to ask the question; `yes-or-no-p' -adds \"(yes or no) \" to it. +appends `yes-or-no-prompt' (default \"(yes or no) \") to it. The user must confirm the answer with RET, and can edit it until it has been confirmed. If the `use-short-answers' variable is non-nil, instead of asking for -\"yes\" or \"no\", this function will ask for \"y\" or \"n\". +\"yes\" or \"no\", this function will ask for \"y\" or \"n\" (and +ignore the value of `yes-or-no-prompt'). If dialog boxes are supported, a dialog box will be used if `last-nonmenu-event' is nil, and `use-dialog-box' is non-nil. */) @@ -3208,8 +3214,7 @@ if `last-nonmenu-event' is nil, and `use-dialog-box' is non-nil. */) if (use_short_answers) return call1 (intern ("y-or-n-p"), prompt); - AUTO_STRING (yes_or_no, "(yes or no) "); - prompt = CALLN (Fconcat, prompt, yes_or_no); + prompt = CALLN (Fconcat, prompt, Vyes_or_no_prompt); specpdl_ref count = SPECPDL_INDEX (); specbind (Qenable_recursive_minibuffers, Qt); @@ -6260,9 +6265,15 @@ When non-nil, `yes-or-no-p' will use `y-or-n-p' to read the answer. We recommend against setting this variable non-nil, because `yes-or-no-p' is intended to be used when users are expected not to respond too quickly, but to take their time and perhaps think about the answer. -The same variable also affects the function `read-answer'. */); +The same variable also affects the function `read-answer'. See also +`yes-or-no-prompt'. */); use_short_answers = false; + DEFVAR_LISP ("yes-or-no-prompt", Vyes_or_no_prompt, + doc: /* String to append when `yes-or-no-p' asks a question. +For best results this should end in a space. */); + Vyes_or_no_prompt = make_unibyte_string ("(yes or no) ", strlen ("(yes or no) ")); + defsubr (&Sidentity); defsubr (&Srandom); defsubr (&Slength); diff --git a/src/frame.c b/src/frame.c index 38a6583605c..983424b0bee 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1892,12 +1892,61 @@ other_frames (struct frame *f, bool invisible, bool force) if (f != f1) { + /* The following code is defined out because it is + responsible for a performance drop under X connections + over a network, and its purpose is unclear. XSync does + not handle events (or call any callbacks defined by + Emacs), and as such it should not note any "recent change + in visibility". + + When writing new code, please try as hard as possible to + avoid calls that require a roundtrip to the X server. + When such calls are inevitable, use the XCB library to + handle multiple consecutive requests with a data reply in + a more asynchronous fashion. The following code + demonstrates why: + + rc = XGetWindowProperty (dpyinfo->display, window, ... + status = XGrabKeyboard (dpyinfo->display, ... + + here, `XGetWindowProperty' will wait for a reply from the + X server before returning, and thus allowing Emacs to + make the XGrabKeyboard request, which in itself also + requires waiting a reply. When XCB is available, this + code could be written: + +#ifdef HAVE_XCB + xcb_get_property_cookie_t cookie1; + xcb_get_property_reply_t *reply1; + xcb_grab_keyboard_cookie_t cookie2; + xcb_grab_keyboard_reply_t *reply2; + + cookie1 = xcb_get_property (dpyinfo->xcb_connection, window, ... + cookie2 = xcb_grab_keyboard (dpyinfo->xcb_connection, ... + reply1 = xcb_get_property_reply (dpyinfo->xcb_connection, + cookie1); + reply2 = xcb_grab_keyboard_reply (dpyinfo->xcb_connection, + cookie2); +#endif + + In this code, the GetProperty and GrabKeyboard requests + are made simultaneously, and replies are then obtained + from the server at once, avoiding the extraneous + roundtrip to the X server after the call to + `XGetWindowProperty'. + + However, please keep an alternative implementation + available for use when Emacs is built without XCB. */ + +#if 0 /* Verify that we can still talk to the frame's X window, and note any recent change in visibility. */ #ifdef HAVE_X_WINDOWS if (FRAME_WINDOW_P (f1)) x_sync (f1); #endif +#endif + if (!FRAME_TOOLTIP_P (f1) /* Tooltips and child frames count neither for invisibility nor for deletions. */ diff --git a/src/frame.h b/src/frame.h index 4a4c8c38447..b95b94c7685 100644 --- a/src/frame.h +++ b/src/frame.h @@ -1010,6 +1010,20 @@ default_pixels_per_inch_y (void) /* True if frame F is currently visible. */ #define FRAME_VISIBLE_P(f) (f)->visible +/* True if frame F should be redisplayed. This is normally the same + as FRAME_VISIBLE_P (f). Under X, frames can continue to be + displayed to the user by the compositing manager even if they are + invisible, so this also checks whether or not the frame is reported + visible by the X server. */ + +#ifndef HAVE_X_WINDOWS +#define FRAME_REDISPLAY_P(f) (FRAME_VISIBLE_P (f)) +#else +#define FRAME_REDISPLAY_P(f) (FRAME_VISIBLE_P (f) \ + || (FRAME_X_P (f) \ + && FRAME_X_VISIBLE (f))) +#endif + /* True if frame F is currently visible but hidden. */ #define FRAME_OBSCURED_P(f) ((f)->visible > 1) @@ -1718,7 +1732,6 @@ extern void x_wm_set_icon_position (struct frame *, int, int); #if !defined USE_X_TOOLKIT extern const char *x_get_resource_string (const char *, const char *); #endif -extern void x_sync (struct frame *); #endif /* HAVE_X_WINDOWS */ #if !defined (HAVE_NS) && !defined (HAVE_PGTK) diff --git a/src/gnutls.c b/src/gnutls.c index 91e369375f2..ca7e9fc4c73 100644 --- a/src/gnutls.c +++ b/src/gnutls.c @@ -34,6 +34,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ # endif # if GNUTLS_VERSION_NUMBER >= 0x030200 +# define HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 # define HAVE_GNUTLS_CIPHER_GET_IV_SIZE # endif @@ -121,6 +122,11 @@ DEF_DLL_FN (int, gnutls_certificate_set_x509_crl_file, DEF_DLL_FN (int, gnutls_certificate_set_x509_key_file, (gnutls_certificate_credentials_t, const char *, const char *, gnutls_x509_crt_fmt_t)); +# ifdef HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 +DEF_DLL_FN (int, gnutls_certificate_set_x509_key_file2, + (gnutls_certificate_credentials_t, const char *, const char *, + gnutls_x509_crt_fmt_t, const char *, unsigned int)); +# endif # ifdef HAVE_GNUTLS_X509_SYSTEM_TRUST DEF_DLL_FN (int, gnutls_certificate_set_x509_system_trust, (gnutls_certificate_credentials_t)); @@ -314,6 +320,9 @@ init_gnutls_functions (void) LOAD_DLL_FN (library, gnutls_certificate_set_verify_flags); LOAD_DLL_FN (library, gnutls_certificate_set_x509_crl_file); LOAD_DLL_FN (library, gnutls_certificate_set_x509_key_file); +# ifdef HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 + LOAD_DLL_FN (library, gnutls_certificate_set_x509_key_file2); +# endif # ifdef HAVE_GNUTLS_X509_SYSTEM_TRUST LOAD_DLL_FN (library, gnutls_certificate_set_x509_system_trust); # endif @@ -455,6 +464,9 @@ init_gnutls_functions (void) # define gnutls_certificate_set_verify_flags fn_gnutls_certificate_set_verify_flags # define gnutls_certificate_set_x509_crl_file fn_gnutls_certificate_set_x509_crl_file # define gnutls_certificate_set_x509_key_file fn_gnutls_certificate_set_x509_key_file +# ifdef HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 +# define gnutls_certificate_set_x509_key_file2 fn_gnutls_certificate_set_x509_key_file2 +# endif # define gnutls_certificate_set_x509_system_trust fn_gnutls_certificate_set_x509_system_trust # define gnutls_certificate_set_x509_trust_file fn_gnutls_certificate_set_x509_trust_file # define gnutls_certificate_type_get fn_gnutls_certificate_type_get @@ -1774,6 +1786,88 @@ gnutls_verify_boot (Lisp_Object proc, Lisp_Object proplist) return gnutls_make_error (ret); } +#ifdef HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 + +/* Helper function for gnutls-boot. + + The key :flags receives a list of symbols, each of which + corresponds to a GnuTLS C flag, the ORed result is to be passed to + the function `gnutls_certificate_set_x509_key_file2' as its last + argument. */ +static unsigned int +key_file2_aux (Lisp_Object flags) +{ + unsigned int rv = 0; + Lisp_Object tail = flags; + FOR_EACH_TAIL_SAFE (tail) + { + Lisp_Object flag = XCAR (tail); + if (EQ (flag, Qgnutls_pkcs_plain)) + rv |= GNUTLS_PKCS_PLAIN; +#ifdef GNUTLS_PKCS_PKCS12_3DES + else if (EQ (flag, Qgnutls_pkcs_pkcs12_3des)) + rv |= GNUTLS_PKCS_PKCS12_3DES; +#endif +#ifdef GNUTLS_PKCS_PKCS12_ARCFOUR + else if (EQ (flag, Qgnutls_pkcs_pkcs12_arcfour)) + rv |= GNUTLS_PKCS_PKCS12_ARCFOUR; +#endif +#ifdef GNUTLS_PKCS_PKCS12_RC2_40 + else if (EQ (flag, Qgnutls_pkcs_pkcs12_rc2_40)) + rv |= GNUTLS_PKCS_PKCS12_RC2_40; +#endif +#ifdef GNUTLS_PKCS_PBES2_3DES + else if (EQ (flag, Qgnutls_pkcs_pbes2_3des)) + rv |= GNUTLS_PKCS_PBES2_3DES; +#endif +#ifdef GNUTLS_PKCS_PBES2_AES_128 + else if (EQ (flag, Qgnutls_pkcs_pbes2_aes_128)) + rv |= GNUTLS_PKCS_PBES2_AES_128; +#endif +#ifdef GNUTLS_PKCS_PBES2_AES_192 + else if (EQ (flag, Qgnutls_pkcs_pbes2_aes_192)) + rv |= GNUTLS_PKCS_PBES2_AES_192; +#endif +#ifdef GNUTLS_PKCS_PBES2_AES_256 + else if (EQ (flag, Qgnutls_pkcs_pbes2_aes_256)) + rv |= GNUTLS_PKCS_PBES2_AES_256; +#endif + else if (EQ (flag, Qgnutls_pkcs_null_password)) + rv |= GNUTLS_PKCS_NULL_PASSWORD; +#ifdef GNUTLS_PKCS_PBES2_DES + else if (EQ (flag, Qgnutls_pkcs_pbes2_des)) + rv |= GNUTLS_PKCS_PBES2_DES; +#endif +#ifdef GNUTLS_PKCS_PBES1_DES_MD5 + else if (EQ (flag, Qgnutls_pkcs_pbes1_des_md5)) + rv |= GNUTLS_PKCS_PBES1_DES_MD5; +#endif +#ifdef GNUTLS_PKCS_PBES2_GOST_TC26Z + else if (EQ (flag, Qgnutls_pkcs_pbes2_gost_tc26z)) + rv |= GNUTLS_PKCS_PBES2_GOST_TC26Z; +#endif +#ifdef GNUTLS_PKCS_PBES2_GOST_CPA + else if (EQ (flag, Qgnutls_pkcs_pbes2_gost_cpa)) + rv |= GNUTLS_PKCS_PBES2_GOST_CPA; +#endif +#ifdef GNUTLS_PKCS_PBES2_GOST_CPB + else if (EQ (flag, Qgnutls_pkcs_pbes2_gost_cpb)) + rv |= GNUTLS_PKCS_PBES2_GOST_CPB; +#endif +#ifdef GNUTLS_PKCS_PBES2_GOST_CPC + else if (EQ (flag, Qgnutls_pkcs_pbes2_gost_cpc)) + rv |= GNUTLS_PKCS_PBES2_GOST_CPC; +#endif +#ifdef GNUTLS_PKCS_PBES2_GOST_CPD + else if (EQ (flag, Qgnutls_pkcs_pbes2_gost_cpd)) + rv |= GNUTLS_PKCS_PBES2_GOST_CPD; +#endif + } + return rv; +} + +#endif /* HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 */ + DEFUN ("gnutls-boot", Fgnutls_boot, Sgnutls_boot, 3, 3, 0, doc: /* Initialize GnuTLS client for process PROC with TYPE+PROPLIST. Currently only client mode is supported. Return a success/failure @@ -1813,6 +1907,22 @@ accept in Diffie-Hellman key exchange. :complete-negotiation, if non-nil, will make negotiation complete before returning even on non-blocking sockets. +:pass, the password of the private key as per GnuTLS' +gnutls_certificate_set_x509_key_file2. Specify as nil to have a NULL +password. + +:flags, a list of symbols relating to :pass, each specifying a flag: +GNUTLS_PKCS_PLAIN, GNUTLS_PKCS_PKCS12_3DES, +GNUTLS_PKCS_PKCS12_ARCFOUR, GNUTLS_PKCS_PKCS12_RC2_40, +GNUTLS_PKCS_PBES2_3DES, GNUTLS_PKCS_PBES2_AES_128, +GNUTLS_PKCS_PBES2_AES_192, GNUTLS_PKCS_PBES2_AES_256, +GNUTLS_PKCS_NULL_PASSWORD, GNUTLS_PKCS_PBES2_DES, +GNUTLS_PKCS_PBES2_DES_MD5, GNUTLS_PKCS_PBES2_GOST_TC26Z, +GNUTLS_PKCS_PBES2_GOST_CPA, GNUTLS_PKCS_PBES2_GOST_CPB, +GNUTLS_PKCS_PBES2_GOST_CPC, GNUTLS_PKCS_PBES2_GOST_CPD. If not +specified, or if nil, the bitflag with value 0 is used. +Note that some of these are only supported since GnuTLS 3.6.3. + The debug level will be set for this process AND globally for GnuTLS. So if you set it higher or lower at any point, it affects global debugging. @@ -1825,6 +1935,9 @@ Processes must be initialized with this function before other GnuTLS functions are used. This function allocates resources which can only be deallocated by calling `gnutls-deinit' or by calling it again. +The :pass and :flags keys are ignored with old versions of GnuTLS, and +:flags is ignored if :pass is not specified. + The callbacks alist can have a `verify' key, associated with a verification function (UNUSED). @@ -1842,16 +1955,22 @@ one trustfile (usually a CA bundle). */) Lisp_Object global_init; char const *priority_string_ptr = "NORMAL"; /* default priority string. */ char *c_hostname; + const char *c_pass; /* Placeholders for the property list elements. */ Lisp_Object priority_string; Lisp_Object trustfiles; Lisp_Object crlfiles; Lisp_Object keylist; + Lisp_Object pass; + Lisp_Object flags; /* Lisp_Object callbacks; */ Lisp_Object loglevel; Lisp_Object hostname; Lisp_Object prime_bits; +#ifdef HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 + unsigned int aux_key_file; +#endif struct Lisp_Process *p = XPROCESS (proc); CHECK_PROCESS (proc); @@ -1877,6 +1996,13 @@ one trustfile (usually a CA bundle). */) crlfiles = plist_get (proplist, QCcrlfiles); loglevel = plist_get (proplist, QCloglevel); prime_bits = plist_get (proplist, QCmin_prime_bits); + pass = plist_get (proplist, QCpass); + flags = plist_get (proplist, QCflags); + + if (STRINGP (pass)) + c_pass = SSDATA (pass); + else + c_pass = NULL; if (!STRINGP (hostname)) { @@ -2038,6 +2164,20 @@ one trustfile (usually a CA bundle). */) keyfile = ansi_encode_filename (keyfile); certfile = ansi_encode_filename (certfile); # endif +# ifdef HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 + if (!NILP (plist_member (proplist, QCpass))) + { + aux_key_file = key_file2_aux (flags); + ret + = gnutls_certificate_set_x509_key_file2 (x509_cred, + SSDATA (certfile), + SSDATA (keyfile), + file_format, + c_pass, + aux_key_file); + } + else +# endif ret = gnutls_certificate_set_x509_key_file (x509_cred, SSDATA (certfile), SSDATA (keyfile), file_format); @@ -2265,6 +2405,9 @@ gnutls_symmetric_aead (bool encrypting, gnutls_cipher_algorithm_t gca, aead_auth_size = aend_byte - astart_byte; } + /* Only block ciphers require that ISIZE be a multiple of the block + size, and AEAD ciphers are not block ciphers. */ +#if 0 ptrdiff_t expected_remainder = encrypting ? 0 : cipher_tag_size; ptrdiff_t cipher_block_size = gnutls_cipher_get_block_size (gca); @@ -2274,6 +2417,7 @@ gnutls_symmetric_aead (bool encrypting, gnutls_cipher_algorithm_t gca, "is not %"pD"d greater than a multiple of the required %"pD"d"), gnutls_cipher_get_name (gca), desc, isize, expected_remainder, cipher_block_size); +#endif ret = ((encrypting ? gnutls_aead_cipher_encrypt : gnutls_aead_cipher_decrypt) (acipher, vdata, vsize, aead_auth_data, aead_auth_size, @@ -2282,7 +2426,7 @@ gnutls_symmetric_aead (bool encrypting, gnutls_cipher_algorithm_t gca, Lisp_Object output; if (GNUTLS_E_SUCCESS <= ret) output = make_unibyte_string (storage, storage_length); - explicit_bzero (storage, storage_length); + memset_explicit (storage, 0, storage_length); gnutls_aead_cipher_deinit (acipher); if (ret < GNUTLS_E_SUCCESS) @@ -2862,8 +3006,26 @@ level in the ones. For builds without libgnutls, the value is -1. */); DEFSYM (QCmin_prime_bits, ":min-prime-bits"); DEFSYM (QCloglevel, ":loglevel"); DEFSYM (QCcomplete_negotiation, ":complete-negotiation"); + DEFSYM (QCpass, ":pass"); + DEFSYM (QCflags, ":flags"); DEFSYM (QCverify_flags, ":verify-flags"); DEFSYM (QCverify_error, ":verify-error"); + DEFSYM (Qgnutls_pkcs_plain, "GNUTLS_PKCS_PLAIN"); + DEFSYM (Qgnutls_pkcs_pkcs12_3des, "GNUTLS_PKCS_PKCS12_3DES"); + DEFSYM (Qgnutls_pkcs_pkcs12_arcfour, "GNUTLS_PKCS_PKCS12_ARCFOUR"); + DEFSYM (Qgnutls_pkcs_pkcs12_rc2_40, "GNUTLS_PKCS_PKCS12_RC2_40"); + DEFSYM (Qgnutls_pkcs_pbes2_3des, "GNUTLS_PKCS_PBES2_3DES"); + DEFSYM (Qgnutls_pkcs_pbes2_aes_128, "GNUTLS_PKCS_PBES2_AES_128"); + DEFSYM (Qgnutls_pkcs_pbes2_aes_192, "GNUTLS_PKCS_PBES2_AES_192"); + DEFSYM (Qgnutls_pkcs_pbes2_aes_256, "GNUTLS_PKCS_PBES2_AES_256"); + DEFSYM (Qgnutls_pkcs_null_password, "GNUTLS_PKCS_NULL_PASSWORD"); + DEFSYM (Qgnutls_pkcs_pbes2_des, "GNUTLS_PKCS_PBES2_DES"); + DEFSYM (Qgnutls_pkcs_pbes1_des_md5, "GNUTLS_PKCS_PBES1_DES_MD5"); + DEFSYM (Qgnutls_pkcs_pbes2_gost_tc26z, "GNUTLS_PKCS_PBES2_GOST_TC26Z"); + DEFSYM (Qgnutls_pkcs_pbes2_gost_cpa, "GNUTLS_PKCS_PBES2_GOST_CPA"); + DEFSYM (Qgnutls_pkcs_pbes2_gost_cpb, "GNUTLS_PKCS_PBES2_GOST_CPB"); + DEFSYM (Qgnutls_pkcs_pbes2_gost_cpc, "GNUTLS_PKCS_PBES2_GOST_CPC"); + DEFSYM (Qgnutls_pkcs_pbes2_gost_cpd, "GNUTLS_PKCS_PBES2_GOST_CPD"); DEFSYM (QCcipher_id, ":cipher-id"); DEFSYM (QCcipher_aead_capable, ":cipher-aead-capable"); diff --git a/src/gtkutil.c b/src/gtkutil.c index f5e70305ead..4cc0f9f15b4 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -2103,7 +2103,7 @@ xg_frame_restack (struct frame *f1, struct frame *f2, bool above_flag) gdk_window_restack (gwin1, gwin2, above_flag); #ifndef HAVE_PGTK - x_sync (f1); + XSync (FRAME_X_DISPLAY (f1), False); #else gdk_flush (); #endif @@ -4793,7 +4793,7 @@ xg_update_scrollbar_pos (struct frame *f, here to get some events. */ #ifndef HAVE_PGTK - x_sync (f); + XSync (FRAME_X_DISPLAY (f), False); #else gdk_flush (); #endif @@ -4894,7 +4894,7 @@ xg_update_horizontal_scrollbar_pos (struct frame *f, } #ifndef HAVE_PGTK - x_sync (f); + XSync (FRAME_X_DISPLAY (f), False); #else gdk_flush (); #endif diff --git a/src/haikufont.c b/src/haikufont.c index 4599ca40c47..a025dec58bb 100644 --- a/src/haikufont.c +++ b/src/haikufont.c @@ -754,7 +754,7 @@ haikufont_encode_char (struct font *font, int c) } static Lisp_Object -haikufont_open (struct frame *f, Lisp_Object font_entity, int x) +haikufont_open (struct frame *f, Lisp_Object font_entity, int pixel_size) { struct haikufont_info *font_info; struct haiku_font_pattern ptn; @@ -765,11 +765,19 @@ haikufont_open (struct frame *f, Lisp_Object font_entity, int x) int avg_width, height, space_width, ascent; int descent, underline_pos, underline_thickness; - if (x <= 0) + if (XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX)) != 0) + pixel_size = XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX)); + else if (pixel_size == 0) { - /* Get pixel size from frame instead. */ - tem = get_frame_param (f, Qfontsize); - x = NILP (tem) ? 0 : XFIXNAT (tem); + /* Try to resolve a suitable size for the font, if the font size + has not already been specified. First, if FRAME_FONT is set, + use its size. Otherwise, use 12, which is the default on + Haiku. */ + + if (FRAME_FONT (f)) + pixel_size = FRAME_FONT (f)->pixel_size; + else + pixel_size = 12; } extra = AREF (font_entity, FONT_EXTRA_INDEX); @@ -788,7 +796,8 @@ haikufont_open (struct frame *f, Lisp_Object font_entity, int x) { block_input (); be_font = be_open_font_at_index (XFIXNUM (XCAR (indices)), - XFIXNUM (XCDR (indices)), x); + XFIXNUM (XCDR (indices)), + pixel_size); unblock_input (); if (!be_font) @@ -799,7 +808,7 @@ haikufont_open (struct frame *f, Lisp_Object font_entity, int x) block_input (); haikufont_spec_or_entity_to_pattern (font_entity, 1, &ptn); - if (BFont_open_pattern (&ptn, &be_font, x)) + if (BFont_open_pattern (&ptn, &be_font, pixel_size)) { haikufont_done_with_query_pattern (&ptn); unblock_input (); @@ -813,7 +822,7 @@ haikufont_open (struct frame *f, Lisp_Object font_entity, int x) block_input (); font_object = font_make_object (VECSIZE (struct haikufont_info), - font_entity, x); + font_entity, pixel_size); ASET (font_object, FONT_TYPE_INDEX, Qhaiku); font_info = (struct haikufont_info *) XFONT_OBJECT (font_object); diff --git a/src/itree.c b/src/itree.c index b8db08bc74c..bd3e62a374a 100644 --- a/src/itree.c +++ b/src/itree.c @@ -1376,7 +1376,7 @@ itree_iterator_first_node (struct itree_tree *tree, return node; } -/* Start a iterator enumerating all intervals in [BEGIN,END) in the +/* Start an iterator enumerating all intervals in [BEGIN,END) in the given ORDER. */ struct itree_iterator * diff --git a/src/itree.h b/src/itree.h index 8f675fd43bc..79d03d31ce2 100644 --- a/src/itree.h +++ b/src/itree.h @@ -25,6 +25,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "lisp.h" +INLINE_HEADER_BEGIN + /* The tree and node structs are mainly here, so they can be allocated. @@ -114,6 +116,11 @@ extern void itree_node_set_region (struct itree_tree *, struct itree_node *, ptrdiff_t, ptrdiff_t); extern struct itree_tree *itree_create (void); extern void itree_destroy (struct itree_tree *); +INLINE bool +itree_empty_p (struct itree_tree *tree) +{ + return !tree || !tree->root; +} extern intmax_t itree_size (struct itree_tree *); extern void itree_clear (struct itree_tree *); extern void itree_insert (struct itree_tree *, struct itree_node *, @@ -178,4 +185,6 @@ struct itree_iterator #define ITREE_FOREACH_NARROW(beg, end) \ itree_iterator_narrow (itree_iter_, beg, end) +INLINE_HEADER_END + #endif diff --git a/src/lisp.h b/src/lisp.h index 70555b3ce91..e6ee6444273 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -22,7 +22,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <alloca.h> #include <setjmp.h> -#include <stdalign.h> #include <stdarg.h> #include <stddef.h> #include <string.h> @@ -5296,6 +5295,26 @@ __lsan_ignore_object (void const *p) } #endif +/* If built with USE_SANITIZER_UNALIGNED_LOAD defined, use compiler + provided ASan functions to perform unaligned loads, allowing ASan + to catch bugs which it might otherwise miss. */ +#if defined HAVE_SANITIZER_COMMON_INTERFACE_DEFS_H \ + && defined ADDRESS_SANITIZER \ + && defined USE_SANITIZER_UNALIGNED_LOAD +# include <sanitizer/common_interface_defs.h> +# if (SIZE_MAX == UINT64_MAX) +# define UNALIGNED_LOAD_SIZE(a, i) \ + (size_t) __sanitizer_unaligned_load64 ((void *) ((a) + (i))) +# elif (SIZE_MAX == UINT32_MAX) +# define UNALIGNED_LOAD_SIZE(a, i) \ + (size_t) __sanitizer_unaligned_load32 ((void *) ((a) + (i))) +# else +# define UNALIGNED_LOAD_SIZE(a, i) *((a) + (i)) +# endif +#else +# define UNALIGNED_LOAD_SIZE(a, i) *((a) + (i)) +#endif + extern void xputenv (const char *); extern char *egetenv_internal (const char *, ptrdiff_t); diff --git a/src/module-env-29.h b/src/module-env-29.h index 6ca03773181..e69de29bb2d 100644 --- a/src/module-env-29.h +++ b/src/module-env-29.h @@ -1,3 +0,0 @@ - /* Add module environment functions newly added in Emacs 29 here. - Before Emacs 29 is released, remove this comment and start - module-env-30.h on the master branch. */ diff --git a/src/module-env-30.h b/src/module-env-30.h new file mode 100644 index 00000000000..6ca03773181 --- /dev/null +++ b/src/module-env-30.h @@ -0,0 +1,3 @@ + /* Add module environment functions newly added in Emacs 29 here. + Before Emacs 29 is released, remove this comment and start + module-env-30.h on the master branch. */ diff --git a/src/nsterm.m b/src/nsterm.m index 4180cdc9e7f..0e75cbf3f0f 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -6703,16 +6703,8 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action) - (void)resetCursorRects { - NSRect visible; - NSCursor *currentCursor; - - /* On macOS 13, [resetCursorRects:] could be called even after the - window is closed. */ - if (! emacsframe || ! FRAME_OUTPUT_DATA (emacsframe)) - return; - - visible = [self visibleRect]; - currentCursor = FRAME_POINTER_TYPE (emacsframe); + NSRect visible = [self visibleRect]; + NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe); NSTRACE ("[EmacsView resetCursorRects]"); if (currentCursor == nil) diff --git a/src/pdumper.c b/src/pdumper.c index 800fc2e9d05..11704ca876d 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -2862,7 +2862,7 @@ dump_buffer (struct dump_context *ctx, const struct buffer *in_buffer) DUMP_FIELD_COPY (out, buffer, inhibit_buffer_hooks); DUMP_FIELD_COPY (out, buffer, long_line_optimizations_p); - if (buffer->overlays && buffer->overlays->root != NULL) + if (!itree_empty_p (buffer->overlays)) /* We haven't implemented the code to dump overlays. */ emacs_abort (); else diff --git a/src/sysdep.c b/src/sysdep.c index ce6a20f5302..a5b3117d262 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -2653,10 +2653,11 @@ emacs_perror (char const *message) int renameat_noreplace (int srcfd, char const *src, int dstfd, char const *dst) { -#if defined SYS_renameat2 && defined RENAME_NOREPLACE - return syscall (SYS_renameat2, srcfd, src, dstfd, dst, RENAME_NOREPLACE); -#elif defined CYGWIN && defined RENAME_NOREPLACE +#if HAVE_RENAMEAT2 && defined RENAME_NOREPLACE return renameat2 (srcfd, src, dstfd, dst, RENAME_NOREPLACE); +#elif defined SYS_renameat2 && defined RENAME_NOREPLACE + /* Linux kernel 3.15 (2014) or later, with glibc 2.27 (2018) or earlier. */ + return syscall (SYS_renameat2, srcfd, src, dstfd, dst, RENAME_NOREPLACE); #elif defined RENAME_EXCL return renameatx_np (srcfd, src, dstfd, dst, RENAME_EXCL); #else diff --git a/src/w32heap.c b/src/w32heap.c index a1975d9a975..628fc28e3c5 100644 --- a/src/w32heap.c +++ b/src/w32heap.c @@ -121,9 +121,9 @@ typedef struct _RTL_HEAP_PARAMETERS { # define DUMPED_HEAP_SIZE 10 #else # if defined _WIN64 || defined WIDE_EMACS_INT -# define DUMPED_HEAP_SIZE (23*1024*1024) +# define DUMPED_HEAP_SIZE (28*1024*1024) # else -# define DUMPED_HEAP_SIZE (13*1024*1024) +# define DUMPED_HEAP_SIZE (18*1024*1024) # endif #endif diff --git a/src/xdisp.c b/src/xdisp.c index d2c91e5847b..72d3bfa6398 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -12938,7 +12938,7 @@ clear_garbaged_frames (void) { struct frame *f = XFRAME (frame); - if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f)) + if (FRAME_REDISPLAY_P (f) && FRAME_GARBAGED_P (f)) { if (f->resized_p /* It makes no sense to redraw a non-selected TTY @@ -12987,7 +12987,7 @@ echo_area_display (bool update_frame_p) f = XFRAME (WINDOW_FRAME (w)); /* Don't display if frame is invisible or not yet initialized. */ - if (!FRAME_VISIBLE_P (f) || !f->glyphs_initialized_p) + if (!FRAME_REDISPLAY_P (f) || !f->glyphs_initialized_p) return; #ifdef HAVE_WINDOW_SYSTEM @@ -13543,7 +13543,7 @@ prepare_menu_bars (void) TTY frames to be completely redrawn, when there are more than one of them, even though nothing should be changed on display. */ - || (FRAME_VISIBLE_P (f) == 2 && FRAME_WINDOW_P (f)))) + || (FRAME_REDISPLAY_P (f) && FRAME_WINDOW_P (f)))) gui_consider_frame_title (frame); } } @@ -16432,7 +16432,7 @@ redisplay_internal (void) { struct frame *f = XFRAME (frame); - if (FRAME_VISIBLE_P (f)) + if (FRAME_REDISPLAY_P (f)) { ++number_of_visible_frames; /* Adjust matrices for visible frames only. */ @@ -16574,7 +16574,7 @@ redisplay_internal (void) && !w->update_mode_line && !current_buffer->clip_changed && !current_buffer->prevent_redisplay_optimizations_p - && FRAME_VISIBLE_P (XFRAME (w->frame)) + && FRAME_REDISPLAY_P (XFRAME (w->frame)) && !FRAME_OBSCURED_P (XFRAME (w->frame)) && !XFRAME (w->frame)->cursor_type_changed && !XFRAME (w->frame)->face_change @@ -16852,7 +16852,7 @@ redisplay_internal (void) if (gcscrollbars && FRAME_TERMINAL (f)->condemn_scroll_bars_hook) FRAME_TERMINAL (f)->condemn_scroll_bars_hook (f); - if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f)) + if (FRAME_REDISPLAY_P (f) && !FRAME_OBSCURED_P (f)) { /* Don't allow freeing images and faces for this frame as long as the frame's update wasn't @@ -16878,7 +16878,7 @@ redisplay_internal (void) if (gcscrollbars && FRAME_TERMINAL (f)->judge_scroll_bars_hook) FRAME_TERMINAL (f)->judge_scroll_bars_hook (f); - if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f)) + if (FRAME_REDISPLAY_P (f) && !FRAME_OBSCURED_P (f)) { /* If fonts changed on visible frame, display again. */ if (f->fonts_changed) @@ -16984,7 +16984,7 @@ redisplay_internal (void) } } } - else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf)) + else if (FRAME_REDISPLAY_P (sf) && !FRAME_OBSCURED_P (sf)) { sf->inhibit_clear_image_cache = true; displayed_buffer = XBUFFER (XWINDOW (selected_window)->contents); @@ -17035,7 +17035,7 @@ redisplay_internal (void) unrequest_sigio (); STOP_POLLING; - if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf)) + if (FRAME_REDISPLAY_P (sf) && !FRAME_OBSCURED_P (sf)) { if (hscroll_retries <= MAX_HSCROLL_RETRIES && hscroll_windows (selected_window)) @@ -17134,7 +17134,7 @@ redisplay_internal (void) FOR_EACH_FRAME (tail, frame) { - if (XFRAME (frame)->visible) + if (FRAME_REDISPLAY_P (XFRAME (frame))) new_count++; } @@ -26332,16 +26332,17 @@ display_menu_bar (struct window *w) it.first_visible_x = 0; it.last_visible_x = FRAME_PIXEL_WIDTH (f); #elif defined (HAVE_X_WINDOWS) /* X without toolkit. */ + struct window *menu_window = NULL; + struct face *face = FACE_FROM_ID (f, MENU_FACE_ID); + if (FRAME_WINDOW_P (f)) { /* Menu bar lines are displayed in the desired matrix of the dummy window menu_bar_window. */ - struct window *menu_w; - menu_w = XWINDOW (f->menu_bar_window); - init_iterator (&it, menu_w, -1, -1, menu_w->desired_matrix->rows, + menu_window = XWINDOW (f->menu_bar_window); + init_iterator (&it, menu_window, -1, -1, + menu_window->desired_matrix->rows, MENU_FACE_ID); - it.first_visible_x = 0; - it.last_visible_x = FRAME_PIXEL_WIDTH (f); } else #endif /* not USE_X_TOOLKIT and not USE_GTK */ @@ -26395,6 +26396,50 @@ display_menu_bar (struct window *w) /* Compute the total height of the lines. */ compute_line_metrics (&it); + it.glyph_row->full_width_p = true; + it.glyph_row->continued_p = false; + it.glyph_row->truncated_on_left_p = false; + it.glyph_row->truncated_on_right_p = false; + +#if defined (HAVE_X_WINDOWS) && !defined (USE_X_TOOLKIT) && !defined (USE_GTK) + /* Make a 3D menu bar have a shadow at its right end. */ + extend_face_to_end_of_line (&it); + if (face->box != FACE_NO_BOX) + { + struct glyph *last = (it.glyph_row->glyphs[TEXT_AREA] + + it.glyph_row->used[TEXT_AREA] - 1); + int box_thickness = face->box_vertical_line_width; + last->right_box_line_p = true; + /* Add back the space for the right box line we subtracted in + init_iterator, since the right_box_line_p flag will make the + glyph wider. We actually add only as much space as is + available for the last glyph of the menu bar and whatever + space is left beyond it, since that glyph could be only + partially visible. */ + if (box_thickness > 0) + last->pixel_width += max (0, (box_thickness + - (it.current_x - it.last_visible_x))); + } + + /* With the non-toolkit version, modify the menu bar window height + accordingly. */ + if (FRAME_WINDOW_P (it.f) && menu_window) + { + struct glyph_row *row; + int delta_height; + + row = it.glyph_row; + delta_height + = ((row->y + row->height) + - WINDOW_BOX_HEIGHT_NO_MODE_LINE (menu_window)); + + if (delta_height != 0) + { + FRAME_MENU_BAR_HEIGHT (it.f) += delta_height; + adjust_frame_size (it.f, -1, -1, 3, false, Qmenu_bar_lines); + } + } +#endif } /* Deep copy of a glyph row, including the glyphs. */ @@ -27576,7 +27621,9 @@ static const char power_letter[] = 'P', /* peta */ 'E', /* exa */ 'Z', /* zetta */ - 'Y' /* yotta */ + 'Y', /* yotta */ + 'R', /* ronna */ + 'Q' /* quetta */ }; static void @@ -33216,7 +33263,7 @@ display_and_set_cursor (struct window *w, bool on, windows and frames; in the latter case, the frame or window may be in the midst of changing its size, and x and y may be off the window. */ - if (! FRAME_VISIBLE_P (f) + if (! FRAME_REDISPLAY_P (f) || vpos >= w->current_matrix->nrows || hpos >= w->current_matrix->matrix_w) return; @@ -33377,7 +33424,7 @@ gui_update_cursor (struct frame *f, bool on_p) void gui_clear_cursor (struct window *w) { - if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p) + if (FRAME_REDISPLAY_P (XFRAME (w->frame)) && w->phys_cursor_on_p) update_window_cursor (w, false); } diff --git a/src/xfns.c b/src/xfns.c index 528ae61ca32..3a129211463 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -43,7 +43,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #ifdef USE_XCB #include <xcb/xcb.h> #include <xcb/xproto.h> -#include <xcb/xcb_aux.h> #endif #include "bitmaps/gray.xbm" @@ -1368,7 +1367,7 @@ x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) XCreateFontCursor is not a request that waits for a reply, and as such can return IDs that will not actually be used by the server. */ - x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f)); + x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f), 0); /* Free any successfully created cursors. */ for (i = 0; i < mouse_cursor_max; i++) @@ -2643,12 +2642,18 @@ append_wm_protocols (struct x_display_info *dpyinfo, if (existing) XFree (existing); - if (!found_wm_ping) - protos[num_protos++] = dpyinfo->Xatom_net_wm_ping; + if (!dpyinfo->untrusted) + { + /* Untrusted clients cannot use these protocols which require + communicating with the window manager. */ + + if (!found_wm_ping) + protos[num_protos++] = dpyinfo->Xatom_net_wm_ping; #if !defined HAVE_GTK3 && defined HAVE_XSYNC - if (!found_wm_sync_request && dpyinfo->xsync_supported_p) - protos[num_protos++] = dpyinfo->Xatom_net_wm_sync_request; + if (!found_wm_sync_request && dpyinfo->xsync_supported_p) + protos[num_protos++] = dpyinfo->Xatom_net_wm_sync_request; #endif + } if (num_protos) XChangeProperty (dpyinfo->display, @@ -4736,6 +4741,7 @@ This function is an internal primitive--use `make-frame' instead. */) #endif /* USE_LUCID && USE_TOOLKIT_SCROLL_BARS */ f->output_data.x->white_relief.pixel = -1; f->output_data.x->black_relief.pixel = -1; + f->output_data.x->visibility_state = VisibilityFullyObscured; fset_icon_name (f, gui_display_get_arg (dpyinfo, parms, @@ -5723,13 +5729,13 @@ x_get_net_workarea (struct x_display_info *dpyinfo, XRectangle *rect) = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) dpyinfo->root_window, (xcb_atom_t) dpyinfo->Xatom_net_current_desktop, - XCB_ATOM_CARDINAL, 0, 1); + XA_CARDINAL, 0, 1); workarea_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) dpyinfo->root_window, (xcb_atom_t) dpyinfo->Xatom_net_workarea, - XCB_ATOM_CARDINAL, 0, UINT32_MAX); + XA_CARDINAL, 0, UINT32_MAX); reply = xcb_get_property_reply (dpyinfo->xcb_connection, current_desktop_cookie, &error); @@ -5740,7 +5746,7 @@ x_get_net_workarea (struct x_display_info *dpyinfo, XRectangle *rect) else { if (xcb_get_property_value_length (reply) != 4 - || reply->type != XCB_ATOM_CARDINAL || reply->format != 32) + || reply->type != XA_CARDINAL || reply->format != 32) rc = false; else current_workspace = *(uint32_t *) xcb_get_property_value (reply); @@ -5755,7 +5761,7 @@ x_get_net_workarea (struct x_display_info *dpyinfo, XRectangle *rect) free (error), rc = false; else { - if (rc && reply->type == XCB_ATOM_CARDINAL && reply->format == 32 + if (rc && reply->type == XA_CARDINAL && reply->format == 32 && (xcb_get_property_value_length (reply) / sizeof (uint32_t) >= current_workspace + 4)) { @@ -7079,8 +7085,8 @@ that mouse buttons are being held down, such as immediately after a /* Catch errors since interning lots of targets can potentially generate a BadAlloc error. */ x_catch_errors (FRAME_X_DISPLAY (f)); - XInternAtoms (FRAME_X_DISPLAY (f), target_names, - ntargets, False, target_atoms); + x_intern_atoms (FRAME_DISPLAY_INFO (f), target_names, + ntargets, target_atoms); x_check_errors (FRAME_X_DISPLAY (f), "Failed to intern target atoms: %s"); x_uncatch_errors_after_check (); @@ -7377,20 +7383,6 @@ If TERMINAL is omitted or nil, that stands for the selected frame's display. */ return Qnil; } -/* Wait for responses to all X commands issued so far for frame F. */ - -void -x_sync (struct frame *f) -{ - block_input (); -#ifndef USE_XCB - XSync (FRAME_X_DISPLAY (f), False); -#else - xcb_aux_sync (FRAME_DISPLAY_INFO (f)->xcb_connection); -#endif - unblock_input (); -} - /*********************************************************************** Window properties @@ -7484,7 +7476,7 @@ silently ignored. */) elsize = element_format == 32 ? sizeof (long) : element_format >> 3; data = xnmalloc (nelements, elsize); - x_fill_property_data (FRAME_X_DISPLAY (f), value, data, nelements, + x_fill_property_data (FRAME_DISPLAY_INFO (f), value, data, nelements, element_format); } else diff --git a/src/xftfont.c b/src/xftfont.c index 1ade22a6006..4d5b855f178 100644 --- a/src/xftfont.c +++ b/src/xftfont.c @@ -628,6 +628,12 @@ xftfont_shape (Lisp_Object lgstring, Lisp_Object direction) static int xftfont_end_for_frame (struct frame *f) { + /* XftDrawDestroy tries to access dpyinfo->display, which could've + been destroyed by now, causing Emacs to crash. The alternative + is to leak the XftDraw, but that's better than a crash. */ + if (!FRAME_X_DISPLAY (f)) + return 0; + block_input (); XftDraw *xft_draw; diff --git a/src/xselect.c b/src/xselect.c index 45f933bba30..0586e46870b 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -16,7 +16,6 @@ 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/>. */ - /* Rewritten by jwz */ #include <config.h> @@ -44,7 +43,7 @@ struct prop_location; struct selection_data; static void x_decline_selection_request (struct selection_input_event *); -static bool x_convert_selection (Lisp_Object, Lisp_Object, Atom, bool, +static bool x_convert_selection (Lisp_Object, Lisp_Object, Atom, struct x_display_info *, bool); static bool waiting_for_other_props_on_window (Display *, Window); static struct prop_location *expect_property_change (Display *, Window, @@ -77,18 +76,20 @@ static void x_send_client_event (Lisp_Object, Lisp_Object, Lisp_Object, #define TRACE0(fmt) (void) 0 #define TRACE1(fmt, a0) (void) 0 #define TRACE2(fmt, a0, a1) (void) 0 +#define TRACE3(fmt, a0, a1, a2) (void) 0 #endif /* Bytes needed to represent 'long' data. This is as per libX11; it is not necessarily sizeof (long). */ #define X_LONG_SIZE 4 -/* If this is a smaller number than the max-request-size of the display, - emacs will use INCR selection transfer when the selection is larger - than this. The max-request-size is usually around 64k, so if you want - emacs to use incremental selection transfers when the selection is - smaller than that, set this. I added this mostly for debugging the - incremental transfer stuff, but it might improve server performance. +/* If this is a smaller number than the max-request-size of the + display, Emacs will use INCR selection transfer when the selection + is larger than this. The max-request-size is usually around 64k, + so if you want emacs to use incremental selection transfers when + the selection is smaller than that, set this. I added this mostly + for debugging the incremental transfer stuff, but it might improve + server performance. This value cannot exceed INT_MAX / max (X_LONG_SIZE, sizeof (long)) because it is multiplied by X_LONG_SIZE and by sizeof (long) in @@ -101,7 +102,9 @@ static void x_send_client_event (Lisp_Object, Lisp_Object, Lisp_Object, static int selection_quantum (Display *display) { - long mrs = XExtendedMaxRequestSize (display); + long mrs; + + mrs = XExtendedMaxRequestSize (display); if (!mrs) mrs = XMaxRequestSize (display); @@ -281,10 +284,8 @@ x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value, timestamp = dpyinfo->last_user_time; block_input (); - x_catch_errors (display); - XSetSelectionOwner (display, selection_atom, selecting_window, timestamp); - x_check_errors (display, "Can't set selection: %s"); - x_uncatch_errors_after_check (); + XSetSelectionOwner (display, selection_atom, selecting_window, + timestamp); unblock_input (); /* Now update the local cache */ @@ -459,7 +460,7 @@ x_decline_selection_request (struct selection_input_event *event) /* The reason for the error may be that the receiver has died in the meantime. Handle that case. */ block_input (); - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, reply->requestor, False, 0, &reply_base); x_stop_ignoring_errors (dpyinfo); @@ -472,19 +473,65 @@ x_decline_selection_request (struct selection_input_event *event) struct selection_data { + /* Pointer to the selection data. */ unsigned char *data; + + /* A Lisp_Object containing the selection data. This is either + Qnil, or `data' is NULL. If non-nil, then this must be a string + whose contents will be written out verbatim. */ + Lisp_Object string; + + /* The size, in number of items, of the selection data. + The value is meaningless if string is non-nil. */ ptrdiff_t size; + + /* The format of the selection data. */ int format; + + /* The type of the selection data. */ Atom type; - bool nofree; + + /* The property describing the selection data. */ Atom property; - /* This can be set to non-NULL during x_reply_selection_request, if - the selection is waiting for an INCR transfer to complete. Don't - free these; that's done by unexpect_property_change. */ - struct prop_location *wait_object; + + /* The next piece of selection data in the current selection request + stack frame. This can be NULL. */ struct selection_data *next; }; +/* Structure representing a single outstanding selection request (or + subrequest if MULTIPLE is being used.) */ + +struct transfer +{ + /* The requestor of this transfer. */ + Window requestor; + + /* The current offset in items into the selection data, and the + number of items to send with each ChangeProperty request. */ + size_t offset, items_per_request; + + /* The display info associated with the transfer. */ + struct x_display_info *dpyinfo; + + /* The converted selection data. */ + struct selection_data data; + + /* The next and last selection transfers on this list. */ + struct transfer *next, *last; + + /* The atimer for the timeout. */ + struct atimer *timeout; + + /* The selection serial. */ + unsigned int serial; + + /* Flags. */ + int flags; +}; + +#define SELECTED_EVENTS 1 + struct x_selection_request { /* The last element in this stack. */ @@ -499,8 +546,8 @@ struct x_selection_request /* Linked list of the above (in support of MULTIPLE targets). */ struct selection_data *converted_selections; - /* "Data" to send a requestor for a failed MULTIPLE subtarget. */ - Atom conversion_fail_tag; + /* The serial used to handle X errors. */ + unsigned int serial; /* Whether or not conversion was successful. */ bool converted; @@ -511,6 +558,50 @@ struct x_selection_request struct x_selection_request *selection_request_stack; +/* List of all outstanding selection transfers which are currently + being processed. */ + +struct transfer outstanding_transfers; + +/* A counter for selection serials. */ + +static unsigned int selection_serial; + + + +struct prop_location +{ + int identifier; + Display *display; + Window window; + Atom property; + int desired_state; + bool arrived; + struct prop_location *next; +}; + +static int prop_location_identifier; + +static Lisp_Object property_change_reply; + +static struct prop_location *property_change_reply_object; + +static struct prop_location *property_change_wait_list; + +static void +set_property_change_object (struct prop_location *location) +{ + /* Input must be blocked so we don't get the event before we set + these. */ + if (! input_blocked_p ()) + emacs_abort (); + + XSETCAR (property_change_reply, Qnil); + property_change_reply_object = location; +} + + + static void x_push_current_selection_request (struct selection_input_event *se, struct x_display_info *dpyinfo) @@ -523,7 +614,6 @@ x_push_current_selection_request (struct selection_input_event *se, frame->request = se; frame->dpyinfo = dpyinfo; frame->converted_selections = NULL; - frame->conversion_fail_tag = None; selection_request_stack = frame; } @@ -554,7 +644,7 @@ x_selection_request_lisp_error (void) for (cs = frame->converted_selections; cs; cs = next) { next = cs->next; - if (! cs->nofree && cs->data) + if (cs->data) xfree (cs->data); xfree (cs); } @@ -564,250 +654,450 @@ x_selection_request_lisp_error (void) x_decline_selection_request (frame->request); } -static void -x_catch_errors_unwind (void) + + +static size_t +c_size_for_format (int format) { - block_input (); - x_uncatch_errors (); - unblock_input (); + switch (format) + { + case 8: + return sizeof (char); + + case 16: + return sizeof (short); + + case 32: + return sizeof (long); + } + + emacs_abort (); } - -/* This stuff is so that INCR selections are reentrant (that is, so we can - be servicing multiple INCR selection requests simultaneously.) I haven't - actually tested that yet. */ +static size_t +x_size_for_format (int format) +{ + switch (format) + { + case 8: + return 1; + + case 16: + return 2; -/* Keep a list of the property changes that are awaited. */ + case 32: + return 4; + } -struct prop_location + emacs_abort (); +} + +/* Return a pointer to the remaining part of the selection data, given + a pointer to a struct selection_data and an offset in items. Place + the number of items remaining in REMAINING. Garbage collection + must not happen, or the returned pointer becomes invalid. */ + +static unsigned char * +selection_data_for_offset (struct selection_data *data, + long offset, size_t *remaining) { - int identifier; - Display *display; - Window window; - Atom property; - int desired_state; - bool arrived; - struct prop_location *next; -}; + unsigned char *base; + size_t size; -static int prop_location_identifier; + if (!NILP (data->string)) + { + base = SDATA (data->string); + size = SBYTES (data->string); + } + else + { + base = data->data; + size = data->size; + } -static Lisp_Object property_change_reply; + if (offset >= size) + { + *remaining = 0; + return NULL; + } -static struct prop_location *property_change_reply_object; + base += (offset * c_size_for_format (data->format)); + *remaining = size - offset; + return base; +} -static struct prop_location *property_change_wait_list; +/* Return the size, in bytes transferred to the X server, of + data->size items of selection data in data->format-bit + quantities. */ -static void -set_property_change_object (struct prop_location *location) +static size_t +selection_data_size (struct selection_data *data) { - /* Input must be blocked so we don't get the event before we set these. */ - if (! input_blocked_p ()) - emacs_abort (); - XSETCAR (property_change_reply, Qnil); - property_change_reply_object = location; + size_t scratch; + + if (!NILP (data->string)) + return SBYTES (data->string); + + switch (data->format) + { + case 8: + return (size_t) data->size; + + case 16: + if (INT_MULTIPLY_WRAPV (data->size, 2, &scratch)) + return SIZE_MAX; + + return scratch; + + case 32: + if (INT_MULTIPLY_WRAPV (data->size, 4, &scratch)) + return SIZE_MAX; + + return scratch; + } + + /* The specified format is invalid. */ + emacs_abort (); } - -/* Send the reply to a selection request event EVENT. */ +/* Return whether or not another outstanding selection transfer is + still selecting for events on the specified requestor window. */ -#ifdef TRACE_SELECTION -static int x_reply_selection_request_cnt; -#endif /* TRACE_SELECTION */ +static bool +transfer_selecting_event (struct x_display_info *dpyinfo, + Window requestor) +{ + struct transfer *next; + + next = outstanding_transfers.next; + for (; next != &outstanding_transfers; next = next->next) + { + if (next->requestor == requestor + && next->dpyinfo == dpyinfo) + return true; + } + + return false; +} + +/* Cancel the specified selection transfer. When called by + `start_transfer', the transfer may be partially formed. */ static void -x_reply_selection_request (struct selection_input_event *event, - struct x_display_info *dpyinfo) +x_cancel_selection_transfer (struct transfer *transfer) { - XEvent reply_base; - XSelectionEvent *reply = &(reply_base.xselection); - Display *display = SELECTION_EVENT_DISPLAY (event); - Window window = SELECTION_EVENT_REQUESTOR (event); - ptrdiff_t bytes_remaining; - int max_bytes = selection_quantum (display); - specpdl_ref count = SPECPDL_INDEX (); - struct selection_data *cs; - struct x_selection_request *frame; + xfree (transfer->data.data); - frame = selection_request_stack; + if (transfer->next) + { + transfer->next->last = transfer->last; + transfer->last->next = transfer->next; + } - reply->type = SelectionNotify; - reply->display = display; - reply->requestor = window; - reply->selection = SELECTION_EVENT_SELECTION (event); - reply->time = SELECTION_EVENT_TIME (event); - reply->target = SELECTION_EVENT_TARGET (event); - reply->property = SELECTION_EVENT_PROPERTY (event); - if (reply->property == None) - reply->property = reply->target; + if (transfer->flags & SELECTED_EVENTS + && !transfer_selecting_event (transfer->dpyinfo, + transfer->requestor) + /* This can be called from x_delete_display. */ + && transfer->dpyinfo->display) + { + /* Ignore errors generated by the change window request in case + the window has gone away. */ + block_input (); + x_ignore_errors_for_next_request (transfer->dpyinfo, 0); + XSelectInput (transfer->dpyinfo->display, + transfer->requestor, NoEventMask); + x_stop_ignoring_errors (transfer->dpyinfo); + unblock_input (); + } - block_input (); - /* The protected block contains wait_for_property_change, which can - run random lisp code (process handlers) or signal. Therefore, we - put the x_uncatch_errors call in an unwind. */ - record_unwind_protect_void (x_catch_errors_unwind); - x_catch_errors (display); + cancel_atimer (transfer->timeout); + xfree (transfer); +} - /* Loop over converted selections, storing them in the requested - properties. If data is large, only store the first N bytes - (section 2.7.2 of ICCCM). Note that we store the data for a - MULTIPLE request in the opposite order; the ICCM says only that - the conversion itself must be done in the same order. */ - for (cs = frame->converted_selections; cs; cs = cs->next) +static void +x_selection_transfer_timeout (struct atimer *atimer) +{ + struct transfer *transfer; + + transfer = atimer->client_data; + x_cancel_selection_transfer (transfer); +} + +/* Start a selection transfer to write the specified selection data to + its requestor. If the data is small enough, write it to the + requestor window and return. Otherwise, start INCR transfer and + begin listening for PropertyNotify events on the requestor. */ + +static void +x_start_selection_transfer (struct x_display_info *dpyinfo, Window requestor, + struct selection_data *data) +{ + struct transfer *transfer; + intmax_t timeout; + intmax_t secs; + int nsecs; + size_t remaining, max_size; + unsigned char *xdata; + unsigned long data_size; + + timeout = max (0, x_selection_timeout); + secs = timeout / 1000; + nsecs = (timeout % 1000) * 1000000; + + transfer = xzalloc (sizeof *transfer); + transfer->requestor = requestor; + transfer->dpyinfo = dpyinfo; + + transfer->timeout = start_atimer (ATIMER_RELATIVE, + make_timespec (secs, nsecs), + x_selection_transfer_timeout, + transfer); + + /* Note that DATA is copied into transfer. DATA->data is then set + to NULL, giving the struct transfer ownership over the selection + data. */ + + transfer->data = *data; + data->data = NULL; + + /* Finally, transfer now holds a reference to data->string, if it is + present. GC cannot be allowed to happen until this function + returns. */ + data->string = Qnil; + + /* Now, try to write the selection data. If it is bigger than + selection_quantum (dpyinfo->display), start incremental transfer + and link the transfer onto the list of pending selections. + Otherwise, write the transfer at once. */ + + max_size = selection_quantum (dpyinfo->display); + + TRACE3 (" x_start_selection_transfer: transferring to 0x%lx. " + "transfer consists of %zu bytes, quantum being %zu", + requestor, selection_data_size (&transfer->data), + max_size); + + if (selection_data_size (&transfer->data) > max_size) { - if (cs->property == None) - continue; + /* Begin incremental selection transfer. First, calculate how + many elements it is ok to write for every ChangeProperty + request. */ + transfer->items_per_request + = (max_size / x_size_for_format (transfer->data.format)); + TRACE1 (" x_start_selection_transfer: starting incremental" + " selection transfer, with %zu items per request", + transfer->items_per_request); + + /* Next, link the transfer onto the list of pending selection + transfers. */ + transfer->next = outstanding_transfers.next; + transfer->last = &outstanding_transfers; + transfer->next->last = transfer; + transfer->last->next = transfer; + + /* Find a valid (non-zero) serial for the selection transfer. + Any asynchronously trapped errors will then cause the + selection transfer to be cancelled. */ + transfer->serial = (++selection_serial + ? selection_serial + : ++selection_serial); + + /* Now, write the INCR property to begin incremental selection + transfer. offset is currently 0. */ + + data_size = selection_data_size (&transfer->data); + + /* Set SELECTED_EVENTS before the actual XSelectInput + request. */ + transfer->flags |= SELECTED_EVENTS; + + x_ignore_errors_for_next_request (dpyinfo, transfer->serial); + XChangeProperty (dpyinfo->display, requestor, + transfer->data.property, + dpyinfo->Xatom_INCR, 32, PropModeReplace, + (unsigned char *) &data_size, 1); + + /* This assumes that Emacs is not selecting for any other events + from the requestor! + + If the holder of some manager selections (i.e. the settings + manager) asks Emacs for selection data, things will subtly go + wrong. */ + XSelectInput (dpyinfo->display, requestor, PropertyChangeMask); + x_stop_ignoring_errors (dpyinfo); + } + else + { + /* Write the property data now. */ + xdata = selection_data_for_offset (&transfer->data, + 0, &remaining); + eassert (remaining <= INT_MAX); + + TRACE1 (" x_start_selection_transfer: writing" + " %zu elements directly to requestor window", + remaining); + + x_ignore_errors_for_next_request (dpyinfo, 0); + XChangeProperty (dpyinfo->display, requestor, + transfer->data.property, + transfer->data.type, + transfer->data.format, + PropModeReplace, xdata, remaining); + x_stop_ignoring_errors (dpyinfo); + + /* Next, get rid of the transfer. */ + x_cancel_selection_transfer (transfer); + } +} - bytes_remaining = cs->size; - bytes_remaining *= cs->format >> 3; - if (bytes_remaining <= max_bytes) - { - /* Send all the data at once, with minimal handshaking. */ - TRACE1 ("Sending all %"pD"d bytes", bytes_remaining); - XChangeProperty (display, window, cs->property, - cs->type, cs->format, PropModeReplace, - cs->data, cs->size); - } - else - { - /* Send an INCR tag to initiate incremental transfer. */ - long value[1]; - - TRACE2 ("Start sending %"pD"d bytes incrementally (%s)", - bytes_remaining, XGetAtomName (display, cs->property)); - cs->wait_object - = expect_property_change (display, window, cs->property, - PropertyDelete); - - /* XChangeProperty expects an array of long even if long is - more than 32 bits. */ - value[0] = min (bytes_remaining, X_LONG_MAX); - XChangeProperty (display, window, cs->property, - dpyinfo->Xatom_INCR, 32, PropModeReplace, - (unsigned char *) value, 1); - XSelectInput (display, window, PropertyChangeMask); - } +/* Write out the next piece of data that is part of the specified + selection transfer. If no more data remains to be written, write + the EOF property and complete the transfer. */ + +static void +x_continue_selection_transfer (struct transfer *transfer) +{ + size_t remaining; + unsigned char *xdata; + + xdata = selection_data_for_offset (&transfer->data, + transfer->offset, + &remaining); + remaining = min (remaining, transfer->items_per_request); + + if (!remaining) + { + /* The transfer is finished. Write zero-length property data to + signal EOF and remove the transfer. */ + TRACE0 (" x_continue_selection_transfer: writing 0 items to" + " indicate EOF"); + x_ignore_errors_for_next_request (transfer->dpyinfo, 0); + XChangeProperty (transfer->dpyinfo->display, + transfer->requestor, + transfer->data.property, + transfer->data.type, + transfer->data.format, + PropModeReplace, + NULL, 0); + x_stop_ignoring_errors (transfer->dpyinfo); + TRACE0 (" x_continue_selection_transfer: done sending incrementally"); + + x_cancel_selection_transfer (transfer); + } + else + { + TRACE2 (" x_continue_selection_transfer: writing %zu items" + "; current offset is %zu", remaining, transfer->offset); + eassert (remaining <= INT_MAX); + + transfer->offset += remaining; + + x_ignore_errors_for_next_request (transfer->dpyinfo, + transfer->serial); + XChangeProperty (transfer->dpyinfo->display, + transfer->requestor, + transfer->data.property, + transfer->data.type, + transfer->data.format, + PropModeReplace, xdata, + remaining); + x_stop_ignoring_errors (transfer->dpyinfo); } +} - /* Now issue the SelectionNotify event. */ - XSendEvent (display, window, False, 0, &reply_base); - XFlush (display); +void +x_remove_selection_transfers (struct x_display_info *dpyinfo) +{ + struct transfer *next, *last; -#ifdef TRACE_SELECTION - { - char *sel = XGetAtomName (display, reply->selection); - char *tgt = XGetAtomName (display, reply->target); - TRACE3 ("Sent SelectionNotify: %s, target %s (%d)", - sel, tgt, ++x_reply_selection_request_cnt); - if (sel) XFree (sel); - if (tgt) XFree (tgt); - } -#endif /* TRACE_SELECTION */ + next = outstanding_transfers.next; + while (next != &outstanding_transfers) + { + last = next; + next = next->next; - /* Finish sending the rest of each of the INCR values. This should - be improved; there's a chance of deadlock if more than one - subtarget in a MULTIPLE selection requires an INCR transfer, and - the requestor and Emacs loop waiting on different transfers. */ - for (cs = frame->converted_selections; cs; cs = cs->next) - if (cs->wait_object) - { - int format_bytes = cs->format / 8; - bool had_errors_p = x_had_errors_p (display); + if (last->dpyinfo == dpyinfo) + x_cancel_selection_transfer (last); + } +} - /* Must set this inside block_input (). unblock_input may read - events and setting property_change_reply in - wait_for_property_change is then too late. */ - set_property_change_object (cs->wait_object); - unblock_input (); +/* Handle an X error generated trying to write to a window. SERIAL + identifies the outstanding incremental selection transfer, which is + immediately removed. */ - bytes_remaining = cs->size; - bytes_remaining *= format_bytes; +void +x_handle_selection_error (unsigned int serial, XErrorEvent *error) +{ + struct transfer *next, *last; - /* Wait for the requestor to ack by deleting the property. - This can run Lisp code (process handlers) or signal. */ - if (! had_errors_p) - { - TRACE1 ("Waiting for ACK (deletion of %s)", - XGetAtomName (display, cs->property)); - wait_for_property_change (cs->wait_object); - } - else - unexpect_property_change (cs->wait_object); + if (error->error_code != BadWindow) + /* The error was not caused by the window going away. As such, + Emacs must deselect for PropertyChangeMask from the requestor + window, which isn't safe here. Return and wait for the timeout + to run. */ + return; - while (bytes_remaining) - { - int i = ((bytes_remaining < max_bytes) - ? bytes_remaining - : max_bytes) / format_bytes; - block_input (); - - cs->wait_object - = expect_property_change (display, window, cs->property, - PropertyDelete); - - TRACE1 ("Sending increment of %d elements", i); - TRACE1 ("Set %s to increment data", - XGetAtomName (display, cs->property)); - - /* Append the next chunk of data to the property. */ - XChangeProperty (display, window, cs->property, - cs->type, cs->format, PropModeAppend, - cs->data, i); - bytes_remaining -= i * format_bytes; - cs->data += i * ((cs->format == 32) ? sizeof (long) - : format_bytes); - XFlush (display); - had_errors_p = x_had_errors_p (display); - /* See comment above about property_change_reply. */ - set_property_change_object (cs->wait_object); - unblock_input (); - - if (had_errors_p) break; - - /* Wait for the requestor to ack this chunk by deleting - the property. This can run Lisp code or signal. */ - TRACE1 ("Waiting for increment ACK (deletion of %s)", - XGetAtomName (display, cs->property)); - wait_for_property_change (cs->wait_object); - } + next = outstanding_transfers.next; + while (next != &outstanding_transfers) + { + last = next; + next = next->next; - /* Now write a zero-length chunk to the property to tell the - requestor that we're done. */ - block_input (); - if (! waiting_for_other_props_on_window (display, window)) - XSelectInput (display, window, 0); - - TRACE1 ("Set %s to a 0-length chunk to indicate EOF", - XGetAtomName (display, cs->property)); - XChangeProperty (display, window, cs->property, - cs->type, cs->format, PropModeReplace, - cs->data, 0); - TRACE0 ("Done sending incrementally"); - } + if (last->serial == serial) + { + /* Clear SELECTED_EVENTS, so x_cancel_selection_transfer + will not make X requests. That is unsafe inside an error + handler, and unnecessary because the window has already + gone. */ + last->flags &= ~SELECTED_EVENTS; + x_cancel_selection_transfer (last); + } + } +} - /* rms, 2003-01-03: I think I have fixed this bug. */ - /* The window we're communicating with may have been deleted - in the meantime (that's a real situation from a bug report). - In this case, there may be events in the event queue still - referring to the deleted window, and we'll get a BadWindow error - in XTread_socket when processing the events. I don't have - an idea how to fix that. gerd, 2001-01-98. */ - /* 2004-09-10: XSync and UNBLOCK so that possible protocol errors are - delivered before uncatch errors. */ - XSync (display, False); - unblock_input (); +/* Send the reply to a selection request event EVENT. */ + +static void +x_reply_selection_request (struct selection_input_event *event, + struct x_display_info *dpyinfo) +{ + XEvent message; + struct selection_data *cs; + struct x_selection_request *frame; - /* GTK queues events in addition to the queue in Xlib. So we - UNBLOCK to enter the event loop and get possible errors delivered, - and then BLOCK again because x_uncatch_errors requires it. */ block_input (); - /* This calls x_uncatch_errors. */ - unbind_to (count, Qnil); + frame = selection_request_stack; + + message.xselection.type = SelectionNotify; + message.xselection.display = dpyinfo->display; + message.xselection.requestor = SELECTION_EVENT_REQUESTOR (event); + message.xselection.selection = SELECTION_EVENT_SELECTION (event); + message.xselection.time = SELECTION_EVENT_TIME (event); + message.xselection.target = SELECTION_EVENT_TARGET (event); + message.xselection.property = SELECTION_EVENT_PROPERTY (event); + + if (message.xselection.property == None) + message.xselection.property = message.xselection.target; + + /* For each of the converted selections, start a write transfer from + Emacs to the requestor. */ + for (cs = frame->converted_selections; cs; cs = cs->next) + x_start_selection_transfer (dpyinfo, + SELECTION_EVENT_REQUESTOR (event), + cs); + + + /* Send the SelectionNotify event to the requestor, telling it that + the property data has arrived. */ + x_ignore_errors_for_next_request (dpyinfo, 0); + XSendEvent (dpyinfo->display, SELECTION_EVENT_REQUESTOR (event), + False, NoEventMask, &message); + x_stop_ignoring_errors (dpyinfo); unblock_input (); } - -/* Handle a SelectionRequest event EVENT. - This is called from keyboard.c when such an event is found in the queue. */ + +/* Handle a SelectionRequest event EVENT. This is called from + keyboard.c when such an event is found in the queue. */ static void x_handle_selection_request (struct selection_input_event *event) @@ -892,7 +1182,9 @@ x_handle_selection_request (struct selection_input_event *event) ptrdiff_t j, nselections; struct selection_data cs; - if (property == None) goto DONE; + if (property == None) + goto DONE; + multprop = x_get_window_property_as_lisp_data (dpyinfo, requestor, property, QMULTIPLE, selection, true); @@ -904,23 +1196,24 @@ x_handle_selection_request (struct selection_input_event *event) /* Perform conversions. This can signal. */ for (j = 0; j < nselections; j++) { - Lisp_Object subtarget = AREF (multprop, 2*j); + Lisp_Object subtarget = AREF (multprop, 2 * j); Atom subproperty = symbol_to_x_atom (dpyinfo, AREF (multprop, 2*j+1)); bool subsuccess = false; if (subproperty != None) subsuccess = x_convert_selection (selection_symbol, subtarget, - subproperty, true, dpyinfo, + subproperty, dpyinfo, use_alternate); if (!subsuccess) - ASET (multprop, 2*j+1, Qnil); + ASET (multprop, 2 * j + 1, Qnil); } + /* Save conversion results */ lisp_data_to_selection_data (dpyinfo, multprop, &cs); - /* If cs.type is ATOM, change it to ATOM_PAIR. This is because - the parameters to a MULTIPLE are ATOM_PAIRs. */ + /* If cs.type is ATOM, change it to ATOM_PAIR. This is + because the parameters to a MULTIPLE are ATOM_PAIRs. */ if (cs.type == XA_ATOM) cs.type = dpyinfo->Xatom_ATOM_PAIR; @@ -929,27 +1222,29 @@ x_handle_selection_request (struct selection_input_event *event) cs.type, cs.format, PropModeReplace, cs.data, cs.size); success = true; + + xfree (cs.data); } else { if (property == None) property = SELECTION_EVENT_TARGET (event); + success = x_convert_selection (selection_symbol, target_symbol, property, - false, dpyinfo, - use_alternate); + dpyinfo, use_alternate); } DONE: - if (pushed) - selection_request_stack->converted = true; - if (success) x_reply_selection_request (event, dpyinfo); else x_decline_selection_request (event); + if (pushed) + selection_request_stack->converted = true; + /* Run the `x-sent-selection-functions' abnormal hook. */ if (!NILP (Vx_sent_selection_functions) && !BASE_EQ (Vx_sent_selection_functions, Qunbound)) @@ -960,19 +1255,18 @@ x_handle_selection_request (struct selection_input_event *event) REALLY_DONE: unbind_to (count, Qnil); + return; } /* Perform the requested selection conversion, and write the data to the converted_selections linked list, where it can be accessed by - x_reply_selection_request. If FOR_MULTIPLE, write out - the data even if conversion fails, using conversion_fail_tag. + x_reply_selection_request. Return true if successful. */ static bool -x_convert_selection (Lisp_Object selection_symbol, - Lisp_Object target_symbol, Atom property, - bool for_multiple, struct x_display_info *dpyinfo, +x_convert_selection (Lisp_Object selection_symbol, Lisp_Object target_symbol, + Atom property, struct x_display_info *dpyinfo, bool use_alternate) { Lisp_Object lisp_selection; @@ -988,33 +1282,16 @@ x_convert_selection (Lisp_Object selection_symbol, /* A nil return value means we can't perform the conversion. */ if (NILP (lisp_selection) || (CONSP (lisp_selection) && NILP (XCDR (lisp_selection)))) - { - if (for_multiple) - { - cs = xmalloc (sizeof *cs); - cs->data = ((unsigned char *) - &selection_request_stack->conversion_fail_tag); - cs->size = 1; - cs->format = 32; - cs->type = XA_ATOM; - cs->nofree = true; - cs->property = property; - cs->wait_object = NULL; - cs->next = frame->converted_selections; - frame->converted_selections = cs; - } - - return false; - } + return false; /* Otherwise, record the converted selection to binary. */ cs = xmalloc (sizeof *cs); cs->data = NULL; - cs->nofree = true; + cs->string = Qnil; cs->property = property; - cs->wait_object = NULL; cs->next = frame->converted_selections; frame->converted_selections = cs; + lisp_data_to_selection_data (dpyinfo, lisp_selection, cs); return true; } @@ -1274,6 +1551,10 @@ void x_handle_property_notify (const XPropertyEvent *event) { struct prop_location *rest; + struct transfer *next; +#ifdef TRACE_SELECTION + char *name; +#endif for (rest = property_change_wait_list; rest; rest = rest->next) { @@ -1283,9 +1564,16 @@ x_handle_property_notify (const XPropertyEvent *event) && rest->display == event->display && rest->desired_state == event->state) { +#ifdef TRACE_SELECTION + name = XGetAtomName (event->display, event->atom); + TRACE2 ("Expected %s of property %s", (event->state == PropertyDelete ? "deletion" : "change"), - XGetAtomName (event->display, event->atom)); + name ? name : "unknown"); + + if (name) + XFree (name); +#endif rest->arrived = true; @@ -1297,6 +1585,26 @@ x_handle_property_notify (const XPropertyEvent *event) return; } } + + /* Look for a property change for an outstanding selection + transfer. */ + next = outstanding_transfers.next; + while (next != &outstanding_transfers) + { + if (next->dpyinfo->display == event->display + && next->requestor == event->window + && next->data.property == event->atom + && event->state == PropertyDelete) + { + TRACE1 ("Expected PropertyDelete event arrived from the" + " requestor window %lx", next->requestor); + + x_continue_selection_transfer (next); + return; + } + + next = next->next; + } } static void @@ -1450,10 +1758,10 @@ x_get_window_property (Display *display, Window window, Atom property, /* Maximum value for TOTAL_SIZE. It cannot exceed PTRDIFF_MAX - 1 and SIZE_MAX - 1, for an extra byte at the end. And it cannot exceed LONG_MAX * X_LONG_SIZE, for XGetWindowProperty. */ - ptrdiff_t total_size_max = - ((min (PTRDIFF_MAX, SIZE_MAX) - 1) / x_long_size < LONG_MAX - ? min (PTRDIFF_MAX, SIZE_MAX) - 1 - : LONG_MAX * x_long_size); + ptrdiff_t total_size_max + = ((min (PTRDIFF_MAX, SIZE_MAX) - 1) / x_long_size < LONG_MAX + ? min (PTRDIFF_MAX, SIZE_MAX) - 1 + : LONG_MAX * x_long_size); block_input (); @@ -1946,10 +2254,14 @@ static void lisp_data_to_selection_data (struct x_display_info *dpyinfo, Lisp_Object obj, struct selection_data *cs) { - Lisp_Object type = Qnil; + Lisp_Object type; + char **name_buffer; + + USE_SAFE_ALLOCA; + + type = Qnil; eassert (cs != NULL); - cs->nofree = false; if (CONSP (obj) && SYMBOLP (XCAR (obj))) { @@ -1959,8 +2271,10 @@ lisp_data_to_selection_data (struct x_display_info *dpyinfo, obj = XCAR (obj); } + /* This is not the same as declining. */ + if (EQ (obj, QNULL) || (EQ (type, QNULL))) - { /* This is not the same as declining */ + { cs->format = 32; cs->size = 0; cs->data = NULL; @@ -1971,12 +2285,14 @@ lisp_data_to_selection_data (struct x_display_info *dpyinfo, if (SCHARS (obj) < SBYTES (obj)) /* OBJ is a multibyte string containing a non-ASCII char. */ signal_error ("Non-ASCII string must be encoded in advance", obj); + if (NILP (type)) type = QSTRING; + cs->format = 8; - cs->size = SBYTES (obj); - cs->data = SDATA (obj); - cs->nofree = true; + cs->size = -1; + cs->data = NULL; + cs->string = obj; } else if (SYMBOLP (obj)) { @@ -2048,8 +2364,19 @@ lisp_data_to_selection_data (struct x_display_info *dpyinfo, x_atoms = data; cs->format = 32; cs->size = size; - for (i = 0; i < size; i++) - x_atoms[i] = symbol_to_x_atom (dpyinfo, AREF (obj, i)); + + if (size == 1) + x_atoms[0] = symbol_to_x_atom (dpyinfo, AREF (obj, i)); + else + { + SAFE_NALLOCA (name_buffer, sizeof *x_atoms, size); + + for (i = 0; i < size; i++) + name_buffer[i] = SSDATA (SYMBOL_NAME (AREF (obj, i))); + + x_intern_atoms (dpyinfo, name_buffer, size, + x_atoms); + } } else /* This vector is an INTEGER set, or something like it */ @@ -2091,6 +2418,8 @@ lisp_data_to_selection_data (struct x_display_info *dpyinfo, signal_error (/* Qselection_error */ "Unrecognized selection data", obj); cs->type = symbol_to_x_atom (dpyinfo, type); + + SAFE_FREE (); } static Lisp_Object @@ -2618,8 +2947,8 @@ x_check_property_data (Lisp_Object data) XClientMessageEvent). */ void -x_fill_property_data (Display *dpy, Lisp_Object data, void *ret, - int nelements_max, int format) +x_fill_property_data (struct x_display_info *dpyinfo, Lisp_Object data, + void *ret, int nelements_max, int format) { unsigned long val; unsigned long *d32 = (unsigned long *) ret; @@ -2654,7 +2983,7 @@ x_fill_property_data (Display *dpy, Lisp_Object data, void *ret, else if (STRINGP (o)) { block_input (); - val = XInternAtom (dpy, SSDATA (o), False); + val = x_intern_cached_atom (dpyinfo, SSDATA (o), false); unblock_input (); } else @@ -2942,7 +3271,7 @@ x_send_client_event (Lisp_Object display, Lisp_Object dest, Lisp_Object from, memset (event.xclient.data.l, 0, sizeof (event.xclient.data.l)); /* event.xclient.data can hold 20 chars, 10 shorts, or 5 longs. */ - x_fill_property_data (dpyinfo->display, values, event.xclient.data.b, + x_fill_property_data (dpyinfo, values, event.xclient.data.b, 5 * 32 / event.xclient.format, event.xclient.format); @@ -3002,10 +3331,11 @@ syms_of_xselect (void) reading_selection_reply = Fcons (Qnil, Qnil); staticpro (&reading_selection_reply); - staticpro (&property_change_reply); - /* FIXME: Duplicate definition in nsselect.c. */ + outstanding_transfers.next = &outstanding_transfers; + outstanding_transfers.last = &outstanding_transfers; + DEFVAR_LISP ("selection-converter-alist", Vselection_converter_alist, doc: /* An alist associating X Windows selection-types with functions. These functions are called to convert the selection, with three args: @@ -3120,9 +3450,43 @@ Note that this does not affect setting or owning selections. */); static void syms_of_xselect_for_pdumper (void) { + outstanding_transfers.next = &outstanding_transfers; + outstanding_transfers.last = &outstanding_transfers; + reading_selection_window = 0; reading_which_selection = 0; property_change_wait_list = 0; prop_location_identifier = 0; property_change_reply = Fcons (Qnil, Qnil); } + +void +mark_xselect (void) +{ + struct transfer *next; + struct x_selection_request *frame; + struct selection_data *cs; + + /* Mark all the strings being used as selection data. A string that + is still reachable is always reachable via either the selection + request stack or the list of outstanding transfers. */ + + next = outstanding_transfers.next; + + if (!next) + /* syms_of_xselect has not yet been called. */ + return; + + while (next != &outstanding_transfers) + { + mark_object (next->data.string); + next = next->next; + } + + frame = selection_request_stack; + for (; frame; frame = frame->last) + { + for (cs = frame->converted_selections; cs; cs = cs->next) + mark_object (cs->string); + } +} diff --git a/src/xterm.c b/src/xterm.c index 6a4b84babe4..1325d923be9 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -26,6 +26,22 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ contains subroutines comprising the redisplay interface, setting up scroll bars and widgets, and handling input. + X WINDOW SYSTEM + + The X Window System is a windowing system for bitmap graphics + displays which originated at MIT in 1984. Version 11, which is + currently supported by Emacs, first appeared in September 1987. + + X has a long history and has been developed by many different + organizations over the years; at present, it is being primarily + developed by the X.Org Foundation. It is the main window system + that Emacs is developed and tested against, and X version 10 was + the first window system that Emacs was ported to. As a consequence + of its age and wide availability, X contains many idiosyncrasies, + but that has not prevented it from becoming the dominant free + window system, and the platform of reference for all GUI code in + Emacs. + Some of what is explained below also applies to the other window systems that Emacs supports, to varying degrees. YMMV. @@ -555,7 +571,56 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ drop happening with the primary selection and synthetic button events (see `x_dnd_do_unsupported_drop'). That function implements the OffiX drag-and-drop protocol by default. See - `x-dnd-handle-unsupported-drop' in `x-dnd.el' for more details. */ + `x-dnd-handle-unsupported-drop' in `x-dnd.el' for more details. + + DISPLAY ERROR HANDLING + + While error handling under X was originally designed solely as a + mechanism for the X server to report fatal errors to clients, most + clients (including Emacs) have adopted a system of "error traps" to + handle or discard these errors as they arrive. Discarding errors is + usually necessary when Emacs performs an X request that might fail: + for example, sending a message to a window that may no longer exist, + or might not exist at all. Handling errors is then necessary when + the detailed error must be reported to another piece of code: for + example, as a Lisp error. + + It is not acceptable for Emacs to crash when it is sent invalid data + by another client, or by Lisp. As a result, errors must be caught + around Xlib functions generating requests containing resource + identifiers that could potentially be invalid, such as window or + atom identifiers provided in a client message from another program, + or a child window ID obtained through XTranslateCoordinates that may + refer to a window that has been deleted in the meantime. + + There are two sets of functions used to perform this "error + trapping". Which one should be used depends on what kind of + processing must be done on the error. The first consists of the + functions `x_ignore_errors_for_next_request' and + `x_stop_ignoring_errors', which ignore errors generated by requests + made in between a call to the first function and a corresponding + call to the second. They should be used for simple asynchronous + requests that do not require a reply from the X server: using them + instead of the second set improves performance, as they simply + record a range of request serials to ignore errors from, instead of + synchronizing with the X server to handle errors. + + The second set consists of the following functions: + + - x_catch_errors_with_handler + - x_catch_errors + - x_uncatch_errors_after_check + - x_uncatch_errors + - x_check_errors + - x_had_errors_p + - x_clear_errors + + Callers using this set should consult the comment(s) on top of the + aformentioned functions. They should not be used when the requests + being made do not require roundtrips to the X server, and obtaining + the details of any error generated is unecessary, as + `x_uncatch_errors' will always synchronize with the X server, which + is a potentially slow operation. */ #include <config.h> #include <stdlib.h> @@ -574,7 +639,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #ifdef USE_XCB #include <xcb/xproto.h> #include <xcb/xcb.h> -#include <xcb/xcb_aux.h> #endif /* If we have Xfixes extension, use it for pointer blanking. */ @@ -1052,6 +1116,20 @@ static const struct x_atom_ref x_atom_refs[] = /* Old OffiX (a.k.a. old KDE) drop protocol support. */ ATOM_REFS_INIT ("DndProtocol", Xatom_DndProtocol) ATOM_REFS_INIT ("_DND_PROTOCOL", Xatom_DND_PROTOCOL) + /* Here are some atoms that are not actually used from C, just + defined to make replying to selection requests fast. */ + ATOM_REFS_INIT ("text/plain;charset=utf-8", Xatom_text_plain_charset_utf_8) + ATOM_REFS_INIT ("LENGTH", Xatom_LENGTH) + ATOM_REFS_INIT ("FILE_NAME", Xatom_FILE_NAME) + ATOM_REFS_INIT ("CHARACTER_POSITION", Xatom_CHARACTER_POSITION) + ATOM_REFS_INIT ("LINE_NUMBER", Xatom_LINE_NUMBER) + ATOM_REFS_INIT ("COLUMN_NUMBER", Xatom_COLUMN_NUMBER) + ATOM_REFS_INIT ("OWNER_OS", Xatom_OWNER_OS) + ATOM_REFS_INIT ("HOST_NAME", Xatom_HOST_NAME) + ATOM_REFS_INIT ("USER", Xatom_USER) + ATOM_REFS_INIT ("CLASS", Xatom_CLASS) + ATOM_REFS_INIT ("NAME", Xatom_NAME) + ATOM_REFS_INIT ("SAVE_TARGETS", Xatom_SAVE_TARGETS) }; enum @@ -2509,7 +2587,7 @@ xm_send_drop_message (struct x_display_info *dpyinfo, Window source, *((uint32_t *) &msg.xclient.data.b[12]) = dmsg->index_atom; *((uint32_t *) &msg.xclient.data.b[16]) = dmsg->source_window; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -2536,7 +2614,7 @@ xm_send_top_level_enter_message (struct x_display_info *dpyinfo, Window source, msg.xclient.data.b[18] = 0; msg.xclient.data.b[19] = 0; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -2567,7 +2645,7 @@ xm_send_drag_motion_message (struct x_display_info *dpyinfo, Window source, msg.xclient.data.b[18] = 0; msg.xclient.data.b[19] = 0; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -2626,7 +2704,7 @@ xm_send_top_level_leave_message (struct x_display_info *dpyinfo, Window source, msg.xclient.data.b[18] = 0; msg.xclient.data.b[19] = 0; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -2921,7 +2999,7 @@ x_dnd_free_toplevels (bool display_alive) if (n_windows) { eassume (dpyinfo); - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); for (i = 0; i < n_windows; ++i) { @@ -3058,7 +3136,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) 0, 0); get_property_cookies[i] = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) toplevels[i], - (xcb_atom_t) dpyinfo->Xatom_wm_state, XCB_ATOM_ANY, + (xcb_atom_t) dpyinfo->Xatom_wm_state, 0, 0, 2); xm_property_cookies[i] = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) toplevels[i], @@ -3069,7 +3147,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) toplevels[i], (xcb_atom_t) dpyinfo->Xatom_net_frame_extents, - XCB_ATOM_CARDINAL, 0, 4); + XA_CARDINAL, 0, 4); get_geometry_cookies[i] = xcb_get_geometry (dpyinfo->xcb_connection, (xcb_window_t) toplevels[i]); @@ -3197,7 +3275,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) { if (xcb_get_property_value_length (extent_property_reply) == 16 && extent_property_reply->format == 32 - && extent_property_reply->type == XCB_ATOM_CARDINAL) + && extent_property_reply->type == XA_CARDINAL) { fextents = xcb_get_property_value (extent_property_reply); frame_extents[0] = fextents[0]; @@ -3291,7 +3369,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) if (dpyinfo->xshape_supported_p) { - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XShapeSelectInput (dpyinfo->display, toplevels[i], ShapeNotifyMask); @@ -3456,7 +3534,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) } #endif - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSelectInput (dpyinfo->display, toplevels[i], (attrs.your_event_mask | StructureNotifyMask @@ -3571,13 +3649,13 @@ x_dnd_get_proxy_proto (struct x_display_info *dpyinfo, Window wdesc, xdnd_proxy_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) wdesc, (xcb_atom_t) dpyinfo->Xatom_XdndProxy, - XCB_ATOM_WINDOW, 0, 1); + XA_WINDOW, 0, 1); if (proto_out) xdnd_proto_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) wdesc, (xcb_atom_t) dpyinfo->Xatom_XdndAware, - XCB_ATOM_ATOM, 0, 1); + XA_ATOM, 0, 1); if (proxy_out) { @@ -3589,7 +3667,7 @@ x_dnd_get_proxy_proto (struct x_display_info *dpyinfo, Window wdesc, else { if (reply->format == 32 - && reply->type == XCB_ATOM_WINDOW + && reply->type == XA_WINDOW && (xcb_get_property_value_length (reply) >= 4)) *proxy_out = *(xcb_window_t *) xcb_get_property_value (reply); @@ -3607,7 +3685,7 @@ x_dnd_get_proxy_proto (struct x_display_info *dpyinfo, Window wdesc, else { if (reply->format == 32 - && reply->type == XCB_ATOM_ATOM + && reply->type == XA_ATOM && (xcb_get_property_value_length (reply) >= 4)) *proto_out = (int) *(xcb_atom_t *) xcb_get_property_value (reply); @@ -3791,15 +3869,15 @@ x_dnd_get_wm_state_and_proto (struct x_display_info *dpyinfo, wmstate_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) window, (xcb_atom_t) dpyinfo->Xatom_wm_state, - XCB_ATOM_ANY, 0, 2); + 0, 0, 2); xdnd_proto_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) window, (xcb_atom_t) dpyinfo->Xatom_XdndAware, - XCB_ATOM_ATOM, 0, 1); + XA_ATOM, 0, 1); xdnd_proxy_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) window, (xcb_atom_t) dpyinfo->Xatom_XdndProxy, - XCB_ATOM_WINDOW, 0, 1); + XA_WINDOW, 0, 1); xm_style_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) window, (xcb_atom_t) dpyinfo->Xatom_MOTIF_DRAG_RECEIVER_INFO, @@ -3846,7 +3924,7 @@ x_dnd_get_wm_state_and_proto (struct x_display_info *dpyinfo, else { if (reply->format == 32 - && reply->type == XCB_ATOM_WINDOW + && reply->type == XA_WINDOW && (xcb_get_property_value_length (reply) >= 4)) *proxy_out = *(xcb_window_t *) xcb_get_property_value (reply); @@ -3962,6 +4040,12 @@ x_dnd_do_unsupported_drop (struct x_display_info *dpyinfo, if (owner != FRAME_X_WINDOW (f)) return; + /* mouse-drag-and-drop-region will immediately deactivate the mark + after this is set. Make sure the primary selection is not + clobbered in that case by setting `deactivate-mark' to + Qdont_save. */ + Vdeactivate_mark = Qdont_save; + event.xbutton.window = child; event.xbutton.subwindow = None; event.xbutton.x = dest_x; @@ -3975,7 +4059,7 @@ x_dnd_do_unsupported_drop (struct x_display_info *dpyinfo, event.xbutton.type = ButtonPress; event.xbutton.time = before + 1; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, child, True, ButtonPressMask, &event); @@ -4487,7 +4571,7 @@ x_dnd_send_enter (struct frame *f, Window target, Window toplevel, so we don't have to set it again. */ x_dnd_init_type_lists = true; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -4559,7 +4643,7 @@ x_dnd_send_position (struct frame *f, Window target, Window toplevel, return; } - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); @@ -4586,7 +4670,7 @@ x_dnd_send_leave (struct frame *f, Window target, Window toplevel) x_dnd_waiting_for_status_window = None; x_dnd_pending_send_position.type = 0; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -4619,7 +4703,7 @@ x_dnd_send_drop (struct frame *f, Window target, Window toplevel, if (supported >= 1) msg.xclient.data.l[2] = timestamp; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); return true; @@ -5666,7 +5750,8 @@ xi_device_from_id (struct x_display_info *dpyinfo, int deviceid) static void xi_link_touch_point (struct xi_device_t *device, - int detail, double x, double y) + int detail, double x, double y, + struct frame *frame) { struct xi_touch_point_t *touchpoint; @@ -5675,6 +5760,7 @@ xi_link_touch_point (struct xi_device_t *device, touchpoint->x = x; touchpoint->y = y; touchpoint->number = detail; + touchpoint->frame = frame; device->touchpoints = touchpoint; } @@ -5703,6 +5789,36 @@ xi_unlink_touch_point (int detail, return false; } +/* Unlink all touch points associated with the frame F. + This is done upon unmapping or destroying F's window, because + touch point delivery after that point is undefined. */ + +static void +xi_unlink_touch_points (struct frame *f) +{ + struct xi_device_t *device; + struct xi_touch_point_t **next, *last; + int i; + + for (i = 0; i < FRAME_DISPLAY_INFO (f)->num_devices; ++i) + { + device = &FRAME_DISPLAY_INFO (f)->devices[i]; + + /* Now unlink all touch points on DEVICE matching F. */ + + for (next = &device->touchpoints; (last = *next);) + { + if (last->frame == f) + { + *next = last->next; + xfree (last); + } + else + next = &last->next; + } + } +} + static struct xi_touch_point_t * xi_find_touch_point (struct xi_device_t *device, int detail) { @@ -6731,7 +6847,7 @@ x_set_frame_alpha (struct frame *f) Do this unconditionally as this function is called on reparent when alpha has not changed on the frame. */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); if (!FRAME_PARENT_FRAME (f)) { @@ -6907,6 +7023,7 @@ static void x_sync_wait_for_frame_drawn_event (struct frame *f) { XEvent event; + struct x_display_info *dpyinfo; if (!FRAME_X_WAITING_FOR_DRAW (f) /* The compositing manager can't draw a frame if it is @@ -6914,6 +7031,8 @@ x_sync_wait_for_frame_drawn_event (struct frame *f) || !FRAME_VISIBLE_P (f)) return; + dpyinfo = FRAME_DISPLAY_INFO (f); + /* Wait for the frame drawn message to arrive. */ if (x_if_event (FRAME_X_DISPLAY (f), &event, x_sync_is_frame_drawn_event, (XPointer) f, @@ -6929,6 +7048,11 @@ x_sync_wait_for_frame_drawn_event (struct frame *f) "been disabled\n"); FRAME_X_OUTPUT (f)->use_vsync_p = false; + /* Remove the compositor bypass property from the outer + window. */ + XDeleteProperty (dpyinfo->display, FRAME_OUTER_WINDOW (f), + dpyinfo->Xatom_net_wm_bypass_compositor); + /* Also change the frame parameter to reflect the new state. */ store_frame_param (f, Quse_frame_synchronization, Qnil); @@ -6942,7 +7066,7 @@ x_sync_wait_for_frame_drawn_event (struct frame *f) } } else - x_sync_note_frame_times (FRAME_DISPLAY_INFO (f), f, &event); + x_sync_note_frame_times (dpyinfo, f, &event); FRAME_X_WAITING_FOR_DRAW (f) = false; } @@ -7553,6 +7677,46 @@ x_after_update_window_line (struct window *w, struct glyph_row *desired_row) #endif } +/* Generate a premultiplied pixel value for COLOR with ALPHA applied + on the given display. COLOR will be modified. The display must + use a visual that supports an alpha channel. + + This is possibly dead code on builds which do not support + XRender. */ + +#ifndef USE_CAIRO + +static unsigned long +x_premultiply_pixel (struct x_display_info *dpyinfo, + XColor *color, double alpha) +{ + unsigned long pixel; + + eassert (dpyinfo->alpha_bits); + + /* Multiply the RGB channels. */ + color->red *= alpha; + color->green *= alpha; + color->blue *= alpha; + + /* First, allocate a fully opaque pixel. */ + pixel = x_make_truecolor_pixel (dpyinfo, color->red, + color->green, + color->blue); + + /* Next, erase the alpha component. */ + pixel &= ~dpyinfo->alpha_mask; + + /* And add an alpha channel. */ + pixel |= (((unsigned long) (alpha * 65535) + >> (16 - dpyinfo->alpha_bits)) + << dpyinfo->alpha_offset); + + return pixel; +} + +#endif + static void x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fringe_bitmap_params *p) @@ -7642,18 +7806,15 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, if (FRAME_DISPLAY_INFO (f)->alpha_bits && f->alpha_background < 1.0) { + /* Extend the background color with an alpha channel + according to f->alpha_background. */ bg.pixel = background; x_query_colors (f, &bg, 1); - bg.red *= f->alpha_background; - bg.green *= f->alpha_background; - bg.blue *= f->alpha_background; - background = x_make_truecolor_pixel (FRAME_DISPLAY_INFO (f), - bg.red, bg.green, bg.blue); - background &= ~FRAME_DISPLAY_INFO (f)->alpha_mask; - background |= (((unsigned long) (f->alpha_background * 0xffff) - >> (16 - FRAME_DISPLAY_INFO (f)->alpha_bits)) - << FRAME_DISPLAY_INFO (f)->alpha_offset); + background + = x_premultiply_pixel (FRAME_DISPLAY_INFO (f), + &bg, + f->alpha_background); } /* Draw the bitmap. I believe these small pixmaps can be cached @@ -8802,7 +8963,11 @@ x_color_cells (Display *dpy, int *ncells) /* On frame F, translate pixel colors to RGB values for the NCOLORS - colors in COLORS. Use cached information, if available. */ + colors in COLORS. Use cached information, if available. + + Pixel values are in unsigned normalized format, meaning that + extending missing bits is done straightforwardly without any + complex colorspace conversions. */ void x_query_colors (struct frame *f, XColor *colors, int ncolors) @@ -8850,6 +9015,7 @@ x_query_colors (struct frame *f, XColor *colors, int ncolors) colors[i].green = (g * gmult) >> 16; colors[i].blue = (b * bmult) >> 16; } + return; } @@ -8892,16 +9058,10 @@ x_query_frame_background_color (struct frame *f, XColor *bgcolor) { bg.pixel = background; x_query_colors (f, &bg, 1); - bg.red *= f->alpha_background; - bg.green *= f->alpha_background; - bg.blue *= f->alpha_background; - background = x_make_truecolor_pixel (FRAME_DISPLAY_INFO (f), - bg.red, bg.green, bg.blue); - background &= ~FRAME_DISPLAY_INFO (f)->alpha_mask; - background |= (((unsigned long) (f->alpha_background * 0xffff) - >> (16 - FRAME_DISPLAY_INFO (f)->alpha_bits)) - << FRAME_DISPLAY_INFO (f)->alpha_offset); + background + = x_premultiply_pixel (FRAME_DISPLAY_INFO (f), + &bg, f->alpha_background); } #endif } @@ -10991,6 +11151,31 @@ x_clear_frame (struct frame *f) unblock_input (); } +/* Send a message to frame F telling the event loop to track whether + or not an hourglass is being displayed. This is required to ignore + the right events when the hourglass is mapped without callig XSync + after displaying or hiding the hourglass. */ + +static void +x_send_hourglass_message (struct frame *f, bool hourglass_enabled) +{ + struct x_display_info *dpyinfo; + XEvent msg; + + dpyinfo = FRAME_DISPLAY_INFO (f); + memset (&msg, 0, sizeof msg); + + msg.xclient.type = ClientMessage; + msg.xclient.message_type + = dpyinfo->Xatom_EMACS_TMP; + msg.xclient.format = 8; + msg.xclient.window = FRAME_X_WINDOW (f); + msg.xclient.data.b[0] = hourglass_enabled ? 1 : 0; + + XSendEvent (dpyinfo->display, FRAME_X_WINDOW (f), + False, NoEventMask, &msg); +} + /* RIF: Show hourglass cursor on frame F. */ static void @@ -11011,14 +11196,14 @@ x_show_hourglass (struct frame *f) if (popup_activated ()) return; + x_send_hourglass_message (f, true); + #ifdef USE_X_TOOLKIT if (x->widget) #else if (FRAME_OUTER_WINDOW (f)) #endif { - x->hourglass_p = true; - if (!x->hourglass_window) { #ifndef USE_XCB @@ -11085,15 +11270,11 @@ x_hide_hourglass (struct frame *f) { #ifndef USE_XCB XUnmapWindow (FRAME_X_DISPLAY (f), x->hourglass_window); - /* Sync here because XTread_socket looks at the - hourglass_p flag that is reset to zero below. */ - XSync (FRAME_X_DISPLAY (f), False); #else xcb_unmap_window (FRAME_DISPLAY_INFO (f)->xcb_connection, (xcb_window_t) x->hourglass_window); - xcb_aux_sync (FRAME_DISPLAY_INFO (f)->xcb_connection); #endif - x->hourglass_p = false; + x_send_hourglass_message (f, false); } } @@ -11217,21 +11398,32 @@ XTflash (struct frame *f) static void XTring_bell (struct frame *f) { - if (FRAME_X_DISPLAY (f)) + struct x_display_info *dpyinfo; + + if (!FRAME_X_DISPLAY (f)) + return; + + dpyinfo = FRAME_DISPLAY_INFO (f); + + if (visible_bell) + XTflash (f); + else { - if (visible_bell) - XTflash (f); - else - { - block_input (); + /* When Emacs is untrusted, Bell requests sometimes generate + Access errors. This is not in the security extension + specification but seems to be a bug in the X consortium XKB + implementation. */ + + block_input (); + x_ignore_errors_for_next_request (dpyinfo, 0); #ifdef HAVE_XKB - XkbBell (FRAME_X_DISPLAY (f), None, 0, None); + XkbBell (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0, None); #else - XBell (FRAME_X_DISPLAY (f), 0); + XBell (FRAME_X_DISPLAY (f), 0); #endif - XFlush (FRAME_X_DISPLAY (f)); - unblock_input (); - } + XFlush (FRAME_X_DISPLAY (f)); + x_stop_ignoring_errors (dpyinfo); + unblock_input (); } } @@ -11477,7 +11669,7 @@ x_frame_highlight (struct frame *f) the window-manager in use, tho something more is at play since I've been using that same window-manager binary for ever. Let's not crash just because of this (bug#9310). */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), f->output_data.x->border_pixel); x_stop_ignoring_errors (dpyinfo); @@ -11500,7 +11692,7 @@ x_frame_unhighlight (struct frame *f) block_input (); /* Same as above for XSetWindowBorder (bug#9310). */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), f->output_data.x->border_tile); x_stop_ignoring_errors (dpyinfo); @@ -11564,7 +11756,7 @@ x_new_focus_frame (struct x_display_info *dpyinfo, struct frame *frame) x_frame_rehighlight (dpyinfo); } -#ifdef HAVE_XFIXES +#if defined HAVE_XFIXES && XFIXES_VERSION >= 40000 /* True if the display in DPYINFO supports a version of Xfixes sufficient for pointer blanking. */ @@ -11576,11 +11768,12 @@ x_fixes_pointer_blanking_supported (struct x_display_info *dpyinfo) && dpyinfo->xfixes_major >= 4); } -#endif /* HAVE_XFIXES */ +#endif /* HAVE_XFIXES && XFIXES_VERSION >= 40000 */ /* Toggle mouse pointer visibility on frame F using the XFixes extension. */ -#ifdef HAVE_XFIXES +#if defined HAVE_XFIXES && XFIXES_VERSION >= 40000 + static void xfixes_toggle_visible_pointer (struct frame *f, bool invisible) @@ -11591,6 +11784,7 @@ xfixes_toggle_visible_pointer (struct frame *f, bool invisible) XFixesShowCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); f->pointer_invisible = invisible; } + #endif /* HAVE_XFIXES */ /* Create invisible cursor on the X display referred by DPYINFO. */ @@ -11639,7 +11833,7 @@ x_toggle_visible_pointer (struct frame *f, bool invisible) if (dpyinfo->invisible_cursor == None) dpyinfo->invisible_cursor = make_invisible_cursor (dpyinfo); -#ifndef HAVE_XFIXES +#if !defined HAVE_XFIXES || XFIXES_VERSION < 40000 if (dpyinfo->invisible_cursor == None) invisible = false; #else @@ -11672,7 +11866,7 @@ static void XTtoggle_invisible_pointer (struct frame *f, bool invisible) { block_input (); -#ifdef HAVE_XFIXES +#if defined HAVE_XFIXES && XFIXES_VERSION >= 40000 if (FRAME_DISPLAY_INFO (f)->fixes_pointer_blanking && x_fixes_pointer_blanking_supported (FRAME_DISPLAY_INFO (f))) xfixes_toggle_visible_pointer (f, invisible); @@ -12261,6 +12455,13 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, struct xi_device_t *device; #endif + if (FRAME_DISPLAY_INFO (f)->untrusted) + /* Untrusted clients cannot send messages to trusted clients or + read the window tree, so drag and drop will likely not work at + all. */ + error ("Drag-and-drop is not possible when the client is" + " not trusted by the X server."); + base = SPECPDL_INDEX (); /* Bind this here to avoid juggling bindings and SAFE_FREE in @@ -13366,6 +13567,10 @@ xi_disable_devices (struct x_display_info *dpyinfo, #ifdef HAVE_XINPUT2_2 struct xi_touch_point_t *tem, *last; #endif +#if defined HAVE_XINPUT2_2 && !defined HAVE_EXT_TOOL_BAR + struct x_output *output; + Lisp_Object tail, frame; +#endif /* Don't pointlessly copy dpyinfo->devices if there are no devices to disable. */ @@ -13408,6 +13613,34 @@ xi_disable_devices (struct x_display_info *dpyinfo, tem = tem->next; xfree (last); } + +#ifndef HAVE_EXT_TOOL_BAR + + /* Now look through each frame on DPYINFO. If it has an + outstanding tool bar press for this device, release + the tool bar. */ + + FOR_EACH_FRAME (tail, frame) + { + if (!FRAME_X_P (XFRAME (frame)) + || (FRAME_DISPLAY_INFO (XFRAME (frame)) + != dpyinfo)) + continue; + + output = FRAME_OUTPUT_DATA (XFRAME (frame)); + + if (output->tool_bar_touch_device + == dpyinfo->devices[i].device_id) + { + if (XFRAME (frame)->last_tool_bar_item != -1 + && WINDOWP (XFRAME (frame)->tool_bar_window)) + handle_tool_bar_click (XFRAME (frame), 0, 0, + false, 0); + + output->tool_bar_touch_device = 0; + } + } +#endif #endif goto out; @@ -15032,9 +15265,7 @@ x_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part, XClientMessageEvent *ev = &event.xclient; struct window *w = XWINDOW (window); struct frame *f = XFRAME (w->frame); - intptr_t iw = (intptr_t) w; verify (INTPTR_WIDTH <= 64); - int sign_shift = INTPTR_WIDTH - 32; /* Don't do anything if too many scroll bar events have been sent but not received. */ @@ -15051,15 +15282,11 @@ x_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part, ev->window = FRAME_X_WINDOW (f); ev->format = 32; - /* A 32-bit X client can pass a window pointer through the X server - as-is. - - A 64-bit client is in trouble because a pointer does not fit in - the 32 bits given for ClientMessage data and will be truncated by - Xlib. So use two slots and hope that X12 will resolve such - issues someday. */ - ev->data.l[0] = iw >> 31 >> 1; - ev->data.l[1] = sign_shift <= 0 ? iw : iw << sign_shift >> sign_shift; + /* These messages formerly contained a pointer to the window, but + now that information is kept internally. The following two + fields are thus zero. */ + ev->data.l[0] = 0; + ev->data.l[1] = 0; ev->data.l[2] = part; ev->data.l[3] = portion; ev->data.l[4] = whole; @@ -18490,7 +18717,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_dnd_waiting_for_status_window = None; else { - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, target, False, NoEventMask, &x_dnd_pending_send_position); @@ -18604,6 +18831,16 @@ handle_one_xevent (struct x_display_info *dpyinfo, } } + if (event->xclient.message_type == dpyinfo->Xatom_EMACS_TMP + && event->xclient.format == 8) + { + /* This is actually an hourglass message. Set whether or + not events from here on have the hourglass enabled. */ + + if (any) + FRAME_X_OUTPUT (any)->hourglass_p = event->xclient.data.b[0]; + } + if (event->xclient.message_type == dpyinfo->Xatom_wm_protocols && event->xclient.format == 32) { @@ -19192,7 +19429,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) FRAME_OUTER_WINDOW (f), (xcb_atom_t) dpyinfo->Xatom_net_wm_window_opacity, - XCB_ATOM_CARDINAL, 0, 1); + XA_CARDINAL, 0, 1); opacity_reply = xcb_get_property_reply (dpyinfo->xcb_connection, opacity_cookie, &error); @@ -19201,9 +19438,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, free (error), rc = false; else rc = (opacity_reply->format == 32 - && (opacity_reply->type == XCB_ATOM_CARDINAL - || opacity_reply->type == XCB_ATOM_ATOM - || opacity_reply->type == XCB_ATOM_WINDOW) + && (opacity_reply->type == XA_CARDINAL + || opacity_reply->type == XA_ATOM + || opacity_reply->type == XA_WINDOW) && (xcb_get_property_value_length (opacity_reply) >= 4)); if (rc) @@ -21349,7 +21586,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf))) { - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), RevertToParent, event->xbutton.time); x_stop_ignoring_errors (dpyinfo); @@ -21570,9 +21807,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, case VisibilityNotify: f = x_top_window_to_frame (dpyinfo, event->xvisibility.window); - if (f && (event->xvisibility.state == VisibilityUnobscured - || event->xvisibility.state == VisibilityPartiallyObscured)) - SET_FRAME_VISIBLE (f, 1); + + if (f) + FRAME_X_OUTPUT (f)->visibility_state = event->xvisibility.state; goto OTHER; @@ -23047,7 +23284,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, /* This can generate XI_BadDevice if the device's attachment was destroyed server-side. */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XISetFocus (dpyinfo->display, device->attachment, /* Note that the input extension only supports RevertToParent-type @@ -23060,7 +23297,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, events to handle focus. Errors are still caught here in case the window is not viewable. */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), RevertToParent, xev->time); x_stop_ignoring_errors (dpyinfo); @@ -24036,6 +24273,73 @@ handle_one_xevent (struct x_display_info *dpyinfo, } #endif +#ifndef HAVE_EXT_TOOL_BAR + /* Is this a touch from a direct touch device that is in + the tool-bar? */ + if (device->direct_p + && WINDOWP (f->tool_bar_window) + && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window))) + { + Lisp_Object window; + int x = xev->event_x; + int y = xev->event_y; + + window = window_from_coordinates (f, x, y, 0, true, true); + /* Ignore button release events if the mouse + wasn't previously pressed on the tool bar. + We do this because otherwise selecting some + text with the mouse and then releasing it on + the tool bar doesn't stop selecting text, + since the tool bar eats the button up + event. */ + tool_bar_p = EQ (window, f->tool_bar_window); + + /* If this touch has started in the tool bar, do not + send it to Lisp. Instead, simulate a tool bar + click, releasing it once it goes away. */ + + if (tool_bar_p) + { + /* Call note_mouse_highlight on the tool bar + item. Otherwise, get_tool_bar_item will + return 1. + + This is not necessary when mouse-highlight is + nil. */ + + if (!NILP (Vmouse_highlight)) + { + note_mouse_highlight (f, x, y); + + /* Always allow future mouse motion to + update the mouse highlight, no matter + where it is. */ + memset (&dpyinfo->last_mouse_glyph, 0, + sizeof dpyinfo->last_mouse_glyph); + dpyinfo->last_mouse_glyph_frame = f; + } + + handle_tool_bar_click_with_device (f, x, y, true, 0, + (source + ? source->name : Qt)); + + /* Flush any changes made by that to the front + buffer. */ + x_flush_dirty_back_buffer_on (f); + + /* Record the device and the touch ID on the + frame. That way, Emacs knows when to dismiss + the tool bar click later. */ + + FRAME_OUTPUT_DATA (f)->tool_bar_touch_device + = device->device_id; + FRAME_OUTPUT_DATA (f)->tool_bar_touch_id = xev->detail; + + goto XI_OTHER; + } + } +#endif + if (!menu_bar_p && !tool_bar_p) { if (f && device->direct_p) @@ -24045,13 +24349,16 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_catch_errors (dpyinfo->display); if (x_input_grab_touch_events) - XIAllowTouchEvents (dpyinfo->display, xev->deviceid, - xev->detail, xev->event, XIAcceptTouch); + XIAllowTouchEvents (dpyinfo->display, + xev->deviceid, + xev->detail, xev->event, + XIAcceptTouch); if (!x_had_errors_p (dpyinfo->display)) { - xi_link_touch_point (device, xev->detail, xev->event_x, - xev->event_y); + xi_link_touch_point (device, xev->detail, + xev->event_x, + xev->event_y, f); inev.ie.kind = TOUCHSCREEN_BEGIN_EVENT; inev.ie.timestamp = xev->time; @@ -24069,7 +24376,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifndef HAVE_GTK3 else if (x_input_grab_touch_events) { - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XIAllowTouchEvents (dpyinfo->display, xev->deviceid, xev->detail, xev->event, XIRejectTouch); x_stop_ignoring_errors (dpyinfo); @@ -24126,10 +24433,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, for (touchpoint = device->touchpoints; touchpoint; touchpoint = touchpoint->next) { - arg = Fcons (list3i (lrint (touchpoint->x), - lrint (touchpoint->y), - lrint (touchpoint->number)), - arg); + if (touchpoint->frame == f) + arg = Fcons (list3i (lrint (touchpoint->x), + lrint (touchpoint->y), + lrint (touchpoint->number)), + arg); } if (source) @@ -24175,6 +24483,33 @@ handle_one_xevent (struct x_display_info *dpyinfo, } } +#ifndef HAVE_EXT_TOOL_BAR + /* Now see if the touchpoint was previously on the tool bar. + If it was, release the tool bar. */ + + if (!f) + f = x_window_to_frame (dpyinfo, xev->event); + + if (f && (FRAME_OUTPUT_DATA (f)->tool_bar_touch_id + == xev->detail)) + { + if (f->last_tool_bar_item != -1) + handle_tool_bar_click_with_device (f, xev->event_x, + xev->event_y, + false, 0, + (source + ? source->name + : Qnil)); + + /* Cancel any outstanding mouse highlight. */ + note_mouse_highlight (f, -1, -1); + x_flush_dirty_back_buffer_on (f); + + /* Now clear the tool bar device. */ + FRAME_OUTPUT_DATA (f)->tool_bar_touch_device = 0; + } +#endif + goto XI_OTHER; } @@ -25506,10 +25841,17 @@ x_clean_failable_requests (struct x_display_info *dpyinfo) x_uncatch_errors_after_check is that this function does not sync to catch errors if requests were made. It should be used instead of those two functions for catching errors around requests that do not - require a reply. */ + require a reply. + + As a special feature intended to support xselect.c, + SELECTION_SERIAL may be an arbitrary number greater than zero: when + that is the case, x_select_handle_selection_error is called with + the specified number to delete the selection request that + encountered the error. */ void -x_ignore_errors_for_next_request (struct x_display_info *dpyinfo) +x_ignore_errors_for_next_request (struct x_display_info *dpyinfo, + unsigned int selection_serial) { struct x_failable_request *request, *max; unsigned long next_request; @@ -25563,6 +25905,7 @@ x_ignore_errors_for_next_request (struct x_display_info *dpyinfo) request->start = next_request; request->end = 0; + request->selection_serial = selection_serial; dpyinfo->next_failable_request++; } @@ -25984,9 +26327,11 @@ For details, see etc/PROBLEMS.\n", if (!ioerror && dpyinfo) { /* Dump the list of error handlers for debugging - purposes. */ + purposes if the list exists. */ - fprintf (stderr, "X error handlers currently installed:\n"); + if ((dpyinfo->failable_requests + != dpyinfo->next_failable_request) || x_error_message) + fprintf (stderr, "X error handlers currently installed:\n"); for (failable = dpyinfo->failable_requests; failable < dpyinfo->next_failable_request; @@ -26075,6 +26420,12 @@ x_error_handler (Display *display, XErrorEvent *event) + (last - fail)); } + /* If a selection transfer is the cause of this error, + remove the selection transfer now. */ + if (fail->selection_serial) + x_handle_selection_error (fail->selection_serial, + event); + return 0; } } @@ -26111,8 +26462,10 @@ x_error_handler (Display *display, XErrorEvent *event) static void NO_INLINE x_error_quitter (Display *display, XErrorEvent *event) { - char buf[256], buf1[400 + INT_STRLEN_BOUND (int) - + INT_STRLEN_BOUND (unsigned long)]; + char buf[256], buf1[800 + INT_STRLEN_BOUND (int) + + INT_STRLEN_BOUND (unsigned long) + + INT_STRLEN_BOUND (XID) + + INT_STRLEN_BOUND (int)]; /* Ignore BadName errors. They can happen because of fonts or colors that are not defined. */ @@ -26125,8 +26478,12 @@ x_error_quitter (Display *display, XErrorEvent *event) XGetErrorText (display, event->error_code, buf, sizeof (buf)); sprintf (buf1, "X protocol error: %s on protocol request %d\n" - "Serial no: %lu\n", buf, event->request_code, - event->serial); + "Serial no: %lu\n" + "Failing resource ID (if any): 0x%lx\n" + "Minor code: %d\n" + "This is a bug! Please report this to bug-gnu-emacs@gnu.org!\n", + buf, event->request_code, event->serial, event->resourceid, + event->minor_code); x_connection_closed (display, buf1, false); } @@ -26627,38 +26984,43 @@ x_set_offset (struct frame *f, int xoff, int yoff, int change_gravity) modified_left, modified_top); #endif - /* 'x_sync_with_move' is too costly for dragging child frames. */ - if (!FRAME_PARENT_FRAME (f) - /* If no window manager exists, just calling XSync will be - sufficient to ensure that the window geometry has been - updated. */ - && NILP (Vx_no_window_manager)) - { - x_sync_with_move (f, f->left_pos, f->top_pos, - FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN); - - /* change_gravity is non-zero when this function is called from Lisp to - programmatically move a frame. In that case, we call - x_check_expected_move to discover if we have a "Type A" or "Type B" - window manager, and, for a "Type A" window manager, adjust the position - of the frame. - - We call x_check_expected_move if a programmatic move occurred, and - either the window manager type (A/B) is unknown or it is Type A but we - need to compute the top/left offset adjustment for this frame. */ - - if (change_gravity != 0 - && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN - || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A - && (FRAME_X_OUTPUT (f)->move_offset_left == 0 - && FRAME_X_OUTPUT (f)->move_offset_top == 0)))) - x_check_expected_move (f, modified_left, modified_top); - } - /* Instead, just wait for the last ConfigureWindow request to - complete. No window manager is involved when moving child - frames. */ - else - XSync (FRAME_X_DISPLAY (f), False); + /* The following code is too slow over a latent network + connection. */ + if (NILP (Vx_lax_frame_positioning)) + { + /* 'x_sync_with_move' is too costly for dragging child frames. */ + if (!FRAME_PARENT_FRAME (f) + /* If no window manager exists, just calling XSync will be + sufficient to ensure that the window geometry has been + updated. */ + && NILP (Vx_no_window_manager)) + { + x_sync_with_move (f, f->left_pos, f->top_pos, + FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN); + + /* change_gravity is non-zero when this function is called from Lisp to + programmatically move a frame. In that case, we call + x_check_expected_move to discover if we have a "Type A" or "Type B" + window manager, and, for a "Type A" window manager, adjust the position + of the frame. + + We call x_check_expected_move if a programmatic move occurred, and + either the window manager type (A/B) is unknown or it is Type A but we + need to compute the top/left offset adjustment for this frame. */ + + if (change_gravity != 0 + && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN + || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A + && (FRAME_X_OUTPUT (f)->move_offset_left == 0 + && FRAME_X_OUTPUT (f)->move_offset_top == 0)))) + x_check_expected_move (f, modified_left, modified_top); + } + /* Instead, just wait for the last ConfigureWindow request to + complete. No window manager is involved when moving child + frames. */ + else + XSync (FRAME_X_DISPLAY (f), False); + } unblock_input (); } @@ -26718,6 +27080,12 @@ x_wm_supports_1 (struct x_display_info *dpyinfo, Atom want_atom) if (!NILP (Vx_no_window_manager)) return false; + /* If the window system says Emacs is untrusted, there will be no + way to send any information to the window manager, making any + hints useless. */ + if (dpyinfo->untrusted) + return false; + block_input (); x_catch_errors (dpy); @@ -27188,13 +27556,12 @@ do_ewmh_fullscreen (struct frame *f) static void XTfullscreen_hook (struct frame *f) { - if (FRAME_VISIBLE_P (f)) - { - block_input (); - x_check_fullscreen (f); - x_sync (f); - unblock_input (); - } + if (!FRAME_VISIBLE_P (f)) + return; + + block_input (); + x_check_fullscreen (f); + unblock_input (); } @@ -27288,10 +27655,7 @@ x_check_fullscreen (struct frame *f) if (FRAME_VISIBLE_P (f)) x_wait_for_event (f, ConfigureNotify); else - { - change_frame_size (f, width, height, false, true, false); - x_sync (f); - } + change_frame_size (f, width, height, false, true, false); } /* `x_net_wm_state' might have reset the fullscreen frame parameter, @@ -27465,6 +27829,12 @@ x_set_window_size_1 (struct frame *f, bool change_gravity, we have to make sure to do it here. */ SET_FRAME_GARBAGED (f); + /* The following code is too slow over a latent network + connection, so skip it when the user says so. */ + + if (!NILP (Vx_lax_frame_positioning)) + return; + /* Now, strictly speaking, we can't be sure that this is accurate, but the window manager will get around to dealing with the size change request eventually, and we'll hear how it went when the @@ -27505,8 +27875,6 @@ x_set_window_size_1 (struct frame *f, bool change_gravity, adjust_frame_size (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, width), FRAME_PIXEL_TO_TEXT_HEIGHT (f, height), 5, 0, Qx_set_window_size_1); - - x_sync (f); } } @@ -27560,7 +27928,7 @@ frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y) && deviceid != -1) { block_input (); - x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f)); + x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f), 0); XIWarpPointer (FRAME_X_DISPLAY (f), deviceid, None, FRAME_X_WINDOW (f), 0, 0, 0, 0, pix_x, pix_y); x_stop_ignoring_errors (FRAME_DISPLAY_INFO (f)); @@ -27857,7 +28225,7 @@ x_set_input_focus (struct x_display_info *dpyinfo, Window window, { eassert (device->use == XIMasterPointer); - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XISetFocus (dpyinfo->display, device->attachment, /* Note that the input extension only supports RevertToParent-type @@ -27872,7 +28240,7 @@ x_set_input_focus (struct x_display_info *dpyinfo, Window window, /* Otherwise, use the pointer device that the X server says is the client pointer. */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSetInputFocus (dpyinfo->display, window, RevertToParent, time); x_stop_ignoring_errors (dpyinfo); } @@ -27892,12 +28260,17 @@ x_focus_frame (struct frame *f, bool noactivate) struct x_display_info *dpyinfo; Time time; + dpyinfo = FRAME_DISPLAY_INFO (f); + + if (dpyinfo->untrusted) + /* The X server ignores all input focus related requests from + untrusted clients. */ + return; + /* The code below is not reentrant wrt to dpyinfo->x_focus_frame and friends being set. */ block_input (); - dpyinfo = FRAME_DISPLAY_INFO (f); - if (FRAME_X_EMBEDDED_P (f)) /* For Xembedded frames, normally the embedder forwards key events. See XEmbed Protocol Specification at @@ -28009,7 +28382,7 @@ xembed_send_message (struct frame *f, Time t, enum xembed_message msg, but I don't understand why: there is no way for clients to survive the death of the parent anyway. */ - x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f)); + x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f), 0); XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_OUTPUT (f)->parent_desc, False, NoEventMask, &event); x_stop_ignoring_errors (FRAME_DISPLAY_INFO (f)); @@ -28160,6 +28533,7 @@ x_make_frame_visible (struct frame *f) && !FRAME_ICONIFIED_P (f) && !FRAME_X_EMBEDDED_P (f) && !FRAME_PARENT_FRAME (f) + && NILP (Vx_lax_frame_positioning) && f->win_gravity == NorthWestGravity && previously_visible) { @@ -28188,7 +28562,8 @@ x_make_frame_visible (struct frame *f) } /* Try to wait for a MapNotify event (that is what tells us when a - frame becomes visible). */ + frame becomes visible). Unless `x-lax-frame-positioning' is + non-nil: there, that is a little slow. */ #ifdef CYGWIN /* On Cygwin, which uses input polling, we need to force input to @@ -28206,7 +28581,8 @@ x_make_frame_visible (struct frame *f) poll_suppress_count = old_poll_suppress_count; #endif - if (!FRAME_VISIBLE_P (f)) + if (!FRAME_VISIBLE_P (f) + && NILP (Vx_lax_frame_positioning)) { if (CONSP (frame_size_history)) frame_size_history_plain @@ -28239,6 +28615,11 @@ x_make_frame_invisible (struct frame *f) block_input (); +#ifdef HAVE_XINPUT2_2 + /* Remove any touch points associated with F. */ + xi_unlink_touch_points (f); +#endif + /* Before unmapping the window, update the WM_SIZE_HINTS property to claim that the current position of the window is user-specified, rather than program-specified, so that when the window is mapped again, it will be @@ -28263,7 +28644,10 @@ x_make_frame_invisible (struct frame *f) error ("Can't notify window manager of window withdrawal"); } - x_sync (f); + /* Don't perform the synchronization if the network connection is + slow, and the user says it is unwanted. */ + if (NILP (Vx_lax_frame_positioning)) + XSync (FRAME_X_DISPLAY (f), False); /* We can't distinguish this from iconification just by the event that we get from the server. @@ -28274,8 +28658,7 @@ x_make_frame_invisible (struct frame *f) SET_FRAME_ICONIFIED (f, false); if (CONSP (frame_size_history)) - frame_size_history_plain - (f, build_string ("x_make_frame_invisible")); + frame_size_history_plain (f, build_string ("x_make_frame_invisible")); unblock_input (); } @@ -28442,6 +28825,11 @@ x_free_frame_resources (struct frame *f) xi_handle_delete_frame (dpyinfo, f); #endif +#ifdef HAVE_XINPUT2_2 + /* Remove any touch points associated with F. */ + xi_unlink_touch_points (f); +#endif + /* If a display connection is dead, don't try sending more commands to the X server. */ if (dpyinfo->display) @@ -28625,6 +29013,13 @@ x_free_frame_resources (struct frame *f) if (f == hlinfo->mouse_face_mouse_frame) reset_mouse_highlight (hlinfo); + /* These two need to be freed now that they are used to compute the + mouse position, I think. */ + if (f == dpyinfo->last_mouse_motion_frame) + dpyinfo->last_mouse_motion_frame = NULL; + if (f == dpyinfo->last_mouse_frame) + dpyinfo->last_mouse_frame = NULL; + #ifdef HAVE_XINPUT2 /* Consider a frame being unfocused with no following FocusIn event while an older focus from another seat exists. The client @@ -28861,6 +29256,53 @@ x_get_atom_name (struct x_display_info *dpyinfo, Atom atom, return value; } +/* Intern an array of atoms, and do so quickly, avoiding extraneous + roundtrips to the X server. + + Avoid sending atoms that have already been found to the X server. + This cannot do anything that will end up triggering garbage + collection. */ + +void +x_intern_atoms (struct x_display_info *dpyinfo, char **names, int count, + Atom *atoms_return) +{ + int i, j, indices[256]; + char *new_names[256]; + Atom results[256], candidate; + + if (count > 256) + /* Atoms array too big to inspect reasonably, just send it to the + server and back. */ + XInternAtoms (dpyinfo->display, new_names, count, False, atoms_return); + else + { + for (i = 0, j = 0; i < count; ++i) + { + candidate = x_intern_cached_atom (dpyinfo, names[i], + true); + + if (candidate) + atoms_return[i] = candidate; + else + { + indices[j++] = i; + new_names[j - 1] = names[i]; + } + } + + if (!j) + return; + + /* Now, get the results back from the X server. */ + XInternAtoms (dpyinfo->display, new_names, j, False, + results); + + for (i = 0; i < j; ++i) + atoms_return[indices[i]] = results[i]; + } +} + #ifndef USE_GTK /* Set up XEmbed for F, and change its save set to handle the parent @@ -29409,6 +29851,7 @@ struct x_display_info * x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) { Display *dpy; + XKeyboardState keyboard_state; struct terminal *terminal; struct x_display_info *dpyinfo; XrmDatabase xrdb; @@ -29628,6 +30071,32 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) dpyinfo = xzalloc (sizeof *dpyinfo); terminal = x_create_terminal (dpyinfo); + if (!NILP (Vx_detect_server_trust)) + { + /* Detect whether or not the X server trusts this client, which + is done by making a SetKeyboardControl request and checking + for an Access error. */ + XGrabServer (dpy); + XGetKeyboardControl (dpy, &keyboard_state); + + x_catch_errors (dpy); + + /* At this point, the display is not on x_display_list, so + x_uncatch_errors won't sync. However, that's okay because + x_had_errors_p will. */ + + if (keyboard_state.global_auto_repeat + == AutoRepeatModeOn) + XAutoRepeatOn (dpy); + else + XAutoRepeatOff (dpy); + + if (x_had_errors_p (dpy)) + dpyinfo->untrusted = true; + x_uncatch_errors_after_check (); + XUngrabServer (dpy); + } + dpyinfo->next_failable_request = dpyinfo->failable_requests; { @@ -29648,13 +30117,17 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) { char *vendor = ServerVendor (dpy); - /* Temporarily hide the partially initialized terminal. */ + /* Temporarily hide the partially initialized terminal. + Use safe_call so that if a signal happens, a partially + initialized display (and display connection) is not + kept around. */ terminal_list = terminal->next_terminal; unblock_input (); - kset_system_key_alist - (terminal->kboard, - call1 (Qvendor_specific_keysyms, - vendor ? build_string (vendor) : empty_unibyte_string)); + kset_system_key_alist (terminal->kboard, + safe_call1 (Qvendor_specific_keysyms, + (vendor + ? build_string (vendor) + : empty_unibyte_string))); block_input (); terminal->next_terminal = terminal_list; terminal_list = terminal; @@ -30272,7 +30745,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) 1, 0, 1); dpyinfo->invisible_cursor = make_invisible_cursor (dpyinfo); -#ifdef HAVE_XFIXES +#if defined HAVE_XFIXES && XFIXES_VERSION >= 40000 dpyinfo->fixes_pointer_blanking = egetenv ("EMACS_XFIXES"); #endif @@ -30600,8 +31073,13 @@ x_delete_display (struct x_display_info *dpyinfo) last = ie; } + /* Delete selection requests bound for dpyinfo from the keyboard + buffer. */ x_delete_selection_requests (dpyinfo); + /* And remove any outstanding selection transfers. */ + x_remove_selection_transfers (dpyinfo); + if (next_noop_dpyinfo == dpyinfo) next_noop_dpyinfo = dpyinfo->next; @@ -31107,7 +31585,7 @@ x_catch_errors_for_lisp (struct x_display_info *dpyinfo) if (!x_fast_protocol_requests) x_catch_errors (dpyinfo->display); else - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); } void @@ -31316,6 +31794,8 @@ syms_of_xterm (void) DEFSYM (Qnow, "now"); DEFSYM (Qx_dnd_targets_list, "x-dnd-targets-list"); DEFSYM (Qx_auto_preserve_selections, "x-auto-preserve-selections"); + DEFSYM (Qexpose, "expose"); + DEFSYM (Qdont_save, "dont-save"); #ifdef USE_GTK xg_default_icon_file = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg"); @@ -31485,7 +31965,6 @@ always uses gtk_window_move and ignores the value of this variable. */); This option is only effective when Emacs is built with XInput 2 support. */); Vx_scroll_event_delta_factor = make_float (1.0); - DEFSYM (Qexpose, "expose"); DEFVAR_BOOL ("x-gtk-use-native-input", x_gtk_use_native_input, doc: /* Non-nil means to use GTK for input method support. @@ -31699,4 +32178,26 @@ select text over slow X connections. If that is still too slow, setting this variable to the symbol `really-fast' will make Emacs return only cached values. */); Vx_use_fast_mouse_position = Qnil; + + DEFVAR_LISP ("x-detect-server-trust", Vx_detect_server_trust, + doc: /* If non-nil, Emacs should detect whether or not it is trusted by X. + +If non-nil, Emacs will make an X request at connection startup that is +prohibited to untrusted clients under the X Security Extension and +check whether or not a resulting Access error is generated by the X +server. If the X server reports the error, Emacs will disable certain +features that do not work for untrusted clients. */); + Vx_detect_server_trust = Qnil; + + DEFVAR_LISP ("x-lax-frame-positioning", Vx_lax_frame_positioning, + doc: /* If non-nil, Emacs won't compensate for WM geometry behavior. + +Setting this to non-nil is useful when the compensation proves to be +too slow, which is usually true when the X server is located over a +network connection with high latency. Doing so will make frame +creation and placement faster at the cost of reducing the accuracy of +frame placement via frame parameters, `set-frame-position', and +`set-frame-size', along with the actual state of a frame after +`x_make_frame_invisible'. */); + Vx_lax_frame_positioning = Qnil; } diff --git a/src/xterm.h b/src/xterm.h index 8834346e7ca..28ae00ca190 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -21,6 +21,22 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #define XTERM_H #include <X11/Xlib.h> + +#ifdef HAVE_XFIXES +#include <X11/extensions/Xfixes.h> + +#if defined HAVE_XINPUT2 && XFIXES_MAJOR < 5 +/* XI2 headers need PointerBarrier, which is not defined in old + versions of the fixes library. Define that type here. */ +typedef XID PointerBarrier; +#endif +#if defined HAVE_XCOMPOSITE && XFIXES_MAJOR < 2 +/* Recent Composite headers need XserverRegion, which is not defined + in old versions of the fixes library. Define that type here. */ +typedef XID XserverRegion; +#endif +#endif + #include <X11/cursorfont.h> /* Include Xutil.h after keysym.h to work around a bug that prevents @@ -241,10 +257,17 @@ struct xi_scroll_valuator_t struct xi_touch_point_t { + /* The next touch point in this list. */ struct xi_touch_point_t *next; + /* The touchpoint detail. */ int number; + + /* The last known X and Y position of the touchpoint. */ double x, y; + + /* The frame associated with this touch point. */ + struct frame *frame; }; #endif @@ -318,6 +341,9 @@ struct x_failable_request /* If this is zero, then the request has not yet been made. Otherwise, this is the request that ends this sequence. */ unsigned long end; + + /* Any selection event serial associated with this error trap. */ + unsigned int selection_serial; }; #ifdef HAVE_XFIXES @@ -360,6 +386,10 @@ struct x_display_info /* Number of frames that are on this display. */ int reference_count; + /* True if this display connection cannot communicate with the + window manager because it is not trusted by the X server. */ + bool untrusted; + /* The Screen this connection is connected to. */ Screen *screen; @@ -406,7 +436,7 @@ struct x_display_info Unused if this display supports Xfixes extension. */ Cursor invisible_cursor; -#ifdef HAVE_XFIXES +#if defined HAVE_XFIXES && XFIXES_VERSION >= 40000 /* Whether or not to use Xfixes for pointer blanking. */ bool fixes_pointer_blanking; #endif @@ -537,6 +567,12 @@ struct x_display_info KDE" protocol in x-dnd.el). */ Atom Xatom_DndProtocol, Xatom_DND_PROTOCOL; + /* Atoms to make x_intern_cached_atom fast. */ + Atom Xatom_text_plain_charset_utf_8, Xatom_LENGTH, Xatom_FILE_NAME, + Xatom_CHARACTER_POSITION, Xatom_LINE_NUMBER, Xatom_COLUMN_NUMBER, + Xatom_OWNER_OS, Xatom_HOST_NAME, Xatom_USER, Xatom_CLASS, + Xatom_NAME, Xatom_SAVE_TARGETS; + /* The frame (if any) which has the X window that has keyboard focus. Zero if none. This is examined by Ffocus_frame in xfns.c. Note that a mere EnterNotify event can set this; if you need to know the @@ -1261,6 +1297,21 @@ struct x_output strictly an optimization to avoid extraneous synchronizing in some cases. */ int root_x, root_y; + + /* The frame visibility state. This starts out + VisibilityFullyObscured, but is set to something else in + handle_one_xevent. */ + int visibility_state; + +#ifdef HAVE_XINPUT2_2 + /* The touch ID of the last touch point to have touched the tool + bar. */ + int tool_bar_touch_id; + + /* The device that last touched the tool bar. 0 if no device + touched the tool bar. */ + int tool_bar_touch_device; +#endif }; enum @@ -1379,6 +1430,11 @@ extern void x_mark_frame_dirty (struct frame *f); /* And its corresponding visual info. */ #define FRAME_X_VISUAL_INFO(f) (&FRAME_DISPLAY_INFO (f)->visual_info) +/* Whether or not the frame is visible. Do not test this alone. + Instead, use FRAME_REDISPLAY_P. */ +#define FRAME_X_VISIBLE(f) (FRAME_X_OUTPUT (f)->visibility_state \ + != VisibilityFullyObscured) + #ifdef HAVE_XRENDER #define FRAME_X_PICTURE_FORMAT(f) FRAME_DISPLAY_INFO (f)->pict_format #define FRAME_X_PICTURE(f) ((f)->output_data.x->picture) @@ -1644,7 +1700,8 @@ extern bool x_had_errors_p (Display *); extern void x_unwind_errors_to (int); extern void x_uncatch_errors (void); extern void x_uncatch_errors_after_check (void); -extern void x_ignore_errors_for_next_request (struct x_display_info *); +extern void x_ignore_errors_for_next_request (struct x_display_info *, + unsigned int); extern void x_stop_ignoring_errors (struct x_display_info *); extern void x_clear_errors (Display *); extern void x_set_window_size (struct frame *, bool, int, int); @@ -1717,6 +1774,11 @@ extern Lisp_Object x_handle_translate_coordinates (struct frame *, Lisp_Object, extern Bool x_query_pointer (Display *, Window, Window *, Window *, int *, int *, int *, int *, unsigned int *); +extern Atom x_intern_cached_atom (struct x_display_info *, const char *, + bool); +extern void x_intern_atoms (struct x_display_info *, char **, int, Atom *); +extern char *x_get_atom_name (struct x_display_info *, Atom, bool *) + ATTRIBUTE_MALLOC ATTRIBUTE_DEALLOC_FREE; #ifdef HAVE_GTK3 extern void x_scroll_bar_configure (GdkEvent *); @@ -1798,6 +1860,9 @@ extern void x_handle_property_notify (const XPropertyEvent *); extern void x_handle_selection_notify (const XSelectionEvent *); extern void x_handle_selection_event (struct selection_input_event *); extern void x_clear_frame_selections (struct frame *); +extern void x_remove_selection_transfers (struct x_display_info *); +extern void x_handle_selection_error (unsigned int, XErrorEvent *); + extern Lisp_Object x_atom_to_symbol (struct x_display_info *, Atom); extern Atom symbol_to_x_atom (struct x_display_info *, Lisp_Object); @@ -1807,11 +1872,8 @@ extern bool x_handle_dnd_message (struct frame *, struct input_event *, bool, int, int); extern int x_check_property_data (Lisp_Object); -extern void x_fill_property_data (Display *, - Lisp_Object, - void *, - int, - int); +extern void x_fill_property_data (struct x_display_info *, Lisp_Object, + void *, int, int); extern Lisp_Object x_property_data_to_lisp (struct frame *, const unsigned char *, Atom, @@ -1824,10 +1886,10 @@ extern Lisp_Object x_timestamp_for_selection (struct x_display_info *, Lisp_Object); extern void x_own_selection (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Time); -extern Atom x_intern_cached_atom (struct x_display_info *, const char *, - bool); -extern char *x_get_atom_name (struct x_display_info *, Atom, bool *) - ATTRIBUTE_MALLOC ATTRIBUTE_DEALLOC_FREE; + +extern void mark_xselect (void); + +/* Misc definitions. */ #ifdef USE_GTK extern bool xg_set_icon (struct frame *, Lisp_Object); diff --git a/test/Makefile.in b/test/Makefile.in index fd21695f5bc..f4b85e7dfe5 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -264,8 +264,8 @@ endif GMP_H = @GMP_H@ LIBGMP = @LIBGMP@ -LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@ -LIB_NANOSLEEP = @LIB_NANOSLEEP@ +CLOCK_TIME_LIB = @CLOCK_TIME_LIB@ +NANOSLEEP_LIB = @NANOSLEEP_LIB@ MODULE_CFLAGS = $(and $(GMP_H),-I.) -I../src -I$(srcdir)/../src \ $(FPIC_CFLAGS) $(PROFILING_CFLAGS) \ @@ -286,7 +286,7 @@ $(test_module): $(test_module:${SO}=.c) ../src/emacs-module.h \ $(AM_V_at)$(CC) -shared $(CPPFLAGS) $(MODULE_CFLAGS) $(LDFLAGS) \ -o $@ $< $(LIBGMP) \ $(and $(GMP_H),$(srcdir)/../lib/mini-gmp.c) \ - $(LIB_CLOCK_GETTIME) $(LIB_NANOSLEEP) + $(CLOCK_TIME_LIB) $(NANOSLEEP_LIB) endif src/emacs-tests.log: ../lib-src/seccomp-filter.c diff --git a/test/lisp/elide-head-tests.el b/test/lisp/elide-head-tests.el index d751eee06a0..40a9d365f37 100644 --- a/test/lisp/elide-head-tests.el +++ b/test/lisp/elide-head-tests.el @@ -180,6 +180,90 @@ ;; along with Mentor. If not, see <https://www.gnu.org/licenses>. " "Mentor is distributed in the hope that") +;; from GnuTLS [has a line break in snail mail address] +(elide-head--add-test gpl3-6 "\ +# This file is part of GnuTLS. +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +# USA +" "This program is distributed in the hope that") + +;; from GnuTLS [has a different line break in snail mail address] +(elide-head--add-test gpl3-7 "\ +# This file is part of GnuTLS. +# +# The GnuTLS is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; either version 2.1 of +# the License, or (at your option) any later version. +# +# The GnuTLS 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with GnuTLS; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA +" "The GnuTLS is distributed in the hope that") + +;; from GnuTLS [has a typo in the 02111-1301 part] +(elide-head--add-test gpl3-8 "\ +/* nettle, low-level cryptographics library + * + * Copyright (C) 2002 Niels Möller + * Copyright (C) 2014 Red Hat + *\s\s + * The nettle library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + *\s + * The nettle library 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 Lesser General Public + * License for more details. + *\s + * You should have received a copy of the GNU Lesser General Public License + * along with the nettle library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02111-1301, USA. + */ +" "The nettle library is distributed in the hope that") + +;; from GnuTLS-EXTRA [has a different line break in snail mail address] +(elide-head--add-test gpl3-9 "\ +# This file is part of GnuTLS-EXTRA. +# +# GnuTLS-extra 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. +# +# GnuTLS-extra 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 GnuTLS-EXTRA; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. +" "GnuTLS-extra is distributed in the hope that") + ;;; GPLv2 @@ -201,6 +285,28 @@ " "This program is distributed in the hope that") +;;; Apache License + +(elide-head--add-test apache1-1 "\ +/* + * Copyright 2011-2016 The Pkcs11Interop Project + * + * Licensed under the Apache License, Version 2.0 (the \"License\"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an \"AS IS\" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +" "Unless required by applicable law") + + + ;;; Obsolete (with-suppressed-warnings ((obsolete elide-head) diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el b/test/lisp/emacs-lisp/bytecomp-tests.el index 7ae10cdea73..2fdf7389fc1 100644 --- a/test/lisp/emacs-lisp/bytecomp-tests.el +++ b/test/lisp/emacs-lisp/bytecomp-tests.el @@ -704,6 +704,59 @@ inner loops respectively." (let ((bytecomp-tests--xx 1)) (set (make-local-variable 'bytecomp-tests--xx) 2) bytecomp-tests--xx) + + ;; Check for-effect optimisation of `condition-case' body form. + ;; With `condition-case' in for-effect context: + (let ((x (bytecomp-test-identity ?A)) + (r nil)) + (condition-case e + (characterp x) ; value (:success, var) + (error (setq r 'bad)) + (:success (setq r (list 'good e)))) + r) + (let ((x (bytecomp-test-identity ?B)) + (r nil)) + (condition-case nil + (characterp x) ; for-effect (:success, no var) + (error (setq r 'bad)) + (:success (setq r 'good))) + r) + (let ((x (bytecomp-test-identity ?C)) + (r nil)) + (condition-case e + (characterp x) ; for-effect (no :success, var) + (error (setq r (list 'bad e)))) + r) + (let ((x (bytecomp-test-identity ?D)) + (r nil)) + (condition-case nil + (characterp x) ; for-effect (no :success, no var) + (error (setq r 'bad))) + r) + ;; With `condition-case' in value context: + (let ((x (bytecomp-test-identity ?E))) + (condition-case e + (characterp x) ; for-effect (:success, var) + (error (list 'bad e)) + (:success (list 'good e)))) + (let ((x (bytecomp-test-identity ?F))) + (condition-case nil + (characterp x) ; for-effect (:success, no var) + (error 'bad) + (:success 'good))) + (let ((x (bytecomp-test-identity ?G))) + (condition-case e + (characterp x) ; value (no :success, var) + (error (list 'bad e)))) + (let ((x (bytecomp-test-identity ?H))) + (condition-case nil + (characterp x) ; value (no :success, no var) + (error 'bad))) + + (condition-case nil + (bytecomp-test-identity 3) + (error 'bad) + (:success)) ; empty handler ) "List of expressions for cross-testing interpreted and compiled code.") @@ -833,13 +886,19 @@ byte-compiled. Run with dynamic binding." ;; Should not warn that mt--test2 is not known to be defined. (should-not (re-search-forward "my--test2" nil t)))) -(defmacro bytecomp--with-warning-test (re-warning &rest form) +(defmacro bytecomp--with-warning-test (re-warning form) (declare (indent 1)) `(with-current-buffer (get-buffer-create "*Compile-Log*") (let ((inhibit-read-only t)) (erase-buffer)) - (byte-compile ,@form) - (ert-info ((prin1-to-string (buffer-string)) :prefix "buffer: ") - (should (re-search-forward ,(string-replace " " "[ \n]+" re-warning)))))) + (let ((text-quoting-style 'grave) + (macroexp--warned + (make-hash-table :test #'equal :weakness 'key)) ; oh dear + (form ,form)) + (ert-info ((prin1-to-string form) :prefix "form: ") + (byte-compile form) + (ert-info ((prin1-to-string (buffer-string)) :prefix "buffer: ") + (should (re-search-forward + (string-replace " " "[ \n]+" ,re-warning)))))))) (ert-deftest bytecomp-warn-wrong-args () (bytecomp--with-warning-test "remq.*3.*2" @@ -863,6 +922,66 @@ byte-compiled. Run with dynamic binding." (bytecomp--with-warning-test "defvar.*foo.*wider than.*characters" `(defvar foo t ,bytecomp-tests--docstring))) +(ert-deftest bytecomp-warn-quoted-condition () + (bytecomp--with-warning-test + "Warning: `condition-case' condition should not be quoted: 'arith-error" + '(condition-case nil + (abc) + ('arith-error "ugh"))) + (bytecomp--with-warning-test + "Warning: `ignore-error' condition argument should not be quoted: 'error" + '(ignore-error 'error (abc)))) + +(ert-deftest bytecomp-warn-dodgy-args-eq () + (dolist (fn '(eq eql)) + (cl-flet ((msg (type arg) + (format + "`%s' called with literal %s that may never match (arg %d)" + fn type arg))) + (bytecomp--with-warning-test (msg "list" 1) `(,fn '(a) 'x)) + (bytecomp--with-warning-test (msg "string" 2) `(,fn 'x "a")) + (bytecomp--with-warning-test (msg "vector" 2) `(,fn 'x [a])) + (bytecomp--with-warning-test (msg "function" 2) `(,fn 'x (lambda () 1))) + (bytecomp--with-warning-test (msg "function" 2) `(,fn 'x #'(lambda () 1))) + (unless (eq fn 'eql) + (bytecomp--with-warning-test (msg "integer" 2) `(,fn 'x #x10000000000)) + (bytecomp--with-warning-test (msg "float" 2) `(,fn 'x 1.0)))))) + +(ert-deftest bytecomp-warn-dodgy-args-memq () + (dolist (fn '(memq memql remq delq assq rassq)) + (cl-labels + ((msg1 (type) + (format + "`%s' called with literal %s that may never match (arg 1)" + fn type)) + (msg2 (type) + (format + "`%s' called with literal %s that may never match (element 2 of arg 2)" + fn type)) + (lst (elt) + (cond ((eq fn 'assq) `((a . 1) (,elt . 2) (c . 3))) + ((eq fn 'rassq) `((1 . a) (2 . ,elt) (3 . c))) + (t `(a ,elt c)))) + (form2 (elt) + `(,fn 'x ',(lst elt)))) + + (bytecomp--with-warning-test (msg1 "list") `(,fn '(a) '(x))) + (bytecomp--with-warning-test (msg1 "string") `(,fn "a" '(x))) + (bytecomp--with-warning-test (msg1 "vector") `(,fn [a] '(x))) + (bytecomp--with-warning-test (msg1 "function") `(,fn (lambda () 1) '(x))) + (bytecomp--with-warning-test (msg1 "function") `(,fn #'(lambda () 1) '(x))) + (unless (eq fn 'memql) + (bytecomp--with-warning-test (msg1 "integer") `(,fn #x10000000000 '(x))) + (bytecomp--with-warning-test (msg1 "float") `(,fn 1.0 '(x)))) + + (bytecomp--with-warning-test (msg2 "list") (form2 '(b))) + (bytecomp--with-warning-test (msg2 "list") (form2 ''b)) + (bytecomp--with-warning-test (msg2 "string") (form2 "b")) + (bytecomp--with-warning-test (msg2 "vector") (form2 [b])) + (unless (eq fn 'memql) + (bytecomp--with-warning-test (msg2 "integer") (form2 #x10000000000)) + (bytecomp--with-warning-test (msg2 "float") (form2 1.0)))))) + (defmacro bytecomp--define-warning-file-test (file re-warning &optional reverse) `(ert-deftest ,(intern (format "bytecomp/%s" file)) () (with-current-buffer (get-buffer-create "*Compile-Log*") @@ -1314,7 +1433,50 @@ literals (Bug#20852)." (set-buffer (get-buffer-create "foo")) nil)) '((suspicious set-buffer)) - "Warning: Use .with-current-buffer. rather than")) + "Warning: Use .with-current-buffer. rather than") + + (test-suppression + '(defun zot () + (let ((_ 1)) + )) + '((empty-body let)) + "Warning: `let' with empty body") + + (test-suppression + '(defun zot () + (let* ((_ 1)) + )) + '((empty-body let*)) + "Warning: `let\\*' with empty body") + + (test-suppression + '(defun zot (x) + (when x + )) + '((empty-body when)) + "Warning: `when' with empty body") + + (test-suppression + '(defun zot (x) + (unless x + )) + '((empty-body unless)) + "Warning: `unless' with empty body") + + (test-suppression + '(defun zot (x) + (ignore-error arith-error + )) + '((empty-body ignore-error)) + "Warning: `ignore-error' with empty body") + + (test-suppression + '(defun zot (x) + (with-suppressed-warnings ((suspicious eq)) + )) + '((empty-body with-suppressed-warnings)) + "Warning: `with-suppressed-warnings' with empty body") + ) (ert-deftest bytecomp-tests--not-writable-directory () "Test that byte compilation works if the output directory isn't diff --git a/test/lisp/emacs-lisp/cl-lib-tests.el b/test/lisp/emacs-lisp/cl-lib-tests.el index d5886626bf1..4e1a0fd63a2 100644 --- a/test/lisp/emacs-lisp/cl-lib-tests.el +++ b/test/lisp/emacs-lisp/cl-lib-tests.el @@ -404,7 +404,7 @@ (ert-deftest cl-lib-nth-value-test-multiple-values () "While CL multiple values are an alias to list, these won't work." :expected-result :failed - (should (eq (cl-nth-value 0 '(2 3)) '(2 3))) + (should (equal (cl-nth-value 0 '(2 3)) '(2 3))) (should (= (cl-nth-value 0 1) 1)) (should (null (cl-nth-value 1 1))) (should-error (cl-nth-value -1 (cl-values 2 3)) :type 'args-out-of-range) @@ -431,7 +431,8 @@ (should (eq nums (cdr (cl-adjoin 3 nums)))) ;; add only when not already there (should (eq nums (cl-adjoin 2 nums))) - (should (equal '(2 1 (2)) (cl-adjoin 2 '(1 (2))))) + (with-suppressed-warnings ((suspicious memql)) + (should (equal '(2 1 (2)) (cl-adjoin 2 '(1 (2)))))) ;; default test function is eql (should (equal '(1.0 1 2) (cl-adjoin 1.0 nums))) ;; own :test function - returns true if match diff --git a/test/lisp/emacs-lisp/multisession-tests.el b/test/lisp/emacs-lisp/multisession-tests.el index c55db6491cd..639a8ab5219 100644 --- a/test/lisp/emacs-lisp/multisession-tests.el +++ b/test/lisp/emacs-lisp/multisession-tests.el @@ -94,7 +94,7 @@ (dotimes (i 100) (cl-incf (multisession-value multisession--bar)))))))) (while (process-live-p proc) - (ignore-error 'sqlite-locked-error + (ignore-error sqlite-locked-error (message "multisession--bar %s" (multisession-value multisession--bar)) ;;(cl-incf (multisession-value multisession--bar)) ) diff --git a/test/lisp/eshell/em-alias-tests.el b/test/lisp/eshell/em-alias-tests.el index 273e19d580b..ec1704545a4 100644 --- a/test/lisp/eshell/em-alias-tests.el +++ b/test/lisp/eshell/em-alias-tests.el @@ -72,6 +72,15 @@ (eshell-match-command-output "show-all-args a" "a\n") (eshell-match-command-output "show-all-args a b c" "a\nb\nc\n"))) +(ert-deftest em-alias-test/alias-all-args-var-splice () + "Test alias with splicing the $* variable" + (with-temp-eshell + (eshell-insert-command "alias show-all-args 'echo args: $@*'") + (eshell-match-command-output "show-all-args" "args:\n") + (eshell-match-command-output "show-all-args a" "(\"args:\" \"a\")\n") + (eshell-match-command-output "show-all-args a b c" + "(\"args:\" \"a\" \"b\" \"c\")\n"))) + (ert-deftest em-alias-test/alias-all-args-var-indices () "Test alias with the $* variable using indices" (with-temp-eshell diff --git a/test/lisp/eshell/em-cmpl-tests.el b/test/lisp/eshell/em-cmpl-tests.el new file mode 100644 index 00000000000..12a156fbb38 --- /dev/null +++ b/test/lisp/eshell/em-cmpl-tests.el @@ -0,0 +1,208 @@ +;;; em-cmpl-tests.el --- em-cmpl test suite -*- lexical-binding:t -*- + +;; Copyright (C) 2023 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Tests for Eshell's interactive completion. + +;;; Code: + +(require 'ert) +(require 'eshell) +(require 'em-cmpl) +(require 'em-dirs) +(require 'em-hist) +(require 'em-tramp) +(require 'em-unix) + +(require 'eshell-tests-helpers + (expand-file-name "eshell-tests-helpers" + (file-name-directory (or load-file-name + default-directory)))) + +(defvar eshell-test-value nil) + +(defun eshell-insert-and-complete (input) + "Insert INPUT and invoke completion, returning the result." + (insert input) + (completion-at-point) + (eshell-get-old-input)) + +(defun eshell-arguments-equal (actual expected) + "Return t if ACTUAL and EXPECTED are equal, including properties of strings. +ACTUAL and EXPECTED should both be lists of strings." + (when (length= actual (length expected)) + (catch 'not-equal + (cl-mapc (lambda (i j) + (unless (equal-including-properties i j) + (throw 'not-equal nil))) + actual expected) + t))) + +(defun eshell-arguments-equal--equal-explainer (actual expected) + "Explain the result of `eshell-arguments-equal'." + `(nonequal-result + (actual ,actual) + (expected ,expected))) + +(put 'eshell-arguments-equal 'ert-explainer + #'eshell-arguments-equal--equal-explainer) + +;;; Tests: + +(ert-deftest em-cmpl-test/parse-arguments/pipeline () + "Test that parsing arguments for completion discards earlier commands." + (with-temp-eshell + (let ((eshell-test-value '("foo" "bar"))) + (insert "echo hi | cat") + (should (eshell-arguments-equal + (car (eshell-complete-parse-arguments)) + '("cat")))))) + +(ert-deftest em-cmpl-test/parse-arguments/multiple-dots () + "Test parsing arguments with multiple dots like \".../\"." + (with-temp-eshell + (insert "echo .../file.txt") + (should (eshell-arguments-equal + (car (eshell-complete-parse-arguments)) + `("echo" ,(propertize "../../file.txt" + 'pcomplete-arg-value + ".../file.txt")))))) + +(ert-deftest em-cmpl-test/parse-arguments/variable/numeric () + "Test parsing arguments with a numeric variable interpolation." + (with-temp-eshell + (let ((eshell-test-value 42)) + (insert "echo $eshell-test-value") + (should (eshell-arguments-equal + (car (eshell-complete-parse-arguments)) + `("echo" ,(propertize "42" 'pcomplete-arg-value 42))))))) + +(ert-deftest em-cmpl-test/parse-arguments/variable/nil () + "Test parsing arguments with a nil variable interpolation." + (with-temp-eshell + (let ((eshell-test-value nil)) + (insert "echo $eshell-test-value") + (should (eshell-arguments-equal + (car (eshell-complete-parse-arguments)) + `("echo" ,(propertize "" 'pcomplete-arg-value nil))))))) + +(ert-deftest em-cmpl-test/parse-arguments/variable/list () + "Test parsing arguments with a list variable interpolation." + (with-temp-eshell + (let ((eshell-test-value '("foo" "bar"))) + (insert "echo $eshell-test-value") + (should (eshell-arguments-equal + (car (eshell-complete-parse-arguments)) + `("echo" ,(propertize "(\"foo\" \"bar\")" + 'pcomplete-arg-value + eshell-test-value))))))) + +(ert-deftest em-cmpl-test/parse-arguments/variable/splice () + "Test parsing arguments with a spliced variable interpolation." + (with-temp-eshell + (let ((eshell-test-value '("foo" "bar"))) + (insert "echo $@eshell-test-value") + (should (eshell-arguments-equal + (car (eshell-complete-parse-arguments)) + '("echo" "foo" "bar")))))) + +(ert-deftest em-cmpl-test/file-completion/unique () + "Test completion of file names when there's a unique result." + (with-temp-eshell + (ert-with-temp-directory default-directory + (write-region nil nil (expand-file-name "file.txt")) + (should (equal (eshell-insert-and-complete "echo fi") + "echo file.txt "))))) + +(ert-deftest em-cmpl-test/file-completion/non-unique () + "Test completion of file names when there are multiple results." + (with-temp-eshell + (ert-with-temp-directory default-directory + (write-region nil nil (expand-file-name "file.txt")) + (write-region nil nil (expand-file-name "file.el")) + (should (equal (eshell-insert-and-complete "echo fi") + "echo file.")) + ;; Now try completing again. + (let ((minibuffer-message-timeout 0) + (inhibit-message t)) + (completion-at-point)) + ;; FIXME: We can't use `current-message' here. + (with-current-buffer (messages-buffer) + (save-excursion + (goto-char (point-max)) + (forward-line -1) + (should (looking-at "Complete, but not unique"))))))) + +(ert-deftest em-cmpl-test/file-completion/after-list () + "Test completion of file names after previous list arguments. +See bug#59956." + (with-temp-eshell + (ert-with-temp-directory default-directory + (write-region nil nil (expand-file-name "file.txt")) + (should (equal (eshell-insert-and-complete "echo (list 1 2) fi") + "echo (list 1 2) file.txt "))))) + +(ert-deftest em-cmpl-test/lisp-symbol-completion () + "Test completion of Lisp forms like \"#'symbol\" and \"`symbol\". +See <lisp/eshell/esh-cmd.el>." + (with-temp-eshell + (should (equal (eshell-insert-and-complete "echo #'system-nam") + "echo #'system-name "))) + (with-temp-eshell + (should (equal (eshell-insert-and-complete "echo `system-nam") + "echo `system-name ")))) + +(ert-deftest em-cmpl-test/lisp-function-completion () + "Test completion of Lisp forms like \"(func)\". +See <lisp/eshell/esh-cmd.el>." + (with-temp-eshell + (should (equal (eshell-insert-and-complete "echo (eshell/ech") + "echo (eshell/echo")))) + +(ert-deftest em-cmpl-test/variable-ref-completion () + "Test completion of variable references like \"$var\". +See <lisp/eshell/esh-var.el>." + (with-temp-eshell + (should (equal (eshell-insert-and-complete "echo $system-nam") + "echo $system-name ")))) + +(ert-deftest em-cmpl-test/variable-assign-completion () + "Test completion of variable assignments like \"var=value\". +See <lisp/eshell/esh-var.el>." + (with-temp-eshell + (ert-with-temp-directory default-directory + (write-region nil nil (expand-file-name "file.txt")) + (should (equal (eshell-insert-and-complete "VAR=f") + "VAR=file.txt "))))) + +(ert-deftest em-cmpl-test/user-ref-completion () + "Test completeion of user references like \"~user\". +See <lisp/eshell/em-dirs.el>." + (unwind-protect + (with-temp-eshell + (cl-letf (((symbol-function 'eshell-read-user-names) + (lambda () (setq eshell-user-names '((1234 . "user")))))) + ;; FIXME: Should this really add a space at the end? + (should (equal (eshell-insert-and-complete "echo ~us") + "echo ~user/ ")))) + ;; Clear the cached user names we set above. + (setq eshell-user-names nil))) + +;;; em-cmpl-tests.el ends here diff --git a/test/lisp/eshell/em-extpipe-tests.el b/test/lisp/eshell/em-extpipe-tests.el index 6d6d4daac9d..1184b5df5f8 100644 --- a/test/lisp/eshell/em-extpipe-tests.el +++ b/test/lisp/eshell/em-extpipe-tests.el @@ -42,7 +42,7 @@ (shell-command-switch "-c")) ;; Strip `eshell-trap-errors'. (should (equal ,expected - (cadr (eshell-parse-command input)))))) + (cadadr (eshell-parse-command input)))))) (with-substitute-for-temp (&rest body) ;; Substitute name of an actual temporary file and/or ;; buffer into `input'. The substitution logic is diff --git a/test/lisp/eshell/em-prompt-tests.el b/test/lisp/eshell/em-prompt-tests.el new file mode 100644 index 00000000000..db45e2ae3a7 --- /dev/null +++ b/test/lisp/eshell/em-prompt-tests.el @@ -0,0 +1,120 @@ +;;; em-prompt-tests.el --- em-prompt test suite -*- lexical-binding:t -*- + +;; Copyright (C) 2023 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Tests for Eshell's prompt support. + +;;; Code: + +(require 'ert) +(require 'eshell) +(require 'em-prompt) + +(require 'eshell-tests-helpers + (expand-file-name "eshell-tests-helpers" + (file-name-directory (or load-file-name + default-directory)))) + +;;; Tests: + +(ert-deftest em-prompt-test/field-properties () + "Check that field properties are properly set on Eshell output/prompts." + (with-temp-eshell + (eshell-insert-command "echo hello") + (let ((last-prompt (field-string (1- eshell-last-input-start))) + (last-input (field-string (1+ eshell-last-input-start))) + (last-output (field-string (1+ eshell-last-input-end)))) + (should (equal-including-properties + last-prompt + (propertize + (format "%s %s " (directory-file-name default-directory) + (if (= (file-user-uid) 0) "#" "$")) + 'read-only t + 'field 'prompt + 'font-lock-face 'eshell-prompt + 'front-sticky '(read-only field font-lock-face) + 'rear-nonsticky '(read-only field font-lock-face)))) + (should (equal last-input "echo hello\n")) + (should (equal-including-properties + last-output + (propertize "hello\n" 'rear-nonsticky '(field) + 'field 'command-output)))))) + +(ert-deftest em-prompt-test/field-properties/no-highlight () + "Check that field properties are properly set on Eshell output/prompts. +This tests the case when `eshell-highlight-prompt' is nil." + (let ((eshell-highlight-prompt nil)) + (with-temp-eshell + (eshell-insert-command "echo hello") + (let ((last-prompt (field-string (1- eshell-last-input-start))) + (last-input (field-string (1+ eshell-last-input-start))) + (last-output (field-string (1+ eshell-last-input-end)))) + (should (equal-including-properties + last-prompt + (propertize + (format "%s %s " (directory-file-name default-directory) + (if (= (file-user-uid) 0) "#" "$")) + 'field 'prompt + 'front-sticky '(field) + 'rear-nonsticky '(field)))) + (should (equal last-input "echo hello\n")) + (should (equal-including-properties + last-output + (propertize "hello\n" 'rear-nonsticky '(field) + 'field 'command-output))))))) + +(ert-deftest em-prompt-test/next-previous-prompt () + "Check that navigating forward/backward through old prompts works correctly." + (with-temp-eshell + (eshell-insert-command "echo one") + (eshell-insert-command "echo two") + (eshell-insert-command "echo three") + (insert "echo fou") ; A partially-entered command. + ;; Go back one prompt. + (eshell-previous-prompt 1) + (should (equal (eshell-get-old-input) "echo three")) + ;; Go back two prompts, starting from the end of this line. + (end-of-line) + (eshell-previous-prompt 2) + (should (equal (eshell-get-old-input) "echo one")) + ;; Go forward three prompts. + (eshell-next-prompt 3) + (should (equal (eshell-get-old-input) "echo fou")))) + +(ert-deftest em-prompt-test/forward-backward-matching-input () + "Check that navigating forward/backward via regexps works correctly." + (with-temp-eshell + (eshell-insert-command "echo one") + (eshell-insert-command "printnl something else") + (eshell-insert-command "echo two") + (eshell-insert-command "echo three") + (insert "echo fou") ; A partially-entered command. + ;; Go back one prompt. + (eshell-backward-matching-input "echo" 1) + (should (equal (eshell-get-old-input) "echo three")) + ;; Go back two prompts, starting from the end of this line. + (end-of-line) + (eshell-backward-matching-input "echo" 2) + (should (equal (eshell-get-old-input) "echo one")) + ;; Go forward three prompts. + (eshell-forward-matching-input "echo" 3) + (should (equal (eshell-get-old-input) "echo fou")))) + +;;; em-prompt-tests.el ends here diff --git a/test/lisp/eshell/em-script-tests.el b/test/lisp/eshell/em-script-tests.el index 4e557fada73..74328844778 100644 --- a/test/lisp/eshell/em-script-tests.el +++ b/test/lisp/eshell/em-script-tests.el @@ -35,21 +35,43 @@ ;;; Tests: (ert-deftest em-script-test/source-script () - "Test sourcing script with no argumentss" + "Test sourcing a simple script." (ert-with-temp-file temp-file :text "echo hi" (with-temp-eshell (eshell-match-command-output (format "source %s" temp-file) "hi\n")))) -(ert-deftest em-script-test/source-script-arg-vars () - "Test sourcing script with $0, $1, ... variables" +(ert-deftest em-script-test/source-script/redirect () + "Test sourcing a script and redirecting its output." + (ert-with-temp-file temp-file + :text "echo hi\necho bye" + (eshell-with-temp-buffer bufname "old" + (with-temp-eshell + (eshell-match-command-output + (format "source %s > #<%s>" temp-file bufname) + "\\`\\'")) + (should (equal (buffer-string) "hibye"))))) + +(ert-deftest em-script-test/source-script/redirect/dev-null () + "Test sourcing a script and redirecting its output, including to /dev/null." + (ert-with-temp-file temp-file + :text "echo hi\necho bad > /dev/null\necho bye" + (eshell-with-temp-buffer bufname "old" + (with-temp-eshell + (eshell-match-command-output + (format "source %s > #<%s>" temp-file bufname) + "\\`\\'")) + (should (equal (buffer-string) "hibye"))))) + +(ert-deftest em-script-test/source-script/arg-vars () + "Test sourcing script with $0, $1, ... variables." (ert-with-temp-file temp-file :text "printnl $0 \"$1 $2\"" (with-temp-eshell (eshell-match-command-output (format "source %s one two" temp-file) (format "%s\none two\n" temp-file))))) -(ert-deftest em-script-test/source-script-all-args-var () - "Test sourcing script with the $* variable" +(ert-deftest em-script-test/source-script/all-args-var () + "Test sourcing script with the $* variable." (ert-with-temp-file temp-file :text "printnl $*" (with-temp-eshell (eshell-match-command-output (format "source %s" temp-file) diff --git a/test/lisp/eshell/em-tramp-tests.el b/test/lisp/eshell/em-tramp-tests.el index 1d4ad9dc632..a3bda970b63 100644 --- a/test/lisp/eshell/em-tramp-tests.el +++ b/test/lisp/eshell/em-tramp-tests.el @@ -23,37 +23,41 @@ (require 'em-tramp) (require 'tramp) +(defmacro em-tramp-test/should-replace-command (form replacement) + "Check that calling FORM results in it being replaced with REPLACEMENT." + (declare (indent 1)) + `(should (equal + (catch 'eshell-replace-command ,form) + (list 'eshell-with-copied-handles + (list 'eshell-trap-errors + ,replacement) + t)))) + (ert-deftest em-tramp-test/su-default () "Test Eshell `su' command with no arguments." - (should (equal - (catch 'eshell-replace-command (eshell/su)) - `(eshell-trap-errors - (eshell-named-command - "cd" - (list ,(format "/su:root@%s:%s" - tramp-default-host default-directory))))))) + (em-tramp-test/should-replace-command (eshell/su) + `(eshell-named-command + "cd" + (list ,(format "/su:root@%s:%s" + tramp-default-host default-directory))))) (ert-deftest em-tramp-test/su-user () "Test Eshell `su' command with USER argument." - (should (equal - (catch 'eshell-replace-command (eshell/su "USER")) - `(eshell-trap-errors - (eshell-named-command - "cd" - (list ,(format "/su:USER@%s:%s" - tramp-default-host default-directory))))))) + (em-tramp-test/should-replace-command (eshell/su "USER") + `(eshell-named-command + "cd" + (list ,(format "/su:USER@%s:%s" + tramp-default-host default-directory))))) (ert-deftest em-tramp-test/su-login () "Test Eshell `su' command with -/-l/--login option." (dolist (args '(("--login") ("-l") ("-"))) - (should (equal - (catch 'eshell-replace-command (apply #'eshell/su args)) - `(eshell-trap-errors - (eshell-named-command - "cd" - (list ,(format "/su:root@%s:~/" tramp-default-host)))))))) + (em-tramp-test/should-replace-command (apply #'eshell/su args) + `(eshell-named-command + "cd" + (list ,(format "/su:root@%s:~/" tramp-default-host)))))) (defun mock-eshell-named-command (&rest args) "Dummy function to test Eshell `sudo' command rewriting." @@ -89,23 +93,19 @@ "Test Eshell `sudo' command with -s/--shell option." (dolist (args '(("--shell") ("-s"))) - (should (equal - (catch 'eshell-replace-command (apply #'eshell/sudo args)) - `(eshell-trap-errors - (eshell-named-command - "cd" - (list ,(format "/sudo:root@%s:%s" - tramp-default-host default-directory)))))))) + (em-tramp-test/should-replace-command (apply #'eshell/sudo args) + `(eshell-named-command + "cd" + (list ,(format "/sudo:root@%s:%s" + tramp-default-host default-directory)))))) (ert-deftest em-tramp-test/sudo-user-shell () "Test Eshell `sudo' command with -s and -u options." - (should (equal - (catch 'eshell-replace-command (eshell/sudo "-u" "USER" "-s")) - `(eshell-trap-errors - (eshell-named-command - "cd" - (list ,(format "/sudo:USER@%s:%s" - tramp-default-host default-directory))))))) + (em-tramp-test/should-replace-command (eshell/sudo "-u" "USER" "-s") + `(eshell-named-command + "cd" + (list ,(format "/sudo:USER@%s:%s" + tramp-default-host default-directory))))) (ert-deftest em-tramp-test/doas-basic () "Test Eshell `doas' command with default user." @@ -142,22 +142,18 @@ "Test Eshell `doas' command with -s/--shell option." (dolist (args '(("--shell") ("-s"))) - (should (equal - (catch 'eshell-replace-command (apply #'eshell/doas args)) - `(eshell-trap-errors - (eshell-named-command - "cd" - (list ,(format "/doas:root@%s:%s" - tramp-default-host default-directory)))))))) + (em-tramp-test/should-replace-command (apply #'eshell/doas args) + `(eshell-named-command + "cd" + (list ,(format "/doas:root@%s:%s" + tramp-default-host default-directory)))))) (ert-deftest em-tramp-test/doas-user-shell () "Test Eshell `doas' command with -s and -u options." - (should (equal - (catch 'eshell-replace-command (eshell/doas "-u" "USER" "-s")) - `(eshell-trap-errors - (eshell-named-command - "cd" - (list ,(format "/doas:USER@%s:%s" - tramp-default-host default-directory))))))) + (em-tramp-test/should-replace-command (eshell/doas "-u" "USER" "-s") + `(eshell-named-command + "cd" + (list ,(format "/doas:USER@%s:%s" + tramp-default-host default-directory))))) ;;; em-tramp-tests.el ends here diff --git a/test/lisp/eshell/esh-cmd-tests.el b/test/lisp/eshell/esh-cmd-tests.el index 912822eeddb..bcecc9a531f 100644 --- a/test/lisp/eshell/esh-cmd-tests.el +++ b/test/lisp/eshell/esh-cmd-tests.el @@ -148,14 +148,21 @@ e.g. \"{(+ 1 2)} 3\" => 3" "echo $name; for name in 3 { echo $name }; echo $name" "env-value\n3\nenv-value\n")))) +(ert-deftest esh-cmd-test/for-loop-pipe () + "Test invocation of a for loop piped to another command." + (skip-unless (executable-find "rev")) + (with-temp-eshell + (eshell-match-command-output "for i in foo bar baz { echo $i } | rev" + "zabraboof"))) + (ert-deftest esh-cmd-test/while-loop () "Test invocation of a while loop." (with-temp-eshell (let ((eshell-test-value '(0 1 2))) (eshell-match-command-output (concat "while $eshell-test-value " - "{ setq eshell-test-value (cdr eshell-test-value) }") - "(1 2)\n(2)\n")))) + "{ (pop eshell-test-value) }") + "0\n1\n2\n")))) (ert-deftest esh-cmd-test/while-loop-lisp-form () "Test invocation of a while loop using a Lisp form." @@ -176,6 +183,17 @@ e.g. \"{(+ 1 2)} 3\" => 3" "{ setq eshell-test-value (1+ eshell-test-value) }") "1\n2\n3\n")))) +(ert-deftest esh-cmd-test/while-loop-pipe () + "Test invocation of a while loop piped to another command." + (skip-unless (executable-find "rev")) + (with-temp-eshell + (let ((eshell-test-value '("foo" "bar" "baz"))) + (eshell-match-command-output + (concat "while $eshell-test-value " + "{ (pop eshell-test-value) }" + " | rev") + "zabraboof")))) + (ert-deftest esh-cmd-test/until-loop () "Test invocation of an until loop." (with-temp-eshell @@ -253,6 +271,30 @@ This tests when `eshell-lisp-form-nil-is-failure' is nil." (eshell-command-result-equal "if {[ foo = bar ]} {echo yes} {echo no}" "no")) +(ert-deftest esh-cmd-test/if-statement-pipe () + "Test invocation of an if statement piped to another command." + (skip-unless (executable-find "rev")) + (with-temp-eshell + (let ((eshell-test-value t)) + (eshell-match-command-output "if $eshell-test-value {echo yes} | rev" + "\\`sey\n?")) + (let ((eshell-test-value nil)) + (eshell-match-command-output "if $eshell-test-value {echo yes} | rev" + "\\`\n?")))) + +(ert-deftest esh-cmd-test/if-else-statement-pipe () + "Test invocation of an if/else statement piped to another command." + (skip-unless (executable-find "rev")) + (with-temp-eshell + (let ((eshell-test-value t)) + (eshell-match-command-output + "if $eshell-test-value {echo yes} {echo no} | rev" + "\\`sey\n?")) + (let ((eshell-test-value nil)) + (eshell-match-command-output + "if $eshell-test-value {echo yes} {echo no} | rev" + "\\`on\n?")))) + (ert-deftest esh-cmd-test/unless-statement () "Test invocation of an unless statement." (let ((eshell-test-value t)) diff --git a/test/lisp/eshell/esh-io-tests.el b/test/lisp/eshell/esh-io-tests.el index b38d6090f13..ed350a9691c 100644 --- a/test/lisp/eshell/esh-io-tests.el +++ b/test/lisp/eshell/esh-io-tests.el @@ -146,6 +146,45 @@ (should (equal (buffer-string) "new")) (should (equal eshell-test-value "new"))))) +(ert-deftest esh-io-test/redirect-subcommands () + "Check that redirecting subcommands applies to all subcommands." + (eshell-with-temp-buffer bufname "old" + (with-temp-eshell + (eshell-insert-command (format "{echo foo; echo bar} > #<%s>" bufname))) + (should (equal (buffer-string) "foobar")))) + +(ert-deftest esh-io-test/redirect-subcommands/override () + "Check that redirecting subcommands applies to all subcommands. +Include a redirect to another location in the subcommand to +ensure only its statement is redirected." + (eshell-with-temp-buffer bufname "old" + (eshell-with-temp-buffer bufname-2 "also old" + (with-temp-eshell + (eshell-insert-command + (format "{echo foo; echo bar > #<%s>; echo baz} > #<%s>" + bufname-2 bufname))) + (should (equal (buffer-string) "bar"))) + (should (equal (buffer-string) "foobaz")))) + +(ert-deftest esh-io-test/redirect-subcommands/dev-null () + "Check that redirecting subcommands applies to all subcommands. +Include a redirect to /dev/null to ensure it only applies to its +statement." + (eshell-with-temp-buffer bufname "old" + (with-temp-eshell + (eshell-insert-command + (format "{echo foo; echo bar > /dev/null; echo baz} > #<%s>" + bufname))) + (should (equal (buffer-string) "foobaz")))) + +(ert-deftest esh-io-test/redirect-subcommands/interpolated () + "Check that redirecting interpolated subcommands applies to all subcommands." + (eshell-with-temp-buffer bufname "old" + (with-temp-eshell + (eshell-insert-command + (format "echo ${echo foo; echo bar} > #<%s>" bufname))) + (should (equal (buffer-string) "foobar")))) + ;; Redirecting specific handles @@ -262,24 +301,56 @@ stdout originally pointed (the terminal)." "stderr\n")) (should (equal (buffer-string) "stdout\n")))) -(ert-deftest esh-io-test/redirect-pipe () - "Check that \"redirecting\" to a pipe works." - ;; `|' should only redirect stdout. + +;; Pipelines + +(ert-deftest esh-io-test/pipeline/default () + "Check that `|' only pipes stdout." + (skip-unless (executable-find "rev")) (eshell-command-result-equal "test-output | rev" - "stderr\ntuodts\n") - ;; `|&' should redirect stdout and stderr. + "stderr\ntuodts\n")) + + +(ert-deftest esh-io-test/pipeline/all () + "Check that `|&' only pipes stdout and stderr." + (skip-unless (executable-find "rev")) (eshell-command-result-equal "test-output |& rev" "tuodts\nrredts\n")) +(ert-deftest esh-io-test/pipeline/subcommands () + "Chek that all commands in a subcommand are properly piped." + (skip-unless (executable-find "rev")) + (with-temp-eshell + (eshell-match-command-output "{echo foo; echo bar} | rev" + "\\`raboof\n?"))) + ;; Virtual targets -(ert-deftest esh-io-test/virtual-dev-eshell () +(ert-deftest esh-io-test/virtual/dev-null () + "Check that redirecting to /dev/null works." + (with-temp-eshell + (eshell-match-command-output "echo hi > /dev/null" "\\`\\'"))) + +(ert-deftest esh-io-test/virtual/dev-null/multiple () + "Check that redirecting to /dev/null works alongside other redirections." + (eshell-with-temp-buffer bufname "old" + (with-temp-eshell + (eshell-match-command-output + (format "echo new > /dev/null > #<%s>" bufname) "\\`\\'")) + (should (equal (buffer-string) "new"))) + (eshell-with-temp-buffer bufname "old" + (with-temp-eshell + (eshell-match-command-output + (format "echo new > #<%s> > /dev/null" bufname) "\\`\\'")) + (should (equal (buffer-string) "new")))) + +(ert-deftest esh-io-test/virtual/dev-eshell () "Check that redirecting to /dev/eshell works." (with-temp-eshell (eshell-match-command-output "echo hi > /dev/eshell" "hi"))) -(ert-deftest esh-io-test/virtual-dev-kill () +(ert-deftest esh-io-test/virtual/dev-kill () "Check that redirecting to /dev/kill works." (with-temp-eshell (eshell-insert-command "echo one > /dev/kill") diff --git a/test/lisp/eshell/esh-util-tests.el b/test/lisp/eshell/esh-util-tests.el index afaf1b77f2b..ed841e96c7e 100644 --- a/test/lisp/eshell/esh-util-tests.el +++ b/test/lisp/eshell/esh-util-tests.el @@ -54,4 +54,69 @@ "Test that `eshell-stringify' correctly stringifies complex objects." (should (equal (eshell-stringify (list 'quote 'hello)) "'hello"))) +(ert-deftest esh-util-test/eshell-convert-to-number/integer () + "Test that `eshell-convert-to-number' correctly converts integers." + (should (equal (eshell-convert-to-number "123") 123)) + (should (equal (eshell-convert-to-number "-123") -123)) + ;; These are technially integers, since Emacs Lisp requires at least + ;; one digit after the "." to be a float: + (should (equal (eshell-convert-to-number "123.") 123)) + (should (equal (eshell-convert-to-number "-123.") -123))) + +(ert-deftest esh-util-test/eshell-convert-to-number/floating-point () + "Test that `eshell-convert-to-number' correctly converts floats." + (should (equal (eshell-convert-to-number "1.23") 1.23)) + (should (equal (eshell-convert-to-number "-1.23") -1.23)) + (should (equal (eshell-convert-to-number ".1") 0.1)) + (should (equal (eshell-convert-to-number "-.1") -0.1))) + +(ert-deftest esh-util-test/eshell-convert-to-number/floating-point-exponent () + "Test that `eshell-convert-to-number' correctly converts exponent notation." + ;; Positive exponent: + (dolist (exp '("e2" "e+2" "E2" "E+2")) + (should (equal (eshell-convert-to-number (concat "123" exp)) 12300.0)) + (should (equal (eshell-convert-to-number (concat "-123" exp)) -12300.0)) + (should (equal (eshell-convert-to-number (concat "1.23" exp)) 123.0)) + (should (equal (eshell-convert-to-number (concat "-1.23" exp)) -123.0)) + (should (equal (eshell-convert-to-number (concat "1." exp)) 100.0)) + (should (equal (eshell-convert-to-number (concat "-1." exp)) -100.0)) + (should (equal (eshell-convert-to-number (concat ".1" exp)) 10.0)) + (should (equal (eshell-convert-to-number (concat "-.1" exp)) -10.0))) + ;; Negative exponent: + (dolist (exp '("e-2" "E-2")) + (should (equal (eshell-convert-to-number (concat "123" exp)) 1.23)) + (should (equal (eshell-convert-to-number (concat "-123" exp)) -1.23)) + (should (equal (eshell-convert-to-number (concat "1.23" exp)) 0.0123)) + (should (equal (eshell-convert-to-number (concat "-1.23" exp)) -0.0123)) + (should (equal (eshell-convert-to-number (concat "1." exp)) 0.01)) + (should (equal (eshell-convert-to-number (concat "-1." exp)) -0.01)) + (should (equal (eshell-convert-to-number (concat ".1" exp)) 0.001)) + (should (equal (eshell-convert-to-number (concat "-.1" exp)) -0.001)))) + +(ert-deftest esh-util-test/eshell-convert-to-number/floating-point/infinite () + "Test that `eshell-convert-to-number' correctly converts infinite floats." + (should (equal (eshell-convert-to-number "1.0e+INF") 1.0e+INF)) + (should (equal (eshell-convert-to-number "2.e+INF") 1.0e+INF)) + (should (equal (eshell-convert-to-number "-1.0e+INF") -1.0e+INF)) + (should (equal (eshell-convert-to-number "-2.e+INF") -1.0e+INF))) + +(ert-deftest esh-util-test/eshell-convert-to-number/floating-point/nan () + "Test that `eshell-convert-to-number' correctly converts NaNs." + (should (equal (eshell-convert-to-number "1.0e+NaN") 1.0e+NaN)) + (should (equal (eshell-convert-to-number "2.e+NaN") 2.0e+NaN)) + (should (equal (eshell-convert-to-number "-1.0e+NaN") -1.0e+NaN)) + (should (equal (eshell-convert-to-number "-2.e+NaN") -2.0e+NaN))) + +(ert-deftest esh-util-test/eshell-convert-to-number/non-numeric () + "Test that `eshell-convert-to-number' does nothing to non-numeric values." + (should (equal (eshell-convert-to-number "foo") "foo")) + (should (equal (eshell-convert-to-number "") "")) + (should (equal (eshell-convert-to-number "123foo") "123foo"))) + +(ert-deftest esh-util-test/eshell-convert-to-number/no-convert () + "Test that `eshell-convert-to-number' does nothing when disabled." + (let ((eshell-convert-numeric-arguments nil)) + (should (equal (eshell-convert-to-number "123") "123")) + (should (equal (eshell-convert-to-number "1.23") "1.23")))) + ;;; esh-util-tests.el ends here diff --git a/test/lisp/eshell/esh-var-tests.el b/test/lisp/eshell/esh-var-tests.el index 7ec1731f94e..6767d9289f9 100644 --- a/test/lisp/eshell/esh-var-tests.el +++ b/test/lisp/eshell/esh-var-tests.el @@ -60,41 +60,101 @@ (eshell-command-result-equal "echo $\"user-login-name\"-foo" (concat user-login-name "-foo"))) -(ert-deftest esh-var-test/interp-var-indices () - "Interpolate list variable with indices" - (let ((eshell-test-value '("zero" "one" "two" "three" "four"))) +(ert-deftest esh-var-test/interp-list-var () + "Interpolate list variable" + (let ((eshell-test-value '(1 2 3))) + (eshell-command-result-equal "echo $eshell-test-value" + '(1 2 3)))) + +(ert-deftest esh-var-test/interp-list-var-concat () + "Interpolate and concat list variable" + (let ((eshell-test-value '(1 2 3))) + (eshell-command-result-equal "echo a$'eshell-test-value'z" + '("a1" 2 "3z")))) + +(defun esh-var-test/interp-var-indices (function &optional range-function) + "Test interpolation of an indexable value with indices. +FUNCTION is a function that takes a list of elements and returns +the object to test. + +RANGE-FUNCTION is a function that takes a list of elements and +returns the expected result of an index range for the object; if +nil, use FUNCTION instead." + (let ((eshell-test-value + (funcall function '("zero" "one" "two" "three" "four"))) + (range-function (or range-function function))) + ;; Positive indices (eshell-command-result-equal "echo $eshell-test-value[0]" "zero") (eshell-command-result-equal "echo $eshell-test-value[0 2]" '("zero" "two")) (eshell-command-result-equal "echo $eshell-test-value[0 2 4]" - '("zero" "two" "four")))) + '("zero" "two" "four")) + ;; Negative indices + (eshell-command-result-equal "echo $eshell-test-value[-1]" + "four") + (eshell-command-result-equal "echo $eshell-test-value[-1 -3]" + '("four" "two")) + ;; Index ranges + (eshell-command-result-equal + "echo $eshell-test-value[1..4]" + (funcall range-function '("one" "two" "three"))) + (eshell-command-result-equal + "echo $eshell-test-value[..2]" + (funcall range-function '("zero" "one"))) + (eshell-command-result-equal + "echo $eshell-test-value[-2..]" + (funcall range-function '("three" "four"))) + (eshell-command-result-equal + "echo $eshell-test-value[..]" + (funcall range-function '("zero" "one" "two" "three" "four"))) + (eshell-command-result-equal + "echo $eshell-test-value[1..4 -2..]" + (list (funcall range-function '("one" "two" "three")) + (funcall range-function '("three" "four")))))) -(ert-deftest esh-var-test/interp-var-split-indices () - "Interpolate string variable with indices" - (let ((eshell-test-value "zero one two three four")) - (eshell-command-result-equal "echo $eshell-test-value[0]" - "zero") - (eshell-command-result-equal "echo $eshell-test-value[0 2]" - '("zero" "two")) - (eshell-command-result-equal "echo $eshell-test-value[0 2 4]" - '("zero" "two" "four")))) +(ert-deftest esh-var-test/interp-var-indices/list () + "Interpolate list variable with indices." + (esh-var-test/interp-var-indices #'identity)) + +(ert-deftest esh-var-test/interp-var-indices/vector () + "Interpolate vector variable with indices." + (esh-var-test/interp-var-indices #'vconcat)) + +(ert-deftest esh-var-test/interp-var-indices/ring () + "Interpolate ring variable with indices." + (esh-var-test/interp-var-indices #'ring-convert-sequence-to-ring)) + +(ert-deftest esh-var-test/interp-var-indices/split () + "Interpolate string variable with indices." + (esh-var-test/interp-var-indices + (lambda (values) (string-join values " ")) + #'identity)) (ert-deftest esh-var-test/interp-var-string-split-indices () - "Interpolate string variable with string splitter and indices" + "Interpolate string variable with string splitter and indices." + ;; Test using punctuation as a delimiter. (let ((eshell-test-value "zero:one:two:three:four")) (eshell-command-result-equal "echo $eshell-test-value[: 0]" "zero") (eshell-command-result-equal "echo $eshell-test-value[: 0 2]" '("zero" "two"))) + ;; Test using a letter as a delimiter. (let ((eshell-test-value "zeroXoneXtwoXthreeXfour")) (eshell-command-result-equal "echo $eshell-test-value[X 0]" "zero") (eshell-command-result-equal "echo $eshell-test-value[X 0 2]" + '("zero" "two"))) + ;; Test using a number as a delimiter. + (let ((eshell-test-value "zero0one0two0three0four")) + (eshell-command-result-equal "echo $eshell-test-value[\"0\" 0]" + "zero") + (eshell-command-result-equal "echo $eshell-test-value[\"0\" 0 2]" '("zero" "two")))) (ert-deftest esh-var-test/interp-var-regexp-split-indices () - "Interpolate string variable with regexp splitter and indices" + "Interpolate string variable with regexp splitter and indices." + ;; Test using a regexp as a delimiter. (let ((eshell-test-value "zero:one!two:three!four")) (eshell-command-result-equal "echo $eshell-test-value['[:!]' 0]" "zero") @@ -103,18 +163,37 @@ (eshell-command-result-equal "echo $eshell-test-value[\"[:!]\" 0]" "zero") (eshell-command-result-equal "echo $eshell-test-value[\"[:!]\" 0 2]" + '("zero" "two"))) + ;; Test using a regexp that looks like range syntax as a delimiter. + (let ((eshell-test-value "zero0..0one0..0two0..0three0..0four")) + (eshell-command-result-equal "echo $eshell-test-value[\"0..0\" 0]" + "zero") + (eshell-command-result-equal "echo $eshell-test-value[\"0..0\" 0 2]" '("zero" "two")))) (ert-deftest esh-var-test/interp-var-assoc () - "Interpolate alist variable with index" - (let ((eshell-test-value '(("foo" . 1) (bar . 2)))) + "Interpolate alist variable with index." + (let ((eshell-test-value '(("foo" . 1) (bar . 2) ("3" . "three")))) (eshell-command-result-equal "echo $eshell-test-value[foo]" 1) (eshell-command-result-equal "echo $eshell-test-value[#'bar]" - 2))) + 2) + (eshell-command-result-equal "echo $eshell-test-value[\"3\"]" + "three"))) + +(ert-deftest esh-var-test/interp-var-indices-subcommand () + "Interpolate list variable with subcommand expansion for indices." + (skip-unless (executable-find "echo")) + (let ((eshell-test-value '("zero" "one" "two" "three" "four"))) + (eshell-command-result-equal + "echo $eshell-test-value[${*echo 0}]" + "zero") + (eshell-command-result-equal + "echo $eshell-test-value[${*echo 0} ${*echo 2}]" + '("zero" "two")))) (ert-deftest esh-var-test/interp-var-length-list () - "Interpolate length of list variable" + "Interpolate length of list variable." (let ((eshell-test-value '((1 2) (3) (5 (6 7 8 9))))) (eshell-command-result-equal "echo $#eshell-test-value" 3) (eshell-command-result-equal "echo $#eshell-test-value[1]" 1) @@ -126,55 +205,75 @@ (eshell-command-result-equal "echo $#eshell-test-value" 6))) (ert-deftest esh-var-test/interp-var-length-alist () - "Interpolate length of alist variable" + "Interpolate length of alist variable." (let ((eshell-test-value '(("foo" . (1 2 3))))) (eshell-command-result-equal "echo $#eshell-test-value" 1) (eshell-command-result-equal "echo $#eshell-test-value[foo]" 3))) +(ert-deftest esh-var-test/interp-var-splice () + "Splice-interpolate list variable." + (let ((eshell-test-value '(1 2 3))) + (eshell-command-result-equal "echo a $@eshell-test-value z" + '("a" 1 2 3 "z")))) + +(ert-deftest esh-var-test/interp-var-splice-concat () + "Splice-interpolate and concat list variable." + (let ((eshell-test-value '(1 2 3))) + (eshell-command-result-equal "echo it is a$@'eshell-test-value'z" + '("it" "is" "a1" 2 "3z")) + ;; This is a tricky case. We're concatenating a spliced list and + ;; a non-spliced list. The general rule is that splicing should + ;; work as though the user typed "$X[0] $X[1] ... $X[N]". That + ;; means that the last value of our splice should get concatenated + ;; into the first value of the non-spliced list. + (eshell-command-result-equal + "echo it is $@'eshell-test-value'$eshell-test-value" + '("it" "is" 1 2 (31 2 3))))) + (ert-deftest esh-var-test/interp-lisp () - "Interpolate Lisp form evaluation" + "Interpolate Lisp form evaluation." (eshell-command-result-equal "+ $(+ 1 2) 3" 6)) (ert-deftest esh-var-test/interp-lisp-indices () - "Interpolate Lisp form evaluation with index" + "Interpolate Lisp form evaluation with index." (eshell-command-result-equal "+ $(list 1 2)[1] 3" 5)) (ert-deftest esh-var-test/interp-cmd () - "Interpolate command result" + "Interpolate command result." (eshell-command-result-equal "+ ${+ 1 2} 3" 6)) (ert-deftest esh-var-test/interp-cmd-indices () - "Interpolate command result with index" + "Interpolate command result with index." (eshell-command-result-equal "+ ${listify 1 2}[1] 3" 5)) (ert-deftest esh-var-test/interp-cmd-external () - "Interpolate command result from external command" + "Interpolate command result from external command." (skip-unless (executable-find "echo")) (with-temp-eshell (eshell-match-command-output "echo ${*echo hi}" "hi\n"))) (ert-deftest esh-var-test/interp-cmd-external-indices () - "Interpolate command result from external command with index" + "Interpolate command result from external command with index." (skip-unless (executable-find "echo")) (with-temp-eshell (eshell-match-command-output "echo ${*echo \"hi\nbye\"}[1]" "bye\n"))) (ert-deftest esh-var-test/interp-temp-cmd () - "Interpolate command result redirected to temp file" + "Interpolate command result redirected to temp file." (eshell-command-result-equal "cat $<echo hi>" "hi")) (ert-deftest esh-var-test/interp-concat-lisp () - "Interpolate and concat Lisp form" + "Interpolate and concat Lisp form." (eshell-command-result-equal "+ $(+ 1 2)3 3" 36)) (ert-deftest esh-var-test/interp-concat-lisp2 () - "Interpolate and concat two Lisp forms" + "Interpolate and concat two Lisp forms." (eshell-command-result-equal "+ $(+ 1 2)$(+ 1 2) 3" 36)) (ert-deftest esh-var-test/interp-concat-cmd () - "Interpolate and concat command with literal" + "Interpolate and concat command with literal." (eshell-command-result-equal "+ ${+ 1 2}3 3" 36) (eshell-command-result-equal "echo ${*echo \"foo\nbar\"}-baz" '("foo" "bar-baz")) @@ -187,18 +286,21 @@ '("hi" "23"))) (ert-deftest esh-var-test/interp-concat-cmd2 () - "Interpolate and concat two commands" + "Interpolate and concat two commands." (eshell-command-result-equal "+ ${+ 1 2}${+ 1 2} 3" 36)) (ert-deftest esh-var-test/interp-concat-cmd-external () - "Interpolate command result from external command with concatenation" + "Interpolate command result from external command with concatenation." (skip-unless (executable-find "echo")) (with-temp-eshell (eshell-match-command-output "echo ${echo hi}-${*echo there}" "hi-there\n"))) + +;; Quoted variable interpolation + (ert-deftest esh-var-test/quoted-interp-var () - "Interpolate variable inside double-quotes" + "Interpolate variable inside double-quotes." (eshell-command-result-equal "echo \"$user-login-name\"" user-login-name)) @@ -209,8 +311,20 @@ (eshell-command-result-equal "echo \"hi, $\\\"user-login-name\\\"\"" (concat "hi, " user-login-name))) +(ert-deftest esh-var-test/quoted-interp-list-var () + "Interpolate list variable inside double-quotes." + (let ((eshell-test-value '(1 2 3))) + (eshell-command-result-equal "echo \"$eshell-test-value\"" + "(1 2 3)"))) + +(ert-deftest esh-var-test/quoted-interp-list-var-concat () + "Interpolate and concat list variable inside double-quotes" + (let ((eshell-test-value '(1 2 3))) + (eshell-command-result-equal "echo \"a$'eshell-test-value'z\"" + "a(1 2 3)z"))) + (ert-deftest esh-var-test/quoted-interp-var-indices () - "Interpolate string variable with indices inside double-quotes" + "Interpolate string variable with indices inside double-quotes." (let ((eshell-test-value '("zero" "one" "two" "three" "four"))) (eshell-command-result-equal "echo \"$eshell-test-value[0]\"" "zero") @@ -224,8 +338,21 @@ (eshell-command-result-equal "echo \"$eshell-test-value[1 2 4]\"" "(\"one\" \"two\" \"four\")"))) +(ert-deftest esh-var-test/quote-interp-var-indices-subcommand () + "Interpolate list variable with subcommand expansion for indices inside double-quotes." + (skip-unless (executable-find "echo")) + (let ((eshell-test-value '("zero" "one" "two" "three" "four"))) + (eshell-command-result-equal + "echo \"$eshell-test-value[${*echo 0}]\"" + "zero") + ;; FIXME: These tests would use the 0th index like the other tests + ;; here, but see above. + (eshell-command-result-equal + "echo \"$eshell-test-value[${*echo 1} ${*echo 2}]\"" + "(\"one\" \"two\")"))) + (ert-deftest esh-var-test/quoted-interp-var-split-indices () - "Interpolate string variable with indices inside double-quotes" + "Interpolate string variable with indices inside double-quotes." (let ((eshell-test-value "zero one two three four")) (eshell-command-result-equal "echo \"$eshell-test-value[0]\"" "zero") @@ -233,8 +360,7 @@ "(\"zero\" \"two\")"))) (ert-deftest esh-var-test/quoted-interp-var-string-split-indices () - "Interpolate string variable with string splitter and indices -inside double-quotes" + "Interpolate string variable with string splitter and indices inside double-quotes." (let ((eshell-test-value "zero:one:two:three:four")) (eshell-command-result-equal "echo \"$eshell-test-value[: 0]\"" "zero") @@ -247,7 +373,7 @@ inside double-quotes" "(\"zero\" \"two\")"))) (ert-deftest esh-var-test/quoted-interp-var-regexp-split-indices () - "Interpolate string variable with regexp splitter and indices" + "Interpolate string variable with regexp splitter and indices." (let ((eshell-test-value "zero:one!two:three!four")) (eshell-command-result-equal "echo \"$eshell-test-value['[:!]' 0]\"" "zero") @@ -260,7 +386,7 @@ inside double-quotes" "(\"zero\" \"two\")"))) (ert-deftest esh-var-test/quoted-interp-var-assoc () - "Interpolate alist variable with index inside double-quotes" + "Interpolate alist variable with index inside double-quotes." (let ((eshell-test-value '(("foo" . 1) (bar . 2)))) (eshell-command-result-equal "echo \"$eshell-test-value[foo]\"" "1") @@ -268,7 +394,7 @@ inside double-quotes" "2"))) (ert-deftest esh-var-test/quoted-interp-var-length-list () - "Interpolate length of list variable inside double-quotes" + "Interpolate length of list variable inside double-quotes." (let ((eshell-test-value '((1 2) (3) (5 (6 7 8 9))))) (eshell-command-result-equal "echo \"$#eshell-test-value\"" "3") @@ -278,41 +404,53 @@ inside double-quotes" "4"))) (ert-deftest esh-var-test/quoted-interp-var-length-string () - "Interpolate length of string variable inside double-quotes" + "Interpolate length of string variable inside double-quotes." (let ((eshell-test-value "foobar")) (eshell-command-result-equal "echo \"$#eshell-test-value\"" "6"))) (ert-deftest esh-var-test/quoted-interp-var-length-alist () - "Interpolate length of alist variable inside double-quotes" + "Interpolate length of alist variable inside double-quotes." (let ((eshell-test-value '(("foo" . (1 2 3))))) (eshell-command-result-equal "echo \"$#eshell-test-value\"" "1") (eshell-command-result-equal "echo \"$#eshell-test-value[foo]\"" "3"))) +(ert-deftest esh-var-test/quoted-interp-var-splice () + "Splice-interpolate list variable inside double-quotes." + (let ((eshell-test-value '(1 2 3))) + (eshell-command-result-equal "echo a \"$@eshell-test-value\" z" + '("a" "1 2 3" "z")))) + +(ert-deftest esh-var-test/quoted-interp-var-splice-concat () + "Splice-interpolate and concat list variable inside double-quotes" + (let ((eshell-test-value '(1 2 3))) + (eshell-command-result-equal "echo \"a$@'eshell-test-value'z\"" + "a1 2 3z"))) + (ert-deftest esh-var-test/quoted-interp-lisp () - "Interpolate Lisp form evaluation inside double-quotes" + "Interpolate Lisp form evaluation inside double-quotes." (eshell-command-result-equal "echo \"hi $(concat \\\"the\\\" \\\"re\\\")\"" "hi there")) (ert-deftest esh-var-test/quoted-interp-lisp-indices () - "Interpolate Lisp form evaluation with index" + "Interpolate Lisp form evaluation with index." (eshell-command-result-equal "concat \"$(list 1 2)[1]\" cool" "2cool")) (ert-deftest esh-var-test/quoted-interp-cmd () - "Interpolate command result inside double-quotes" + "Interpolate command result inside double-quotes." (eshell-command-result-equal "echo \"hi ${echo \\\"there\\\"}\"" "hi there")) (ert-deftest esh-var-test/quoted-interp-cmd-indices () - "Interpolate command result with index inside double-quotes" + "Interpolate command result with index inside double-quotes." (eshell-command-result-equal "concat \"${listify 1 2}[1]\" cool" "2cool")) (ert-deftest esh-var-test/quoted-interp-temp-cmd () - "Interpolate command result redirected to temp file inside double-quotes" + "Interpolate command result redirected to temp file inside double-quotes." (let ((temporary-file-directory (file-name-as-directory (make-temp-file "esh-vars-tests" t)))) (unwind-protect @@ -320,21 +458,36 @@ inside double-quotes" (delete-directory temporary-file-directory t)))) (ert-deftest esh-var-test/quoted-interp-concat-cmd () - "Interpolate and concat command with literal" + "Interpolate and concat command with literal." (eshell-command-result-equal "echo \"${echo \\\"foo\nbar\\\"} baz\"" "foo\nbar baz")) +;; Interpolating commands + +(ert-deftest esh-var-test/command-interp () + "Interpolate a variable as a command name." + (let ((eshell-test-value "printnl")) + (eshell-command-result-equal "$eshell-test-value hello there" + "hello\nthere\n"))) + +(ert-deftest esh-var-test/command-interp-splice () + "Interpolate a splice variable as a command name with arguments." + (let ((eshell-test-value '("printnl" "hello" "there"))) + (eshell-command-result-equal "$@eshell-test-value" + "hello\nthere\n"))) + + ;; Interpolated variable conversion (ert-deftest esh-var-test/interp-convert-var-number () - "Interpolate numeric variable" + "Interpolate numeric variable." (let ((eshell-test-value 123)) (eshell-command-result-equal "type-of $eshell-test-value" 'integer))) (ert-deftest esh-var-test/interp-convert-var-split-indices () - "Interpolate and convert string variable with indices" + "Interpolate and convert string variable with indices." ;; Check that numeric forms are converted to numbers. (let ((eshell-test-value "000 010 020 030 040")) (eshell-command-result-equal "echo $eshell-test-value[0]" @@ -349,7 +502,7 @@ inside double-quotes" "baz\n"))) (ert-deftest esh-var-test/interp-convert-quoted-var-number () - "Interpolate numeric quoted numeric variable" + "Interpolate numeric quoted numeric variable." (let ((eshell-test-value 123)) (eshell-command-result-equal "type-of $'eshell-test-value'" 'integer) @@ -357,7 +510,7 @@ inside double-quotes" 'integer))) (ert-deftest esh-var-test/interp-convert-quoted-var-split-indices () - "Interpolate and convert quoted string variable with indices" + "Interpolate and convert quoted string variable with indices." (let ((eshell-test-value "000 010 020 030 040")) (eshell-command-result-equal "echo $'eshell-test-value'[0]" 0) @@ -365,11 +518,11 @@ inside double-quotes" '(0 20)))) (ert-deftest esh-var-test/interp-convert-cmd-string-newline () - "Interpolate trailing-newline command result" + "Interpolate trailing-newline command result." (eshell-command-result-equal "echo ${echo \"foo\n\"}" "foo")) (ert-deftest esh-var-test/interp-convert-cmd-multiline () - "Interpolate multi-line command result" + "Interpolate multi-line command result." (eshell-command-result-equal "echo ${echo \"foo\nbar\"}" '("foo" "bar")) ;; Numeric output should be converted to numbers... @@ -380,24 +533,24 @@ inside double-quotes" '("01" "02" "hi"))) (ert-deftest esh-var-test/interp-convert-cmd-number () - "Interpolate numeric command result" + "Interpolate numeric command result." (eshell-command-result-equal "echo ${echo \"1\"}" 1)) (ert-deftest esh-var-test/interp-convert-cmd-split-indices () - "Interpolate command result with indices" + "Interpolate command result with indices." (eshell-command-result-equal "echo ${echo \"000 010 020\"}[0]" 0) (eshell-command-result-equal "echo ${echo \"000 010 020\"}[0 2]" '(0 20))) (ert-deftest esh-var-test/quoted-interp-convert-var-number () - "Interpolate numeric variable inside double-quotes" + "Interpolate numeric variable inside double-quotes." (let ((eshell-test-value 123)) (eshell-command-result-equal "type-of \"$eshell-test-value\"" 'string))) (ert-deftest esh-var-test/quoted-interp-convert-var-split-indices () - "Interpolate string variable with indices inside double-quotes" + "Interpolate string variable with indices inside double-quotes." (let ((eshell-test-value "000 010 020 030 040")) (eshell-command-result-equal "echo \"$eshell-test-value[0]\"" "000") @@ -405,7 +558,7 @@ inside double-quotes" "(\"000\" \"020\")"))) (ert-deftest esh-var-test/quoted-interp-convert-quoted-var-number () - "Interpolate numeric quoted variable inside double-quotes" + "Interpolate numeric quoted variable inside double-quotes." (let ((eshell-test-value 123)) (eshell-command-result-equal "type-of \"$'eshell-test-value'\"" 'string) @@ -413,7 +566,7 @@ inside double-quotes" 'string))) (ert-deftest esh-var-test/quoted-interp-convert-quoted-var-split-indices () - "Interpolate quoted string variable with indices inside double-quotes" + "Interpolate quoted string variable with indices inside double-quotes." (let ((eshell-test-value "000 010 020 030 040")) (eshell-command-result-equal "echo \"$eshell-test-value[0]\"" "000") @@ -421,23 +574,23 @@ inside double-quotes" "(\"000\" \"020\")"))) (ert-deftest esh-var-test/quoted-interp-convert-cmd-string-newline () - "Interpolate trailing-newline command result inside double-quotes" + "Interpolate trailing-newline command result inside double-quotes." (eshell-command-result-equal "echo \"${echo \\\"foo\n\\\"}\"" "foo") (eshell-command-result-equal "echo \"${echo \\\"foo\n\n\\\"}\"" "foo")) (ert-deftest esh-var-test/quoted-interp-convert-cmd-multiline () - "Interpolate multi-line command result inside double-quotes" + "Interpolate multi-line command result inside double-quotes." (eshell-command-result-equal "echo \"${echo \\\"foo\nbar\\\"}\"" "foo\nbar")) (ert-deftest esh-var-test/quoted-interp-convert-cmd-number () - "Interpolate numeric command result inside double-quotes" + "Interpolate numeric command result inside double-quotes." (eshell-command-result-equal "echo \"${echo \\\"1\\\"}\"" "1")) (ert-deftest esh-var-test/quoted-interp-convert-cmd-split-indices () - "Interpolate command result with indices inside double-quotes" + "Interpolate command result with indices inside double-quotes." (eshell-command-result-equal "echo \"${echo \\\"000 010 020\\\"}[0]\"" "000")) @@ -596,19 +749,19 @@ it, since the setter is nil." (window-body-height nil 'remap))) (ert-deftest esh-var-test/columns-var () - "$COLUMNS should equal (window-body-width nil 'remap)" + "$COLUMNS should equal (window-body-width nil 'remap)." (eshell-command-result-equal "echo $COLUMNS" (window-body-width nil 'remap))) (ert-deftest esh-var-test/inside-emacs-var () - "Test presence of \"INSIDE_EMACS\" in subprocesses" + "Test presence of \"INSIDE_EMACS\" in subprocesses." (with-temp-eshell (eshell-match-command-output "env" (format "INSIDE_EMACS=%s,eshell" emacs-version)))) (ert-deftest esh-var-test/inside-emacs-var-split-indices () - "Test using \"INSIDE_EMACS\" with split indices" + "Test using \"INSIDE_EMACS\" with split indices." (with-temp-eshell (eshell-match-command-output "echo $INSIDE_EMACS[, 1]" "eshell"))) @@ -672,8 +825,12 @@ it, since the setter is nil." (format "cd %s" ert-remote-temporary-file-directory)) (eshell-match-command-output "echo $PATH" (regexp-quote remote-path))))) +(ert-deftest esh-var-test/uid-var () + "Test that $UID is equivalent to (user-uid) for local directories." + (eshell-command-result-equal "echo $UID" (user-uid))) + (ert-deftest esh-var-test/last-status-var-lisp-command () - "Test using the \"last exit status\" ($?) variable with a Lisp command" + "Test using the \"last exit status\" ($?) variable with a Lisp command." (with-temp-eshell (eshell-match-command-output "zerop 0; echo $?" "t\n0\n") @@ -683,7 +840,7 @@ it, since the setter is nil." "1\n" nil t))) (ert-deftest esh-var-test/last-status-var-lisp-form () - "Test using the \"last exit status\" ($?) variable with a Lisp form" + "Test using the \"last exit status\" ($?) variable with a Lisp form." (let ((eshell-lisp-form-nil-is-failure t)) (with-temp-eshell (eshell-match-command-output "(zerop 0); echo $?" @@ -706,7 +863,7 @@ This tests when `eshell-lisp-form-nil-is-failure' is nil." "1\n" nil t)))) (ert-deftest esh-var-test/last-status-var-ext-cmd () - "Test using the \"last exit status\" ($?) variable with an external command" + "Test using the \"last exit status\" ($?) variable with an external command." (skip-unless (executable-find "[")) (with-temp-eshell (eshell-match-command-output "[ foo = foo ]; echo $?" @@ -715,19 +872,19 @@ This tests when `eshell-lisp-form-nil-is-failure' is nil." "1\n"))) (ert-deftest esh-var-test/last-result-var () - "Test using the \"last result\" ($$) variable" + "Test using the \"last result\" ($$) variable." (with-temp-eshell (eshell-match-command-output "+ 1 2; + $$ 2" "3\n5\n"))) (ert-deftest esh-var-test/last-result-var-twice () - "Test using the \"last result\" ($$) variable twice" + "Test using the \"last result\" ($$) variable twice." (with-temp-eshell (eshell-match-command-output "+ 1 2; + $$ $$" "3\n6\n"))) (ert-deftest esh-var-test/last-result-var-ext-cmd () - "Test using the \"last result\" ($$) variable with an external command" + "Test using the \"last result\" ($$) variable with an external command." (skip-unless (executable-find "[")) (with-temp-eshell ;; MS-DOS/MS-Windows have an external command 'format', which we @@ -739,7 +896,7 @@ This tests when `eshell-lisp-form-nil-is-failure' is nil." "nil\n")))) (ert-deftest esh-var-test/last-result-var-split-indices () - "Test using the \"last result\" ($$) variable with split indices" + "Test using the \"last result\" ($$) variable with split indices." (with-temp-eshell (eshell-match-command-output "string-join (list \"01\" \"02\") :; + $$[: 1] 3" @@ -749,13 +906,13 @@ This tests when `eshell-lisp-form-nil-is-failure' is nil." "01:02\n02\n"))) (ert-deftest esh-var-test/last-arg-var () - "Test using the \"last arg\" ($_) variable" + "Test using the \"last arg\" ($_) variable." (with-temp-eshell (eshell-match-command-output "+ 1 2; + $_ 4" "3\n6\n"))) (ert-deftest esh-var-test/last-arg-var-indices () - "Test using the \"last arg\" ($_) variable with indices" + "Test using the \"last arg\" ($_) variable with indices." (with-temp-eshell (eshell-match-command-output "+ 1 2; + $_[0] 4" "3\n5\n") @@ -763,7 +920,7 @@ This tests when `eshell-lisp-form-nil-is-failure' is nil." "3\n6\n"))) (ert-deftest esh-var-test/last-arg-var-split-indices () - "Test using the \"last arg\" ($_) variable with split indices" + "Test using the \"last arg\" ($_) variable with split indices." (with-temp-eshell (eshell-match-command-output "concat 01:02 03:04; + $_[0][: 1] 5" "01:0203:04\n7\n") diff --git a/test/lisp/eshell/eshell-tests-helpers.el b/test/lisp/eshell/eshell-tests-helpers.el index f1d12dbe9f3..2c913d71cb4 100644 --- a/test/lisp/eshell/eshell-tests-helpers.el +++ b/test/lisp/eshell/eshell-tests-helpers.el @@ -33,9 +33,9 @@ (defvar eshell-history-file-name nil) (defvar eshell-last-dir-ring-file-name nil) -(defvar eshell-test--max-subprocess-time 5 - "The maximum amount of time to wait for a subprocess to finish, in seconds. -See `eshell-wait-for-subprocess'.") +(defvar eshell-test--max-wait-time 5 + "The maximum amount of time to wait for a condition to resolve, in seconds. +See `eshell-wait-for'.") (defun eshell-tests-remote-accessible-p () "Return if a test involving remote files can proceed. @@ -73,19 +73,28 @@ BUFNAME will be set to the name of the temporary buffer." (let ((,bufname (buffer-name))) ,@body))) +(defun eshell-wait-for (predicate &optional message) + "Wait until PREDICATE returns non-nil. +If this takes longer than `eshell-test--max-wait-time', raise an +error. MESSAGE is an optional message to use if this times out." + (let ((start (current-time)) + (message (or message "timed out waiting for condition"))) + (while (not (funcall predicate)) + (when (> (float-time (time-since start)) + eshell-test--max-wait-time) + (error message)) + (sit-for 0.1)))) + (defun eshell-wait-for-subprocess (&optional all) "Wait until there is no interactive subprocess running in Eshell. If ALL is non-nil, wait until there are no Eshell subprocesses at all running. -If this takes longer than `eshell-test--max-subprocess-time', +If this takes longer than `eshell-test--max-wait-time', raise an error." - (let ((start (current-time))) - (while (if all eshell-process-list (eshell-interactive-process-p)) - (when (> (float-time (time-since start)) - eshell-test--max-subprocess-time) - (error "timed out waiting for subprocess(es)")) - (sit-for 0.1)))) + (eshell-wait-for + (lambda () + (not (if all eshell-process-list (eshell-interactive-process-p)))))) (defun eshell-insert-command (command &optional func) "Insert a COMMAND at the end of the buffer. diff --git a/test/lisp/eshell/eshell-tests.el b/test/lisp/eshell/eshell-tests.el index 3c4a8ec97ea..776cfb9b92f 100644 --- a/test/lisp/eshell/eshell-tests.el +++ b/test/lisp/eshell/eshell-tests.el @@ -117,27 +117,28 @@ (with-temp-eshell (eshell-insert-command "echo $(+ 1 (- 4 3)) \"alpha beta\" file" 'ignore) (let ((here (point)) begin valid) - (eshell-bol) + (beginning-of-line) (setq begin (point)) (eshell-forward-argument 4) (setq valid (= here (point))) (eshell-backward-argument 4) (prog1 (and valid (= begin (point))) - (eshell-bol) + (beginning-of-line) (delete-region (point) (point-max)))))) (ert-deftest eshell-test/queue-input () - "Test queuing command input" + "Test queuing command input. +This should let the current command finish, then automatically +insert the queued one at the next prompt, and finally run it." (with-temp-eshell - (eshell-insert-command "sleep 2") - (eshell-insert-command "echo alpha" 'eshell-queue-input) - (let ((count 10)) - (while (and eshell-current-command - (> count 0)) - (sit-for 1) - (setq count (1- count)))) - (should (eshell-match-output "alpha\n")))) + (eshell-insert-command "sleep 1; echo slept") + (eshell-insert-command "echo alpha" #'eshell-queue-input) + (let ((start (marker-position (eshell-beginning-of-output)))) + (eshell-wait-for (lambda () (not eshell-current-command))) + (should (string-match "^slept\n.*echo alpha\nalpha\n$" + (buffer-substring-no-properties + start (eshell-end-of-output))))))) (ert-deftest eshell-test/flush-output () "Test flushing of previous output" @@ -147,12 +148,17 @@ (should (eshell-match-output (concat "^" (regexp-quote "*** output flushed ***\n") "$"))))) -(ert-deftest eshell-test/run-old-command () - "Re-run an old command" +(ert-deftest eshell-test/get-old-input () + "Test that we can get the input of a previous command." (with-temp-eshell (eshell-insert-command "echo alpha") (goto-char eshell-last-input-start) - (string= (eshell-get-old-input) "echo alpha"))) + (should (string= (eshell-get-old-input) "echo alpha")) + ;; Make sure that `eshell-get-old-input' works even if the point is + ;; inside the prompt. + (let ((inhibit-field-text-motion t)) + (beginning-of-line)) + (should (string= (eshell-get-old-input) "echo alpha")))) (provide 'eshell-tests) diff --git a/test/lisp/net/tramp-archive-tests.el b/test/lisp/net/tramp-archive-tests.el index b28b32bc7d3..94ef40a1116 100644 --- a/test/lisp/net/tramp-archive-tests.el +++ b/test/lisp/net/tramp-archive-tests.el @@ -121,12 +121,6 @@ the origin of the temporary TMPFILE, have no write permissions." (directory-files tmpfile 'full directory-files-no-dot-files-regexp)) (delete-directory tmpfile))) -(defun tramp-archive--test-emacs27-p () - "Check for Emacs version >= 27.1. -Some semantics has been changed for there, without new functions or -variables, so we check the Emacs version directly." - (>= emacs-major-version 27)) - (ert-deftest tramp-archive-test00-availability () "Test availability of archive file name functions." :expected-result (if tramp-archive-enabled :passed :failed) @@ -615,16 +609,13 @@ This checks also `file-name-as-directory', `file-name-directory', (with-temp-buffer (insert-directory tramp-archive-test-archive nil) (goto-char (point-min)) - (should - (looking-at-p - (tramp-compat-rx (literal tramp-archive-test-archive))))) + (should (looking-at-p (rx (literal tramp-archive-test-archive))))) (with-temp-buffer (insert-directory tramp-archive-test-archive "-al") (goto-char (point-min)) (should (looking-at-p - (tramp-compat-rx - bol (+ nonl) blank (literal tramp-archive-test-archive) eol)))) + (rx bol (+ nonl) blank (literal tramp-archive-test-archive) eol)))) (with-temp-buffer (insert-directory (file-name-as-directory tramp-archive-test-archive) @@ -880,26 +871,31 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'." (ert-deftest tramp-archive-test43-file-system-info () "Check that `file-system-info' returns proper values." (skip-unless tramp-archive-enabled) - ;; Since Emacs 27.1. - (skip-unless (fboundp 'file-system-info)) - ;; `file-system-info' exists since Emacs 27. We don't want to see - ;; compiler warnings for older Emacsen. - (let ((fsi (with-no-warnings (file-system-info tramp-archive-test-archive)))) + (let ((fsi (file-system-info tramp-archive-test-archive))) (skip-unless fsi) (should (and (consp fsi) - (= (length fsi) 3) + (tramp-compat-length= fsi 3) (numberp (nth 0 fsi)) ;; FREE and AVAIL are always 0. (zerop (nth 1 fsi)) (zerop (nth 2 fsi)))))) -(ert-deftest tramp-archive-test47-auto-load () +;; `file-user-uid' was introduced in Emacs 30.1. +(ert-deftest tramp-archive-test44-file-user-uid () + "Check that `file-user-uid' returns proper values." + (skip-unless tramp-archive-enabled) + (skip-unless (fboundp 'file-user-uid)) + + (let ((default-directory tramp-archive-test-archive)) + ;; `file-user-uid' exists since Emacs 30.1. We don't want to see + ;; compiler warnings for older Emacsen. + (should (integerp (with-no-warnings (file-user-uid)))))) + +(ert-deftest tramp-archive-test48-auto-load () "Check that `tramp-archive' autoloads properly." :tags '(:expensive-test) (skip-unless tramp-archive-enabled) - ;; Autoloading tramp-archive works since Emacs 27.1. - (skip-unless (tramp-archive--test-emacs27-p)) ;; tramp-archive is neither loaded at Emacs startup, nor when ;; loading a file like "/mock::foo" (which loads Tramp). @@ -922,7 +918,7 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'." (dolist (file `("/mock::foo" ,(concat tramp-archive-test-archive "foo"))) (should (string-match - (tramp-compat-rx + (rx "tramp-archive loaded: " (literal (symbol-name (tramp-archive-file-name-p default-directory))) @@ -941,12 +937,10 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'." (format "(setq tramp-archive-enabled %s)" enabled)) (shell-quote-argument (format code file))))))))))) -(ert-deftest tramp-archive-test47-delay-load () +(ert-deftest tramp-archive-test48-delay-load () "Check that `tramp-archive' is loaded lazily, only when needed." :tags '(:expensive-test) (skip-unless tramp-archive-enabled) - ;; Autoloading tramp-archive works since Emacs 27.1. - (skip-unless (tramp-archive--test-emacs27-p)) ;; tramp-archive is neither loaded at Emacs startup, nor when ;; loading a file like "/foo.tar". It is loaded only when @@ -967,7 +961,7 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'." (dolist (tae '(t nil)) (should (string-match - (tramp-compat-rx + (rx "tramp-archive loaded: nil" (+ ascii) "tramp-archive loaded: nil" (+ ascii) "tramp-archive loaded: " (literal (symbol-name tae))) diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el index ff0fc56043e..338482d2b61 100644 --- a/test/lisp/net/tramp-tests.el +++ b/test/lisp/net/tramp-tests.el @@ -33,7 +33,7 @@ ;; remote host, set this environment variable to "/dev/null" or ;; whatever is appropriate on your system. -;; For slow remote connections, `tramp-test44-asynchronous-requests' +;; For slow remote connections, `tramp-test45-asynchronous-requests' ;; might be too heavy. Setting $REMOTE_PARALLEL_PROCESSES to a proper ;; value less than 10 could help. @@ -74,16 +74,15 @@ (defvar tramp-remote-path) (defvar tramp-remote-process-environment) -;; Needed for Emacs 26. -(declare-function with-connection-local-variables "files-x") ;; Needed for Emacs 27. (defvar lock-file-name-transforms) (defvar process-file-return-signal-string) (defvar remote-file-name-inhibit-locks) -(defvar shell-command-dont-erase-buffer) -;; Needed for Emacs 28. (defvar dired-copy-dereference) +;; Declared in Emacs 30. +(defvar remote-file-name-inhibit-delete-by-moving-to-trash) + ;; `ert-resource-file' was introduced in Emacs 28.1. (unless (macrop 'ert-resource-file) (eval-and-compile @@ -166,6 +165,9 @@ A resource file is in the resource directory as per ;; Suppress nasty messages. (fset #'shell-command-sentinel #'ignore) ;; We do not want to be interrupted. + (fset #'tramp-action-yesno + (lambda (_proc vec) + (tramp-send-string vec (concat "yes" tramp-local-end-of-line)) t)) (eval-after-load 'tramp-gvfs '(fset 'tramp-gvfs-handler-askquestion (lambda (_message _choices) '(t nil 0))))) @@ -224,7 +226,7 @@ If LOCAL is non-nil, a local file name is returned. If QUOTED is non-nil, the local part of the file name is quoted. The temporary file is not created." (funcall - (if quoted #'tramp-compat-file-name-quote #'identity) + (if quoted #'file-name-quote #'identity) (expand-file-name (make-temp-name "tramp-test") (if local temporary-file-directory ert-remote-temporary-file-directory)))) @@ -2296,10 +2298,9 @@ This checks also `file-name-as-directory', `file-name-directory', ;; Check `directory-abbrev-alist' abbreviation. (let ((directory-abbrev-alist - `((,(tramp-compat-rx bos (literal home-dir) "/foo") - . ,(concat home-dir "/f")) - (,(tramp-compat-rx bos (literal remote-host) "/nowhere") - . ,(concat remote-host "/nw"))))) + `((,(rx bos (literal home-dir) "/foo") . ,(concat home-dir "/f")) + (,(rx bos (literal remote-host) "/nowhere") + . ,(concat remote-host "/nw"))))) (should (equal (abbreviate-file-name (concat home-dir "/foo/bar")) (concat remote-host-nohop "~/f/bar"))) (should (equal (abbreviate-file-name @@ -2350,7 +2351,24 @@ This checks also `file-name-as-directory', `file-name-directory', (expand-file-name (file-name-nondirectory tmp-name) trash-directory)))) (delete-directory trash-directory 'recursive) - (should-not (file-exists-p trash-directory))))))) + (should-not (file-exists-p trash-directory)))) + + ;; Setting `remote-file-name-inhibit-delete-by-moving-to-trash' + ;; prevents trashing remote files. + (let ((trash-directory (tramp--test-make-temp-name 'local quoted)) + (delete-by-moving-to-trash t) + (remote-file-name-inhibit-delete-by-moving-to-trash t)) + (make-directory trash-directory) + (should-not (file-exists-p tmp-name)) + (write-region "foo" nil tmp-name) + (should (file-exists-p tmp-name)) + (delete-file tmp-name 'trash) + (should-not (file-exists-p tmp-name)) + (should-not + (file-exists-p + (expand-file-name (file-name-nondirectory tmp-name) trash-directory))) + (delete-directory trash-directory 'recursive) + (should-not (file-exists-p trash-directory)))))) (ert-deftest tramp-test08-file-local-copy () "Check `file-local-copy'." @@ -2479,17 +2497,14 @@ This checks also `file-name-as-directory', `file-name-directory', (should (string-equal (buffer-string) "foo"))) ;; Write empty string. Used for creation of temporary files. - ;; Since Emacs 27.1. - (when (fboundp 'make-empty-file) - (with-no-warnings - (should-error - (make-empty-file tmp-name) - :type 'file-already-exists) - (delete-file tmp-name) - (make-empty-file tmp-name) - (with-temp-buffer - (insert-file-contents tmp-name) - (should (string-equal (buffer-string) ""))))) + (should-error + (make-empty-file tmp-name) + :type 'file-already-exists) + (delete-file tmp-name) + (make-empty-file tmp-name) + (with-temp-buffer + (insert-file-contents tmp-name) + (should (string-equal (buffer-string) ""))) ;; Write partly. (with-temp-buffer @@ -2511,8 +2526,7 @@ This checks also `file-name-as-directory', `file-name-directory', (string-match-p (if (and (null noninteractive) (or (eq visit t) (null visit) (stringp visit))) - (tramp-compat-rx - bol "Wrote " (literal tmp-name) "\n" eos) + (rx bol "Wrote " (literal tmp-name) "\n" eos) (rx bos)) tramp--test-messages)))))) @@ -2542,8 +2556,6 @@ This checks also `file-name-as-directory', `file-name-directory', "Check that `file-precious-flag' is respected with Tramp in use." (skip-unless (tramp--test-enabled)) (skip-unless (tramp--test-sh-p)) - ;; The bug is fixed in Emacs 27.1. - (skip-unless (tramp--test-emacs27-p)) (let* ((tmp-name (tramp--test-make-temp-name)) (inhibit-message t) @@ -2626,10 +2638,7 @@ This checks also `file-name-as-directory', `file-name-directory', "Check `copy-file'." (skip-unless (tramp--test-enabled)) - ;; `filename-non-special' has been fixed in Emacs 27.1, see Bug#29579. - (dolist (quoted - (if (and (tramp--test-expensive-test-p) (tramp--test-emacs27-p)) - '(nil t) '(nil))) + (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil))) (let ((tmp-name1 (tramp--test-make-temp-name nil quoted)) (tmp-name2 (tramp--test-make-temp-name nil quoted)) (tmp-name3 (tramp--test-make-temp-name 'local quoted))) @@ -2738,10 +2747,7 @@ This checks also `file-name-as-directory', `file-name-directory', "Check `rename-file'." (skip-unless (tramp--test-enabled)) - ;; `filename-non-special' has been fixed in Emacs 27.1, see Bug#29579. - (dolist (quoted - (if (and (tramp--test-expensive-test-p) (tramp--test-emacs27-p)) - '(nil t) '(nil))) + (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil))) (let ((tmp-name1 (tramp--test-make-temp-name nil quoted)) (tmp-name2 (tramp--test-make-temp-name nil quoted)) (tmp-name3 (tramp--test-make-temp-name 'local quoted))) @@ -2857,6 +2863,7 @@ This checks also `file-name-as-directory', `file-name-directory', This tests also `file-directory-p' and `file-accessible-directory-p'." (skip-unless (tramp--test-enabled)) + ;; Since Emacs 29.1, `make-directory' has defined return values. (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil))) (let* ((tmp-name1 (tramp--test-make-temp-name nil quoted)) (tmp-name2 (expand-file-name "foo/bar" tmp-name1)) @@ -2865,7 +2872,9 @@ This tests also `file-directory-p' and `file-accessible-directory-p'." (unwind-protect (progn (with-file-modes unusual-file-mode-1 - (make-directory tmp-name1)) + (if (tramp--test-emacs29-p) + (should-not (make-directory tmp-name1)) + (make-directory tmp-name1))) (should-error (make-directory tmp-name1) :type 'file-already-exists) @@ -2878,15 +2887,19 @@ This tests also `file-directory-p' and `file-accessible-directory-p'." (make-directory tmp-name2) :type 'file-error) (with-file-modes unusual-file-mode-2 - (make-directory tmp-name2 'parents)) + (if (tramp--test-emacs29-p) + (should-not (make-directory tmp-name2 'parents)) + (make-directory tmp-name2 'parents))) (should (file-directory-p tmp-name2)) (should (file-accessible-directory-p tmp-name2)) (when (tramp--test-supports-set-file-modes-p) (should (equal (format "%#o" unusual-file-mode-2) (format "%#o" (file-modes tmp-name2))))) ;; If PARENTS is non-nil, `make-directory' shall not - ;; signal an error when DIR exists already. - (make-directory tmp-name2 'parents)) + ;; signal an error when DIR exists already. It returns t. + (if (tramp--test-emacs29-p) + (should (make-directory tmp-name2 'parents)) + (make-directory tmp-name2 'parents))) ;; Cleanup. (ignore-errors (delete-directory tmp-name1 'recursive)))))) @@ -2918,13 +2931,11 @@ This tests also `file-directory-p' and `file-accessible-directory-p'." (delete-directory tmp-name1 'recursive) (should-not (file-directory-p tmp-name1)) - ;; Trashing directories works only since Emacs 27.1. It doesn't - ;; work when `system-move-file-to-trash' is defined (on MS - ;; Windows and macOS), for encrypted remote directories and for - ;; ange-ftp. + ;; Trashing directories doesn't work when + ;; `system-move-file-to-trash' is defined (on MS Windows and + ;; macOS), for encrypted remote directories and for ange-ftp. (when (and (not (fboundp 'system-move-file-to-trash)) - (not (tramp--test-crypt-p)) (not (tramp--test-ftp-p)) - (tramp--test-emacs27-p)) + (not (tramp--test-crypt-p)) (not (tramp--test-ftp-p))) (let ((trash-directory (tramp--test-make-temp-name 'local quoted)) (delete-by-moving-to-trash t)) (make-directory trash-directory) @@ -2965,7 +2976,23 @@ This tests also `file-directory-p' and `file-accessible-directory-p'." "%s/%s/%s/bla" trash-directory (file-name-nondirectory tmp-name1) (file-name-nondirectory tmp-name2)))) (delete-directory trash-directory 'recursive) - (should-not (file-exists-p trash-directory))))))) + (should-not (file-exists-p trash-directory)))) + + ;; Setting `remote-file-name-inhibit-delete-by-moving-to-trash' + ;; prevents trashing remote files. + (let ((trash-directory (tramp--test-make-temp-name 'local quoted)) + (delete-by-moving-to-trash t) + (remote-file-name-inhibit-delete-by-moving-to-trash t)) + (make-directory trash-directory) + (make-directory tmp-name1) + (should (file-directory-p tmp-name1)) + (delete-directory tmp-name1 nil 'trash) + (should-not (file-exists-p tmp-name1)) + (should-not + (file-exists-p + (expand-file-name (file-name-nondirectory tmp-name1) trash-directory))) + (delete-directory trash-directory 'recursive) + (should-not (file-exists-p trash-directory)))))) (ert-deftest tramp-test15-copy-directory () "Check `copy-directory'." @@ -3193,9 +3220,6 @@ This tests also `file-directory-p' and `file-accessible-directory-p'." ;; (this is performed by `dired'). If FULL is nil, it shows just ;; one file. So we refrain from testing. (skip-unless (not (tramp--test-ange-ftp-p))) - ;; `insert-directory' of encrypted remote directories works only - ;; since Emacs 27.1. - (skip-unless (or (not (tramp--test-crypt-p)) (tramp--test-emacs27-p))) (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil))) (let* ((tmp-name1 @@ -3213,26 +3237,23 @@ This tests also `file-directory-p' and `file-accessible-directory-p'." (with-temp-buffer (insert-directory tmp-name1 nil) (goto-char (point-min)) - (should (looking-at-p (tramp-compat-rx (literal tmp-name1))))) + (should (looking-at-p (rx (literal tmp-name1))))) (with-temp-buffer (insert-directory (file-name-as-directory tmp-name1) nil) (goto-char (point-min)) (should - (looking-at-p - (tramp-compat-rx (literal (file-name-as-directory tmp-name1)))))) + (looking-at-p (rx (literal (file-name-as-directory tmp-name1)))))) (with-temp-buffer (insert-directory tmp-name1 "-al") (goto-char (point-min)) (should - (looking-at-p - (tramp-compat-rx bol (+ nonl) blank (literal tmp-name1) eol)))) + (looking-at-p (rx bol (+ nonl) blank (literal tmp-name1) eol)))) (with-temp-buffer (insert-directory (file-name-as-directory tmp-name1) "-al") (goto-char (point-min)) (should (looking-at-p - (tramp-compat-rx - bol (+ nonl) blank (literal tmp-name1) "/" eol)))) + (rx bol (+ nonl) blank (literal tmp-name1) "/" eol)))) (with-temp-buffer (insert-directory (file-name-as-directory tmp-name1) "-al" nil 'full-directory-p) @@ -3293,7 +3314,7 @@ This tests also `file-directory-p' and `file-accessible-directory-p'." (tmp-name4 (expand-file-name "bar" tmp-name2)) (ert-remote-temporary-file-directory (funcall - (if quoted #'tramp-compat-file-name-quote #'identity) + (if quoted #'file-name-quote #'identity) ert-remote-temporary-file-directory)) buffer) (unwind-protect @@ -3316,14 +3337,14 @@ This tests also `file-directory-p' and `file-accessible-directory-p'." (goto-char (point-min)) (should (re-search-forward - (tramp-compat-rx + (rx (literal (file-relative-name tmp-name1 ert-remote-temporary-file-directory))))) (goto-char (point-min)) (should (re-search-forward - (tramp-compat-rx + (rx (literal (file-relative-name tmp-name2 ert-remote-temporary-file-directory)))))) @@ -3338,14 +3359,14 @@ This tests also `file-directory-p' and `file-accessible-directory-p'." (goto-char (point-min)) (should (re-search-forward - (tramp-compat-rx + (rx (literal (file-relative-name tmp-name3 ert-remote-temporary-file-directory))))) (goto-char (point-min)) (should (re-search-forward - (tramp-compat-rx + (rx (literal (file-relative-name tmp-name4 @@ -3368,14 +3389,14 @@ This tests also `file-directory-p' and `file-accessible-directory-p'." (goto-char (point-min)) (should (re-search-forward - (tramp-compat-rx + (rx (literal (file-relative-name tmp-name3 ert-remote-temporary-file-directory))))) (goto-char (point-min)) (should (re-search-forward - (tramp-compat-rx + (rx (literal (file-relative-name tmp-name4 @@ -3548,7 +3569,7 @@ This tests also `access-file', `file-readable-p', (should (string-equal (funcall - (if quoted #'tramp-compat-file-name-quote #'identity) + (if quoted #'file-name-quote #'identity) (file-attribute-type attr)) (file-remote-p (file-truename tmp-name1) 'localname))) (delete-file tmp-name2)) @@ -3612,9 +3633,6 @@ This tests also `access-file', `file-readable-p', (cons '(nil "perl" nil) tramp-connection-properties))) (progn - ;; `ert-test-result-duration' exists since Emacs 27. It - ;; doesn't hurt to call it unconditionally, because - ;; `skip-unless' hides the error. (skip-unless (< (ert-test-result-duration result) 300)) (funcall (ert-test-body ert-test))) (ert-skip (format "Test `%s' must run before" ',test))))) @@ -3643,9 +3661,6 @@ This tests also `access-file', `file-readable-p', (nil "id" nil)) tramp-connection-properties))) (progn - ;; `ert-test-result-duration' exists since Emacs 27. It - ;; doesn't hurt to call it unconditionally, because - ;; `skip-unless' hides the error. (skip-unless (< (ert-test-result-duration result) 300)) (funcall (ert-test-body ert-test))) (ert-skip (format "Test `%s' must run before" ',test))))) @@ -3672,9 +3687,6 @@ This tests also `access-file', `file-readable-p', (nil "readlink" nil)) tramp-connection-properties))) (progn - ;; `ert-test-result-duration' exists since Emacs 27. It - ;; doesn't hurt to call it unconditionally, because - ;; `skip-unless' hides the error. (skip-unless (< (ert-test-result-duration result) 300)) (funcall (ert-test-body ert-test))) (ert-skip (format "Test `%s' must run before" ',test))))) @@ -3710,9 +3722,9 @@ They might differ only in time attributes or directory size." ;; few seconds). We use a test start time minus 10 seconds, in ;; order to compensate a possible timestamp resolution higher than ;; a second on the remote machine. - (when (or (tramp-compat-time-equal-p + (when (or (time-equal-p (file-attribute-modification-time attr1) tramp-time-dont-know) - (tramp-compat-time-equal-p + (time-equal-p (file-attribute-modification-time attr2) tramp-time-dont-know)) (setcar (nthcdr 5 attr1) tramp-time-dont-know) (setcar (nthcdr 5 attr2) tramp-time-dont-know)) @@ -3723,9 +3735,9 @@ They might differ only in time attributes or directory size." (float-time (file-attribute-modification-time attr2))) (setcar (nthcdr 5 attr2) tramp-time-dont-know)) ;; Status change time. Ditto. - (when (or (tramp-compat-time-equal-p + (when (or (time-equal-p (file-attribute-status-change-time attr1) tramp-time-dont-know) - (tramp-compat-time-equal-p + (time-equal-p (file-attribute-status-change-time attr2) tramp-time-dont-know)) (setcar (nthcdr 6 attr1) tramp-time-dont-know) (setcar (nthcdr 6 attr2) tramp-time-dont-know)) @@ -3864,7 +3876,7 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'." (should (string-equal (funcall - (if quoted #'tramp-compat-file-name-unquote #'identity) + (if quoted #'file-name-unquote #'identity) (file-remote-p tmp-name1 'localname)) (file-symlink-p tmp-name2))) ;; Both report the modes of `tmp-name1'. @@ -3937,7 +3949,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (should (string-equal (funcall - (if quoted #'tramp-compat-file-name-unquote #'identity) + (if quoted #'file-name-unquote #'identity) (file-remote-p tmp-name1 'localname)) (file-symlink-p tmp-name2))) (when (tramp--test-expensive-test-p) @@ -3955,14 +3967,14 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (should (string-equal (funcall - (if quoted #'tramp-compat-file-name-unquote #'identity) + (if quoted #'file-name-unquote #'identity) (file-remote-p tmp-name1 'localname)) (file-symlink-p tmp-name2)))) (make-symbolic-link tmp-name1 tmp-name2 'ok-if-already-exists) (should (string-equal (funcall - (if quoted #'tramp-compat-file-name-unquote #'identity) + (if quoted #'file-name-unquote #'identity) (file-remote-p tmp-name1 'localname)) (file-symlink-p tmp-name2))) ;; If we use the local part of `tmp-name1', it shall still work. @@ -3972,7 +3984,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (should (string-equal (funcall - (if quoted #'tramp-compat-file-name-unquote #'identity) + (if quoted #'file-name-unquote #'identity) (file-remote-p tmp-name1 'localname)) (file-symlink-p tmp-name2))) ;; `tmp-name3' is a local file name. Therefore, the link @@ -3994,7 +4006,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (should (string-equal (funcall - (if quoted #'tramp-compat-file-name-unquote #'identity) + (if quoted #'file-name-unquote #'identity) (file-remote-p tmp-name1 'localname)) (file-symlink-p tmp-name5))) ;; Check, that files in symlinked directories still work. @@ -4088,16 +4100,14 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." "/[penguin/motd]" "/penguin:motd:"))) (delete-file tmp-name2) (make-symbolic-link - (funcall - (if quoted #'tramp-compat-file-name-unquote #'identity) penguin) + (funcall (if quoted #'file-name-unquote #'identity) penguin) tmp-name2) (should (file-symlink-p tmp-name2)) (should-not (file-regular-p tmp-name2)) (should (string-equal (file-truename tmp-name2) - (tramp-compat-file-name-quote - (concat (file-remote-p tmp-name2) penguin))))) + (file-name-quote (concat (file-remote-p tmp-name2) penguin))))) ;; `tmp-name3' is a local file name. ;; `make-symbolic-link' might not be permitted on w32 systems. (unless (tramp--test-windows-nt-p) @@ -4110,7 +4120,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (should (string-equal (file-truename tmp-name1) - (tramp-compat-file-name-unquote (file-truename tmp-name3)))))) + (file-name-unquote (file-truename tmp-name3)))))) ;; Cleanup. (ignore-errors @@ -4166,6 +4176,10 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (should (file-symlink-p tmp-name1)) (should-not (file-regular-p tmp-name1)) (should-not (file-regular-p tmp-name2)) + (should + (string-equal + (file-truename tmp-name1) + (file-truename tmp-name2))) (if (tramp--test-smb-p) ;; The symlink command of "smbclient" detects the ;; cycle already. @@ -4173,10 +4187,15 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (make-symbolic-link tmp-name1 tmp-name2) :type 'file-error) (make-symbolic-link tmp-name1 tmp-name2) + (should (file-symlink-p tmp-name1)) (should (file-symlink-p tmp-name2)) + (should-not (file-regular-p tmp-name1)) (should-not (file-regular-p tmp-name2)) (should-error (file-truename tmp-name1) + :type 'file-error) + (should-error + (file-truename tmp-name2) :type 'file-error)))) ;; Cleanup. @@ -4188,7 +4207,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (let* ((dir1 (directory-file-name (funcall - (if quoted #'tramp-compat-file-name-quote #'identity) + (if quoted #'file-name-quote #'identity) ert-remote-temporary-file-directory))) (dir2 (file-name-as-directory dir1))) (should (string-equal (file-truename dir1) (expand-file-name dir1))) @@ -4217,12 +4236,12 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (skip-unless (set-file-times tmp-name1 (seconds-to-time 60))) ;; Dumb remote shells without perl(1) or stat(1) are not ;; able to return the date correctly. They say "don't know". - (unless (tramp-compat-time-equal-p + (unless (time-equal-p (file-attribute-modification-time (file-attributes tmp-name1)) tramp-time-dont-know) (should - (tramp-compat-time-equal-p + (time-equal-p (file-attribute-modification-time (file-attributes tmp-name1)) (seconds-to-time 60))) ;; Setting the time for not existing files shall fail. @@ -4241,7 +4260,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (with-no-warnings (set-file-times tmp-name1 (seconds-to-time 60) 'nofollow) (should - (tramp-compat-time-equal-p + (time-equal-p (file-attribute-modification-time (file-attributes tmp-name1)) (seconds-to-time 60))))))) @@ -4287,10 +4306,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (skip-unless (file-acl ert-remote-temporary-file-directory)) (skip-unless (not (tramp--test-crypt-p))) - ;; `filename-non-special' has been fixed in Emacs 27.1, see Bug#29579. - (dolist (quoted - (if (and (tramp--test-expensive-test-p) (tramp--test-emacs27-p)) - '(nil t) '(nil))) + (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil))) (let ((tmp-name1 (tramp--test-make-temp-name nil quoted)) (tmp-name2 (tramp--test-make-temp-name nil quoted)) (tmp-name3 (tramp--test-make-temp-name 'local quoted))) @@ -4367,10 +4383,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." '(nil nil nil nil)))) (skip-unless (not (tramp--test-crypt-p))) - ;; `filename-non-special' has been fixed in Emacs 27.1, see Bug#29579. - (dolist (quoted - (if (and (tramp--test-expensive-test-p) (tramp--test-emacs27-p)) - '(nil t) '(nil))) + (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil))) (let ((tmp-name1 (tramp--test-make-temp-name nil quoted)) (tmp-name2 (tramp--test-make-temp-name nil quoted)) (tmp-name3 (tramp--test-make-temp-name 'local quoted))) @@ -4535,17 +4548,17 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (and (string-match-p tramp-ipv6-regexp host) tramp-postfix-ipv6-format))) ;; Complete method name. - (unless (or (zerop (length method)) - (zerop (length tramp-method-regexp))) + (unless (or (tramp-string-empty-or-nil-p method) + (string-empty-p tramp-method-regexp)) (should (member (concat prefix-format method tramp-postfix-method-format) (file-name-all-completions (concat prefix-format (substring method 0 1)) "/")))) ;; Complete host name. - (unless (or (zerop (length method)) - (zerop (length tramp-method-regexp)) - (zerop (length host)) + (unless (or (tramp-string-empty-or-nil-p method) + (string-empty-p tramp-method-regexp) + (tramp-string-empty-or-nil-p host) (tramp--test-gvfs-p method)) (should (member @@ -4871,13 +4884,14 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." ;; Cleanup. (ignore-errors (delete-process proc))) - ;; Disabled process filter. "sshfs" does not cooperate. - (unless (tramp--test-sshfs-p) + ;; Disabled process filter. It doesn't work reliable. + (unless t (unwind-protect (with-temp-buffer - (setq command '("cat") - proc - (apply #'start-file-process "test4" (current-buffer) command)) + (setq command '("cat") + proc + (apply + #'start-file-process "test4" (current-buffer) command)) (should (processp proc)) (should (equal (process-status proc) 'run)) (should (equal (process-get proc 'remote-command) command)) @@ -4897,12 +4911,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." ;; Process connection type. (when (and (tramp--test-sh-p) (not (tramp-direct-async-process-p)) - ;; `executable-find' has changed the number of - ;; parameters in Emacs 27.1, so we use `apply' for - ;; older Emacsen. - (ignore-errors - (with-no-warnings - (apply #'executable-find '("hexdump" remote))))) + (executable-find "hexdump" 'remote)) (dolist (process-connection-type '(nil pipe t pty)) (unwind-protect (with-temp-buffer @@ -4923,13 +4932,10 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (while (accept-process-output proc 0 nil t)))) (should (string-match-p - (if (and (memq process-connection-type '(nil pipe)) - (not (tramp--test-macos-p))) - ;; On macOS, there is always newline conversion. - ;; "telnet" converts \r to <CR><NUL> if `crlf' - ;; flag is FALSE. See telnet(1) man page. - (rx "66\n6F\n6F\n0D" (? "\n00") "\n0A\n") - (rx "66\n6F\n6F\n0A" (? "\n00") "\n0A\n")) + ;; On macOS, there is always newline conversion. + ;; "telnet" converts \r to <CR><NUL> if `crlf' + ;; flag is FALSE. See telnet(1) man page. + (rx "66\n" "6F\n" "6F\n" (| "0D\n" "0A\n") (? "00\n") "0A\n") (buffer-string)))) ;; Cleanup. @@ -4959,33 +4965,29 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." "Define ert test `TEST-direct-async' for direct async processes. If UNSTABLE is non-nil, the test is tagged as `:unstable'." (declare (indent 1)) - ;; `make-process' supports file name handlers since Emacs 27. We - ;; cannot use `tramp--test-always' during compilation of the macro. - (when (let ((file-name-handler-alist '(("" . (lambda (&rest _) t))))) - (ignore-errors (make-process :file-handler t))) - `(ert-deftest ,(intern (concat (symbol-name test) "-direct-async")) () - ;; This is the docstring. However, it must be expanded to a - ;; string inside the macro. No idea. - ;; (concat (ert-test-documentation (get ',test 'ert--test)) - ;; "\nUse direct async process.") - :tags (append '(:expensive-test :tramp-asynchronous-processes) - (and ,unstable '(:unstable))) - (skip-unless (tramp--test-enabled)) - (let ((default-directory ert-remote-temporary-file-directory) - (ert-test (ert-get-test ',test)) - (tramp-connection-properties - (cons '(nil "direct-async-process" t) - tramp-connection-properties))) - (skip-unless (tramp-direct-async-process-p)) - ;; We do expect an established connection already, - ;; `file-truename' does it by side-effect. Suppress - ;; `tramp--test-enabled', in order to keep the connection. - ;; Suppress "Process ... finished" messages. - (cl-letf (((symbol-function #'tramp--test-enabled) #'tramp--test-always) - ((symbol-function #'internal-default-process-sentinel) - #'ignore)) - (file-truename ert-remote-temporary-file-directory) - (funcall (ert-test-body ert-test))))))) + `(ert-deftest ,(intern (concat (symbol-name test) "-direct-async")) () + ;; This is the docstring. However, it must be expanded to a + ;; string inside the macro. No idea. + ;; (concat (ert-test-documentation (get ',test 'ert--test)) + ;; "\nUse direct async process.") + :tags (append '(:expensive-test :tramp-asynchronous-processes) + (and ,unstable '(:unstable))) + (skip-unless (tramp--test-enabled)) + (let ((default-directory ert-remote-temporary-file-directory) + (ert-test (ert-get-test ',test)) + (tramp-connection-properties + (cons '(nil "direct-async-process" t) + tramp-connection-properties))) + (skip-unless (tramp-direct-async-process-p)) + ;; We do expect an established connection already, + ;; `file-truename' does it by side-effect. Suppress + ;; `tramp--test-enabled', in order to keep the connection. + ;; Suppress "Process ... finished" messages. + (cl-letf (((symbol-function #'tramp--test-enabled) #'tramp--test-always) + ((symbol-function #'internal-default-process-sentinel) + #'ignore)) + (file-truename ert-remote-temporary-file-directory) + (funcall (ert-test-body ert-test)))))) (tramp--test-deftest-direct-async-process tramp-test29-start-file-process) @@ -4996,24 +4998,21 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." '(:unstable))) (skip-unless (tramp--test-enabled)) (skip-unless (tramp--test-supports-processes-p)) - ;; `make-process' supports file name handlers since Emacs 27. - (skip-unless (tramp--test-emacs27-p)) (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil))) (let ((default-directory ert-remote-temporary-file-directory) (tmp-name (tramp--test-make-temp-name nil quoted)) kill-buffer-query-functions command proc) - (with-no-warnings (should-not (make-process))) + (should-not (make-process)) ;; Simple process. (unwind-protect (with-temp-buffer (setq command '("cat") proc - (with-no-warnings - (make-process - :name "test1" :buffer (current-buffer) :command command - :file-handler t))) + (make-process + :name "test1" :buffer (current-buffer) :command command + :file-handler t)) (should (processp proc)) (should (equal (process-status proc) 'run)) (should (equal (process-get proc 'remote-command) command)) @@ -5035,10 +5034,9 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." (should (file-exists-p tmp-name)) (setq command `("cat" ,(file-name-nondirectory tmp-name)) proc - (with-no-warnings - (make-process - :name "test2" :buffer (current-buffer) :command command - :file-handler t))) + (make-process + :name "test2" :buffer (current-buffer) :command command + :file-handler t)) (should (processp proc)) (should (equal (process-get proc 'remote-command) command)) ;; Read output. @@ -5057,13 +5055,12 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." (with-temp-buffer (setq command '("cat") proc - (with-no-warnings - (make-process - :name "test3" :buffer (current-buffer) :command command - :filter - (lambda (p s) - (with-current-buffer (process-buffer p) (insert s))) - :file-handler t))) + (make-process + :name "test3" :buffer (current-buffer) :command command + :filter + (lambda (p s) + (with-current-buffer (process-buffer p) (insert s))) + :file-handler t)) (should (processp proc)) (should (equal (process-status proc) 'run)) (should (equal (process-get proc 'remote-command) command)) @@ -5078,17 +5075,15 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." ;; Cleanup. (ignore-errors (delete-process proc))) - ;; Disabled process filter. "sshfs" does not cooperate. - (unless (tramp--test-sshfs-p) + ;; Disabled process filter. It doesn't work reliable. + (unless t (unwind-protect (with-temp-buffer (setq command '("cat") proc - (with-no-warnings - (make-process - :name "test4" :buffer (current-buffer) :command command - :filter t - :file-handler t))) + (make-process + :name "test4" :buffer (current-buffer) :command command + :filter t :file-handler t)) (should (processp proc)) (should (equal (process-status proc) 'run)) (should (equal (process-get proc 'remote-command) command)) @@ -5109,13 +5104,12 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." (with-temp-buffer (setq command '("cat") proc - (with-no-warnings - (make-process - :name "test5" :buffer (current-buffer) :command command - :sentinel - (lambda (p s) - (with-current-buffer (process-buffer p) (insert s))) - :file-handler t))) + (make-process + :name "test5" :buffer (current-buffer) :command command + :sentinel + (lambda (p s) + (with-current-buffer (process-buffer p) (insert s))) + :file-handler t)) (should (processp proc)) (should (equal (process-status proc) 'run)) (should (equal (process-get proc 'remote-command) command)) @@ -5141,11 +5135,9 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." (with-temp-buffer (setq command '("cat" "/does-not-exist") proc - (with-no-warnings - (make-process - :name "test6" :buffer (current-buffer) :command command - :stderr stderr - :file-handler t))) + (make-process + :name "test6" :buffer (current-buffer) :command command + :stderr stderr :file-handler t)) (should (processp proc)) (should (equal (process-get proc 'remote-command) command)) ;; Read output. @@ -5174,11 +5166,9 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." (with-temp-buffer (setq command '("cat" "/does-not-exist") proc - (with-no-warnings - (make-process - :name "test7" :buffer (current-buffer) :command command - :stderr tmp-name - :file-handler t))) + (make-process + :name "test7" :buffer (current-buffer) :command command + :stderr tmp-name :file-handler t)) (should (processp proc)) (should (equal (process-get proc 'remote-command) command)) ;; Read stderr. @@ -5199,12 +5189,7 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." ;; Process connection type. (when (and (tramp--test-sh-p) (not (tramp-direct-async-process-p)) - ;; `executable-find' has changed the number of - ;; parameters in Emacs 27.1, so we use `apply' for - ;; older Emacsen. - (ignore-errors - (with-no-warnings - (apply #'executable-find '("hexdump" remote))))) + (executable-find "hexdump" 'remote)) (dolist (connection-type '(nil pipe t pty)) ;; `process-connection-type' is taken when ;; `:connection-type' is nil. @@ -5214,15 +5199,14 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." (with-temp-buffer (setq command '("hexdump" "-v" "-e" "/1 \"%02X\n\"") proc - (with-no-warnings - (make-process - :name - (format "test8-%s-%s" - connection-type process-connection-type) - :buffer (current-buffer) - :connection-type connection-type - :command command - :file-handler t))) + (make-process + :name + (format "test8-%s-%s" + connection-type process-connection-type) + :buffer (current-buffer) + :connection-type connection-type + :command command + :file-handler t)) (should (processp proc)) (should (equal (process-status proc) 'run)) (should (equal (process-get proc 'remote-command) command)) @@ -5235,14 +5219,10 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." (while (accept-process-output proc 0 nil t)))) (should (string-match-p - (if (and (memq (or connection-type process-connection-type) - '(nil pipe)) - (not (tramp--test-macos-p))) - ;; On macOS, there is always newline conversion. - ;; "telnet" converts \r to <CR><NUL> if `crlf' - ;; flag is FALSE. See telnet(1) man page. - (rx "66\n6F\n6F\n0D" (? "\n00") "\n0A\n") - (rx "66\n6F\n6F\n0A" (? "\n00") "\n0A\n")) + ;; On macOS, there is always newline conversion. + ;; "telnet" converts \r to <CR><NUL> if `crlf' + ;; flag is FALSE. See telnet(1) man page. + (rx "66\n" "6F\n" "6F\n" (| "0D\n" "0A\n") (? "00\n") "0A\n") (buffer-string)))) ;; Cleanup. @@ -5258,8 +5238,6 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." (skip-unless (tramp--test-sh-p)) (skip-unless (not (tramp--test-windows-nt-p))) (skip-unless (not (tramp--test-crypt-p))) - ;; Since Emacs 27.1. - (skip-unless (macrop 'with-connection-local-variables)) ;; We must use `file-truename' for the temporary directory, in ;; order to establish the connection prior running an asynchronous @@ -5301,8 +5279,6 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." (skip-unless (tramp--test-sh-p)) (skip-unless (not (tramp--test-windows-nt-p))) (skip-unless (not (tramp--test-crypt-p))) - ;; Since Emacs 27.1. - (skip-unless (macrop 'with-connection-local-variables)) ;; Since Emacs 29.1. (skip-unless (boundp 'signal-process-functions)) @@ -5419,7 +5395,7 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." (when-let ((default-directory ert-remote-temporary-file-directory) (mi (memory-info))) (should (consp mi)) - (should (= (length mi) 4)) + (should (tramp-compat-length= mi 4)) (dotimes (i (length mi)) (should (natnump (nth i mi)))))) @@ -5429,11 +5405,9 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." INPUT, if non-nil, is a string sent to the process." (let ((proc (async-shell-command command output-buffer error-buffer)) (delete-exited-processes t)) - ;; Since Emacs 27.1. - (when (macrop 'with-connection-local-variables) - (should (equal (process-get proc 'remote-command) - (with-connection-local-variables - `(,shell-file-name ,shell-command-switch ,command))))) + (should (equal (process-get proc 'remote-command) + (with-connection-local-variables + `(,shell-file-name ,shell-command-switch ,command)))) (cl-letf (((symbol-function #'shell-command-sentinel) #'ignore)) (when (stringp input) (process-send-string proc input)) @@ -5454,10 +5428,6 @@ INPUT, if non-nil, is a string sent to the process." :tags '(:expensive-test) (skip-unless (tramp--test-enabled)) (skip-unless (tramp--test-supports-processes-p)) - ;; Prior Emacs 27, `shell-file-name' was hard coded as "/bin/sh" for - ;; remote processes in Emacs. That doesn't work for tramp-adb.el. - (when (tramp--test-adb-p) - (skip-unless (tramp--test-emacs27-p))) (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil))) (let ((tmp-name (tramp--test-make-temp-name nil quoted)) @@ -5525,7 +5495,7 @@ INPUT, if non-nil, is a string sent to the process." (should (string-match-p ;; Some shells echo, for example the "adb" or container methods. - (tramp-compat-rx + (rx bos (** 1 2 (literal (file-name-nondirectory tmp-name)) "\n") eos) (buffer-string)))) @@ -5533,10 +5503,8 @@ INPUT, if non-nil, is a string sent to the process." ;; Cleanup. (ignore-errors (delete-file tmp-name)))))) - ;; Test `async-shell-command-width'. It exists since Emacs 26.1, - ;; but seems to work since Emacs 27.1 only. - (when (and (tramp--test-asynchronous-processes-p) - (tramp--test-sh-p) (tramp--test-emacs27-p)) + ;; Test `async-shell-command-width'. + (when (and (tramp--test-asynchronous-processes-p) (tramp--test-sh-p)) (let* ((async-shell-command-width 1024) (default-directory ert-remote-temporary-file-directory) (cols (ignore-errors @@ -5556,8 +5524,6 @@ INPUT, if non-nil, is a string sent to the process." (skip-unless (tramp--test-enabled)) (skip-unless nil) (skip-unless (tramp--test-supports-processes-p)) - ;; Prior Emacs 27, `shell-command-dont-erase-buffer' wasn't working properly. - (skip-unless (tramp--test-emacs27-p)) ;; (message " s-c-d-e-b current-buffer buffer-string point") ;; (message "===============================================") @@ -5732,8 +5698,7 @@ INPUT, if non-nil, is a string sent to the process." ;; Variable is set. (should (string-match-p - (tramp-compat-rx (literal envvar)) - (funcall this-shell-command-to-string "set")))) + (rx (literal envvar)) (funcall this-shell-command-to-string "set")))) (unless (tramp-direct-async-process-p) ;; We force a reconnect, in order to have a clean environment. @@ -5759,7 +5724,7 @@ INPUT, if non-nil, is a string sent to the process." ;; Variable is unset. (should-not (string-match-p - (tramp-compat-rx (literal envvar)) + (rx (literal envvar)) ;; We must remove PS1, the output is truncated otherwise. ;; We must suppress "_=VAR...". (funcall @@ -5804,13 +5769,10 @@ INPUT, if non-nil, is a string sent to the process." (dolist (dir '("/mock:localhost#11111:" "/mock:localhost#22222:")) (tramp-cleanup-connection (tramp-dissect-file-name dir))))) -;; Connection-local variables are enabled per default since Emacs 27.1. (ert-deftest tramp-test34-connection-local-variables () "Check that connection-local variables are enabled." :tags '(:expensive-test) (skip-unless (tramp--test-enabled)) - ;; Since Emacs 27.1. - (skip-unless (macrop 'with-connection-local-variables)) (let* ((default-directory ert-remote-temporary-file-directory) (tmp-name1 (tramp--test-make-temp-name)) @@ -5874,19 +5836,12 @@ INPUT, if non-nil, is a string sent to the process." :tags '(:expensive-test :tramp-asynchronous-processes) (skip-unless (tramp--test-enabled)) (skip-unless (tramp--test-supports-processes-p)) - ;; Prior Emacs 27, `shell-file-name' was hard coded as "/bin/sh" for - ;; remote processes in Emacs. That doesn't work for tramp-adb.el. - (when (tramp--test-adb-p) - (skip-unless (tramp--test-emacs27-p))) (let ((default-directory ert-remote-temporary-file-directory) explicit-shell-file-name kill-buffer-query-functions connection-local-profile-alist connection-local-criteria-alist) (unwind-protect (progn - ;; `shell-mode' would ruin our test, because it deletes all - ;; buffer local variables. Not needed in Emacs 27.1. - (put 'explicit-shell-file-name 'permanent-local t) (connection-local-set-profile-variables 'remote-sh `((explicit-shell-file-name . ,(tramp--test-shell-file-name)) @@ -5917,29 +5872,24 @@ INPUT, if non-nil, is a string sent to the process." (put 'explicit-shell-file-name 'permanent-local nil) (kill-buffer "*shell*")))) -;; `exec-path' was introduced in Emacs 27.1. `executable-find' has -;; changed the number of parameters, so we use `apply' for older -;; Emacsen. (ert-deftest tramp-test35-exec-path () "Check `exec-path' and `executable-find'." (skip-unless (tramp--test-enabled)) (skip-unless (tramp--test-supports-processes-p)) (skip-unless (tramp--test-supports-set-file-modes-p)) - ;; Since Emacs 27.1. - (skip-unless (fboundp 'exec-path)) (let ((tmp-name (tramp--test-make-temp-name)) (default-directory ert-remote-temporary-file-directory)) (unwind-protect (progn - (should (consp (with-no-warnings (exec-path)))) + (should (consp (exec-path))) ;; Last element is the `exec-directory'. (should (string-equal - (car (last (with-no-warnings (exec-path)))) + (car (last (exec-path))) (file-remote-p default-directory 'localname))) ;; The shell "sh" shall always exist. - (should (apply #'executable-find '("sh" remote))) + (should (executable-find "sh" 'remote)) ;; Since the last element in `exec-path' is the current ;; directory, an executable file in that directory will be ;; found. @@ -5950,32 +5900,25 @@ INPUT, if non-nil, is a string sent to the process." (should (file-executable-p tmp-name)) (should (string-equal - (apply - #'executable-find `(,(file-name-nondirectory tmp-name) remote)) + (executable-find (file-name-nondirectory tmp-name) 'remote) (file-remote-p tmp-name 'localname))) (should-not - (apply - #'executable-find - `(,(concat (file-name-nondirectory tmp-name) "foo") remote)))) + (executable-find + (concat (file-name-nondirectory tmp-name) "foo") 'remote))) ;; Cleanup. (ignore-errors (delete-file tmp-name))))) ;; This test is inspired by Bug#33781. -;; `exec-path' was introduced in Emacs 27.1. `executable-find' has -;; changed the number of parameters, so we use `apply' for older -;; Emacsen. (ert-deftest tramp-test35-remote-path () "Check loooong `tramp-remote-path'." (skip-unless (tramp--test-enabled)) (skip-unless (tramp--test-sh-p)) (skip-unless (not (tramp--test-crypt-p))) - ;; Since Emacs 27.1. - (skip-unless (fboundp 'exec-path)) (let* ((tmp-name (tramp--test-make-temp-name)) (default-directory ert-remote-temporary-file-directory) - (orig-exec-path (with-no-warnings (exec-path))) + (orig-exec-path (exec-path)) (tramp-remote-path tramp-remote-path) (orig-tramp-remote-path tramp-remote-path) path) @@ -5985,20 +5928,20 @@ INPUT, if non-nil, is a string sent to the process." (setq tramp-remote-path (cons (file-remote-p tmp-name 'localname) tramp-remote-path)) (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password) - (should (equal (with-no-warnings (exec-path)) orig-exec-path)) + (should (equal (exec-path) orig-exec-path)) (setq tramp-remote-path orig-tramp-remote-path) ;; Double entries are removed. (setq tramp-remote-path (append '("/" "/") tramp-remote-path)) (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password) - (should - (equal (with-no-warnings (exec-path)) (cons "/" orig-exec-path))) + (should (equal (exec-path) (cons "/" orig-exec-path))) (setq tramp-remote-path orig-tramp-remote-path) ;; We make a super long `tramp-remote-path'. (make-directory tmp-name) (should (file-directory-p tmp-name)) - (while (< (length (mapconcat #'identity orig-exec-path ":")) 5000) + (while (tramp-compat-length< + (mapconcat #'identity orig-exec-path ":") 5000) (let ((dir (make-temp-file (file-name-as-directory tmp-name) 'dir))) (should (file-directory-p dir)) (setq tramp-remote-path @@ -6010,19 +5953,20 @@ INPUT, if non-nil, is a string sent to the process." `(,(file-remote-p dir 'localname)) (last orig-exec-path))))) (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password) - (should (equal (with-no-warnings (exec-path)) orig-exec-path)) + (should (equal (exec-path) orig-exec-path)) ;; Ignore trailing newline. (setq path (substring (shell-command-to-string "echo $PATH") nil -1)) ;; The shell doesn't handle such long strings. - (when (<= (length path) - (tramp-get-connection-property - tramp-test-vec "pipe-buf" 4096)) + (unless (tramp-compat-length> + path + (tramp-get-connection-property + tramp-test-vec "pipe-buf" 4096)) ;; The last element of `exec-path' is `exec-directory'. (should (string-equal path (mapconcat #'identity (butlast orig-exec-path) ":")))) ;; The shell "sh" shall always exist. - (should (apply #'executable-find '("sh" remote)))) + (should (executable-find "sh" 'remote))) ;; Cleanup. (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password) @@ -6142,7 +6086,7 @@ INPUT, if non-nil, is a string sent to the process." (string-equal (make-auto-save-file-name) (funcall - (if quoted #'tramp-compat-file-name-quote #'identity) + (if quoted #'file-name-quote #'identity) (expand-file-name (format "#%s#" (file-name-nondirectory tmp-name1)) ert-remote-temporary-file-directory)))))) @@ -6167,7 +6111,7 @@ INPUT, if non-nil, is a string sent to the process." ("|" . "__") ("[" . "_l") ("]" . "_r")) - (tramp-compat-file-name-unquote tmp-name1))) + (file-name-unquote tmp-name1))) tmp-name2))) (should (file-directory-p tmp-name2))))) @@ -6191,7 +6135,7 @@ INPUT, if non-nil, is a string sent to the process." ("|" . "__") ("[" . "_l") ("]" . "_r")) - (tramp-compat-file-name-unquote tmp-name1))) + (file-name-unquote tmp-name1))) tmp-name2))) (should (file-directory-p tmp-name2))))) @@ -6247,7 +6191,7 @@ INPUT, if non-nil, is a string sent to the process." (find-backup-file-name tmp-name1) (list (funcall - (if quoted #'tramp-compat-file-name-quote #'identity) + (if quoted #'file-name-quote #'identity) (expand-file-name (format "%s~" (file-name-nondirectory tmp-name1)) ert-remote-temporary-file-directory))))))) @@ -6261,7 +6205,7 @@ INPUT, if non-nil, is a string sent to the process." (find-backup-file-name tmp-name1) (list (funcall - (if quoted #'tramp-compat-file-name-quote #'identity) + (if quoted #'file-name-quote #'identity) (expand-file-name (format "%s~" @@ -6290,7 +6234,7 @@ INPUT, if non-nil, is a string sent to the process." (find-backup-file-name tmp-name1) (list (funcall - (if quoted #'tramp-compat-file-name-quote #'identity) + (if quoted #'file-name-quote #'identity) (expand-file-name (format "%s~" @@ -6321,7 +6265,7 @@ INPUT, if non-nil, is a string sent to the process." (find-backup-file-name tmp-name1) (list (funcall - (if quoted #'tramp-compat-file-name-quote #'identity) + (if quoted #'file-name-quote #'identity) (expand-file-name (format "%s~" @@ -6378,7 +6322,7 @@ INPUT, if non-nil, is a string sent to the process." (skip-unless (and (fboundp 'file-locked-p) (fboundp 'make-lock-file-name))) ;; `lock-file', `unlock-file', `file-locked-p' and - ;; `make-lock-file-name' exists since Emacs 28.1. We don't want to + ;; `make-lock-file-name' exist since Emacs 28.1. We don't want to ;; see compiler warnings for older Emacsen. (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil))) (let ((tmp-name1 (tramp--test-make-temp-name nil quoted)) @@ -6579,7 +6523,6 @@ INPUT, if non-nil, is a string sent to the process." (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password))))))) -;; The functions were introduced in Emacs 26.1. (ert-deftest tramp-test40-make-nearby-temp-file () "Check `make-nearby-temp-file' and `temporary-file-directory'." (skip-unless (tramp--test-enabled)) @@ -6611,12 +6554,6 @@ INPUT, if non-nil, is a string sent to the process." (delete-directory tmp-file) (should-not (file-exists-p tmp-file)))) -(defun tramp--test-emacs27-p () - "Check for Emacs version >= 27.1. -Some semantics has been changed for there, without new functions -or variables, so we check the Emacs version directly." - (>= emacs-major-version 27)) - (defun tramp--test-emacs28-p () "Check for Emacs version >= 28.1. Some semantics has been changed for there, without new functions @@ -6651,7 +6588,7 @@ This is used in tests which we don't want to tag :body nil :tags '(:tramp-asynchronous-processes)))) ;; tramp-adb.el cannot apply multi-byte commands. (not (and (tramp--test-adb-p) - (string-match-p (tramp-compat-rx multibyte) default-directory))))) + (string-match-p (rx multibyte) default-directory))))) (defun tramp--test-crypt-p () "Check, whether the remote directory is encrypted." @@ -6816,10 +6753,7 @@ This requires restrictions of file name syntax." (defun tramp--test-check-files (&rest files) "Run a simple but comprehensive test over every file in FILES." - ;; `filename-non-special' has been fixed in Emacs 27.1, see Bug#29579. - (dolist (quoted - (if (and (tramp--test-expensive-test-p) (tramp--test-emacs27-p)) - '(nil t) '(nil))) + (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil))) ;; We must use `file-truename' for the temporary directory, ;; because it could be located on a symlinked directory. This ;; would let the test fail. @@ -6869,7 +6803,7 @@ This requires restrictions of file name syntax." (should (string-equal (funcall - (if quoted #'tramp-compat-file-name-quote #'identity) + (if quoted #'file-name-quote #'identity) (file-attribute-type (file-attributes file3))) (file-remote-p (file-truename file1) 'localname))) ;; Check file contents. @@ -6960,14 +6894,14 @@ This requires restrictions of file name syntax." (should (string-equal (caar (directory-files-and-attributes - file1 nil (tramp-compat-rx (literal elt1)))) + file1 nil (rx (literal elt1)))) elt1)) (should (string-equal (funcall - (if quoted #'tramp-compat-file-name-quote #'identity) + (if quoted #'file-name-quote #'identity) (cadr (car (directory-files-and-attributes - file1 nil (tramp-compat-rx (literal elt1)))))) + file1 nil (rx (literal elt1)))))) (file-remote-p (file-truename file2) 'localname))) (delete-file file3) (should-not (file-exists-p file3)))) @@ -6976,15 +6910,7 @@ This requires restrictions of file name syntax." ;; `default-directory' with special characters. See ;; Bug#53846. (when (and (tramp--test-expensive-test-p) - (tramp--test-supports-processes-p) - ;; Prior Emacs 27, `shell-file-name' was - ;; hard coded as "/bin/sh" for remote - ;; processes in Emacs. That doesn't work - ;; for tramp-adb.el. tramp-sshfs.el times - ;; out for older Emacsen, reason unknown. - (or (and (not (tramp--test-adb-p)) - (not (tramp--test-sshfs-p))) - (tramp--test-emacs27-p))) + (tramp--test-supports-processes-p)) (let ((default-directory file1)) (dolist (this-shell-command (append @@ -7022,7 +6948,7 @@ This requires restrictions of file name syntax." (goto-char (point-min)) (should (re-search-forward - (tramp-compat-rx + (rx bol (literal envvar) "=" (literal (getenv envvar)) eol)))))))) @@ -7142,6 +7068,9 @@ This requires restrictions of file name syntax." ;; Use all available language specific snippets. (lambda (x) (and + ;; The "Oriya" and "Odia" languages use some problematic + ;; composition characters. + (not (member (car x) '("Oriya" "Odia"))) (stringp (setq x (eval (get-language-info (car x) 'sample-text) t))) ;; Filter out strings which use unencodable characters. (not (and (or (tramp--test-gvfs-p) (tramp--test-smb-p)) @@ -7168,23 +7097,47 @@ This requires restrictions of file name syntax." (ert-deftest tramp-test43-file-system-info () "Check that `file-system-info' returns proper values." (skip-unless (tramp--test-enabled)) - ;; Since Emacs 27.1. - (skip-unless (fboundp 'file-system-info)) - ;; `file-system-info' exists since Emacs 27.1. We don't want to see - ;; compiler warnings for older Emacsen. - (when-let ((fsi (with-no-warnings - (file-system-info ert-remote-temporary-file-directory)))) + (when-let ((fsi (file-system-info ert-remote-temporary-file-directory))) (should (consp fsi)) - (should (= (length fsi) 3)) + (should (tramp-compat-length= fsi 3)) (dotimes (i (length fsi)) (should (natnump (or (nth i fsi) 0)))))) -;; `tramp-test44-asynchronous-requests' could be blocked. So we set a +;; `file-user-uid' was introduced in Emacs 30.1. +(ert-deftest tramp-test44-file-user-uid () + "Check that `file-user-uid' and `tramp-get-remote-*' return proper values." + (skip-unless (tramp--test-enabled)) + + (let ((default-directory ert-remote-temporary-file-directory)) + ;; `file-user-uid' exists since Emacs 30.1. We don't want to see + ;; compiler warnings for older Emacsen. + (when (fboundp 'file-user-uid) + (should (integerp (with-no-warnings (file-user-uid))))) + + (with-parsed-tramp-file-name default-directory nil + (should (or (integerp (tramp-get-remote-uid v 'integer)) + (null (tramp-get-remote-uid v 'integer)))) + (should (or (stringp (tramp-get-remote-uid v 'string)) + (null (tramp-get-remote-uid v 'string)))) + + (should (or (integerp (tramp-get-remote-gid v 'integer)) + (null (tramp-get-remote-gid v 'integer)))) + (should (or (stringp (tramp-get-remote-gid v 'string)) + (null (tramp-get-remote-gid v 'string)))) + + (when-let ((groups (tramp-get-remote-groups v 'integer))) + (should (consp groups)) + (dolist (group groups) (should (integerp group)))) + (when-let ((groups (tramp-get-remote-groups v 'string))) + (should (consp groups)) + (dolist (group groups) (should (stringp group))))))) + +;; `tramp-test45-asynchronous-requests' could be blocked. So we set a ;; timeout of 300 seconds, and we send a SIGUSR1 signal after 300 ;; seconds. Similar check is performed in the timer function. (defconst tramp--test-asynchronous-requests-timeout 300 - "Timeout for `tramp-test44-asynchronous-requests'.") + "Timeout for `tramp-test45-asynchronous-requests'.") (defmacro tramp--test-with-proper-process-name-and-buffer (proc &rest body) "Set \"process-name\" and \"process-buffer\" connection properties. @@ -7220,7 +7173,7 @@ This is needed in timer functions as well as process filters and sentinels." (tramp-flush-connection-property v "process-buffer"))))) ;; This test is inspired by Bug#16928. -(ert-deftest tramp-test44-asynchronous-requests () +(ert-deftest tramp-test45-asynchronous-requests () "Check parallel asynchronous requests. Such requests could arrive from timers, process filters and process sentinels. They shall not disturb each other." @@ -7230,10 +7183,6 @@ process sentinels. They shall not disturb each other." '(:unstable))) (skip-unless (tramp--test-enabled)) (skip-unless (tramp--test-supports-processes-p)) - ;; Prior Emacs 27, `shell-file-name' was hard coded as "/bin/sh" for - ;; remote processes in Emacs. That doesn't work for tramp-adb.el. - (when (tramp--test-adb-p) - (skip-unless (tramp--test-emacs27-p))) (skip-unless (not (tramp--test-container-p))) (skip-unless (not (tramp--test-telnet-p))) (skip-unless (not (tramp--test-sshfs-p))) @@ -7391,7 +7340,7 @@ process sentinels. They shall not disturb each other." (unless (process-live-p proc) (setq buffers (delq buf buffers)))))) - ;; Checks. All process output shall exists in the + ;; Checks. All process output shall exist in the ;; respective buffers. All created files shall be ;; deleted. (tramp--test-message "Check %s" (current-time-string)) @@ -7417,10 +7366,10 @@ process sentinels. They shall not disturb each other." (ignore-errors (cancel-timer timer)) (ignore-errors (delete-directory tmp-name 'recursive)))))) -;; (tramp--test-deftest-direct-async-process tramp-test44-asynchronous-requests +;; (tramp--test-deftest-direct-async-process tramp-test45-asynchronous-requests ;; 'unstable) -(ert-deftest tramp-test45-dired-compress-file () +(ert-deftest tramp-test46-dired-compress-file () "Check that Tramp (un)compresses normal files." (skip-unless (tramp--test-enabled)) (skip-unless (tramp--test-sh-p)) @@ -7441,7 +7390,7 @@ process sentinels. They shall not disturb each other." (should (string= tmp-name (dired-get-filename))) (delete-file tmp-name))) -(ert-deftest tramp-test45-dired-compress-dir () +(ert-deftest tramp-test46-dired-compress-dir () "Check that Tramp (un)compresses directories." (skip-unless (tramp--test-enabled)) (skip-unless (tramp--test-sh-p)) @@ -7463,7 +7412,7 @@ process sentinels. They shall not disturb each other." (delete-directory tmp-name) (delete-file (concat tmp-name ".tar.gz")))) -(ert-deftest tramp-test46-read-password () +(ert-deftest tramp-test47-read-password () "Check Tramp password handling." :tags '(:expensive-test) (skip-unless (tramp--test-enabled)) @@ -7523,7 +7472,7 @@ process sentinels. They shall not disturb each other." (should (file-exists-p ert-remote-temporary-file-directory))))))))) ;; This test is inspired by Bug#29163. -(ert-deftest tramp-test47-auto-load () +(ert-deftest tramp-test48-auto-load () "Check that Tramp autoloads properly." ;; If we use another syntax but `default', Tramp is already loaded ;; due to the `tramp-change-syntax' call. @@ -7539,7 +7488,7 @@ process sentinels. They shall not disturb each other." ert-remote-temporary-file-directory))) (should (string-match-p - (rx "Tramp loaded: t" (+ (any "\n\r"))) + (rx "Tramp loaded: t" (+ (any "\r\n"))) (shell-command-to-string (format "%s -batch -Q -L %s --eval %s" @@ -7548,7 +7497,7 @@ process sentinels. They shall not disturb each other." (mapconcat #'shell-quote-argument load-path " -L ") (shell-quote-argument code))))))) -(ert-deftest tramp-test47-delay-load () +(ert-deftest tramp-test48-delay-load () "Check that Tramp is loaded lazily, only when needed." ;; Tramp is neither loaded at Emacs startup, nor when completing a ;; non-Tramp file name like "/foo". Completing a Tramp-alike file @@ -7566,10 +7515,10 @@ process sentinels. They shall not disturb each other." (dolist (tm '(t nil)) (should (string-match-p - (tramp-compat-rx - "Tramp loaded: nil" (+ (any "\n\r")) - "Tramp loaded: nil" (+ (any "\n\r")) - "Tramp loaded: " (literal (symbol-name tm)) (+ (any "\n\r"))) + (rx + "Tramp loaded: nil" (+ (any "\r\n")) + "Tramp loaded: nil" (+ (any "\r\n")) + "Tramp loaded: " (literal (symbol-name tm)) (+ (any "\r\n"))) (shell-command-to-string (format "%s -batch -Q -L %s --eval %s" @@ -7578,7 +7527,7 @@ process sentinels. They shall not disturb each other." (mapconcat #'shell-quote-argument load-path " -L ") (shell-quote-argument (format code tm))))))))) -(ert-deftest tramp-test47-recursive-load () +(ert-deftest tramp-test48-recursive-load () "Check that Tramp does not fail due to recursive load." (skip-unless (tramp--test-enabled)) @@ -7602,7 +7551,7 @@ process sentinels. They shall not disturb each other." (mapconcat #'shell-quote-argument load-path " -L ") (shell-quote-argument code)))))))) -(ert-deftest tramp-test47-remote-load-path () +(ert-deftest tramp-test48-remote-load-path () "Check that Tramp autoloads its packages with remote `load-path'." ;; `tramp-cleanup-all-connections' is autoloaded from tramp-cmds.el. ;; It shall still work, when a remote file name is in the @@ -7614,7 +7563,7 @@ process sentinels. They shall not disturb each other." (tramp-cleanup-all-connections))")) (should (string-match-p - (tramp-compat-rx + (rx "Loading " (literal (expand-file-name @@ -7627,7 +7576,7 @@ process sentinels. They shall not disturb each other." (mapconcat #'shell-quote-argument load-path " -L ") (shell-quote-argument code))))))) -(ert-deftest tramp-test48-unload () +(ert-deftest tramp-test49-unload () "Check that Tramp and its subpackages unload completely. Since it unloads Tramp, it shall be the last test to run." :tags '(:expensive-test) @@ -7665,6 +7614,8 @@ Since it unloads Tramp, it shall be the last test to run." ;; `tramp-register-archive-file-name-handler' is autoloaded ;; in Emacs < 29.1. (not (eq 'tramp-register-archive-file-name-handler x)) + ;; `tramp-compat-rx' is autoloaded in Emacs 29.1. + (not (eq 'tramp-compat-rx x)) (not (string-match-p (rx bol "tramp" (? "-archive") (** 1 2 "-") "test") (symbol-name x))) @@ -7726,19 +7677,19 @@ If INTERACTIVE is non-nil, the tests are run interactively." ;; * file-name-case-insensitive-p ;; * memory-info ;; * tramp-get-home-directory -;; * tramp-get-remote-gid -;; * tramp-get-remote-groups -;; * tramp-get-remote-uid ;; * tramp-set-file-uid-gid ;; * Work on skipped tests. Make a comment, when it is impossible. ;; * Revisit expensive tests, once problems in `tramp-error' are solved. ;; * Fix `tramp-test06-directory-file-name' for "ftp". +;; * Check, why a process filter t doesn't work in +;; `tramp-test29-start-file-process' and +;; `tramp-test30-make-process'. ;; * Implement `tramp-test31-interrupt-process' and ;; `tramp-test31-signal-process' for "adb", "sshfs" and for direct ;; async processes. Check, why they don't run stable. ;; * Check, why direct async processes do not work for -;; `tramp-test44-asynchronous-requests'. +;; `tramp-test45-asynchronous-requests'. (provide 'tramp-tests) diff --git a/test/lisp/proced-tests.el b/test/lisp/proced-tests.el new file mode 100644 index 00000000000..1f475665298 --- /dev/null +++ b/test/lisp/proced-tests.el @@ -0,0 +1,122 @@ +;;; proced-tests.el --- Test suite for proced.el -*- lexical-binding: t -*- + +;; Copyright (C) 2022 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Code: +(require 'ert) +(require 'proced) +(require 'thingatpt) + +(cl-defmacro proced--within-buffer (format filter &body body) + "Execute BODY within a proced buffer using format FORMAT and filter FILTER." + `(let ((proced-format ,format) + (proced-filter ,filter) + (proced-auto-update-flag nil) + (inhibit-message t)) + (proced) + (unwind-protect + (with-current-buffer "*Proced*" + ,@body) + (kill-buffer "*Proced*")))) + +(defun proced--assert-emacs-pid-in-buffer () + "Fail unless the process ID of the current Emacs process exists in buffer." + (should (string-match-p + (number-to-string (emacs-pid)) + (buffer-substring-no-properties (point-min) (point-max))))) + +(defun proced--move-to-column (attribute) + "Move to the column under ATTRIBUTE in the current proced buffer." + (move-to-column (string-match attribute proced-header-line))) + +(ert-deftest proced-format-test () + (dolist (format '(short medium long verbose)) + (proced--within-buffer + format + 'user + (proced--assert-emacs-pid-in-buffer)))) + +(ert-deftest proced-update-test () + (proced--within-buffer + 'short + 'user + (proced-update) + (proced--assert-emacs-pid-in-buffer))) + +(ert-deftest proced-revert-test () + (proced--within-buffer + 'short + 'user + (proced-revert) + (proced--assert-emacs-pid-in-buffer))) + +(ert-deftest proced-color-test () + (let ((proced-enable-color-flag t)) + (proced--within-buffer + 'short + 'user + (proced--assert-emacs-pid-in-buffer)))) + +(ert-deftest proced-refine-test () + ;;(skip-unless (memq system-type '(gnu/linux gnu/kfreebsd darwin))) + (proced--within-buffer + 'medium + 'user + ;; When refining on PID for process A, a process is kept if and only + ;; if its PID are the same as process A, which more or less guarentees + ;; the refinement will remove some processes. + (proced--move-to-column "PID") + (let ((pid (word-at-point))) + (proced-refine) + (while (not (eobp)) + (proced--move-to-column "PID") + (should (string= pid (word-at-point))) + (forward-line))))) + +(ert-deftest proced-refine-with-update-test () + (proced--within-buffer + 'medium + 'user + (proced--move-to-column "PID") + (let ((pid (word-at-point))) + (proced-refine) + (proced-update t) + (while (not (eobp)) + (proced--move-to-column "PID") + (should (string= pid (word-at-point))) + (forward-line))))) + +(ert-deftest proced-update-preserves-pid-at-point-test () + (proced--within-buffer + 'medium + 'user + (goto-char (point-min)) + (search-forward (number-to-string (emacs-pid))) + (proced--move-to-column "PID") + (save-window-excursion + (let ((pid (proced-pid-at-point)) + (new-window (split-window)) + (old-window (get-buffer-window))) + (select-window new-window) + (with-current-buffer "*Proced*" + (proced-update t t)) + (select-window old-window) + (should (= pid (proced-pid-at-point))))))) + +(provide 'proced-tests) +;;; proced-tests.el ends here diff --git a/test/lisp/progmodes/java-ts-mode-resources/indent.erts b/test/lisp/progmodes/java-ts-mode-resources/indent.erts new file mode 100644 index 00000000000..e59d5fed8e8 --- /dev/null +++ b/test/lisp/progmodes/java-ts-mode-resources/indent.erts @@ -0,0 +1,44 @@ +Code: + (lambda () + (setq indent-tabs-mode nil) + (setq java-ts-mode-indent-offset 2) + (java-ts-mode) + (indent-region (point-min) (point-max))) + +Point-Char: | + +Name: Basic + +=-= +public class Basic { + public void basic() { + return; + } +} +=-=-= + +Name: Empty Line + +=-= +public class EmptyLine { + public void emptyLine() { + | + } +} +=-=-= + +Name: Statements + +=-= +if (x) { + for (var foo : foos) { + | + } +} else if (y) { + for (int i = 0; x < foos.size(); i++) { + return; + } +} else { + return; +} +=-=-= diff --git a/test/lisp/progmodes/java-ts-mode-resources/movement.erts b/test/lisp/progmodes/java-ts-mode-resources/movement.erts new file mode 100644 index 00000000000..23639b1f5ff --- /dev/null +++ b/test/lisp/progmodes/java-ts-mode-resources/movement.erts @@ -0,0 +1,154 @@ +Code: + (lambda () + (java-ts-mode) + (forward-sentence 1)) + +Point-Char: | + +Name: forward-sentence moves over if + +=-= +public class Basic { + public void basic() { + |if (x) { + + } + log.info("some text: {}", text); + return; + } +} +=-= +public class Basic { + public void basic() { + if (x) { + + }| + log.info("some text: {}", text); + return; + } +} +=-=-= + +Name: forward-sentence moves over method invocation + +=-= +public class Basic { + public void basic() { + |log.info("some text: {}", text); + } +} +=-= +public class Basic { + public void basic() { + log.info("some text: {}", text);| + } +} +=-=-= + +Code: + (lambda () + (java-ts-mode) + (forward-sentence 2)) + +Name: forward-sentence moves over multiple statements + +=-= +public class Basic { + public void basic() { + |return; + return; + } +} +=-= +public class Basic { + public void basic() { + return; + return;| + } +} +=-=-= + +Code: + (lambda () + (java-ts-mode) + (backward-sentence 1)) + +Name: backward-sentence moves over one statement + +=-= +public class Basic { + public void basic() { + return;| + } +} +=-= +public class Basic { + public void basic() { + |return; + } +} +=-=-= + +Code: + (lambda () + (java-ts-mode) + (beginning-of-defun)) + +Name: beginning-of-defun moves to defun start + +=-= +public class Basic { + public void basic() { + return;| + } +} +=-= +public class Basic { +| public void basic() { + return; + } +} +=-=-= + +Code: + (lambda () + (java-ts-mode) + (beginning-of-defun) + (beginning-of-defun)) + +Name: beginning-of-defun moves to class + +=-= +public class Basic { + public void basic() { + return;| + } +} +=-= +|public class Basic { + public void basic() { + return; + } +} +=-=-= + +Code: + (lambda () + (java-ts-mode) + (end-of-defun)) + +Name: end-of-defun moves to defun end + +=-= +public class Basic { + public void basic() { + return;| + } +} +=-= +public class Basic { + public void basic() { + return; + } +|} +=-=-= diff --git a/test/lisp/progmodes/java-ts-mode-tests.el b/test/lisp/progmodes/java-ts-mode-tests.el new file mode 100644 index 00000000000..4fd8fc3019f --- /dev/null +++ b/test/lisp/progmodes/java-ts-mode-tests.el @@ -0,0 +1,35 @@ +;;; java-ts-mode-tests.el --- Tests for Tree-sitter-based Java mode -*- lexical-binding: t; -*- + +;; Copyright (C) 2023 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Code: + +(require 'ert) +(require 'ert-x) +(require 'treesit) + +(ert-deftest java-ts-mode-test-indentation () + (skip-unless (treesit-ready-p 'java)) + (ert-test-erts-file (ert-resource-file "indent.erts"))) + +(ert-deftest java-ts-mode-test-movement () + (skip-unless (treesit-ready-p 'java)) + (ert-test-erts-file (ert-resource-file "movement.erts"))) + +(provide 'java-ts-mode-tests) +;;; java-ts-mode-tests.el ends here diff --git a/test/lisp/progmodes/typescript-ts-mode-resources/indent.erts b/test/lisp/progmodes/typescript-ts-mode-resources/indent.erts new file mode 100644 index 00000000000..146ee76574e --- /dev/null +++ b/test/lisp/progmodes/typescript-ts-mode-resources/indent.erts @@ -0,0 +1,73 @@ +Code: + (lambda () + (setq indent-tabs-mode nil) + (setq typescript-ts-mode-indent-offset 2) + (typescript-ts-mode) + (indent-region (point-min) (point-max))) + +Point-Char: | + +Name: Basic indentation + +=-= +const foo = () => { + console.log("bar"); + if (x) { + return y; + } else if (y) { + return u; + } + return baz.x() + ? true + : false; +} +=-=-= + +Code: + (lambda () + (setq indent-tabs-mode nil) + (setq tsx-ts-mode-indent-offset 2) + (tsx-ts-mode) + (indent-region (point-min) (point-max))) + +Name: JSX indentation + +=-= +const foo = (props) => { + return ( + <div> + <div> + <div> + <div> + { + props.foo + ? Hello, foo! + : Hello, World!; + } + </div> + </div> + </div> + </div> + ); +} +=-=-= + +Name: JSX indentation with attributes + +=-= +const foo = (props) => { + return ( + <div + className={foo} + onClick={() => { + alert('???'); + return () => { + return 5+5; + }; + }} + > + <p>Some text</p> + </div> + ); +} +=-=-= diff --git a/test/lisp/progmodes/typescript-ts-mode-tests.el b/test/lisp/progmodes/typescript-ts-mode-tests.el new file mode 100644 index 00000000000..126f5e3298f --- /dev/null +++ b/test/lisp/progmodes/typescript-ts-mode-tests.el @@ -0,0 +1,31 @@ +;;; typescript-ts-mode-tests.el --- Tests for Tree-sitter-based TypeScript mode -*- lexical-binding: t; -*- + +;; Copyright (C) 2023 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Code: + +(require 'ert) +(require 'ert-x) +(require 'treesit) + +(ert-deftest typescript-ts-mode-test-indentation () + (skip-unless (treesit-ready-p 'typescript)) + (ert-test-erts-file (ert-resource-file "indent.erts"))) + +(provide 'typescript-ts-mode-tests) +;;; typescript-ts-mode-tests.el ends here diff --git a/test/lisp/url/url-future-tests.el b/test/lisp/url/url-future-tests.el index 5c5802ef3e4..18e6e31c8ce 100644 --- a/test/lisp/url/url-future-tests.el +++ b/test/lisp/url/url-future-tests.el @@ -52,7 +52,7 @@ (should (equal (url-future-cancel tocancel) tocancel)) (should-error (url-future-call tocancel)) (should (null url-future-tests--saver)) - (should (url-future-cancelled-p tocancel)))) + (should (url-future-canceled-p tocancel)))) (provide 'url-future-tests) diff --git a/test/lisp/whitespace-tests.el b/test/lisp/whitespace-tests.el index 7b76ac87129..f059104cdb9 100644 --- a/test/lisp/whitespace-tests.el +++ b/test/lisp/whitespace-tests.el @@ -57,6 +57,24 @@ buffer's content." (whitespace-cleanup) (buffer-string))) +(ert-deftest whitespace-tests--global () + (let ((backup global-whitespace-mode) + (noninteractive nil) + (whitespace-enable-predicate (lambda () t))) + (unwind-protect + (progn + (global-whitespace-mode 1) + (ert-with-test-buffer-selected () + (normal-mode) + (should whitespace-mode) + (global-whitespace-mode -1) + (should (null whitespace-mode)) + (whitespace-mode 1) + (should whitespace-mode) + (global-whitespace-mode 1) + (should whitespace-mode))) + (global-whitespace-mode (if backup 1 -1))))) + (ert-deftest whitespace-cleanup-eob () (let ((whitespace-style '(empty))) (should (equal (whitespace-tests--cleanup-string "a\n") diff --git a/test/manual/noverlay/itree-tests.c b/test/manual/noverlay/itree-tests.c index 1fef87ea98d..0f1e4138954 100644 --- a/test/manual/noverlay/itree-tests.c +++ b/test/manual/noverlay/itree-tests.c @@ -26,7 +26,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "emacs-compat.h" #define EMACS_LISP_H /* lisp.h inclusion guard */ -#define ITREE_DEBUG 1 #define ITREE_TESTING #include "itree.c" @@ -53,7 +52,7 @@ test_insert1_setup (void) enum { N = 6 }; const int values[N] = {50, 30, 20, 10, 15, 5}; struct itree_node *nodes[N] = {&N_50, &N_30, &N_20, &N_10, &N_15, &N_05}; - interval_tree_init (&tree); + itree_init (&tree); for (int i = 0; i < N; ++i) { nodes[i]->begin = nodes[i]->end = values[i]; @@ -67,7 +66,7 @@ START_TEST (test_insert_1) * [50] */ - interval_tree_insert (&tree, &N_50); + itree_insert_node (&tree, &N_50); ck_assert (! N_50.red); ck_assert_ptr_eq (&N_50, tree.root); } @@ -81,8 +80,8 @@ START_TEST (test_insert_2) * (30) */ - interval_tree_insert (&tree, &N_50); - interval_tree_insert (&tree, &N_30); + itree_insert_node (&tree, &N_50); + itree_insert_node (&tree, &N_30); ck_assert (! N_50.red); ck_assert (N_30.red); ck_assert_ptr_eq (&N_50, tree.root); @@ -102,9 +101,9 @@ START_TEST (test_insert_3) * (20) (50) */ - interval_tree_insert (&tree, &N_50); - interval_tree_insert (&tree, &N_30); - interval_tree_insert (&tree, &N_20); + itree_insert_node (&tree, &N_50); + itree_insert_node (&tree, &N_30); + itree_insert_node (&tree, &N_20); ck_assert (N_50.red); ck_assert (! N_30.red); ck_assert (N_20.red); @@ -128,10 +127,10 @@ START_TEST (test_insert_4) * (10) */ - interval_tree_insert (&tree, &N_50); - interval_tree_insert (&tree, &N_30); - interval_tree_insert (&tree, &N_20); - interval_tree_insert (&tree, &N_10); + itree_insert_node (&tree, &N_50); + itree_insert_node (&tree, &N_30); + itree_insert_node (&tree, &N_20); + itree_insert_node (&tree, &N_10); ck_assert (! N_50.red); ck_assert (! N_30.red); ck_assert (! N_20.red); @@ -159,11 +158,11 @@ START_TEST (test_insert_5) * (10) (20) */ - interval_tree_insert (&tree, &N_50); - interval_tree_insert (&tree, &N_30); - interval_tree_insert (&tree, &N_20); - interval_tree_insert (&tree, &N_10); - interval_tree_insert (&tree, &N_15); + itree_insert_node (&tree, &N_50); + itree_insert_node (&tree, &N_30); + itree_insert_node (&tree, &N_20); + itree_insert_node (&tree, &N_10); + itree_insert_node (&tree, &N_15); ck_assert (! N_50.red); ck_assert (! N_30.red); ck_assert (N_20.red); @@ -197,12 +196,12 @@ START_TEST (test_insert_6) * (5) */ - interval_tree_insert (&tree, &N_50); - interval_tree_insert (&tree, &N_30); - interval_tree_insert (&tree, &N_20); - interval_tree_insert (&tree, &N_10); - interval_tree_insert (&tree, &N_15); - interval_tree_insert (&tree, &N_05); + itree_insert_node (&tree, &N_50); + itree_insert_node (&tree, &N_30); + itree_insert_node (&tree, &N_20); + itree_insert_node (&tree, &N_10); + itree_insert_node (&tree, &N_15); + itree_insert_node (&tree, &N_05); ck_assert (! N_50.red); ck_assert (! N_30.red); ck_assert (! N_20.red); @@ -238,7 +237,7 @@ test_insert2_setup (void) enum { N = 6 }; const int values[] = {50, 70, 80, 90, 85, 95}; struct itree_node *nodes[N] = {&N_50, &N_70, &N_80, &N_90, &N_85, &N_95}; - interval_tree_init (&tree); + itree_init (&tree); for (int i = 0; i < N; ++i) { nodes[i]->begin = nodes[i]->end = values[i]; @@ -252,7 +251,7 @@ START_TEST (test_insert_7) * [50] */ - interval_tree_insert (&tree, &N_50); + itree_insert_node (&tree, &N_50); ck_assert (! N_50.red); ck_assert_ptr_eq (&N_50, tree.root); } @@ -266,8 +265,8 @@ START_TEST (test_insert_8) * (70) */ - interval_tree_insert (&tree, &N_50); - interval_tree_insert (&tree, &N_70); + itree_insert_node (&tree, &N_50); + itree_insert_node (&tree, &N_70); ck_assert (! N_50.red); ck_assert (N_70.red); ck_assert_ptr_eq (&N_50, tree.root); @@ -287,9 +286,9 @@ START_TEST (test_insert_9) * (50) (80) */ - interval_tree_insert (&tree, &N_50); - interval_tree_insert (&tree, &N_70); - interval_tree_insert (&tree, &N_80); + itree_insert_node (&tree, &N_50); + itree_insert_node (&tree, &N_70); + itree_insert_node (&tree, &N_80); ck_assert (N_50.red); ck_assert (! N_70.red); ck_assert (N_80.red); @@ -313,10 +312,10 @@ START_TEST (test_insert_10) * (90) */ - interval_tree_insert (&tree, &N_50); - interval_tree_insert (&tree, &N_70); - interval_tree_insert (&tree, &N_80); - interval_tree_insert (&tree, &N_90); + itree_insert_node (&tree, &N_50); + itree_insert_node (&tree, &N_70); + itree_insert_node (&tree, &N_80); + itree_insert_node (&tree, &N_90); ck_assert (! N_50.red); ck_assert (! N_70.red); ck_assert (! N_80.red); @@ -344,11 +343,11 @@ START_TEST (test_insert_11) * (80) (90) */ - interval_tree_insert (&tree, &N_50); - interval_tree_insert (&tree, &N_70); - interval_tree_insert (&tree, &N_80); - interval_tree_insert (&tree, &N_90); - interval_tree_insert (&tree, &N_85); + itree_insert_node (&tree, &N_50); + itree_insert_node (&tree, &N_70); + itree_insert_node (&tree, &N_80); + itree_insert_node (&tree, &N_90); + itree_insert_node (&tree, &N_85); ck_assert (! N_50.red); ck_assert (! N_70.red); ck_assert (N_80.red); @@ -383,12 +382,12 @@ START_TEST (test_insert_12) * (95) */ - interval_tree_insert (&tree, &N_50); - interval_tree_insert (&tree, &N_70); - interval_tree_insert (&tree, &N_80); - interval_tree_insert (&tree, &N_90); - interval_tree_insert (&tree, &N_85); - interval_tree_insert (&tree, &N_95); + itree_insert_node (&tree, &N_50); + itree_insert_node (&tree, &N_70); + itree_insert_node (&tree, &N_80); + itree_insert_node (&tree, &N_90); + itree_insert_node (&tree, &N_85); + itree_insert_node (&tree, &N_95); ck_assert (! N_50.red); ck_assert (! N_70.red); ck_assert (! N_80.red); @@ -419,7 +418,7 @@ START_TEST (test_insert_13) enum { N = 4 }; const int values[N] = {10, 20, 30, 40}; struct itree_node *nodes[N] = {&N_10, &N_20, &N_30, &N_40}; - interval_tree_init (&tree); + itree_init (&tree); for (int i = 0; i < N; ++i) itree_insert (&tree, nodes[i], values[i], values[i]); @@ -437,13 +436,13 @@ END_TEST START_TEST (test_insert_14) { enum { N = 3 }; - struct itree_node nodes[N]; - interval_tree_init (&tree); + struct itree_node nodes[N] = {0}; + itree_init (&tree); for (int i = 0; i < N; ++i) itree_insert (&tree, &nodes[i], 10, 10); for (int i = 0; i < N; ++i) - ck_assert (interval_tree_contains (&tree, &nodes[i])); + ck_assert (itree_contains (&tree, &nodes[i])); } END_TEST @@ -458,7 +457,7 @@ END_TEST static void test_remove1_setup (void) { - interval_tree_init (&tree); + itree_init (&tree); tree.root = &B; A.parent = &B; B.parent = NULL; C.parent = &D; D.parent = &B; E.parent = &D; A.left = A.right = C.left = C.right = E.left = E.right = NULL; @@ -480,7 +479,7 @@ START_TEST (test_remove_1) { B.red = A.red = C.red = E.red = false; D.red = true; - interval_tree_remove_fix (&tree, &A, &B); + itree_remove_fix (&tree, &A, &B); ck_assert (! A.red); ck_assert (! B.red); @@ -502,7 +501,7 @@ END_TEST START_TEST (test_remove_2) { B.red = D.red = A.red = C.red = E.red = false; - interval_tree_remove_fix (&tree, &A, &B); + itree_remove_fix (&tree, &A, &B); ck_assert (! A.red); ck_assert (! B.red); @@ -523,7 +522,7 @@ START_TEST (test_remove_3) { D.red = A.red = E.red = false; B.red = C.red = true; - interval_tree_remove_fix (&tree, &A, &B); + itree_remove_fix (&tree, &A, &B); ck_assert (! A.red); ck_assert (! B.red); @@ -546,7 +545,7 @@ START_TEST (test_remove_4) { B.red = C.red = E.red = true; A.red = D.red = false; - interval_tree_remove_fix (&tree, &A, &B); + itree_remove_fix (&tree, &A, &B); ck_assert (! A.red); ck_assert (! B.red); @@ -569,7 +568,7 @@ END_TEST static void test_remove2_setup (void) { - interval_tree_init (&tree); + itree_init (&tree); tree.root = &B; A.parent = &B; B.parent = NULL; C.parent = &D; D.parent = &B; E.parent = &D; A.right = A.left = C.right = C.left = E.right = E.left = NULL; @@ -589,7 +588,7 @@ START_TEST (test_remove_5) { B.red = A.red = C.red = E.red = false; D.red = true; - interval_tree_remove_fix (&tree, &A, &B); + itree_remove_fix (&tree, &A, &B); ck_assert (! A.red); ck_assert (! B.red); @@ -611,7 +610,7 @@ END_TEST START_TEST (test_remove_6) { B.red = D.red = A.red = C.red = E.red = false; - interval_tree_remove_fix (&tree, &A, &B); + itree_remove_fix (&tree, &A, &B); ck_assert (! A.red); ck_assert (! B.red); @@ -632,7 +631,7 @@ START_TEST (test_remove_7) { D.red = A.red = E.red = false; B.red = C.red = true; - interval_tree_remove_fix (&tree, &A, &B); + itree_remove_fix (&tree, &A, &B); ck_assert (! A.red); ck_assert (! B.red); @@ -655,7 +654,7 @@ START_TEST (test_remove_8) { B.red = C.red = E.red = true; A.red = D.red = false; - interval_tree_remove_fix (&tree, &A, &B); + itree_remove_fix (&tree, &A, &B); ck_assert (! A.red); ck_assert (! B.red); @@ -676,7 +675,7 @@ START_TEST (test_remove_9) enum { N = 4 }; const int values[N] = {10, 20, 30, 40}; struct itree_node *nodes[N] = {&N_10, &N_20, &N_30, &N_40}; - interval_tree_init (&tree); + itree_init (&tree); for (int i = 0; i < N; ++i) itree_insert (&tree, nodes[i], values[i], values[i]); @@ -722,8 +721,8 @@ START_TEST (test_remove_10) srand (42); shuffle (index, N); - interval_tree_init (&tree); - struct itree_node nodes[N]; + itree_init (&tree); + struct itree_node nodes[N] = {0}; for (int i = 0; i < N; ++i) { ptrdiff_t pos = (i + 1) * 10; @@ -733,10 +732,10 @@ START_TEST (test_remove_10) shuffle (index, N); for (int i = 0; i < N; ++i) { - ck_assert (interval_tree_contains (&tree, &nodes[index[i]])); + ck_assert (itree_contains (&tree, &nodes[index[i]])); itree_remove (&tree, &nodes[index[i]]); } - ck_assert_ptr_null (tree.root); + ck_assert (itree_empty_p (&tree)); ck_assert_int_eq (tree.size, 0); } END_TEST @@ -748,12 +747,12 @@ END_TEST START_TEST (test_generator_1) { - struct itree_node node, *n; - struct itree_iterator *g; - interval_tree_init (&tree); + struct itree_node node = {0}, *n; + struct itree_iterator it, *g; + itree_init (&tree); itree_insert (&tree, &node, 10, 20); - g = itree_iterator_start (&tree, 0, 30, ITREE_ASCENDING, NULL, 0); + g = itree_iterator_start (&it, &tree, 0, 30, ITREE_ASCENDING); n = itree_iterator_next (g); ck_assert_ptr_eq (n, &node); ck_assert_int_eq (n->begin, 10); @@ -761,13 +760,11 @@ START_TEST (test_generator_1) ck_assert_ptr_null (itree_iterator_next (g)); ck_assert_ptr_null (itree_iterator_next (g)); ck_assert_ptr_null (itree_iterator_next (g)); - itree_iterator_finish (g); - g = itree_iterator_start (&tree, 30, 50, ITREE_ASCENDING, NULL, 0); + g = itree_iterator_start (&it, &tree, 30, 50, ITREE_ASCENDING); ck_assert_ptr_null (itree_iterator_next (g)); ck_assert_ptr_null (itree_iterator_next (g)); ck_assert_ptr_null (itree_iterator_next (g)); - itree_iterator_finish (g); } END_TEST @@ -777,8 +774,8 @@ test_check_generator (struct itree_tree *tree, int n, ...) { va_list ap; - struct itree_iterator *g = - itree_iterator_start (tree, begin, end, ITREE_ASCENDING, NULL, 0); + struct itree_iterator it, *g = + itree_iterator_start (&it, tree, begin, end, ITREE_ASCENDING); va_start (ap, n); for (int i = 0; i < n; ++i) @@ -790,13 +787,12 @@ test_check_generator (struct itree_tree *tree, va_end (ap); ck_assert_ptr_null (itree_iterator_next (g)); ck_assert_ptr_null (itree_iterator_next (g)); - itree_iterator_finish (g); } START_TEST (test_generator_2) { - interval_tree_init (&tree); - struct itree_node nodes[3]; + itree_init (&tree); + struct itree_node nodes[3] = {0}; for (int i = 0; i < 3; ++i) itree_insert (&tree, &nodes[i], 10 * (i + 1), 10 * (i + 2)); @@ -830,7 +826,7 @@ test_create_tree (struct itree_node *nodes, int n, bool doshuffle) shuffle (index, n); } - interval_tree_init (&tree); + itree_init (&tree); for (int i = 0; i < n; ++i) { struct itree_node *node = &nodes[index[i]]; @@ -862,8 +858,8 @@ START_TEST (test_generator_5) {.begin = 30, .end = 50}, {.begin = 40, .end = 60}}; test_create_tree (nodes, N, false); - struct itree_iterator *g = - itree_iterator_start (&tree, 0, 100, ITREE_PRE_ORDER, NULL, 0); + struct itree_iterator it, *g = + itree_iterator_start (&it, &tree, 0, 100, ITREE_PRE_ORDER); for (int i = 0; i < N; ++i) { struct itree_node *n = itree_iterator_next (g); @@ -876,7 +872,6 @@ START_TEST (test_generator_5) case 3: ck_assert_int_eq (40, n->begin); break; } } - itree_iterator_finish (g); } END_TEST @@ -888,8 +883,8 @@ START_TEST (test_generator_6) {.begin = 30, .end = 50}, {.begin = 40, .end = 60}}; test_create_tree (nodes, N, true); - struct itree_iterator *g = - itree_iterator_start (&tree, 0, 100, ITREE_ASCENDING, NULL, 0); + struct itree_iterator it, *g = + itree_iterator_start (&it, &tree, 0, 100, ITREE_ASCENDING); for (int i = 0; i < N; ++i) { struct itree_node *n = itree_iterator_next (g); @@ -902,7 +897,6 @@ START_TEST (test_generator_6) case 3: ck_assert_int_eq (40, n->begin); break; } } - itree_iterator_finish (g); } END_TEST @@ -914,8 +908,8 @@ START_TEST (test_generator_7) {.begin = 30, .end = 50}, {.begin = 40, .end = 60}}; test_create_tree (nodes, N, true); - struct itree_iterator *g = - itree_iterator_start (&tree, 0, 100, ITREE_DESCENDING, NULL, 0); + struct itree_iterator it, *g = + itree_iterator_start (&it, &tree, 0, 100, ITREE_DESCENDING); for (int i = 0; i < N; ++i) { struct itree_node *n = itree_iterator_next (g); @@ -928,7 +922,6 @@ START_TEST (test_generator_7) case 3: ck_assert_int_eq (10, n->begin); break; } } - itree_iterator_finish (g); } END_TEST @@ -938,14 +931,13 @@ START_TEST (test_generator_8) struct itree_node nodes[N] = {{.begin = 20, .end = 30}, {.begin = 40, .end = 50}}; test_create_tree (nodes, N, false); - struct itree_iterator *g = - itree_iterator_start (&tree, 1, 60, ITREE_DESCENDING, NULL, 0); + struct itree_iterator it, *g = + itree_iterator_start (&it, &tree, 1, 60, ITREE_DESCENDING); struct itree_node *n = itree_iterator_next (g); ck_assert_int_eq (n->begin, 40); itree_iterator_narrow (g, 50, 60); n = itree_iterator_next (g); ck_assert_ptr_null (n); - itree_iterator_finish (g); } END_TEST @@ -955,14 +947,13 @@ START_TEST (test_generator_9) struct itree_node nodes[N] = {{.begin = 25, .end = 25}, {.begin = 20, .end = 30}}; test_create_tree (nodes, N, false); - struct itree_iterator *g = - itree_iterator_start (&tree, 1, 30, ITREE_DESCENDING, NULL, 0); + struct itree_iterator it, *g = + itree_iterator_start (&it, &tree, 1, 30, ITREE_DESCENDING); struct itree_node *n = itree_iterator_next (g); ck_assert_int_eq (n->begin, 25); itree_iterator_narrow (g, 25, 30); n = itree_iterator_next (g); ck_assert_int_eq (n->begin, 20); - itree_iterator_finish (g); } END_TEST @@ -981,7 +972,7 @@ static void test_setup_gap_node (ptrdiff_t begin, ptrdiff_t end, bool front_advance, bool rear_advance) { - interval_tree_init (&gap_tree); + itree_init (&gap_tree); gap_node.front_advance = front_advance; gap_node.rear_advance = rear_advance; itree_insert (&gap_tree, &gap_node, begin, end); @@ -1281,9 +1272,8 @@ main (void) Suite *s = basic_suite (); SRunner *sr = srunner_create (s); - init_itree (); srunner_run_all (sr, CK_ENV); - int nfailed = srunner_ntests_failed (sr); + int failed = srunner_ntests_failed (sr); srunner_free (sr); - return (nfailed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; + return failed ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/test/src/process-tests.el b/test/src/process-tests.el index c3b4e17dbc0..e17e1c0d833 100644 --- a/test/src/process-tests.el +++ b/test/src/process-tests.el @@ -830,7 +830,7 @@ Return nil if that can't be determined." (when (eq process-tests--EMFILE-message :unknown) (setq process-tests--EMFILE-message (with-temp-buffer - (when (eql (ignore-error 'file-error + (when (eql (ignore-error file-error (call-process "errno" nil t nil "EMFILE")) 0) (goto-char (point-min)) diff --git a/test/src/regex-emacs-tests.el b/test/src/regex-emacs-tests.el index cd4924f9785..34fa35e32ff 100644 --- a/test/src/regex-emacs-tests.el +++ b/test/src/regex-emacs-tests.el @@ -273,7 +273,7 @@ on success" string (condition-case nil (if (string-match pattern string) nil 'search-failed) - ('invalid-regexp 'compilation-failed)) + (invalid-regexp 'compilation-failed)) bounds-ref substring-ref))) @@ -518,7 +518,7 @@ known/benign differences in behavior.") what-failed (condition-case nil (if (string-match pattern string) nil 'search-failed) - ('invalid-regexp 'compilation-failed)) + (invalid-regexp 'compilation-failed)) matches-observed (cl-loop for x from 0 to 20 diff --git a/test/src/undo-tests.el b/test/src/undo-tests.el index 84151d3b5db..fd45a9101fa 100644 --- a/test/src/undo-tests.el +++ b/test/src/undo-tests.el @@ -439,6 +439,78 @@ Demonstrates bug 16818." (should (string= (buffer-string) "aaaFirst line\nSecond line\nbbb")))) +(ert-deftest undo-test-combine-change-calls-1 () + "Test how `combine-change-calls' updates `buffer-undo-list'. +Case 1: a file-visiting buffer with `buffer-undo-list' non-nil +and `buffer-modified-p' non-nil when `combine-change-calls' is +called." + (ert-with-temp-file tempfile + (with-current-buffer (find-file tempfile) + (insert "A") + (undo-boundary) + (insert "B") + (undo-boundary) + (insert "C") + (undo-boundary) + (insert " ") + (undo-boundary) + (insert "D") + (undo-boundary) + (insert "E") + (undo-boundary) + (insert "F") + (should (= (length buffer-undo-list) 14)) + (goto-char (point-min)) + (combine-change-calls (point-min) (point-max) + (re-search-forward "ABC ") + (replace-match "Z ")) + (should (= (length buffer-undo-list) 15))))) + +(ert-deftest undo-test-combine-change-calls-2 () + "Test how `combine-change-calls' updates `buffer-undo-list'. +Case 2: a file-visiting buffer with `buffer-undo-list' non-nil +and `buffer-modified-p' nil when `combine-change-calls' is +called." + (ert-with-temp-file tempfile + (with-current-buffer (find-file tempfile) + (insert "A") + (undo-boundary) + (insert "B") + (undo-boundary) + (insert "C") + (undo-boundary) + (insert " ") + (undo-boundary) + (insert "D") + (undo-boundary) + (insert "E") + (undo-boundary) + (insert "F") + (should (= (length buffer-undo-list) 14)) + (save-buffer) + (goto-char (point-min)) + (combine-change-calls (point-min) (point-max) + (re-search-forward "ABC ") + (replace-match "Z ")) + (should (= (length buffer-undo-list) 15))))) + +(ert-deftest undo-test-combine-change-calls-3 () + "Test how `combine-change-calls' updates `buffer-undo-list'. +Case 3: a file-visiting buffer with `buffer-undo-list' nil and +`buffer-modified-p' nil when `combine-change-calls' is called." + (ert-with-temp-file tempfile + (with-current-buffer (find-file tempfile) + (insert "ABC DEF") + (save-buffer) + (kill-buffer)) + (with-current-buffer (find-file tempfile) + (should (= (length buffer-undo-list) 0)) + (goto-char (point-min)) + (combine-change-calls (point-min) (point-max) + (re-search-forward "ABC ") + (replace-match "Z ")) + (should (= (length buffer-undo-list) 1))))) + (defun undo-test-all (&optional interactive) "Run all tests for \\[undo]." (interactive "p") |