feature/igc3 397afb025b9: Merge branch 'master' into feature/igc3
Helmut Eller <[email protected]> Mon, 27 Jul 2026 04:06:50 -0400 (EDT)
| Newsgroups | gmane.emacs.diffs |
|---|---|
| Message-ID | <[email protected]> |
branch: feature/igc3 commit 397afb025b9e5d3e9eb4c21209bb7e06130ea16f Merge: abd0574762f 810e9d675ba Author: Helmut Eller <[email protected]> Commit: Helmut Eller <[email protected]> Merge branch 'master' into feature/igc3 --- .dir-locals.el | 4 +- ChangeLog.5 | 1443 ++++++++++++++- Makefile.in | 42 +- admin/MAINTAINERS | 3 + admin/make-tarball.txt | 193 +- admin/merge-gnulib | 5 +- admin/notes/documentation | 4 + admin/notes/jargon | 1 + admin/notes/repo | 30 + admin/nt/dist-build/README-windows-binaries | 23 +- configure.ac | 53 +- doc/emacs/android.texi | 2 + doc/emacs/building.texi | 14 +- doc/emacs/calendar.texi | 6 +- doc/emacs/display.texi | 6 +- doc/emacs/frames.texi | 15 +- doc/emacs/maintaining.texi | 223 ++- doc/emacs/rmail.texi | 4 + doc/emacs/search.texi | 4 + doc/emacs/text.texi | 19 +- doc/lispintro/emacs-lisp-intro.texi | 13 +- doc/lispref/buffers.texi | 7 +- doc/lispref/commands.texi | 28 +- doc/lispref/control.texi | 7 + doc/lispref/display.texi | 30 +- doc/lispref/edebug.texi | 6 +- doc/lispref/elisp.texi | 2 + doc/lispref/files.texi | 18 +- doc/lispref/frames.texi | 116 ++ doc/lispref/functions.texi | 2 + doc/lispref/intro.texi | 6 +- doc/lispref/keymaps.texi | 28 +- doc/lispref/minibuf.texi | 5 +- doc/lispref/modes.texi | 7 +- doc/lispref/os.texi | 25 +- doc/lispref/parsing.texi | 132 +- doc/lispref/processes.texi | 157 +- doc/lispref/strings.texi | 3 + doc/lispref/text.texi | 10 +- doc/lispref/variables.texi | 8 + doc/lispref/windows.texi | 69 +- doc/misc/Makefile.in | 4 +- doc/misc/calc.texi | 14 +- doc/misc/cl.texi | 6 - doc/misc/erc.texi | 973 +++++++++- doc/misc/modus-themes.org | 1870 ++++++++------------ doc/misc/org.org | 18 +- doc/misc/texinfo.tex | 41 +- doc/misc/tramp.texi | 26 +- doc/misc/trampver.texi | 2 +- doc/translations/README | 64 +- doc/translations/default/{ => misc}/info_common.mk | 0 doc/translations/fr/{ => misc}/info_common.mk | 0 etc/AUTHORS | 166 +- etc/DEBUG | 11 +- etc/EGLOT-NEWS | 2 +- etc/ERC-NEWS | 41 + etc/NEWS | 196 ++ etc/NEWS.31 | 370 ++-- etc/PROBLEMS | 41 + etc/emacs-buffer.gdb | 6 +- etc/refcards/orgcard.tex | 2 +- etc/themes/modus-operandi-deuteranopia-theme.el | 8 +- etc/themes/modus-operandi-theme.el | 8 +- etc/themes/modus-operandi-tinted-theme.el | 8 +- etc/themes/modus-operandi-tritanopia-theme.el | 8 +- etc/themes/modus-themes.el | 739 ++++---- etc/themes/modus-vivendi-deuteranopia-theme.el | 8 +- etc/themes/modus-vivendi-theme.el | 8 +- etc/themes/modus-vivendi-tinted-theme.el | 8 +- etc/themes/modus-vivendi-tritanopia-theme.el | 8 +- java/AndroidManifest.xml.in | 6 +- java/INSTALL | 18 +- java/org/gnu/emacs/EmacsFillPolygon.java | 11 +- lib/af_alg.h | 115 -- lib/faccessat.c | 24 +- lib/fchmodat.c | 48 +- lib/fstatat.c | 17 +- lib/getopt-pfx-ext.h | 1 + lib/getopt1.c | 12 +- lib/gnulib.mk.in | 2 +- lib/intprops-internal.h | 2 +- lib/md5-stream.c | 6 +- lib/mini-gmp.c | 52 +- lib/mini-gmp.h | 5 +- lib/signal.in.h | 2 +- lib/stat-time.h | 2 +- lib/stdbit.in.h | 6 +- lib/stdlib.in.h | 3 +- lib/string.in.h | 12 +- lib/sys_stat.in.h | 28 +- lib/unistd.in.h | 32 +- lisp/bindings.el | 32 +- lisp/bookmark.el | 2 +- lisp/calc/calc-forms.el | 5 +- lisp/calendar/cal-dst.el | 4 +- lisp/calendar/calendar.el | 4 +- lisp/calendar/icalendar-macs.el | 8 +- lisp/calendar/icalendar-recur.el | 15 +- lisp/calendar/parse-time.el | 8 +- lisp/calendar/timeclock.el | 30 +- lisp/cedet/ede.el | 2 +- lisp/comint.el | 4 +- lisp/cus-edit.el | 57 +- lisp/cus-start.el | 6 +- lisp/dabbrev.el | 2 +- lisp/dired-aux.el | 8 +- lisp/dired-x.el | 1 + lisp/dired.el | 20 +- lisp/electric.el | 100 +- lisp/emacs-lisp/backtrace.el | 6 +- lisp/emacs-lisp/byte-opt.el | 2 +- lisp/emacs-lisp/bytecomp.el | 6 +- lisp/emacs-lisp/cl-macs.el | 13 +- lisp/emacs-lisp/debug-early.el | 8 +- lisp/emacs-lisp/edebug.el | 19 +- lisp/emacs-lisp/eldoc.el | 25 +- lisp/emacs-lisp/elisp-scope.el | 579 +++--- lisp/emacs-lisp/ewoc.el | 17 +- lisp/emacs-lisp/gv.el | 87 +- lisp/emacs-lisp/lisp-mode.el | 1 - lisp/emacs-lisp/lisp.el | 31 +- lisp/emacs-lisp/macroexp.el | 5 +- lisp/emacs-lisp/map-ynp.el | 47 +- lisp/emacs-lisp/multisession.el | 1 - lisp/emacs-lisp/package-activate.el | 2 - lisp/emacs-lisp/package.el | 53 +- lisp/emacs-lisp/pcase.el | 45 +- lisp/emacs-lisp/smie.el | 23 +- lisp/emacs-lisp/subr-x.el | 87 +- lisp/emacs-lisp/uuid.el | 245 +++ lisp/emacs-lock.el | 44 +- lisp/erc/erc-backend.el | 4 +- lisp/erc/erc-button.el | 8 +- lisp/erc/erc-common.el | 23 +- lisp/erc/erc-desktop-notifications.el | 134 +- lisp/erc/erc-fill.el | 20 +- lisp/erc/erc-goodies.el | 20 +- lisp/erc/erc-imenu.el | 8 +- lisp/erc/erc-match.el | 408 ++++- lisp/erc/erc-networks.el | 50 +- lisp/erc/erc-settings.el | 296 ++++ lisp/erc/erc-stamp.el | 10 +- lisp/erc/erc-track.el | 8 +- lisp/erc/erc-truncate.el | 4 +- lisp/erc/erc.el | 57 +- lisp/files.el | 28 +- lisp/frame.el | 10 +- lisp/gnus/mml.el | 13 +- lisp/gnus/nndiary.el | 3 +- lisp/help-fns.el | 3 +- lisp/help.el | 21 +- lisp/image/image-dired.el | 8 +- lisp/international/mule-conf.el | 2 + lisp/isearch.el | 4 +- lisp/jsonrpc.el | 10 +- lisp/ldefs-boot.el | 455 ++++- lisp/mail/emacsbug.el | 4 +- lisp/mail/rmail.el | 26 +- lisp/man.el | 6 + lisp/minibuffer.el | 40 +- lisp/mouse.el | 32 +- lisp/net/browse-url.el | 4 +- lisp/net/eww.el | 128 +- lisp/net/gnutls.el | 2 +- lisp/net/goto-addr.el | 7 + lisp/net/newst-backend.el | 2 +- lisp/net/newst-treeview.el | 10 + lisp/net/tramp-archive.el | 3 +- lisp/net/tramp-cmds.el | 5 +- lisp/net/tramp-compat.el | 18 +- lisp/net/tramp-container.el | 4 +- lisp/net/tramp-fuse.el | 15 +- lisp/net/tramp-message.el | 7 + lisp/net/tramp-sh.el | 335 ++-- lisp/net/tramp-smb.el | 62 +- lisp/net/tramp.el | 207 ++- lisp/net/trampver.el | 8 +- lisp/obsolete/cl-compat.el | 4 - lisp/org/ob-core.el | 5 +- lisp/org/org-agenda.el | 6 +- lisp/org/org-feed.el | 2 +- lisp/org/org-version.el | 4 +- lisp/org/org.el | 9 +- lisp/org/ox-beamer.el | 1 + lisp/org/ox-latex.el | 2 +- lisp/outline.el | 107 +- lisp/progmodes/c-ts-mode.el | 1 + lisp/progmodes/cc-mode.el | 44 +- lisp/progmodes/cc-vars.el | 8 +- lisp/progmodes/cperl-mode.el | 13 +- lisp/progmodes/eglot.el | 11 +- lisp/progmodes/elisp-mode.el | 13 +- lisp/progmodes/etags-regen.el | 5 +- lisp/progmodes/flymake.el | 6 +- lisp/progmodes/js.el | 31 +- lisp/progmodes/perl-mode.el | 2 +- lisp/progmodes/prog-mode.el | 10 +- lisp/progmodes/project.el | 114 +- lisp/progmodes/python.el | 19 +- lisp/progmodes/sh-script.el | 19 +- lisp/progmodes/typescript-ts-mode.el | 6 +- lisp/progmodes/verilog-mode.el | 14 +- lisp/replace.el | 12 +- lisp/simple.el | 16 +- lisp/startup.el | 15 +- lisp/subr.el | 80 +- lisp/system-taskbar.el | 4 +- lisp/textmodes/markdown-ts-mode.el | 116 +- lisp/textmodes/yaml-ts-mode.el | 1 + lisp/time-stamp.el | 2 +- lisp/timezone.el | 4 +- lisp/treesit.el | 21 +- lisp/url/url-util.el | 10 +- lisp/vc/diff-mode.el | 72 +- lisp/vc/log-edit.el | 68 +- lisp/vc/vc-annotate.el | 23 +- lisp/vc/vc-bzr.el | 43 +- lisp/vc/vc-cvs.el | 11 +- lisp/vc/vc-dir.el | 614 +++++-- lisp/vc/vc-dispatcher.el | 50 +- lisp/vc/vc-git.el | 168 +- lisp/vc/vc-hg.el | 103 +- lisp/vc/vc-src.el | 1 + lisp/vc/vc-svn.el | 24 +- lisp/vc/vc.el | 191 +- lisp/window-x.el | 219 ++- lisp/window.el | 40 +- lisp/winner.el | 9 +- lisp/woman.el | 4 +- lisp/xdg.el | 9 +- lisp/xwidget.el | 2 +- m4/fcntl_h.m4 | 4 +- m4/fstatat.m4 | 53 +- m4/manywarnings.m4 | 49 +- nextstep/templates/Info.plist.in | 6 + nt/inc/unistd.h | 1 + nt/mingw-cfg.site | 1 + oldXMenu/Create.c | 12 +- oldXMenu/XCrAssoc.c | 3 +- src/android-asset.h | 48 +- src/atimer.c | 3 + src/buffer.c | 31 +- src/callproc.c | 3 +- src/comp.c | 69 +- src/editfns.c | 161 +- src/emacs.c | 14 +- src/eval.c | 35 +- src/frame.c | 12 +- src/image.c | 23 +- src/itree.c | 25 +- src/keyboard.c | 45 +- src/keymap.c | 3 +- src/minibuf.c | 28 +- src/nsterm.m | 8 - src/pdumper.c | 18 +- src/pgtkselect.c | 15 +- src/pgtkterm.c | 61 +- src/process.c | 2 +- src/search.c | 2 +- src/sfnt.c | 10 +- src/timefns.c | 20 +- src/treesit.c | 17 +- src/w32.c | 3 + src/window.c | 42 +- src/window.h | 1 + src/xdisp.c | 188 +- src/xfaces.c | 2 +- src/xselect.c | 15 +- src/xterm.c | 52 +- .../import-bug-11473.diary-iso | 2 +- .../import-bug-22092.diary-iso | 2 +- .../import-bug-33277.diary-iso | 2 +- .../import-legacy-vars.diary-iso | 2 +- .../import-multiple-vcalendars.diary-iso | 8 +- .../import-non-recurring-1.diary-iso | 2 +- .../import-non-recurring-all-day.diary-iso | 2 +- .../import-non-recurring-another-example.diary-iso | 2 +- .../import-non-recurring-folded-summary.diary-iso | 2 +- .../import-non-recurring-long-summary.diary-iso | 2 +- .../import-time-format-12hr-blank.diary-iso | 2 +- .../import-with-attachment.diary-iso | 2 +- .../import-with-timezone.diary-iso | 4 +- .../import-with-uid.diary-iso | 2 +- test/lisp/calendar/icalendar-recur-tests.el | 6 +- .../rmail-tests.el => calendar/timeclock-tests.el} | 30 +- test/lisp/dired-tests.el | 10 + test/lisp/emacs-lisp/benchmark-tests.el | 5 +- test/lisp/emacs-lisp/lisp-tests.el | 6 +- test/lisp/emacs-lisp/macroexp-tests.el | 21 + test/lisp/emacs-lisp/map-ynp-tests.el | 78 +- test/lisp/emacs-lisp/package-tests.el | 13 + test/lisp/emacs-lisp/pcase-tests.el | 15 + test/lisp/emacs-lisp/subr-x-tests.el | 14 + test/lisp/emacs-lisp/uuid-tests.el | 175 ++ test/lisp/erc/erc-desktop-notifications-tests.el | 139 ++ test/lisp/erc/erc-match-tests.el | 259 ++- test/lisp/erc/erc-scenarios-fill-wrap.el | 68 + test/lisp/erc/erc-scenarios-match-api.el | 127 ++ test/lisp/erc/erc-scenarios-settings.el | 190 ++ test/lisp/erc/erc-settings-tests.el | 119 ++ test/lisp/erc/erc-tests.el | 73 +- test/lisp/erc/resources/erc-scenarios-common.el | 79 +- .../resources/fill/snapshots/merge-01-start.eld | 2 +- .../resources/fill/snapshots/merge-02-right.eld | 2 +- .../erc/resources/fill/snapshots/merge-wrap-01.eld | 2 +- .../fill/snapshots/merge-wrap-indicator-pre-01.eld | 2 +- .../fill/snapshots/monospace-01-start.eld | 2 +- .../fill/snapshots/monospace-02-right.eld | 2 +- .../resources/fill/snapshots/monospace-03-left.eld | 2 +- .../fill/snapshots/monospace-04-reset.eld | 2 +- .../resources/fill/snapshots/spacing-01-mono.eld | 2 +- .../resources/fill/snapshots/stamps-left-01.eld | 2 +- .../erc/resources/match/functions/custom-match-log | 39 + test/lisp/erc/resources/match/functions/custom.eld | 49 + test/lisp/erc/resources/settings/basic-sasl.eld | 47 + test/lisp/erc/resources/settings/basic.eld | 38 + test/lisp/filenotify-tests.el | 46 +- test/lisp/files-tests.el | 4 +- test/lisp/files-x-tests.el | 37 + test/lisp/gnus/gnus-icalendar-tests.el | 5 + test/lisp/mail/rmail-tests.el | 17 + test/lisp/minibuffer-resources/pcm/sources/clang | 0 test/lisp/minibuffer-resources/pcm/sys/class | 0 test/lisp/minibuffer-tests.el | 25 + test/lisp/net/tramp-tests.el | 80 +- .../progmodes/c-ts-mode-resources/indent-bsd.erts | 9 + test/lisp/progmodes/project-tests.el | 79 +- test/lisp/server-tests.el | 3 +- test/lisp/vc/diff-mode-tests.el | 117 ++ test/lisp/vc/vc-git-tests.el | 39 +- .../lisp/vc/vc-tests/resources/vc-tests-helpers.el | 100 ++ test/lisp/vc/vc-tests/vc-test-misc.el | 334 ++++ test/lisp/vc/vc-tests/vc-tests.el | 78 +- test/lisp/visual-wrap-tests.el | 146 +- test/manual/cedet/semantic-tests.el | 2 +- test/src/keyboard-tests.el | 15 + test/src/process-tests.el | 1 + test/src/undo-tests.el | 2 +- test/src/xdisp-tests.el | 34 + 340 files changed, 13299 insertions(+), 5022 deletions(-) diff --git a/.dir-locals.el b/.dir-locals.el index b1123032443..d1cc520e232 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -7,7 +7,6 @@ (emacs-lisp-docstring-fill-column . 72) (vc-git-annotate-switches . "-w") (bug-reference-url-format . "https://debbugs.gnu.org/%s") - (diff-add-log-use-relative-names . t) (etags-regen-regexp-alist . ((("c" "objc") . @@ -57,7 +56,8 @@ (change-log-mode . ((add-log-time-zone-rule . t) (fill-column . 74) (mode . bug-reference))) - (diff-mode . ((mode . whitespace))) + (diff-mode . ((mode . whitespace) + (diff-add-log-use-relative-names . t))) (emacs-lisp-mode . ((indent-tabs-mode . nil) (electric-quote-comment . nil) (electric-quote-string . nil) diff --git a/ChangeLog.5 b/ChangeLog.5 index fbf23263ad3..714fbd19662 100644 --- a/ChangeLog.5 +++ b/ChangeLog.5 @@ -1,3 +1,1444 @@ +2026-07-22 Sean Whitton <[email protected]> + + VC-Annotate menu: Fix inserting "Span NN.NN days" entries + + * lisp/vc/vc-annotate.el (vc-annotate-mode-menu): Generate + entries based on vc-annotate-color-map using a :filter function, + instead of using whatever value that variable happened to have + at load time. + +2026-07-22 Donjuanplatinum <[email protected]> (tiny change) + + Fix typo in Fmatch_end's doc string + + * src/search.c (Fmatch_end): Fix "start position" to "end position". + (Bug#81447) + +2026-07-21 James Cherti <[email protected]> + + Fix false positive warnings in 'elisp-flymake-checkdoc' when narrowed + + * lisp/progmodes/elisp-mode.el (elisp-flymake-checkdoc): Temporarily + widen the buffer before calling 'checkdoc-current-buffer'. This + prevents checkdoc from reporting missing file-level structural + elements when the user has narrowed the buffer. (Bug#81258) + +2026-07-20 Aaron L. Zeng <[email protected]> (tiny change) + + Fix void-function on push-button in goto-address-mode + + * lisp/net/goto-addr.el (goto-address--button-action): + New function (bug#81419). + (goto-address-fontify): Use it as the button action. + +2026-07-19 Petteri Hintsanen <[email protected]> + + Fix perl-calculate-indent + + * lisp/progmodes/perl-mode.el (perl-calculate-indent): Ensure that + the value from (nth 3 state) is a character before passing it to + char-equal. + +2026-07-19 Michael Albinus <[email protected]> + + * admin/notes/documentation: Describe quoting of key names. + +2026-07-19 Eli Zaretskii <[email protected]> + + Fix 'url-parse-query-string' + + * lisp/url/url-util.el (url-parse-query-string): Fix use of + 'match-beginning' and 'match-end'. (Bug#81430) + +2026-07-18 Eshel Yaron <[email protected]> + + markdown-ts-mode: Fix code-block fontification leak + + * lisp/textmodes/markdown-ts-mode.el + (markdown-ts--fontify-non-ts-collect-faces): Prevent + 'font-lock-ensure' from widening and fontifying outside the + intended code-block (bug#81412). + +2026-07-18 Eli Zaretskii <[email protected]> + + Fix 'mouse-drag-copy-region' = 'non-empty' + + * lisp/mouse.el (mouse-save-then-kill): Fix conditions for copying + when 'mouse-drag-copy-region' is 'non-empty'. (Bug#81366) + +2026-07-16 Michael Albinus <[email protected]> + + Fix `with-tramp-local-environment' + + * lisp/net/tramp.el (with-tramp-local-environment): Do not change the + global environment. Reported by Daniel Kraus <[email protected]>. + (Bug#81409) + +2026-07-16 Dmitry Gutov <[email protected]> + + project.el: Bump version to 0.12 + + Do not merge to master. + +2026-07-15 Paul Eggert <[email protected]> + + Port pdumper to m68k + + Problem reported by John Paul Adrian Glaubitz (bug#44531). + * src/pdumper.c (DUMP_RELOCATION_ALIGNMENT_BITS): Remove. It’s + not needed for optimization, as today’s compilers deduce that + multiplying and dividing by the alignment can be done with shifts. + All uses changed to use DUMP_RELOCATION_ALIGNMENT. + (DUMP_RELOCATION_ALIGNMENT) [__mc68000__]: + Now min (4, alignof (Lisp_Object)), not 4. + (dump_reloc_set_offset): Change eassert to eassume to help + the compiler. + +2026-07-14 Mark Hindley <[email protected]> (tiny change) + + browse-url-with-browser-kind: Use strings for DEF + + * lisp/net/browse-url.el (browse-url-with-browser-kind): Use + strings for DEF argument to completing-read (bug#81369). + +2026-07-14 Martin Rudalics <[email protected]> + + Fix issues related to window layout changes (Bug#81406) + + * src/window.c (Vwindow_combination_resize): In doc-string say + that binding this to nil may be necessary to produce specific, + predefined frame layouts (Bug#81406). + * lisp/window-x.el (window-layout-rotate-clockwise) + (window-layout-rotate-anticlockwise) + (window-layout-flip-leftright, window-layout-flip-topdown) + (window-layout-transpose, rotate-windows-change-selected) + (rotate-windows, rotate-windows-back): Rewrite doc-strings. + Make sure that non-interactive calls with nil or absent WINDOW + argument work on the frame's main window. Fix infinite loop + when 'rotate-windows' is called for a non-selected frame. + * doc/lispref/windows.texi (Recombining Windows): Say that + binding 'window-combination-resize' to nil may be necessary to + produce specific, predefined frame layouts (Bug#81406). + (Changing Window Layouts): Minor rewrite. + * etc/NEWS: Announce names of new commands to change window + layout (Bug#81406). + +2026-07-13 Martin Rudalics <[email protected]> + + Turn off combination resizing in 'window--transpose-1' (Bug#81406) + + * lisp/window-x.el (window--transpose-1): Bind + 'window-combination-resize' to nil around splitting (Bug#81406). + +2026-07-13 Eli Zaretskii <[email protected]> + + Fix copy-by-mouse in *Backtrace* buffers + + * lisp/emacs-lisp/backtrace.el (backtrace--filter-visible): + Support BEG and END in reverse order. Patch by Jakub + T. Jankiewicz <[email protected]>. (Bug#81365) + +2026-07-11 Kisaragi Hiu <[email protected]> + + Support javascript "using" keyword (bug#81351) + + * lisp/progmodes/js.el: + (js--keyword-re): Add "using" as a JavaScript keyword. + (js--font-lock-keywords-3, js--declaration-keyword-re): + Add "using" as a variable declaration keyword, like "const". + (js--treesit-optional-keywords): New variable, for keywords that may not + yet be supported by many versions of tree-sitter-javascript. + (js--treesit-font-lock-settings): Use it. + (js--treesit-defun-name, js--treesit-valid-imenu-entry) + (js--treesit-sentence-nodes, js--treesit-simple-imenu-settings) + (js--treesit-defun-type-regexp): Add using_declaration as an alternative + to lexical_declaration (let and const) and variable_declaration (var). + + * lisp/progmodes/typescript-ts-mode.el (typescript-ts-mode--keywords): + Add "using" as a TypeScript keyword. + +2026-07-10 Juri Linkov <[email protected]> + + Ensure the correct current buffer in completions--background-update + + * lisp/minibuffer.el (completions--background-update): + Add new arg 'buffer' and compare it with 'current-buffer'. + (completions--start-background-update): Run an idle timer + for 'completions--background-update' with a new arg + set to 'current-buffer' that ensures that the timer function + is run in the same buffer (bug#81349). + +2026-07-09 Daniel Mendler <[email protected]> + + Improve eldoc-help-at-pt docstrings + + * lisp/emacs-lisp/eldoc.el (eldoc-help-at-pt, eldoc-show-help-at-pt): + Improve docstrings. (Bug#81356) + +2026-07-09 Daniel Mendler <[email protected]> + + Fix 'eldoc-show-help-at-pt' + + * lisp/emacs-lisp/eldoc.el (eldoc-show-help-at-pt): Don't test + 'eldoc-help-at-pt'. (Bug#81356) + +2026-07-07 Paul Eggert <[email protected]> + + Fix uninit read in Android TrueType font scan + + Problem reported privately by Michal Majchrowicz and Marcin + Wyczechowski, members of the AFINE Team. + * src/sfnt.c (sfnt_read_table_directory): + Fix typo where wrong size was used. + +2026-07-07 Paul Eggert <[email protected]> + + Fix OOB read in Android TrueType font scan + + Problem reported privately by Michal Majchrowicz and Marcin + Wyczechowski, members of the AFINE Team. + * src/sfnt.c (sfnt_vary_simple_glyph, sfnt_vary_compound_glyph): + Reject indexes equal exactly to sizes. + +2026-07-07 Martin Rudalics <[email protected]> + + Have 'replace-buffer-in-windows' remove BUFFER-OR-NAME everywhere (Bug#81370) + + * lisp/window.el (replace-buffer-in-windows): Unrecord + BUFFER-OR-NAME and thus remove it from the lists of previous and + next buffers in all live windows regardless of whether they + currently show BUFFER-OR-NAME or not (Bug#81370). + +2026-07-07 Juri Linkov <[email protected]> + + Fix test breakage in files-tests + + * test/lisp/files-tests.el (files-tests--with-buffer-offer-save): + Redefine 'read-key-sequence-vector' instead of 'read-key' + after recent changes in 'map-y-or-n-p' (bug#81168). + +2026-07-07 Juri Linkov <[email protected]> + + Check for a live buffer in 'quit-restore-window' + + * lisp/window.el (quit-restore-window): + Check with 'buffer-live-p' when finding a prev buffer + in 'window-prev-buffers' (bug#81370). + +2026-07-07 Daniel Mendler <[email protected]> + + Fix blinking Eldoc messages + + Ensure that `global-eldoc-mode' does not enable `eldoc-mode' in + ephemeral Eldoc buffers and accidentally reset `eldoc-last-message'. + This caused Eldoc message blinking (bug#81356). + + * lisp/emacs-lisp/eldoc.el (eldoc--supported-p): Exclude ephemeral Eldoc + buffers to avoid blinking. + (eldoc-help-at-pt): Add custom :set function. + (eldoc-documentation-functions): Do not register `eldoc-show-help-at-pt' + by default. + +2026-07-06 Paul Eggert <[email protected]> + + Fix undefined behavior in pbm_load + + int*int problem reported by Tristan Madani in: + https://bugs.gnu.org/81344 + * src/image.c (pbm_load): Avoid undefined behavior when + multiplying ints, or when adding pointer to int. + +2026-07-05 Philip Kaludercic <[email protected]> + + Avoid destructively modifying 'package--builtin-alist' + + * lisp/emacs-lisp/package.el (package--upgradeable-packages): + Use 'append' instead of 'nconc' to not append the contents of + 'package-alist' to 'package--builtin-alist'. (Bug#81242) + +2026-07-05 Kyle Meyer <[email protected]> + + Update to Org 9.8.7 + +2026-07-05 Michael Albinus <[email protected]> + + Ensure, that `buffer-file-name' is expanded in tramp-archive + + * lisp/net/tramp-archive.el (tramp-archive-handle-insert-file-contents): + Ensure, that `buffer-file-name' is expanded. + +2026-07-04 Eli Zaretskii <[email protected]> + + Fix min-width in mode-line constructs + + * src/xdisp.c (handle_display_prop): To handle min-width's end on + the mode line, call display_min_width also when starting a new + string. This is needed because mode line supports :propertize + application to a list of strings, and we only need to apply the + effect of min-width at the end of the last element. (Bug#81354) + +2026-07-03 Binbin Ye <[email protected]> (tiny change) + + Fix syntax of tsx tag angle brackets to use matching pairs + + The matching characters for JSX tag angle brackets were + self-referential ('<' matched '<', and '>' matched '>') rather than + pointing at each other. Tools that check the matching character, such + as 'show-paren-mode' and the rainbow-delimiters package, therefore + treated every JSX closing '>' as a mismatched delimiter. Use the same + descriptors as 'sgml-make-syntax-table', where '<' is closed by '>' + and '>' by '<' (bug#81348). + + * lisp/progmodes/typescript-ts-mode.el + (tsx-ts--syntax-propertize-captures): Give '<' the syntax descriptor + "(>" and '>' the descriptor ")<". + +2026-07-03 Samuele FAVAZZA <[email protected]> (tiny change) + + Fix Tramp container name completion + + * lisp/net/tramp-container.el (tramp-container--completion-function): + Use "<>" as separator instead of "\t", which could be modified in + the shell. + +2026-07-03 Sean Whitton <[email protected]> + + server-tests/can-create-frames-p: Check for TERM=dumb-emacs-ansi + + * test/lisp/server-tests.el (server-tests/can-create-frames-p): + Check for TERM=dumb-emacs-ansi. + +2026-07-03 Sean Whitton <[email protected]> + + Disable failing SCCS tests on the release branch + + These are broken and we don't have an SCCS expert to fix them at + present. This shouldn't block the Emacs 31 release because SCCS + is a relatively obscure VCS. + + * test/lisp/vc/vc-tests/vc-tests.el (vc-test-sccs05-rename-file) + (vc-test-sccs10-rename-directory): Mark as expected to fail. + Do not merge to master. + +2026-07-03 Sean Whitton <[email protected]> + + Finish reverting experiment with proportional font on mode line + + This change + + Author: Lars Ingebrigtsen <[email protected]> + AuthorDate: Thu Dec 23 11:43:47 2021 +0100 + + Revert back to using monospaced fonts in the mode line + + * lisp/faces.el (mode-line-active, mode-line-inactive): Revert + back to using monospaced fonts on the mode line (for now). The + main remaining usability problem is clicking on the very small "-" + characters in "U:--". + + didn't also undo these changes to bindings.el that were + introduced along with the proportional font experiment, leading + to bug#81336. + + * lisp/bindings.el (mode-line-position) + (standard-mode-line-format): Don't set display minimum widths (bug#81336). + +2026-07-03 Alan Mackenzie <[email protected]> + + CC Mode: Fix erroneous type: arguments to two defcustoms. + + This allows customize to set the variables directly to regular + expressions as an alternative to a list of identifiers. It + fixes bug#81339. + * lisp/progmodes/cc-vars.el (c-noise-macro-with-parens-names) + (c-noise-macro-names): Correct the type: arguments to defcustom + to two `choice' constructs. + +2026-07-02 Spencer Baugh <[email protected]> + + Fix initials completion style after // in file name + + * lisp/minibuffer.el (completion-initials-expand): Change the + heuristic to check for an empty previous field, not total string + length (bug#81241). + * test/lisp/minibuffer-tests.el (completion-initials): New test. + +2026-07-02 Spencer Baugh <[email protected]> + + Fix c-pcm-try-completion with boundaries completion + + PCM try-completion could behavior incorrectly with completion + tables using boundaries, such as file name completion. It would + "grow" earlier path components as if point was at the end of + each path component (rather than at its true location), which + meant all path components would "grow" not only from the left + \(which is correct) but also from the right (which can only work + when point is there). + + * lisp/minibuffer.el (completion-pcm--find-all-completions): + Drop the sub-pattern's trailing `point' (bug#80914). + * test/lisp/minibuffer-tests.el (completion-pcm-test-9): New + test. + +2026-07-02 haiyang miao <[email protected]> (tiny change) + + In pgtk_free_frame_resources transfer keyboard focus to parent (Bug#64625) + + * src/pgtkterm.c (pgtk_new_focus_frame): Declare static. + (pgtk_free_frame_resources): If this frame currently holds + keyboard focus, explicitly transfer focus to its parent frame + before releasing resources (Bug#64625). + +2026-07-02 Johan Myréen <[email protected]> (tiny change) + + Fix fullscreen state handling for PGTK (Bug#81165, Bug#81320) + + * src/pgtkterm.c (set_fullscreen_state): Unfullscreen frame in + the FULLSCREEN_HEIGHT/_WIDTH case (Bug#81165, Bug#81320). + +2026-07-02 Dmitry Gutov <[email protected]> + + * lisp/progmodes/project.el: Update Commentary. + +2026-07-02 Dmitry Gutov <[email protected]> + + Localize cache invalidation to project-try-vc + + With other functions only using the cached values or populating + when necessary. + + * lisp/progmodes/project.el: Update commentary (bug#81317). + (project--get-cached): Add explicit parameter TIMEOUT, use it. + (project-try-vc): Build its value from 'non-essential' and the + values of two timeout variables. And pass them on. + (project-try-vc--search, project--vc-merge-submodules-p) + (project--value-in-dir): Also add TIMEOUT. + (project-files, vc-git-project-list-files) + (vc-hg-project-list-files, project-ignores, project-buffers) + (project-name, project-uniquify-dirname-transform): Remove the + binding of 'non-essential' as now redundant for cache duration. + + * test/lisp/progmodes/project-tests.el (project-try-vc-uses-cache) + (project-try-vc-invalidates-cache) + (project-name-<vc>-reuses-cache) + (project-name-<vc>-obeys-cache-invalidation): New tests. + (project-vc-supports-project-in-different-dir) + (project-vc-ignores-in-external-directory): Use + 'project--clear-cache' as the more reliable option. + +2026-07-02 Dmitry Gutov <[email protected]> + + Fix project--clear-cache and project--value-in-dir in special case + + * lisp/progmodes/project.el (project--clear-cache): Make sure to + clear the 'project-vc-dir-locals' keys too. + (project--value-in-dir): Predicate the cache lookup (and most + importantly, write) on whether enable-dir-local-variables is + non-nil. So its uses inside recursive 'project-try-vc--search' + call do not not bust the value (bug#81317). + +2026-07-01 Michael Albinus <[email protected]> + + * admin/notes/jargon: Add TTTT. + +2026-07-01 Michael Albinus <[email protected]> + + Fix error handling in Tramp delete-{file,directory} + + * lisp/net/tramp-smb.el (tramp-smb-handle-delete-directory): + * lisp/net/tramp.el (tramp-skeleton-delete-directory): Fail if + DIRECTORY is missing. + (tramp-skeleton-delete-file): Don't fail if DIRECTORY is missing. + + * test/lisp/net/tramp-tests.el (tramp-test14-delete-directory): + Adapt test. + +2026-07-01 Michael Albinus <[email protected]> + + Change Tramp version integrated in Emacs 31.1 (don't merge) + + * doc/misc/trampver.texi: + * lisp/net/trampver.el (tramp-version): Adapt Tramp versions. + + * lisp/net/trampver.el (customize-package-emacs-version-alist): + Change Tramp version integrated in Emacs 31.1. + +2026-07-01 Yuan Fu <[email protected]> + + Correct cursor range in Ftreesit_query_capture (bug#81297) + + * src/treesit.c (Ftreesit_query_capture): Always explicitly set + cursor's range. + +2026-06-30 Sean Whitton <[email protected]> + + vc-dir-update: Remove assertion invalid on this branch + + * lisp/vc/vc-dir.el (vc-dir-update): Remove assertion invalid on + the emacs-31 branch. Do not merge to master. + +2026-06-30 Martin Rudalics <[email protected]> + + Don't use window manager activation when a child frame has focus (Bug#81326) + + * src/xterm.c (x_get_toplevel_parent): Remove. + (x_focus_frame): Never call x_ewmh_activate_frame when a child + frame has focus (Bug#81326). + +2026-06-29 Philip Kaludercic <[email protected]> + + Compile User Lisp files after adjusting 'load-path' + + * lisp/startup.el (prepare-user-lisp): Collect Lisp files in a + list and process these after traversing the file system. This + is necessary to prevent the compiler from failing to + byte-compile files that depend on other files in the User Lisp + directory because their neighboring dependencies cannot be + located. (Bug#81304) + +2026-06-29 Sean Whitton <[email protected]> + + Fix strange logic in vc-git-incoming-revision + + I think that I didn't fully update this function in this change: + + commit e915646b8944d8b611ab7094d9eb305ed162ff27 + Author: Sean Whitton <[email protected]> + Date: Wed Feb 18 11:35:16 2026 +0000 + + vc-git-pull, vc-git-incoming-revision: Use push remotes + + * lisp/vc/vc-git.el (vc-git-pull, vc-git-incoming-revision): Use + configured push remotes. + * etc/NEWS: Announce change to vc-git-pull. + + * lisp/vc/vc-git.el (vc-git-incoming-revision): Don't duplicate + looking for a branch remote after just having called + vc-git--branch-remotes (bug#81328). + +2026-06-28 Eli Zaretskii <[email protected]> + + Fix 'format-mode-line' when faces are in format string + + * src/xdisp.c (store_mode_line_string): Don't assume that PROPS + can only specify the face for LISP_STRING; if PROPS don't specify + a face, fall back on the 'face' property of LISP_STRING. + (Bug#81316) + + * test/src/xdisp-tests.el (xdisp-test-format-mode-line): Add a + test for this issue. + +2026-06-28 Martin Rudalics <[email protected]> + + Restore frame's fullheight/fullwidth after exiting from fullboth (Bug#81165) + + * src/xterm.c (do_ewmh_fullscreen): Try to restore + fullheight/fullwidth states after exiting from fullboth state + (Bug#81165). + +2026-06-27 Zhengyi Fu <[email protected]> (tiny change) + + Fix interactive mode spec of `xwidget-webkit-end-edit-textarea' + + * lisp/xwidget.el (xwidget-webkit-end-edit-textarea): Remove + `xwidget-webkit-mode' condition from the interactive mode spec. + This command is intended to be invoked in the 'textarea' buffer, + which is created by `xwidget-webkit-begin-edit-textarea', and + that buffer is in Fundamental mode. (Bug#81306) + +2026-06-27 Andrea Alberti <[email protected]> + + Fix pixels-vs-columns confusion in margin face fill (bug#81109) + + * src/xdisp.c (extend_face_to_end_of_line): WINDOW_LEFT/RIGHT_MARGIN_WIDTH + is a pixel value (columns times the frame column width). Compare the + margin glyph count against WINDOW_LEFT/RIGHT_MARGIN_COLS instead, and use + the *_WIDTH value directly for remaining_pixels rather than multiplying it + by FRAME_COLUMN_WIDTH a second time. The old code worked on text + terminals, where the column width is one pixel, but computed wrong widths + on GUI frames. + +2026-06-27 Richard Lawrence <[email protected]> + + Fix ISO date insertion in diary + + See Bug#81263. Diary's 'iso' dates should use ISO8601 YYYY-MM-DD + format. This change fixes the format used by `diary-insert-entry'. + + * lisp/calendar/calendar.el (diary-iso-date-insertion-form): Use + YYYY-MM-DD format (not YYYY/M/D) when inserting ISO dates. + * test/lisp/calendar/diary-icalendar-resources/import-bug-11473.diary-iso: + * test/lisp/calendar/diary-icalendar-resources/import-bug-22092.diary-iso: + * test/lisp/calendar/diary-icalendar-resources/import-bug-33277.diary-iso: + * test/lisp/calendar/diary-icalendar-resources/import-legacy-vars.diary-iso: + * test/lisp/calendar/diary-icalendar-resources/import-multiple-vcalendars.diary-iso: + * test/lisp/calendar/diary-icalendar-resources/import-non-recurring-1.diary-iso: + * test/lisp/calendar/diary-icalendar-resources/import-non-recurring-all-day.diary-iso: + * test/lisp/calendar/diary-icalendar-resources/import-non-recurring-another-example.diary-iso: + * test/lisp/calendar/diary-icalendar-resources/import-non-recurring-folded-summary.diary-iso: + * test/lisp/calendar/diary-icalendar-resources/import-non-recurring-long-summary.diary-iso: + * test/lisp/calendar/diary-icalendar-resources/import-time-format-12hr-blank.diary-iso: + * test/lisp/calendar/diary-icalendar-resources/import-with-attachment.diary-iso: + * test/lisp/calendar/diary-icalendar-resources/import-with-timezone.diary-iso: + * test/lisp/calendar/diary-icalendar-resources/import-with-uid.diary-iso: + Update tests. + +2026-06-27 Eli Zaretskii <[email protected]> + + Minor fix for 'format-mode-line' + + * src/xdisp.c (Fformat_mode_line): Treat 'default' exactly like + nil. (Bug#81307) + +2026-06-26 Juri Linkov <[email protected]> + + Improve the previous fix in toggle-window-dedicated + + * lisp/window.el (toggle-window-dedicated): + Don't select the window by mouse click in another window. + This keeps the currently selected window like for + toggling other indicators on the mode-line (bug#81178). + +2026-06-25 Sean Whitton <[email protected]> + + VC-Dir: Fix removing empty directory entries + + * lisp/vc/vc-dir.el (vc-dir-refresh-files): Do another pass to + remove directory entries with no children. Do not merge to + master. + +2026-06-25 Juri Linkov <[email protected]> + + Fix interactive spec of some commands bound on the mode line + + Use interactive spec '@' for two commands bound on the mode line + that should select the window associated with the mouse click + to avoid toggling the status of the wrong window or buffer. + + * lisp/progmodes/elisp-mode.el (elisp-enable-lexical-binding): + Add interactive spec '@' (bug#81178). + + * lisp/window.el (toggle-window-dedicated): Add interactive + spec '@' and replace 'current-buffer' with 'window-buffer' + to not assume that it operates on the current buffer. + +2026-06-25 Sean Whitton <[email protected]> + + vc-dir--count-outgoing: Bind enable-local-variables + + * lisp/vc/vc-dir.el (vc-dir--count-outgoing): Bind + enable-local-variables (bug#81233). Do not merge to master. + +2026-06-25 Michael Albinus <[email protected]> + + Support tramp-rpc in filenotify-tests.el + + * test/lisp/filenotify-tests.el (top, file-notify--test-monitor) + (file-notify-test03-events, file-notify-test12-unmount): + Handle also tramp-rpc. + +2026-06-25 Alan Mackenzie <[email protected]> + + CC Mode: Set parse-sexp-lookup-properties for every mode + + This fixes a bug reported and diagnosed by Campbell Barton + <[email protected]> on the emacs-devel list. + + * lisp/progmodes/cc-mode.el (c-basic-common-init): Set + parse-sexp-lookup-properties or (for XEmacs) lookup-syntax-properties + for every CC Mode mode. + +2026-06-25 Dirk-Jan C. Binnema <[email protected]> (tiny change) + + Disable DMABUF and Compositing for xwidget + + Webkit does not support DMABUF or accelerated compositing in the + offscreen widgets Emacs uses for xwidget. Disable both for non-pgtk + GTK3 builds (Bug#80834). + * src/xterm.c (init_xterm): Set WEBKIT_DISABLE_DMABUF_RENDERER and + WEBKIT_DISABLE_COMPOSITING_MODE when built with xwidgets and not pgtk. + +2026-06-25 Eli Zaretskii <[email protected]> + + Fix failure code in 'run-hook-query-error-with-timeout' + + * lisp/subr.el (run-hook-query-error-with-timeout): Fix incorrect + call to 'error'. (Bug#81292) + +2026-06-25 Zhengyi Fu <[email protected]> (tiny change) + + Use default-value in project--value-in-dir + + When in a VC project whose dir-locals file specifies `project-vc-name', + the function `project--value-in-dir' previously used `symbol-value' to + retrieve the variable value, causing `project-name' to return the same + name for all VC projects without an explicit `project-vc-name'. Use + `default-value' instead to correctly fall back to the default value. + + * lisp/progmodes/project.el (project--value-in-dir): Replace `symbol-value' + with `default-value' (bug#81293). + +2026-06-24 Dmitry Gutov <[email protected]> + + etags-regen--maybe-generate: No error when no project found + + * lisp/progmodes/etags-regen.el (etags-regen--maybe-generate): + When no project found, abort cleanly with a message. + +2026-06-24 Stephen Berman <[email protected]> + + Mark ChangeLog entry as tiny change + + * ChangeLog.5: Mark an entry as a tiny change, because the + "Copyright-paperwork-exempt: yes" line was mistakenly omitted from + the commit log entry. + +2026-06-24 Sean Whitton <[email protected]> + + VC revert: When un-adding, clear vc-backend property + + * lisp/vc/vc.el (vc-revert-file, vc-revert-files): When + un-adding, clear vc-backend property (bug#81291). + +2026-06-24 Martin Rudalics <[email protected]> + + Document new option 'delete-frame-choose-selected' (Bug#80397) + + * doc/lispref/frames.texi (Deleting Frames): Document new option + 'delete-frame-choose-selected'. + * etc/NEWS: Mark 'delete-frame-choose-selected', 'split-frame' + and 'merge-frames' as documented. + +2026-06-23 Martin Rudalics <[email protected]> + + Document 'split-frame' and 'merge-frames' in Elisp manual + + * doc/lispref/frames.texi (Splitting and Merging Frames): New + section. + * doc/lispref/elisp.texi (Top): Add new section. + * doc/lispref/windows.texi (Basic Windows): Explain terms + 'layout' and 'identity' of windows. + (Window Configurations): Explain that window identities are + preserved by window configurations and get lost with window + states. + +2026-06-23 Sean Whitton <[email protected]> + + Eglot: release version 1.24 + + * lisp/progmodes/eglot.el (Version): Bump to 1.24. + + * etc/EGLOT-NEWS: Announce new version. + +2026-06-23 Sean Whitton <[email protected]> + + Jsonrpc: release version 1.0.29 + + (Version): Bump to 1.0.29. + +2026-06-23 João Távora <[email protected]> + + jsonrpc-shutdown: Ensure we wait whole timeout & increase timeout + + * lisp/jsonrpc.el (jsonrpc-shutdown): Ensure that we wait for + the whole timeout and increase the timeout to 300ms (bug#80140). + +2026-06-23 Sean Whitton <[email protected]> + + vc-hg-state-slow: Run from the repository root + + * lisp/vc/vc-hg.el (vc-hg-state-slow): Run command from the + repository root. This fixes cases where a whole subdirectory no + longer exists. We should return 'missing' for any files within + it. + +2026-06-23 Sean Whitton <[email protected]> + + vc-dir-delete-file: Call vc-delete-file on FILESET-ONLY-FILES + + * lisp/vc/vc-dir.el (vc-dir-delete-file): Call vc-delete-file on + FILESET-ONLY-FILES. See bug#80998. + +2026-06-23 Stéphane Marks <[email protected]> + + Fix 'truncate-string-pixelwise' to restore the window buffer + + * lisp/emacs-lisp/subr-x.el (truncate-string-pixelwise): Safely + save/restore the selected window's buffer, and not the reference + or current buffers. Guard dedicated windows. Remove the work + buffer from the window's buffer list. Bind + 'buffer-list-update-hook' 'window-scroll-functions' + 'window-configuration-change-hook' to nil around the window + buffer swap. (Bug#81262; see also bug#80244.) + +2026-06-23 Stéphane Marks <[email protected]> + + Restore progress-reporter suffix as update-text (bug#81134) + + * lisp/subr.el (progress-reporter-update-functions): Update + docstring. + (progress-reporter-update): New UPDATE-TEXT argument replacing + previously deleted SUFFIX. + (make-progress-reporter): Document suffix slot available for + reuse. + (progress-reporter-force-update): Update function signature. + (progress-reporter-echo-area): Restore the text argument and + echo it. + (progress-reporter-do-update): Update function signature. Treat + UPDATE-TEXT as ephemeral and do not persist it in the reporter + instance. Update the hook. + (progress-reporter-done): Update the hook. + * lisp/system-taskbar.el + (system-taskbar--progress-reporter-update): Update function + signature. + * lisp/net/tramp.el (tramp-progress-reporter-update): Update + function signature. + * doc/lispref/display.texi (Progress): Update documentation. + +2026-06-22 Juri Linkov <[email protected]> + + Rename recently added after-delete-frame-select-mru-frame + + Rename 'after-delete-frame-select-mru-frame' to + 'delete-frame-choose-selected' for symmetry with + 'delete-window-choose-selected' with the same + default value 'mru' (bug#80397). + + * lisp/cus-start.el: Add a choice like in + 'delete-window-choose-selected'. + + * src/frame.c (delete_frame): Compare delete_frame_choose_selected + with Qmru. + (syms_of_frame): Define symbol Qmru. + Use DEFVAR_LISP for 'delete-frame-choose-selected' + and set the default value to Qmru. + +2026-06-22 duli <[email protected]> (tiny change) + + Eglot: decode unhexed file URI paths as UTF-8 (bug#79897) + + 'url-unhex-string' only decodes %XX sequences and returns a + unibyte string; it does not interpret the resulting octets as + UTF-8. Its docstring says that the resulting string generally + requires decoding with an appropriate coding system. + + LSP messages are UTF-8, and document URIs are transferred as URI + strings. When recovering the file path from the URI, decode the + unhexed octets as UTF-8 instead of using them directly as an + Emacs string. This should fix bug#79897. + + + * lisp/progmodes/eglot.el (eglot-uri-to-path): Decode the + result of 'url-unhex-string' with 'utf-8-unix'. + +2026-06-22 Michael Albinus <[email protected]> + + Sync with Tramp 2.8.2 + + * lisp/net/tramp-message.el (tramp-trace-add-package): New defun. + + * lisp/net/tramp-smb.el (tramp-smb-maybe-open-connection): + Remove superfluous comment. + + * lisp/net/tramp.el (tramp-restricted-shell-hosts-alist): + Use `file-name-sans-extension'. + (tramp-completion-handle-expand-file-name): + Apply `tramp-drop-volume-letter' consequently. + + * test/lisp/net/tramp-tests.el + (tramp--test-ignore-make-symbolic-link-error): Use `file-error' + instead of `remote-file-error' + (tramp--test-instrument-test-case-p): Fix doxstring. + (tramp-test10-write-region-other-file-name-handler) + (tramp-test49-external-backend-function): Adapt tests. + +2026-06-22 Sean Whitton <[email protected]> + + Rename variable to macroexp-enable-preserve-posification + + * lisp/emacs-lisp/macroexp.el + (macroexp-enable-pos-preservation): Rename ... + (macroexp-enable-preserve-posification): ... to this. All uses + changes. + +2026-06-22 Eshel Yaron <[email protected]> + + New variable 'macroexp-enable-pos-preservation' (bug#79599) + + * lisp/emacs-lisp/macroexp.el + (macroexp-enable-pos-preservation): New variable. + (macroexp-preserve-posification): Respect it. + * lisp/emacs-lisp/elisp-scope.el (elisp-scope-1): Use it. + * test/lisp/emacs-lisp/macroexp-tests.el + (macroexp--test-macroexp-enable-pos-preservation): New test. + +2026-06-21 milkvetch <[email protected]> (tiny change) + + Avoid infinite loop in some Dired marking commands + + These commands use dired-get-filename inside a dired-mark-if form; + when the bottom subdirectory is hidden, dired-get-filename makes + it so the dired-mark-if loop never reaches the end of the buffer. + This is fixed by skipping hidden subdirectories (bug#80964). + + * lisp/dired.el (dired-mark-files-regexp) + (dired-mark-files-containing-regexp): + * lisp/dired-x.el (dired-mark-unmarked-files): + * lisp/dired-aux.el (dired-compare-directories): Skip hidden subdirectories. + +2026-06-20 Eli Zaretskii <[email protected]> + + Resurrect effect of 2nd arg t in 'format-mode-line' + + * src/xdisp.c (Fformat_mode_line): Resurrect support for FACE = t. + Doc fix. (Bug#81271) + + * doc/lispref/modes.texi (Emulating Mode Line): Fix documentation + of 'format-mode-line' when 2nd argument is t. + + * test/src/xdisp-tests.el (xdisp-test-format-mode-line): New test. + +2026-06-20 Eli Zaretskii <[email protected]> + + Fix 'format-mode-line' for integer second argument + + * src/xdisp.c (Fformat_mode_line): Test for integers with + INTEGERP. (Bug#81272) + +2026-06-20 Stéphane Marks <[email protected]> + + markdown-ts-mode: fix code block and table overlays (bug#81195) + + Fix to eliminate erroneous multiple code block overlays. Fixes + to deal with 'treesit' fontification catching up to + user-initiated code block range expansions; e.g., inserting, + yanking. Set overlay properties only once. + + * lisp/textmodes/markdown-ts-mode.el + (markdown-ts--fontify-code-block): Use 'overlays-in' not + 'overlays-at'. Use only overlays, eliminate markers. + (markdown-ts--enable-code-block-in-context-mode): Add 'sit-for' + to allow 'treesit' to catch up (pending input should not be an + issue). + (markdown-ts--run-command-in-code-block): Use overlays instead + of 'get-char-property'. + (markdown-ts--code-block-in-context-mode-update-ov): Use + overlays instead of 'get-char-property'. Set overlay properties + only once. + (markdown-ts--in-table-mode-update-ov): Set overlay properties + only once. + +2026-06-20 Stéphane Marks <[email protected]> + + markdown-ts-mode: Fix computing code block current region (bug#81219) + + This ensures that commands such as 'comment-or-uncomment-region' + operate on the correct region in the work buffer. + + * lisp/textmodes/markdown-ts-mode.el (markdown-ts--run-command-in-code-block): + Fix adj-region-beg and adj-region-end. + +2026-06-20 Oleksandr Makhmudov <[email protected]> (tiny change) + + Eglot: add 'nu-ts-mode' as a nushell major mode + + 'nu-ts-mode' is an alternative tree-sitter-based major mode for + nushell. This commit adds it to the list of major modes that run + the nushell language server. + * lisp/progmodes/eglot.el (eglot-server-programs): Add 'nu-ts-mode'. + (Bug#81206) + +2026-06-20 समीर सिंह Sameer Singh <[email protected]> + + Fix c-ts-mode bsd-style indentation of union bodies (bug#81255) + + * lisp/progmodes/c-ts-mode.el (c-ts-mode--simple-indent-rules): Add + "union_specifier" to the parent-is regexp. + + * test/lisp/progmodes/c-ts-mode-resources/indent-bsd.erts: New test. + +2026-06-20 Yuan Fu <[email protected]> + + Fix markdown-inline incremental parsing issue (bug#81019) + + * lisp/treesit.el: + (treesit--embed-languages-need-full-parse): New variable. + (treesit--set-embed-ranges): Reparse full range if the langauge + needs it. + +2026-06-19 Stephen Berman <[email protected]> + + Avoid an unusual error when visiting a directory in Dired + + * lisp/dired.el (dired-internal-noselect): Unset + 'dired--ls-error-buffer' before calling 'dired-readin'. This is a + safeguard to prevent an error when visiting a directory in Dired, + which apparently happens when the variable somehow gets set even + though 'ls' has not emitted an error message (bug#80499, Message #218). + + * test/lisp/dired-tests.el (dired-test-set-dired--ls-error-buffer): New test. + +2026-06-19 Dmitry Gutov <[email protected]> + + Fix "diff-apply-buffer applies to the wrong file" + + * lisp/vc/diff-mode.el (diff-find-file-name): Inhibit the "drop + dir" behavior in diffs produced by Git and Hg (bug#81210). + Except for the virtual subdirectories like a/b/etc, which is + moved and happens for all such diffs. Tighten the check for + such virtual directory names, though (characters are the chars + used by the configuration option 'diff.mnemonicPrefix'). + (diff-setup-buffer-type): Recognize Hg diffs where only one + revision is specified, too. + + * test/lisp/vc/diff-mode-tests.el + (diff-mode-test-setup-buffer-type) + (diff-mode-test-find-file-name-create): New tests. + +2026-06-18 Martin Rudalics <[email protected]> + + Fix thinko in 'set-frame-size-and-position' (Bug#81193) + + * lisp/frame.el (set-frame-size-and-position): Do not subtract + scoll bar, fringes and internal border sizes twice (Bug#81193). + +2026-06-17 JD Smith <[email protected]> + + Correct default native-comp tests + + Supersedes 5bd9d1f7df3. + + * configure.ac: Store `with_native_compilation' to correctly test + whether to use the soft or hard (error) checks, as these set the + variable by side-effect. + +2026-06-16 JD Smith <[email protected]> + + Revert "Fix the Android build" + + This reverts commit 916572f6e0ab3e36f7098b6d9b5ff19f87240da4, in favor + of another fix. + +2026-06-16 Stefan Monnier <[email protected]> + + (comint--intersect-regions): Fix bug#81243 + + * lisp/comint.el (comint--intersect-regions): Fix syntax-propertization. + +2026-06-14 Kyle Meyer <[email protected]> + + Update to Org 9.8.6 + +2026-06-13 Stefan Monnier <[email protected]> + + src/keyboard.c (Finsert_special_event): Don't ignore unknown events + +2026-06-13 João Távora <[email protected]> + + Eglot: restore compatibility to Emacs 26.3 + + Github-reference: https://github.com/joaotavora/eglot/discussions/1591 + + Can't use setf plist-get. + + * lisp/progmodes/eglot.el (eglot--async-request): Use cl-getf. + +2026-06-12 Martin Rudalics <[email protected]> + + Fix behavior of 'temp-buffer-resize-mode' (Bug#81207) + + * lisp/help.el (temp-buffer-resize-mode): Fix doc-string - a + window can be resized now even if it has shown another buffer in + between (Bug#81207). + (resize-temp-buffer-window): Resize window if and only if its + buffer is the buffer it has shown initially (Bug#81207). + +2026-06-11 Xiyue Deng <[email protected]> + + Restore public interfaces for accessing built-in package info + + These functions were removed in ab36f5892203e4b1f59da7c995e0f1fa0a81d1b6 + during the reorganization of package.el as part of Bug#80079. + + Also add a simple test for these functions to avoid future regressions. + + See also discussion at + https://lists.gnu.org/archive/html/emacs-devel/2026-06/msg00149.html. + + * lisp/emacs-lisp/package.el (package-versioned-builtin-packages, + package-builtin-package-version): Restore. + * lisp/emacs-lisp/package-activate.el: Remove lingering comments. + * test/lisp/emacs-lisp/package-tests.el + (package-test-builtin-package-info): Add. + +2026-06-11 Philip Kaludercic <[email protected]> + + Allow uninstalling dependency with multiple installations + + * lisp/emacs-lisp/package.el (package--dependency-p): Add new + function to check if a package is a dependency. + (package-delete): Prompt user if it is OK to uninstall a package + that serves as a dependency, but where the package has multiple + installations. This also means that we don't de-select a + selected dependency if there are multiple installations. + + (Bug#81082) + +2026-06-11 Andrea Alberti <[email protected]> + + Fix memcpy size in 'merge_faces' + + * src/xfaces.c (merge_faces): Use 'sizeof lface_attrs' instead of + LFACE_VECTOR_SIZE as the 'memcpy' size argument. (Bug#81224) + +2026-06-11 Sean Whitton <[email protected]> + + Fix fontification in short unintegrated changes logs (bug#81215) + + Do not merge to master. + + * lisp/vc/vc.el (vc--shortlog): New variable. + (vc-print-log-internal): + * lisp/vc/vc-git.el (vc-git-log-view-mode): + * lisp/vc/vc-hg.el (vc-hg-log-view-mode): Use it. + +2026-06-11 Sean Whitton <[email protected]> + + * lisp/vc/vc.el (vc-log-remote-unintegrated): Set vc-log-view-type. + + Do not merge to master. + +2026-06-11 Sean Whitton <[email protected]> + + vc-hg-trunk-or-topic-p, vc-hg-topic-outgoing-base: Fix ret vals + + * lisp/vc/vc-hg.el (vc-hg-trunk-or-topic-p) + (vc-hg-topic-outgoing-base): Fix return values. + +2026-06-11 Stéphane Marks <[email protected]> + + markdown-ts-mode: Sanitize work-buffer pool + + This a workaround for the release branch due to the work-buffer + pool being insufficiently sanitized. + * lisp/textmodes/markdown-ts-mode.el + (markdown-ts--run-command-in-code-block): Reset 'mark-active'. + Do not merge to master. (Bug#81218) (Bug#81111) + +2026-06-10 Michael Albinus <[email protected]> + + Extend Tramp external operations + + * doc/misc/tramp.texi (New operations): Extend. + + * lisp/net/tramp.el (tramp-file-name-for-operation-external): + Extend docstring. + (tramp-file-name-for-operation): Make more use of + `tramp-file-name-for-operation-external'. + (tramp-add-external-operation): Support ARG-TYPE `tramp-file-name'. + + * test/lisp/net/tramp-tests.el (tramp-test49-external-backend-function): + Extend test. + +2026-06-10 Rahul Martim Juliato <[email protected]> + + markdown-ts-mode: fix duplicated menu entries (bug#81201) + + * lisp/textmodes/markdown-ts-mode.el + (markdown-ts-code-block-in-context-mode-map) + (markdown-ts-in-table-mode-map): Remove redundant :parent. + +2026-06-10 Sean Whitton <[email protected]> + + vc-dir-recompute-file-state: Change directory to DEF-DIR + + * lisp/vc/vc-dir.el (vc-dir-recompute-file-state): Change + directory to DEF-DIR before calling into the backend. + * test/lisp/vc/vc-tests/vc-test-misc.el + (vc-test-vc-dir-on-symlink): Test that the file has the right + state. + +2026-06-10 Pip Cet <[email protected]> + + Restore "interactive" when describing functions + + * lisp/help-fns.el (help-fns-function-description-header): Only + substitute "an" for "a", not for a longer BEG (bug#81203). + +2026-06-09 Stéphane Marks <[email protected]> + + Inhibit follow-link via `mouse-1' on the tab-bar (bug#81036) + + Prevent 'tab-bar' mouse clicks from being directed to the + current buffer, for example, in `dired-mode'. This prevents the + side effect that the clicked tab is erroneously closed. + + * lisp/mouse.el (mouse-on-link-p): Explicitly exempt clicks in + 'tab-bar' if there is a 'follow-link' property. + +2026-06-09 Juri Linkov <[email protected]> + + Fix the tab close button appearance when clicking (bug#76394) + + * src/xdisp.c (handle_tab_bar_click): Use the variable 'close_p' + to show mouse face as sunken/raised only when clicked + on the close button. Clicking elsewhere on the tab should not + change the close button's appearance using DRAW_MOUSE_FACE. + +2026-06-09 Peter Oliver <[email protected]> + + Install images with info documentation (bug#81204) + + * Makefile.in (info_misc): Install all files with .png and .jpg + extensions into the info directory (bug#81204). + +2026-06-09 Sean Whitton <[email protected]> + + vc-dir-recompute-file-state: Return nil state for nonexistent file + + * lisp/vc/vc-dir.el (vc-dir-recompute-file-state): Return nil + state for nonexistent file (bug#81191). + +2026-06-09 Sean Whitton <[email protected]> + + vc-test-vc-dir-on-symlink: Use vc-test--with-author-identity + + * test/lisp/vc/vc-tests/vc-tests.el (vc-hg-global-switches): + Declare. + (vc-tests-helpers): Require. + (vc-test--create-repo-function, vc-test--with-author-identity): + Move these from here ... + * test/lisp/vc/vc-tests/resources/vc-tests-helpers.el + (vc-test--create-repo-function, vc-test--with-author-identity): + ... to here. + (vc-hg-global-switches): + * test/lisp/vc/vc-tests/vc-test-misc.el (vc-hg-global-switches): + Declare. + (vc-dir, log-edit, vc-tests-helpers): Require. + (vc-test-vc-dir-on-symlink): Use vc-test--with-author-identity + and vc-test--create-repo-function. + +2026-06-08 Stéphane Marks <[email protected]> + + Fix M-RET in 'markdown-ts-in-table-mode-map' + + * lisp/textmodes/markdown-ts-mode.el + (markdown-ts-in-table-mode-map): Map 'M-RET' to + 'markdown-ts-table-insert-row-below' (bug#81196). + +2026-06-08 Sean Whitton <[email protected]> + + Fix recurrence of bug#80803 after changes in bug#80967 + + * lisp/vc/vc-dir.el (vc-dir-resynch-file): Pass only truenames + to vc-dir-recompute-file-state. + * test/lisp/vc/vc-tests/vc-test-misc.el (vc-git): Require. + (vc-test-vc-dir-on-symlink): New test. + +2026-06-08 Michael Albinus <[email protected]> + + Ensure Tramp backward compatibility + + * lisp/net/tramp.el (tramp-local-environment-variable-p): + Use `tramp-compat-funcall'. + +2026-06-07 Juri Linkov <[email protected]> + + Read a key sequence instead of a single key in 'map-y-or-n-p' + + This is necessary to correctly read keys like 'M-~' + used by 'save-some-buffers' that is two keys 'ESC ~' + on a tty. + + * doc/lispref/minibuf.texi (Multiple Queries): + Index 'y-or-n-p-use-read-key' for 'map-y-or-n-p'. + Mention using a key sequence instead of single keys. + + * lisp/emacs-lisp/map-ynp.el (map-y-or-n-p): + In the 'y-or-n-p-use-read-key' cond-branch, + use 'read-key-sequence-vector' instead of 'read-key'. + In the default cond-branch, use 'this-command-keys-vector' + instead of 'last-command-event'. In both cond-branches + use 'key-description' instead of 'single-key-description' + (bug#81168). + Instead of '(eq def nil)' check if chars are either nil + or an empty vector in noninteractive mode (bug#67836). + + * test/lisp/emacs-lisp/map-ynp-tests.el (test-map-ynp-kmacro): + Test separately nil/non-nil 'y-or-n-p-use-read-key'. + (test-map-ynp-keys): New test for complete coverage of + 'map-y-or-n-p'. + +2026-06-07 Eli Zaretskii <[email protected]> + + Avoid recursive error in debug-early in batch mode + + * lisp/emacs-lisp/debug-early.el (cl--generic-compiler): Defvar it. + (debug-early-backtrace): Bind it so as to avoid loading + byte-compiler; see the value of the variable in cl-generic.el. + Do not merge to master. (Bug#80916) + +2026-06-07 Eli Zaretskii <[email protected]> + + Remove from CC Mode code that modifies 'major-mode-remap-defaults' + + * lisp/progmodes/cc-mode.el: Remove code that adds to + 'major-mode-remap-defaults', as enabling and disabling tree-sitter + based modes now goes through 'treesit-enabled-modes'. + +2026-06-06 Pip Cet <[email protected]> + + Assert we don't double-free timers (bug#81108) + + * src/atimer.c (cancel_atimer): Assert that we found the timer. + +2026-06-06 Pip Cet <[email protected]> + + Don't cancel random timers in x_get_foreign_selection (bug#81108) + + * src/pgtkselect.c (pgtk_display_selection_waiting_message): + (pgtk_cancel_atimer): + (pgtk_get_foreign_selection): + * src/xselect.c (x_display_selection_waiting_message): + (x_cancel_atimer): + (x_get_foreign_selection): Use a pointer to a timer variable, which is + cleared when the timer runs or is otherwise cancelled. Don't cancel + the timer twice. + +2026-06-06 Pip Cet <[email protected]> + + Fix use-after-free in Ffuncall_with_delayed_message (bug#81108) + + * src/eval.c (with_delayed_message_display): + (with_delayed_message_cancel): + (Ffuncall_with_delayed_message): Use new temporary data + structure. Cancel timer at most once. + +2026-06-06 Andrea Alberti <[email protected]> + + Document 'margin' face as base for margin display strings (Bug#80693) + + * doc/lispref/display.texi (Displaying Faces): Note that the + underlying-text rule does not apply to strings displayed in the + display margins, and reword the margin-face bullet to describe + 'margin' as the base. + (Basic Faces): Note that the 'margin' face also provides the base + attributes for strings displayed in the margins. + (Display Margins): Drop a sentence that restated the preceding one + about unspecified attributes inheriting from 'margin'. + * etc/NEWS: Document the change for margin strings. + + Suggested by F. Jason Park <[email protected]>. + +2026-06-06 Augusto Stoffel <[email protected]> + + Improve prompting for mail sending by by 'report-emacs-bug' + + * lisp/mail/emacsbug.el (report-emacs-bug-hook): Don't ask about + mail sending options if 'message-server-alist' is set. (Bug#81176) + +2026-06-06 Po Lu <[email protected]> + + Fix the Android build + + * configure.ac: Don't test for libgccjit.h if a preceding test + have already concluded that native compilation is unavailable. + +2026-06-05 Andrea Alberti <[email protected]> + + Don't resurrect invisible child frames when rebuilding parent links + + On the NS port, -[EmacsWindow setParentChildRelationships] reattaches + every child frame to its parent via -addChildWindow:ordered:, which also + orders the child window onto the screen. This runs whenever the + parent/child relationships are rebuilt, e.g., when entering non-native + fullscreen, which allocates a fresh EmacsWindow whose initializer + rebuilds the relationships. A child frame that Emacs had made invisible + (e.g. a corfu/company completion popup) was thereby brought back as a + stale, non-responsive child frame. Emacs never repaints to clear it + because frame_redisplay_p trusts FRAME_VISIBLE_P on the NS port and + avoids dealing with the child frame when it is marked as invisible. + + Native fullscreen does not trigger this: -toggleFullScreen: hands off to + AppKit without allocating a new window, so the rebuild never runs. + + A hidden child frame is normally detached from its parent already: Emacs + hides it with -orderOut: (ns_make_frame_invisible), which per Apple's + documentation removes a child window from its parent before ordering it + out. The fix is therefore not to re-attach a child while it is + invisible; ns_make_frame_visible already reinstates the parent/child link + when the frame is shown again. + + * src/nsterm.m ([EmacsWindow setParentChildRelationships]): Only + re-attach a child window when the frame is marked visible. + (ns_make_frame_visible): Explain, with a reference to Apple's + documentation, why the parent/child link must be reinstated on show. + +2026-06-05 Stéphane Marks <[email protected]> + + Improve progress-reporter state to remove hard coded length (bug#80988) + + Remove hard-coded state range, now a monotonically increasing + integer. + + * lisp/subr.el (progress-reporter-update-functions): Update + docstring. + (progress-reporter-echo-area): Use + 'progress-reporter--pulse-characters' length. + (progress-reporter-do-update): Increase 'state' by 1 each pass. + * + lisp/system-taskbar.el (system-taskbar--progress-reporter-update): + Make steps independent of 'progress-reporter-echo-area' steps. + +2026-06-05 Arash Esbati <[email protected]> + + (tex-main-file): Add forgotten safety predicate (bug#81099) + + That variable is commonly set file-locally. + + * lisp/textmodes/tex-mode.el (tex-main-file): Add safety predicate. + +2026-06-05 Al Haji-Ali <[email protected]> + + Fix bug in latexenc when AUCTeX is loaded + + * lisp/international/latexenc.el + (latexenc-find-file-coding-system): Set file name correctly when + `TeX-master' is a string. (Bug#81099) + +2026-06-05 Stefan Monnier <[email protected]> + + paren.el: Fix part of bug#81035 + + * lisp/paren.el (show-paren--default): Syntax-propertize before narrowing. + +2026-06-05 Michael Albinus <[email protected]> + + Adapt Tramp version + + * lisp/net/trampver.el (customize-package-emacs-version-alist): + Add Tramp version integrated in Emacs 31.1. + + * doc/misc/trampver.texi: + * lisp/net/trampver.el (tramp-version): Adapt Tramp versions. + +2026-06-05 Augusto Stoffel <[email protected]> + + Check buffer-local value in tramp-local-environment-variable-p + + * lisp/net/tramp.el (tramp-local-environment-variable-p): Do it. + +2026-06-05 Sean Whitton <[email protected]> + + Bump Emacs version to 31.0.90 + + * README: + * configure.ac: + * exec/configure.ac: + * java/AndroidManifest.xml.in (Version-code): + * msdos/sed2v2.inp: + * nt/README.W32: Bump Emacs version to 31.0.90. + 2026-06-04 Stefan Monnier <[email protected]> message.el: Fix part of bug#81035 @@ -65759,7 +67200,7 @@ This file records repository revisions from commit 1cda0967b4d3c815fc610794ad6a8fc2b913a3c5 (exclusive) to -commit 5e3e1a5bb23b5e7813a60c2b121b1393ff6ca86f (inclusive). +commit 1bd56ff93273f754e72e9a50cbefae3b218d2260 (inclusive). See ChangeLog.4 for earlier changes. ;; Local Variables: diff --git a/Makefile.in b/Makefile.in index 1c5bbc9ce2e..370eb00d27c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -809,7 +809,7 @@ install-info: info done; \ (cd "$${thisdir}"; \ ${INSTALL_INFO} --info-dir="$(DESTDIR)${infodir}" "$(DESTDIR)${infodir}/$$elt"); \ - cp elisp_type_hierarchy* $(DESTDIR)${infodir}/; \ + cp *.jpg *.png $(DESTDIR)${infodir}/; \ done; \ fi @@ -1152,15 +1152,26 @@ $(1)-DOCLANG-$(2): $(1)-common $$(MAKE) -C doc/$$(subst -, DOCLANG=$(2) ,$(1)) endef +## Languages from DOCLANGS to build the manuals in doc/$(1) for: the +## default language (when in DOCLANGS), plus every other language in +## DOCLANGS that has translations for this directory +## (doc/translations/<lang>/$(1)). Directories without translations +## for a language must not run a sub-make for it: the doc Makefiles of +## untranslated directories ignore DOCLANG, so such a sub-make would +## just repeat the default-language build, and two sub-makes producing +## the same outputs race under "make -j" (e.g. "cp: cannot create +## regular file ...: File exists"). +FILTER_DOCLANGS = $(filter $(DOCLANGS),default) $(foreach lang,$(filter-out default,$(DOCLANGS)),$(if $(wildcard ${srcdir}/doc/translations/$(lang)/$(1)),$(lang))) +# $(1) = doc target (e.g. lispintro-info), $(2) = languages to build define MAKE_DOC # Define a target to which dependencies common to all of the doc files # in this directory may be assigned. $(1)-common: -$(1): $$(addprefix $(1)-DOCLANG-,$(DOCLANGS)) +$(1): $$(addprefix $(1)-DOCLANG-,$(2)) -$$(foreach lang,$(DOCLANGS),$$(eval $$(call MAKE_DOC_FOR_DOCLANG,$(1),$$(lang)))) +$$(foreach lang,$(2),$$(eval $$(call MAKE_DOC_FOR_DOCLANG,$(1),$$(lang)))) endef -$(foreach doc,$(DOCS),$(eval $(call MAKE_DOC,$(doc)))) +$(foreach doc,$(DOCS),$(eval $(call MAKE_DOC,$(doc),$(call FILTER_DOCLANGS,$(word 1,$(subst -, ,$(doc))))))) .PHONY: $(DOCS) docs pdf ps .PHONY: info dvi dist html info-dir check-info @@ -1185,17 +1196,34 @@ misc-dvi-common misc-html-common misc-pdf-common misc-ps-common: src info-dir: ${srcdir}/info/dir define set_texi_misc -texi_misc_$(1) = $$(shell MAKEFLAGS= $${MAKE} --no-print-directory -s -C doc/misc LANG=$(1) echo-sources) +texi_misc_$(1) = $$(shell MAKEFLAGS= $${MAKE} --no-print-directory -s -C doc/misc DOCLANG=$(1) echo-sources) endef $(foreach lang,$(DOCLANGS),$(eval $(call set_texi_misc,$(lang)))) -srcdir_doc_info_dir_inputs = \ +## For the default language, depend on the actual sources reported by +## doc/misc (echo-sources): .org files for the org-based manuals and +## .texi files for the rest. Deriving foo.texi names from INFO_COMMON +## would break in a fresh checkout, because the .texi files of the +## org-based manuals (e.g. modus-themes.texi) are generated and there +## is no rule to build them at this level. make-info-dir extracts dir +## entries from both formats. +srcdir_doc_info_dir_inputs := \ ${srcdir}/doc/emacs/emacs.texi \ ${srcdir}/doc/lispintro/emacs-lisp-intro.texi \ ${srcdir}/doc/lispref/elisp.texi \ - $(foreach lang,$(DOCLANGS),$(addprefix ${srcdir}/doc/misc/$(filter-out ../translations/default/misc/,../translations/$(lang)/misc/),$(texi_misc_$(lang)) )) + $(addprefix ${srcdir}/doc/misc/,${texi_misc_default}) +TRANSLATED_DIRS:=misc +# $(1) = dir +# $(2) = lang +define GET_DOC_SRC +-include ${srcdir}/doc/translations/$(2)/$(1)/info_common.mk +INFO_COMMON:=$$(subst ccmode,cc-mode,$$(INFO_COMMON)) +srcdir_doc_info_dir_inputs:=$$(srcdir_doc_info_dir_inputs) $$(patsubst %,${srcdir}/doc/translations/$(2)/$(1)/%-$(2).texi,$$(INFO_COMMON)) +endef +$(foreach dir,$(TRANSLATED_DIRS),$(foreach lang,$(filter-out default,$(DOCLANGS)),$(eval $(call GET_DOC_SRC,$(dir),$(lang))))) + info_dir_inputs = \ ../build-aux/dir_top \ $(subst ${srcdir}/doc/,,${srcdir_doc_info_dir_inputs}) diff --git a/admin/MAINTAINERS b/admin/MAINTAINERS index 3ffa21c0d45..a2e80bf2dc8 100644 --- a/admin/MAINTAINERS +++ b/admin/MAINTAINERS @@ -123,6 +123,9 @@ Amin Bandali ERC lisp/erc/* doc/misc/erc.texi + lisp/net/browse-url.el + lisp/net/eww.el + lisp/url/* Andrea Corallo Lisp native compiler diff --git a/admin/make-tarball.txt b/admin/make-tarball.txt index 8299668a8a6..51908478877 100644 --- a/admin/make-tarball.txt +++ b/admin/make-tarball.txt @@ -1,14 +1,14 @@ Instructions to create pretest or release tarballs. -*- coding: utf-8 -*- --- originally written by Gerd Möllmann, amended by Francesco Potortì - with the initial help of Eli Zaretskii +-- originally written by Gerd Möllmann; amended by Francesco Potortì + with the initial help of Eli Zaretskii; amended by Sean Whitton Preparations: 0. In order to upload to the GNU FTP server, you must be registered as an Emacs maintainer and have your GPG key acknowledged by the FTP - people. Do this as soon as possible to avoid lead time. For - instructions, see: + people. Do this as soon as possible to avoid lead time. + For instructions, see: <https://www.gnu.org/prep/maintain/html_node/Automated-Upload-Registration.html>. Steps to take before starting on the first pretest in any release sequence: @@ -16,57 +16,64 @@ Steps to take before starting on the first pretest in any release sequence: 0. The release branch (e.g. emacs-31) should already have been made and you should use it for all that follows. Diffs from this branch should be going to the emacs-diffs mailing list. + Check that it builds and that 'make check' passes. + + If there has been a change in who is the Emacs maintainer since the + last release, update doc/misc/ack.texi and admin/MAINTAINERS to + reflect this. You can commit this separately. 1. Decide on versions of m4 and autoconf, and ensure you will have them available for the duration of the release process. -2. Remove any old pretests from <https://alpha.gnu.org/gnu/emacs/pretest>. - You can use 'gnupload --delete' (see below for more gnupload details). +2. Ensure you have the gnulib <https://www.gnu.org/s/gnulib/> script + "build-aux/gnupload" available (/usr/share/gnulib/build-aux/gnupload + on Debian and its derivatives with the 'gnulib' and 'ncftp' packages + installed). 3. Check that all new Lisp libraries belong to sensible packages. Run "make -C lisp finder-data" and check the diff of the generated file against the previously released Emacs version to see what has changed. -4. If this is an emergency release without a prior pretest, inform the - maintainers of the bundled packages which are developed separately - to make sure they install adjustments required for an official - release. Currently, these packages include: +4. If this is an emergency release without a prior pretest, inform the + maintainers of the bundled packages which are developed separately + to make sure they install adjustments required for an official + release. Currently, these packages include: - . Tramp + . Tramp General steps (for each step, check for possible errors): -1. git pull # fetch from the repository - git status # check for locally modified files +1. Ensure that you have a clean, unmodified Git state. The easiest way + is to use a new Git worktree. First switch branches in your + existing worktrees so that you don't have the emacs-NN branch + checked out anywhere. Then, from a buffer with default-directory in + one of those worktrees, + + C-x v w c ~/src/emacs/tarballs/ RET emacs-NN RET - Ensure that you have a clean, unmodified state. - If you switched in-place from another branch to the release branch, - there could be inappropriate generated ignored files left over. - You might want to use "git status --ignored" to check for such files, - or some form of "git clean -x". It's probably simpler and safer to - make a new working directory exclusively for the release branch. + If this worktree already exists then either delete with 'C-x v w x' + and recreate, or do a full clean -- this sequence will delete all + untracked *and ignored* files, so first make sure you don't have any + valuable work in the worktree (that's why we suggest a new one): - If the working directory has subdirectories created when making - previous releases or pretests, remove those subdirectories, as the - command which updates the ChangeLog file might attempt to recurse - there and scan any ChangeLog.* files there. + git reset + git checkout . + git clean -xdff - Make sure the tree is built, or at least configured. That's - because some of the commands below run Make, so they need - Makefiles to be present. + Configure the tree: - ./autogen.sh - ./configure --without-native-compilation && make + ./autogen.sh autoconf + ./configure --without-native-compilation - For a release (as opposed to pretest), visit etc/NEWS and use the +2. For a release (as opposed to pretest), visit etc/NEWS and use the "M-x emacs-news-delete-temporary-markers" command to delete any left-over "---" and "+++" markers from etc/NEWS, as well as the "Temporary note" section at the beginning of that file, and commit etc/NEWS if it was modified. For a bug fix release (e.g. 31.2), delete any empty headlines too. -2. Regenerate the versioned ChangeLog.N and etc/AUTHORS files. +3. Regenerate the versioned ChangeLog.N and etc/AUTHORS files. The "M-x authors" command below will first update the current versioned ChangeLog.N file. For this to work correctly, make sure @@ -126,14 +133,23 @@ General steps (for each step, check for possible errors): Save the "*Authors*" buffer as etc/AUTHORS. Check the diff looks reasonable. Maybe add more entries to authors-ambiguous-files or authors-aliases, and repeat. - Commit any fixes to authors.el. + Commit and push any fixes to authors.el with a message like this: + + ; Update exported ChangeLog files and etc/AUTHORS + + * ChangeLog.N: + * etc/AUTHORS: Update. + + (i.e. these changes should be merged to master -- don't say + "regenerate" or "re-generate" so they aren't skipped). 3. Set the version number (M-x load-file RET admin/admin.el RET, then M-x set-version RET). For a pretest, start at version .90. After - .99, use .990 (so that it sorts). Commit the resulting changes - as one, with nothing else included, and using a log message + .99, use .990 (so that it sorts). 'C-x s' and commit the changes + as one, with nothing else included, using a log message of the format "Bump Emacs version to ...", so that the commit can - be skipped when merging branches (see admin/gitmerge.el). + be skipped when merging branches (see admin/gitmerge.el; i.e., these + changes should *not* be merged to master). Push. If this is a final pretest before the release: @@ -170,13 +186,28 @@ General steps (for each step, check for possible errors): Never replace an existing tarfile! If you need to fix something, always upload it with a different name. -4. autoreconf -i -I m4 --force - make bootstrap +4. autoreconf -i -I m4 --force && make bootstrap + + Copy lisp/loaddefs.el to lisp/ldefs-boot.el. + Edit ldefs-boot.el to add + + ;; no-byte-compile: t + + to its file-local variables section. I.e. your changes to + ldefs-boot.el should not include any changes to its file-local + variables block. Commit with a message like + + ; Update ldefs-boot.el. + + Do not merge to master. - Then do this: + and push. - make -C etc/refcards - make -C etc/refcards clean + If someone else makes a commit and you pull it, repeat from this + step onwards. Or you can just continue and allow that commit to be + part of the next pretest/release. + +5. make -C etc/refcards && make -C etc/refcards clean If some of the etc/refcards, especially the non-English ones, fail to build, you probably need to install some TeX/LaTeX packages, in @@ -187,39 +218,7 @@ General steps (for each step, check for possible errors): messages from TeX, but those seem to be harmless, as the result looks just fine.) -5. Copy lisp/loaddefs.el to lisp/ldefs-boot.el. After copying, edit - ldefs-boot.el to add - - ;; no-byte-compile: t - - to its file-local variables section, otherwise make-dist will - complain. - - Commit ChangeLog.N, etc/AUTHORS, lisp/ldefs-boot.el, and the files - changed by M-x set-version. Note that the set-version changes - should be committed separately, as described in step 3 above, to - avoid them being merged to master. The lisp/ldefs-boot.el file - should not be merged to master either, so it could be added to the - same commit or committed separately. To make sure the changes to - ChangeLog.N and etc/AUTHORS are _not_ skipped, do NOT describe their - updates as "regenerate" or "re-generate", since gitmerge.el by - default skips such commits; instead, use "update" or some such. - - The easiest way of doing that is "C-x v d ROOT-DIR RET", then go - to the first modified file, press 'M' to mark all modified files, - and finally 'v' to commit them. Make sure the commit log message - mentions all the changes in all modified files, as by default 'v' - doesn't necessarily do so. - - If someone else made a commit between step 1 and now, - you need to repeat from step 4 onwards. (You can commit the files - from step 2 and 3 earlier to reduce the chance of this.) - -6. If there has been a change in who is the Emacs maintainer since - the last release, update doc/misc/ack.texi and admin/MAINTAINERS - to reflect this. You can commit this separately. - -7. ./make-dist --snapshot --no-compress +7. ./make-dist --snapshot --no-compress Check the contents of the new tar with admin/diff-tar-files against the previous release (if this is the first pretest) or the @@ -227,7 +226,7 @@ General steps (for each step, check for possible errors): yourself, find it at <https://alpha.gnu.org/gnu/emacs/pretest>. Releases are at <https://ftp.gnu.org/pub/gnu/emacs/>. - ./admin/diff-tar-files emacs-OLD.tar emacs-NEW.tar + ./admin/diff-tar-files .../emacs-OLD.tar emacs-NEW.tar Alternatively, if you want to do this manually using the compressed tarballs: @@ -249,21 +248,22 @@ General steps (for each step, check for possible errors): tarball than the one you get from find. 8. tar xf emacs-NEW.tar; cd emacs-NEW - ./configure --prefix=/tmp/emacs && make check && make install + ./configure --prefix=/tmp/emacs && make -j1 check && make -j1 install - Use 'script' or M-x compile to save the compilation log in + Use script(1) or M-x compile to save the compilation log in compile-NEW.log and compare it against an old one. The easiest way to do that is to visit the old log in Emacs, change the version number of the old Emacs to __, do the same with the new log and do - M-x ediff. Especially check that Info files aren't built, and that - no autotools (autoconf etc) run. + 'M-x ediff'. Doing a non-parallel build (the '-j1') should make the + diff smaller but it is not strictly necessary. + + Especially check that Info files aren't built, and that no autotools + (autoconf etc.) run. -9. You can now tag the release/pretest and push it together with the - last commit: +9. You can now tag the release/pretest: - cd EMACS_ROOT_DIR && git tag -s TAG -m "Emacs STR" - git push - git push --tags + git tag -s TAG -m "Emacs STR" + git push origin tag TAG Here TAG is emacs-XX.Y.ZZ for a pretest, emacs-XX.Y for a release. For STR see below. For a release, if you are producing a release @@ -273,11 +273,11 @@ General steps (for each step, check for possible errors): safer to use the SHA1 of the last commit which went into the release tarball, in case there were some intervening commits since then: - git tag -s TAG -m "Emacs TAG STR" SHA1 - git push --tags + git tag -s TAG -m "Emacs STR" SHA1 + git push origin tag TAG In the past, we were not always consistent with the annotation - (i.e. -m "Emacs TAG"). The preferred format is like this for a + (i.e. the -m "Emacs STR"). The preferred format is like this for a pretest, release candidate and final release: git tag -s emacs-31.0.90 -m "Emacs 31.0.90 pretest" @@ -293,20 +293,19 @@ General steps (for each step, check for possible errors): xz -c emacs-NEW.tar > emacs-NEW.tar.xz For pretests, just xz is probably fine (saves bandwidth). - Now you should upload the files to the GNU FTP server; your - GPG key must already be accepted as described above. - The simplest method of uploading is with the gnulib - <https://www.gnu.org/s/gnulib/> script "build-aux/gnupload" - (/usr/share/gnulib/build-aux/gnupload on Debian and its derivatives - with the 'gnulib' and 'ncftp' packages installed): + Now we will upload the files to the GNU FTP server. In the case of + a pretest we will also remove the previous pretest; if there are + other old ones still there, explicitly list those too before the + '--' in order to remove them. For a pretest or release candidate: gnupload [--user [email protected]] --to alpha.gnu.org:emacs/pretest \ - FILE.gz FILE.xz ... + --delete OLD_FILE.gz OLD_FILE.xz \ + -- NEW_FILE.gz NEW_FILE.xz ... For a release: gnupload [--user [email protected]] --to ftp.gnu.org:emacs \ - FILE.gz FILE.xz ... + NEW_FILE.gz NEW_FILE.xz ... You only need the --user part if you have multiple GPG keys and do not want to use the default. Instead of "[email protected]" you @@ -333,10 +332,11 @@ General steps (for each step, check for possible errors): 12. After five minutes, verify that the files are visible at <https://alpha.gnu.org/gnu/emacs/pretest/> for a pretest, or - <https://ftp.gnu.org/gnu/emacs/> for a release. + <https://ftp.gnu.org/gnu/emacs/> for a release. If uploading a + pretest, the delete of the previous pretest a few minutes before the + creation of the new file. Download them and check the signatures and SHA1/SHA256 checksums. - Check they build (./configure --with-native-compilation). 13. Send an announcement to: emacs-devel, and bcc: [email protected]. For a pretest, also bcc: [email protected]. @@ -344,8 +344,7 @@ General steps (for each step, check for possible errors): (The reason for using bcc: is to make it less likely that people will followup on the wrong list.) See the info-gnu-emacs mailing list archives for the form - of past announcements. The first pretest announcement, and the - release announcement, should have more detail. + of past announcements. Use the emacs-devel topic 'emacs-announce'. The best way to do this is to add a header "Keywords: emacs-announce" to your mail. (You can also put it in the Subject, but this is not as good diff --git a/admin/merge-gnulib b/admin/merge-gnulib index 8c906d34cef..eca94e12d9a 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib @@ -61,7 +61,7 @@ AVOIDED_MODULES=' access btoc32 c32_apply_type_test c32_get_type_test c32isalnum c32rtomb c32tolower c32toupper - chmod close crypto/af_alg dup fchdir fstat gnulib-i18n + chmod close dup fchdir fstat gnulib-i18n langinfo-h libgmp-mpq localcharset localeinfo localename-unsafe-limited lock mbrtoc32-regular mbsinit memchr mkdir @@ -164,8 +164,7 @@ cp -- "$gnulib_srcdir"/build-aux/config.guess \ "$gnulib_srcdir"/build-aux/install-sh \ "$gnulib_srcdir"/build-aux/move-if-change \ "$src"build-aux && -cp -- "$gnulib_srcdir"/lib/af_alg.h \ - "$gnulib_srcdir"/lib/save-cwd.h \ +cp -- "$gnulib_srcdir"/lib/save-cwd.h \ "$src"lib && cp -- "$gnulib_srcdir"/m4/codeset.m4 \ "$src"m4 && diff --git a/admin/notes/documentation b/admin/notes/documentation index f6fa321b217..cb69269693c 100644 --- a/admin/notes/documentation +++ b/admin/notes/documentation @@ -145,6 +145,10 @@ This results in clickable Lisp symbols when the NEWS file is visited via follow this rule, like 'TAB' or ':type'. Exception: the symbols t and nil are not quoted. +Key names are embedded in angle brackets like '<LEFT>', except keys that +have a special shorthand syntax: 'NUL', 'RET', 'TAB', 'LFD', 'ESC', +'SPC' and 'DEL'. + Arguments of a function are written in capital letters LIKE-THIS, and they are not quoted. diff --git a/admin/notes/jargon b/admin/notes/jargon index 35f7a8c1037..20ebf200e92 100644 --- a/admin/notes/jargon +++ b/admin/notes/jargon @@ -75,6 +75,7 @@ TIA - thanks in advance TIL - today I learned TL;DR - too long; didn't read TRT - the right thing +TTTT - to tell the truth WFM - works for me WIP - work in progress WRT - with respect to diff --git a/admin/notes/repo b/admin/notes/repo index 2ed51c5cfc7..5bf6c9d0218 100644 --- a/admin/notes/repo +++ b/admin/notes/repo @@ -118,6 +118,8 @@ again. This is a semi-automated way to find the revision that introduced a bug. Browse 'git help bisect' for technical instructions. +** Starting a bisection + It is recommended to start a bisection with the admin/git-bisect-start script. Using that script ensures that commits in branches that are the result of merging external trees into the Emacs repository, as @@ -126,6 +128,34 @@ during the bisection process. That script can also be executed automatically when 'git bisect start' is called, with the help of a wrapper script that is included in its commentary section. +** Automated bisection + +In the case that you have a command which exits non-zero if and only if +the bug is present, then after starting the bisection, you can have Git +automatically recompile Emacs at the relevant revisions and run that +command for you, recording a result based on the exit code. + +Suppose 'emacs -batch -eval "(foo)"' exits non-zero if and only if the +bug is present. Then you may be able to use something like this: + + git bisect run sh -xc '{ test -e Makefile && { make || make bootstrap; }; } \ + || { git clean -xdff && ./autogen.sh autoconf && ./configure && make; } \ + || exit 125; src/emacs -batch -eval "(foo)"' + +This tries to recompile Emacs, tries a bootstrap build if that fails, +and completely empties out your working tree of build products with 'git +clean -xdff' if even that fails. If that isn't enough for a successful +build, returning code 125 tells Git to skip evaluating that commit. + +You can substitute in any options to './configure' you need on your +machine, and the test command at the end. It is usually best to +configure with '--without-native-compilation' for rebuild speed, unless +the bug only occurs with native compilation enabled. + +Note that this runs 'git clean -xdff', which deletes **any and all +untracked files**, so it is best to run it in a throwaway Git worktree. +You can create these using 'C-x v w c' from inside Emacs. + * Maintaining ChangeLog history Older ChangeLog entries are kept in history files named ChangeLog.1, diff --git a/admin/nt/dist-build/README-windows-binaries b/admin/nt/dist-build/README-windows-binaries index 50b2244147c..d901c9b00fa 100644 --- a/admin/nt/dist-build/README-windows-binaries +++ b/admin/nt/dist-build/README-windows-binaries @@ -21,7 +21,6 @@ Making a link to our copy of the source is NOT sufficient, since we might upgrade to a new version while you are still distributing the old binaries. - Windows Binaries ================ @@ -62,18 +61,34 @@ intended that these will be updated after that point. Source for Emacs itself is found in the directory above. +Emacs binaries are normally built using MSYS2/MINGW64 and include a full +"Ahead of Time" (AOT) build of provided elisp. Other binaries for a +given version of Emacs, if any, that have been created from atypical +compilation environments or built using alternative (e.g. "noaot") +settings may include architecture (e.g. "i668") and or other "tags" +following the version identifier (for example: +emacs-X.Y.Z-i686-notreesitter-nognutls.zip). + Snapshots ========= We also distribute "snapshots" of Emacs built at points throughout the development cycle, for those interested in following this cycle. They are not recommended for normal users; however, they are useful for -people who want to report bugs against the current master. +people who want to report bugs against the current master, to help in +"pretesting" new release versions, and so on. The files follow the same naming convention, but also include a date -(and sometimes information about their branch). The Emacs source at -the time of these builds is also distributed. +(and sometimes information about their branch) or they may releate to a +sepecific pretest or release candidate for an "uncut" Emacs. Emacs +sources are distributed along with each dated snapshot. Sources are +provided for the pretest and release candidate Emacs versions here, as +for release builds, are found in the directory (or directories) above. + +Meta +==== +You can find a copy this file, along with other programs used to build Emacs as a native windows program using the MSYS2 toolchain, within the emacs source tree, see: https://git.savannah.gnu.org/cgit/emacs.git/tree/admin/nt/dist-build LICENSE ====== diff --git a/configure.ac b/configure.ac index 09bd782240f..1645ba02282 100644 --- a/configure.ac +++ b/configure.ac @@ -985,7 +985,7 @@ a valid path to android.jar. See config.log for more details.]) fi AC_CACHE_CHECK([whether android.jar is new enough], - [emacs_cv_android_w_or_later], + [emacs_cv_android_x_or_later], AS_IF([rm -f conftest.class cat << EOF > conftest.java @@ -993,7 +993,7 @@ import android.os.Build; class conftest { - private static int test = Build.VERSION_CODES.BAKLAVA; + private static int test = Build.VERSION_CODES.CINNAMON_BUN; } EOF @@ -1004,7 +1004,7 @@ EOF if test "$emacs_cv_android_w_or_later" = "no"; then AC_MSG_ERROR([Emacs must be built with an android.jar file produced for \ -Android 16 (BAKLAVA) or later.]) +Android 17 (CINNAMON_BUN) or later.]) fi dnl See if the Java compiler supports the `--release' option which @@ -5165,19 +5165,6 @@ You can find the instructions on how to compile and install libgccjit from source on this site: <https://gcc.gnu.org/wiki/JIT>.])]) -HAVE_NATIVE_COMP=no -LIBGCCJIT_LIBS= -LIBGCCJIT_CFLAGS= -if test "$canonical" = i686-pc-cygwin; then - if test "${with_cygwin32_native_compilation}" = yes; then - with_native_compilation=yes - elif test "${with_native_compilation}" != no; then - AC_MSG_ERROR([Native compilation is not supported on 32-bit Cygwin. -If you really want to try it anyway, use the configure option -'--with-cygwin32-native-compilation'.]) - fi -fi - AC_DEFUN([libgccjit_not_found], [ AC_MSG_WARN([Elisp native compiler can't be enabled as libgccjit was not found. @@ -5211,6 +5198,19 @@ source on this site: with_native_compilation=no]) +HAVE_NATIVE_COMP=no +LIBGCCJIT_LIBS= +LIBGCCJIT_CFLAGS= +if test "$canonical" = i686-pc-cygwin; then + if test "${with_cygwin32_native_compilation}" = yes; then + with_native_compilation=yes + elif test "${with_native_compilation}" != no; then + AC_MSG_ERROR([Native compilation is not supported on 32-bit Cygwin. +If you really want to try it anyway, use the configure option +'--with-cygwin32-native-compilation'.]) + fi +fi + if test "$with_features" = "no" \ && test "${with_native_compilation}" = "default"; then with_native_compilation=no @@ -5254,24 +5254,23 @@ if test "${with_native_compilation}" != "no"; then fi # Check if libgccjit is available. + native_compilation_requested=${with_native_compilation} AC_CHECK_LIB([gccjit], [gcc_jit_context_acquire], [], - [if test "${with_native_compilation}" = "default"; then + [if test "${native_compilation_requested}" = "default"; then libgccjit_not_found else libgccjit_not_found_err fi]) - # `libgcc_not_found' may set `with_native_compilation' to `no'. - AS_IF([test "$with_native_compilation" != "no"], - [AC_CHECK_HEADERS([libgccjit.h], [], - [if test "${with_native_compilation}" = "default"; then + AC_CHECK_HEADERS([libgccjit.h], [], + [if test "${native_compilation_requested}" = "default"; then libgccjit_dev_not_found else libgccjit_dev_not_found_err - fi])]) + fi]) if test "${with_native_compilation}" != "no"; then # Check if libgccjit really works. AC_RUN_IFELSE([libgccjit_smoke_test], [], - [if test "${with_native_compilation}" = "default"; then + [if test "${native_compilation_requested}" = "default"; then libgccjit_broken else libgccjit_broken_err @@ -7943,10 +7942,10 @@ if test "$XCONFIGURE" != "android"; then AS_MKDIR_P([cross/etc]) AS_IF([test "x$with_android" != "xno"], [ - dnl Link gnulib files to cross/lib as well. af_alg.h and - dnl lib/save-cwd.h are copied manually from gnulib, and as such - dnl aren't specified in gl_FILE_LIST. - emacs_files='gl_FILE_LIST lib/af_alg.h lib/save-cwd.h' + dnl Link gnulib files to cross/lib as well. + dnl lib/save-cwd.h is copied manually from gnulib, + dnl and as such isn't specified in gl_FILE_LIST. + emacs_files='gl_FILE_LIST lib/save-cwd.h' dnl These files are specific to Emacs. emacs_files="$emacs_files lib/fingerprint.c lib/fingerprint.h \ lib/save-cwd.c lib/openat-die.c lib/save-cwd.c \ diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi index bc596d766ff..7fb68fe03ea 100644 --- a/doc/emacs/android.texi +++ b/doc/emacs/android.texi @@ -529,6 +529,8 @@ version of Android installed: @item @code{android.permission.ACCESS_LOCATION_EXTRA_COMMANDS} @item +@code{android.permission.ACCESS_LOCAL_NETWORK} +@item @code{android.permission.ACCESS_NETWORK_STATE} @item @code{android.permission.ACCESS_NOTIFICATION_POLICY} diff --git a/doc/emacs/building.texi b/doc/emacs/building.texi index 2af98997480..78c13903edf 100644 --- a/doc/emacs/building.texi +++ b/doc/emacs/building.texi @@ -746,13 +746,13 @@ for special commands that can be used in the GUD interaction buffer. As you debug a program, Emacs displays the relevant source files by visiting them in Emacs buffers, with an arrow in the left fringe indicating the current execution line. (On a text terminal, the arrow -appears as @samp{=>}, overlaid on the first two text columns.) Moving -point in such a buffer does not move the arrow. You are free to edit -these source files, but note that inserting or deleting lines will -throw off the arrow's positioning, as Emacs has no way to figure out -which edited source line corresponds to the line reported by the -debugger subprocess. To update this information, you typically have -to recompile and restart the program. +appears as @samp{=>}, in the left margin.) Moving point in such a +buffer does not move the arrow. You are free to edit these source +files, but note that inserting or deleting lines will throw off the +arrow's positioning, as Emacs has no way to figure out which edited +source line corresponds to the line reported by the debugger subprocess. +To update this information, you typically have to recompile and restart +the program. @cindex GUD and hl-line-mode @cindex highlighting execution lines in GUD diff --git a/doc/emacs/calendar.texi b/doc/emacs/calendar.texi index a9ac654cdca..5593c64f546 100644 --- a/doc/emacs/calendar.texi +++ b/doc/emacs/calendar.texi @@ -660,9 +660,9 @@ if these values are not what you want (or if the operating system does not supply them), you must set them yourself. Here is an example: @example -(setq calendar-time-zone -360) -(setq calendar-standard-time-zone-name "CST") -(setq calendar-daylight-time-zone-name "CDT") +(setq calendar-time-zone (* 12 60)) +(setq calendar-standard-time-zone-name "NZST") +(setq calendar-daylight-time-zone-name "NZDT") @end example @noindent diff --git a/doc/emacs/display.texi b/doc/emacs/display.texi index a64c009f2d9..a0e59d6bda0 100644 --- a/doc/emacs/display.texi +++ b/doc/emacs/display.texi @@ -1640,12 +1640,16 @@ present. @findex delete-trailing-whitespace @vindex delete-trailing-lines +@findex delete-trailing-whitespace-mode Type @kbd{M-x delete-trailing-whitespace} to delete all trailing whitespace. This command deletes all extra spaces at the end of each line in the buffer, and all empty lines at the end of the buffer; to ignore the latter, change the variable @code{delete-trailing-lines} to @code{nil}. If the region is active, the command instead deletes -extra spaces at the end of each line in the region. +extra spaces at the end of each line in the region. If you enable the +buffer-local mode @code{delete-trailing-whitespace-mode}, Emacs will +automatically invoke @code{delete-trailing-whitespace} each time you +save the buffer. @vindex indicate-empty-lines @cindex unused lines diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi index 7375396c054..2cce638aecb 100644 --- a/doc/emacs/frames.texi +++ b/doc/emacs/frames.texi @@ -82,6 +82,9 @@ Move point to where you click (@code{mouse-set-point}). Activate the region around the text selected by dragging, and put the text in the primary selection (@code{mouse-set-region}). +@item S-mouse-1 +Adjust already selected region. + @item mouse-2 Move point to where you click, and insert the contents of the primary selection there (@code{mouse-yank-primary}). @@ -134,6 +137,12 @@ is less than a half a character, you'd normally get the empty string in your kill ring, but with @code{non-empty}, this short mouse drag won't affect the kill ring. +@findex mouse-shift-adjust-mode + If you activate the Mouse-Shift-Adjust minor mode, clicking the left +mouse button with the @kbd{Shift} modifier (@kbd{S-down-mouse-1}) +adjusts (extends or shrinks, depending on where you click) the already +selected region. + @vindex mouse-scroll-min-lines If you move the mouse off the top or bottom of the window while dragging, the window scrolls at a steady rate until you move the mouse @@ -1918,6 +1927,7 @@ in the mode line when the frame is selected. Some text terminals support mouse clicks in the terminal window. @cindex xterm +@findex xterm-mouse-mode In a terminal emulator which is compatible with @command{xterm}, you can use @kbd{M-x xterm-mouse-mode} to give Emacs control over simple uses of the mouse---basically, only non-modified single clicks are @@ -1925,8 +1935,9 @@ supported. Newer versions of @command{xterm} also support mouse-tracking. The normal @command{xterm} mouse functionality for such clicks is still available by holding down the @key{SHIFT} key when you press the mouse button. Xterm Mouse mode is a global minor -mode (@pxref{Minor Modes}). Repeating the command turns the mode off -again. +mode (@pxref{Minor Modes}), which is turned on by default if Emacs +detects at start time that the terminal supports it. Repeating the +command turns the mode off again. @findex gpm-mouse-mode In the console on GNU/Linux, you can use @kbd{M-x gpm-mouse-mode} to diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi index 785322118f9..7e893ab4fdf 100644 --- a/doc/emacs/maintaining.texi +++ b/doc/emacs/maintaining.texi @@ -562,10 +562,12 @@ v}. Note that registering the files doesn't commit them; you must invoke @w{@kbd{C-x v v}} again to commit; see the next point. @item -If every file in the VC fileset has been either newly-added or -modified, commit the changed files. To do this, Emacs pops up a -@file{*vc-log*} buffer; type the desired log entry for the changes, -followed by @kbd{C-c C-c} to commit. @xref{Log Buffer}. +If every file in the VC fileset has been either newly-added or modified, +commit the changed files. To do this, Emacs pops up a @file{*vc-log*} +buffer, in which you can type the log entry for the changes (or, if the +entry has been automatically inserted from a ChangeLog file or buffer, +further edit it). When you are satisfied with the log entry, type +@kbd{C-c C-c} to commit the changes. See @ref{Log Buffer} for details. If @kbd{C-x v v} is invoked from a buffer under Diff mode, the command treats the buffer as holding a set of patches for one or more files. It @@ -715,49 +717,83 @@ out individual files. When you tell VC to commit a change, it pops up a buffer named @file{*vc-log*}. In this buffer, you should write a @dfn{log entry} describing the changes you have made (@pxref{Why Version Control?}). -After you are done, type @kbd{C-c C-c} (@code{log-edit-done}) to exit -the buffer and commit the change, together with your log entry. +Alternatively, you can have the entry automatically inserted from a +ChangeLog file or buffer (see below), which you can further edit in the +@file{*vc-log*} buffer if necessary. After you are done, type @kbd{C-c +C-c} (@code{log-edit-done}) to exit the buffer and commit the change, +together with your log entry. + + In the @file{*vc-log*} buffer, you can also write one or more +@dfn{header lines} specifying additional information to be supplied to +the version control system. For example, the following header line +states that the present change was not written by you, but by another +developer: + +@smallexample +Author: J. R. Hacker <jrh@@example.com> +@end smallexample + +@noindent +Each header line must occupy a single line at the top of the buffer; the +first line that is not a header line is treated as the start of the log +entry. In addition to the @samp{Author} header, most version control +systems also support the headers @samp{Summary} (a one-line summary of +the changeset) and @samp{Date} (a manually specified commit time). +Emacs recognizes these as well as several VCS-specific headers. If you +specify a header for a VCS that does not support it, the header is +treated as part of the log entry. @cindex Log Edit mode @cindex mode, Log Edit @vindex vc-log-mode-hook @c FIXME: Mention log-edit-mode-hook here? --xfq +@vindex log-edit-hook The major mode for the @file{*vc-log*} buffer is Log Edit mode, a variant of Text mode (@pxref{Text Mode}). On entering Log Edit mode, Emacs runs the hooks @code{text-mode-hook} and @code{vc-log-mode-hook} -(@pxref{Hooks}). - - In the @file{*vc-log*} buffer, you can write one or more @dfn{header -lines}, specifying additional information to be supplied to the -version control system. Each header line must occupy a single line at -the top of the buffer; the first line that is not a header line is -treated as the start of the log entry. For example, the following -header line states that the present change was not written by you, but -by another developer: - -@smallexample -Author: J. R. Hacker <jrh@@example.com> -@end smallexample - -@noindent -Apart from the @samp{Author} header, Emacs recognizes the headers -@samp{Summary} (a one-line summary of the changeset), @samp{Date} (a -manually-specified commit time), and @samp{Fixes} (a reference to a -bug fixed by the change). Not all version control systems recognize -all headers. If you specify a header for a system that does not -support it, the header is treated as part of the log entry. +(@pxref{Hooks}). In addition, to set up the @file{*vc-log*} buffer, +Emacs runs the hook @code{log-edit-hook}, which optionally makes several +useful features available. The following paragraphs describe several of +these features, including three that are generally useful and enabled by +default. (To see a complete list of the features and enable or disable +any of them, type @w{@kbd{M-x customize-option RET log-edit-hook RET}}; +@pxref{Specific Customization}.) + +@findex log-edit-insert-message-template + The function @code{log-edit-insert-message-template} produces the +default @file{*vc-log*} buffer setup, containing @samp{Author} and +@samp{Summary} headers, and displays a thick line separating the header +part of the buffer from the log entry part. If you remove +@code{log-edit-insert-message-template} from @code{log-edit-hook}, then +the initial @file{*vc-log*} buffer is simply empty. The two header +lines are initially empty. If you are the author of the change and you +have configured the VCS to use your name and email address in commit +messages, you can leave the @samp{Author} header empty. If you leave +the @samp{Summary} header empty, most systems will use the first line of +the log entry as the summary line (see below for a way to have the +@samp{Summary} header automatically filled). @kindex C-c C-f @r{(Log Edit mode)} @findex log-edit-show-files + When VC pops up the @file{*vc-log*} buffer, a buffer named +@file{*log-edit-files*} listing the current VC fileset, that is, the +files that will be committed if you type @w{@kbd{C-c C-c}}, also pops up +by default. If you have removed the command @code{log-edit-show-files} +from @code{log-edit-hook}, the @file{*log-edit-files*} buffer does not +automatically pop up, but you can invoke the command by typing +@w{@kbd{C-c C-f}}. Likewise, if you kill or bury the +@file{*log-edit-files*} buffer, typing @w{@kbd{C-c C-f}} will pop it up +again. + @kindex C-c C-d @r{(Log Edit mode)} @findex log-edit-show-diff - While in the @file{*vc-log*} buffer, the current VC fileset is -considered to be the fileset that will be committed if you type -@w{@kbd{C-c C-c}}. To view a list of the files in the VC fileset, -type @w{@kbd{C-c C-f}} (@code{log-edit-show-files}). To view a diff -of changes between the VC fileset and the version from which you -started editing (@pxref{Old Revisions}), type @kbd{C-c C-d} -(@code{log-edit-show-diff}). + To view a diff of changes between the VC fileset and the version from +which you started editing (@pxref{Old Revisions}), type @kbd{C-c C-d} +(@code{log-edit-show-diff}). This command also selects the window +displaying the diff. To have VC automatically display the diff when it +pops up the @file{*vc-log*} buffer, add @code{log-edit-maybe-show-diff} +to @code{log-edit-hook}; unlike @kbd{C-c C-d}, this function does not +select the window displaying the diff. @kindex C-c C-w @r{(Log Edit mode)} @findex log-edit-generate-changelog-from-diff @@ -773,15 +809,37 @@ VC root, customize @code{diff-add-log-use-relative-names}. @kindex C-c C-a @r{(Log Edit mode)} @findex log-edit-insert-changelog - If the VC fileset includes one or more @file{ChangeLog} files -(@pxref{Change Log}), type @kbd{C-c C-a} -(@code{log-edit-insert-changelog}) to pull the relevant entries into -the @file{*vc-log*} buffer. If the topmost item in each -@file{ChangeLog} was made under your user name on the current date, -this command searches that item for entries matching the file(s) to be -committed, and inserts them. + If you have added log entries for the current VC fileset to one or +more @file{ChangeLog} files or to a temporary ChangeLog buffer +(@pxref{Change Log}), by default VC automatically inserts these entries +into the @file{*vc-log*} buffer on popping it up. If you have removed +the command @code{log-edit-insert-changelog} from @code{log-edit-hook}, +VC does not automatically insert the log entries, but you can invoke the +command by typing @kbd{C-c C-a}. Likewise, if you delete or otherwise +change the content of this buffer and then decide you want to use the +ChangeLog entries after all, type @kbd{C-c C-a} to repopulate the buffer +with these entries. + + If the relevant log entries are in one or more @file{ChangeLog} files +and the topmost item in each file was made under your user name on the +current date, this command searches that item (or those items) for +entries matching the file(s) to be committed, and inserts them. If you +invoke the command with a prefix argument (@kbd{C-u C-c C-a}) or repeat +it immediately (@kbd{C-c C-a C-c C-a}), it searches the topmost item +regardless of the user name and date of the item. + + If VC detects that all log entries come from the same ChangeLog file +or buffer, then the command simply inserts the entire body of the entry +into the @file{*vc-log*} buffer. In addition, if the first line of the +entry does not begin with @samp{* } (an asterisk followed by a space), +VC considers it to be a summary line and moves it to the @samp{Summary} +header. Finally, if VC detects that the set of changed files listed in +the ChangeLog entry differs from the current VC fileset, it displays a +warning urging you to fix this discrepancy before committing the +changes. + @ifnottex -If you are using CVS or RCS, see @ref{Change Logs and VC}, for the + If you are using CVS or RCS, see @ref{Change Logs and VC}, for the opposite way of working---generating ChangeLog entries from the Log Edit buffer. @end ifnottex @@ -1599,17 +1657,6 @@ unpushed revisions"} where @var{N} is a number. You can click on this text to execute the @code{vc-root-log-outgoing} command (@pxref{VC Change Log}). -@vindex vc-dir-show-outgoing-count - Emacs tries to use cached information to determine the number of -unpushed revisions, but for some backends this isn't possible. In these -cases Emacs must occasionally fetch from the remote repository in order -to determine the count. If your connection to the remote repository is -slow then this may cause unacceptable slowdowns in refreshing the VC -Directory buffer. If this affects you, you can customize -@code{vc-dir-show-outgoing-count} to @code{nil} to disable the unpushed -revisions count altogether. You can also set this on a per-repository -basis using directory local variables (@pxref{Directory Variables}). - @node VC Directory Commands @subsubsection VC Directory Commands @@ -1652,9 +1699,10 @@ cannot be marked with this command if any file in its tree is marked. @item M If point is on a file entry, mark all files with the same status; if -point is on a directory entry, mark all files in that directory tree -(@code{vc-dir-mark-all-files}). With a prefix argument, mark all -listed files and directories. +point is on a directory entry, mark all and only the files that are +immediate descendents (i.e., children) of that directory +(@code{vc-dir-mark-all-files}). With a prefix argument, mark all listed +files. @findex vc-dir-mark-by-regexp @item % m @@ -1691,9 +1739,10 @@ active, unmark all the files in the region (@code{vc-dir-unmark}). @item U If point is on a file entry, unmark all files with the same status; if -point is on a directory entry, unmark all files in that directory tree +point is on a directory entry, unmark all and only the files that are +immediate descendents (i.e., children) of that directory (@code{vc-dir-unmark-all-files}). With a prefix argument, unmark all -files and directories. +listed files and directories. @item x Hide files with @samp{up-to-date} or @samp{ignored} status @@ -1712,13 +1761,22 @@ Quit the VC Directory buffer, and bury it (@code{quit-window}). While in the VC Directory buffer, all the files that you mark with @kbd{m} (@code{vc-dir-mark}) or @kbd{M} (@code{vc-dir-mark-all-files}) are in the current VC fileset. If you mark a directory entry with -@kbd{m}, all the listed files in that directory tree are in the -current VC fileset. The files and directories that belong to the -current VC fileset are indicated with a @samp{*} character in the VC -Directory buffer, next to their VC status. In this way, you can set -up a multi-file VC fileset to be acted on by VC commands like -@w{@kbd{C-x v v}} (@pxref{Basic VC Editing}), @w{@kbd{C-x v =}} -(@pxref{Old Revisions}), and @w{@kbd{C-x v u}} (@pxref{VC Undo}). +@kbd{m}, all the listed files in that directory tree (i.e., not only the +listed files of the directory but also the listed files of its +subdirectories) are in the current VC fileset. The files and +directories that belong to the current VC fileset are indicated with a +@samp{*} character in the VC Directory buffer, next to their VC status. +In this way, you can set up a multi-file VC fileset to be acted on by VC +commands like @w{@kbd{C-x v v}} (@pxref{Basic VC Editing}), @w{@kbd{C-x +v =}} (@pxref{Old Revisions}), and @w{@kbd{C-x v u}} (@pxref{VC Undo}). + + In a VC Directory buffer containing no marked file or directory +entries, the current VC fileset is determined as follows. If point is +on a file entry, the fileset consists of just that file. If point is on +a directory entry, the fileset consists of all files in that directory +tree. Consequently, if point in on (or above) the entry @samp{./} +(representing the working directory), the fileset consists of all listed +files. The VC Directory buffer also defines some single-key shortcuts for VC commands with the @kbd{C-x v} prefix: @kbd{=}, @kbd{+}, @kbd{l}, @@ -2537,13 +2595,36 @@ dated in May 1993, with two items and one item respectively. @end smallexample One entry can describe several changes; each change should have its -own item, or its own line in an item. Normally there should be a -blank line between items. When items are related (parts of the same -change, in different places), group them by leaving no blank line -between them. +own item, or its own line in an item. Normally there should be a blank +line between items. When items are related (parts of the same change, +in different places), group them by leaving no blank line between them. +Such a multi-item entry often begins with a single line of text that +succintly summarizes the whole changeset. The entry may also contain +additional explanatory text between the summary line and the first +change item; the explanatory text should also be bounded by blank lines. +Here is an example: + +@iftex +@medbreak +@end iftex +@smallexample +2026-02-27 Sean Whitton <spwhitton@@spwhitton.name> + + New 'log-outstanding' value for vc-log-view-type + + This fixes vc-hg-print-log's choice of -r arguments to 'hg log'. + + * lisp/vc/vc.el (vc-log-view-type): New 'log-outstanding' value. + (vc-log-outstanding): Pass it. + * lisp/vc/vc-git.el (vc-git-log-view-mode): + * lisp/vc/vc-hg.el (vc-hg-print-log, vc-hg-log-view-mode): Treat + 'log-outstanding' the same as 'log-outgoing'. +@end smallexample - You should put a copyright notice and permission notice at the -end of the change log file. Here is an example: + If you include one or more change log files in a software package that +is distributed to others, you should put a copyright notice and +permission notice at the end of each change log file. Here is an +example: @smallexample Copyright 1997--1998, 2025--2026 Free Software Foundation, Inc. diff --git a/doc/emacs/rmail.texi b/doc/emacs/rmail.texi index d82cd177fa6..4c3989f51b9 100644 --- a/doc/emacs/rmail.texi +++ b/doc/emacs/rmail.texi @@ -451,6 +451,10 @@ in Rmail mode. You can use @kbd{M-x rmail-input} even when not in Rmail, but it is easier to type @kbd{C-u M-x rmail}, which does the same thing. + Files named @file{RMAIL} or ending in @file{.rmail} are visited in +Rmail mode automatically by ordinary file-visiting commands, such as +@kbd{C-x C-f}. + The file you read with @kbd{i} should normally be a valid mbox file. If it is not, Rmail tries to convert its text to mbox format, and visits the converted text in the buffer. If you save the buffer, that diff --git a/doc/emacs/search.texi b/doc/emacs/search.texi index 5f7aa1f1ef5..314f1de8e83 100644 --- a/doc/emacs/search.texi +++ b/doc/emacs/search.texi @@ -1937,6 +1937,10 @@ case. I.e., if you have a @code{query-replace} from @samp{foo} to @samp{Bar}. Use this command to do the current replacement with exact case. +@item d +to show the replacement of the current match as a buffer of diffs +between the original text and text with the match replaced. + @item C-l to redisplay the screen. Then you must type another character to specify what to do with this occurrence. diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi index b4f0d6f64bc..fad9a1f60e4 100644 --- a/doc/emacs/text.texi +++ b/doc/emacs/text.texi @@ -1197,8 +1197,8 @@ header line. Make the current heading line's body invisible (@code{outline-hide-entry}). @item C-c C-e -Make the current heading line's body visible -(@code{outline-show-entry}). +Reveal the current entry and its parent hierarchy +(@code{outline-show-entry-and-parents}). @item C-c C-d Make everything under the current heading invisible, not including the heading itself (@code{outline-hide-subtree}). @@ -1235,14 +1235,14 @@ Show bodies of headings that match @var{regexp} @end table @findex outline-hide-entry -@findex outline-show-entry +@findex outline-show-entry-and-parents @kindex C-c C-c @r{(Outline mode)} @kindex C-c C-e @r{(Outline mode)} The simplest of these commands are @kbd{C-c C-c} (@code{outline-hide-entry}), which hides the body lines directly following the current heading line, and @kbd{C-c C-e} -(@code{outline-show-entry}), which reveals them. Subheadings and -their bodies are not affected. +(@code{outline-show-entry-and-parents}), which reveals the current entry, +all of its ancestor headings, and their immediate sibling headings. @findex outline-hide-subtree @findex outline-show-subtree @@ -1372,9 +1372,9 @@ levels. Consider an Outline mode buffer with all the text and subheadings under level-1 headings hidden. To look at what is hidden under one of these -headings, you could use @kbd{C-c C-e} (@kbd{M-x outline-show-entry}) -to expose the body, or @kbd{C-c C-i} to expose the child (level-2) -headings. +headings, you could use @kbd{C-c C-e} (@kbd{M-x outline-show-entry-and-parents}) +to expose the body and its parent hierarchy, or @kbd{C-c C-i} to expose +the child (level-2) headings. @kindex C-c C-z @findex foldout-zoom-subtree @@ -1408,7 +1408,8 @@ particular chapter or section of your document. This hides all the text and subheadings under the top-level heading and returns you to the previous view of the buffer. Specifying a numeric argument exits that many levels of folds. Specifying a zero argument -exits all folds. +exits all folds. Specifying a negative argument (so that the exited +fold remains visible) preserves the position of point and window view. To cancel the narrowing of a fold without hiding the text and subheadings, specify a negative argument. For example, @w{@kbd{M--2 C-c diff --git a/doc/lispintro/emacs-lisp-intro.texi b/doc/lispintro/emacs-lisp-intro.texi index fc1da41af8b..cedd757555e 100644 --- a/doc/lispintro/emacs-lisp-intro.texi +++ b/doc/lispintro/emacs-lisp-intro.texi @@ -15206,12 +15206,13 @@ nil 100 @end group @group -(20615 27034 579989 697000) -(17905 55681 0 0) -(20615 26327 734791 805000)@footnote{If @code{current-time-list} is -@code{nil} the three timestamps are @code{(1351051674579989697 -. 1000000000)}, @code{(1173477761000000000 . 1000000000)}, and -@code{(1351050967734791805 . 1000000000)}, respectively.} +(1351051674579989697 . 1000000000) +(1173477761000000000 . 1000000000) +(1351050967734791805 . 1000000000)@footnote{If @code{current-time-list} is +@code{t} the three timestamps are +@code{(20615 27034 579989 697000)}, +@code{(17905 55681 0 0)}, and +@code{(20615 26327 734791 805000)}, respectively.} 13188 "-rw-r--r--" @end group diff --git a/doc/lispref/buffers.texi b/doc/lispref/buffers.texi index 054efba9ae1..33fab9e89bc 100644 --- a/doc/lispref/buffers.texi +++ b/doc/lispref/buffers.texi @@ -391,7 +391,7 @@ the buffer name are distinct and can be set independently. @xref{Visiting Files}. @defun buffer-file-name &optional buffer -This function returns the absolute file name of the file that +This function returns the fully-expanded absolute file name of the file that @var{buffer} is visiting. If @var{buffer} is not visiting any file, @code{buffer-file-name} returns @code{nil}. If @var{buffer} is not supplied, it defaults to the current buffer. @@ -405,10 +405,11 @@ supplied, it defaults to the current buffer. @end defun @defvar buffer-file-name -This buffer-local variable contains the name of the file being visited +This buffer-local variable contains the absolute name of the file being visited in the current buffer, or @code{nil} if it is not visiting a file. It is a permanent local variable, unaffected by -@code{kill-all-local-variables}. +@code{kill-all-local-variables}. The value is identical to the one +which the @code{buffer-file-name} function returns. @example @group diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi index df3752e7aff..0e993f45b48 100644 --- a/doc/lispref/commands.texi +++ b/doc/lispref/commands.texi @@ -388,7 +388,18 @@ It is a single, isolated character. @table @samp @item * -Signal an error if the current buffer is read-only. Special. +Signal an error if the current buffer is read-only. Special. Note that +many Emacs primitives will signal an error if a command attempts to +modify text of a read-only buffer, even if the command's interactive +spec does not include @samp{*}. So this character is for when you want +to forcibly signal an error even if the command's implementation doesn't +invoke any primitives which modify the buffer, or if you want to avoid +processing or side effects of a command that will fail later due to +buffer modifications. For example, a command that binds +@code{inhibit-read-only} non-@code{nil} (because it affects more than +just read-only buffers), or a command which, depending on the +conditions, might end up not modifying the buffer, but you want it to +signal this error anyway. @item @@ Select the window mentioned in the first mouse event in the key @@ -3777,14 +3788,15 @@ supplied to input methods (@pxref{Input Methods}). Use if you want to translate characters after input methods operate. @end defvar -@defun key-translate from to -This function modifies @code{keyboard-translate-table} to translate -character code @var{from} into character code @var{to}. It creates the +@deffn Command key-translate from to +This command modifies @code{keyboard-translate-table} to translate +character code @var{from} into character code @var{to}. Interactively, +it prompts for @var{from} and @var{to}. It creates the keyboard translate table if necessary. Both @var{from} and @var{to} should be strings that satisfy @code{key-valid-p} (@pxref{Key Sequences}). If @var{to} is @code{nil}, the function removes any existing translation for @var{from}. -@end defun +@end deffn Here's an example of using the @code{keyboard-translate-table} to make @kbd{C-x}, @kbd{C-c} and @kbd{C-v} perform the cut, copy and paste @@ -3812,6 +3824,12 @@ input events that are not characters (i.e., @code{characterp} returns @code{nil} for them), you must use the event translation mechanism described there. +@deffn Command key-translate-remove from +This command prompts for a key @var{from} and its translation, and +removes the translation from the translation table. When calling from +Lisp, specify just the key @var{from}, without its translation. +@end deffn + @node Invoking the Input Method @subsection Invoking the Input Method @cindex invoking input method diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi index d3662f727cc..909c69a854e 100644 --- a/doc/lispref/control.texi +++ b/doc/lispref/control.texi @@ -1489,6 +1489,13 @@ introduced in each one of the @var{bindings} are available in the being available in @var{body}. @end defmac +@defmac pcase-let*-strict bindings body@dots{} +Like @code{pcase-let*}, but signals an error if a @var{pattern} does +not match its corresponding @var{exp}. For example, this can alert +you when a value that you would like to destructure is not as +expected. +@end defmac + @defmac pcase-dolist (pattern list) body@dots{} Execute @var{body} once for each element of @var{list}, on each iteration performing a destructuring binding of variables in diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 49b09f6583d..0d0899e418c 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -531,7 +531,7 @@ This function calls @code{progress-reporter-update}, so the first message is printed immediately. @end defun -@defun progress-reporter-update reporter &optional value suffix +@defun progress-reporter-update reporter &optional value update-text This function does the main work of reporting progress of your operation. It displays the message of @var{reporter}, followed by progress percentage determined by @var{value}. If percentage is zero, @@ -545,10 +545,11 @@ state of your operation and must be between @var{min-value} and @code{make-progress-reporter}. For instance, if you scan a buffer, then @var{value} should be the result of a call to @code{point}. -Optional argument @var{suffix} is a string to be displayed after -@var{reporter}'s main message and progress text. If @var{reporter} is -a non-numerical reporter, then @var{value} should be @code{nil}, or a -string to use instead of @var{suffix}. +Optional argument @var{update-text} is a string to be displayed after +@var{reporter}'s main message and progress text. One typical use is as +the ``step'' of a long-running process so the user knows where it is. +If @var{reporter} is a non-numerical reporter, then @var{value} should +be @code{nil}, or a string to use instead of @var{update-text}. This function respects @var{min-change} and @var{min-time} as passed to @code{make-progress-reporter} and so does not output new messages @@ -557,11 +558,11 @@ try to reduce the number of calls to it: resulting overhead will most likely negate your effort. @end defun -@defun progress-reporter-force-update reporter &optional value new-message suffix +@defun progress-reporter-force-update reporter &optional value new-message update-text This function is similar to @code{progress-reporter-update} except that it prints a message in the echo area unconditionally. -@var{reporter}, @var{value}, and @var{suffix} have the same meaning as for +@var{reporter}, @var{value}, and @var{update-text} have the same meaning as for @code{progress-reporter-update}. Optional @var{new-message} allows you to change the message of the @var{reporter}. Since this function always updates the echo area, such a change will be immediately @@ -5065,11 +5066,12 @@ to the left of the display area. @defvar overlay-arrow-position This variable holds a marker that indicates where to display the overlay arrow. It should point at the beginning of a line. On a non-graphical -display, or when the left fringe is not shown, the arrow text -appears at the beginning of that line, overlaying any text that would -otherwise appear. Since the arrow is usually short, and the line -usually begins with indentation, normally nothing significant is -overwritten. +display, or when the left fringe is not shown, the arrow text appears at +the beginning of that line, overlaying any text that would otherwise +appear. Since the arrow is usually short, and the line usually begins +with indentation, normally nothing significant is overwritten. If the +window has a left margin with enough space, Emacs displays the arrow +there instead and the text area is not overwritten. The overlay-arrow string is displayed in any given buffer if the value of @code{overlay-arrow-position} in that buffer points into that @@ -5700,7 +5702,9 @@ edge, center, or right edge of the text area. When the window displays line numbers, and @code{:align-to} is used in display properties of buffer text (as opposed to header line, see below), the @code{left} and the @code{center} positions are offset to account for -the screen space taken by the line-number display. +the screen space taken by the line-number display. In particular, +@code{center} then denotes the center of the editable text area, i.e.@: +the text area excluding the line-number display. Any of the above window elements (except @code{text}) can also be used with @code{:align-to} to specify that the position is relative to diff --git a/doc/lispref/edebug.texi b/doc/lispref/edebug.texi index 8aec8abf7c0..e729cb7aef3 100644 --- a/doc/lispref/edebug.texi +++ b/doc/lispref/edebug.texi @@ -105,8 +105,10 @@ the Lisp code you are debugging. This is referred to as the @dfn{source code buffer}, and it is temporarily read-only. An arrow in the left fringe indicates the line where the function is -executing. Point initially shows where within the line the function is -executing, but this ceases to be true if you move point yourself. +executing. On a non-graphical display (or when the left fringe is not +shown), this arrow is displayed in the left margin instead. Point +initially shows where within the line the function is executing, but +this ceases to be true if you move point yourself. If you instrument the definition of @code{fac} (shown below) and then execute @code{(fac 3)}, here is what you would normally see. Point is diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index 9115b3a4691..2944b598178 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi @@ -1137,6 +1137,7 @@ Frames * Frame Titles:: Automatic updating of frame titles. * Deleting Frames:: Frames last until explicitly deleted. * Finding All Frames:: How to examine all existing frames. +* Splitting and Merging Frames:: Transferring window layouts between frames. * Minibuffers and Frames:: How a frame finds the minibuffer to use. * Input Focus:: Specifying the selected frame. * Visibility of Frames:: Frames may be visible or invisible, or icons. @@ -1453,6 +1454,7 @@ Processes * Misc Network:: Additional relevant functions for net connections. * Serial Ports:: Communicating with serial ports. * Byte Packing:: Using bindat to pack and unpack binary data. +* UUIDs:: Generating and converting UUIDs. Receiving Output from Processes diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index f86a18fd896..5c516c0b0d1 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -1467,20 +1467,20 @@ is owned by the user with name @samp{lh}. @item "users" is in the group with name @samp{users}. -@item (20614 64019 50040 152000) +@item (1351023123050040152 . 1000000000) was last accessed on October 23, 2012, at 20:12:03.050040152 UTC@. -(This timestamp is @code{(1351023123050040152 . 1000000000)} -if @code{current-time-list} is @code{nil}.) +(This timestamp is @code{(20614 64019 50040 152000)} +if @code{current-time-list} is @code{t}.) -@item (20000 23 0 0) +@item (1310720023000000000 . 1000000000) was last modified on July 15, 2001, at 08:53:43.000000000 UTC@. -(This timestamp is @code{(1310720023000000000 . 1000000000)} -if @code{current-time-list} is @code{nil}.) +(This timestamp is @code{(20000 23 0 0)} +if @code{current-time-list} is @code{t}.) -@item (20614 64555 902289 872000) +@item (1351023659902289872 . 1000000000) last had its status changed on October 23, 2012, at 20:20:59.902289872 UTC@. -(This timestamp is @code{(1351023659902289872 . 1000000000)} -if @code{current-time-list} is @code{nil}.) +(This timestamp is @code{(20614 64555 902289 872000)} +if @code{current-time-list} is @code{t}.) @item 122295 is 122295 bytes long. (It may not contain 122295 characters, though, diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi index a3be6cc2bfc..945cb4d0f32 100644 --- a/doc/lispref/frames.texi +++ b/doc/lispref/frames.texi @@ -151,6 +151,7 @@ unique id. * Frame Titles:: Automatic updating of frame titles. * Deleting Frames:: Frames last until explicitly deleted. * Finding All Frames:: How to examine all existing frames. +* Splitting and Merging Frames:: Transferring window layouts between frames. * Minibuffers and Frames:: How a frame finds the minibuffer to use. * Input Focus:: Specifying the selected frame. * Visibility of Frames:: Frames may be visible or invisible, or icons. @@ -1303,6 +1304,28 @@ The default is @code{inhibit} on NS builds and @code{nil} everywhere else. @end defopt +@defun set-frame-size-and-position &optional frame width height left top +This function sets the new size and position of @var{frame} in a single +step; @var{frame} defaults to the selected frame. The size and position +are specified as with the corresponding frame parameters @code{width}, +@code{height}, @code{left}, and @code{top} (@pxref{Size Parameters}, and +@pxref{Position Parameters}). If any of these 4 arguments is omitted or +@code{nil}, that means not to change the corresponding parameter of +@var{frame}. +@end defun + +@cindex gravity of frame +@defun set-frame-size-and-position-pixelwise frame width height x y &optional gravity +This function sets the new size and position of a frame, similarly to +@code{set-frame-size-and-position}, but in pixel units. The optional +argument @var{gravity} specified the new @dfn{gravity} of a frame and +must be a value between 0 and 10; it defaults to 1. The gravity +determines how a window or its contents adjust when resized or +positioned. The interpretation is specific to each window-system; for +example, GTK uses window gravity to define which point of the window +remains fixed during resizing. +@end defun + @cindex tracking frame size changes The abnormal hook @code{window-size-change-functions} (@pxref{Window Hooks}) tracks all changes of the inner size of a frame including those @@ -2968,6 +2991,18 @@ for example, deleting a frame during a drag-and-drop operation the @code{delete-frame} call in a @code{condition-case} form. @end defun +When the selected frame gets deleted Emacs has to select another frame +instead. The following option lets you choose which one. + +@defopt delete-frame-choose-selected +This variable specifies which frame to select after deleting the +selected frame. The default value @code{mru} means @code{delete-frame} +should try to select the most recently used frame as returned by +@code{get-mru-frame} (@pxref{Input Focus}) on the same terminal. The +value @code{nil} means that @code{delete-frame} will try to select the +oldest visible frame on the same terminal as the deleted one. +@end defopt + @node Finding All Frames @section Finding All Frames @@ -3054,6 +3089,87 @@ criteria, and should return non-@code{nil} if the frame satisfies the criteria. @end defun + +@node Splitting and Merging Frames +@section Splitting and Merging Frames +@cindex splitting a frame +@cindex merging two frames +@cindex transferring window layouts to frames + +The following two functions are useful to transfer parts of the window +layout (@pxref{Basic Windows}) of one frame to two separate frames and +to merge the window layouts of two separate frames into one frame. + +@deffn Command split-frame &optional frame arg +This command transfers some windows of the specified @var{frame} to a +new frame and subsequently deletes them on @var{frame}. @var{frame} +must be a live frame and defaults to the selected frame. @var{arg} +specifies the number of windows to transfer and defaults to 1. +Interactively, @var{arg} is the prefix argument. + +In a first step, it divides the child windows (@pxref{Windows and +Frames}) of @var{frame}'s main window (@pxref{Side Windows}) into two +parts. The first part includes the first @var{arg} child windows if +@var{arg} is positive, and the @minus{}@var{arg} last child windows if +@var{arg} is negative. The second part includes the remaining child +windows of @var{frame}'s main window. + +In a second step, it clones (@pxref{Window Configurations}) into a newly +created frame each of the windows of the part which does not include +@var{frame}'s selected window (@pxref{Selecting Windows}) and removes +those windows from @var{frame}. Note that the original identity +(@pxref{Basic Windows}) of the cloned windows is lost in this step. The +identity of the windows retained on @var{frame} is preserved, however. +In a final step, it deletes the windows that have been cloned from +@var{frame} and returns the newly created frame. + +This function signals an error if @var{arg} is either zero or not a +number, or if @var{frame}'s main window is either live or does not have +more child windows than specified by the absolute value of @var{arg}. +@end deffn + +@deffn Command merge-frames &optional frame1 frame2 vertical +This command transfers the main window (@pxref{Side Windows}) of +@var{frame2} to @var{frame1}. Both @var{frame1} and @var{frame2} must +specify live frames. + +In the first step it splits the main window of @var{frame1}. If +@var{vertical} is non-@code{nil}, it makes the new window below the old +main window of @var{frame1}. Otherwise, it makes the new window on the +right of @var{frame1}'s main window. + +In the second step it makes the new window a clone (@pxref{Window +Configurations}) of the main window of @var{frame2}. The original +identity (@pxref{Basic Windows}) of the cloned windows is lost in that +step. In the final step, it deletes @var{frame2} if the merge completed +successfully and returns @var{frame1}. + +Interactively, @var{vertical} is the prefix argument, @var{frame1} is +the selected frame and @var{frame2} is the frame following @var{frame1} +in the list of all frames (@pxref{Finding All Frames}). If @var{frame1} +and @var{frame2} are omitted or @code{nil} in calls from Lisp, they +default to the above values. +@end deffn + +In general you cannot ``undo'' a @code{split-frame} call with a +subsequent @code{merge-frames} call for the following reasons: In its +second step @code{merge-frame} puts the main window of @var{frame2} into +an internal window split off in the first step. No such window was +present in the configuration of @var{frame1} before calling +@code{split-frame}. Also, after merging is complete, the window cloned +from the main window of @var{frame2} will occupy as much space as the +main window of @var{frame1} before merging. This might not match the +space distribution of the original layout. + +Hence, if your preferred workflow is to temporarily split off windows +for working on them in a separate frame and later continue with the +original layout of the original frame, you should proceed as follows: +Save the configuration (@pxref{Window Configurations}) of the original +frame, call @code{split-frame} to create the separate frame and finally +restore the saved configuration of the original frame and delete the +separate frame. + + @node Minibuffers and Frames @section Minibuffers and Frames diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi index 53597236da8..876cb702e3b 100644 --- a/doc/lispref/functions.texi +++ b/doc/lispref/functions.texi @@ -1131,6 +1131,8 @@ This function returns @var{argument} and has no side effects. @defun ignore &rest arguments This function ignores any @var{arguments} and returns @code{nil}. +When used as a place (@pxref{Generalized Variables}), the assignment has +simply no effect. @end defun @defun always &rest arguments diff --git a/doc/lispref/intro.texi b/doc/lispref/intro.texi index cc0cbfaf980..f73db91a379 100644 --- a/doc/lispref/intro.texi +++ b/doc/lispref/intro.texi @@ -504,11 +504,11 @@ if the information is not available. @example @group emacs-build-time - @result{} (25194 55894 8547 617000) + @result{} (1651169878008547617 . 1000000000) @end group @end example -(This timestamp is @code{(1651169878008547617 . 1000000000)} -if @code{current-time-list} was @code{nil} when Emacs was built.) +(This timestamp is @code{(25194 55894 8547 617000)} +if @code{current-time-list} was @code{t} when Emacs was built.) @end defvar @defvar emacs-version diff --git a/doc/lispref/keymaps.texi b/doc/lispref/keymaps.texi index 8ef6b77c178..97d496b8df2 100644 --- a/doc/lispref/keymaps.texi +++ b/doc/lispref/keymaps.texi @@ -133,14 +133,14 @@ A three key sequence of the keys @kbd{S}, @kbd{o} and @kbd{m}. A two key sequence of the keys @kbd{c} with the control modifier and then the key @kbd{o} -@item H-<left> -The key named @kbd{left} with the hyper modifier. +@item H-@key{LEFT} +The key named @key{LEFT} with the hyper modifier. -@item M-RET -The @kbd{return} key with a meta modifier. +@item M-@key{RET} +The @key{RET} or @key{Return} key with a meta modifier. -@item C-M-<space> -The @kbd{space} key with both the control and meta modifiers. +@item C-M-@key{SPC} +The @key{SPC} key with both the control and meta modifiers. @end table The only keys that have a special shorthand syntax are @kbd{NUL}, @@ -151,16 +151,12 @@ The modifiers have to be specified in alphabetical order: @findex keymap-set @defun keymap-set keymap key binding -This function sets the binding for @var{key} in @var{keymap}. (If -@var{key} is more than one event long, the change is actually made -in another keymap reached from @var{keymap}.) The argument -@var{binding} can be any Lisp object, but only certain types are -meaningful. (For a list of meaningful types, see @ref{Key Lookup}.) -The value returned by @code{keymap-set} is @var{binding}. - -If @var{key} is @kbd{<t>}, this sets the default binding in -@var{keymap}. When an event has no binding of its own, the Emacs -command loop uses the keymap's default binding, if there is one. +This function sets the binding for @var{key} in @var{keymap}. The +argument @var{key} is a string that must satisfy @code{key-valid-p} +(@pxref{Key Sequences}). The argument @var{binding} can be any Lisp +object, but only certain types are meaningful. (For a list of +meaningful types, see @ref{Key Lookup}.) The value returned by +@code{keymap-set} is @var{binding}. @cindex invalid prefix key error @cindex key sequence error diff --git a/doc/lispref/minibuf.texi b/doc/lispref/minibuf.texi index 9d73aa89b2d..6b914da9a86 100644 --- a/doc/lispref/minibuf.texi +++ b/doc/lispref/minibuf.texi @@ -2380,9 +2380,12 @@ asking each question individually. This gives the user certain convenient facilities such as the ability to answer the whole series at once. +@vindex y-or-n-p-use-read-key@r{, and} map-y-or-n-p @defun map-y-or-n-p prompter actor list &optional help action-alist no-cursor-in-echo-area This function asks the user a series of questions, reading a -single-character answer in the echo area for each one. +single-character answer in the minibuffer for each one. However, if +@code{y-or-n-p-use-read-key} is non-@code{nil} (@pxref{Key Sequence +Input}), it reads a key sequence from the echo area. The value of @var{list} specifies the objects to ask questions about. It should be either a list of objects or a generator function. If it diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi index 5f0e9a0fade..28c12e35207 100644 --- a/doc/lispref/modes.texi +++ b/doc/lispref/modes.texi @@ -2004,6 +2004,11 @@ turn on the minor mode in a buffer, it uses the function function so it could determine whether to enable the minor mode or not when it is not a priori clear that it should always be enabled.) +Note that this is different from using @code{define-minor-mode} with the +@code{:global} keyword non-@code{nil}, in that the mode defined by this +macro is still buffer-local, it is just enabled in all (or some) +buffers. + Globally enabling the mode affects only those buffers subsequently created that use a major mode which follows the convention to run @code{run-mode-hooks}. The minor mode will not be enabled in those @@ -2869,7 +2874,7 @@ The value string normally has text properties that correspond to the faces, keymaps, etc., that the mode line would have. Any character for which no @code{face} property is specified by @var{format} gets a default value determined by @var{face}. If @var{face} is @code{t}, that -stands for either @code{mode-line} if @var{window} is selected, +stands for either @code{mode-line-active} if @var{window} is selected, otherwise @code{mode-line-inactive}. If @var{face} is @code{nil} or omitted, that stands for the default face. If @var{face} is an integer, the value returned by this function will have no text properties. diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi index 59e0fe90a46..04ca0241622 100644 --- a/doc/lispref/os.texi +++ b/doc/lispref/os.texi @@ -1447,15 +1447,13 @@ The operating system limits the range of time and zone values. @end defun @defvar current-time-list -This boolean variable is a transition aid. If @code{t}, -@code{current-time} and related functions return timestamps in list -form, typically @code{(@var{high} @var{low} @var{micro} @var{pico})}; -otherwise, they use @code{(@var{ticks} . @var{hz})} form. Currently -this variable defaults to @code{t}, for behavior compatible with -previous Emacs versions. Developers are encouraged to test -timestamp-related code with this variable set to @code{nil}, as it -will default to @code{nil} in a future Emacs version, and will be -removed in some version after that. +This boolean variable is a transition aid. If @code{nil} (the default), +@code{current-time} and related functions return timestamps in +@code{(@var{ticks} . @var{hz})} form. If @code{t}, these functions +return in list form, typically @code{(@var{high} @var{low} @var{micro} +@var{pico})}, for behavior compatible with previous Emacs versions. +As it is merely a transition aid, this variable is planned to be removed +in some future Emacs version. @end defvar @defun current-time @@ -1534,9 +1532,10 @@ in. The value has the form @code{(@var{offset} @var{abbr})}. Here @var{offset} is an integer giving the number of seconds ahead of Universal Time (east of Greenwich). A negative value means west of Greenwich. The -second element, @var{abbr}, is a string giving an abbreviation for the -time zone, e.g., @samp{"CST"} for China Standard Time or for -U.S. Central Standard Time. Both elements can change when daylight +second element, @var{abbr}, is a string giving a possibly-ambiguous +abbreviation for the time zone, e.g., @samp{"IST"} for India Standard +Time, Irish Standard Time, or Israel Standard Time. +Both elements can change when daylight saving time begins or ends; if the user has specified a time zone that does not use a seasonal time adjustment, then the value is constant through time. @@ -1981,7 +1980,7 @@ This stands for the year without century (00--99). @item %Y This stands for the year with century. @item %Z -This stands for the time zone abbreviation (e.g., @samp{EST}). +This stands for the time zone abbreviation (e.g., @samp{IST}). @item %z This stands for the time zone numerical offset. The @samp{z} can be preceded by one, two, or three colons; if plain @samp{%z} stands for diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi index 4da72b512b0..dac6574a969 100644 --- a/doc/lispref/parsing.texi +++ b/doc/lispref/parsing.texi @@ -455,20 +455,20 @@ is non-@code{nil}, this function always creates a new parser. @code{nil}. Different parsers can have the same tag. @end defun -Given a parser, we can query information about it. - -@defun treesit-parser-buffer parser -This function returns the buffer associated with @var{parser}. -@end defun - -@defun treesit-parser-language parser -This function returns the language used by @var{parser}. -@end defun - -@defun treesit-parser-p object -This function checks if @var{object} is a tree-sitter parser, and -returns non-@code{nil} if it is, and @code{nil} otherwise. -@end defun +@findex treesit-parser-buffer +@findex treesit-parser-language +@findex treesit-parser-embed-level +@findex treesit-parser-p +Given a parser, we can query information about it: +@code{treesit-parser-buffer} returns the buffer associated with a +parser, and @code{treesit-parser-language} returns the language used by +the parser. A parser's tag can be retrieved by +@code{treesit-parser-tag}. Each parser also optionally carries an embed +level that can be set by @code{treesit-parser-set-embed-level} and +retrieved by @code{treesit-parser-embed-level} (see +@ref{parser-embed-level}, for more about embed level). Finally, +@code{treesit-parser-p} tells you whether an object is a tree-sitter +parser. There is no need to explicitly parse a buffer, because parsing is done automatically and lazily. A parser only parses when a Lisp program @@ -1808,10 +1808,11 @@ Again, @var{thing} can be either a symbol or a predicate. If @var{parser} is non-@code{nil}, only use that parser's parse tree. Otherwise try each parser covering point, from the most specific -(deepest-embedded) to the least specific. If there are multiple parsers with -the same embed level at @var{position}, which parser is tried first is -undefined. If @var{parser} is a language symbol, the function limits -the parsers it tries to the ones for that language. +(deepest-embedded) to the least specific. If there are multiple parsers +with the same embed level (@pxref{parser-embed-level}) at +@var{position}, which parser is tried first is undefined. If +@var{parser} is a language symbol, the function limits the parsers it +tries to the ones for that language. @end defun @defun treesit-thing-next position thing &optional parser @@ -1875,8 +1876,9 @@ position must be strictly greater than @var{position}. If @var{parser} is non-nil, only use that parser's parse tree. Otherwise try each parser covering point, from the most specific (deepest-embedded) to the least specific. If there are multiple parsers -with the same embed level at @var{position}, which parser is tried first is -undefined. @var{parser} can also be a language symbol. +with the same embed level (@pxref{parser-embed-level}) at +@var{position}, which parser is tried first is undefined. @var{parser} +can also be a language symbol. @end defun @findex treesit-beginning-of-thing @@ -2032,11 +2034,12 @@ for nodes in a region. @defun treesit-language-at pos This function returns the language of the text at buffer position @var{pos}. Under the hood it calls -@code{treesit-language-at-point-function} and returns its return -value. If @code{treesit-language-at-point-function} is @code{nil}, -this function returns the language of the deepest parser by embed level -among parsers returned by @code{treesit-parsers-at}. If there is no -parser at that buffer position, it returns @code{nil}. +@code{treesit-language-at-point-function} and returns its return value. +If @code{treesit-language-at-point-function} is @code{nil}, this +function returns the language of the deepest parser by embed level +(@pxref{parser-embed-level}) among parsers returned by +@code{treesit-parsers-at}. If there is no parser at that buffer +position, it returns @code{nil}. @end defun @heading Supporting multiple languages in major modes @@ -2153,10 +2156,38 @@ a @var{query} preceded by zero or more @var{keyword}/@var{value} pairs. Each @var{query} is a tree-sitter query in either the string, s-expression, or compiled form, or a function. +@code{treesit-update-ranges} uses @var{query} to figure out how to set +the ranges for parsers for the embedded language. It queries +@var{query} in a host language parser, computes the ranges which the +captured nodes span, and applies these ranges to embedded language +parsers. + If @var{query} is a tree-sitter query, it should be preceded by two @var{keyword}/@var{value} pairs, where the @code{:embed} keyword -specifies the embedded language, and the @code{:host} keyword -specifies the host language. +specifies the embedded language, and the @code{:host} keyword specifies +the host language. The captured nodes determine the range of embedded +parsers. The capture names don't matter, but names that starts with an +underscore are ignored, and the @code{@@language} capture name is +reserved. + +If the embedded language is dynamic, then @code{:embed} can specify a +function rathar than a static language. The function takes the node +captured with @code{@@language} capture name. Care have to be taken that +the @code{@@language} capture and the range capture are in the same +match group. The function should return either a language symbol, or nil +if no valid language can be found. + +If the query is given a @code{:offset} keyword whose value is a pair +of numbers, each captured range is offset by those numbers. For +example, an offset of @code{(1 . -1)} will update a captured range of +@code{(2 . 8)} to be @code{(3 . 7)}. This can be used to exclude things +like surrounding delimiters from being included in the range covered by +an embedded parser. + +By default, a parser sees its ranges as a continuum, rather than +treating them as separate independent segments. Therefore, if the +embedded ranges are semantically independent segments, they should be +processed by local parsers, described below. @cindex local parser If the query is given the @code{:local} keyword whose value is @@ -2164,19 +2195,44 @@ If the query is given the @code{:local} keyword whose value is otherwise the range shares a parser with other ranges for the same language. -By default, a parser sees its ranges as a continuum, rather than -treating them as separate independent segments. Therefore, if the -embedded ranges are semantically independent segments, they should be -processed by local parsers, described below. - -Local parser set to a range can be retrieved by +Local parsers set to a range can be retrieved by @code{treesit-local-parsers-at} and @code{treesit-local-parsers-on}. -@code{treesit-update-ranges} uses @var{query} to figure out how to set -the ranges for parsers for the embedded language. It queries -@var{query} in a host language parser, computes the ranges which the -captured nodes span, and applies these ranges to embedded language -parsers. +Emacs treats local embedded parsers and non-local embedded parsers quite +differently: + +@itemize @bullet +@item +Local parsers are managed by Emacs. Emacs creates new local parsers when +they are needed and deletes them when they are not. Non-local parsers +must be created by major modes, and Emacs only make use of them if one +exists. + +@item +Because local parsers can be freely created by Emacs, they are suitable +for recursively nested embedded parsers, where the embed level can be +arbitrarily deep. On the other hand, since non-local parsers created by +major modes, they can only handle a fix number of embed levels. +@end itemize + +@anchor{parser-embed-level} +@cindex embed level, tree-sitter +The embed level of the top-level parsers is 0 or omitted, the first +level of embedded parsers get embed level 1, and so on. For local +parsers, each embed level creates a new parser; for non-local parsers, +since Emacs cannot create non-local parsers freely, it tries to find a +usable parser at the right embed level; if none exists, Emacs just gives +up. + +If the query is given a @code{:range-fn} keyword whose value is a +function, Emacs uses that function to compute the ranges to use for the +embedded parser. The function takes as arguments the captured node and +the offset given by the @code{:offset} keyword, and returns a list of +ranges, where each range is a cons of the start and end position. For +local parsers, each @var{query} creates one local parser, and the ranges +set by the @code{:range-fn} are applied to that parser; for non-local +parsers, all the ranges (including ranges created by @code{:range-fn}) +in that embed level are joined together and applied to the same parser. If @var{query} is a function, it doesn't need any @var{keyword} and @var{value} pair. It should be a function that takes 2 arguments, diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi index 829735b3c95..bc4fcdbe27a 100644 --- a/doc/lispref/processes.texi +++ b/doc/lispref/processes.texi @@ -68,6 +68,7 @@ Processes}. * Misc Network:: Additional relevant functions for net connections. * Serial Ports:: Communicating with serial ports. * Byte Packing:: Using bindat to pack and unpack binary data. +* UUIDs:: Generating and converting UUIDs. @end menu @node Subprocess Creation @@ -1670,9 +1671,10 @@ On some systems, when Emacs reads the output from a subprocess, the output data is read in very small blocks, potentially resulting in very poor performance. This behavior can be remedied to some extent by setting the variable @code{process-adaptive-read-buffering} to a -non-@code{nil} value (the default), as it will automatically delay reading +non-@code{nil} value, as it will automatically delay reading from such processes, thus allowing them to produce more output before -Emacs tries to read it. +Emacs tries to read it. The default is @code{nil}, since a +non-@code{nil} value reduces performance. @end defvar @menu @@ -3882,3 +3884,154 @@ arguments @var{args}. Its behavior follows that of @code{defmacro}, which the important difference that the new forms can only be used within Bindat type expressions. @end defmac + +@node UUIDs +@section UUIDs +@cindex uuids + + Emacs Lisp can generate and parse the most popular UUID variants to +and from strings and binary. It can generate UUIDv4, UUIDv5 and UUIDv7 +according to RFC 9562. UUIDv4 is a randomly generated identifier, +UUIDv5 is an identifier generated from a standard namespace and a name, +and UUIDv7 is a combination of a timestamp and random identifier, with +the advantage of having good index performance in databases. + +All UUIDs are 16 byte identifiers with a common string representation, +consisting of hex digits and dashes of a predetermined length, such as +@samp{919108f7-52d1-4320-9bac-f847db4148a8}. + +@menu +* UUID Generation:: +* UUID Conversion:: +* Special UUID values:: +@end menu + +@node UUID Generation +@subsection UUID Generation +@cindex uuid generation + + To generate UUIDs, call @code{uuid-v4}, @code{uuid-v5} or +@code{uuid-v7}. UUID v4 and v7 will by default use the normal elisp +@dfn{random} for random numbers, but a different random number generator +can be passed in, as long as it can be called with an arg of the end of +the range of acceptable integers to generate (exclusive), and returns an +integer. + +@defun uuid-v4 &key rng +Return a @code{uuid-v4} Lisp object representing a new UUIDv4. +@var{rng}, if provided, is a function that will, when called with a +numeric argument, return a random number between 0 and that number +(exclusive). +@end defun + +@defun uuid-v7 &key rng +Similar to @code{uuid-v4} but returns a @code{uuid-v7}, which is +generated with a timestamp in addition to random numbers (generated from +@var{rng} in a similar manner as @code{uuid-v4}). +@end defun + +These use random numbers, which should be cryptographically secure. +@xref{Random Numbers}, but generally these random numbers are not +sufficient to generate sufficiently random UUIDs. For private uses, the +default behavior should be sufficient, but for professional uses, +@var{rng} should be used, and provide cryptographically secure random +numbers. + +@noindent +UUIDv5s must be created with a namespace and a name. The namespaces are +defined in @code{uuid-namespace-alist} and are by default @code{dns}, +@code{url}, @code{oid}, and @code{x500}. + +@defun uuid-v5 namespace name +This function returns a new @code{uuid-v5} Lisp object based on +@var{namespace}, which is a symbol in the key of the +@code{uuid-namespace-alist}: @code{dns}, @code{url}, @code{oid}, +@code{x500}, or any symbol added. This is combined with @var{name} to +construct a new UUIDv5. +@end defun + +An example is: + +@cindex uuidv5 +@example +(uuid-v5 'dns "www.example.com") +@end example + +@defvar uuid-namespace-alist +A list of namespace symbols and their corresponding UUIDs. Each alist +entry is a cons of the symbol and a UUID Lisp object representing the +namespace. This is used in @code{uuid-v5}, see above for more info on +how this is used. +@end defvar + +@node UUID Conversion +@subsection UUID Conversion +@cindex uuid conversion + +To use a UUID, typically it is converted to a string, and sometimes to a +binary representation. This is done using @code{uuid-to-string} function. + +@defun uuid-to-string uuid +Return the standard string value, with hex values and dashes, of Lisp +object @code{uuid}. +@end defun + +@example +(uuid-to-string (uuid-v4)) ; @r{"230156d4-488a-45d1-93c9-507ec8be37ca"} +@end example + +@noindent +Binary can also be generated, which generates a unibyte string, using +@code{uuid-to-bytes}, and a numeric representation of a UUID can be +generated with @code{uuid-to-number}. + +@defun uuid-to-bytes uuid +Return a unibyte string representing the binary value of @code{uuid}. +@end defun + +@defun uuid-to-number uuid +Return a numeric representation of the value of @code{uuid}. +@end defun + +@noindent +String UUIDs can also be converted to a UUID Lisp object, with +@code{uuid-from-string}, and bytes can be converted with +@code{uuid-from-bytes}. These work with all UUIDs, not just the ones +this module can generate. + +@defun uuid-from-string uuid-str +Return a UUID Lisp object that represents @var{uuid-str}. +@end defun + +@defun uuid-from-bytes uuid-bytes +Return a UUID Lisp object that represents @var{uuid-bytes}, which is +expected to be a unibyte string. +@end defun + +Valid UUIDs have types, which can be used with @code{cl-typep}, +@code{cl-check-type} and @code{cl-typecase}. The type is specified with +the type specifier @code{(uuid-v <version>)}. @var{version} can be any +version of UUID, but we make sure the UUID variant is correctly +@code{2}; any other value is not a valid version. + +@example +(when (cl-typep my-uuid '(uuid-v 4)) + (process-v4-uuid my-uuid)) + +(defun process-v4-uuid (uuid) + ;; Error if not the correct type + (cl-check-type uuid (uuid-v 4)) + ;; Proceed to process the UUIDv4. + (more-processing uuid)) +@end example + +@node Special UUID values +@subsection Special UUID values +@cindex special uuid values +@cindex uuid nil and uuid max +@cindex nil uuid +@cindex max uuid + +@code{uuid-nil} and @code{uuid-max} are constant values representing the +UUID equivalents of @code{nil} and a max sentinel value, as defined in +RFC 9562. diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index 53d80bc84d2..5aac39fa0f9 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi @@ -444,6 +444,9 @@ characters, and removes all text properties. It may also change @var{string}'s length. @end defun + To modify the text properties of a string, use the functions described +in @ref{Changing Properties}. + @need 2000 @node Text Comparison @section Comparison of Characters and Strings diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index a5535df601b..db2410fbf30 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -238,7 +238,10 @@ reordering of bidirectional text, use the @defun filter-buffer-substring start end &optional delete This function filters the buffer text between @var{start} and @var{end} using a function specified by the variable -@code{filter-buffer-substring-function}, and returns the result. +@code{filter-buffer-substring-function}, and returns the result. The +order of buffer positions specified by @var{start} and @var{end} should +not matter, since this function is frequently used for extracting text +passed to kill functions (@pxref{Kill Functions}). The default filter function consults the obsolete wrapper hook @code{filter-buffer-substring-functions} (see the documentation string @@ -264,6 +267,9 @@ will call to do the actual work. The function receives three arguments, the same as those of @code{filter-buffer-substring}, which it should treat as per the documentation of that function. It should return the filtered text (and optionally delete the source text). +Note that it must process the @var{start} and @var{end} arguments +regardless of the order of the buffer positions they specify, to comply +with the protocol of extracting text for the purposes of killing it. @end defvar @noindent The following two variables are obsoleted by @@ -4863,7 +4869,7 @@ faster but suboptimal solution. The default value is 1000000. @code{replace-region-contents} returns @code{t} if a non-destructive replacement could be performed. Otherwise, i.e., if @var{max-secs} -was exceeded, it returns @code{nil}. +was exceeded or too much memory would have been needed, it returns @code{nil}. Note: When using the refined replacement algorithm, if the replacement is a string, it will be internally copied to a temporary buffer. diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi index 8779cf88917..78b01888a1b 100644 --- a/doc/lispref/variables.texi +++ b/doc/lispref/variables.texi @@ -1748,6 +1748,14 @@ local hook functions that have a non-@code{nil} killed, but if the optional @var{kill-permanent} argument is non-@code{nil}, even those variables will be killed. +If @var{kill-permanent} is the symbol @code{permanent-local}, this +function kills local variables and ignores any variable watchers. If it +is the symbol @code{reset}, the function ignores variable watchers and +resets the buffer as if the buffer was newly created. Use these values +with caution: for example, @code{reset} sets buffer variables such as +@code{default-directory} to @code{nil} and thus may result in unexpected +behavior. + This function also resets certain other information pertaining to the buffer: it sets the local keymap to @code{nil}, the syntax table to the value of @code{(standard-syntax-table)}, the case table to diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index fbd578b08f0..ddc8524ddb6 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -78,14 +78,19 @@ disambiguation, we use the term @dfn{window-system window} when we mean the window-system window corresponding to an Emacs frame. @cindex tiled windows +@cindex window layout Unlike X windows, Emacs windows are @dfn{tiled}; they never overlap within the area of their frame. When a window is created, resized, or deleted, the change in window space is taken from or given to other windows on the same frame, so that the total area of the frame is -unchanged. +unchanged. The @dfn{window layout} of a frame is the result of all +tiling operations for that frame. +@cindex window object +@cindex window identity In Emacs Lisp, windows are represented by a special Lisp object type -(@pxref{Window Type}). +(@pxref{Window Type}). Two windows are identical if and only if they are +represented by the same Lisp object. @defun windowp object This function returns @code{t} if @var{object} is a window (whether or @@ -2020,6 +2025,13 @@ combination. The default is @code{nil}. Other values are reserved for future use. A specific split operation may ignore the value of this variable if it is affected by a non-@code{nil} value of @code{window-combination-limit}. + +If you plan to use a sequence of @code{split-window} calls to produce a +specific, predefined layout of windows on a frame, bind this variable +temporarily to @code{nil}. @code{window-state-put} (@pxref{Window +Configurations}) and the functions which change window layouts +(@pxref{Changing Window Layouts}) do that in order to restore a previous +or systematically changed layout of a frame. @end defopt To illustrate the effect of @code{window-combination-resize}, consider @@ -2297,9 +2309,9 @@ below, we shall always assume that the windows displayed constitute their frame's main window and the @var{window} argument is @code{nil} unless stated otherwise. - The first two commands rotate a window layout either clockwise or -counterclockwise. @cindex rotate window layout + The first two commands rotate an entire window layout either +clockwise or counterclockwise. @deffn Command window-layout-rotate-clockwise &optional window This command rotates the window layout clockwise by 90 degrees. Imagine @@ -2339,9 +2351,10 @@ layout in the opposite direction as demonstrated in the example below. @end smallexample @end deffn -The next two commands @sc{flip} the window layout---rotate it around an -imaginary horizontal or vertical axis. @cindex flip window layout +The next two commands @sc{flip} the window layout---rotate it around an +imaginary horizontal or vertical axis. If the number of windows to be +flipped is odd, the window in the middle remains in its original place. @deffn Command window-layout-flip-topdown &optional window This command flips windows such that windows on the bottom become @@ -2363,7 +2376,7 @@ windows on the top and vice-versa as in the example below. @deffn Command window-layout-flip-leftright &optional window This command rearranges window in a way that the windows on the right -become the window on the left, and vice-versa. +become the windows on the left, and vice-versa. @smallexample @group @@ -2401,16 +2414,22 @@ becomes a vertical split and vice versa. @end smallexample @end deffn -The final two commands can be used to rotate windows within the existing +@cindex rotating windows +The final two commands can be used to @dfn{rotate} windows within the existing layout. They are like the commands that rotate the layout but leave the underlying structure of the layout unchanged. What actually changes are -the positions of windows within the existing layout. -@cindex rotating windows +the positions of windows within the existing layout. This happens in a +way that the space formerly occupied by any window will be occupied by +the window preceding (following if @var{reverse} is non-@code{nil}) it +in the cyclic ordering of windows (@pxref{Cyclic Window Ordering}) on +@var{window}'s frame. These commands may signal an error if windows +chosen to rotate are dedicated to their buffers, atomic or of fixed +size. @deffn Command rotate-windows &optional window reverse -This rotate windows under @var{window} in cyclic ordering. The optional -argument @var{reverse} means to rotate windows backward, in reverse -cyclic order. +This command rotates @var{window}'c child windows in cyclic ordering. +The optional argument @var{reverse} means to rotate windows backwards, +in reverse cyclic order. @smallexample @group @@ -2427,7 +2446,7 @@ cyclic order. @end deffn @deffn Command rotate-windows-back &optional window -This command rotates windows under @var{window} backward in cyclic +This command rotates @var{window}'s child windows backwards in cyclic ordering. @smallexample @@ -2450,7 +2469,7 @@ The last two commands are subject to the following option. If this is @code{nil}, the selected window will remain unaffected by @code{rotate-windows} and @code{rotate-windows-back}. Otherwise, the selected window will change to the window that appears at the location -of the selected window before any of these commands were invoked. +of the window selected before any of these commands were invoked. @end defopt @@ -4934,6 +4953,11 @@ and @var{window-pos} is a marker that gives the window point position The list is ordered so that earlier elements correspond to more recently-shown buffers, and the first element usually corresponds to the buffer most recently removed from the window. + +As a rule, elements are removed from this list when their buffer gets +killed. In rare cases, however, elements may have survived the killing +of their buffer. It's a good idea therefore to always check buffers for +liveness when processing the return value of this function. @end defun @defun set-window-prev-buffers window prev-buffers @@ -7263,11 +7287,16 @@ and/or two columns. In the context of window states, the @dfn{clone of a window} is a window that has the same decorations and contents as the window whose state was used to produce it, but is actually represented by another window -object. Operating on the original or the clone of a window does not -affect the other in any way. Note that while @code{window-state-get} -clones existing windows, these clones are not yet valid windows. They -become valid only after @code{window-state-put} has put them into a live -frame. +object. Hence it does not have the same identity as the original +window. Operating on the original or the clone of a window does not +affect the other in any way. + +Note that while @code{set-window-configuration} always restores the +identity of the windows it puts back into their frame, +@code{window-state-put} never does that. Note also that while +@code{window-state-get} clones existing windows, these clones are not +yet valid windows. They become valid only after @code{window-state-put} +has put them into a live frame. By default, @code{set-window-configuration} and @code{window-state-put} may delete a window from the restored configuration or state when they diff --git a/doc/misc/Makefile.in b/doc/misc/Makefile.in index 11a2dc3d517..dda6a9dd7a9 100644 --- a/doc/misc/Makefile.in +++ b/doc/misc/Makefile.in @@ -65,7 +65,7 @@ MAKEINFO_OPTS = --force -I$(emacsdir) ifeq ($(DOCLANG),) DOCLANG:=default -else ifeq ($(wildcard $(srcdir)/../translations/$(DOCLANG)/info_common.mk),) +else ifeq ($(wildcard $(srcdir)/../translations/$(DOCLANG)/misc/info_common.mk),) $(error No manual language $(DOCLANG) found) DOCLANG:=default endif @@ -78,7 +78,7 @@ DOCMISC_W32 = @DOCMISC_W32@ DOCMISC_W32_TARGET = efaq-w32 ## Info files to build and install on all platforms. -include $(srcdir)/../translations/$(DOCLANG)/info_common.mk +include $(srcdir)/../translations/$(DOCLANG)/misc/info_common.mk ## Info files to install on current platform. INFO_INSTALL = $(INFO_COMMON) $(DOCMISC_W32) diff --git a/doc/misc/calc.texi b/doc/misc/calc.texi index a626ee09f8e..636b024d50c 100644 --- a/doc/misc/calc.texi +++ b/doc/misc/calc.texi @@ -17367,12 +17367,14 @@ and @kbd{t U}, the normal argument is then taken from the second-to-top stack position.) This allows you to give a non-integer time zone adjustment. The time-zone argument can also be an HMS form, or 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). +For example @samp{tzone(JST) = tzone(-9)} and @samp{tzone(gmt) = tzone(0)} +(for Japan standard and Greenwich mean time, respectively). 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, +the @samp{PST}- and @samp{MST-}related names have disagreed with +time in western Canada since 2026, 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, @@ -17397,13 +17399,13 @@ 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 -circa-2022 US Pacific Time look like this: +circa-2026 time in Sydney, Australia might look like this: @smallexample @group -( ( "PST" 8 0 ) ; Name as an upper-case string, then standard - ( "PDT" 8 -1 ) ; adjustment, then daylight saving adjustment. - ( "PGT" 8 "PST" "PDT" ) ) ; Generalized time zone. +(("AEST" -10 0) ; Name as an upper-case string, then standard + ("AEDT" -10 -1) ; adjustment, then daylight saving adjustment. + ("AEGT" -10 "AEST" "AEDT")) ; Generalized time zone. @end group @end smallexample diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi index 86af253bdf1..b15b1b187a4 100644 --- a/doc/misc/cl.texi +++ b/doc/misc/cl.texi @@ -1245,12 +1245,6 @@ blocks for other macros like @code{cl-pushnew}. The @code{cl-letf} and @code{cl-letf*} macros are used in the processing of symbol macros; @pxref{Macro Bindings}. -@defmac with-memoization @var{place} @var{code}@dots{} -This macro provides a simple way to do memoization. @var{code} is -evaluated and then stashed in @var{place}. If @var{place}'s value is -non-@code{nil}, return that value instead of evaluating @var{code}. -@end defmac - @node Variable Bindings @section Variable Bindings diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi index 03767a2e68c..3e39f819a52 100644 --- a/doc/misc/erc.texi +++ b/doc/misc/erc.texi @@ -76,12 +76,24 @@ Getting Started * Sample Session:: Example of connecting to the @samp{#emacs} channel * Special Features:: Differences from standalone IRC clients +Advanced Module Topics + +* Scope: Module Scope. Differences between module types. +* Loading: Module Loading. How ERC loads modules. +* Example: Module Example. An example module. +* Usage: Module Usage. How to use specific modules. + +Individual Modules + +* Settings: Settings Module. Per-buffer configuration. + Advanced Usage * Connecting:: Ways of connecting to an IRC server. * SASL:: Authenticating via SASL. * Sample Configuration:: An example configuration file. * Integrations:: Integrations available for ERC. +* Match API:: Custom matching and highlighting. * Options:: Options that are available for ERC. @end detailmenu @@ -136,7 +148,6 @@ ERC comes with the following capabilities enabled by default. @node Getting Started @chapter Getting Started -@cindex settings The command @kbd{M-x erc} will start ERC and prompt for the server to connect to. If you're unsure of which server or network to connect @@ -544,6 +555,10 @@ Scroll to the bottom of the buffer @item services Identify to Nickserv (IRC Services) automatically +@cindex modules, settings +@item settings +Apply options locally per-buffer (@pxref{Settings Module}) + @cindex modules, smiley @item smiley Convert smileys to pretty icons @@ -615,9 +630,19 @@ so demands special precautions to avoid degrading the user experience. At present, the only such module is @code{networks}, whose library ERC always loads anyway. +@c Advanced module topics and individual module usage. +@menu +* Scope: Module Scope. Differences between module types. +* Loading: Module Loading. How ERC loads modules. +* Example: Module Example. An example module. +* Usage: Module Usage. How to use specific modules. +@end menu + @anchor{Local Modules} -@subheading Local Modules +@node Module Scope +@section Scope @cindex local modules +@cindex module scope @c Earlier language in code comments, commit messages, and tracker @c discussions used to describe a local module as being "active" in a @@ -698,10 +723,8 @@ buffers belonging to their connection (when called interactively). And unlike global toggles, none of these ever mutates @code{erc-modules}. -@c FIXME add section to Advanced chapter for creating modules, and -@c move this there. -@anchor{Module Loading} -@subheading Loading +@node Module Loading +@section Loading @cindex module loading ERC loads internal modules in alphabetical order and third-party @@ -755,7 +778,623 @@ Customize into displaying the widget for @code{erc-modules} incorrectly, with built-in modules moved from the predefined checklist to the user-provided free-form area. +@node Module Example +@section Example +@cindex module example + +This is a walkthrough of a working module, presented in sections. +If you'd prefer to view it as a whole, you can install it as a +third-party package through ERC's devel archive: +@uref{https://emacs-erc.gitlab.io/bugs/archive/erc-view.html}. + +@lisp +;;; erc-view.el -- Automatic view-mode for ERC -*- lexical-binding: t; -*- + +;; Maintainer: The ERC Maintainers <emacs-erc@@gnu.org> +;; Keywords: convenience +;; Version: 0.1 +;; Package-Requires: ((emacs "30.1")) +;; URL: https://gitlab.com/emacs-erc/erc-view + +;;; Commentary: + +;; This is a demo local module for ERC. It automatically enables +;; `view-mode' when leaving the prompt area and disables it when +;; reentering. It also ensures `view-mode' stays enabled or disabled +;; when reconnecting. + +;;; Code: +@end lisp + +@noindent +You need to import ERC's main library somehow. The easiest way is +directly, via a simple @code{(require 'erc)}, although this module does +so indirectly because it also uses definitions from @file{erc-goodies}: + +@lisp +(require 'erc-goodies) +(require 'view) +@end lisp + +@noindent +Avoid headaches by aligning the name of your module with its containing +library and Custom group: one group and module per library. + +@lisp +(defgroup erc-view nil + "Automatically enter and exit `view-mode' in ERC." + :version "0.1" + :group 'erc) + +(defcustom erc-view-enable-when-exiting-prompt t + "Whether to enable `view-mode' when exiting the prompt area." + :type 'boolean) + +(defcustom erc-view-disable-when-entering-prompt t + "Whether to disable `view-mode' when entering the prompt area." + :type 'boolean) + +(defcustom erc-view-backspace-at-prompt-scrolls-down t + "Whether a \\`<backspace>' at the prompt scrolls down to enter `view-mode'." + :type 'boolean) + +(defvar-local erc-view--enabled-p nil + "Current reconnect-aware activation state of `view-mode'.") +@end lisp + +@noindent +In some cases, you may need a variable's value to survive the +reinitialization of ERC's @code{major-mode} performed in each buffer +upon reconnecting. Do this by leveraging the @code{permanent-local} +symbol property. (@pxref{Creating Buffer-Local,,,elisp,}.) Also see +the mini-section after this example for a few caveats regarding the +durability of permanent values like this. + +@lisp +(put 'erc-view--enabled-p 'permanent-local t) +@end lisp + +Moving on, if your module needs to bind keys, define its keymap +@emph{before} the module itself, and use the standard minor-mode naming +convention of @code{erc-my-module-mode-map}. + +@lisp +(defvar-keymap erc-view-mode-map + :doc "Keymap for `view-mode' in ERC." + "<remap> <delete-backward-char>" #'erc-view--enable-on-backspace) + +(defvar-keymap erc-view-mode-overriding-map + :parent view-mode-map + :doc "Overriding keymap for `view-mode' when `erc-view-mode' is active. +Hitting \\`<RET>' atop a button prompts for an action by default. Use +\\`C-j' or \\`j' for scrolling up by a line." + "C" nil ; View-kill-and-leave + "E" #'erc-view--exit-to-bottom ; View-exit-and-edit + "Q" nil ; View-quit-all + "k" #'View-scroll-line-backward ; Vi backwards line + "j" #'View-scroll-line-forward ; Vi forwards line + "S-<return>" #'View-scroll-line-backward) +@end lisp + +You'll almost always want to define your module as buffer-local. Do +this by including a @code{localp} flag as the final parameter to +@code{define-erc-module}, after the @dfn{disable body}. If your module +only operates in one kind of buffer, disable it elsewhere in the +@dfn{enable body}. For example, if it should only run in server +buffers, disable it in target buffers by doing something like @code{(if +(erc-target) (erc-my-module-mode -1) (erc-my-module--setup))}. And in +all cases, do mention the module's intended @dfn{scope} in the doc +string. Some informal adjectives that may help with that are: + +@itemize +@item query-local +@item channel-local +@item target-local (query or channel) +@item server-local +@item session-local (server and target) +@item buffer-local (server or target) +@end itemize + +@noindent +You may also wish to mention this in the Custom group's doc string. + +@lisp +(define-erc-module view nil + "Use `view-mode' for reading and navigating \"scrollback\". +If enabling, restore `view-mode' activation state. + +Note that if paired with the `scrolltobottom' module, the option +`erc-scrolltobottom-all' should probably be enabled. This module is +buffer-local." + ((add-hook 'view-mode-hook #'erc-view--remember 0 t) + (add-hook 'post-command-hook #'erc-view--enforce-prompt-boundary 0 t) + (setf (alist-get 'view-mode minor-mode-overriding-map-alist) + erc-view-mode-overriding-map) + (unless (local-variable-p 'erc-view--enabled-p) + (setq-local erc-view--enabled-p nil)) + (view-mode (if erc-view--enabled-p +1 -1))) + ((kill-local-variable 'erc-view--enabled-p) + (remove-hook 'post-command-hook #'erc-view--enforce-prompt-boundary t) + (remove-hook 'view-mode-hook #'erc-view--remember t) + (setf (alist-get 'view-mode minor-mode-overriding-map-alist nil 'remove) + nil)) + localp) +@end lisp + +Always define your module early, before any code that refers to its mode +command or minor-mode variable. + +@lisp +(defun erc-view--enable-on-backspace (lines) + "Enable `view-mode' at the prompt by hitting \\`<backspace>'." + (interactive "P") + (if (and erc-view-backspace-at-prompt-scrolls-down (not view-mode) + (= (point) erc-input-marker)) + (progn + (view-mode +1) + (View-scroll-page-backward lines)) + (call-interactively #'delete-backward-char))) + +(defun erc-view--enforce-prompt-boundary () + "Enable or disable `view-mode' when crossing prompt boundary." + (when-let* + ((new (if (>= (point) erc-input-marker) + (and view-mode erc-view-disable-when-entering-prompt -1) + (and (not view-mode) erc-view-enable-when-exiting-prompt +1)))) + (run-at-time 0 nil (lambda (buffer new) + (with-current-buffer buffer (view-mode new))) + (current-buffer) new))) + +(defun erc-view--exit-to-bottom () + "Scroll to prompt, exit `view-mode', and move to EOB." + (interactive) + (let (view-no-disable-on-exit) + (View-scroll-to-buffer-end) + (View-exit) + (goto-char (point-max)))) + +(defun erc-view--remember () + "Remember the value of `view-mode'. +Disable `erc-move-to-prompt-setup' locally when `view-mode' is enabled." + (setq erc-view--enabled-p view-mode) + (when erc-move-to-prompt-mode + (if view-mode + (remove-hook 'pre-command-hook #'erc-move-to-prompt t) + (erc-move-to-prompt-setup)))) +@end lisp + +Don't forget to @code{provide} your module so that +@code{erc-update-modules} can find it. + +@lisp +(provide 'erc-view) + +;;; erc-view.el ends here + +@end lisp +Mimicking the above should just about cover most use cases. If your +module isn't loading correctly, it's likely a naming, layout, or +packaging issue. If you @emph{must} defy the convention recommended +earlier regarding a library-group-module correspondence or if you've +designed your module mainly to be toggled interactively rather than +added to @code{erc-modules}, try placing a line like the following above +the module's definition. + +@lisp +;;;###autoload(autoload 'erc-my-module-mode "erc-my-module" nil t) +@end lisp + +@noindent +Just remember, doing so means you'll need to (re)generate the autoload +file when hacking locally (@pxref{Fetching Package Sources,,, emacs,}). + +@subsection Nuances Regarding Local Module State +By convention, disabling a module's minor mode kills local bindings. +Mode commands, like @code{erc-view-mode}, do so in the current buffer +only, while unidirectional ones, like @code{erc-view-mode-disable}, do +so connection-wide if given a prefix argument. + +There are also occasions in which the persistence of a buffer-local +variable is undefined, most notably during a @dfn{transplant}, when +copying an old buffer's contents into its replacement buffer. This +crude merge operation can occur, for example, in server buffers upon +@dfn{logical connection} (at @samp{MOTD}'s end) if a user reconnects +with a new invocation of an entry-point command, like @code{erc-tls}, +instead of via the auto-reconnect facility or by issuing a +@samp{/reconnect} at the prompt. (Unaffected are entry-point +invocations that include an @code{:id} keyword because reassociation +happens immediately in such cases, before ERC even initializes any +modules.) + +Transplants can also happen in target buffers, most often after a user +reconnects under a new nick and conducts business in the same channel +and query buffers, only to renick @emph{back} to the previous nick via a +@samp{/nick oldme} or similar. As of version 5.7, ERC retains the +current buffer's permanent value in all such situations, meaning ERC +ignores permanent values from previous buffers and retains default ones +assigned during module initialization. Package authors needing access +to these internal transplant junctures should make a case on the mailing +list or the bug tracker. + + @c PRE5_4: Document every option of every module in its own subnode +@node Module Usage +@section Usage +@cindex individual modules +@cindex module usage + +Detailed documentation on individual built-in modules. + +@menu +* Settings: Settings Module. Scoped user options. +@end menu + +@node Settings Module +@subsection Settings +@cindex settings + +This global module lets you apply ERC options on a per-buffer basis as +local variable bindings (@pxref{Buffer-Local Variables,,, elisp,}). It +consists of a single @dfn{meta option}: + +@defopt erc-settings +An alist where each key is a @dfn{match condition} and each value a list +of bindings that loosely resembles a @code{let}-style @var{varlist}. +The first element of each binding is the variable of a user option and +the second an arbitrary sexp assigned to it locally in all matching +buffers. You can tell ERC to evaluate a given sexp as a Lisp form +before assigning it by including a trailing third element: the +@dfn{modifier flag} @code{:eval}. + +A match condition specifies when and whether ERC should apply each group +of bindings. These resemble @code{buffer-match-p} conditions, with two +major differences (@pxref{Buffer List,,, elisp,}). The first is that +predicate conditions don't take any arguments. Instead, ERC runs them +with the candidate buffer current. The second difference is that the +assortment of associative cons-cell conditions is completely new. Gone +are @code{major-mode}, @code{category}, etc. In their place, ERC offers +the following: + +@itemize +@item @code{(network . @samp{<symbol>})} +@item @code{(id . @samp{<symbol>})} +@item @code{(name . @samp{<string>})} +@item @code{(target . @samp{<string or nil>})} +@end itemize + +The associated @code{cdr} values for the @code{network} and @code{id} +conditions are symbols identifying the current IRC network and the +@dfn{network context}, respectively. When first connecting, a +@code{network} condition is always @code{nil}, but an @code{id} +condition can be non-@code{nil} if you supply a matching @var{ID} +argument to an entry-point command, like @code{erc-tls} (@pxref{Network +Identifier}). + +Additionally, ERC also recognizes @code{buffer-match-p}'s boolean +operations and constants: + +@itemize +@item @code{(and @samp{<condition...>})} +@item @code{(or @samp{<condition...>})} +@item @code{(not @samp{<condition>})} +@item @code{t} +@item @code{nil} +@end itemize + +Also valid are regular expressions and nullary predicates: + +@itemize +@item @code{"<some regexp>"} +@item @code{<predicate symbol>} +@end itemize + +@end defopt + +@noindent +Here's a contrived @code{erc-settings} value containing seven entries, +the first of which has two assignments: + +@lisp +(((and (network . Libera.Chat) ; buffers #emacs, + "\\`#emacs") ; #emacs-foo, etc., + (my-own-variable 42) ; on Libera.Chat only + (erc-foo "")) + + ((or (target . "#chan") ; buffers #chan, bob, + (target . "bob")) ; chan@@Libera.Chat, + (erc-foo (erc-current-nick) :eval)) ; bob@@OFTC, etc. + + (erc-open-server-buffer-p (erc-bar 1)) ; connected server buffers + (erc-query-buffer-p (erc-bar 2)) ; query buffers only + (erc-channel-buffer-p (erc-bar 3)) ; channel buffers only + (erc-target (erc-bar 4)) ; query or channel buffers + (t (erc-bar 5))) ; any `erc-mode' buffer +@end lisp + +@noindent +Unfortunately, predicate functions too dissimilar from those in the last +hunk above may not work in all match contexts due to the interaction +between this module and ERC's rather convoluted major-mode setup. While +the only way to know for sure is to try them, selecting them becomes +much easier if you can gain a sense for when exactly @samp{settings} +attempts to create bindings: + +@itemize +@item +In server buffers +@enumerate +@item +before ERC enables any modules or sets any local variables +@item +after establishing a logical IRC connection and learning what network +it's connected to +@end enumerate + +@item +In target buffers +@enumerate +@item +before enabling any modules, but only if you're overriding +@code{erc-modules} and, only then, for that option alone +@item +after ERC has set most of its default local variables and run +global-module setup but before running major-mode hooks or local-module +setup +@end enumerate +@end itemize + +The main downside of this staggered approach is that @samp{settings} +skips any bindings for variables that already have a local binding +rather than do the intuitive thing and simply clobber them. The reason +for this is to retain a consistent state between a global module's minor +mode setup and any local-module setup or major-mode hooks. They must +all witness the same value for the same variable. + +Revisiting the phony example above with this precedence quirk in mind, +notice that the made-up variable @code{erc-bar} will be @code{2} in +query buffers, @code{3} in channel buffers, and @code{5} in server +buffers. It's never @code{1} because the first binding opportunity +occurs before connecting, when @code{erc-open-server-buffer-p} returns +@code{nil}. It's likewise never @code{4} because that binding appears +lower in the list than those for @code{2} and @code{3}. For more on +this behavior, see the very last example below. + +When it comes to binding the option @code{erc-modules}, @samp{settings} +must make special accommodations. Getting it right may take some trial +and error, and it's only guaranteed to work for local modules because +most global ones share state among all sessions. However, it's fine to +include global modules in an @code{erc-modules} binding as long as they +also appear in the @code{default-value}. To set @code{erc-modules} for +a specific server buffer, specify an entry like + +@lisp +("[.]libera[.]chat:" + (erc-modules (seq-union '(sasl keep-place-indicator) erc-modules) + :eval) + (erc-sasl-user :nick)) +@end lisp + +@noindent +Here, the match condition is a regexp matching a dialed @acronym{TCP} +address because server buffers typically have these as temporary names +while connecting. As mentioned, ERC later renames them to reflect a +discovered network, after which @samp{settings} binds any matching +unbound options. + +A session's target buffers normally share the @code{erc-modules} value +bound locally in their server buffer. To specify a separate, overriding +set of modules for certain target buffers, use a condition that only +applies to them: + +@lisp +((and (network . Libera.Chat) erc-channel-buffer-p) + (erc-modules (seq-union '(fill-wrap) erc-modules) :eval)) +@end lisp + +@noindent +This is often unnecessary because local modules that only operate in one +kind of buffer tend to disable themselves elsewhere. And some, like +@samp{keep-place-indicator}, offer an option to restrict activation +based on buffer type. + +@anchor{Settings Examples} +@subsection Settings Examples +@cindex settings, examples + +A typical setup might include configuration for two networks, one that +uses @acronym{SASL} to authenticate and another that uses a server +password. + +@lisp +(setopt erc-modules + `(settings ,@@erc-modules) ; assuming `erc' is loaded + + erc-settings + ;; Pre-connect and server buffer config for @samp{Libera.Chat}. + '(("libera\\.chat:" + (erc-prompt "Libera>") + (erc-autojoin-channels-alist ((Libera.Chat "##jrh"))) + (erc-header-line-format "%n on %S (%m, %l)") + (erc-sasl-user :nick) + (erc-modules `(sasl ,@@erc-modules) :eval)) + + ;; Channel buffer config for @samp{Libera.Chat}. + ((and (network . Libera.Chat) erc-channel-buffer-p) + (erc-modules `(keep-place-indicator ,@@erc-modules) :eval) + (erc-prompt erc-prompt-format) + (erc-prompt-format "%c%b>") + (erc-header-line-format "%t: %o")) + + ;; Query buffer configuration for any network. + (erc-query-buffer-p + (erc-prompt erc-prompt-format) + (erc-prompt-format "%S>") + (erc-header-line-format nil)) + + ;; Pre-connect and server-buffer config for @samp{OFTC}. + ("oftc\\.net:" + (erc-prompt "OFTC!") + (erc-modules `(nicks ,@@erc-modules) :eval)))) +@end lisp + +@noindent +Note that the pre-connection config described in the last entry can't +use the @dfn{global module} @samp{services} because it's incompatible +with the @dfn{local module} @samp{sasl}, needed for Libera by the first +entry. In this scenario, instead of a server password, the @samp{OFTC} +connection could alternatively use @dfn{CertFP} via auth-source (see +next example). + +@anchor{ID-based Settings Example} +@subsubsection ID-based +@cindex settings, examples, id-based + +New users coming from traditional IRC clients often express a desire to +store connection details alongside other per-network or per-connection +configuration. Although ERC was designed to keep these concerns +separate, the @samp{settings} module can emulate that experience to some +degree. + +@lisp +(setopt erc-modules + `(settings ,@@erc-modules) + + erc-settings + ;; Connection details common to both @samp{Libera.Chat} IDs. + '(((and (or (id . lib-jrh) (id . lib-jrbot)) + (not erc-server-process-alive)) + (erc-server "irc.libera.chat") + (erc-port 6697) + (erc-modules `(sasl ,@@erc-modules) :eval)) + + ;; Connection details for account @samp{jrh}. + ((and (id . lib-jrh) (not erc-server-process-alive)) + (erc-nick "jrh") + (erc-user-full-name "J. Random Hacker") + (erc-email-userid "jrh") + (erc-autojoin-channels-alist ((lib-jrh "##jrh")))) + + ;; Connection details for account @samp{jrbot}. + ((and (id . lib-jrbot) (not erc-server-process-alive)) + (erc-nick "jrbot") + (erc-email-userid "jrbot") + (erc-user-full-name "J.R. Bot (jrh's bot)") + (erc-sasl-auth-source-function erc-auth-source-function) + (erc-autojoin-channels-alist ((lib-jrbot "##jrh" "##jrbot")))) + + ;; Non-connection opts for both @samp{Libera.Chat} sessions. + ((and (network . Libera.Chat) erc-open-server-buffer-p) + (erc-prompt "libera>") + (erc-header-line-format "%n on %S (%m, %l)")) + ((and (network . Libera.Chat) erc-channel-buffer-p) + (erc-modules `(keep-place-indicator ,@@erc-modules) :eval) + (erc-prompt erc-prompt-format) + (erc-prompt-format "%c%b>") + (erc-header-line-format "%t: %o")) + + ;; Server details for @samp{OFTC}. + ((and (id . oftc) (target . nil)) + (erc-server "irc.oftc.net") + (erc-port 6697) + (erc-nick "jrh") + (erc-email-userid "jrh") + (erc-user-full-name "J. Random Hacker") + (network-stream-use-client-certificates t) + (erc-modules `(services-regain ,@@erc-modules) :eval) + (erc-prompt "jrh@@OFTC!")))) + +(defun my-erc-up (id) + "Connect to preconfigured session identified by ID." + (interactive "SNet id: ") + (erc-tls :server nil + :port nil + :nick nil + :user nil + :password nil + :full-name nil + :id network-id)) +@end lisp + +@noindent +With a setup like the above, you can connect to a predefined session by +supplying an identifying symbol, like @code{lib-jrh}, along with the +@var{ID} keyword parameter to the entry-point command @code{erc-tls}. +The main gotcha when using these identifiers is that a regexp targeting +a dialed @acronym{TCP} address, like +@code{"\\`irc[.]libera[.]chat:6697\\'"}, won't work for conditions like +the first one above because server buffers receive permanent names +immediately upon creation, long before connecting. Instead, you'll want +to specify a chosen identifier via the @samp{(id . <symbol>)} pattern +and likely qualify it with another subcondition, like @code{(not +erc-server-process-alive)}, to ensure that the @code{erc-modules} +binding only matches the server buffer and not any target buffers. +Equivalent qualifying subconditions would be @code{(not erc-target)} and +@code{(target . nil)}. + +Regarding authentication, notice that the @samp{lib-jrbot} connection +retrieves its @acronym{SASL} credentials, which might be a client +certificate, via auth-source, while session @samp{lib-jrh} prompts you +interactively for a password. (@xref{SASL, SASL in ERC}.) The +@samp{oftc} connection also uses auth-source to supply its credentials, +this time for non-@acronym{SASL} client-cert (@dfn{CertFP}) +authentication. Lastly, in the scenario above, a user would need to run +@kbd{M-x my-erc-up @key{RET}} instead of @kbd{M-x erc @key{RET}} when +connecting to IRC. For convenience, ERC provides a similar command: + +@defun erc-settings-connect-by-id network-id +Prompt the user and provide completion for some @samp{(id . <symbol>)} +appearing in their @code{erc-settings}, and specify it as the argument +to the @var{ID} keyword parameter when invoking @code{erc-tls}. +@end defun + +With both traditional and ID-based setups, it's often more convenient to +define less exclusive, more ``overlapping'' match conditions: + +@lisp +(use-package erc-settings + :custom + (erc-settings + '(((not erc-server-process-alive) ; common to all servers + (erc-nick "jrh") + (erc-port 6697) + (erc-email-userid "jrh") + (erc-user-full-name "J. Random Hacker")) + + (erc-channel-buffer-p ; all channels + (erc-modules `(keep-place-indicator ,@@erc-modules) :eval)) + + ((id . id-libera) ; Libera.Chat only, including targets + (erc-server "irc.libera.chat") + (erc-sasl-password "changeme") + (erc-modules `(sasl ,@@erc-modules) :eval) + (erc-prompt erc-prompt-format) + (erc-autojoin-channels-alist ((id-foonet "#erc")))) + + ((id . id-oftc) ; OFTC only, including targets + (erc-server "irc.oftc.net") + (erc-modules `(fill-wrap ,@@erc-modules) :eval) + (erc-autojoin-channels-alist ((id-barnet "##jrh"))))))) +@end lisp + +If you go this route, know that @samp{settings} will often create local +bindings in buffers where they're not applicable. In the above example, +buffer @file{#erc} on @samp{Libera.Chat} will have @code{erc-server} and +@code{erc-sasl-password} bound locally for no reason. In most cases, +this is perfectly harmless. + +A final thing to notice about the example above is that the +@code{erc-modules} binding in the second group, the one with match +condition @code{erc-channel-buffer-p}, effectively @dfn{shadow}s that +same variable in all remaining settings affecting channel buffers. If +it instead appeared at the end of the list, ERC would skip its +@code{erc-modules} binding because the variable would already be locally +bound. But, as is, both @file{##jrh} on @samp{OFTC} and @file{#erc} on +@samp{Libera.Chat} activate @samp{keep-place-indicator} but not +@samp{fll-wrap}. Server buffer @file{id-oftc} has only @samp{fll-wrap}, +and server buffer @file{id-libera} has neither. And, if you were to +receive a query from @samp{alice} on @samp{OFTC}, buffer @file{alice} +would only have @samp{fill-wrap} but not @samp{keep-place-indicator} +because it's a non-channel on @samp{OFTC}. @node Advanced Usage @@ -767,6 +1406,7 @@ to the user-provided free-form area. * SASL:: Authenticating via SASL. * Sample Configuration:: An example configuration file. * Integrations:: Integrations available for ERC. +* Match API:: Custom matching and highlighting. * Options:: Options that are available for ERC. @detailmenu @@ -1263,6 +1903,11 @@ authenticate successfully. @item Multiple networks +If you use the @samp{settings} module, introduced in ERC 5.7, please +refer to that section's guide for a more modern, config-based approach +to specifying buffer-local @acronym{SASL} options (@pxref{Settings +Examples}). + @example # ~/.authinfo.gpg @@ -2101,6 +2746,322 @@ All keys are symbols, as are values, unless otherwise noted. @end itemize @end table +@node Match API +@section Match API +@cindex low-level match + +This section describes the low-level @samp{match} @acronym{API} +introduced in ERC 5.7. For basic configuration help, please see the doc +strings for option @code{erc-pal-highlight-type} and friends in the +@code{erc-match} group. Unfortunately, those options often prove +insufficient for more granular filtering and highlighting needs, and +advanced users may come to outgrow them. However, under the hood, those +options all use the same foundational @code{erc-match} API, which +centers around a @code{cl-defstruct} @dfn{type} of the same name: + +@deftp {Struct} erc-match @ + predicate spkr-beg spkr-end body-beg sender nick command handler newlinep + + This is a @code{cl-struct} type that contains some handy facts about + the message being processed. That formatted message occupies the + narrowed buffer when ERC creates and provides access to each + @code{erc-match} instance. To use this interface, you add a + @dfn{constructor}-like function to the hook + @code{erc-match-functions}: + + @defopt erc-match-functions + + An abnormal hook for which each member function accepts the parameters + named above as an @samp{&rest}-style plist and returns a new + @code{erc-match} instance. Conforming to this interface are, of + course, traditional constructors automatically provided by a + @code{cl-defstruct} definition derived from @code{erc-match}, such as + @samp{make-my-match} for some @dfn{subtype} @samp{my-match}. + + @end defopt + + The only slot you definitely need to specify is @samp{predicate}. + Both it and @samp{handler} are functions that take a single argument: + the instance itself. As its name implies, @samp{predicate} must + return non-@code{nil} if @samp{handler}, whose return value ERC + ignores, should run. + + A few slots, like @samp{spkr-beg}, @samp{spkr-end}, and @samp{nick}, + may surprise you. The first two are null for non-chat messages, like + those displayed for @samp{JOIN} events. The @samp{nick} slot can + likewise be @code{nil} if the sender of the message is a domain-style + host name, such as @samp{irc.example.org}, which it often is for + informational messages, like @samp{*** #chan was created on 2023-12-26 + 00:36:42}. This includes, for example, server-sent @samp{NOTICE}s and + @samp{221} user-mode changes. + + To locate the start of the just-inserted message, use slot + @samp{body-beg}, a marker indicating the beginning of the message + proper. Locating the end depends on whether the narrowed buffer + includes a trailing newline, which it does if the slot @samp{newlinep} + is non-nil. If you want to extract just the message body's text, use + the function @code{erc-match-get-message-body}: + + @defun erc-match-get-message-body match + + Takes an @code{erc-match} instance and returns a string containing the + message body, sans trailing newline and any leading speaker or + decorative component, such as @code{erc-notice-prefix}. The match + buffer must be current. + + @end defun + +@end deftp + +@noindent +Unless you're writing a module, there's often no need to subclass +@code{erc-match}. For everyday tasks or simple customizations in your +@file{init.el}, you can often just instantiate it directly (it's +@dfn{concrete}). To do this, define a function that invokes its +constructor: + +@lisp +(require 'erc-match) + +(defvar my-mentions 0) + +(defun my-match (&rest plist) + (apply #'erc-match + :predicate (lambda (_) (search-forward "my-project" nil t)) + :handler (lambda (_) (cl-incf my-mentions)) + plist)) + +(add-hook 'erc-match-functions #'my-match) +(setopt erc-prompt (lambda () (format "%d!" my-mentions))) +@end lisp + +@noindent +Here, the user could just as well shove the incrementer into the +@samp{predicate} body, since @samp{handler} is set to @code{ignore} by +default (however, some frown at the notion of a predicate exhibiting +side effects). The user could also choose to concentrate only on chat +content by filtering out non-@samp{PRIVMSG} messages via the slot +@samp{command}. + +In cases where you need a handler to only run when some other match type +appearing earlier in @code{erc-match-functions} has _not_ yielded a +match, use: + +@defun erc-match-get-match constructor + +When called from a @samp{handler} or a @samp{predicate} body, this +utility returns the @code{erc-match} instance from the last successful +match by @code{erc-match-functions} member @var{constructor} for the +current message. Use this for deduplication and to share data between +match instances. + +@end defun + +@noindent +For a detailed example of matching for non-highlighting purposes, see +the @samp{jabbycat} demo module, available on ERC's dev-oriented package +archive: @uref{https://emacs-erc.gitlab.io/bugs/archive/jabbycat.html}. +If you're in a hurry, check out @file{erc-desktop-notifications.el}, +which ships with ERC. Just be aware that it's full of potentially +confusing compatibility-related fuss you'll want to ignore, such as +adapting the global setup and teardown business to a buffer-local +context. (New modules most likely adhere to the modern convention of +being defined as @code{local} in order to allow things like adding local +members to @code{erc-match-functions} in their @dfn{enable body}.) + +@anchor{highlighting} +@subsection Highlighting +@cindex highlighting + +Module authors and normal users alike will often want to manage and +apply faces themselves. If that's you, feel free to skip to the more +extensive examples in the subsection below. However, for the sake of +completeness, it's worth mentioning that (especially in a pinch) you can +likely piggyback atop the highlighting functionality already provided by +@samp{match} to support its traditional high-level options. + +@lisp +(require 'erc-match) + +(defvar my-keywords + `((foonet ("#chan" ,(rx bow (or "foo" "bar" "baz") eow))))) + +(defface my-face + '((t (:inherit font-lock-constant-face :weight bold))) + "My face.") + +(defun my-match (&rest plist) + (apply #'erc-match-opt-keyword + :data (and-let* ((chans (alist-get (erc-network) my-keywords))) + (cdr (assoc (erc-target) chans))) + :face 'my-face + plist)) + +(add-hook 'erc-match-functions #'my-match) +@end lisp + +@noindent +Here, the user leverages a handy subtype of @code{erc-match}, called +@code{erc-match-opt-keyword}, which actually descends directly from +another, intermediate @code{erc-match} type: + +@deftp {Struct} erc-match-traditional category face data part + +Use this type or one of its descendants (see below) if you want +@code{erc-text-matched-hook} to run right after the @samp{handler} +slot's default highlighter, @code{erc-match-highlight}, on every match +for which the @samp{category} slot's value is non-@code{nil} (it becomes +the argument provided for the hook's @var{match-type} parameter). + +The @samp{part} slot determines what portion of the message is being +highlighted or otherwise operated on. It can be any symbol, but the +ones with predefined methods are @code{nick}, @code{message}, +@code{all}, @code{keyword}, @code{nick-or-keyword}, and +@code{nick-or-mention}. + +Accompanying the @samp{part} slot is @samp{data}, which holds the value +of the module's option corresponding to the specific type. For example, +ERC initializes the @samp{data} slot for the @code{erc-match-opt-pal} +type with the value of @code{erc-pals}. + +The default handler, @code{erc-match-highlight}, does its work by +deferring to a purpose-built @dfn{method} meant to handle +@samp{part}-based highlighting: + +@defop {Method} erc-match-traditional erc-match-highlight-by-part @ + instance part + + You can override this method by @dfn{specializing} on any subclassed + @code{erc-match-traditional} type and/or non-reserved @var{part}, such + as one known only to your @file{init.el} or (informally) associated + with your package by its library @dfn{namespace}. + +@end defop + +Note that when the handler runs, the narrowed buffer contains a trailing +newline after the inserted message because, unlike with a normal +@code{erc-match} object, the @samp{newlinep} slot is non-nil. + +@end deftp + +@noindent +You likely won't be needing these, but just for the record, other +options-based types similar to @code{erc-match-opt-keyword} include +@code{erc-match-opt-current-nick}, @code{erc-match-opt-fool}, +@code{erc-match-opt-pal}, and @code{erc-match-opt-dangerous-host}. (If +you're familiar with this module's user options, you'll notice some +parallels here.) + +@anchor{highlighting examples} +@subsubsection Complete Highlighting Examples +@cindex highlighting examples + +As mentioned, most users needn't bother with the piggybacking approach +detailed above, which can oftentimes be more complicated than starting +afresh. Here's a more elaborate, module-like example demoing some +highlighting with a custom @code{erc-match}-derived type. It's a +superficial rewrite of @file{erc-colorize.el} by Sylvain Rousseau +@uref{https://github.com/thisirs/erc-colorize.git}. + +@lisp +;;; erc-colorize.el --- Per-user message faces -*- lexical-binding: t; -*- + +(require 'ring) +(require 'erc-match) +(require 'erc-button) ; for `erc-button-add-face' + +(defgroup erc-colorize nil + "Highlight messages with per-user faces from a limited pool." + :group 'erc) + +(defface erc-colorize-1 '((t :inherit font-lock-keyword-face)) + "Auto-assigned face for distinguishing between messages.") + +(defface erc-colorize-2 '((t :inherit font-lock-type-face)) + "Auto-assigned face for distinguishing between messages.") + +(defface erc-colorize-3 '((t :inherit font-lock-string-face)) + "Auto-assigned face for distinguishing between messages.") + +(defface erc-colorize-4 '((t :inherit font-lock-constant-face)) + "Auto-assigned face for distinguishing between messages.") + +(defface erc-colorize-5 '((t :inherit font-lock-preprocessor-face)) + "Auto-assigned face for distinguishing between messages.") + +(defface erc-colorize-6 '((t :inherit font-lock-variable-name-face)) + "Auto-assigned face for distinguishing between messages.") + +(defface erc-colorize-7 '((t :inherit font-lock-warning-face)) + "Auto-assigned face for distinguishing between messages.") + +(defvar erc-colorize-faces '(erc-colorize-1 + erc-colorize-2 + erc-colorize-3 + erc-colorize-4 + erc-colorize-5 + erc-colorize-6 + erc-colorize-7) + "List of faces to apply to chat messages.") + +(defvar-local erc-colorize-ring nil + "Ring of cons cells of the form (NICK . FACE).") + +(define-erc-module colorize nil + "Highlight messages from a speaker with the same face in target buffers." + ((when (erc-target) + (add-hook 'erc-match-functions 'erc-colorize 0 t) + (setq erc-colorize-ring (make-ring (length erc-colorize-faces))))) + ((remove-hook 'erc-match-functions 'erc-colorize t)) + localp) + +(defun erc-colorize-color (ring nick) + "Return a face to use for string NICK. +Prefer an existing entry in RING. If there isn't one, pick the first +unused face in `erc-colorize-faces'. Otherwise, pick the least used +face." + (or + (and-let* ((i (catch 'found + (dotimes (i (ring-length ring)) + (when (equal (car (ring-ref ring i)) nick) + (throw 'found i)))))) + (ring-insert ring (ring-remove ring i)) + (cdr (ring-ref ring 0))) + (let ((used (mapcar #'cdr (ring-elements ring)))) + (and-let* ((face (catch 'found + (dolist (face erc-colorize-faces) + (unless (member face used) + (throw 'found face)))))) + (prog1 face + (ring-insert ring (cons nick face))))) + (let ((older (ring-remove ring))) + (ring-insert ring (cons nick (cdr older))) + (cdr older)))) + +(cl-defstruct (erc-colorize ( :include erc-match + (predicate #'erc-colorize-nick) + (handler #'erc-colorize-message)) + (:constructor erc-colorize)) + "An `erc-match' type for the `erc-colorize' module.") + +(defun erc-colorize-message (match) + "Highlight MATCH's full message with a face from `erc-colorize-faces'." + (erc-button-add-face (point-min) (point-max) + (erc-colorize-color erc-colorize-ring + (erc-colorize-nick match)))) + +(provide 'erc-colorize) + +;;; erc-colorize.el ends here +@end lisp + +@noindent +Finally, for an even more thorough example in the form of a package, +check out @uref{https://emacs-erc.gitlab.io/bugs/archive/erc-link.html}, +which demos some good practices for integrating with other modules and +passing data from predicate to handler. + + @node Options @section Options @cindex options diff --git a/doc/misc/modus-themes.org b/doc/misc/modus-themes.org index 6e6cf68c7d2..4f62dec7378 100644 --- a/doc/misc/modus-themes.org +++ b/doc/misc/modus-themes.org @@ -1,12 +1,12 @@ #+title: Modus themes for GNU Emacs -#+author: Protesilaos Stavrou +#+author: Protesilaos #+email: [email protected] #+language: en #+options: ':t toc:nil author:t email:t num:t #+startup: content -#+macro: stable-version 5.2.0 -#+macro: release-date 2025-12-31 -#+macro: development-version 5.3.0-dev +#+macro: stable-version 5.3.0 +#+macro: release-date 2026-06-21 +#+macro: development-version 5.4.0-dev #+macro: file @@texinfo:@file{@@$1@@texinfo:}@@ #+macro: space @@texinfo:@: @@ #+macro: kbd @@texinfo:@kbd{@@$1@@texinfo:}@@ @@ -15,15 +15,15 @@ #+texinfo_dir_title: Modus Themes: (modus-themes) #+texinfo_dir_desc: Elegant, highly legible and customizable themes #+texinfo_header: @set MAINTAINERSITE @uref{https://protesilaos.com,maintainer webpage} -#+texinfo_header: @set MAINTAINER Protesilaos Stavrou +#+texinfo_header: @set MAINTAINER Protesilaos #+texinfo_header: @set MAINTAINEREMAIL @email{[email protected]} #+texinfo_header: @set MAINTAINERCONTACT @uref{mailto:[email protected],contact the maintainer} #+texinfo: @insertcopying -This manual, written by Protesilaos Stavrou, describes the -customization options for the Modus themes, and provides every other -piece of information pertinent to them. +This manual, written by Protesilaos, 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 @@ -45,10 +45,10 @@ Current development target is {{{development-version}}}. #+toc: headlines 8 insert TOC here, with eight headline levels * COPYING -:properties: -:copying: t -:custom_id: h:b14c3fcb-13dd-4144-9d92-2c58b3ed16d3 -:end: +:PROPERTIES: +:COPYING: t +:CUSTOM_ID: h:b14c3fcb-13dd-4144-9d92-2c58b3ed16d3 +:END: Copyright (C) 2020-2026 Free Software Foundation, Inc. @@ -65,43 +65,43 @@ modify this GNU manual.” #+end_quote * Overview -:properties: -:custom_id: h:f0f3dbcb-602d-40cf-b918-8f929c441baf -:end: +:PROPERTIES: +: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 -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 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 eight themes, divided into four 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 + 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. + are variants of the two main themes. They tone down the intensity of + the background and rely on a marginally altered palette for + stylistic harmony. ~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 + 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). + added lines. Instead, they implement colors that are discernible by + users with deueteranopia or deuteranomaly (those colors are mostly + shades of yellow and blue). - Tritanopia themes :: ~modus-operandi-tritanopia~ and its counterpart ~modus-vivendi-tritanopia~ are optimized for users with blue-yellow - color deficiency. The idea is the same as with the deuteranopia + color deficiency. The idea is the same as with the deuteranopia variants: color coding relies only on hues that are accessible to people with tritanopia or tritanomaly, namely, shades of red and cyan. @@ -111,58 +111,54 @@ 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 -usability and stylistic considerations, we will always opt for the +The overarching objective of this project is to consistently offer +accessible color combinations. There shall never be a compromise on +this principle. If there arises an inescapable trade-off between +usability and stylistic considerations, I will always opt for the former. Starting with version 0.12.0 and onwards, the themes are built into GNU Emacs. ** How do the themes look like -:properties: -:custom_id: h:69b92089-069c-4ba1-9d94-cc3415fc4f87 -:end: +:PROPERTIES: +:CUSTOM_ID: h:69b92089-069c-4ba1-9d94-cc3415fc4f87 +:END: #+cindex: Screenshots -Check the web page with [[https://protesilaos.com/emacs/modus-themes-pictures/][the screen shots]]. Note that the themes are +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: -:custom_id: h:2cc37c36-6c1a-48b2-a010-1050b270ee18 -:end: +:PROPERTIES: +:CUSTOM_ID: h:2cc37c36-6c1a-48b2-a010-1050b270ee18 +:END: #+cindex: Changelog -Please refer to the [[https://protesilaos.com/emacs/modus-themes-changelog][web page with the change log]]. It is comprehensive -and covers everything that goes into every tagged release of the themes. +Please refer to the [[https://protesilaos.com/emacs/modus-themes-changelog][web page with the change log]]. It is comprehensive +and covers everything that goes into each tagged release of the themes. * Installation -:properties: -:custom_id: h:1af85373-7f81-4c35-af25-afcef490c111 -:end: +:PROPERTIES: +:CUSTOM_ID: h:1af85373-7f81-4c35-af25-afcef490c111 +:END: The Modus themes are distributed with Emacs starting with version -28.1. On Emacs 27, they can be installed using Emacs' package manager -or manually from their code repository. There also exist packages for -distributions of GNU/Linux. +28.1. They are also available as a standalone package. -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. +Emacs 28 ships with ~modus-themes~ version =1.6.0=. Emacs 29 includes +version =3.0.0=. Emacs 30 provides version =4.4.0=, while Emacs 31 has +version =5.2.0=. ** Install manually from source -:properties: -:custom_id: h:da3414b7-1426-46b8-8e76-47b845b76fd0 -:end: +:PROPERTIES: +:CUSTOM_ID: h:da3414b7-1426-46b8-8e76-47b845b76fd0 +:END: -In the following example, we are assuming that your Emacs files are +In the following example, I am assuming that your Emacs files are stored in {{{file(~/.emacs.d)}}} and that you want to place the Modus -themes in {{{file(~/.emacs.d/modus-themes)}}}. +themes in {{{file(~/.emacs.d/modus-themes)}}}. If you are using Emacs +29, you do not need to do this manually ([[#h:0e667835-ade2-4f8c-8aa4-0983dbbbe45b][Install from source with ~package-vc-install~]]). 1. Get the source and store it in the desired path by running the following in the command line shell: @@ -173,71 +169,48 @@ themes in {{{file(~/.emacs.d/modus-themes)}}}. snippet of Emacs Lisp in your init file (e.g. {{{file(init.el)}}}): #+begin_src emacs-lisp -(add-to-list 'load-path "~/.emacs.d/modus-themes") +(add-to-list 'load-path "~/.emacs.d/modus-themes/") #+end_src The themes are now ready to be used: [[#h:3f3c3728-1b34-437d-9d0c-b110f5b161a9][Enable and load]]. -** Install from the archives -:properties: -:custom_id: h:c4b10085-149f-43e2-bd4d-347f33aee054 -:end: - -The ~modus-themes~ package is available from the GNU ELPA archive, which -is configured by default. - -Prior to querying any package archive, make sure to update the index, -with {{{kbd(M-x package-refresh-contents)}}}. Then all you need to do -is type {{{kbd(M-x package-install)}}} and specify the ~modus-themes~. - -Once installed, the themes are ready to be used: [[#h:3f3c3728-1b34-437d-9d0c-b110f5b161a9][Enable and load]]. - -** Install on GNU/Linux -:properties: -:custom_id: h:da640eb1-95dd-4e86-bb4e-1027b27885f0 -:end: - -The themes are also available from the archives of some distributions of -GNU/Linux. These should correspond to a tagged release rather than -building directly from the latest Git commit. It all depends on the -distro's packaging policies. - -*** Debian 11 Bullseye -:properties: -:custom_id: h:7e570360-9ee6-4bc5-8c04-9dc11418a3e4 -:end: +** Install from source with ~package-vc-install~ +:PROPERTIES: +:CUSTOM_ID: h:0e667835-ade2-4f8c-8aa4-0983dbbbe45b +:END: -The themes are part of Debian 11 Bullseye. Get them with: +Starting with Emacs version 29, you can install the ~modus-themes~ +directly from source with the function ~package-vc-install~: -#+begin_src sh -sudo apt install elpa-modus-themes +#+begin_src emacs-lisp +;; Install from source. Do not do it if the package is already installed. +;; +;; To upgrade packages installed with `package-vc-install', use the +;; commands `package-vc-upgrade' or `package-vc-upgrade-all'. +(unless (package-installed-p 'modus-themes) + (package-vc-install "https://github.com/protesilaos/modus-themes.git")) #+end_src -They are now ready to be used: [[#h:3f3c3728-1b34-437d-9d0c-b110f5b161a9][Enable and load]]. - -NOTE that Debian's package is severely out-of-date as of this writing -2022-07-24 09:57 +0300. - -*** GNU Guix -:properties: -:custom_id: h:a4ca52cd-869f-46a5-9e16-4d9665f5b88e -:end: - -Users of Guix can get the themes with this command: +** Install from GNU ELPA +:PROPERTIES: +:CUSTOM_ID: h:c4b10085-149f-43e2-bd4d-347f33aee054 +:END: -#+begin_src sh -guix package -i emacs-modus-themes -#+end_src +The ~modus-themes~ package is available from the official GNU ELPA +archive. Prior to querying any package archive, make sure to update +the index, with {{{kbd(M-x package-refresh-contents)}}}. Then all you +need to do is type {{{kbd(M-x package-install)}}} and specify the +~modus-themes~ at the prompt. -They are now ready to be used: [[#h:3f3c3728-1b34-437d-9d0c-b110f5b161a9][Enable and load]]. +Once installed, the themes are ready for use: [[#h:3f3c3728-1b34-437d-9d0c-b110f5b161a9][Enable and load]]. ** Dealing with byte compilation errors -:properties: -:custom_id: h:e6268471-e847-4c9d-998f-49a83257b7f1 -:end: +:PROPERTIES: +:CUSTOM_ID: h:e6268471-e847-4c9d-998f-49a83257b7f1 +:END: -From time to time, we receive bug reports pertaining to errors with -byte compilation. These seldom have to do with faulty code in the +From time to time, I receive bug reports pertaining to errors with +byte compilation. These seldom have to do with faulty code in the themes: it might be a shortcoming of {{{file(package.el)}}}, some regression in the current development target of Emacs, a misconfiguration in an otherwise exotic setup, and the like. @@ -251,140 +224,61 @@ The common solution with a stable version of Emacs is to: For those building Emacs directly from source, the solution may involve reverting to an earlier commit in emacs.git. -At any rate, if you encounter such an issue please report it: we will -either fix the bug on our end if it is truly ours, or help forward it to -the relevant upstream maintainer. Whatever you do, please understand -that a build failure does not mean we are necessarily doing something -wrong. +At any rate, if you encounter such an issue please report it: I will +either fix the bug or help forward it to the relevant upstream +maintainer. Whatever you do, please understand that a build failure +does not mean I am necessarily doing something wrong. [[#h:6536c8d5-3f98-43ab-a787-b94120e735e8][Issues you can help with]]. -* Enable and load -:properties: -:custom_id: h:3f3c3728-1b34-437d-9d0c-b110f5b161a9 -:end: -#+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 ([[#h:adb0c49a-f1f9-4690-868b-013a080eed68][Option for disabling other themes while loading Modus]]). - -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 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 there are multiple Modus themes ([[#h:f0f3dbcb-602d-40cf-b918-8f929c441baf][Overview]]). Adapt the -above snippet accordingly. +* Sample configuration +:PROPERTIES: +:CUSTOM_ID: h:e979734c-a9e1-4373-9365-0f2cd36107b8 +:END: +#+cindex: use-package configuration +#+cindex: sample configuration -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 one of the themes: +It is common for Emacs users to rely on ~use-package~ to declare +package configurations ([[#h:b66b128d-54a4-4265-b59f-4d1ea2feb073][The ~require-theme~ for built-in Emacs themes]]): #+begin_src emacs-lisp -(require 'modus-themes) -#+end_src +(use-package modus-themes + :ensure t + :config + ;; Your customizations here. All customizations must be evaluated + ;; BEFORE loading the theme. Reload the theme for new customizations + ;; to take effect. + (setq modus-themes-italic-constructs t + modus-themes-bold-constructs nil) -One can activate a theme with something like the following expression, -replacing ~modus-operandi~ with their preferred Modus theme: + (modus-themes-load-theme 'modus-operandi) -#+begin_src emacs-lisp -(load-theme 'modus-operandi :no-confirm) + (define-key global-map (kbd "<f5>") #'modus-themes-toggle)) #+end_src -Changes to the available customization options must always be evaluated -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 ([[#h:b66b128d-54a4-4265-b59f-4d1ea2feb073][The require-theme for built-in Emacs themes]]): +The same without ~use-package~: #+begin_src emacs-lisp -;;; For the built-in themes which cannot use `require'. -(require-theme 'modus-themes) - -;; Add all your customizations prior to loading the themes. -(setq modus-themes-italic-constructs t - modus-themes-bold-constructs nil) - -;; 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'. - (require 'modus-themes) -;; Add all your customizations prior to loading the themes +;; Your customizations here. All customizations must be evaluated +;; BEFORE loading the theme. Reload the theme for new customizations +;; to take effect. (setq modus-themes-italic-constructs t modus-themes-bold-constructs nil) -;; Load the theme of your choice. -(load-theme 'modus-operandi :no-confirm) +(modus-themes-load-theme 'modus-operandi) (define-key global-map (kbd "<f5>") #'modus-themes-toggle) #+end_src -[[#h:e979734c-a9e1-4373-9365-0f2cd36107b8][Sample configuration with and without use-package]]. - -To disable other themes before loading a Modus theme, use something -like this: - -#+begin_src emacs-lisp -(mapc #'disable-theme custom-enabled-themes) -(load-theme 'modus-operandi :no-confirm) -#+end_src - -#+findex: modus-themes-load-theme -Instead of using the basic ~load-theme~ function, users can rely on -the ~modus-themes-load-theme~. It accepts a single argument, which is -a symbol representing the Modus theme of choice, such as: - -#+begin_src emacs-lisp -(modus-themes-load-theme 'modus-operandi) -#+end_src - -#+vindex: modus-themes-after-load-theme-hook -#+vindex: modus-themes-post-load-hook -The ~modus-themes-load-theme~ takes care to disable other themes, if -the user opts in ([[#h:adb0c49a-f1f9-4690-868b-013a080eed68][Option for disabling other themes while loading Modus]]). -After loading the theme of choice, this function calls the -hook ~modus-themes-after-load-theme-hook~ (alias ~modus-themes-post-load-hook~). -Users can add their own functions to this hook to make further -customizations ([[#h:f4651d55-8c07-46aa-b52b-bed1e53463bb][Advanced customization]]). - -#+findex: modus-themes-toggle -#+findex: modus-themes-select -#+findex: modus-themes-rotate -#+findex: modus-themes-load-random -The commands ~modus-themes-toggle~, ~modus-themes-rotate~, -~modus-themes-load-random~, and ~modus-themes-select~ use -~modus-themes-load-theme~ internally ([[#h:4fbfed66-5a89-447a-a07d-a03f6819c5bd][Option for which themes to toggle]]). -The aforementioned hold true for them as well. - -Convenience commands for loading only dark or light themes are: - -#+findex: modus-themes-select-dark -- ~modus-themes-select-dark~ - -#+findex: modus-themes-select-light -- ~modus-themes-select-light~ - -#+findex: modus-themes-load-random-dark -- ~modus-themes-load-random-dark~ +[[#h:e68560b3-7fb0-42bc-a151-e015948f8a35][Difference between loading and enabling]]. -#+findex: modus-themes-load-random-light -- ~modus-themes-load-random-light~ +Note: make sure not to customize the variable ~custom-theme-load-path~ +or ~custom-theme-directory~ after the themes' package declaration. +That will lead to failures in loading the files. If either or both of +those variables need to be changed, their values should be defined +before the package declaration of the themes. ** The ~require-theme~ for built-in Emacs themes :PROPERTIES: @@ -392,151 +286,141 @@ Convenience commands for loading only dark or light themes are: :END: The version of the Modus themes that is included in Emacs CANNOT use -the standard ~require~. This is because the built-in themes are not -included in the ~load-path~ (not my decision). The ~require-theme~ -function must be used in this case as a replacement. For example: +the standard ~require~ that ~use-package~ calls internally. This is +because the built-in themes are not included in the ~load-path~ (not +my decision). The ~require-theme~ function must be used instead. For +example: #+begin_src emacs-lisp (require-theme 'modus-themes) -;; All customizations here +;; Your customizations here. All customizations must be evaluated +;; BEFORE loading the theme. Reload the theme for new customizations +;; to take effect. (setq modus-themes-bold-constructs t modus-themes-italic-constructs t) -;; Load the theme of choice (built-in themes are always "safe" so they -;; do not need the `no-require' argument of `load-theme'). -(load-theme 'modus-operandi) +(modus-themes-load-theme 'modus-operandi) (define-key global-map (kbd "<f5>") #'modus-themes-toggle) #+end_src -** Sample configuration -:properties: -:custom_id: h:e979734c-a9e1-4373-9365-0f2cd36107b8 -:end: -#+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: +Same principle but with ~use-package~: #+begin_src emacs-lisp -;;; For the built-in themes which cannot use `require'. (use-package emacs :init - (require-theme 'modus-themes) ; `require-theme' is ONLY for the built-in Modus themes + ;; `require-theme' is ONLY for the built-in Modus themes + (require-theme 'modus-themes) :config - ;; Add all your customizations prior to loading the themes + ;; Your customizations here. All customizations must be evaluated + ;; BEFORE loading the theme. Reload the theme for new customizations + ;; to take effect. (setq modus-themes-italic-constructs t modus-themes-bold-constructs nil) - ;; Load the theme of your choice. (modus-themes-load-theme 'modus-operandi) (define-key global-map (kbd "<f5>") #'modus-themes-toggle)) +#+end_src +* Enable and load +:PROPERTIES: +:CUSTOM_ID: h:3f3c3728-1b34-437d-9d0c-b110f5b161a9 +:END: +#+cindex: Essential configuration +#+findex: load-theme +#+findex: modus-themes-load-theme +#+vindex: modus-themes-after-load-theme-hook +#+vindex: modus-themes-post-load-hook +Emacs provides the generic ~load-theme~ function to load the given +theme. Modus themes work with it as expected. Though I also define the +function ~modus-themes-load-theme~ which (i) calls the +~modus-themes-after-load-theme-hook~ (alias ~modus-themes-post-load-hook~) +and (ii) disables all other color themes if the relevant user option +is enabled ([[#h:adb0c49a-f1f9-4690-868b-013a080eed68][Option to disable other color themes when loading a Modus theme]]). -;;; For packaged versions which must use `require'. -(use-package modus-themes - :ensure t - :config - ;; Add all your customizations prior to loading the themes - (setq modus-themes-italic-constructs t - modus-themes-bold-constructs nil) - - ;; Load the theme of your choice. - (modus-themes-load-theme 'modus-operandi) - - (define-key global-map (kbd "<f5>") #'modus-themes-toggle)) -#+end_src - -The same without ~use-package~: +The ~modus-themes-after-load-theme-hook~ is specific to the Modus +themes. As such, users can rely on it to work as expected with the +functions and macros that Modus defines ([[#h:f4651d55-8c07-46aa-b52b-bed1e53463bb][Advanced customization]]). -#+begin_src emacs-lisp -(require 'modus-themes) ; OR for the built-in themes: (require-theme 'modus-themes) +#+findex: modus-themes-toggle +#+findex: modus-themes-select +#+findex: modus-themes-rotate +#+findex: modus-themes-load-random +The commands ~modus-themes-toggle~, ~modus-themes-rotate~, +~modus-themes-load-random~, and ~modus-themes-select~ use +~modus-themes-load-theme~ internally: -;; Add all your customizations prior to loading the themes -(setq modus-themes-italic-constructs t - modus-themes-bold-constructs nil) +- ~modus-themes-toggle~ :: Switches between two predefined Modus + themes ([[#h:4fbfed66-5a89-447a-a07d-a03f6819c5bd][Option for which themes to toggle]]). -;; Load the theme of your choice: -(modus-themes-load-theme 'modus-operandi :no-confirm) +- ~modus-themes-rotate~ :: Cycles through a list of Modus themes in + rotation from left to right ([[#h:a10c0202-3683-4fad-9897-433c25e255f6][Option for which themes to rotate]]). -(define-key global-map (kbd "<f5>") #'modus-themes-toggle) -#+end_src +- ~modus-themes-select~ :: Selects a Modus theme using the minibuffer. + When called with a prefix argument ({{{kbd(C-u)}}} by default), it + first prompts for a light or dark subset and then loads a theme + accordingly. -[[#h:e68560b3-7fb0-42bc-a151-e015948f8a35][Differences between loading and enabling]]. +- ~modus-themes-load-random~ :: Loads a Modus theme at random. When + called with a prefix argument, it prompts for the light or dark + subset to load a theme from. -Note: make sure not to customize the variable ~custom-theme-load-path~ -or ~custom-theme-directory~ after the themes' package declaration. That -will lead to failures in loading the files. If either or both of those -variables need to be changed, their values should be defined before the -package declaration of the themes. - -** Differences between loading and enabling -:properties: -:custom_id: h:e68560b3-7fb0-42bc-a151-e015948f8a35 -:end: -#+cindex: load-theme VS enable-theme +Convenience commands for loading only dark or light themes are: -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 -~enable-theme~ function simply puts an already loaded theme to the top -of the list of enabled items, reusing whatever state was last loaded. +#+findex: modus-themes-select-dark +- ~modus-themes-select-dark~ -As such, ~load-theme~ reads all customizations that may happen during -any given Emacs session: even after the initial setup of a theme. -Examples are calls to ~custom-set-faces~, as well as new values assigned -to the options the Modus themes provide ([[#h:bf1c82f2-46c7-4eb2-ad00-dd11fdd8b53f][Customization Options]]). +#+findex: modus-themes-select-light +- ~modus-themes-select-light~ -Our tests show that ~enable-theme~ does not read such variables anew, so -it might appear to the unsuspecting user that the themes are somehow -broken whenever they try to assign a new value to a customization option -or some face. +#+findex: modus-themes-load-random-dark +- ~modus-themes-load-random-dark~ -This "reset" that ~load-theme~ brings about does, however, come at the -cost of being somewhat slower than ~enable-theme~. Users who have a -stable setup and who seldom update their variables during a given Emacs -session, are better off using something like this: +#+findex: modus-themes-load-random-light +- ~modus-themes-load-random-light~ -#+begin_src emacs-lisp -(require 'modus-themes) +** Difference between loading and enabling +:PROPERTIES: +:CUSTOM_ID: h:e68560b3-7fb0-42bc-a151-e015948f8a35 +:END: +#+cindex: load-theme VS enable-theme -;; Activate your desired themes here -(load-theme 'modus-operandi t t) -(load-theme 'modus-vivendi t t) +#+findex: load-theme +#+findex: enable-theme +#+vindex: custom-enabled-themes +Emacs differentiates between loading, per ~load-theme~, and enabling a +theme per ~enable-theme~. The former refers to the process of loading +and evaluating the theme. While the latter is about moving the given +theme to the front of the ~custom-enabled-themes~, without evaluating +it anew. -;; Enable the preferred one -(enable-theme 'modus-operandi) -#+end_src +Concretely, loading a theme always accounts for changes to user +options and thus updates the relevant styles accordingly +([[#h:bf1c82f2-46c7-4eb2-ad00-dd11fdd8b53f][Customization Options]]). Whereas enabling a theme will not perform any +further computations. [[#h:b40aca50-a3b2-4c43-be58-2c26fcd14237][Toggle themes without reloading them]]. [[#h:e979734c-a9e1-4373-9365-0f2cd36107b8][Sample configuration]]. -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:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Use theme colors in code with modus-themes-with-colors]]. - * Customization options -:properties: -:custom_id: h:bf1c82f2-46c7-4eb2-ad00-dd11fdd8b53f -:end: +: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. 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. +without any tweaks. I provide a variety of user options, making these +perhaps the most customizable themes available. The following code +block provides an overview. + +The Modus themes support palette overrides. Those can be used to make +thoroughgoing changes to the looks of the themes, to the point where a +given theme looks completely different from how I have designed it +([[#h:34c7a691-19bb-4037-8d2f-67a07edab150][Option for palette overrides]]). I 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 @@ -551,26 +435,8 @@ reloaded for changes to take effect. modus-themes-variable-pitch-ui nil modus-themes-disable-other-themes t - ;; Options for `modus-themes-prompts' are either nil (the - ;; default), or a list of properties that may include any of those - ;; symbols: `italic', `WEIGHT' - modus-themes-prompts '(italic bold) - - ;; 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): - ;; - ;; `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} - ;; The `modus-themes-headings' is an alist: read the manual's - ;; node about it or its doc string. Basically, it supports + ;; node about it or its docstring. 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'. @@ -581,332 +447,125 @@ reloaded for changes to take effect. (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. +;; Remember that more (MUCH MORE) can be done with palette overrides, +;; which I document extensively in this manual. #+end_src -** Option for disabling other themes while loading Modus -:properties: -:alt_title: Disable other themes -:description: Determine whether loading a Modus themes disables all others -:custom_id: h:adb0c49a-f1f9-4690-868b-013a080eed68 -:end: -#+vindex: modus-themes-disable-other-themes - -Brief: Disable all other themes when loading a Modus theme. - -Symbol: ~modus-themes-disable-other-themes~ (=boolean= type) - -Possible values: +** Option to disable other color themes when loading a Modus theme +:PROPERTIES: +:ALT_TITLE: Disable other themes +:DESCRIPTION: Determine whether loading a Modus themes disables all others +:CUSTOM_ID: h:adb0c49a-f1f9-4690-868b-013a080eed68 +:END: -1. ~nil~ -2. ~t~ (default) +#+vindex: modus-themes-disable-other-themes +The user option ~modus-themes-disable-other-themes~ makes Modus +commands that load a theme automatically disable all other color +themes ([[#h:3f3c3728-1b34-437d-9d0c-b110f5b161a9][Enable and load]]). This is to ensure that Emacs does not blend +two or more color themes, which it will otherwise do. Blending +different color themes seldom leads to good results. -#+findex: modus-themes-toggle -#+findex: modus-themes-rotate -#+findex: modus-themes-load-random -#+findex: modus-themes-select -#+findex: modus-themes-load-theme -When the value is non-~nil~, the commands ~modus-themes-toggle~, -~modus-themes-rotate~, ~modus-themes-load-random~, and -~modus-themes-select~, as well as the ~modus-themes-load-theme~ -function (and any related convenience wrappers like -~modus-themes-load-random-dark~), will disable all other themes while -loading the specified Modus theme ([[#h:4fbfed66-5a89-447a-a07d-a03f6819c5bd][Option for which themes to toggle]]). -This is done to ensure that Emacs does not blend two or more themes: -such blends lead to awkward results that undermine the work of the -designer. - -When the value is ~nil~, the aforementioned commands and function will -only disable other themes within the Modus collection. - -This option is provided because Emacs themes are not necessarily -limited to colors/faces: they can consist of an arbitrary set of -customizations. Users who use such customization bundles must set -this variable to a ~nil~ value. +This user option is enabled by default. Set it to ~nil~ if you want to +load and subsequently blend color themes. ** Option for more bold constructs -:properties: -:alt_title: Bold constructs -:description: Toggle bold constructs in code -:custom_id: h:b25714f6-0fbe-41f6-89b5-6912d304091e -:end: -#+vindex: modus-themes-bold-constructs - -Brief: Use bold for code syntax highlighting and related. - -Symbol: ~modus-themes-bold-constructs~ (=boolean= type) - -Possible values: - -1. ~nil~ (default) -2. ~t~ - -The default is to use a bold typographic weight only when it is -required. +:PROPERTIES: +:ALT_TITLE: Bold constructs +:DESCRIPTION: Toggle bold constructs in code +:CUSTOM_ID: h:b25714f6-0fbe-41f6-89b5-6912d304091e +:END: -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. +#+vindex: modus-themes-bold-constructs +The user option ~modus-themes-bold-constructs~ controls whether +several elements across different interfaces use a decorative bold +weight. By default, when the value of this user option is set to +~nil~, Modus themes use bold only where necessary. -Advanced users may also want to configure the exact attributes of the -~bold~ face. - -[[#h:2793a224-2109-4f61-a106-721c57c01375][Configure bold and italic faces]]. +Modus is designed to apply the ~bold~ face in such cases. This means +that users can modify that face directly, such as to make its weight +heavier or use a different font family ([[#h:2793a224-2109-4f61-a106-721c57c01375][Configure bold and italic faces]]). +Once that is done, everything that Modus renders in a bold weight will +exhibit those exact styles. ** Option for more italic constructs -:properties: -:alt_title: Italic constructs -:description: Toggle italic font constructs in code -:custom_id: h:977c900d-0d6d-4dbb-82d9-c2aae69543d6 -:end: -#+vindex: modus-themes-italic-constructs - -Brief: Use italics for code syntax highlighting and related. - -Symbol: ~modus-themes-italic-constructs~ (=boolean= type) - -Possible values: - -1. ~nil~ (default) -2. ~t~ - -The default is to not use slanted text forms (italics) unless it is -absolutely necessary. - -With a non-~nil~ value (~t~) choose to render more faces in italics. This -typically affects documentation strings and code comments. - -Advanced users may also want to configure the exact attributes of the -~italic~ face. +:PROPERTIES: +:ALT_TITLE: Italic constructs +:DESCRIPTION: Toggle italic font constructs in code +:CUSTOM_ID: h:977c900d-0d6d-4dbb-82d9-c2aae69543d6 +:END: -[[#h:2793a224-2109-4f61-a106-721c57c01375][Configure bold and italic faces]]. +#+vindex: modus-themes-italic-constructs +The user option ~modus-themes-italic-constructs~ controls whether +several elements across different interfaces use a decorative italic +style, which typically is expressed as slanted text. By default, when +the value of this user option is set to ~nil~, Modus themes use italic +only where necessary. + +Modus is designed to apply the ~italic~ face in such cases. This means +that users can modify that face directly, such as to change its slant, +if that is supported by the underlying font family, or simply a +different font family than the main font ([[#h:2793a224-2109-4f61-a106-721c57c01375][Configure italic and italic faces]]). +Once that is done, everything that Modus renders in italics will +exhibit those exact styles. ** Option for which themes to toggle :PROPERTIES: :CUSTOM_ID: h:4fbfed66-5a89-447a-a07d-a03f6819c5bd :END: -#+findex: modus-themes-toggle -Brief: Specify which two themes to toggle between when using the command -~modus-themes-toggle~. - #+vindex: modus-themes-to-toggle -Symbol: ~modus-themes-to-toggle~ (=list= type) - -Default value: ='(modus-operandi modus-vivendi)= - -Possible values: - -- ~modus-operandi~ -- ~modus-operandi-tinted~ -- ~modus-operandi-deuteranopia~ -- ~modus-operandi-tritanopia~ -- ~modus-vivendi~ -- ~modus-vivendi-tinted~ -- ~modus-vivendi-deuteranopia~ -- ~modus-vivendi-tritanopia~ +#+findex: modus-themes-toggle +#+findex: modus-themes-get-themes +The user option ~modus-themes-to-toggle~ controls which themes will +the command ~modus-themes-toggle~ switch between. Possible values +include all themes returned by the function ~modus-themes-get-themes~ +([[#h:86eb375b-9be4-43ce-879a-0686a524a63b][Build on top of the Modus themes]]). ** Option for which themes to rotate :PROPERTIES: :CUSTOM_ID: h:a10c0202-3683-4fad-9897-433c25e255f6 :END: -#+findex: modus-themes-rotate -Brief: Specify which themes to rotate through when using the command -~modus-themes-rotate~. - #+vindex: modus-themes-to-rotate -Symbol: ~modus-themes-to-rotate~ (=list= type) - -Default value: nil - -Possible values: - -#+vindex: modus-themes-items -- Any of the themes listed in the value of the variable ~modus-themes-items~. -#+findex: modus-themes-get-themes -- Any of the themes returned by the function ~modus-themes-get-themes~ - ([[#h:86eb375b-9be4-43ce-879a-0686a524a63b][Build on top of the Modus themes]]). - -When the value is a list of themes, ~modus-themes-rotate~ will go -through them from left to right. With an optional prefix argument -({{{kbd(C-u)}}} by default), it will move in reverse. If the value is -~nil~, the command will perform the same action for all the themes -returned by the function ~modus-themes-get-themes~. +#+findex: modus-themes-rotate +The user option ~modus-themes-to-rotate~ controls which themes will +the command ~modus-themes-rotate~ cycle between in rotation from left +to right. When ~modus-themes-rotate~ is called with an optional prefix +argument ({{{kbd(C-u)}}} by default), it will move from right to left. +Possible values include all themes returned by the function +~modus-themes-get-themes~ ([[#h:86eb375b-9be4-43ce-879a-0686a524a63b][Build on top of the Modus themes]]). ** Option for font mixing -:properties: -:alt_title: Mixed fonts -:description: Toggle mixing of font families -:custom_id: h:115e6c23-ee35-4a16-8cef-e2fcbb08e28b -:end: -#+vindex: modus-themes-mixed-fonts - -Brief: Toggle the use of monospaced fonts for spacing-sensitive -constructs (affects font families). - -Symbol: ~modus-themes-mixed-fonts~ (=boolean= type) - -Possible values: - -1. ~nil~ (default) -2. ~t~ - -When set to non-~nil~ (~t~), configure some spacing-sensitive faces like Org -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 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]]. - -** Option for command prompt styles -:properties: -:alt_title: Command prompts -:description: Control the style of command 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: - -+ ~italic~ -+ ~italic~ -+ A font weight, which must be supported by the underlying typeface: - - ~thin~ - - ~ultralight~ - - ~extralight~ - - ~light~ - - ~semilight~ - - ~regular~ - - ~medium~ - - ~semibold~ - - ~bold~ - - ~heavy~ - - ~extrabold~ - - ~ultrabold~ - -The default (a ~nil~ value or an empty list) means to only use a subtle -colored foreground color. - -The ~italic~ property adds a slant to the font's forms (italic or -oblique forms, depending on the typeface). - -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 -(bold italic) -(italic semibold) -#+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-prompts '(extrabold italic)) -#+end_src - -[[#h:bd75b43a-0bf1-45e7-b8b4-20944ca8b7f8][Make prompts more or less colorful]]. - -** Option for completion framework aesthetics -:properties: -:alt_title: Completion UIs -:description: Choose among several styles for completion UIs -:custom_id: h:f1c20c02-7b34-4c35-9c65-99170efb2882 -:end: -#+vindex: modus-themes-completions - -Brief: Set the overall style of completion framework interfaces. - -Symbol: ~modus-themes-completions~ (=alist= type properties) - -This affects Company, Corfu, Flx, Icomplete/Fido, Ido, Ivy, Orderless, -Vertico, and the standard =*Completions*= buffer. 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 underline)) - (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, -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: - -- ~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 - 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, -a bold weight, and the base foreground value for the text. The list -of properties it accepts is as follows (order is not significant): - -- ~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 - variable ~modus-themes-weights~. The absence of a weight means - that bold will be used. - -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: +:PROPERTIES: +:ALT_TITLE: Mixed fonts +:DESCRIPTION: Toggle mixing of font families +:CUSTOM_ID: h:115e6c23-ee35-4a16-8cef-e2fcbb08e28b +:END: -#+begin_src emacs-lisp -(setq modus-themes-completions - '((t . (extrabold underline)))) -#+end_src +#+vindex: modus-themes-mixed-fonts +The user option ~modus-themes-mixed-fonts~ sets up Modus to render +spacing-sensitive elements, such as Org tables and code blocks, in a +monospaced font. It does so when it is set to a non-~nil~ value. -Is the same as: +Then, it is possible for users to rely on the built-in {{{kbd(M-x +variable-pitch-mode)}}}. ~variable-pitch-mode~ sets the current buffer +to a proportionately spaced font, but it will not affect the elements +that Modus renders in an explicitly monospaced way. -#+begin_src emacs-lisp -(setq modus-themes-completions - '((matches . (extrabold underline)) - (selection . (extrabold underline)))) -#+end_src +If ~modus-themes-mixed-fonts~ is set to ~nil~ (the default), buffers +that have ~variable-pitch-mode~ enabled may appear broken wherever +spacing-sensitive elements are present. -[[#h:d959f789-0517-4636-8780-18123f936f91][Make completion matches more or less colorful]]. +For a consistent typographic experience, user may need to specify the +font family of the ~default~, ~fixed-pitch~, and ~variable-pitch~ +faces ([[#h:defcf4fc-8fa8-4c29-b12e-7119582cc929][Font configurations for Org and others]]). ** 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: +: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 As part of version =4.4.0=, the ~modus-themes-org-blocks~ is no more. @@ -914,15 +573,15 @@ Users can apply palette overrides to set a style that fits their preference (purple, blue, yellow, green, etc.). It is more flexible and more powerful ([[#h:f44cc6e3-b0f1-4a5e-8a90-9e48fa557b50][DIY Make Org block colors more or less colorful]]) -For the option to change the background of Org source blocks, we +For the option to change the background of Org source blocks, I provide the relevant setup ([[#h:8c842804-43b7-4287-b4e9-8c07d04d1f89][DIY Use colored Org source blocks per language]]). ** 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: +: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 Brief: Heading styles with optional list of values per heading level. @@ -935,7 +594,7 @@ through 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 +title or equivalent, such as the =#+title= construct I find in Org files. Levels 1-8 are regular headings. The =LIST-OF-VALUES= covers symbols that refer to properties, as @@ -1038,11 +697,11 @@ done in older versions of the themes). [[#h:11297984-85ea-4678-abe9-a73aeab4676a][Make headings more or less colorful]]. ** 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: +: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 @@ -1068,14 +727,14 @@ is done by assigning the ~variable-pitch~ face to the relevant items. [[#h:defcf4fc-8fa8-4c29-b12e-7119582cc929][Font configurations for Org and others]]. ** Option for palette overrides -:properties: -:alt_title: Palette overrides -:description: Refashion color values and/or semantic color mappings -:custom_id: h:34c7a691-19bb-4037-8d2f-67a07edab150 -:end: +:PROPERTIES: +:ALT_TITLE: Palette overrides +:DESCRIPTION: Refashion color values and/or semantic color mappings +:CUSTOM_ID: h:34c7a691-19bb-4037-8d2f-67a07edab150 +:END: 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]]). +alternative, use the presets I provide ([[#h:b0bc811c-227e-42ec-bf67-15e1f41eb7bc][Palette override presets]]). Each Modus theme specifies a color palette that declares named color values and semantic color mappings: @@ -1216,7 +875,7 @@ definitions that are shared among the themes or on a per-theme basis. #+vindex: modus-themes-common-palette-user The common values are stored in the user option ~modus-themes-common-palette-user~. -As for per-theme variables, we have the following user options: +As for per-theme variables, I have the following user options: #+vindex: modus-operandi-palette-user - ~modus-operandi-palette-user~ @@ -1284,9 +943,9 @@ Examples demonstrating how to use the aforementioned: #+end_src * Preview theme colors -:properties: -:custom_id: h:f4d4b71b-2ca5-4c3d-b0b4-9bfd7aa7fb4d -:end: +:PROPERTIES: +:CUSTOM_ID: h:f4d4b71b-2ca5-4c3d-b0b4-9bfd7aa7fb4d +:END: #+cindex: Preview named colors or semantic color mappings #+findex: modus-themes-list-colors @@ -1412,7 +1071,7 @@ An example with ~modus-operandi~ to show how this function behaves with/without overrides and when recursive mappings are introduced. #+begin_src emacs-lisp -;; Here we show the recursion of palette mappings. In general, it is +;; Here I show the recursion of palette mappings. In general, it is ;; better for the user to specify named colors to avoid possible ;; confusion with their configuration, though those still work as ;; expected. @@ -1432,13 +1091,13 @@ with/without overrides and when recursive mappings are introduced. #+end_src ** Use theme colors in code with ~modus-themes-with-colors~ -:properties: -:custom_id: h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae -:end: +:PROPERTIES: +:CUSTOM_ID: h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae +:END: #+cindex: Use colors from the palette anywhere [ Note that for common cases the following is not not needed. Just rely on - the comprehensive overrides we provide ([[#h:34c7a691-19bb-4037-8d2f-67a07edab150][Option for palette overrides]]). ] + the comprehensive overrides I provide ([[#h:34c7a691-19bb-4037-8d2f-67a07edab150][Option for palette overrides]]). ] #+findex: modus-themes-with-colors Advanced users may want to apply many colors from the palette of the @@ -1470,16 +1129,16 @@ same with ~modus-vivendi~ as the active theme: 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]]). +I provide commands to inspect those ([[#h:f4d4b71b-2ca5-4c3d-b0b4-9bfd7aa7fb4d][Preview theme colors]]). Others sections in this manual show how to use the aforementioned macro ([[#h:f4651d55-8c07-46aa-b52b-bed1e53463bb][Advanced customization]]). In practice, the use of a hook will also be needed ([[#h:d87673fe-2ce1-4c80-a4b8-be36ca9f2d24][DIY Use a hook at the post-load-theme phase]]). * Advanced customization -:properties: -:custom_id: h:f4651d55-8c07-46aa-b52b-bed1e53463bb -:end: +:PROPERTIES: +:CUSTOM_ID: h:f4651d55-8c07-46aa-b52b-bed1e53463bb +:END: Unlike the predefined customization options which follow a clear pattern of allowing the user to quickly specify their preference, the @@ -1497,7 +1156,7 @@ they are labeled as "do-it-yourself" or "DIY". :END: This section shows how to refashion the themes by opting in to the -stylistic presets we provide. Those presets override the default +stylistic presets I provide. Those presets override the default color mappings to amplify, tone down, or refashion the overall coloration of the themes. @@ -1513,7 +1172,7 @@ 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. -On the opposite end of the stylistic spectrum, we have this +On the opposite end of the stylistic spectrum, I have this #+begin_src emacs-lisp ;; Always remember to reload the theme for changes to take effect! @@ -1538,7 +1197,7 @@ For some stylistic variation try the "cooler" and "warmer" presets: #+end_src 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 +overrides I 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]]). @@ -1559,11 +1218,50 @@ the general idea (extra space for didactic purposes): (underline-paren-match fg-main) ;; And expand the preset here. Note that the ,@ works because - ;; we use the backtick for this list, instead of a straight + ;; I use the backtick for this list, instead of a straight ;; quote. ,@modus-themes-preset-overrides-intense)) #+end_src +** DIY Add support for ~vc-annotate~ +:PROPERTIES: +:CUSTOM_ID: h:4016a69a-d0df-4683-9859-3386d506ad72 +:END: + +The built-in ~vc-annotate~ command relies on a user option to read +color values. Users thus need to write their own configuration like +this ([[#h:d87673fe-2ce1-4c80-a4b8-be36ca9f2d24][DIY Use a hook at the post-load-theme phase]]): + +#+begin_src emacs-lisp +(defun my-modus-vc-annotate (&rest _) + (modus-themes-with-colors + (setq vc-annotate-background-mode nil) + (setq vc-annotate-very-old-color fg-dim) + (setq vc-annotate-color-map + `(( 20. . ,red) + ( 40. . ,red-cooler) + ( 60. . ,red-warmer) + ( 80. . ,yellow-warmer) + (100. . ,yellow) + (120. . ,yellow-cooler) + (140. . ,green-warmer) + (160. . ,green) + (180. . ,green-cooler) + (200. . ,cyan-cooler) + (220. . ,cyan-warmer) + (240. . ,cyan) + (260. . ,blue-warmer) + (280. . ,blue) + (300. . ,blue-cooler) + (320. . ,blue-intense) + (340. . ,magenta-cooler) + (360. . ,fg-dim))))) + +(with-eval-after-load 'vc-annotate + (my-modus-vc-annotate) + (add-hook 'enable-theme-functions #'my-modus-vc-annotate)) +#+end_src + ** DIY Add support for ~engrave-faces~ :PROPERTIES: :CUSTOM_ID: h:6c3f87a8-3573-43de-89e0-53f567c0ede1 @@ -1573,9 +1271,9 @@ The ~engraved-faces~ package is used as part of an Org export process to produce decent colors in the output. Its default style though requires changes to use the colors of the active Modus theme. -In the code below we show how to map everything that ~engrave-faces~ +In the code below I show how to map everything that ~engrave-faces~ defines to the corresponding entry in the palette of the active Modus -theme. We then use a hook to ensure that the value is updated after we +theme. I then use a hook to ensure that the value is updated after I switch to another theme in the collection ([[#h:d87673fe-2ce1-4c80-a4b8-be36ca9f2d24][DIY Use a hook at the post-load-theme phase]]). #+begin_src emacs-lisp @@ -1668,7 +1366,7 @@ 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 +before the call that loads the theme. Remember that I also provide presets that are easier to apply ([[#h:b0bc811c-227e-42ec-bf67-15e1f41eb7bc][Palette override presets]]). *** DIY Make the mode line borderless @@ -1676,9 +1374,9 @@ presets that are easier to apply ([[#h:b0bc811c-227e-42ec-bf67-15e1f41eb7bc][Pal :CUSTOM_ID: h:80ddba52-e188-411f-8cc0-480ebd75befe :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 +hide the border around the active and inactive mode lines, I need to set their color to that of the underlying background. [[#h:e8d781be-eefc-4a81-ac4e-5ed156190df7][Make the active mode line colorful]]. @@ -1707,9 +1405,9 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:e8d781be-eefc-4a81-ac4e-5ed156190df7 :END: -This is one of our practical examples to override the semantic colors +This is one of my 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. +Here I 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~. @@ -1757,9 +1455,9 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:096658d7-a0bd-4a99-b6dc-9b20a20cda37 :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 colors of the built-in ~tab-bar-mode~ +Here I show how to affect the colors of the built-in ~tab-bar-mode~ and ~tab-line-mode~. For consistent theme-wide results, consider changing the mode line, @@ -1802,9 +1500,9 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:c312dcac-36b6-4a1f-b1f5-ab1c9abe27b0 :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 +Here I 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. @@ -1830,9 +1528,9 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:6c1d1dea-5cbf-4d92-b7bb-570a7a23ffe9 :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 +this example, I showcase the special use of the ~unspecified~ symbol that underline mappings can read correctly. #+begin_src emacs-lisp @@ -1858,9 +1556,7 @@ Reload the theme for changes to take effect. 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. - -[[#h:db5a9a7c-2928-4a28-b0f0-6f2b9bd52ba1][Option for command prompt styles]]. +block I show how to add or remove color from prompts. #+begin_src emacs-lisp ;; Keep the background unspecified (like the default), but use a faint @@ -1888,16 +1584,14 @@ Reload the theme for changes to take effect. :END: 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 +the themes ([[#h:34c7a691-19bb-4037-8d2f-67a07edab150][Option for palette overrides]]). Here I demonstrate how +to activate background coloration for completion matches. I show three different degrees of intensity. -[[#h:f1c20c02-7b34-4c35-9c65-99170efb2882][Option for completion framework aesthetics]]. - #+begin_src emacs-lisp ;; Add a nuanced background color to completion matches, while keeping ;; their foreground intact (foregrounds do not need to be specified in -;; this case, but we do it for didactic purposes). +;; this case, but I do it for didactic purposes). (setq modus-themes-common-palette-overrides '((fg-completion-match-0 blue) (fg-completion-match-1 magenta-warmer) @@ -1968,11 +1662,11 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:26f53daa-0065-48dc-88ab-6a718d16cd95 :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 +previous versions of the themes, I 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 +good enough, as the exact values were hardcoded. Here I show how to reproduce the effect, but also how to tweak it to one's liking. [[#h:c8767172-bf11-4c96-81dc-e736c464fc9c][Make code syntax use the old alt-syntax style]]. @@ -2005,12 +1699,12 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:c8767172-bf11-4c96-81dc-e736c464fc9c :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 +this section I 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: +upside of using overrides for this purpose is that I can tweak the +style to my liking, but first let's start with its recreation: #+begin_src emacs-lisp ;; The old "alt-syntax" (before version 4.0.0 of the Modus themes) @@ -2083,7 +1777,7 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:943063da-7b27-4ba4-9afe-f8fe77652fd1 :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 @@ -2167,10 +1861,10 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:259cf8f5-48ec-4b13-8a69-5d6387094468 :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 +this code block I show how to change the background of matching +delimiters when ~show-paren-mode~ is enabled. I also demonstrate how to enable underlines for those highlights. #+begin_src emacs-lisp @@ -2197,7 +1891,7 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:4f6b6ca3-f5bb-4830-8312-baa232305360 :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 @@ -2219,9 +1913,9 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:b57bb50b-a863-4ea8-bb38-6de2275fa868 :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 +Here I show how to affect just the =TODO= and =DONE= keywords that I encounter in Org buffers. The idea is to make those pop out more or to subdue them. @@ -2253,10 +1947,10 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:11297984-85ea-4678-abe9-a73aeab4676a :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 +Here I show how to alter the looks of headings, such as in Org mode. +Using overrides here offers far more flexibility than what I could achieve with previous versions of the themes: the user can mix and match styles at will. @@ -2299,13 +1993,13 @@ match styles at will. Reload the theme for changes to take effect. *** DIY Make Org block colors more or less colorful -:properties: -:custom_id: h:f44cc6e3-b0f1-4a5e-8a90-9e48fa557b50 -:end: +:PROPERTIES: +:CUSTOM_ID: h:f44cc6e3-b0f1-4a5e-8a90-9e48fa557b50 +:END: -This is one of our practical examples to override the semantic colors +This is one of my 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 change the presentation of Org blocks (and other such +I show how to change the presentation of Org blocks (and other such blocks like Markdown fenced code sections, though the exact presentation depends on each major mode). @@ -2351,7 +2045,7 @@ color. #+end_src The previous examples differentiate the delimiter lines from the -block's contents. Though we can mimic the default aesthetic of a +block's contents. Though I can mimic the default aesthetic of a uniform background, while changing the applicable colors. Here are some nice combinations: @@ -2401,13 +2095,13 @@ until version 4.3.0. :CUSTOM_ID: h:a5af0452-a50f-481d-bf60-d8143f98105f :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 +Here I 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 +these styles with what I show in the other chapters with practical stylistic variants. #+begin_src emacs-lisp @@ -2478,11 +2172,11 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:bb5b396f-5532-4d52-ab13-149ca24854f1 :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 +the following code block I show how to affect constructs such as +Org's verbatim, code, and macro entries. I also provide mappings for +tables, property drawers, tags, and code block delimiters, though I do not show every possible permutation. - [[#h:b57bb50b-a863-4ea8-bb38-6de2275fa868][Make TODO and DONE more or less intense]]. @@ -2530,15 +2224,15 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:7da7a4ad-5d3a-4f11-9796-5a1abed0f0c4 :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 +this section I show how to change the coloration of email message +headers and citations. Before I show the code, this is the anatomy of a message: #+begin_example message From: Protesilaos <[email protected]> -To: Modus-Themes Development <~protesilaos/[email protected]> +To: Some Person <[email protected]> Subject: Test subject --- Headers above this line; message and citations below --- This is some sample text @@ -2547,7 +2241,7 @@ This is some sample text > Newer quote #+end_example -We thus have the following: +I thus have the following: #+begin_src emacs-lisp ;; Reduce the intensity of mail citations and headers @@ -2592,9 +2286,9 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:c8605d37-66e1-42aa-986e-d7514c3af6fe :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 +Here I 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. @@ -2625,9 +2319,9 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:b5cab69d-d7cb-451c-8ff9-1f545ceb6caf :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 +the following code block I show how to affect the semantic color mapping that covers mouse hover effects and related highlights: #+begin_src emacs-lisp @@ -2647,9 +2341,9 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:03dbd5af-6bae-475e-85a2-cec189f69598 :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 +Here I show how to affect the color of the underlines that are used by code linters and prose spell checkers. #+begin_src emacs-lisp @@ -2673,9 +2367,9 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:b6466f51-cb58-4007-9ebe-53a27af655c7 :END: -This is one of our practical examples to override the semantic colors +This is one of my 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~. +this section I show how to affect the ~display-line-numbers-mode~. #+begin_src emacs-lisp ;; Make line numbers less intense @@ -2708,13 +2402,13 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:b3761482-bcbf-4990-a41e-4866fb9dad15 :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 diff buffers (e.g. in ~magit~) to -only use color-coded text without any added background. What we +this section I show how to change diff buffers (e.g. in ~magit~) to +only use color-coded text without any added background. What I basically do is to disable the applicable backgrounds and then intensify the foregrounds. Since the deuteranopia-optimized themes do -not use the red-green color coding, we make an extra set of +not use the red-green color coding, I make an extra set of adjustments for them by overriding their palettes directly instead of just using the "common" overrides. @@ -2743,8 +2437,8 @@ just using the "common" overrides. (bg-diff-context unspecified))) ;; Because deuteranopia cannot use the typical red-yellow-green -;; combination, we need to arrange for a yellow-purple-blue sequence. -;; Notice that the above covers the "common" overrides, so we do not +;; combination, I need to arrange for a yellow-purple-blue sequence. +;; Notice that the above covers the "common" overrides, so I do not ;; need to reproduce the whole list of them. (setq modus-operandi-deuteranopia-palette-overrides '((fg-added blue) @@ -2774,9 +2468,9 @@ Reload the theme for changes to take effect. :CUSTOM_ID: h:16389ea1-4cb6-4b18-9409-384324113541 :END: -This is one of our practical examples to override the semantic colors +This is one of my 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 implement a red+blue color coding for +this section I show how to implement a red+blue color coding for diffs in the themes ~modus-operandi-deuteranopia~ and ~modus-vivendi-deuteranopia~. As those themes are optimized for users with red-green color deficiency, they do not use the typical red+green @@ -2879,7 +2573,7 @@ palette such as by adapting these resources ([[#h:f4d4b71b-2ca5-4c3d-b0b4-9bfd7a #+begin_src emacs-lisp ! Theme: modus-operandi ! Description: XTerm port of modus-operandi (Modus themes for GNU Emacs) -! Author: Protesilaos Stavrou, <https://protesilaos.com> +! Author: Protesilaos, <https://protesilaos.com> xterm*background: #ffffff xterm*foreground: #000000 xterm*color0: #000000 @@ -2901,7 +2595,7 @@ xterm*color15: #ffffff ! Theme: modus-vivendi ! Description: XTerm port of modus-vivendi (Modus themes for GNU Emacs) -! Author: Protesilaos Stavrou, <https://protesilaos.com> +! Author: Protesilaos, <https://protesilaos.com> xterm*background: #000000 xterm*foreground: #ffffff xterm*color0: #000000 @@ -2923,9 +2617,9 @@ xterm*color15: #ffffff #+end_src ** DIY Per-theme customization settings -:properties: -:custom_id: h:a897b302-8e10-4a26-beab-3caaee1e1193 -:end: +:PROPERTIES: +:CUSTOM_ID: h:a897b302-8e10-4a26-beab-3caaee1e1193 +:END: If you prefer to maintain different customization options between the two themes, it is best you write your own functions that first set those @@ -2966,7 +2660,7 @@ Reload the theme for changes to take effect. By default, the background of the ~region~ face extends from the end of the line to the edge of the window. To limit it to the end of -the line, we need to override the face's =:extend= attribute. Adding +the line, I need to override the face's =:extend= attribute. Adding this to the Emacs configuration file will suffice: #+begin_src emacs-lisp @@ -2986,7 +2680,7 @@ this to the Emacs configuration file will suffice: Protesilaos) for more than just the mode line. ] 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 +the text and its box boundaries. I 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 @@ -3008,7 +2702,7 @@ mode line. [[#h:d87673fe-2ce1-4c80-a4b8-be36ca9f2d24][Using a hook at the post-load-theme phase]]. 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 +In older versions of the themes, I 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: @@ -3031,7 +2725,7 @@ above: (add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-custom-faces) #+end_src -The reason we no longer provide this option is because it depends on a +The reason I 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 awkward in prose. @@ -3043,21 +2737,21 @@ state of affairs. Reload the theme for changes to take effect. ** DIY Remap face with local value -:properties: -:custom_id: h:7a93cb6f-4eca-4d56-a85c-9dcd813d6b0f -:end: +:PROPERTIES: +:CUSTOM_ID: h:7a93cb6f-4eca-4d56-a85c-9dcd813d6b0f +:END: #+cindex: Remapping faces -There are cases where we need to change the buffer-local attributes of a -face. This might be because we have our own minor mode that reuses a +There are cases where I need to change the buffer-local attributes of a +face. This might be because I have my own minor mode that reuses a face for a particular purpose, such as a line selection tool that -activates ~hl-line-mode~, but we wish to keep it distinct from other +activates ~hl-line-mode~, but I 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][Use theme colors in code with modus-themes-with-colors]]. -In this example we will write a simple interactive function that adjusts +In this example I will write a simple interactive function that adjusts the background color of the ~region~ face. This is the sample code: #+begin_src emacs-lisp @@ -3086,7 +2780,7 @@ When ~my-rainbow-region~ is called interactively, it prompts for a color to use. The list of candidates is drawn from the car of each association in ~my-rainbow-region-colors~ (so "red", "green", etc.). -To extend this principle, we may write wrapper functions that pass a +To extend this principle, I may write wrapper functions that pass a color directly. Those can be useful in tandem with hooks. Consider this example: @@ -3097,19 +2791,19 @@ this example: (add-hook 'diff-mode-hook #'my-rainbow-region-magenta) #+end_src -Whenever we enter a ~diff-mode~ buffer, we now get a magenta-colored +Whenever I enter a ~diff-mode~ buffer, I now get a magenta-colored region. Perhaps you may wish to generalize those findings in to a set of -functions that also accept an arbitrary face. We shall leave the +functions that also accept an arbitrary face. I shall leave the experimentation up to you. Reload the theme for changes to take effect. ** DIY Font configurations for Org and others -:properties: -:custom_id: h:defcf4fc-8fa8-4c29-b12e-7119582cc929 -:end: +:PROPERTIES: +:CUSTOM_ID: h:defcf4fc-8fa8-4c29-b12e-7119582cc929 +:END: #+cindex: Font configurations [ Consider using the ~fontaine~ package from GNU ELPA (by Protesilaos) @@ -3135,7 +2829,7 @@ faces respectively. It may also be convenient to set your main typeface by configuring the ~default~ face the same way. Put something like this in your initialization file (also consider -reading the doc string of ~set-face-attribute~): +reading the docstring of ~set-face-attribute~): #+begin_src emacs-lisp ;; Main typeface @@ -3176,9 +2870,9 @@ absolute height). [[#h:e6c5451f-6763-4be7-8fdb-b4706a422a4c][Note for EWW and Elfeed fonts]]. ** DIY Configure bold and italic faces -:properties: -:custom_id: h:2793a224-2109-4f61-a106-721c57c01375 -:end: +:PROPERTIES: +:CUSTOM_ID: h:2793a224-2109-4f61-a106-721c57c01375 +:END: #+cindex: Bold and italic fonts [ Consider using the ~fontaine~ package from GNU ELPA (by Protesilaos) @@ -3214,7 +2908,7 @@ instructions for all typeface tweaks. [[#h:defcf4fc-8fa8-4c29-b12e-7119582cc929][Font configurations for Org and others]]. -In this example, we set the default font family to Fira Code, while we +In this example, I set the default font family to Fira Code, while I choose to render italics in the Hack typeface (obviously you need to pick fonts that work well together): @@ -3223,7 +2917,7 @@ pick fonts that work well together): (set-face-attribute 'italic nil :family "Hack") #+end_src -And here we play with different weights, using Source Code Pro: +And here I play with different weights, using Source Code Pro: #+begin_src emacs-lisp (set-face-attribute 'default nil :family "Source Code Pro" :height 110 :weight 'light) @@ -3254,7 +2948,7 @@ operations (~custom-set-faces~ follows the format used in the source code of the themes, which can make it easier to redefine faces in bulk). #+begin_src emacs-lisp -;; our generic function +;; my generic function (defun my-modes-themes-bold-italic-faces (&rest _) (set-face-attribute 'default nil :family "Source Code Pro" :height 110) (set-face-attribute 'bold nil :weight 'semibold)) @@ -3278,9 +2972,9 @@ of the themes, which can make it easier to redefine faces in bulk). Reload the theme for changes to take effect. ** DIY Custom Org todo keyword and priority faces -:properties: -:custom_id: h:89f0678d-c5c3-4a57-a526-668b2bb2d7ad -:end: +:PROPERTIES: +:CUSTOM_ID: h:89f0678d-c5c3-4a57-a526-668b2bb2d7ad +:END: #+cindex: Org custom todo faces Users of ~org-mode~ have the option to configure various keywords and @@ -3289,7 +2983,7 @@ priority cookies to better match their workflow. User options are As those are meant to be custom faces, it is futile to have the themes guess what each user wants to use, which keywords to target, and so on. -Instead, we can provide guidelines on how to customize things to one's +Instead, I can provide guidelines on how to customize things to one's liking with the intent of retaining the overall aesthetic of the themes. Please bear in mind that the end result of those is not controlled by @@ -3367,9 +3061,9 @@ it if you plan to control face attributes. [[#h:02e25930-e71a-493d-828a-8907fc80f874][Check color combinations]]. ** DIY Custom Org emphasis faces -:properties: -:custom_id: h:26026302-47f4-4471-9004-9665470e7029 -:end: +:PROPERTIES: +:CUSTOM_ID: h:26026302-47f4-4471-9004-9665470e7029 +:END: #+cindex: Org custom emphasis faces Org provides the user option ~org-emphasis-alist~ which associates a @@ -3438,8 +3132,8 @@ green and yellow hues, respectively: "My underline emphasis for Org.") #+end_src -In the case of a strike-through effect, we have no generic face to -inherit from, so we can write it as follows to also change the +In the case of a strike-through effect, I have no generic face to +inherit from, so I can write it as follows to also change the foreground to a more subtle gray: #+begin_src emacs-lisp @@ -3452,7 +3146,7 @@ foreground to a more subtle gray: "My strike-through emphasis for Org.") #+end_src -Or we can just change the color of the line that strikes through the +Or I can just change the color of the line that strikes through the text to, for example, a shade of red: #+begin_src emacs-lisp @@ -3482,7 +3176,7 @@ entry in the palette. [[#h:f4d4b71b-2ca5-4c3d-b0b4-9bfd7aa7fb4d][Visualize the active Modus theme's palette]]. -Once we have defined the faces we need, we must update the +Once I have defined the faces I need, I must update the ~org-emphasis-alist~. Given that ~org-verbatim~ and ~org-code~ are already styled by the themes, it probably is best not to edit them: @@ -3509,7 +3203,7 @@ invoke {{{kbd(M-x org-mode-restart)}}}. In versions of the Modus themes before =4.4.0= there was an option to change the coloration of Org source blocks so that certain languages would have a distinctly colored background. This was not flexible -enough, because (i) we cannot cover all languages effectively and (ii) +enough, because (i) I cannot cover all languages effectively and (ii) the user had no choice over the =language --> color= mapping. As such, the old user option is no more. Users can use the following @@ -3590,9 +3284,9 @@ idea: #+end_src ** DIY Measure color contrast -:properties: -:custom_id: h:02e25930-e71a-493d-828a-8907fc80f874 -:end: +:PROPERTIES: +:CUSTOM_ID: h:02e25930-e71a-493d-828a-8907fc80f874 +:END: #+findex: modus-themes-contrast #+findex: modus-themes-wcag-formula #+cindex: Color contrast @@ -3663,11 +3357,11 @@ Such knowledge may prove valuable while attempting to customize the theme's color palette. ** DIY Load theme depending on time of day -:properties: -:custom_id: h:1d1ef4b4-8600-4a09-993c-6de3af0ddd26 -:end: +:PROPERTIES: +:CUSTOM_ID: h:1d1ef4b4-8600-4a09-993c-6de3af0ddd26 +:END: -While we do provide ~modus-themes-toggle~ to manually switch between the +While I do provide ~modus-themes-toggle~ to manually switch between the themes, users may also set up their system to perform such a task automatically at sunrise and sunset. @@ -3691,9 +3385,9 @@ the ~circadian~ package: #+end_src ** DIY Backdrop for pdf-tools -:properties: -:custom_id: h:ff69dfe1-29c0-447a-915c-b5ff7c5509cd -:end: +:PROPERTIES: +:CUSTOM_ID: h:ff69dfe1-29c0-447a-915c-b5ff7c5509cd +:END: #+cindex: Remapping pdf-tools backdrop Most PDF files use a white background for their page, making it @@ -3702,13 +3396,13 @@ the Modus Operandi theme. To introduce a distinction between the buffer's backdrop and the PDF page's background, the former must be rendered as some shade of gray. Ideally, ~pdf-tools~ would provide a face that the themes could support directly, though this does not seem to be -the case for the time being. We must thus employ the face remapping +the case for the time being. I must thus employ the face remapping technique that is documented elsewhere in this document to change the buffer-local value of the ~default~ face. [[#h:7a93cb6f-4eca-4d56-a85c-9dcd813d6b0f][Remap face with local value]]. -To remap the buffer's backdrop, we start with a function like this one: +To remap the buffer's backdrop, I start with a function like this one: #+begin_src emacs-lisp (defun my-pdf-tools-backdrop (&rest _) @@ -3728,9 +3422,9 @@ remapping function does not get evaluated anew whenever the theme changes, such as upon invoking {{{kbd(M-x modus-themes-toggle)}}} ([[#h:4fbfed66-5a89-447a-a07d-a03f6819c5bd][Option for which themes to toggle]]). -To have our face remapping adapt gracefully while switching between the -Modus themes, we need to also account for the current theme and control -the activation of ~pdf-view-midnight-minor-mode~. To which end we arrive +To have my face remapping adapt gracefully while switching between the +Modus themes, I need to also account for the current theme and control +the activation of ~pdf-view-midnight-minor-mode~. To which end I arrive at something like the following, which builds on the above example: #+begin_src emacs-lisp @@ -3767,9 +3461,9 @@ mode when ~modus-themes-toggle~ is called. Reload the theme for changes to take effect. ** DIY Toggle themes without reloading them -:properties: -:custom_id: h:b40aca50-a3b2-4c43-be58-2c26fcd14237 -:end: +:PROPERTIES: +:CUSTOM_ID: h:b40aca50-a3b2-4c43-be58-2c26fcd14237 +:END: #+cindex: Switch themes without load-theme Users who have a stable setup and who only ever need to toggle between @@ -3791,7 +3485,7 @@ manual." (_ (error "No Modus theme is loaded; evaluate `modus-themes-load-themes' first")))) #+end_src -[[#h:e68560b3-7fb0-42bc-a151-e015948f8a35][Differences between loading and enabling]]. +[[#h:e68560b3-7fb0-42bc-a151-e015948f8a35][Difference between loading and enabling]]. Recall that ~modus-themes-toggle~ uses ~load-theme~. @@ -3828,7 +3522,7 @@ refers to the first frame that appears on Emacs startup. The that Emacs creates (unless those are explicitly overridden by a bespoke ~make-frame~ call). -In detail, first we use the same values for the two frame alist variables: +In detail, first I use the same values for the two frame alist variables: #+begin_src emacs-lisp ;; This must go in the early-init.el so that it applies to the initial @@ -3839,10 +3533,10 @@ In detail, first we use the same values for the two frame alist variables: #+end_src What the ~dolist~ does is to call ~add-to-list~ for the two variables -we specify there. This economizes on typing. +I specify there. This economizes on typing. -Then we define a function that makes the relevant faces invisible. -The reason we do this with a function is so we can hook it to the +Then I define a function that makes the relevant faces invisible. +The reason I do this with a function is so I can hook it to the "post load" phase of a theme, thus applying the new background value (otherwise you keep the old background, which likely means that the faces will no longer be invisible). @@ -3893,7 +3587,7 @@ defining their own theme-agnostic hook ([[#h:86f6906b-f090-46cc-9816-1fe8aeb3877 The ~hl-todo~ package provides the user option ~hl-todo-keyword-faces~: it specifies a pair of keyword and corresponding color value. The Modus themes configure that option in -the interest of legibility. While this works for our purposes, users +the interest of legibility. While this works for my purposes, users may still prefer to apply their custom values, in which case the following approach is necessary: @@ -3925,7 +3619,7 @@ Or include a ~let~ form, if needed: [[#h:d87673fe-2ce1-4c80-a4b8-be36ca9f2d24][Using a hook at the post-load-theme phase]]. -Normally, we do not touch user options, though this is an exception: +Normally, I do not touch user options, though this is an exception: otherwise the defaults are not always legible. Reload the theme for changes to take effect. @@ -3948,27 +3642,27 @@ However, the assumption that users opt in to this feature does not always hold true. There are cases where it is enabled by defaultsuch as in the popular Doom Emacs configuration. Thus, the unsuspecting user who loads ~modus-operandi~ or ~modus-vivendi~ without the requisite -customizations is getting a sub-par experience; an experience that we +customizations is getting a sub-par experience; an experience that I did not intend and cannot genuinely fix. -Because the Modus themes are meant to work everywhere, we cannot make an -exception for Doom Emacs and/or Solaire users. Furthermore, we shall +Because the Modus themes are meant to work everywhere, I cannot make an +exception for Doom Emacs and/or Solaire users. Furthermore, I shall not introduce hacks, such as by adding a check in all relevant faces to be adjusted based on Solaire or whatever other package. Hacks of this sort are unsustainable and penalize the entire userbase. Besides, the -themes are built into Emacs and we must keep their standard high. +themes are built into Emacs and I must keep their standard high. The fundamental constraint with Solaire is that Emacs does not have a real distinction between "content" and "UI" buffers. For themes to work with Solaire, they need to be designed around that package. Such is an -arrangement that compromises on our accessibility standards and/or -hinders our efforts to provide the best possible experience while using +arrangement that compromises on my accessibility standards and/or +hinders my efforts to provide the best possible experience while using the Modus themes. As such, ~solaire-mode~ is not---and will not be---supported by the Modus themes (or any other of my themes, for that matter). Users who want it must style the faces manually. Below is some sample code, based -on what we cover at length elsewhere in this manual: +on what I cover at length elsewhere in this manual: [[#h:f4651d55-8c07-46aa-b52b-bed1e53463bb][Advanced customization]]. @@ -4081,10 +3775,12 @@ Many of the Do-It-Yourself (DIY) snippets provided herein make use of a hook to apply the desired changes. In most examples, this hook is the ~modus-themes-after-load-theme-hook~ (alias ~modus-themes-post-load-hook~). This hook is provided by the Modus themes and is called at the end of -one the following: +one the following (or their derivatives): - Command ~modus-themes-toggle~ :: [[#h:4fbfed66-5a89-447a-a07d-a03f6819c5bd][Option for which themes to toggle]]. +- Command ~modus-themes-rotate~ :: [[#h:a10c0202-3683-4fad-9897-433c25e255f6][Option for which themes to rotate]]. + - Command ~modus-themes-select~ :: Select a Modus theme using minibuffer completion and then load it. @@ -4115,23 +3811,23 @@ declares it will not use them (in plain terms, the code works with or without ~enable-theme-functions~). *** DIY A theme-agnostic hook for theme loading -:properties: -:custom_id: h:86f6906b-f090-46cc-9816-1fe8aeb38776 -:end: +:PROPERTIES: +:CUSTOM_ID: h:86f6906b-f090-46cc-9816-1fe8aeb38776 +:END: [ NOTE: The following is for versions of Emacs before 29. For Emacs 29 or higher, users can rely on the built-in ~enable-theme-functions~ ([[#h:d87673fe-2ce1-4c80-a4b8-be36ca9f2d24][Using a hook at the post-load-theme phase]]). ] The themes are designed with the intent to be useful to Emacs users of -varying skill levels, from beginners to experts. This means that we try +varying skill levels, from beginners to experts. This means that I 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 ~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 +command ~modus-themes-toggle~). I recommend using that hook for +advanced customizations, because (1) I 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. @@ -4165,7 +3861,7 @@ 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. -In this document, we cover ~modus-themes-after-load-theme-hook~ though +In this document, I 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). @@ -4249,7 +3945,7 @@ passing all the mandatory arguments, but not the optional ones: 'ef-summer-palette-overrides) #+end_src -Here we notice how ~ef-summer~ has ~modus-operandi-palette~ as its +Here I notice how ~ef-summer~ has ~modus-operandi-palette~ as its =CORE-PALETTE=. This means that if the ~ef-summer-palette~ lacks some entry, the theme will still work and it will inherit the style of ~modus-operandi~ for that specific element. @@ -4300,9 +3996,9 @@ corresponds to some named color in the palette of the active theme. [ For more context: [[#h:86eb375b-9be4-43ce-879a-0686a524a63b][Build on top of the Modus themes]]. ] -In this section, we show how to define a new Modus derivative theme. +In this section, I show how to define a new Modus derivative theme. In its simplest form, a theme is a file called =NAME-theme.el= in a -directory that is part of the ~custom-theme-load-path~. We show how to +directory that is part of the ~custom-theme-load-path~. I show how to do this for a package and for a private configuration: - [[#h:f2757848-ea41-4cd7-a04d-7e650555a59b][Complete example of a package that is derived from Modus]] @@ -4331,7 +4027,7 @@ individual theme files. For example, the family of themes that includes =prot-light-theme.el= and =prot-dark-theme.el= has a shared library which is -=prot-themes.el= and therein we find at least the following: +=prot-themes.el= and therein I find at least the following: #+begin_src emacs-lisp ;; Package headers here for prot-themes.el... @@ -4417,8 +4113,8 @@ file: #+end_src The function ~locate-user-emacs-file~ takes care to return a path -relative to where the user's init file is. If, say, we have -=~/.emacs.d/init.el= then we get =~/.emacs.d/my-custom-themes/=. +relative to where the user's init file is. If, say, I have +=~/.emacs.d/init.el= then I get =~/.emacs.d/my-custom-themes/=. Create the directory in that path. Then for each derivative Modus theme, write a new file of the form =NAME-theme.el=. If, for instance, @@ -4456,7 +4152,7 @@ The core and user palettes are among the arguments passed to the ~modus-themes-theme~ functions, as explained elsewhere in this manual ([[#h:86eb375b-9be4-43ce-879a-0686a524a63b][Build on top of the Modus themes]]). -In the following example, we are defining the ~prot-light~ theme in +In the following example, I am defining the ~prot-light~ theme in the =prot-light-theme.el= file. This theme declares itself as belonging to the =prot-themes= family. It is based on the ~modus-operandi-palette~ but then defines its own palette, the @@ -4486,7 +4182,7 @@ There is no limit to how comprehensive the user palette is. Depending on the requirements, this theme can make itself further customizable by the end user via theme-specific palette overrides. In -this case, we have the addition of a user option, which we could call +this case, I have the addition of a user option, which I could call anything though it makes sense to name it consistently like ~prot-light-palette-overrides~. #+begin_src emacs-lisp @@ -4511,7 +4207,7 @@ anything though it makes sense to name it consistently like ~prot-light-palette- 'prot-light-palette-overrides) #+end_src -In the above example, we have our ~prot-light~ theme which is like +In the above example, I have my ~prot-light~ theme which is like ~modus-operandi~ except three colors and which can now be customized further by the user via the ~prot-light-palette-overrides~ ([[#h:34c7a691-19bb-4037-8d2f-67a07edab150][Option for palette overrides]]). @@ -4571,8 +4267,8 @@ palette that can be passed to ~modus-themes-theme~ without necessarily depending on any of the core Modus palettes. I will walk you through the steps of working with something like the following code block. -[ We use color values from Solarized as an example for the rest of - this entry, naming them according to our conventions. ] +[ I use color values from Solarized as an example for the rest of + this entry, naming them according to my conventions. ] #+begin_src emacs-lisp (defvar modus-solarized-dark-palette @@ -4636,7 +4332,7 @@ The =BASE-COLORS= can be as short as follows: The only two mandatory entries in =BASE-COLORS= are =bg-main= and =fg-main= as shown above. In this scenario, the derived palette will get the job done, but will be very close to what Modus defines. The -more we add to the =BASE-COLORS=, the more well defined the character +more I add to the =BASE-COLORS=, the more well defined the character of the new palette will be. For example: #+begin_src emacs-lisp @@ -4654,9 +4350,9 @@ of the new palette will be. For example: This is already going to be a tolerable port of Solarized. If the =BASE-COLORS= provides =bg-main=, =fg-main=, and the six hues of -=red=, =green=, =yellow=, =blue=, =magenta=, =cyan=, we will get a new +=red=, =green=, =yellow=, =blue=, =magenta=, =cyan=, I will get a new palette that has no trace of the color values implemented by core -Modus. Though we can go further and greatly improve the results. +Modus. Though I can go further and greatly improve the results. #+vindex: modus-themes-operandi-palette #+vindex: modus-themes-vivendi-palette @@ -4667,7 +4363,7 @@ then the ~modus-themes-operandi-palette~ is used, otherwise it is ~modus-themes-vivendi-palette~. If all six of the aforementioned hues are present, the ~modus-themes-generate-palette~ will not calculate any more color values. It will use those to derive the relevant -permutations (e.g. blue backgrounds from the =blue= we give it). +permutations (e.g. blue backgrounds from the =blue= I give it). What also plays a role in the interal calculations is whether =bg-main= is a =cool= or =warm= color, meaning whether it is closer to @@ -4701,7 +4397,7 @@ cooler foreground values. Thus: (blue "#268BD2") (magenta "#D33682") (cyan "#2AA198")) - 'warm) ; but we want to use it with `warm' foregrounds + 'warm) ; but I want to use it with `warm' foregrounds ;; And here is the inverse of the above, now with the light version of ;; Solarized. @@ -4714,10 +4410,10 @@ cooler foreground values. Thus: (blue "#268BD2") (magenta "#D33682") (cyan "#2AA198")) - 'cool) ; but we want to use it with `cool' foregrounds + 'cool) ; but I want to use it with `cool' foregrounds #+end_src -This is now getting better, but we can go further. At this point users +This is now getting better, but I can go further. At this point users should be able to do the common work of taking a color scheme that was originally designed for terminal emulators and quickly turning it into a fully fledged Modus palette. All they need is to follow the naming @@ -4725,7 +4421,7 @@ convention for =bg-main=, =fg-main=, and then ={red,green,yellow,blue,magenta,cyan}{,-warmer,-cooler}=. Preview a palette to get the complete list ([[#h:f4d4b71b-2ca5-4c3d-b0b4-9bfd7aa7fb4d][Preview theme colors]]). And, again, remember that not all colors need to be defined in =BASE-COLORS= (e.g. -we could leave out ~magenta-cooler~ if we do not care about it). +I could leave out ~magenta-cooler~ if I do not care about it). The next optional parameter of ~modus-themes-generate-palette~ is the =CORE-PALETTE= it should use. This is to make explicit the decision @@ -4759,7 +4455,7 @@ but, again, users probably should leave this to ~nil~: (magenta "#D33682") (cyan "#2AA198")) nil ; COOL-OR-WARM-PREFERENCE is derived internally based on `bg-main' - 'modus-themes-vivendi-tritanopia-palette) ; we specifically want this as our CORE-PALETTE + 'modus-themes-vivendi-tritanopia-palette) ; I specifically want this as my CORE-PALETTE #+end_src With core Modus palettes, the =CORE-PALETTE= should not make much of a @@ -4771,11 +4467,11 @@ different semantic mappings. Finally, ~modus-themes-generate-palette~ has an optional =MAPPINGS= parameter. This is a list of semantic mappings where each entry is of the form =(NAME OTHER-NAME)= ([[#h:34c7a691-19bb-4037-8d2f-67a07edab150][Option for palette overrides]]). The -=NAME= has the same meaning as for the =BASE-COLORS= we have been +=NAME= has the same meaning as for the =BASE-COLORS= I have been examining all along, while =OTHER-NAME= is the symbol of another =NAME= that exists in the palette, hence the mapping. This manual contains lots of examples along those lines ([[#h:df1199d8-eaba-47db-805d-6b568a577bf3][DIY Stylistic variants using palette overrides]]). -For our purposes, we will modify some of the obvious elements of the +For my purposes, I will modify some of the obvious elements of the theme, namely, the cursor, mode lines, current line highlight, matching parentheses, and active region. @@ -4791,13 +4487,13 @@ matching parentheses, and active region. (cyan "#2AA198")) nil nil - ;; And here are our MAPPINGS where we can specify what values apply + ;; And here are my MAPPINGS where I can specify what values apply ;; to which semantic color. The `modus-themes-list-colors' shows ;; them all. ;; - ;; Note that in our BASE-COLORS above we never wrote what, say, + ;; Note that in my BASE-COLORS above I never wrote what, say, ;; `magenta-warmer' is: it is derived programmatically from the - ;; `magenta' we have there. Absent that, it would be taken from + ;; `magenta' I have there. Absent that, it would be taken from ;; the CORE-PALETTE. '((cursor magenta-warmer) (bg-hl-line bg-blue-nuanced) @@ -4818,8 +4514,8 @@ you already knew how to do this, ~modus-themes-generate-palette~ would not be of real value). The point is to start with something that works and then refine it one small step at a time. -We are now ready to try our Solarized themes, using the example of -doing this in our private configuration ([[#h:f2757848-ea41-4cd7-a04d-7e650555a59b][Complete example of a package that is derived from Modus]]). +I am now ready to try my Solarized themes, using the example of +doing this in my private configuration ([[#h:f2757848-ea41-4cd7-a04d-7e650555a59b][Complete example of a package that is derived from Modus]]). - Create two files, one is called =modus-solarized-dark-theme.el= (or however you want to identify it, but always keep =-theme.el= at the @@ -4842,8 +4538,8 @@ doing this in our private configuration ([[#h:f2757848-ea41-4cd7-a04d-7e650555a5 ;; Modus+Solarized dark (defvar modus-solarized-dark-palette (modus-themes-generate-palette - ;; We provide the two base colors of Solarized, plus most of its - ;; accents. These form the BASE-COLORS we pass as an argument. + ;; I provide the two base colors of Solarized, plus most of its + ;; accents. These form the BASE-COLORS I pass as an argument. ;; All other color values come from those. The BASE-COLORS here ;; are enough to generate a new palatte that has no traces of, say, ;; the `modus-vivendi' color values. @@ -4856,20 +4552,20 @@ doing this in our private configuration ([[#h:f2757848-ea41-4cd7-a04d-7e650555a5 (magenta "#D33682") (cyan "#2AA198")) ;; The COOL-OR-WARM-PREFERENCE is derived internally based on - ;; `bg-main'. We can pass it here if we feel strongly about it. + ;; `bg-main'. I can pass it here if I feel strongly about it. nil - ;; If we need to specify the CORE-PALETTE from where to inherit any - ;; missing colors and/or semantic mappings, we can give it here. + ;; If I need to specify the CORE-PALETTE from where to inherit any + ;; missing colors and/or semantic mappings, I can give it here. ;; Though nil is the appropriate starting point, as the code will ;; handle things internally. nil - ;; And here are our MAPPINGS where we can specify what values apply + ;; And here are my MAPPINGS where I can specify what values apply ;; to which semantic color. The `modus-themes-list-colors' shows ;; them all. ;; - ;; Note that in our BASE-COLORS above we never wrote what, say, + ;; Note that in my BASE-COLORS above I never wrote what, say, ;; `magenta-warmer' is: it is derived programmatically from the - ;; `magenta' we have there. Absent that, it would be taken from + ;; `magenta' I have there. Absent that, it would be taken from ;; the CORE-PALETTE. '((cursor magenta-warmer) (bg-hl-line bg-blue-nuanced) @@ -4896,8 +4592,8 @@ And the light variant: ;; Modus+Solarized light (defvar modus-solarized-light-palette (modus-themes-generate-palette - ;; We provide the two base colors of Solarized, plus most of its - ;; accents. These form the BASE-COLORS we pass as an argument. + ;; I provide the two base colors of Solarized, plus most of its + ;; accents. These form the BASE-COLORS I pass as an argument. ;; All other color values come from those. The BASE-COLORS here ;; are enough to generate a new palatte that has no traces of, say, ;; the `modus-operandi' color values. @@ -4910,20 +4606,20 @@ And the light variant: (magenta "#D33682") (cyan "#2AA198")) ;; The COOL-OR-WARM-PREFERENCE is derived internally based on - ;; `bg-main'. We can pass it here if we feel strongly about it. + ;; `bg-main'. I can pass it here if I feel strongly about it. nil - ;; If we need to specify the CORE-PALETTE from where to inherit any - ;; missing colors and/or semantic mappings, we can give it here. + ;; If I need to specify the CORE-PALETTE from where to inherit any + ;; missing colors and/or semantic mappings, I can give it here. ;; Though nil is the appropriate starting point, as the code will ;; handle things internally. nil - ;; And here are our MAPPINGS where we can specify what values apply + ;; And here are my MAPPINGS where I can specify what values apply ;; to which semantic color. The `modus-themes-list-colors' shows ;; them all. ;; - ;; Note that in our BASE-COLORS above we never wrote what, say, + ;; Note that in my BASE-COLORS above I never wrote what, say, ;; `magenta-warmer' is: it is derived programmatically from the - ;; `magenta' we have there. Absent that, it would be taken from + ;; `magenta' I have there. Absent that, it would be taken from ;; the CORE-PALETTE. '((cursor yellow-warmer) (bg-hl-line bg-red-nuanced) @@ -4997,7 +4693,7 @@ is =ef-themes=. All the Modus commands that switch between themes will thus only work with those Ef themes. #+findex: modus-themes-include-derivatives-mode -For our part, we define the ~modus-themes-include-derivatives-mode~. +For my part, I define the ~modus-themes-include-derivatives-mode~. It is how users can opt in to the all-inclusive conception of "Modus". In this scenario, every theme that is declared with the aforementioned ~modus-themes-theme~ will count as "Modus" and be available to all the @@ -5031,7 +4727,7 @@ accordingly." what is described herein. Just enable the ~modus-themes-include-derivatives-mode~. ] #+findex: modus-themes-define-derivative-command -In the previous section, we explored the mechanics of the +In the previous section, I explored the mechanics of the ~modus-themes-get-themes~ ([[#h:412e3017-81fe-4a95-97a6-225de1867757][Determine what counts as a Modus theme]]). Independent of that method, developers can use the macro ~modus-themes-define-derivative-command~ to define small wrappers for @@ -5083,7 +4779,7 @@ The ~modus-themes-theme~ function is responsible for instantiating a theme and registering it for use by the various Modus commands that act on a theme ([[#h:86eb375b-9be4-43ce-879a-0686a524a63b][Build on top of the Modus themes]]). Due to how Emacs themes are designed to be bound to files, ~modus-themes-theme~ can -only work if the given theme file is already loaded. Otherwise our +only work if the given theme file is already loaded. Otherwise my function is never called and the theme is never created. To this end, users need to call the function ~modus-themes-activate~ @@ -5097,7 +4793,7 @@ form, the activation looks as follows, assuming the theme's file (modus-themes-activate 'modus-solarized-dark) #+end_src -To load multiple themes at once we can define a function like the +To load multiple themes at once I can define a function like the following: #+begin_src emacs-lisp @@ -5127,20 +4823,20 @@ Again, remember that the directory is in the ~custom-theme-load-path~: #+end_src * Face coverage -:properties: -:custom_id: h:a9c8f29d-7f72-4b54-b74b-ddefe15d6a19 -:end: +:PROPERTIES: +:CUSTOM_ID: h:a9c8f29d-7f72-4b54-b74b-ddefe15d6a19 +:END: The Modus themes try to provide as close to full face coverage as possible. This is necessary to ensure a consistently accessible reading experience across all available interfaces. ** Full support for packages or face groups -:properties: -:alt_title: Supported packages -:description: Full list of covered face groups -:custom_id: h:60ed4275-60d6-49f8-9287-9a64e54bea0e -:end: +:PROPERTIES: +:ALT_TITLE: Supported packages +:DESCRIPTION: Full list of covered face groups +:CUSTOM_ID: h:60ed4275-60d6-49f8-9287-9a64e54bea0e +:END: #+cindex: Explicitly supported packages This list will always be updated to reflect the current state of the @@ -5269,6 +4965,7 @@ have lots of extensions, so the "full support" may not be 100% true… + info + info+ (info-plus) + info-colors ++ institution-calendar + ioccur + isearch, occur, etc. + ivy* @@ -5286,12 +4983,14 @@ have lots of extensions, so the "full support" may not be 100% true… + kmacro-menu + ledger-mode + leerzeichen ++ lin + line numbers (~display-line-numbers-mode~ and global variant) + magit + make-mode + man + marginalia + markdown-mode ++ markdown-ts-mode + markup-faces (~adoc-mode~) + mb-depth + mct @@ -5338,6 +5037,7 @@ have lots of extensions, so the "full support" may not be 100% true… + prescient + proced + prodigy ++ pulsar + pulse + pyim + quick-peek @@ -5385,9 +5085,11 @@ have lots of extensions, so the "full support" may not be 100% true… + trashed + treemacs + tree-sitter ++ trust-manager + tty-menu + tuareg + typescript ++ typst + undo-tree + vc ({{{file(vc-dir.el)}}}, {{{file(vc-hooks.el)}}}) + vertico @@ -5418,9 +5120,9 @@ have lots of extensions, so the "full support" may not be 100% true… Plus many other miscellaneous faces that are provided by Emacs. ** Indirectly covered packages -:properties: -:custom_id: h:2cb359c7-3a84-4262-bab3-dcdc1d0034d7 -:end: +:PROPERTIES: +:CUSTOM_ID: h:2cb359c7-3a84-4262-bab3-dcdc1d0034d7 +:END: #+cindex: Implicitly supported packages These do not require any extra styles because they are configured to @@ -5480,17 +5182,17 @@ supported by the themes. + xref * Notes on individual packages -:properties: -:custom_id: h:4c4d901a-84d7-4f20-bd99-0808c2b06eba -:end: +:PROPERTIES: +:CUSTOM_ID: h:4c4d901a-84d7-4f20-bd99-0808c2b06eba +:END: This section covers information that may be of interest to users of individual packages. ** Note on calendar.el weekday and weekend colors -:properties: -:custom_id: h:b2db46fb-32f4-44fd-8e11-d2b261cf51ae -:end: +:PROPERTIES: +:CUSTOM_ID: h:b2db46fb-32f4-44fd-8e11-d2b261cf51ae +:END: By default, the {{{kbd(M-x calendar)}}} interface differentiates weekdays from weekends by applying a gray color to the former and a faint red to the @@ -5528,8 +5230,8 @@ contiguous lines which may look nicer, but require a change to the foreground of the relevant faces to yield the desired color combinations. -Since this is Doom-specific, we urge users to apply changes in their -local setup. Below is some sample code, based on what we cover at +Since this is Doom-specific, I urge users to apply changes in their +local setup. Below is some sample code, based on what I cover at length elsewhere in this manual: [[#h:f4651d55-8c07-46aa-b52b-bed1e53463bb][Advanced customization]]. @@ -5595,9 +5297,9 @@ This seems to make all comments use the appropriate face: As always, re-load the theme for changes to take effect. ** Note on underlines in compilation buffers -:properties: -:custom_id: h:420f5a33-c7a9-4112-9b04-eaf2cbad96bd -:end: +:PROPERTIES: +:CUSTOM_ID: h:420f5a33-c7a9-4112-9b04-eaf2cbad96bd +:END: Various buffers that produce compilation results or run tests on code apply an underline to the file names they reference or to relevant @@ -5620,13 +5322,13 @@ render the affected text with the ~italic~ face: [[#h:2793a224-2109-4f61-a106-721c57c01375][Configure bold and italic faces]]. ** Note on inline Latex in Org buffers -:properties: -:custom_id: h:dd8478da-f56a-45cd-b199-b836c85c3c5a -:end: +:PROPERTIES: +:CUSTOM_ID: h:dd8478da-f56a-45cd-b199-b836c85c3c5a +:END: Org can work with inline latex and related syntax. To actually fontify those constructs, set the variable ~org-highlight-latex-and-related~ to -the desired list of values (per its doc string). For example: +the desired list of values (per its docstring). For example: #+begin_src emacs-lisp (setq org-highlight-latex-and-related '(latex script)) @@ -5635,13 +5337,13 @@ the desired list of values (per its doc string). For example: Remember to use {{{kbd(M-x org-mode-restart)}}} for changes to take effect. ** Note on dimmer.el -:properties: -:custom_id: h:8eb4b758-d318-4480-9ead-357a571beb93 -:end: +:PROPERTIES: +:CUSTOM_ID: h:8eb4b758-d318-4480-9ead-357a571beb93 +:END: The {{{file(dimmer.el)}}} library by Neil Okamoto can be configured to automatically dim the colors of inactive Emacs windows. To guarantee -consistent results with the Modus themes, we suggest some tweaks to the +consistent results with the Modus themes, I suggest some tweaks to the default styles, such as in this minimal setup: #+begin_src emacs-lisp @@ -5654,7 +5356,7 @@ default styles, such as in this minimal setup: (dimmer-mode 1)) #+end_src -Of the above, we strongly recommend the RGB color space because it is +Of the above, I strongly recommend the RGB color space because it is the one that remains faithful to the hueness of the colors used by the themes. Whereas the default CIELAB space has a tendency to distort colors in addition to applying the dim effect, which can be somewhat @@ -5671,16 +5373,16 @@ inadvertently leads to the opposite of the intended utility of this package: it draws too much attention to unfocused windows. ** Note on display-fill-column-indicator-mode -:properties: -:custom_id: h:2a602816-bc1b-45bf-9675-4cbbd7bf6cab -:end: +:PROPERTIES: +:CUSTOM_ID: h:2a602816-bc1b-45bf-9675-4cbbd7bf6cab +:END: The ~display-fill-column-indicator-mode~ uses a typographic character to draw its line. This has the downside of creating a dashed line. The dashes are further apart depending on how tall the font's glyph height is and what integer the ~line-spacing~ is set to. -At the theme level we eliminate this effect by making the character one +At the theme level I eliminate this effect by making the character one pixel tall: the line is contiguous. Users who prefer the dashed line are advised to change the ~fill-column-indicator~ face, as explained elsewhere in this document. For example: @@ -5694,7 +5396,7 @@ elsewhere in this document. For example: [[#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 +size instead of the one pixel I use. This is done by specifying a rate instead of an absolute number, as in =:height 1.0= versus =:height 1=. For example: @@ -5714,20 +5416,20 @@ surrounding parentheses, highlighting only those which are around the point. The package expects users to customize the applicable colors on their own by configuring certain variables. -To make the Modus themes work as expected with this, we need to use some +To make the Modus themes work as expected with this, I need to use some of the techniques that are discussed at length in the various "Do-It-Yourself" (DIY) sections, which provide insight into the more advanced customization options of the themes. [[#h:f4651d55-8c07-46aa-b52b-bed1e53463bb][Advanced customization]]. -In the following example, we are assuming that the user wants to (i) +In the following example, I am assuming that the user wants to (i) reuse color variables provided by the themes, (ii) be able to retain their tweaks while switching between ~modus-operandi~ and ~modus-vivendi~, and (iii) have the option to highlight either the foreground of the parentheses or the background as well. -We start by defining our own variable, which will serve as a toggle +I start by defining my own variable, which will serve as a toggle between foreground and background coloration styles: #+begin_src emacs-lisp @@ -5735,29 +5437,29 @@ between foreground and background coloration styles: "Prefer `highlight-parentheses-background-colors'.") #+end_src -Then we can update our preference with this: +Then I can update my preference with this: #+begin_src emacs-lisp ;; Set to nil to disable backgrounds. (setq my-highlight-parentheses-use-background nil) #+end_src -To reuse colors from the themes, we must wrap our code in the -~modus-themes-with-colors~ macro. Our implementation must interface with +To reuse colors from the themes, I must wrap my code in the +~modus-themes-with-colors~ macro. My implementation must interface with the variables ~highlight-parentheses-background-colors~ and/or ~highlight-parentheses-colors~. -So we can have something like this (the doc string of +So I can have something like this (the docstring of ~modus-themes-with-colors~ explains where the names of the colors can be found): #+begin_src emacs-lisp (modus-themes-with-colors - ;; Our preference for setting either background or foreground + ;; My preference for setting either background or foreground ;; styles, depending on `my-highlight-parentheses-use-background'. (if my-highlight-parentheses-use-background - ;; Here we set color combinations that involve both a background + ;; Here I set color combinations that involve both a background ;; and a foreground value. (setq highlight-parentheses-background-colors (list bg-cyan-intense bg-magenta-intense @@ -5768,7 +5470,7 @@ found): green yellow)) - ;; And here we pass only foreground colors while disabling any + ;; And here I pass only foreground colors while disabling any ;; backgrounds. (setq highlight-parentheses-colors (list green-intense magenta-intense @@ -5779,12 +5481,12 @@ found): ;; Include this if you also want to make the parentheses bold: (set-face-attribute 'highlight-parentheses-highlight nil :inherit 'bold) -;; Our changes must be evaluated before enabling the relevant mode, so +;; My changes must be evaluated before enabling the relevant mode, so ;; this comes last. (global-highlight-parentheses-mode 1) #+end_src -For our changes to persist while switching between the Modus themes, we +For my changes to persist while switching between the Modus themes, I need to include them in a function which can then get passed to ~modus-themes-after-load-theme-hook~. This is the complete implementation: @@ -5800,11 +5502,11 @@ implementation: (defun my-modus-themes-highlight-parentheses (&rest _) (modus-themes-with-colors - ;; Our preference for setting either background or foreground + ;; My preference for setting either background or foreground ;; styles, depending on `my-highlight-parentheses-use-background'. (if my-highlight-parentheses-use-background - ;; Here we set color combinations that involve both a background + ;; Here I set color combinations that involve both a background ;; and a foreground value. (setq highlight-parentheses-background-colors (list bg-cyan-intense bg-magenta-intense @@ -5815,7 +5517,7 @@ implementation: green yellow)) - ;; And here we pass only foreground colors while disabling any + ;; And here I pass only foreground colors while disabling any ;; backgrounds. (setq highlight-parentheses-colors (list green-intense magenta-intense @@ -5826,7 +5528,7 @@ implementation: ;; Include this if you also want to make the parentheses bold: (set-face-attribute 'highlight-parentheses-highlight nil :inherit 'bold) - ;; Our changes must be evaluated before enabling the relevant mode, so + ;; My changes must be evaluated before enabling the relevant mode, so ;; this comes last. (global-highlight-parentheses-mode 1)) @@ -5838,9 +5540,9 @@ implementation: As always, re-load the theme for changes to take effect. ** Note on mmm-mode.el background colors -:properties: -:custom_id: h:99cf0d6c-e478-4e26-9932-3bf3427d13f6 -:end: +:PROPERTIES: +:CUSTOM_ID: h:99cf0d6c-e478-4e26-9932-3bf3427d13f6 +:END: The faces used by {{{file(mmm-mode.el)}}} are expected to have a colorful background, while they should not touch any foreground value. The idea @@ -5860,13 +5562,13 @@ There are two competing goals at play: color-coding of the underlying background. As the Modus themes are designed with the express purpose of conforming -with the first point, we have to forgo the apparent color-coding of the -background elements. Instead we use subtle colors that do not undermine +with the first point, I have to forgo the apparent color-coding of the +background elements. Instead I use subtle colors that do not undermine the legibility of the affected text while they still offer a sense of added context. Users who might prefer to fall below the minimum 7:1 contrast ratio in -relative luminance (the accessibility target we conform with), can opt +relative luminance (the accessibility target I conform with), can opt to configure the relevant faces on their own. [[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Use theme colors in code with modus-themes-with-colors]]. @@ -5888,23 +5590,23 @@ very high cost of degraded legibility. #+end_src ** Note on prism.el -:properties: -:alt_title: Note for prism -:custom_id: h:a94272e0-99da-4149-9e80-11a7e67a2cf2 -:end: +:PROPERTIES: +:ALT_TITLE: Note for prism +:CUSTOM_ID: h:a94272e0-99da-4149-9e80-11a7e67a2cf2 +:END: This package by Adam Porter, aka "alphapapa" or "github-alphapapa", 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 +As {{{file(prism.el)}}} offers a broad range of customizations, I cannot style it directly at the theme level: that would run contrary -to the spirit of the package. Instead, we may offer preset color +to the spirit of the package. Instead, I 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~ +In the following code snippets, I employ the ~modus-themes-with-colors~ 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: @@ -5985,9 +5687,9 @@ examples with the 4, 8, 16 colors): #+end_src ** Note on company-mode overlay pop-up -:properties: -:custom_id: h:20cef8c4-d11f-4053-8b2c-2872925780b1 -:end: +:PROPERTIES: +:CUSTOM_ID: h:20cef8c4-d11f-4053-8b2c-2872925780b1 +:END: By default, the ~company-mode~ pop-up that lists completion candidates is drawn using an overlay. This creates alignment issues every time it is @@ -6003,9 +5705,9 @@ 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 -:end: +:PROPERTIES: +:CUSTOM_ID: h:98bdf319-1e32-4469-8a01-771200fba65c +:END: The built-in IRC client ~erc~ has the ability to colorize any text using escape sequences that start with =^C= (inserted with {{{kbd(C-q C-c)}}}) and are @@ -6022,8 +5724,8 @@ separated by a comma. Like this =^C1,6=. The minimum setup is this: #+end_src As this allows users the chance to make arbitrary combinations, it is -impossible to guarantee a consistently high contrast ratio. All we can -we do is provide guidance on the combinations that satisfy the +impossible to guarantee a consistently high contrast ratio. All I can +I do is provide guidance on the combinations that satisfy the accessibility standard of the themes: + Modus Operandi :: Use foreground color 1 for all backgrounds from @@ -6036,29 +5738,29 @@ Colors 0 and 1 are white and black respectively. So combine them together, if you must. ** Note on powerline or spaceline -:properties: -:custom_id: h:9130a8ba-d8e3-41be-a58b-3cb1eb7b6d17 -:end: +:PROPERTIES: +:CUSTOM_ID: h:9130a8ba-d8e3-41be-a58b-3cb1eb7b6d17 +:END: Both Powerline and Spaceline package users will likely need to use the command ~powerline-reset~ whenever they make changes to their themes and/or mode line setup. ** Note on SHR colors -:properties: -:custom_id: h:4cc767dc-ffef-4c5c-9f10-82eb7b8921bf -:end: +:PROPERTIES: +:CUSTOM_ID: h:4cc767dc-ffef-4c5c-9f10-82eb7b8921bf +:END: Emacs' HTML rendering library ({{{file(shr.el)}}}) may need explicit configuration to respect the theme's colors instead of whatever specifications the webpage provides. -Consult the doc string of ~shr-use-colors~. +Consult the docstring of ~shr-use-colors~. ** Note on SHR fonts -:properties: -:custom_id: h:e6c5451f-6763-4be7-8fdb-b4706a422a4c -:end: +:PROPERTIES: +:CUSTOM_ID: h:e6c5451f-6763-4be7-8fdb-b4706a422a4c +:END: #+cindex: Fonts in EWW, Elfeed, Ement, and SHR By default, packages that build on top of the Simple HTML Renderer @@ -6077,9 +5779,9 @@ Packages affected by this are: This is a non-exhaustive list. ** Note on Ement colors and fonts -:properties: -:custom_id: h:8e636056-356c-4ca7-bc78-ebe61031f585 -:end: +:PROPERTIES: +:CUSTOM_ID: h:8e636056-356c-4ca7-bc78-ebe61031f585 +:END: The {{{file(ement.el)}}} library by Adam Porter (also known as "alphapapa") defaults to a method of colorizing usernames in a rainbow @@ -6092,7 +5794,7 @@ can be disabled with: The contrast ratio of these colors is governed by another user option: ~ement-room-prism-minimum-contrast~. By default, it is set to 6 which is -slightly below our nominal target. Try this instead: +slightly below my nominal target. Try this instead: #+begin_src emacs-lisp (setq ement-room-prism-minimum-contrast 7) @@ -6100,7 +5802,7 @@ slightly below our nominal target. Try this instead: With regard to fonts, Ement depends on ~shr~ ([[#h:e6c5451f-6763-4be7-8fdb-b4706a422a4c][Note on SHR fonts]]). -Since we are here, here is an excerpt from Ement's source code: +Since I am here, here is an excerpt from Ement's source code: #+begin_src emacs-lisp (defcustom ement-room-prism-minimum-contrast 6 @@ -6113,13 +5815,13 @@ This should be a reasonable number from, e.g. 0-7 or so." Yes, I do approve of that default. Even a 4.5 (the WCAG AA rating) 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 +My target is the highest of the sort, though I do not demand that everyone conforms with it. ** Note on pdf-tools link hints -:properties: -:custom_id: h:2659d13e-b1a5-416c-9a89-7c3ce3a76574 -:end: +:PROPERTIES: +:CUSTOM_ID: h:2659d13e-b1a5-416c-9a89-7c3ce3a76574 +:END: Hints are drawn by [[https://imagemagick.org/][ImageMagick]], not Emacs, i.e., ImageMagick doesn't know about the hint face unless you tell ImageMagick about it. By @@ -6167,9 +5869,9 @@ you've customized any faces. #+end_src ** Note on the Notmuch logo -:properties: -:custom_id: h:636af312-54a5-4918-84a6-0698e85a3c6d -:end: +:PROPERTIES: +:CUSTOM_ID: h:636af312-54a5-4918-84a6-0698e85a3c6d +:END: By default, the "hello" buffer of Notmuch includes a header with the programs' logo and a couple of buttons. The logo has the effect of @@ -6207,25 +5909,25 @@ stand out more, due to the use of the uncommon =@= character but also because they are often enclosed in angled brackets). * Frequently Asked Questions -:properties: -:custom_id: h:b3384767-30d3-4484-ba7f-081729f03a47 -:end: +:PROPERTIES: +:CUSTOM_ID: h:b3384767-30d3-4484-ba7f-081729f03a47 +:END: #+cindex: Frequently Asked Questions -In this section we provide answers related to some aspects of the Modus +In this section I provide answers related to some aspects of the Modus themes' design and application. ** Is the contrast ratio about adjacent colors? -:properties: -:custom_id: h:5ce7ae2e-9348-4e55-b4cf-9302345b1826 -:end: +:PROPERTIES: +:CUSTOM_ID: h:5ce7ae2e-9348-4e55-b4cf-9302345b1826 +:END: #+cindex: Contrast between adjacent colors The minimum contrast ratio in relative luminance that the themes conform with always refers to any given combination of background and foreground -colors. If we have some blue colored text next to a magenta one, both -against a white background, we do not mean to imply that blue:magenta is -7:1 in terms of relative luminance. Rather, we state that blue:white +colors. If I have some blue colored text next to a magenta one, both +against a white background, I do not mean to imply that blue:magenta is +7:1 in terms of relative luminance. Rather, I state that blue:white and magenta:white each are 7:1 or higher. The point of reference is always the background. Because colors have @@ -6234,7 +5936,7 @@ necessarily are fairly close to each other in this measure. A possible blue:magenta combination would naturally be around 1:1 in contrast of the sort here considered. -To differentiate between sequential colors, we rely on hueness by +To differentiate between sequential colors, I rely on hueness by mapping contrasting hues to adjacent constructs, while avoiding exaggerations. A blue next to a magenta can be told apart regardless of their respective contrast ratio against their common background. @@ -6244,9 +5946,9 @@ be colored differently. They would still be legible though, which is the primary objective of the Modus themes. ** What does it mean to avoid exaggerations? -:properties: -:custom_id: h:44284e1f-fab8-4c4f-92f0-544728a7c91e -:end: +:PROPERTIES: +:CUSTOM_ID: h:44284e1f-fab8-4c4f-92f0-544728a7c91e +:END: #+cindex: Avoiding exaggerations in design The Modus themes are designed with restraint, so that their default @@ -6277,9 +5979,9 @@ magenta can suffice to tell things apart and avoid excess coloration: a harmonious rhythm. ** Why are colors mostly variants of blue, magenta, cyan? -:properties: -:custom_id: h:0b26cb47-9733-4cb1-87d9-50850cb0386e -:end: +:PROPERTIES: +:CUSTOM_ID: h:0b26cb47-9733-4cb1-87d9-50850cb0386e +:END: #+cindex: Innate color qualities of the palette Due to the innate properties of color, some options are better than @@ -6289,7 +5991,7 @@ of exaggerations in design. [[#h:44284e1f-fab8-4c4f-92f0-544728a7c91e][What does it mean to avoid exaggerations?]] -What we describe as color is a function of three distinct channels of +What I describe as color is a function of three distinct channels of light: red, green, blue. In hexadecimal RGB notation, a color value is read as three pairs of red, green, and blue light: =#RRGGBB=. Of those three, the most luminant is green, while the least luminant is blue. @@ -6298,7 +6000,7 @@ The three basic colors represent each of the channels of light. They can be intermixed to give us six colors: red and green derive yellow, green and blue make cyan, red and blue turn into magenta. -We can test the luminance of each of those against white and black to +I can test the luminance of each of those against white and black to get a sense of how not all colors are equally good for accessibility (white is =#ffffff=, which means that all three light channels are fully luminated, while black is =#000000= meaning that no light is present @@ -6317,11 +6019,11 @@ luminated, while black is =#000000= meaning that no light is present [[#h:02e25930-e71a-493d-828a-8907fc80f874][Measure color contrast]]. -By reading this table we learn that every color that has a high level of +By reading this table I learn that every color that has a high level of green light (green, yellow, cyan) is virtually unreadable against a white background and, conversely, can be easily read against black. -We can then infer that red and blue, in different combinations, with +I can then infer that red and blue, in different combinations, with green acting as calibrator for luminance, will give us fairly moderate colors that pass the 7:1 target. Blue with a bit of green produce appropriate variants of cyan. Similarly, blue combined with some red @@ -6345,7 +6047,7 @@ the relative luminance of shades of red, yellow, magenta against white: | #990099 | 7.46 | #+end_example -We notice that equal values of red and blue light in =#990099= (magenta +I notice that equal values of red and blue light in =#990099= (magenta shade) do not lead to a considerable change in luminance compared with =#990000= (red variant). Whereas less amount of green light in =#995500= leads to a major drop in luminance relative to white. It follows that @@ -6353,24 +6055,24 @@ using the green channel of light to calibrate the luminance of colors is more effective than trying to do the same with either red or blue (the latter is the least effective in that regard). -When we need to work with several colors, it is always better to have -sufficient manoeuvring space, especially since we cannot pick arbitrary +When I need to work with several colors, it is always better to have +sufficient manoeuvring space, especially since I cannot pick arbitrary colors but only those that satisfy the accessibility objectives of the themes. -As for why we do not mostly use green, yellow, cyan for the dark theme, +As for why I do not mostly use green, yellow, cyan for the dark theme, it is because those colors are far more luminant than their counterparts on the other side of the spectrum, so to ensure that they all have about -the same contrast ratios we would have to alter their hueness +the same contrast ratios I would have to alter their hueness considerably. In short, the effect would not be optimal as it would lead to exaggerations. Plus, it would make ~modus-vivendi~ look completely different than ~modus-operandi~, to the effect that the two could not be properly considered part of the same project. ** What is the best setup for legibility? -:properties: -:custom_id: h:f60cc2ae-129d-47c0-9849-4f6bbd87d8be -:end: +:PROPERTIES: +:CUSTOM_ID: h:f60cc2ae-129d-47c0-9849-4f6bbd87d8be +:END: #+cindex: General setup for readability The Modus themes can be conceptually simplified as combinations of color @@ -6378,7 +6080,7 @@ values that account for relative luminance and inner harmony. Those qualities do not guarantee that every end-user will have the same experience, due to differences between people, but also because of variances in hardware capabilities and configurations. For the purposes -of this document, we may only provide suggestions pertaining to the +of this document, I may only provide suggestions pertaining to the latter case. ~modus-operandi~ is best used outdoors or in a room that either gets @@ -6418,9 +6120,9 @@ the remaining contributing factors in each case need to be considered in full. ** Are these color schemes? -:properties: -:custom_id: h:a956dbd3-8fd2-4f5d-8b01-5f881268cf2b -:end: +:PROPERTIES: +:CUSTOM_ID: h:a956dbd3-8fd2-4f5d-8b01-5f881268cf2b +:END: #+cindex: Themes, not color schemes No, the Modus themes are not color schemes. @@ -6443,16 +6145,16 @@ 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 +By configuring the multitude of faces on offer I thus control both which colors are applied and how they appear in their context. When a package wants to render each instance of "foo" with the "bar" face, it is not requesting a specific color, which makes things considerably more -flexible as we can treat "bar" in its own right without necessarily -having to use some color value that we hardcoded somewhere. +flexible as I can treat "bar" in its own right without necessarily +having to use some color value that I hardcoded somewhere. Which brings us to the distinction between consistency and uniformity -where our goal is always the former: we want things to look similar -across all interfaces, but we must never force a visual identity where +where my goal is always the former: I want things to look similar +across all interfaces, but I must never force a visual identity where that runs contrary to the functionality of the given interface. For instance, all links are underlined by default yet there are cases such as when viewing listings of emails in Gnus (and Mu4e, Notmuch) where (i) @@ -6477,11 +6179,11 @@ not-so-obvious error of treating different cases as if they were the same. The Modus themes prioritize "thematic consistency" over abstract harmony -or regularity among their applicable colors. In concrete terms, we do -not claim that, say, our yellows are the best complements for our blues -because we generally avoid using complementary colors side-by-side, so +or regularity among their applicable colors. In concrete terms, I do +not claim that, say, my yellows are the best complements for my blues +because I generally avoid using complementary colors side-by-side, so it is wrong to optimize for a decontextualised blue+yellow combination. -Not to imply that our colors do not work well together because they do, +Not to imply that my colors do not work well together because they do, just to clarify that consistency of context is what themes must strive for, and that requires widening the scope of the design beyond the particularities of a color scheme. @@ -6490,9 +6192,9 @@ Long story short: color schemes and themes have different requirements. Please do not conflate the two. ** Port the Modus themes to other platforms? -:properties: -:custom_id: h:7156b949-917d-488e-9a72-59f70d80729c -:end: +:PROPERTIES: +:CUSTOM_ID: h:7156b949-917d-488e-9a72-59f70d80729c +:END: #+cindex: Porting the themes to other editors There is no plan to port the themes to other platforms or text editors. @@ -6550,17 +6252,17 @@ themes, they are welcome to contact me and I will do my best to help them in their efforts. * Contributing -:properties: -:custom_id: h:9c3cd842-14b7-44d7-84b2-a5c8bc3fc3b1 -:end: +:PROPERTIES: +:CUSTOM_ID: h:9c3cd842-14b7-44d7-84b2-a5c8bc3fc3b1 +:END: This section documents the canonical sources of the themes and the ways in which you can contribute to their ongoing development. ** Sources of the themes -:properties: -:custom_id: h:89504f1c-c9a1-4bd9-ab39-78fd0eddb47c -:end: +:PROPERTIES: +:CUSTOM_ID: h:89504f1c-c9a1-4bd9-ab39-78fd0eddb47c +:END: #+cindex: Sources of the themes + Package name (GNU ELPA): ~modus-themes~ @@ -6568,17 +6270,15 @@ in which you can contribute to their ongoing development. + 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 ++ Git repositories: + + GitHub: <https://github.com/protesilaos/modus-themes> + + GitLab: <https://gitlab.com/protesilaos/modus-themes> ++ Backronym: My Old Display Unexpectedly Sharpened ... themes. ** Issues you can help with -:properties: -:custom_id: h:6536c8d5-3f98-43ab-a787-b94120e735e8 -:end: +:PROPERTIES: +:CUSTOM_ID: h:6536c8d5-3f98-43ab-a787-b94120e735e8 +:END: #+cindex: Contributing A few tasks you can help with by sending an email to the general @@ -6591,7 +6291,7 @@ A few tasks you can help with by sending an email to the general + Suggest refinements to the color palette. + Help expand this document or any other piece of documentation. + Send patches for code refinements (if you need, ask me for help with - Git---we all start out as beginners). + Git---I all start out as beginners). [[#h:111773e2-f26f-4b68-8c4f-9794ca6b9633][Patches require copyright assignment to the FSF]]. @@ -6606,9 +6306,9 @@ between aesthetics and accessibility, it shall always be made in the interest of the latter. ** Patches require copyright assignment to the FSF -:properties: -:custom_id: h:111773e2-f26f-4b68-8c4f-9794ca6b9633 -:end: +:PROPERTIES: +:CUSTOM_ID: h:111773e2-f26f-4b68-8c4f-9794ca6b9633 +:END: Code contributions are most welcome. For any major edit (more than 15 lines, or so, in aggregate per person), you need to make a copyright @@ -6641,7 +6341,7 @@ GNU Emacs Even if that material is free software, we need to know about it.] Copied a few snippets from the same files I edited. Their author, -Protesilaos Stavrou, has already assigned copyright to the Free Software +Protesilaos, has already assigned copyright to the Free Software Foundation. [Do you have an employer who might have a basis to claim to own @@ -6669,30 +6369,32 @@ so far?] #+end_example * Acknowledgements -:properties: -:custom_id: h:95c3da23-217f-404e-b5f3-56c75760ebcf -:end: +:PROPERTIES: +:CUSTOM_ID: h:95c3da23-217f-404e-b5f3-56c75760ebcf +:END: #+cindex: Contributors The Modus themes are a collective effort. Every bit of work matters. -+ Author/maintainer :: Protesilaos Stavrou. ++ Author/maintainer :: Protesilaos. + 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, David Edmondson, Eli Zaretskii, Eric Ottosson, + Contovounesios, Benjamin Kästner, Björn Lindström, Carlo Zancanaro, + Christian Tietze, Daniel Colascione, Daniel Mendler, David + Edmondson, Eli Zaretskii, Elias Gabriel Perez, Eric Ottosson, Frédéric Giquel, Fritz Grabo, Gautier Ponsinet, Illia Ostapyshyn, - Jacob S.{{{space()}}} Gordon, Jared Finder, Jimmy Yuen Ho Wong, - Kevin Fleming, Kévin Le Gouguec, Koen van Greevenbroek, Kostadin - Ninev, Leilei332, Madhavan Krishnan, Manuel Giraud, Markus Beppler, - Matthew Stevenson, Mauro Aranda, Nacho Barrientos, Niall Dooley, - Nicolas De Jaeghere, Paul David, Pavel Novichkov, Philip Kaludercic, - Pierre Téchoueyres, Rahul M.{{{space()}}} Juliato, Rudolf Adamkovič, - Sergey Nichiporchik, Shreyas Ragavan, Stefan x Kangas, Stephen - Berman, Stephen Gildea, Steve Downey, Suleyman Boyar, Thanos Apollo, - Tomasz Hołubowicz, Utkarsh Singh, Vincent Murphy, Xinglu Chen, - Yuanchen Xie, fluentpwn, okamsn. + Jacob S.{{{space()}}} Gordon, Jared Finder, JD Smith, Jimmy Yuen Ho + Wong, Kevin Fleming, Kévin Le Gouguec, Koen van Greevenbroek, + Kostadin Ninev, Leilei332, Madhavan Krishnan, Manuel Giraud, Markus + Beppler, Matthew Stevenson, Mauro Aranda, Mike Olson, Nacho + Barrientos, Niall Dooley, Nicolas De Jaeghere, Paul David, Pavel + Novichkov, Philip Kaludercic, Pierre Téchoueyres, Rahul + M.{{{space()}}} Juliato, Rudolf Adamkovič, Sergey Nichiporchik, + Shreyas Ragavan, Stefan x Kangas, Stephen Berman, Stephen Gildea, + Steve Downey, Steven Allen, Suleyman Boyar, Thanos Apollo, Tomasz + Hołubowicz, Utkarsh Singh, Vincent Murphy, Xinglu Chen, Yuanchen + Xie, fluentpwn, okamsn, ukiran03. + Ideas and user feedback :: Aaron Jensen, Adam Porter, Adam Spiers, Adrian Manea, Aleksei Pirogov, Alex Griffin, Alex Koen, Alex @@ -6716,23 +6418,25 @@ The Modus themes are a collective effort. Every bit of work matters. Miguel Castañeda, Magne Hov, Manuel Giraud, Manuel Uberti, Mark Bestley, Mark Burton, Mark Simpson, Marko Kocic, Markus Beppler, 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, Nicolas - Semrau, Olaf Meeuwissen, Oliver Epper, Pablo Stafforini, Paul - Poloskov, Pengji Zhang, Pete Kazmier, Peter Wu, Philip Kaludercic, - Pierre Téchoueyres, Przemysław Kryger, Robert Hepple, Roman Rudakov, - Roshan Shariff, Russell Sim, Ryan Phillips, Rytis Paškauskas, Rudolf - Adamkovič, Sam Kleinman, Samuel Culpepper, Saša Janiška, Shreyas - Ragavan, Simon Pugnet, Stéphane Marks, Steve Downey, Tassilo Horn, - Thanos Apollo, Thibaut Verron, Thomas Heartman, Togan Muftuoglu, - Tony Zorman, Trey Merkley, Tomasz Hołubowicz, Toon Claes, Uri Sharf, + Maxime Tréca, Michael Goldenberg, Mike Crowe, Morgan Smith, Morgan + Willcock, Morten Kjeldgaard, Murilo Pereira, Nicky van Foreest, + Nicolas De Jaeghere, Nicolas Semrau, Olaf Meeuwissen, Oliver Epper, + Pablo Stafforini, Paul Poloskov, Pengji Zhang, Pete Kazmier, Peter + Wu, Philip Kaludercic, Pierre Téchoueyres, Pranshu Sharma, + Przemysław Kryger, Robert Hepple, Roman Rudakov, Roshan Shariff, + Russell Sim, Ryan Phillips, Rytis Paškauskas, Rudolf Adamkovič, Sam + Kleinman, Samuel Culpepper, Saša Janiška, Shreyas Ragavan, Simon + Pugnet, Stéphane Marks, Steve Downey, Tassilo Horn, Thanos Apollo, + Thibaut Verron, Thomas Heartman, Togan Muftuoglu, Tony Zorman, Trey + Merkley, Tomasz Hołubowicz, Toon Claes, Troy Brown, Uri Sharf, Utkarsh Singh, Vincent Foley, Zoltan Kiraly. As well as users: Ben, CsBigDataHub1, Emacs Contrib, Eugene, Fourchaux, Fredrik, Moesasji, - Nick, Summer Emacs, TheBlob42, TitusMu, Trey, bepolymathe, - bit9tream, bangedorrunt, case-lambda, chainedghost, derek-upham, - doolio, fleimgruber, gitrj95, iSeeU, jixiuf, ltmsyvag, okamsn, - pedro-nonfree, pRot0ta1p, realazy, shimeike, shipmints, soaringbird, - tumashu, wakamenod. + Nick, Summer Emacs, TheBlob42, TitusMu, Trey, aikrahguzar, + amano-kenji, baconabo, bangedorrunt, bepolymathe, bit9tream, + case-lambda, chainedghost, derek-upham, doolio, fleimgruber, + gitrj95, iSeeU, jixiuf, ltmsyvag, okamsn, pedro-nonfree, pRot0ta1p, + realazy, shimeike, shipmints, soaringbird, tumashu, vpxyz, + wakamenod. + Packaging :: Basil L.{{{space()}}} Contovounesios, Eli Zaretskii, Glenn Morris, Mauro Aranda, Richard Stallman, Stefan Kangas (core @@ -6751,10 +6455,10 @@ themes' design and/or aspects of their functionality. All errors are my own. * GNU Free Documentation License -:properties: -:appendix: t -:custom_id: h:3077c3d2-7f90-4228-8f0a-73124f4026f6 -:end: +:PROPERTIES: +:APPENDIX: t +:CUSTOM_ID: h:3077c3d2-7f90-4228-8f0a-73124f4026f6 +:END: #+texinfo: @include doclicense.texi @@ -6765,7 +6469,7 @@ All errors are my own. Version 1.3, 3 November 2008 - Copyright (C) 2000-2002, 2007-2008, 2026 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. <https://fsf.org/> Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -7217,26 +6921,26 @@ to permit their use in free software. #+html: <!-- * Indices -:properties: -:custom_id: h:55104b26-8e94-46cf-9975-43ea00316489 -:end: +:PROPERTIES: +:CUSTOM_ID: h:55104b26-8e94-46cf-9975-43ea00316489 +:END: ** Function index -:properties: -:index: fn -:custom_id: h:6bec5005-529c-4521-ae05-3d990baffb5b -:end: +:PROPERTIES: +:INDEX: fn +:CUSTOM_ID: h:6bec5005-529c-4521-ae05-3d990baffb5b +:END: ** Variable index -:properties: -:index: vr -:custom_id: h:16ad8df6-b015-40a9-9259-03d4f7a23ee4 -:end: +:PROPERTIES: +:INDEX: vr +:CUSTOM_ID: h:16ad8df6-b015-40a9-9259-03d4f7a23ee4 +:END: ** Concept index -:properties: -:index: cp -:custom_id: h:6aa7a656-884b-4c39-b759-087e412eec13 -:end: +:PROPERTIES: +:INDEX: cp +:CUSTOM_ID: h:6aa7a656-884b-4c39-b759-087e412eec13 +:END: #+html: --> diff --git a/doc/misc/org.org b/doc/misc/org.org index 8644109a6a1..d4bf8cb009c 100644 --- a/doc/misc/org.org +++ b/doc/misc/org.org @@ -10013,8 +10013,8 @@ entries with a =NEXT= TODO keyword. ((org-agenda-max-entries 5))))) #+end_src -Once you mark one of these five entry as DONE, rebuilding the agenda -will again the next five entries again, including the first entry that +Once you mark one of these five entries as DONE, rebuilding the agenda +will show the next five entries again, including the first entry that was excluded so far. You can also dynamically set temporary limits, which are lost when @@ -10269,7 +10269,7 @@ the other commands, point needs to be in the desired line. Toggle Archives mode. In Archives mode, trees that are archived (see [[*Internal archiving]]) are also scanned when producing the agenda. To exit archives mode, press {{{kbd(v a)}}} again. The - initial setting for this mode in new agenda buffers can set with the + initial setting for this mode in new agenda buffers can be set with the variable ~org-agenda-start-with-archives-mode~, which can be set with the same values as ~org-agenda-archives-mode~. @@ -14552,11 +14552,13 @@ include: #+vindex: org-latex-tables-booktabs #+vindex: org-latex-tables-centered All three commands are toggles. =:booktabs= brings in modern - typesetting enhancements to regular tables. The booktabs package - has to be loaded through ~org-latex-packages-alist~. =:center= is - for centering the table. =:rmlines= removes all but the very first - horizontal line made of ASCII characters from "table.el" tables - only. + typesetting enhancements to regular tables. The =booktabs= package + needs to be loaded through ~org-latex-packages-alist~, unless it is + already included by your document class[fn:: For example, + [[https://authors.acm.org/proceedings/production-information/preparing-your-article-with-latex][the + ACM article template]].]. =:center= is for centering the table. + =:rmlines= removes all but the very first horizontal line made of + ASCII characters from "table.el" tables only. - =:math-prefix=, =:math-suffix=, =:math-arguments= :: diff --git a/doc/misc/texinfo.tex b/doc/misc/texinfo.tex index 54c2f3e7831..7187edf08e7 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{2026-04-26.12} +\def\texinfoversion{2026-07-04.10} % -% Copyright 1985, 1986, 1988, 1990-2025 Free Software Foundation, Inc. +% Copyright 1985, 1986, 1988, 1990-2026 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 @@ -765,22 +765,24 @@ where each line of input produces a line of output.} % @include FILE -- \input text of FILE. % -\def\include{\parseargusing\filenamecatcodes\includezzz} +\def\include{\tracingmacros=1\parseargusing\filenamecatcodes\includezzz} \def\includezzz#1{% \pushthisfilestack \def\thisfile{#1}% + \includecheckspace\thisfile {% \makevalueexpandable % we want to expand any @value in FILE. \turnoffactive % and allow special characters in the expansion \indexnofonts % Allow `@@' and other weird things in file names. \wlog{texinfo.tex: doing @include of #1^^J}% - \edef\temp{\noexpand\input #1 }% + \edef\temp{\noexpand\input \thisfile }% % % This trickery is to read FILE outside of a group, in case it makes % definitions, etc. \expandafter }\temp \popthisfilestack + \def\thisfile{#1}% for @thisfile command } \def\filenamecatcodes{% \catcode`\\=\other @@ -796,6 +798,21 @@ where each line of input produces a line of output.} \catcode`\'=\other } +% \includecheckspace\FILENAME - if there is a space in the expansion of +% \FILENAME, wrap the expansion in braces +\def\includecheckspace#1{% + \expandafter\includecheckspacezz\expandafter#1#1 \includecheckspacezz} + +\def\includecheckspacezz#1#2 #3\includecheckspacezz{% + \def\tmp{#3}% + \ifx\tmp\empty + % no space in the file name + \else + % there is a space in the file name + \edef#1{{#1}}% + \fi +} + \def\pushthisfilestack{% \expandafter\pushthisfilestackX\popthisfilestack\StackTerm } @@ -5359,7 +5376,7 @@ $$% % \checksortas\segment % Call \indexwritesortas if a @sortas command appears in the segment -\def\checksortas#1{ +\def\checksortas#1{% \let\sortas\relax \expandafter\checksortasx#1\relax\sortas{}\sortas } @@ -5372,7 +5389,7 @@ $$% % \checkseealso\segment % Call \indexwriteseealso if a @seealso command appears in the segment -\def\checkseealso#1{ +\def\checkseealso#1{% \let\seealso\relax \expandafter\checkseealsox#1\relax\seealso{}\seealso } @@ -5385,7 +5402,7 @@ $$% % \checkseeentry\segment % Call \indexwriteseeentry if a @seeentry command appears in the segment -\def\checkseeentry#1{ +\def\checkseeentry#1{% \let\seeentry\relax \expandafter\checkseeentryx#1\relax\seeentry{}\seeentry } @@ -5798,9 +5815,9 @@ might help (with 'rm \jobname.?? \jobname.??s')% % The glue before the bonus allows a little bit of space at the % bottom of a column to reduce an increase in inter-line spacing. \nobreak - \vskip 0pt plus 5\baselineskip + \vskip 0pt plus 4\baselineskip \penalty -300 - \vskip 0pt plus -5\baselineskip + \vskip 0pt plus -4\baselineskip % % Typeset the initial. Making this add up to a whole number of % baselineskips increases the chance of the dots lining up from column @@ -11010,6 +11027,12 @@ directory should work if nowhere else does.} \expandafter\gdef\UTFviiiTmp{#2}% } +% Used in translation files, e.g. in txi-is.tex: +% \DefineSortKey{00DE}{{\string\idxsort{1}{\string\TH{}}}} % Þ +% We provide a definition here in case the sequence shows up in sorted +% index files. +\def\idxsort#1#2{#2} + % this could be used as follows %\DefineSortKey{00F1}{nzzz} % n tilde - sort between n and o %\DefineSortKey{00D1}{Nzzz} % N tilde - sort between n and o diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi index 6daa2b010cf..7bee92a94d5 100644 --- a/doc/misc/tramp.texi +++ b/doc/misc/tramp.texi @@ -6973,7 +6973,7 @@ If the same @var{function} shall be used for different @value{tramp} backends, @code{tramp-add-external-operation} must be called for every backend, respectively. -The optional argument @var{arg-type} specisfies, which argument of +The optional argument @var{arg-type} specifies, which argument of @var{operation} shall be used in order to determine, whether the handler @var{function} should be called. It can be @@ -6988,6 +6988,10 @@ checked. This is the default, if @var{arg-type} is @code{nil}. @item @code{process}@* @code{default-directory} of the process buffer of the first argument of @var{operation}, a process, is the remote file name to be checked. + +@item @code{tramp-file-name}@* +The @code{tramp-file-name} structure of the first argument of +@var{operation} is the remote file name to be checked. @end itemize If the first argument of @var{operation} is nil, @@ -7015,6 +7019,26 @@ The example above could be changed like this: @end lisp @end defun +@defun tramp-external-operation-p operation backend +This checks, whether @value{tramp}'s backend @var{backend} supports +external @var{operation}. It returns the function registered as +handler, or @code{nil}. Example: + +@lisp +@group +(tramp-external-operation-p + #'my-test-operation 'tramp-sh) +@result{} my-handle-test-operation +@end group + +@group +(tramp-external-operation-p + #'my-test-operation 'tramp-gvfs) +@result{} nil +@end group +@end lisp +@end defun + @defun tramp-remove-external-operation operation backend The handler for @var{operation}, added by @code{tramp-add-external-operation}, is removed from @var{backend}. diff --git a/doc/misc/trampver.texi b/doc/misc/trampver.texi index 165d0eb1352..07f017403f9 100644 --- a/doc/misc/trampver.texi +++ b/doc/misc/trampver.texi @@ -7,7 +7,7 @@ @c In the Tramp GIT, the version number and the bug report address @c are auto-frobbed from configure.ac. -@set trampver 2.8.2 +@set trampver 2.8.3-pre @set trampurl https://www.gnu.org/software/tramp/ @set tramp-bug-report-address tramp-devel@@gnu.org @set emacsver 28.1 diff --git a/doc/translations/README b/doc/translations/README index f97f4fb105c..49c63ef62ad 100644 --- a/doc/translations/README +++ b/doc/translations/README @@ -1,19 +1,73 @@ * Translated Emacs manuals ** Translations available -Translations for language _doclang_ can be found under directory -doc/translations/_doclang_. +Translations for language DOCLANG can be found under directory +doc/translations/DOCLANG. DOCLANG is for instance fr for French. -** Compiling a manual translation +** Compiling all manual translations + +Manual Texinfo sources are grouped into four subdirectories DIR with DIR +in { lispref, lispintro, emacs, misc}, and can be compiled to five +output formats FORMAT with FORMAT in { dvi, html, info, pdf, ps}. Texinfo +source code is under doc/DIR for the default language, and under +doc/translations/DOCLANG/DIR for language DOCLANG, for instance replace +DOCLANG by fr for French. + +You can build all the manuals including their translations for any +combination of DIR and FORMAT by making the target DIR-FORMAT with the +top level Makefile. For instance: + + make misc-info + +to make all manuals from the misc subdirectory into the info format and +for all the language listed in the DOCLANGS list resulting from the +./configure step or superseded by setting DOCLANGS in the +environment. Outputs are made into the info directory for info format +and into the doc/DIR subdirectory for other formats (the output is in +doc/DIR, not doc/translations/DOCLANG/DIR, even when the DOCLANG is not +default). + +You can select only some translations by means of the DOCLANGS +environment variable. DOCLANGS is otherwise set by the ./configure step +to all language supported by the Texinfo compiler and for which at least +one manual translation is available. DOCLANGS is a space separated list +of languages. ./configure --help for values supported. For instance: + + make misc-info DOCLANGS=fr + +to make all manuals from the misc subdirectory into the info format and +for language French only. + +Alternatively, you can use: + + make -C doc/DIR FORMAT + +to build manuals from DIR subdirectory, output format FORMAT and for the +default language only. + +Use: + + make -C doc/DIR FORMAT DOCLANG=fr + +to build manuals from DIR subdirectory and output format FORMAT for the +French language only (replace fr by any language supported for DOCLANGS +as listed in ./configure --help). + + +** Compiling one manual translation For the info output, and, say, SES manual in French: make -C doc/misc ses DOCLANG=fr +ses-fr.info will go into the info directory. + For the pdf output: make -C doc/misc ses-fr.pdf DOCLANG=fr +ses-fr.pdf will go into the doc/misc directory. + * Translating the Emacs manuals ** Copyright assignment @@ -85,7 +139,7 @@ few rules to follow: - Most Emacs manuals are set to include the docstyle.Texi file. This file adds the "@documentencoding UTF-8" directive to the targeted - manual. There is no need to add this directive in a manual that + manual. There is no need to add this directive in a manual that includes docstyle.texi. - Add a @documentlanguage directive that includes your language. @@ -112,7 +166,7 @@ See the 'Bugs' section in the Emacs manual. ** Sending your contributions Send your contributions (files or revisions) for review to the Emacs -development list at [email protected]. Subscribing to the list is not +development list at [email protected]. Subscribing to the list is not obligatory. Always send contributions in the format of the original document. Most diff --git a/doc/translations/default/info_common.mk b/doc/translations/default/misc/info_common.mk similarity index 100% rename from doc/translations/default/info_common.mk rename to doc/translations/default/misc/info_common.mk diff --git a/doc/translations/fr/info_common.mk b/doc/translations/fr/misc/info_common.mk similarity index 100% rename from doc/translations/fr/info_common.mk rename to doc/translations/fr/misc/info_common.mk diff --git a/etc/AUTHORS b/etc/AUTHORS index 150f5ee6527..fce94721cd4 100644 --- a/etc/AUTHORS +++ b/etc/AUTHORS @@ -17,7 +17,7 @@ Aaron Jensen: changed nsterm.m frameset.el ruby-bracketed-args-indent.rb Aaron Larson: co-wrote bibtex.el Aaron L. Zeng: changed savehist.el emacs-module-tests.el emacs-module.c - eval.c lisp.h vc-hg.el + eval.c goto-addr.el lisp.h vc-hg.el Aaron S. Hawley: wrote lisp-tests.el undo-tests.el and changed simple.el files.texi isearch.el morse.el sgml-mode.el @@ -258,6 +258,8 @@ Alfred M. Szmidt: changed rmail.el vc-svn.el html2text.el openbsd.h Alfredo Finelli: changed TUTORIAL.it +Al Haji-Ali: changed latexenc.el + Ali Bahrami: changed configure configure.ac sol2-10.h Alin C. Soare: changed lisp-mode.el hexl.el @@ -311,7 +313,8 @@ and changed nsterm.m nsfns.m nsmenu.m nsterm.h font-lock.el nsimage.m Anders Waldenborg: changed emacsclient.c -Andrea Alberti: changed xdisp.c dispextern.h faces.el xfaces.c +Andrea Alberti: changed xdisp.c xfaces.c dispextern.h display.texi + faces.el nsterm.m Andrea Corallo: wrote [native compilation of Emacs Lisp] comp-common.el comp-cstr-tests.el comp-cstr.el comp-run.el comp-tests.el comp.c @@ -502,9 +505,9 @@ Antonin Houska: changed newcomment.el Antonio Ruiz: changed handwrite.el Arash Esbati: changed reftex-vars.el efaq-w32.texi reftex-cite.el - reftex-tests.el reftex.texi reftex-parse.el reftex.el gnus.texi - ispell.el reftex-auc.el reftex-dcr.el reftex-ref.el tex-mode.el - align.el eglot.el ffap.el latexenc.el maintaining.texi nnmaildir.el + reftex-tests.el reftex.texi reftex-parse.el reftex.el tex-mode.el + gnus.texi ispell.el reftex-auc.el reftex-dcr.el reftex-ref.el align.el + eglot.el ffap.el latexenc.el maintaining.texi nnmaildir.el reftex-global.el reftex-toc.el Arik Mitschang: changed smime.el @@ -583,9 +586,9 @@ Augustin Chéneau: changed c-ts-mode.el treesit.el Augusto Stoffel: co-wrote ansi-osc.el and changed progmodes/python.el eglot.el isearch.el comint.el eldoc.el progmodes/compile.el project.el README.md bookmark.el dired.el - dockerfile-ts-mode.el files.el font-lock.el glasses.el gnutls.el man.el - message.el message.texi misc.texi modes.texi outline.el - and 17 other files + dockerfile-ts-mode.el emacsbug.el files.el font-lock.el glasses.el + gnutls.el man.el message.el message.texi misc.texi modes.texi + and 19 other files Aurélien Aptel: changed alloc.c emacs-module.h lisp.h Makefile configure.ac cus-face.el data.c dispextern.h display.texi dynlib.c @@ -735,6 +738,7 @@ Billy Lei: wrote burmese.el Billy Zheng: changed README.md eglot.el Binbin Ye: changed json-ts-mode-tests.el json-ts-mode.el + typescript-ts-mode.el Bjarte Johansen: wrote ob-sed.el and changed use-package-bind-key.el @@ -979,7 +983,7 @@ and co-wrote longlines.el tango-dark-theme.el tango-theme.el and changed simple.el display.texi xdisp.c files.el frames.texi cus-edit.el files.texi custom.el subr.el text.texi faces.el keyboard.c startup.el package.el misc.texi emacs.texi modes.texi mouse.el - custom.texi image.c window.el and 920 other files + custom.texi image.c window.el and 903 other files Chris Chase: co-wrote idlw-shell.el idlwave.el @@ -1301,10 +1305,10 @@ Daniel McClanahan: changed lisp-mode.el Daniel M Coffman: changed arc-mode.el Daniel Mendler: co-wrote compat.el -and changed minibuffer.el simple.el browse-url.el ibuffer.el crm.el - eww.el minibuf.texi project.el buffer-tests.el buffer.c buffer.h +and changed minibuffer.el simple.el browse-url.el eldoc.el ibuffer.el + crm.el eww.el minibuf.texi project.el buffer-tests.el buffer.c buffer.h dispextern.h display.texi faces.el frame.c frame.h package.el - picture.el subr-tests.el subr.el window.c and 30 other files + picture.el subr-tests.el subr.el and 30 other files Daniel M German: co-wrote org-protocol.el @@ -1441,7 +1445,7 @@ and changed cedet/semantic.el db.el insert.el semantic/complete.el c.by c.el db-el.el db-file.el db-find.el ede-grammar.el eieio-opt.el eieio.el eieio.texi gnus.texi registry.el srecode/compile.el wisent/python.el analyze.el bovine/el.el bovine/grammar.el - decorate/mode.el and 88 other files + decorate/mode.el and 87 other files Davide Pola: changed comp-cstr.el comp-run.el @@ -1673,7 +1677,7 @@ Dionisio E Alonso: changed eglot.el Dirk Herrmann: co-wrote bibtex.el Dirk-Jan C. Binnema: changed xwidget.c configure.ac org-agenda.el - process.c process.h + process.c process.h xterm.c Dirk Ullrich: changed ispell.el @@ -1698,8 +1702,8 @@ Dmitry Gutov: wrote elisp-mode-tests.el etags-regen.el jit-lock-tests.el and changed project.el xref.el ruby-mode.el vc-git.el ruby-ts-mode.el vc.el elisp-mode.el js.el etags.el ruby-mode-tests.el vc-hg.el package.el minibuffer.el maintaining.texi simple.el symref/grep.el - progmodes/python.el ruby-ts-mode-tests.el treesit.el dired-aux.el - project-tests.el and 189 other files + progmodes/python.el project-tests.el ruby-ts-mode-tests.el treesit.el + dired-aux.el and 190 other files Dmitry Kurochkin: changed isearch.el @@ -1814,7 +1818,7 @@ and co-wrote help-tests.el and changed xdisp.c display.texi w32.c msdos.c simple.el w32fns.c files.el fileio.c keyboard.c configure.ac emacs.c text.texi dispnew.c w32term.c frames.texi files.texi w32proc.c xfaces.c process.c window.c - dispextern.h and 1453 other files + dispextern.h and 1441 other files Eliza Velasquez: changed server.el simple.el @@ -1917,7 +1921,7 @@ and changed c.srt ede.texi info.el rmail.el speedbspec.el cedet.el ede-autoconf.srt ede-make.srt eieio.texi gud.el sb-dir-minus.xpm sb-dir-plus.xpm sb-dir.xpm sb-mail.xpm sb-pg-minus.xpm sb-pg-plus.xpm sb-pg.xpm sb-tag-gt.xpm sb-tag-minus.xpm sb-tag-plus.xpm - and 35 other files + and 34 other files Eric Schulte: wrote ob-awk.el ob-calc.el ob-comint.el ob-css.el ob-dot.el ob-emacs-lisp.el ob-eval.el ob-forth.el ob-gnuplot.el ob-haskell.el @@ -1975,7 +1979,7 @@ and changed completion-preview-tests.el programs.texi eglot.el elisp-mode.el emacs.texi emoji.el eww.el help-fns.el info.el minibuffer-tests.el minibuffer.el text-mode.el window.c xdisp.c xref.el bookmark.el dictionary.el display.texi easy-mmode.el eldoc.el - elec-pair.el and 21 other files + elec-pair.el and 24 other files Espen Skoglund: wrote pascal.el @@ -2316,7 +2320,7 @@ and changed configure.ac Makefile.in src/Makefile.in calendar.el lisp/Makefile.in diary-lib.el files.el make-dist rmail.el progmodes/f90.el bytecomp.el admin.el misc/Makefile.in simple.el authors.el startup.el emacs.texi lib-src/Makefile.in display.texi - ack.texi subr.el and 1771 other files + ack.texi subr.el and 1753 other files Glynn Clements: wrote gamegrid.el snake.el tetris.el @@ -2399,6 +2403,8 @@ Guy Geens: changed gnus-score.el Gwern Branwen: changed browse-url.el +Haiyang Miao: changed pgtkterm.c + Håkan Granath: changed dired.el Håkon Malmedal: changed calendar.el holidays.el @@ -2706,7 +2712,7 @@ and changed org-lparse.el org.el org.texi ox.el icomplete.el etags.el htmlfontify.el ido.el indian.el iswitchb.el org-bbdb.el org-compat.el and 5 other files -James Cherti: changed sh-script.el eldoc.el outline.el +James Cherti: changed sh-script.el eldoc.el elisp-mode.el outline.el progmodes/python.el yaml-ts-mode.el James Clark: wrote nxml-enc.el nxml-maint.el nxml-mode.el nxml-ns.el @@ -2853,10 +2859,10 @@ Jay McCarthy: changed org-colview.el Jay Sachs: changed gnus-score.el gnus-win.el J.D. Smith: co-wrote idlw-help.el idlw-shell.el idlwave.el -and changed idlw-rinfo.el comint.el idlwave.texi loaddefs-gen.el vc.el - bibtex.el byte-run.el cl-generic.el configure.ac easy-mmode.el eglot.el - files.texi functions.texi hideshow.el inline.el loading.texi misc.texi - mouse.el os.texi pcase.el repeat.el and 10 other files +and changed idlw-rinfo.el comint.el configure.ac idlwave.texi + loaddefs-gen.el vc.el bibtex.el byte-run.el cl-generic.el easy-mmode.el + eglot.el files.texi functions.texi hideshow.el inline.el loading.texi + misc.texi mouse.el os.texi pcase.el repeat.el and 10 other files Jean Abou Samra: changed scheme.el @@ -3123,6 +3129,8 @@ Johan Claesson: changed cl.texi filecache.el files-x.el help-fns.el Johan Euphrosine: changed ibuf-ext.el +Johan Myréen: changed pgtkterm.c + Johannes Weiner: changed browse-url.el keyboard.c configure.ac lisp-mode.el lisp.h pp.el sound.c w32term.c xfaces.c xterm.c @@ -3345,7 +3353,7 @@ and co-wrote help-tests.el keymap-tests.el and changed subr.el desktop.el w32fns.c bs.el faces.el simple.el emacsclient.c files.el server.el help-fns.el xdisp.c org.el w32term.c w32.c buffer.c keyboard.c ido.el image.c window.c eval.c allout.el - and 1206 other files + and 1191 other files Juan Pechiar: changed ob-octave.el @@ -3395,10 +3403,11 @@ and changed callproc.c eglot.el tramp-gvfs.el tramp-sh.el comint.el Juri Linkov: wrote compose.el emoji.el files-x.el misearch.el repeat-tests.el replace-tests.el tab-bar-tests.el tab-bar.el tab-line.el -and changed isearch.el simple.el replace.el info.el dired.el treesit.el - minibuffer.el dired-aux.el window.el outline.el progmodes/grep.el - subr.el diff-mode.el repeat.el vc.el mouse.el files.el image-mode.el - menu-bar.el project.el display.texi and 528 other files +and changed isearch.el simple.el replace.el info.el dired.el + minibuffer.el treesit.el dired-aux.el window.el outline.el + progmodes/grep.el subr.el diff-mode.el repeat.el vc.el mouse.el + files.el image-mode.el menu-bar.el project.el display.texi + and 527 other files Jussi Lahdenniemi: changed w32fns.c ms-w32.h msdos.texi w32.c w32.h w32console.c w32heap.c w32inevt.c w32term.h @@ -3428,7 +3437,7 @@ and co-wrote longlines.el tramp-sh.el tramp.el and changed message.el gnus-agent.el gnus-sum.el files.el nnmail.el tramp.texi nntp.el gnus.el simple.el ange-ftp.el dired.el paragraphs.el bindings.el files.texi gnus-art.el gnus-group.el man.el INSTALL - Makefile.in crisp.el fileio.c and 45 other files + Makefile.in crisp.el fileio.c and 44 other files Kailash C. Chowksey: changed HELLO ind-util.el kannada.el knd-util.el lisp/Makefile.in loadup.el @@ -3560,7 +3569,7 @@ and co-wrote ps-def.el ps-mule.el ps-print.el ps-samp.el quail.el and changed coding.c mule-cmds.el mule.el fontset.c charset.c xdisp.c font.c fontset.el xterm.c fileio.c mule-conf.el ftfont.c characters.el fns.c mule-diag.el coding.h charset.h ccl.c xfaces.c editfns.c - composite.c and 385 other files + composite.c and 370 other files Kenichi Okada: co-wrote sasl-cram.el sasl-digest.el @@ -3661,6 +3670,8 @@ Kirill A. Korinskiy: changed fortune.el Kirk Kelsey: changed make-mode.el vc-hg.el +Kisaragi Hiu: changed js.el typescript-ts-mode.el + Kiso Katsuyuki: changed tab-line.el Kjartan Óli Ágústsson: changed doc-view.el @@ -3787,7 +3798,7 @@ and co-wrote gnus-kill.el gnus-mh.el gnus-msg.el gnus-score.el and changed subr.el simple.el gnus.texi files.el display.texi process.c help-fns.el text.texi image.c dired.el help.el image.el package.el edebug.el shortdoc.el dired-aux.el gnutls.c minibuffer.el subr-x.el - auth-source.el smtpmail.el and 1051 other files + auth-source.el smtpmail.el and 1050 other files Lars Rasmusson: changed ebrowse.c @@ -3923,7 +3934,7 @@ Luc Teirlinck: wrote help-at-pt.el and changed files.el autorevert.el cus-edit.el subr.el simple.el frames.texi startup.el display.texi files.texi dired.el comint.el modes.texi custom.texi emacs.texi fns.c frame.el ielm.el minibuf.texi - variables.texi buffers.texi commands.texi and 211 other files + variables.texi buffers.texi commands.texi and 210 other files Ludovic Courtès: wrote nnregistry.el and changed configure.ac gnus.texi loadup.el @@ -4067,6 +4078,8 @@ Mark Diekhans: changed files.el ispell.el progmodes/compile.el subr.el Mark E. Shoulson: changed org.el org-entities.el +Mark Hindley: changed browse-url.el + Mark Hood: changed gnus-uu.el Mark H. Weaver: changed comint.el @@ -4163,9 +4176,9 @@ Martin Neitzel: changed supercite.el Martin Pohlack: changed iimage.el pc-select.el Martin Rudalics: co-wrote window-x.el -and changed window.el window.c windows.texi frame.c xdisp.c frames.texi +and changed window.el window.c windows.texi frame.c frames.texi xdisp.c xterm.c w32fns.c frame.el w32term.c xfns.c frame.h display.texi - cus-start.el buffer.c help.el keyboard.c mouse.el window.h dispnew.c + cus-start.el help.el buffer.c keyboard.c mouse.el window.h dispnew.c gtkutil.c and 220 other files Martin Stjernholm: wrote cc-bytecomp.el @@ -4339,7 +4352,8 @@ Michael Albinus: wrote autorevert-tests.el dbus-tests.el dbus.el tramp-gvfs.el tramp-integration.el tramp-message.el tramp-rclone.el tramp-smb.el tramp-sshfs.el tramp-sudoedit.el tramp-tests.el url-tramp-tests.el url-tramp.el zeroconf.el -and co-wrote tramp-cache.el tramp-sh.el tramp.el vc-tests.el +and co-wrote tramp-cache.el tramp-sh.el tramp.el vc-tests-helpers.el + vc-tests.el and changed tramp.texi tramp-adb.el trampver.el trampver.texi gitlab-ci.yml files.el dbusbind.c files.texi ange-ftp.el Dockerfile.emba dbus.texi file-notify-tests.el autorevert.el @@ -4425,7 +4439,7 @@ Michael Olson: changed erc.el erc-backend.el Makefile erc-track.el erc-log.el erc-stamp.el erc-autoaway.el erc-dcc.el erc-goodies.el erc-list.el erc-compat.el erc-identd.el erc.texi erc-bbdb.el erc-match.el erc-notify.el erc-ibuffer.el erc-services.el remember.el - erc-button.el erc-nicklist.el and 54 other files + erc-button.el erc-nicklist.el and 53 other files Michael Orlitzky: changed tex-mode.el @@ -4866,6 +4880,8 @@ and changed dired-aux.el outline.el checkdoc.el files.el subr.el buffer.c Oleksandr Gavenko: changed generic-x.el progmodes/grep.el +Oleksandr Makhmudov: changed eglot.el + Olin Shivers: wrote cmuscheme.el inf-lisp.el and co-wrote comint.el shell.el @@ -5085,12 +5101,12 @@ Peter Münster: changed image-dired.el gnus-delay.el gnus-demon.el Peter O'Gorman: changed configure.ac frame.h hpux10-20.h termhooks.h -Peter Oliver: changed emacsclient.desktop emacs.metainfo.xml - emacsclient-mail.desktop Makefile.in emacs-mail.desktop - treesit-admin.el configure.ac dired-tests.el efaq.texi misc.texi - server.el term.c AndroidManifest.xml.in Dockerfile.emba admin.el - compat-template.html ediff-diff.el emacs.c emacs.desktop emacsclient.1 - perl-mode.el and 6 other files +Peter Oliver: changed emacsclient.desktop emacs.metainfo.xml Makefile.in + emacsclient-mail.desktop emacs-mail.desktop treesit-admin.el + configure.ac dired-tests.el efaq.texi misc.texi server.el term.c + AndroidManifest.xml.in Dockerfile.emba admin.el compat-template.html + ediff-diff.el emacs.c emacs.desktop emacsclient.1 perl-mode.el + and 6 other files Peter Povinec: changed term.el @@ -5131,7 +5147,7 @@ Petr Salinger: changed configure.ac gnu-kfreebsd.h Petteri Hintsanen: changed sequences.texi tab-bar.el Makefile.in bindat.el emacs/Makefile.in lispintro/Makefile.in lispref/Makefile.in - misc/Makefile.in + misc/Makefile.in perl-mode.el Phil Hagelberg: wrote ert-x-tests.el and changed package.el pcmpl-unix.el eglot.el subr.el @@ -5148,7 +5164,7 @@ Philip Kaludercic: wrote epa-ks.el newcomers-presets-theme.el and co-wrote compat.el and changed package.el rcirc.el package.texi rcirc.texi vc.el sgml-mode.el vc-git.el project.el which-key.el package-autosuggest.eld - package-activate.el startup.el message.el subr.el custom.texi eglot.el + startup.el package-activate.el message.el subr.el custom.texi eglot.el simple.el bytecomp.el cus-edit.el custom.el help.el and 94 other files Philippe Altherr: changed sh-script.el sh-script-tests.el shell.sh @@ -5237,10 +5253,10 @@ Piotr Trojanek: changed gnutls.c process.c Piotr Zieliński: wrote org-mouse.el Pip Cet: wrote image-circular-tests.el -and changed pdumper.c comp.c lisp.h xdisp.c alloc.c xterm.c fns.c - configure.ac emacs.c eval.c image.c comp.el frame.c print.c - src/Makefile.in byte-opt.el conf_post.h data.c doc.c ftcrfont.c - gtkutil.c and 119 other files +and changed pdumper.c comp.c lisp.h xdisp.c alloc.c xterm.c eval.c fns.c + configure.ac emacs.c image.c comp.el frame.c print.c src/Makefile.in + byte-opt.el conf_post.h data.c doc.c ftcrfont.c gtkutil.c + and 123 other files Platon Pronko: changed tramp.el @@ -5270,10 +5286,9 @@ Protesilaos Stavrou: wrote modus-operandi-deuteranopia-theme.el modus-vivendi-deuteranopia-theme.el modus-vivendi-theme.el modus-vivendi-tinted-theme.el modus-vivendi-tritanopia-theme.el and changed modus-themes.org eww.el vc-dir.el TUTORIAL.el_GR log-view.el - modus-themes.texi time.el vc-git.el appt.el apropos.el custom.el - diff-mode.el flymake.el ibuffer.el language/greek.el log-edit.el - minibuffer.el package.el perl-mode.el shortdoc.el shr.el - and 6 other files + time.el vc-git.el appt.el apropos.el custom.el diff-mode.el flymake.el + ibuffer.el language/greek.el log-edit.el minibuffer.el package.el + perl-mode.el shortdoc.el shr.el vc-cvs.el and 5 other files Przemsyław Kryger: wrote package-vc-tests.el @@ -5443,9 +5458,9 @@ and changed calendar.el diary-icalendar-tests.el icalendar-recur-tests.el icalendar-parser-tests.el icalendar-tests.el .gitattributes cal-dst.el cal-move.el cond-star.el diary-icalendar-resources emacs.texi gnus-icalendar-tests.el icalendar-ast-tests.el - import-legacy-function.ics import-legacy-vars.ics - import-non-recurring-all-day.ics import-rrule-anniversary.ics - and 8 other files + import-bug-11473.diary-iso import-bug-22092.diary-iso + import-bug-33277.diary-iso import-legacy-function.ics + and 22 other files Richard Levitte: changed vc-mtn.el @@ -5690,6 +5705,8 @@ and changed progmodes/compile.el cl-indent.el simple.el vc-cvs.el vc.el Samuel Bronson: changed custom.el emacsclient.c keyboard.c progmodes/grep.el semantic/format.el unexmacosx.c +Samuele Favazza: changed tramp-container.el + Samuel Freilich: changed simple.el Samuel Loury: changed org.el @@ -5765,11 +5782,11 @@ Sean Sieger: changed emacs-lisp-intro.texi Sean Whitton: wrote em-elecslash.el em-extpipe-tests.el em-extpipe.el vc-test-misc.el -and co-wrote vc-tests.el +and co-wrote vc-tests-helpers.el vc-tests.el and changed vc.el vc-git.el vc-dispatcher.el vc-hg.el vc-dir.el diff-mode.el vc-hooks.el vc1-xtra.texi log-view.el maintaining.texi subr.el project.el log-edit.el files.texi server.el simple.el window.el - cond-star.el dired-aux.el keyboard.c vc/vc-bzr.el and 333 other files + cond-star.el dired-aux.el keyboard.c vc/vc-bzr.el and 334 other files Sebastian Fieber: changed gnus-art.el mm-decode.el mm-view.el @@ -5964,7 +5981,7 @@ Sławomir Nowaczyk: changed emacs.py progmodes/python.el TUTORIAL.pl Spencer Baugh: wrote map-ynp-tests.el uniquify-tests.el which-func-tests.el -and changed minibuffer.el project.el minibuffer-tests.el simple.el +and changed minibuffer.el minibuffer-tests.el project.el simple.el flymake.el process.c progmodes/grep.el startup.el vc-hg.el crm.el mini.texi uniquify.el comint.el data-tests.el dired-aux.el easy-mmode.el eglot.el elisp-mode.el ffap.el flymake.texi keymap.c @@ -5998,7 +6015,7 @@ and co-wrote help-tests.el keymap-tests.el and changed subr.el package.el image-dired.el checkdoc.el efaq.texi cperl-mode.el help.el simple.el progmodes/python.el dired.el files.el bookmark.el browse-url.el gnus.texi keymap.c dired-x.el erc.el image.c - cl-macs.el message.el subr-tests.el and 1948 other files + cl-macs.el message.el subr-tests.el and 1947 other files Stefan Merten: co-wrote rst.el @@ -6015,7 +6032,7 @@ and co-wrote font-lock.el gitmerge.el pcvs.el visual-wrap.el and changed subr.el simple.el cl-macs.el bytecomp.el files.el keyboard.c lisp.h vc.el eval.c xdisp.c alloc.c help-fns.el buffer.c sh-script.el package.el tex-mode.el progmodes/compile.el lread.c keymap.c window.c - easy-mmode.el and 1745 other files + easy-mmode.el and 1744 other files Stefano Facchini: changed gtkutil.c @@ -6042,10 +6059,10 @@ Steinar Bang: changed gnus-setup.el imap.el Stéphane Boucher: changed replace.el Stephane Marks: wrote savehist-tests.el system-sleep.el system-taskbar.el -and changed frame.el frames.texi nsfns.m tab-bar.el bookmark.el frame.c - nsterm.m markdown-ts-mode.el project.el recentf.el savehist.el subr.el - vtable.el w32fns.c display.texi ibuf-macs.el os.texi saveplace.el - shell.el treesit.el vtable-tests.el and 32 other files +and changed frame.el markdown-ts-mode.el frames.texi nsfns.m tab-bar.el + bookmark.el frame.c nsterm.m subr.el project.el display.texi recentf.el + savehist.el vtable.el w32fns.c ibuf-macs.el os.texi saveplace.el + shell.el subr-x.el treesit.el and 34 other files Stephane Zermatten: changed term-tests.el term.el ansi-osc.el @@ -6056,11 +6073,11 @@ Stephen A. Wood: changed fortran.el Stephen Berman: wrote todo-mode-tests.el and co-wrote todo-mode.el visual-wrap.el -and changed dired.el wid-edit.el wdired.el dired-tests.el files.el +and changed dired.el wid-edit.el dired-tests.el wdired.el files.el todo-mode.texi dabbrev-tests.el wdired-tests.el diary-lib.el menu-bar.el minibuffer.el dabbrev.el dired-aux.el doc-view.el info.el outline.el simple.el todo-test-1.todo widget.texi INSTALL_BEGIN - allout.el and 90 other files + allout.el and 89 other files Stephen C. Gilardi: changed configure.ac @@ -6252,7 +6269,7 @@ and changed spam.el gnus.el nnimap.el gnus.texi gnutls.c gnus-sum.el auth.texi cfengine.el gnus-sync.el gnus-util.el gnus-start.el netrc.el gnutls.h message.el spam-stat.el .gitlab-ci.yml encrypt.el mail-source.el nnir.el nnmail.el auth-source-tests.el - and 125 other files + and 124 other files Terje Rosten: changed xfns.c version.el xterm.c xterm.h @@ -6865,8 +6882,9 @@ Xi Lu: changed etags.c htmlfontify.el ruby-mode.el CTAGS.good_crlf CTAGS.good_update Makefile TUTORIAL.cn crlf eww.el filesets.el man-tests.el man.el shortdoc.el tramp-sh.el -Xiyue Deng: changed emacs-lisp-intro.texi strings.texi smtpmail.el - functions.texi package.el package.texi symbols.texi +Xiyue Deng: changed emacs-lisp-intro.texi strings.texi package.el + smtpmail.el functions.texi package-activate.el package-tests.el + package.texi symbols.texi Xuan Wang: changed warnings.el @@ -7008,7 +7026,7 @@ Zhang Weize: wrote ob-plantuml.el Zhehao Lin: changed xfaces.c Zhengyi Fu: changed bookmark.el executable.el progmodes/grep.el - replace.el + project.el replace.el xwidget.el Zhiwei Chen: changed hideif.el @@ -7029,8 +7047,8 @@ and changed fontset.el HELLO language/indian.el quail/indian.el loadup.el BidiBrackets.txt BidiMirroring.txt Blocks.txt IVD_Sequences.txt IdnaMappingTable.txt NormalizationTest.txt PropertyValueAliases.txt ScriptExtensions.txt Scripts.txt SpecialCasing.txt UnicodeData.txt - characters.el confusables.txt copyright.html emoji-data.txt - emoji-sequences.txt and 8 other files + c-ts-mode.el characters.el confusables.txt copyright.html + emoji-data.txt and 10 other files উৎসব রায়: changed quail/indian.el diff --git a/etc/DEBUG b/etc/DEBUG index f078a87ac25..d5a726910b7 100644 --- a/etc/DEBUG +++ b/etc/DEBUG @@ -25,8 +25,15 @@ happens only with optimized code, you may need to enable optimizations. If that happens, try using -Og first instead of -O2, as -Og disables some optimizations that make debugging some code exceptionally hard. -Older versions of GCC may need more than just the -g3 flag. For more, -search for "analyze failed assertions" below. +The -g3 option is needed to allow GDB expand macros, which the Emacs C +code uses a lot; without it, you will need to look up the macro +definitions in the C headers and source files, and expand them by hand, +before using them in expressions you want GDB to evaluate. Older +versions of GCC may need more than just the -g3 flag. Also, Emacs +compiled with -g3 reportedly causes GDB to crash on OpenBSD, so on that +OS you should instead use either -ggdb or just -g (and the macro +information will be unavailable to GDB, unfortunately). For more about +-g3, search for "analyze failed assertions" below. The 2 --enable-* switches are optional. They don't have any effect on debugging with GDB, but will compile additional code that might catch diff --git a/etc/EGLOT-NEWS b/etc/EGLOT-NEWS index cdbd3048f27..ad6aae10436 100644 --- a/etc/EGLOT-NEWS +++ b/etc/EGLOT-NEWS @@ -18,7 +18,7 @@ to look up issue github#1234, go to https://github.com/joaotavora/eglot/issues/1234. -* Changes to upcoming Eglot +* Changes in Eglot 1.24 (23/6/2026) ** New command 'M-x eglot-describe-connection' diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index d28c0670a73..bc9669e7b59 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -14,6 +14,33 @@ GNU Emacs since Emacs version 22.1. * Changes in ERC 5.7 +** A flexible 'match' API. +To the frustration many, ERC has long lacked of a flexible API for +reacting to a message's contents and envelope info, like its sender and +associated IRC command. While the long-term plan is to transition to an +object-based formatting model that should offer more useful access to +the various parts of a message before they're assembled, it's become +obvious that users need something practical in the interim. This +'match' API is based on a simple hook-like handler system that offers +more opportunities for things like filtering and styling. See Info node +'Match API' to find out more. + +** Exercise more control in skipping certain desktop notifications. +Skip select notifications that ERC would otherwise emit with new hook +option 'erc-desktop-notifications-skip-predicates'. Its default members +skip messages from "fools" and those in untracked buffers. + +** Opt out of desktop notifications from the active buffer. +Option 'erc-desktop-notifications-ignored-when-focused' can spare users +from being notified when interacting with the initiating buffer. + +** Apply options granularly to specific connections or buffers. +Based on an idea drafted nearly a quarter century ago by ERC's earliest +contributors, the 'settings' module offers a ready-made method for +binding arbitrary user options to various "scopes" of interest. It +leverages buffer-local variables and match conditions reminiscent of +'buffer-match-p'. + ** Changes in the library API. *** Module setup runs in query buffers on reconnect. @@ -31,6 +58,20 @@ were simply reversed as given. Now, just like with global modules, ERC preserves the preferred order when activating local modules for new sessions. +*** Major-mode setup runs before global-module setup in 'erc-open'. +The "enable" body of a global module's minor-mode command will now see +'erc-mode' as the 'major-mode'. Although ERC still delays its +major-mode hook until after it has initialized its main session +variables, a module can also now set any of its own variables that don't +depend on such initialization immediately and without fear of their +being killed. For modules still needing to run delayed, session-aware +code, a new convenience macro called 'erc-with-initialized-session' is +now available to automate any 'erc-mode-hook' wrangling for you. + +*** A predicate to detect if the current buffer is a channel. +New function 'erc-channel-buffer-p' is a channel-detecting complement to +'erc-query-buffer-p' and a light wrapper around 'erc-channel-p'. + * Changes in ERC 5.6.2 diff --git a/etc/NEWS b/etc/NEWS index 1b5bd471cb8..92033851c74 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -49,6 +49,46 @@ behavior. If this variable is nil, 'tty-cursor-movement-use-TAB-BS' has no effect, and Emacs will never use TABs for any cursor-movement sequences. +--- +** File- and directory-local variables respect user option setters. +Values of variables that are user options mentioned in file-local +variable sections and directory-locals via ".dir-locals.el" are now +set similarly to 'setopt-local'; i.e., if a user option has a defcustom +':set' function, that function will be invoked. + +--- +** New user option 'setopt-local-type-mismatch'. +This option controls what 'setopt-local' does when it detects a type +mismatch between the specified value and the ':type' specification of a +user option. Its backward-compatible default is nil which emits a +warning and accepts the type-mismatched value. You can control this by +customizing 'setopt-local-type-mismatch' to a non-nil value: the value +'accept' inhibits the warning and silently accepts type-mismatched +values; the value 'discard' inhibits the warning and discards +type-mismatched values; any other non-nil value prompts you whether to +accept or ignore the value. + +--- +** Specifying a minor mode as a local variable enables that mode. +The previous behavior, toggling the mode, was neither reliable nor +generally desirable. + ++++ +** Emacs tries to display the overlay arrow in the left margin. +On a non-graphical display (or when the left fringe is not shown), if a +left margin is present, Emacs will now display the overlay arrow into +this margin. Edebug is now using this feature by explicitly setting up +a left margin for it. + +** Mode Line + +*** Popup menus invoked from mode line select another window. +Clicking mode line elements in inactive windows now first +selects another window before displaying the menu, so the +commands invoked from the menu will operate on the right buffer. +You can restore the previous behavior by removing +'mode-line-window-select' from 'x-pre-popup-menu-hook'. + * Editing Changes in Emacs 32.1 @@ -70,6 +110,105 @@ check out the repository to prepare a patch for the package maintainer. --- *** Messages from Ansible are now recognized. +** Man + +--- +*** OSC 8 hyperlinks in man pages are now buttonized. +When a man page contains OSC 8 hyperlink escape sequences, they +are now buttonized, allowing using mouse or 'RET' to follow them. + +** Woman + +--- +*** The variable 'woman-topic-history' is now obsolete. +Use 'Man-topic-history' instead. + +** VC + ++++ + +*** VC Directory outgoing revisions count is now asynchronous. +This means it won't get in your way even if it's slow for your +repository. As such, the 'vc-dir-show-outgoing-count' option is now +obsolete. + +--- +*** VC Directory now shows key binding hints. +To hide these, you can customize the new user option +'vc-dir-show-key-binding-hints' to nil. +Backends can supply additional hints using the new 'dir-extra-hints' +backend method. + +--- +*** VC Directory doesn't process very large status output by default. +If the VCS status process used to populate the VC Directory buffer +produces a very large amount of output, it often means that you did +something accidental like renaming a subdirectory containing thousands +of files, and Emacs can become unresponsive while trying to process all +the output. Now Emacs stops early. When this happens, VC Directory +includes a message saying so, with a button to override it. You can +customize the new user option 'vc-dir-process-output-limit' to control +how early to stop, and to disable this feature. + +--- +*** VC-Dir resolves symbolic links only if the directory has no backend. +When called interactively, 'M-x vc-dir' checks if the passed directory +has a VC backend. If it doesn't, but the directory's truename does +have a backend, and 'vc-follow-symlinks' is non-nil, the truename is +used instead. Previously, the truename was used unconditionally. + ++++ +*** Improved creation of commit log entry from ChangeLog. +When VC detects that all log entries for the current changeset come from +the same ChangeLog file or buffer, it now inserts the entire body of the +ChangeLog entry into the "*vc-log*" buffer. If the ChangeLog entry +contains a summary line, VC inserts it into the "*vc-log*" Summary header. +If VC detects that the set of changed files listed in the ChangeLog +entry differs from the current VC fileset, it displays a warning. + +** Outline mode + +*** New command 'outline-show-entry-and-parents'. +It is bound to 'C-e' and reveals the current entry +with its parent hierarchy. + +--- +*** New function 'outline-search-from-regexp'. +A generic 'outline-search-function' implementation driven by +'outline-regexp', suitable for modes or minor modes that customize +'outline-regexp' but do not need a custom search strategy. +Install it with: + + (setq-local outline-search-function #'outline-search-from-regexp) + +--- +*** 'outline-search-function' is now a user option. +Previously a plain variable, it is now a 'defcustom' +with named choices for the predefined search functions +('outline-search-from-regexp' and 'outline-search-level') +as well as the default nil and arbitrary user functions. + +** Newsticker + +--- +*** New command to copy the URL of the selected newsticker item. +The new command 'newsticker-treeview-copy-url', bound to 'w', adds the +URL of the currently selected item in the list view to the kill ring. + +** Rmail + ++++ +*** Files named "RMAIL" or ending in ".rmail" are now visited in Rmail mode. +You can now visit such files in Rmail mode using ordinary file-visiting +commands, such as 'C-x C-f'. + +** Timeclock + +--- +*** New user option 'timeclock-use-24hr-format'. +If this option is set to non-nil, displayed times (clocked in/out +since, time to leave) will use 24-hour clock instead of 12-hour clock. + * New Modes and Packages in Emacs 32.1 @@ -87,9 +226,42 @@ To install the grammars, use 'M-x markdown-ts-mode-install-parsers'. * Incompatible Lisp Changes in Emacs 32.1 +** Pcase + ++++ +*** Add 'pcase-let*-strict'. +This macro is like 'pcase-let*', but signals an error if a 'pcase' +pattern does not match its corresponding value. This can be useful for +destructuring values when you do not wish to continue if the +corresponding value is not as expected. + ++++ +** The transition variable 'current-time-list' now defaults to nil. +Therefore, timestamps now default to '(TICKS . HZ)' form instead of the +older '(HIGH LOW USEC PSEC)' form. + * Lisp Changes in Emacs 32.1 ++++ +** 'ignore' is now also a place, acting as a "blackhole" like "/dev/null". +E.g., '(push (new-elem) (pcase (foo) (0 var1) (1 var2) (_ (ignore))))'. + ++++ +** 'kill-all-local-variables' can kill locals silently and reset the buffer. +This function's KILL-PERMANENT argument now accepts the value +'permanent-local', which kills all locals ignoring any variable +watchers. That argument can also be 'reset', which does what +'permanent-local' does, and also resets the buffer as if it were newly +created. Use these with caution to avoid unexpected behavior such as +'default-directory' being reset to nil. + +--- +** 'with-work-buffer' kills all locals silently and resets its buffers. +When this macro returns a buffer to its buffer pool, it now kills all +buffer locals silently, ignoring any variable watchers, and resets the +buffer as if it were newly created. + +++ ** The new function 'markers-in' returns the set of markers in a region. @@ -108,9 +280,33 @@ The HANDLER argument of 'dbus-call-method-asynchronously' can be a cons cell '(HANDLER . ERROR-HANDLER)'. ERROR-HANDLER is invoked if the method call returns with a D-Bus error; the error is passed as argument. +** Elisp Scope + +*** Custom analyzers can be associated with multiple functions. +Elisp Scope macros that define custom analyzer functions, such as +'elisp-scope-define-function-analyzer' and +'elisp-scope-define-macro-analyzer', can now take a list of symbols to +which the defined analyzer should apply (or a single symbol, as before). +This makes it easy to specify the same analyzer for multiple functions. + +*** New macro 'elisp-scope-define-function-spec'. +This macro in a declarative alternative to +'elisp-scope-define-function-analyzer'. It lets you tell Elisp Scope +how to analyze the arguments of a function by declaring the +specification of each argument, rather than implementing an analyzer +function as you would with 'elisp-scope-define-function-analyzer'. + * Changes in Emacs 32.1 on Non-Free Operating Systems ++++ +*** Emacs has been updated to target Android 17. +Emacs has been updated to require the SDK for Android 17 (API level 37) +during compilation, and to target that version of the operating system. +A corollary of this change is that on Android 17 and later systems, it +must be granted permission to access nearby devices from Settings in +order to establish network connections to hosts on local networks. + ---------------------------------------------------------------------- This file is part of GNU Emacs. diff --git a/etc/NEWS.31 b/etc/NEWS.31 index 0aaeb547f06..1270b95e622 100644 --- a/etc/NEWS.31 +++ b/etc/NEWS.31 @@ -29,6 +29,9 @@ applies, and please also update docstrings as needed. The traditional unexec dumper, deprecated since Emacs 27, has been removed. ++++ +*** The portable dumper now works on m68k a.out targets. + --- ** Emacs's old 'ctags' program is no longer built or installed. You are encouraged to use Universal Ctags <https://ctags.io/> instead. @@ -51,6 +54,7 @@ systemd is installed; default is '${prefix}/usr/lib/systemd/user'. * Startup Changes in Emacs 31.1 ++++ ** In compatible terminals, 'xterm-mouse-mode' is turned on by default. For these terminals the mouse will work by default. A compatible terminal is one that supports Emacs setting and getting the OS selection @@ -113,9 +117,9 @@ Previously, such characters would be rendered as, e.g., white boxes. that are used for borders around child frames and menu separators on TTY frames. -Call the function 'standard-display-unicode-special-glyphs' to set up +Call the command 'standard-display-unicode-special-glyphs' to set up the 'standard-display-table's extra slots with Unicode characters. -Please see the documentation of that function to see which slots of the +Please see the documentation of that command to see which slots of the display table it changes. +++ @@ -208,20 +212,20 @@ you type if the completion property 'eager-update', set by the completion table, is non-nil. This property can be overridden for different completion categories by customizing 'completion-category-overrides'. Alternatively, the new user option -'completion-eager-update can be set to t to make "*Completions*" always +'completion-eager-update' can be set to t to make "*Completions*" always be updated as you type, or nil to suppress this always. Note that for large or inefficient completion tables this can slow down typing. +++ *** New optional value of 'minibuffer-visible-completions'. -If the value of this option is 'up-down', only the '<up>' and '<down>' +If the value of this option is 'up-down', only the '<UP>' and '<DOWN>' arrow keys move point between candidates shown in the "*Completions*" -buffer display, while '<right>' and '<left>' arrows move point in the +buffer display, while '<RIGHT>' and '<LEFT>' arrows move point in the minibuffer window. --- -*** 'RET' chooses the completion selected with 'M-<up>/M-<down>'. -If a completion candidate is selected with 'M-<up>' or 'M-<down>', +*** 'RET' chooses the completion selected with 'M-<UP>/M-<DOWN>'. +If a completion candidate is selected with 'M-<UP>' or 'M-<DOWN>', hitting 'RET' will exit completion with that as the result. This works both in minibuffer completion and in-buffer completion. This supersedes 'minibuffer-completion-auto-choose', which previously provided similar @@ -250,18 +254,18 @@ and 'completion-category-defaults'. +++ *** Navigating "*Completions*" now accommodates 'completions-format'. When 'completions-format' is set to 'vertical', typing 'n', 'TAB' or -'M-<down>' in the "*Completions*" buffer (the latter also in the +'M-<DOWN>' in the "*Completions*" buffer (the latter also in the minibuffer) now moves point to the completion candidate in the next line in the current column, and wraps to the next column when typed on the last completion candidate of the current column. Likewise, typing 'p', -'S-TAB' or 'M-<up>' moves point to the completion candidate in the +'S-TAB' or 'M-<UP>' moves point to the completion candidate in the previous line or wraps to the previous column. Previously, these keys ignored the vertical format, i.e., moved point only to the item in the same line of the next or previous column, in accordance with the default -horizontal format. In vertical format, typing '<left>' and '<right>' in +horizontal format. In vertical format, typing '<LEFT>' and '<RIGHT>' in the "*Completions*" buffer (and when 'minibuffer-visible-completions' is non-nil, also in the minibuffer) moves point only within the current -line, analogously to how, in horizontal format, '<down>' and '<up>' move +line, analogously to how, in horizontal format, '<DOWN>' and '<UP>' move point only within the current column. --- @@ -319,10 +323,12 @@ is still waiting for input. It still can use 'read-key' when the variable 'read-char-choice-use-read-key' is non-nil. ++++ *** 'map-y-or-n-p' now uses the minibuffer to read a character. It still can use 'read-key' when the variable 'y-or-n-p-use-read-key' is non-nil. +--- *** 'flex' completion style rewritten to be faster and more accurate. Completion and highlighting use a new superior algorithm. For example, pattern "scope" now ranks 'elisp-scope-*' functions well above @@ -331,6 +337,7 @@ pattern "scope" now ranks 'elisp-scope-*' functions well above ** Mouse ++++ *** New mode 'mouse-shift-adjust-mode' extends selection with 'S-<mouse-1>'. When enabled, you can use the left mouse button with the '<Shift>' modifier to extend the boundaries of the active region by dragging the mouse pointer. @@ -353,14 +360,24 @@ increments as with Emacs 24 through Emacs 30 you now have to set ** Windows +++ -*** New commands to modify window layouts. - -- 'C-x w t' and 'C-x w r <left>/<right>' rotate the window layout. -- 'C-x w o <left>/<right>' rotate the windows within the current layout. -- 'C-x w f <left>/<right>/<up>/<down>' flip window layouts. +*** New commands to modify window layouts of frames. +'window-layout-rotate-clockwise' ('C-x w r <RIGHT>') and its counterpart +'window-layout-rotate-anticlockwise' ('C-x w r <LEFT>') rotate an entire +window layout. +'window-layout-flip-topdown' ('C-x w f <DOWN>', 'C-x w f <UP>') and +'window-layout-flip-leftright' ('C-x w f <LEFT>', 'C-x w f <RIGHT>') +flip the window layout vertically and horizontally. +'window-layout-transpose' ('C-x w t') reorganizes windows such that +every horizontal split becomes a vertical split and vice versa. +'rotate-windows' ('C-x w o <RIGHT>') and its counterpart +'rotate-windows-back' ('C-x w o <LEFT>') rotate windows in cyclic +ordering. -By default, these commands operate on the selected frame's root window. -With a prefix argument, they operate on the selected window's parent. +*** New user option 'rotate-windows-change-selected'. +This controls whether 'rotate-windows' and 'rotate-windows-back' change +the selected window. If nil, the selected window does not change. +The default is t, which means the new selected window will be the one +that winds up at the location of the previously-selected window. +++ *** Windmove commands now move to skipped windows if invoked twice in a row. @@ -404,10 +421,10 @@ further destiny of any window showing the buffer to be killed. +++ *** 'split-window' can optionally resurrect deleted windows. -A new argument REFER of 'split-window' makes it possible to, instead of -making a new window object, reuse an existing, deleted one. This can be -used to preserve the identity of windows when swapping or transposing -them. +A new optional argument REFER of 'split-window' makes it possible to, +instead of making a new window object, reuse an existing, deleted one. +This can be used to preserve the identity of windows when swapping or +transposing them. +++ *** New window parameter 'quit-restore-prev'. @@ -450,11 +467,11 @@ option to 'vertical'. The value 'horizontal' always prefers the horizontal split. --- -The default value of 'split-width-threshold' is changed from 160 to 150. +*** The default value of 'split-width-threshold' is changed from 160 to 150. After splitting it is still comfortable to read text filled to 75 columns. +++ -*** New argument INDIRECT for 'get-buffer-window-list'. +*** New optional argument INDIRECT for 'get-buffer-window-list'. With this argument non-nil, 'get-buffer-window-list' will include in the return value windows whose buffers share their text with BUFFER-OR-NAME. @@ -474,6 +491,7 @@ helps to restore window buffers across Emacs sessions. You can use this in 'display-buffer-alist' to match buffers displayed during the execution of particular commands. +--- *** New command 'other-window-backward' ('C-x O'). This moves in the opposite direction of 'other-window' and is for its default keybinding consistent with 'repeat-mode'. @@ -514,11 +532,11 @@ same terminal as the selected frame. Child frames can be excluded. A single frame can be excluded, for example, the selected frame. 'get-mru-frame' returns the single most recently used frame. ---- ++++ *** After deleting, 'delete-frame' now selects the most recently used frame. Previously, after deleting a specified frame, 'delete-frame' would select the oldest visible frame on the same terminal. To revert to the -old behavior, set the new variable 'after-delete-frame-select-mru-frame' +old behavior, set the new user option 'delete-frame-choose-selected' to nil. +++ @@ -537,6 +555,7 @@ either resize the frame and change the fullscreen status accordingly or keep the frame size unchanged. The value t means to first reset the fullscreen status and then resize the frame. ++++ *** New functions to set frame size and position in one compound step. 'set-frame-size-and-position' sets the new size and position of a frame in one compound step. Both, size and position, can be specified as with @@ -544,6 +563,7 @@ the corresponding frame parameters 'width', 'height', 'left' and 'top'. 'set-frame-size-and-position-pixelwise' is similar but has a more restricted set of values for specifying size and position. ++++ *** New commands 'split-frame' and 'merge-frames'. 'split-frame' moves a specified number of windows from an existing frame to a newly-created frame. 'merge-frames' merges all windows from two @@ -566,6 +586,7 @@ These are useful if you need to detect a cloned frame or undeleted frame in hooks like 'after-make-frame-functions' and 'server-after-make-frame-hook'. ++++ *** Frames now have unique ids and the new function 'frame-id'. Each non-tooltip frame is assigned a unique integer id. This allows you to unambiguously identify frames even if they share the same name or @@ -573,6 +594,7 @@ title. When 'undelete-frame-mode' is enabled, each deleted frame's id is stored for resurrection. The function 'frame-id' returns a frame's id (in C, use the frame struct member 'id'). ++++ *** New commands 'select-frame-by-id', 'undelete-frame-by-id'. The command 'select-frame-by-id' selects a frame by ID and undeletes it if deleted. The command 'undelete-frame-by-id' undeletes a frame by its @@ -581,7 +603,7 @@ ID. When called interactively, both functions prompt for an ID. ** Mode Line --- -*** New definitions for mode-line faces under dark background mode. +*** New definitions for mode line faces under dark background mode. The faces 'mode-line' and 'mode-line-highlight' now have separate definitions for the dark background mode. Previously, these two faces looked the same in both the light and dark background modes. To get the @@ -595,6 +617,7 @@ single button. The value could also be a list to specify minor mode lighters to hide or show. The default value is nil, which retains the previous behavior of showing all minor mode lighters. +--- *** New user option 'mode-line-modes-delimiters'. This option allows changing or removing the delimiters shown around the major mode and list of minor modes in the mode line. The default @@ -607,6 +630,13 @@ The command 'mode-line-invisible-mode' toggles the visibility of the current-buffer's mode line. The default is to show the mode line of every buffer. +--- +*** Standard mode line no longer specifies minimum widths. +The default values for the 'mode-line-position' variable and +'mode-line-format' user option no longer specify any minimum widths. If +you use a proportional font for your mode line, you may need to +customize the values of these variables to include minimum widths again. + ** Tab Bars and Tab Lines --- @@ -662,13 +692,13 @@ wrapping and resizing the tab bar to more than one line. --- *** New user option 'tab-line-define-keys'. When t, the default, it redefines window buffer switching keys -such as 'C-x <left>' and 'C-x <right>' to tab-line specific variants +such as 'C-x <LEFT>' and 'C-x <RIGHT>' to tab-line specific variants for switching tabs. --- -*** New command 'tab-line-move-tab-forward' ('C-x M-<right>'). +*** New command 'tab-line-move-tab-forward' ('C-x M-<RIGHT>'). Together with the new command 'tab-line-move-tab-backward' -('C-x M-<left>'), it can be used to move the current tab +('C-x M-<LEFT>'), it can be used to move the current tab on the tab line to a different position. --- @@ -702,9 +732,10 @@ on the tab lines are now these two: the selected window uses +++ *** New keybinding 'C-h u' for 'apropos-user-option'. +--- ** IDLWAVE has been moved to GNU ELPA. The version bundled with Emacs is out-of-date, and is now marked as -obsolete. Use 'M-x list-packages' to install the 'idlwave' package from +obsolete. Use 'list-packages' to install the 'idlwave' package from GNU ELPA instead. +++ @@ -713,8 +744,10 @@ These inherit from the 'header-line' face, but the faces actually used on the header lines are now these two: the selected window uses 'header-line-active', non-selected windows use 'header-line-inactive'. +--- ** In 'customize-face', the "Font family" attribute now supports completion. ++++ ** 'process-adaptive-read-buffering' is now nil by default. Setting this variable to a non-nil value reduces performance and leads to wrong results in some cases. We believe that it is no longer useful; @@ -746,6 +779,7 @@ setting is an alternative to 'help-at-pt-display-when-idle'. Customize this to nil to disable starting new asynchronous native compilations while AC power is not connected. ++++ ** New user option 'show-paren-not-in-comments-or-strings'. If this option is non-nil, it tells 'show-paren-mode' not to highlight the parens that are inside comments and strings. If set to 'all', @@ -760,6 +794,7 @@ If this option is non-nil, the lossage buffer in 'view-lossage' will be refreshed automatically for each new input keystroke and command performed. +--- ** Change in SVG foreground color handling. SVG images no longer have the 'fill' attribute set to the value of ':foreground' or the current text foreground color. The 'currentcolor' @@ -813,6 +848,7 @@ mode in most cases in which Emacs would by default enter that mode. This can make things work better for some cases of X forwarding; see the docstring for the new option. ++++ ** Emacs now comes with Org v9.8. See the file "etc/ORG-NEWS" for user-visible changes in Org. @@ -821,17 +857,19 @@ See the file "etc/ORG-NEWS" for user-visible changes in Org. compile.el will now use paths specified in both 'compilation-search-extra-path' and 'compilation-search-path', when doing search. 'compilation-search-extra-path' is consulted first. -One possible use case of this option is to customize add new search -paths on a per-project basis with directory-local variables. +One possible use case of this option is to add new search paths on a +per-project basis with directory-local variables. * Editing Changes in Emacs 31.1 ++++ ** Commands for keyboard translation. 'key-translate' is now interactive. It prompts for a key to translate from, and another to translate to, and sets 'keyboard-translate-table'. The new command 'key-translate-remove' prompts for a key/translation -pair with 'completing-read', and removes it from the translation table. +pair, with 'completing-read', and removes the translation from the +translation table. ** Internationalization @@ -926,13 +964,15 @@ Typing 'M-~' while saving some buffers means not to save the buffer and also to mark it as unmodified. This is an alternative way to mark a buffer as unmodified which doesn't require switching to that buffer. ++++ ** New minor mode 'delete-selection-local-mode'. This mode sets 'delete-selection-mode' buffer-locally. This can be useful for enabling or disabling the features of 'delete-selection-mode' based on the state of the buffer, such as for the different states of modal editing packages. -** New user variable 'exchange-point-and-mark-highlight-region'. +--- +** New user option 'exchange-point-and-mark-highlight-region'. When set to nil, this modifies 'exchange-point-and-mark' so that it doesn't activate the mark if it is not already active. The default value is t, which retains the old behavior. @@ -977,6 +1017,7 @@ These commands did not previously accept a prefix argument. Now a numeric prefix argument specifies a repeat count, just like it already did for 'undo'. +--- ** New minor mode 'center-line-mode'. This mode keeps modified lines centered horizontally according to the value of 'fill-column', by calling 'center-line' on each non-empty line @@ -1063,12 +1104,13 @@ buffer named "*name-of-project-shell<2>*". By comparison, a plain universal argument as in 'C-u C-x p s' always creates a new session. --- -*** 'project-switch-buffer' re-uniquifies buffer names while prompting. -When 'uniquify-buffer-name-style' is non-nil, 'project-switch-buffer' +*** 'project-switch-to-buffer' re-uniquifies buffer names while prompting. +When 'uniquify-buffer-name-style' is non-nil, 'project-switch-to-buffer' changes the buffer names to only make them unique within the given project, during completion. That makes some items shorter. -*** 'project-switch-buffer' uses 'project-buffer' as completion category. +--- +*** 'project-switch-to-buffer' uses 'project-buffer' as completion category. The category defaults are the same as for 'buffer' but any user customizations would need to be re-added. @@ -1078,16 +1120,19 @@ If the value of 'project-mode-line' is 'non-remote', project name and the Project menu will be shown on the mode line only for projects with local files. +--- *** The "VC-aware" project backend caches the current project and its name. The duration for which the values are cached depends on whether it is -called from 'non-essential' context, and it determined by variables +called from 'non-essential' context, and it is determined by variables 'project-vc-cache-timeout' and 'project-vc-non-essential-cache-timeout'. ** Network Security Manager (NSM) +--- *** NSM warns about TLS 1.1 by default. It has been deprecated by RFC 8996, published in 2021. +--- *** NSM warns about DHE and RSA key exchange by default. Emacs now warns about ephemeral Diffie-Hellman key exchange, and static RSA key exchange, also when 'network-security-level' is customized to @@ -1106,6 +1151,7 @@ tables for files in which no tags were found. ** Delete Selection mode +--- *** New face 'delete-selection-replacement' for the replacement text. This comes with a change to how we track what is considered "the replacement text", which should be more robust now, and is made @@ -1122,11 +1168,11 @@ to call 'editorconfig-apply'. +++ *** Non-existing or empty files are ignored in 'auth-sources'. -File-based data stores are ignored in ‘auth-sources’, if the underlying +File-based data stores are ignored in 'auth-sources', if the underlying data file does not exist. This is relevant, if a new secret is stored -in such a file; the first usable entry of ‘auth-sources’ is selected as +in such a file; the first usable entry of 'auth-sources' is selected as target. If you want also not existing files to be selected, set the -user option ‘auth-source-ignore-non-existing-file’ to nil. +user option 'auth-source-ignore-non-existing-file' to nil. --- *** 'auth-sources' set to nil means using the password cache only. @@ -1143,7 +1189,7 @@ with finer grained control. ** Register +++ -*** New functions 'buffer-to-register' and 'file-to-register'. +*** New commands 'buffer-to-register' and 'file-to-register'. These allow users to interactively store files and buffers in registers. Killed buffers stored in a register using 'buffer-to-register' are automatically converted to a file-query value if the buffer was visiting @@ -1168,20 +1214,25 @@ Depending on customization, it modifies the variable 'treesit-major-mode-remap-alist' prepared by tree-sitter based mode packages. +--- *** New user option 'treesit-auto-install-grammar'. It controls the automatic installation of tree-sitter grammar libraries needed for tree-sitter based modes, if these grammar libraries are not available when such modes are turned on. +--- *** 'treesit-extra-load-path' now is a customizable user option. The first directory in the list is used as the default directory to install the language grammar when 'treesit-auto-install-grammar' is 'ask', 'ask-dir' or 'always'. +--- *** 'treesit-language-source-alist' supports keywords. -The language and URL are mandatory, but remaining data can use keywords: -'(json "https://github.com/tree-sitter/tree-sitter-json" :commit "4d770d3")'. +The language and URL are mandatory, but remaining data can use keywords like + + (json "https://github.com/tree-sitter/tree-sitter-json" :commit "4d770d3") +--- *** The file treesit-x.el defines a number of simple tree-sitter modes. Using the new macro 'define-treesit-generic-mode', generic modes are defined including, but not limited to, 'gitattributes-generic-ts-mode'. @@ -1189,19 +1240,20 @@ Visiting a file in such mode asks for confirmation before installing its tree-sitter grammar. Then it highlights the visited file according to the syntax defined by the grammar. +--- *** New command 'treesit-cycle-sexp-thing'. It cycles the type of navigation for commands that move across sexp's and lists, such as 'treesit-forward-sexp', 'treesit-forward-list', 'treesit-down-list', and 'treesit-up-list'. The type can be either 'list', the default, or 'sexp'. -With the default 'list' type these commands move using syntax tables for +With the default 'list' type, these commands move using syntax tables for symbols and using the thing 'list' for lists. -With the 'sexp' type these commands move across nodes defined by +With the 'sexp' type, these commands move across nodes defined by the tree-sitter thing 'sexp' in 'treesit-thing-settings'. +++ *** Indirect buffers can have their own parser list. -Before, indirect buffers share their base buffer’s parser list and +Before, indirect buffers share their base buffer's parser list and parsers. Now they can have their own parser list. +++ @@ -1222,13 +1274,15 @@ override flag by 'treesit-font-lock-setting-query', 'treesit-font-lock-setting-feature', 'treesit-font-lock-setting-enable', and 'treesit-font-lock-setting-override'. +--- *** New tree-sitter thing 'list'. Unlike the existing thing 'sexp' that defines both lists and atoms, 'list' defines only lists to be navigated by 'forward-sexp'. -The new function 'treesit-forward-sexp-list' uses 'list' +The new command 'treesit-forward-sexp-list' uses 'list' to move across lists. But to move across atoms inside the list it uses 'forward-sexp-default-function'. +--- *** New tree-sitter based functions for moving by lists. If a major mode defines 'list' in 'treesit-thing-settings', tree-sitter setup for these modes sets 'forward-list-function' to @@ -1237,15 +1291,18 @@ tree-sitter setup for these modes sets 'forward-list-function' to 'forward-list', 'up-list', and 'down-list' motion commands for those modes. +--- *** Tree-sitter enabled modes now properly support 'show-paren-mode'. They do that by letting 'show-paren-mode' use the results of parsing by the tree-sitter library. The new function 'treesit-show-paren-data' is used to communicate the tree-sitter parsing results to 'show-paren-mode'. +--- *** Tree-sitter enabled modes now properly support 'hs-minor-mode'. All commands from hideshow.el can selectively display blocks defined by the new tree-sitter thing 'list'. +--- *** New tree-sitter thing 'comment'. The new variable 'forward-comment-function' is set to the new function 'treesit-forward-comment' if a major mode defines the thing 'comment'. @@ -1265,12 +1322,14 @@ language symbol. For example, 'cpp' is translated to "C++". A new variable 'treesit-language-display-name-alist' holds the translations of language symbols where that translation is not trivial. +--- *** New function 'treesit-merge-font-lock-feature-list'. This function merges two tree-sitter font-lock feature lists. It returns a new font-lock feature list with no duplicates in the same level. It can be used to merge font-lock feature lists in a multi-language major mode. +--- *** New function 'treesit-replace-font-lock-feature-settings'. Given two tree-sitter font-lock settings, it replaces the feature in the second font-lock settings with the same feature in the first font-lock @@ -1278,6 +1337,7 @@ settings. In a multi-language major mode it is sometimes necessary to replace features from one of the major modes with others, that are better suited to the new multilingual context. +--- *** New function 'treesit-simple-indent-modify-rules'. Given two tree-sitter indent rules, it replaces, adds, or prepends rules in the old rules with new ones, then returns the modified rules. In a @@ -1293,10 +1353,12 @@ This variable allows major modes to setup Imenu for multiple languages. This variable allows major modes to setup 'outline-minor-mode' for multiple languages. +--- *** New function 'treesit-simple-indent-add-rules'. This new function makes it easier to customize indent rules for tree-sitter modes. +--- *** New variable 'treesit-simple-indent-override-rules'. Users can customize this variable to add simple custom indentation rules for tree-sitter major modes. @@ -1365,7 +1427,7 @@ newer tree-sitter libraries mandate query predicates to end with a question mark. Emacs will transparently convert ':equal', ':match', and ':pred' to ':eq?', ':match?', and ':pred?', respectively, so existing queries still work fine with the latest tree-sitter library. The -predicate ':equal' is changed to ':eq?' to better follow tree-sitter’s +predicate ':equal' is changed to ':eq?' to better follow tree-sitter's convention. Also, the ':match?' predicate can now take the regexp as either the first or second argument, so it works with both tree-sitter convention (regexp arg second) and Emacs convention (regexp arg first). @@ -1389,7 +1451,7 @@ This command hides or shows all the blocks in the current buffer. --- *** 'hs-hide-level' no longer hides all the blocks in the current buffer. -If 'hs-hide-level' was not inside a code block it would hide all the +If 'hs-hide-level' was not inside a code block, it would hide all the blocks in the buffer like 'hs-hide-all'. Now it should only hide all the second level blocks. @@ -1404,6 +1466,7 @@ This user option determines if Hideshow should display indicators to show and toggle the block hiding. If non-nil, the indicators are enabled. By default this is disabled. ++++ *** New user option 'hs-indicator-maximum-buffer-size'. This user option limits the display of Hideshow indicators to buffers that are not too large. By default, buffers larger than 2MB have the @@ -1468,6 +1531,7 @@ available. ** Csharp-ts mode +--- *** Renamed feature in 'treesit-font-lock-feature-list'. The feature 'property' has been renamed to 'attribute', since this is what it is called in the general C# community. @@ -1511,12 +1575,13 @@ blocks are syntax-highlighted if the Doxygen grammar library is available. --- -*** New user option 'java-ts-mode-method-chaining-indent-offset'. +*** New user option 'java-ts-method-chaining-indent-offset'. Now method chaining is indented by 8 spaces rather than 4, and this option controls how much is indented for method chaining. ** JSON-ts mode +--- *** New command 'json-ts-jq-path-at-point'. This command copies the path of the JSON element at point to the kill-ring, formatted for use with the 'jq' utility. @@ -1526,7 +1591,7 @@ kill-ring, formatted for use with the 'jq' utility. --- *** 'php-ts-mode' now depends on 'mhtml-ts-mode'. The direct dependency on 'js-ts-mode', 'css-ts-mode' and 'html-ts-mode' -has now been replaced by ‘mhtml-ts-mode’. Navigation, Outline and Imenu +has now been replaced by 'mhtml-ts-mode'. Navigation, Outline and Imenu work for all languages, and code maintenance is easier. --- @@ -1588,15 +1653,6 @@ at run-time for the use of the associated deprecated features. '(setq eieio-backward-compatibility t)' can be used to recover the previous silence. -** Emacs Lisp mode - -+++ -*** Semantic highlighting support for Emacs Lisp. -'emacs-lisp-mode' can now use code analysis to highlight more symbols -more accurately. Customize the new user option -'elisp-fontify-semantically' to non-nil to enable this feature, and see -the Info node "(emacs) Semantic Font Lock" for more information. - ** Text mode --- @@ -1611,11 +1667,10 @@ converted to '1', etc. Companion commands 'halfwidth-region' and ** Texinfo mode --- -*** texinfo-mode now can auto-close the ``'' pairs. +*** Texinfo mode now can auto-close the ``'' pairs. Now inserting `` in 'texinfo-mode' will close it by inserting its respective '', if 'electric-pair-mode' is enabled. - ** ASM mode --- @@ -1647,7 +1702,7 @@ content. --- *** New Ibuffer-dedicated faces. New faces 'ibuffer-marked', 'ibuffer-deletion', 'ibuffer-title', and -'ibuffer-filter-group-name'. By default they inherit from the +'ibuffer-filter-group-name'. By default, they inherit from the general-purpose faces Ibuffer previously used, to preserve previous behavior. @@ -1682,6 +1737,7 @@ default is nil, which retains the old format. ** Term +--- *** The terminal emulator now supports auto-margins control. Term mode now handles DECAWM escape sequences that control whether text automatically wraps at the right margin: @@ -1689,26 +1745,30 @@ automatically wraps at the right margin: - \e[?7h enables auto-margins (default) - \e[?7l disables auto-margins -When auto-margins is disabled, characters that would go beyond the right margin -are discarded, which matches the behavior of physical terminals and other -terminal emulators. Control sequences and escape sequences are still processed -correctly regardless of margin position. +When auto-margins is disabled, characters that would go beyond the right +margin are discarded, which matches the behavior of physical terminals +and other terminal emulators. Control sequences and escape sequences +are still processed correctly regardless of margin position. --- ** SMerge mode +--- *** New 'repeat-map' for SMerge conflict resolution commands. With 'repeat-mode' enabled, after invoking an SMerge command (for example, 'C-c ^ n'), you can repeat further SMerge commands by typing just the final key (for example, 'n', 'p', 'u', 'l'). +--- *** New command 'smerge-extend' extends a conflict over surrounding lines. +--- *** New command 'smerge-refine-exchange-point' to jump to the other side. When used inside a refined chunk, it jumps to the matching position in the "other" side of the refinement: if you are in the new text, it jumps to the corresponding position in the old text and vice versa. +--- *** New user option 'smerge-refine-shadow-cursor'. When 'smerge-refine' shows the conflict diffs at word granularity, a "shadow cursor" is now displayed in the "lower" version when point @@ -1717,6 +1777,7 @@ just the character corresponding to the position where 'smerge-refine-exchange-point' would jump, shown in a new distinct face 'smerge-refine-shadow-cursor', by default a box face. +--- *** 'smerge-refine-regions' can compare regions in different buffers. ** Cursor Sensor mode @@ -1726,10 +1787,12 @@ face 'smerge-refine-shadow-cursor', by default a box face. ** Image Dired +--- *** 'image-dired-show-all-from-dir' takes the same first argument as 'dired'. This allows passing a string with wildcards, or a cons cell where the first element is a list and the rest is a list of files. +--- *** Bound unused letters in 'image-dired-thumbnail-mode-map'. For a more comfortable navigation experience (as in, no modifier keys), the keys 'f', 'b', 'n', 'p', 'a' and 'e' are now bound to the @@ -1737,6 +1800,7 @@ same functions as their 'C-' counterparts. ** Browse URL +--- *** New user option 'browse-url-transform-alist'. This user option is an alist that allows transforming URLs before asking a web browser to load them. For example, it could be used like this: @@ -1744,10 +1808,12 @@ a web browser to load them. For example, it could be used like this: (add-to-list 'browse-url-transform-alist '("www.google.com" . "www.duckduckgo.com")) -*** New function 'browse-url-qutebrowser' for Qutebrowser. +--- +*** New command 'browse-url-qutebrowser' for Qutebrowser. For better integration with Qutebrowser, set 'browse-url(-secondary)-browser-function' to 'browse-url-qutebrowser'. +--- *** New GTK-native launch mode. For better Wayland support, the pgtk toolkit exposes a new 'x-gtk-launch-uri' browse-url handler and uses it by default when URLs @@ -1755,15 +1821,18 @@ are browsed from a PGTK frame. For other frames, we fall back to the default URL launch function. This change allows us to properly raise browser windows under Wayland using the xdg_activation_v1 protocol. +--- *** 'RET' can visit URLs in read-only buffers. In some keymaps such as 'ansi-osc-hyperlink-map', 'browse-url-button-map', 'goto-address-highlight-keymap', 'bug-reference-map' it is possible now to visit URLs by typing just 'RET' instead of 'C-c RET' in read-only buffers. +--- *** Removed support for some obsolete web browsers. Conkeror (obsolete since Emacs 28.1), gnome-moz-remote (obsolete since Emacs 25.1), and gnudoit (obsolete since Emacs 25.1). +--- *** 'browse-url-firefox-program' now supports LibreWolf and Zen Browser. LibreWolf, Floorp and Zen Browser, three popular Firefox forks, have been added to the programs that are automatically recognizable as Firefox @@ -1774,8 +1843,6 @@ one of these found on your system. +++ *** Derived types (i.e. 'cl-deftype') can now be used as method specializers. -As part of this new support, the new function 'cl-types-of' returns -the list of types to which a value belongs. +++ *** Some cl-lib functions and macros are now built-in. @@ -1948,7 +2015,7 @@ a horizontal shift of text on display, and thus could be annoying). The "In-Reply-To" header created when replying to a message now contains only the originating message's id, conforming to RFC 5322. The previous behavior included additional information about the originating message. -The new variable 'message-header-use-obsolete-in-reply-to', nil by +The new user option 'message-header-use-obsolete-in-reply-to', nil by default, can be set to a non-nil value to restore the previous behavior. +++ @@ -1996,7 +2063,7 @@ Gnus, see "(gnus) Symbolic Prefixes" in the Gnus manual. *** System sleep integration is now independent of D-Bus. The system sleep integration previously provided by customizing the variable 'gnus-dbus-close-on-sleep' is now deprecated. A new system -using the builtin 'system-sleep' library is now available by customizing +using the builtin system-sleep.el library is now available by customizing 'gnus-close-on-sleep'. This will work on all systems that the 'system-sleep' library supports. @@ -2028,7 +2095,7 @@ its current directory, and creates a remote connection, if necessary. You can customize 'shell-bookmark-name-function'. *** New command to complete the shell history. -'comint-complete-input-ring' ('C-x <up>') is like 'minibuffer-complete-history' +'comint-complete-input-ring' ('C-x <UP>') is like 'minibuffer-complete-history' but completes on comint inputs. --- @@ -2187,7 +2254,7 @@ non-nil; customize to nil to disable the check. ** Sendmail --- -*** Sending an email via 'sendmail' checks for suspicious addressees. +*** Sending an email via sendmail.el checks for suspicious addressees. The command 'mail-send', used to send email in Mail mode, now checks the addressees for suspicious email addresses. If such addresses are found, the command will show them and the reason they are considered @@ -2242,7 +2309,7 @@ HTML 'doctype' declaration to have context-type "text/html". When there is no EWW buffer, 'eww-switch-to-buffer' falls back to calling 'eww'. -** Url Queue +** URL Queue --- *** 'url-queue-retrieve' now makes use of some url request variables. @@ -2275,6 +2342,13 @@ To get the old behavior back, add an element '(enum-open ** Emacs Lisp mode ++++ +*** Semantic highlighting support for Emacs Lisp. +'emacs-lisp-mode' can now use code analysis to highlight more symbols +more accurately. Customize the new user option +'elisp-fontify-semantically' to non-nil to enable this feature, and see +the Info node "(emacs) Semantic Font Lock" for more information. + --- *** Checkdoc no longer warns about missing footer lines in some cases. Emacs Lisp libraries have traditionally ended with a footer line @@ -2290,7 +2364,7 @@ explicitly only support Emacs 30.1 or later, as specified in the packages that support earlier versions of Emacs is that package.el in those versions can't install packages where that line is missing. -This change affects both 'M-x checkdoc' and the corresponding flymake +This change affects both 'checkdoc' and the corresponding flymake backend. --- @@ -2323,6 +2397,7 @@ positives. It checks the buffer in batch mode, prints all found errors and signals the first found error. +--- *** New file-local variable 'lisp-indent-local-overrides'. This variable can be used to locally override the indent specification of symbols. @@ -2343,23 +2418,23 @@ inside an sexp typing 'RET' inserts a newline, and otherwise Emacs proceeds with evaluating the expression. This is useful when 'electric-pair-mode', or a similar automatic pairing mode, is enabled. -** DocView +** Doc View --- *** Dedicated buffer for plain text contents. When switching to the plain text contents with 'doc-view-open-text', -DocView now creates a dedicated buffer to display it. 'C-c C-c' gets you -back to the real DocView buffer if it still exists. +Doc View now creates a dedicated buffer to display it. 'C-c C-c' gets you +back to the real Doc View buffer if it still exists. +++ *** New commands to save and restore pages in buffer-local registers. -Docview can store the current page to buffer-local registers with the new +Doc View can store the current page to buffer-local registers with the new command 'doc-view-page-to-register' (bound to 'm'), and later the stored page can be restored with 'doc-view-jump-to-register' (bound to '''). +++ -*** Docview can generate imenu indices for DjVu and ODF documents. -When the 'djvused' program is available, Docview can now generate an imenu +*** Doc View can generate imenu indices for DjVu and ODF documents. +When the 'djvused' program is available, Doc View can now generate an imenu index for DjVu files from its outline. Indices for Open Document Format (ODF) files as used by OpenOffice and LibreOffice are generated using the 'mutool' program after their initial conversion to PDF format. The @@ -2482,6 +2557,7 @@ started inside Emacs. ** Isearch and Replace ++++ *** Typing 'd' during 'query-replace' shows the diff buffer with replacements. ** Diff @@ -2529,6 +2605,7 @@ one as before. This makes them different from 'vc-diff' and 'vc-root-diff' when those are called without a prefix argument. *** 'diff-apply-hunk' now supports creating and deleting files. +'diff-apply-buffer' supports creating files but not deleting them, yet. +++ *** Diff mode's application and killing commands now consider the region. @@ -2612,6 +2689,7 @@ Without 'dired-hide-details-hide-absolute-location': When 'dired-make-directory-clickable' is non-nil, clicking on the base name of the directory now reverts the Dired buffer. +--- *** 'dired-copy-filename-as-kill' supports project-relative names. With a new value of the prefix argument (1), this command copies file names relative to the root directory of the current project. @@ -2690,8 +2768,7 @@ with a file-local variable, you may be asked to update the value. *** New Xref backend for TeX modes. The new backend ('tex-etags') is on by default, and improves the functionality of the standard 'xref' commands in TeX buffers. You can -restore the standard 'etags' backend with the 'M-x xref-etags-mode' -toggle. +restore the standard 'etags' backend with the 'xref-etags-mode' toggle. ** BibTeX mode @@ -2730,6 +2807,7 @@ mode. Now, one needs to say '(midnight-mode +1)' instead. ** Python mode +--- *** New 'repeat-map' for Python indentation commands. The commands 'python-indent-shift-left' and 'python-indent-shift-right' can now be repeated using 'repeat-mode'. With 'repeat-mode' enabled, @@ -2787,6 +2865,7 @@ string instead of prepending it and 'tmm-mid-prompt' to said entry. ** Foldout ++++ *** Improved behavior of 'foldout-exit-fold' with negative prefix argument. When 'foldout-exit-fold' is called with a negative argument (so that the exited fold remains visible), the position of point and window view are @@ -2935,6 +3014,7 @@ from the history of the current branch, though without undoing the changes made by those revisions to the working tree. 'X' is similar except that it does remove the changes from the working tree. +--- *** New command 'log-edit-done-strip-cvs-lines'. This command strips all lines beginning with "CVS:" from the buffer. It is intended to be added to the 'log-edit-done-hook' so that @@ -3182,7 +3262,7 @@ already have, consider replacing the default global bindings, like this: This command is Diff mode's specialized 'narrow-to-region'. 'narrow-to-region' has long been disabled by default, so for consistency, 'diff-restrict-view' is now too. -To enable it again, use 'M-x enable-command'. +To enable it again, use 'enable-command'. --- *** 'C-x v !' has its own input history. @@ -3199,7 +3279,7 @@ This was already in place for Mercurial. --- *** 'vc-hg-working-revision' now returns changeset hashes. -Previously it returned local revision numbers, but hashes are more +Previously, it returned local revision numbers, but hashes are more robust for how this function is typically used. ** Package @@ -3367,7 +3447,7 @@ implementations to suppress messages in Auto Revert modes, for example. ** Strokes --- +--- *** 'strokes-mode' no longer demands the presence of a mouse. 'strokes-mode' now permits itself to be enabled if no mouse is connected, to facilitate enabling 'strokes-mode' in sessions where the @@ -3427,6 +3507,7 @@ Meant to be given a global binding convenient to the user. Example: ** Icomplete +--- *** Change in meaning of 'icomplete-show-matches-on-no-input' (again). For Emacs 28 to Emacs 30, when 'icomplete-show-matches-on-no-input' was non-nil, 'RET' had special behavior when the minibuffer's contents was @@ -3441,6 +3522,7 @@ You can opt back in to the special behavior of 'RET' like this: icomplete-minibuffer-map "<remap> <minibuffer-complete-and-exit>" #'icomplete-ret) +--- *** New user options for 'icomplete-vertical-mode'. New user options have been added to enhance 'icomplete-vertical-mode': @@ -3453,6 +3535,7 @@ New user options have been added to enhance 'icomplete-vertical-mode': - 'icomplete-vertical-unselected-prefix-indicator' specifies the prefix string for unselected candidates. +--- *** New faces for 'icomplete-vertical-mode'. New faces have been added to 'icomplete-vertical-mode': @@ -3461,7 +3544,7 @@ New faces have been added to 'icomplete-vertical-mode': - 'icomplete-vertical-unselected-prefix-indicator-face' controls the appearance of unselected candidate prefixes. -** Customize +** Custom +++ *** New function 'custom-initialize-after-file-load'. @@ -3471,7 +3554,7 @@ functions defined later than the variable, as is common for minor modes. ':init-value' is non-nil. --- -*** New major mode 'Customize-dirlocals-mode'. +*** New major mode 'Custom-dirlocals-mode'. This is intended for customizing directory-local variables in the current directory's ".dir-locals.el" file. @@ -3487,7 +3570,7 @@ text field for other values). ** Pulse --- +--- *** New function 'pulse-faces'. This function pulses a specified list of faces. The pulse duration is determined by the new user option 'pulse-face-duration'. @@ -3569,7 +3652,7 @@ This function flashes the current echo area briefly. It is intended to be used in 'ring-bell-function'. --- -*** New user option 'flash-face-duration'. +*** New user option 'pulse-face-duration'. This option controls the flash duration for 'flash-face-bell-function' and 'flash-echo-area-bell-function'. @@ -3578,7 +3661,7 @@ and 'flash-echo-area-bell-function'. This option tells 'flash-face-bell-function' which faces should flash. --- -*** New user option 'flash-face-attributes' +*** New user option 'flash-face-attributes'. This option tells 'flash-face-bell-function' and 'flash-echo-area-bell-function' which face attributes should be used for flash. @@ -3619,11 +3702,13 @@ is still available on 'v'. --- ** Flymake -*** Enhanced 'flymake-show-diagnostics-at-end-of-line' ++++ +*** Enhanced 'flymake-show-diagnostics-at-end-of-line'. The new value 'fancy' allowed for this user option will attempt to layout diagnostics below the affected line using unicode graphics to point to diagnostic locus. +--- *** Enhanced 'flymake-show-buffer-diagnostics'. The command 'flymake-show-buffer-diagnostics' is now capable of highlighting a nearby diagnostic in the resulting listing. Additionally, @@ -3631,25 +3716,30 @@ it is bound to mouse clicks on fringe and margin indicators, operating on the diagnostics of the corresponding line. The user may bind it in other situations such as the diagnostic overlay map. ++++ *** More powerful 'flymake-make-diagnostic' API. Flymake backends can now specify origin and code attributes, allowing Flymake and other extensions to segregate diagnostics based on this extended information. ++++ *** New user option 'flymake-diagnostic-format-alist'. This provides fine-grained control over diagnostic formatting across different contexts, allowing you to specify which components (origin, code, message or one-liner message) appear in each output destination. +--- *** Dynamic column sizing in diagnostic listings. The tabulated listings produced by 'flymake-show-buffer-diagnostics' and 'flymake-show-project-diagnostics' now automatically adjust their column widths based on content, optimizing display space and readability. +--- *** New value 'auto' of user option 'flymake-indicator-type'. This value (set by default) tries to use fringes if possible, otherwise falls back to margins. +--- *** New user option 'elisp-flymake-byte-compile-executable'. This allows customizing the Emacs executable used for Flymake byte compilation in 'emacs-lisp-mode'. This option should be set when editing @@ -3661,7 +3751,7 @@ provide more accurate warnings from byte compilation. +++ *** SQLite databases can now be opened in read-only mode. -The new optional argument READONLY to 'sqlite-open' function allows to +The new optional argument READONLY of function 'sqlite-open' allows to open an existing database only for reading. +++ @@ -3678,7 +3768,7 @@ DISABLE-URI non-nil. +++ *** 'pdb', 'perldb', and 'guiler' suggest debugging the current file via 'M-n'. -When starting these debuggers (e.g., 'M-x pdb') while visiting a file, +When starting these debuggers (e.g., 'pdb') while visiting a file, pressing 'M-n' in the command prompt suggests a command line including the file name, using the minibuffer's "future history". @@ -3695,6 +3785,7 @@ You can now use the mouse wheel to scroll the calendar by 3 months. With the shift modifier, it scrolls by one month. With the meta modifier, it scrolls by year. ++++ *** Simpler key bindings for navigation in calendar by months and by years. The month and year navigation key bindings 'M-}', 'M-{', 'C-x ]' and 'C-x [' now have the alternative keys '}', '{', ']' and '['. @@ -3705,9 +3796,10 @@ The user options 'calendar-mark-holidays-flag' and 'calendar-mark-diary-entries-flag' are not modified anymore when changing the marking state in the calendar buffer. +--- *** New library for iCalendar data. A new library has been added to the calendar for handling iCalendar -(RFC5545) data. The library is designed for reuse in other parts of +(RFC 5545) data. The library is designed for reuse in other parts of Emacs and in third-party packages. Package authors can find the new library in the Emacs distribution under "lisp/calendar/icalendar-*.el". @@ -3718,6 +3810,7 @@ features from icalendar.el; see below. ** Diary +--- *** New user option 'diary-date-insertion-form'. This user option determines how dates are inserted into the diary by Lisp functions. Its value is a pseudo-pattern of the same type as in @@ -3725,7 +3818,7 @@ Lisp functions. Its value is a pseudo-pattern of the same type as in entries from the calendar, or when importing them from other formats. +++ -*** New library 'diary-icalendar'. +*** New library diary-icalendar.el. This library reimplements features previously provided by icalendar.el: import from iCalendar format to the diary, and export from the diary to iCalendar. It also adds the ability to include iCalendar files in the @@ -3749,6 +3842,7 @@ The old names are kept as obsolete aliases. ** Calc ++++ *** New user option 'calc-string-maximum-character'. Previously, the 'calc-display-strings', 'string', and 'bstring' functions only considered integer vectors whose elements are all in the @@ -3764,6 +3858,7 @@ default value is nil to preserve the existing behavior. ** Time +--- *** New user option 'world-clock-sort-order'. This option controls the order of timezone entries in the 'world-clock'. By default, no sorting is done, and entries appear in the same order as @@ -3795,7 +3890,7 @@ is actually about Org (in which case users should use the Org-specific command for reporting bugs). --- -** The elint package is now obsolete. +** The elint.el package is now obsolete. Use the byte-compiler instead; it provides more and more useful warnings. ** Newsticker @@ -3817,11 +3912,13 @@ or obsolete. ** CPerl mode +--- *** Syntax of Perl up to version 5.42 is supported. CPerl mode creates imenu entries for ":writer" generated accessors and recognizes the new functions "all" and "any". See https://perldoc.perl.org/5.42.0/perldelta for details. +--- ** Zone Zone can scramble multiple windows across multiple frames; it may also @@ -3867,9 +3964,10 @@ it will begrudgingly use the scratch buffer. +++ *** You can now enable Abbrev mode by default using Easy Customization. -Customize the variable 'abbrev-mode' to non-nil to enable Abbrev mode by -default in all buffers. +Customize the user option 'abbrev-mode' to non-nil to enable Abbrev mode +by default in all buffers. +--- ** Antlr mode *** Variable 'antlr-tool-version' is no user option anymore. @@ -3882,7 +3980,7 @@ value "java org.antlr.Tool") when 'antlr-tool-version' has the value *** Command 'antlr-mode' now also works on ANTLR v3 or v4 grammars. If the variable 'antlr-tool-version' is not set locally, e.g., by the -file’s local variables specs, the command sets its local value to +file's local variables specs, the command sets its local value to 'antlr-v2' if a keyword "class" or "header" appears at the beginning of the source, or to 'antlr-v3' otherwise. @@ -3912,6 +4010,7 @@ If an active region exists, the commands 'hi-lock-line-face-buffer' and 'hi-lock-face-phrase-buffer' now use its contents as their default value. Previously, only 'hi-lock-face-buffer' supported this. +--- ** Shadowfile *** 'shadow-info-buffer' and 'shadow-todo-buffer' use ephemeral buffer names now. @@ -3929,6 +4028,7 @@ percentage, or presence in the bay changes. ** Etags Regen mode +--- *** Tags table is not created during completion anymore. Previously, when there was no tags table loaded and the default completion function was called, 'etags-regen-mode' ensured that tags @@ -3938,20 +4038,24 @@ were created. This has been disabled, and the new user option * New Modes and Packages in Emacs 31.1 +--- ** New major mode 'icalendar-mode'. -A major mode for displaying and editing iCalendar (RFC5545) data. This +A major mode for displaying and editing iCalendar (RFC 5545) data. This mode handles line unfolding and fontification, including highlighting syntax errors in invalid data. ++++ ** New minor mode 'delete-trailing-whitespace-mode'. A simple buffer-local mode that runs 'delete-trailing-whitespace' before saving the buffer. +--- ** New major mode 'conf-npmrc-mode'. A major mode based on 'conf-mode' for editing ".npmrc" files. ** New major modes based on the tree-sitter library +--- *** New major mode 'mhtml-ts-mode'. An optional major mode based on the tree-sitter library for editing HTML files. This mode handles indentation, fontification, and commenting for @@ -3963,9 +4067,11 @@ A major mode based on the tree-sitter library for editing "go.work" files. If tree-sitter is properly set-up by the user, it can be enabled for files named "go.work". +--- ** New package 'lua-mode'. The 'lua-mode' package from NonGNU ELPA is now included in Emacs. +--- ** New library 'timeout'. This library provides functions to throttle or debounce Emacs Lisp functions. This is useful for corralling overeager code that is slow @@ -4038,16 +4144,6 @@ modes used 'FOO-mode-indent-offset' instead of the previous conventional 'go-ts-indent-offset', 'csharp-ts-indent-offset', 'cmake-ts-indent-offset', 'c-ts-indent-offset'. -** Files loaded from '-x' and '--script' now use lexical binding. -If you don't have time to adapt your script's code to the lexical -binding dialect (see "(elisp) Converting to Lexical Binding"), you can -wrap your code in: - - #!/usr/bin/env -S emacs --batch --script - (eval - '(progn - YOUR CODE HERE)) - +++ ** String mutation has been restricted further. 'aset' on unibyte strings now requires the new character to be a single @@ -4078,6 +4174,7 @@ may return either nil or t. --- ** The obsolete variable 'redisplay-dont-pause' has been removed. +--- ** The 'rx' category name 'chinese-two-byte' must now be spelled correctly. An old alternative name (without the first 'e') has been removed. @@ -4098,6 +4195,7 @@ All the characters that belong to the 'symbol' script (according to 'char-script-table') now have the 'symbol' category, whose mnemonic is '5'. +--- ** Some libraries obsolete since Emacs 24.4 and 24.5 have been removed: cc-compat.el, info-edit.el, meese.el, otodo-mode.el, rcompile.el, sup-mouse.el, terminal.el, vi.el, vip.el, ws-mode.el, and yow.el. @@ -4112,7 +4210,7 @@ single binding syntax, which we'd kept only for backwards compatibility. --- ** The Eshell 'pwd' command now expands the directory name on all systems. This ensures that user directories are properly expanded to their full -name. Previously, Eshell only did this for MS-Windows systems. To +name. Previously, Eshell only did this for MS-Windows systems. To restore the old behavior, you can set 'eshell-pwd-convert-function' to 'identity'. @@ -4218,8 +4316,8 @@ modification takes place inside 'with-help-window' or ** Xref commands don't automatically suggest to visit a tags table anymore. When no tags file is loaded, symbol completion just won't provide any suggestions. So the 'M-?' command now works without a tags table. And -the 'M-.' will show a message describing the several built-in options -that will provide an Xref backend when used. +the 'M-.' command will show a message describing the several built-in +options that will provide an Xref backend when used. +++ ** Calling 'debug' in batch sessions no longer kills Emacs. @@ -4251,7 +4349,7 @@ without performing a collection. +++ ** Improve 'replace-region-contents' to accept more forms of sources. -It has been promoted from 'subr-x' to the C code. +It has been promoted from subr-x.el to the C code. You can now directly pass it a string or a buffer rather than a function. Actually passing it a function is now deprecated. @@ -4302,6 +4400,17 @@ change it globally with: --- *** Loading a file displays a warning if there is no 'lexical-binding' cookie. +--- +** Files loaded from '-x' and '--script' now use lexical binding. +If you don't have time to adapt your script's code to the lexical +binding dialect (see "(elisp) Converting to Lexical Binding"), you can +wrap your code in: + + #!/usr/bin/env -S emacs --batch --script + (eval + '(progn + YOUR CODE HERE)) + --- ** New function 'set-local'. This is the buffer-local equivalent of the function 'set'. @@ -4355,6 +4464,7 @@ construct '(any ...)' is unrelated and not obsolete. ** ERT +--- *** Some experimental ERT macros are now considered stable. The following macros, previously only available in the experimental 'ert-x' module, are now considered stable and have been moved to 'ert': @@ -4434,6 +4544,7 @@ functions 'dbus--fd-open', 'dbus--fd-close' and 'dbus--registered-fds' implement managing these file descriptors. See the Info node "(dbus) File Descriptors" for details. +--- ** The customization group 'wp' has been removed. It has been obsolete since Emacs 26.1. Use the group 'text' instead. @@ -4518,6 +4629,7 @@ the 'repeat-continue' property of each command in that list. The 'use-package' and 'bind-keys' macros support a similar keyword ':continue-only'. ++++ ** New function 'completion-table-with-metadata'. It offers a more concise way to create a completion table with metadata. @@ -4563,6 +4675,7 @@ This function inserts the special EVENT into the input event queue. This event is sent when the device running Emacs enters or leaves the sleep state. +--- ** Function aliases obsolete since Emacs 23.2 have been removed: 'advertised-undo', 'advertised-widget-backward', and 'dired-advertised-find-file'. @@ -4573,6 +4686,7 @@ sleep state. and set the top-level buffer-local value of a variable. A top-level value is the one that variable has outside of any let-bindings. ++++ ** New function 'exec-suffixes'. This function by default returns the value of the corresponding user option, but can optionally return the equivalent of 'exec-suffixes' from @@ -4619,26 +4733,19 @@ When the theme is set on PGTK, Android, or MS-Windows systems, variable 'toolkit-theme' as either symbol 'dark' or 'light', but may be extended to encompass other toolkit-specific symbols in the future. -** Progress reporter - +++ -*** Progress reporter callbacks. -'make-progress-reporter' now accepts optional arguments UPDATE-CALLBACK, -called on progress steps, and DONE-CALLBACK, called when the progress -reporter is done. See the 'make-progress-reporter' docstring for a full -specification of these new optional arguments. - -+++ -*** Progress reporter context. +** Progress reporter context. 'make-progress-reporter' now accepts the optional argument CONTEXT, which if it is the symbol 'async', inhibits updates in the echo area when it is busy. This is useful, for example, if you want to monitor progress of an inherently asynchronous command such as 'compile'. ++++ ** Binary format specifications '%b' and '%B' added. These produce the binary representation of a number. '%#b' and '%#B' prefix the bits with '0b' and '0B', respectively. +--- ** 'pp-eval-expression' can now insert results into the current buffer. With a prefix argument, 'pp-eval-expression' inserts the result into the current buffer, just like 'eval-expression' already did. @@ -4651,6 +4758,7 @@ safe to run the command multiple times on subsequent partitions of the list of arguments. The variable 'command-line-max-length' controls the partitioning. ++++ ** New function 'ensure-proper-list'. This function is a variation on 'ensure-list' that checks if an object is a proper list, in which case the list will be returned as is, @@ -4725,8 +4833,8 @@ Note: Accepting this permission allows the use of system APIs, which may send user data to Apple's speech recognition servers. --- -** Re-introduced dictation, lost in Emacs v30 (macOS). -We lost macOS dictation in v30 when migrating to NSTextInputClient. +** Re-introduced dictation, lost in Emacs 30 (macOS). +We lost macOS dictation in Emacs 30 when migrating to NSTextInputClient. Implemented 'selectedRange' in 'nsterm.m' to enable in new subsystem. You may notice a slight change in dictation UI provided by macOS. @@ -4747,7 +4855,7 @@ supported. As on X, the user options 'dnd-scroll-margin' and --- ** Emacs on MS-Windows now supports color fonts. -On Windows 8.1 and later versions Emacs now uses DirectWrite to draw +On Windows 8.1 and later versions, Emacs now uses DirectWrite to draw text, which supports color fonts. This can be disabled by setting the variable 'w32-inhibit-dwrite' to t. Also see 'w32-dwrite-available' and 'w32-dwrite-reinit' to check availability and to configure the diff --git a/etc/PROBLEMS b/etc/PROBLEMS index 54302968e6d..c9b01e65ea4 100644 --- a/etc/PROBLEMS +++ b/etc/PROBLEMS @@ -959,6 +959,16 @@ specified run-time search path in the executable. Please refer to the documentation of your dynamic linker for details. +*** Using Enchant 2.x as the Ispell back-end signals an error. + +The error message says "enchant-2: Unknown option -C". + +This is because many dictionary definitions in the default value of +'ispell-dictionary-alist' use the '-C' command-line option, which is not +supported by some versions of Enchant 2.x. Support for '-C' was added +to Enchant in version 2.8.17, so use that or later version to solve this +problem. + *** When you run Ispell from Emacs, it reports a "misalignment" error. This can happen if you compiled the Ispell program to use ASCII @@ -3177,6 +3187,25 @@ XKeymacs Version 3.47, deactivating XKeymacs when Emacs is active is not enough to avoid its messing with the keyboard input. Exiting XKeymacs completely is reported to solve the problem. +** Pasting non-ASCII characters into "emacs -nw" doesn't work. + +This happens if you paste using the Windows shortcuts, such as +S-<Insert> and C-v or C-S-v. Evidently, these paste methods support +only ASCII text, at least in some Windows configurations. + +Instead, use the Emacs C-y key to paste from the clipboard, which on +Windows works on text-only frames as well. Make sure your +customizations don't affect the value of 'interprogram-paste-function', +which should be 'gui-selection-value', even in -nw sessions. In +addition, you should make sure the font used by the Windows Terminal +supports the characters you paste (the default font set by Windows +should be okay). For best results, we also recommend to set the console +codepage to 65001, which is the UTF-8 codepage. You can do that with +the following command, which should be done _before_ running Emacs on +the Windows Terminal: + + c:\> chcp 65001 + ** Pasting from Windows clipboard into Emacs doesn't work. This was reported to be the result of an anti-virus software blocking @@ -3920,6 +3949,18 @@ The organization of the Settings app might disagree with that illustrated above, which if true you should consult the documentation or any search mechanism for it. +** Emacs Input Methods don't work. + +When using the Android touchscreen keyboard, Emacs input methods set by +'C-\' don't work. This is because Android's virtual input methods +function by applying editing commands directly to Emacs buffers, which +circumvents and is not compatible with Emacs's character-centric input +methods. You can disable what the virtual input methods do by setting +'overriding-text-conversion-style' to nil rather than 'lambda', at the +cost of your virtual input method's own text editing aids, or (in some +cases) the ability to perform character composition or input CJK or +non-Latin scripts. + ** Emacs is not compatible with the "Microsoft SwiftKey" input method. When enabled, windows are repeatedly recentered around earlier buffer diff --git a/etc/emacs-buffer.gdb b/etc/emacs-buffer.gdb index 73bb71644b0..eada92f0f48 100644 --- a/etc/emacs-buffer.gdb +++ b/etc/emacs-buffer.gdb @@ -265,7 +265,11 @@ document ysave-buffer end define ybuffer-contents - ydump-buffer $arg0 /dev/stdout + if defined_WINDOWSNT + ydump-buffer $arg0 CONOUT$ + else + ydump-buffer $arg0 /dev/stdout + end if $yverbose && $buf->z_byte <= 1 yget-current-buffer-name printf "[Buffer \"%s\" is empty.]\n", $ycurrent_buffer_name diff --git a/etc/refcards/orgcard.tex b/etc/refcards/orgcard.tex index 8b38b98897e..f558d05ae74 100644 --- a/etc/refcards/orgcard.tex +++ b/etc/refcards/orgcard.tex @@ -1,5 +1,5 @@ % Reference Card for Org Mode -\def\orgversionnumber{9.8.5} +\def\orgversionnumber{9.8.7} \def\versionyear{2026} % latest update \input emacsver.tex diff --git a/etc/themes/modus-operandi-deuteranopia-theme.el b/etc/themes/modus-operandi-deuteranopia-theme.el index c86649d0c70..802b0eb0f15 100644 --- a/etc/themes/modus-operandi-deuteranopia-theme.el +++ b/etc/themes/modus-operandi-deuteranopia-theme.el @@ -1,9 +1,9 @@ ;;; modus-operandi-deuteranopia-theme.el --- Deuteranopia-optimized theme with a white background -*- lexical-binding:t -*- -;; Copyright (C) 2019-2026 Free Software Foundation, Inc. +;; Copyright (C) 2019-2026 Free Software Foundation, Inc. -;; Author: Protesilaos Stavrou <[email protected]> -;; Maintainer: Protesilaos Stavrou <[email protected]> +;; Author: Protesilaos <[email protected]> +;; Maintainer: Protesilaos <[email protected]> ;; URL: https://github.com/protesilaos/modus-themes ;; Keywords: faces, theme, accessibility @@ -90,4 +90,6 @@ standard)." 'modus-operandi-deuteranopia-palette-overrides 'modus-themes-faces-deuteranopia) +(provide 'modus-operandi-deuteranopia-theme) + ;;; modus-operandi-deuteranopia-theme.el ends here diff --git a/etc/themes/modus-operandi-theme.el b/etc/themes/modus-operandi-theme.el index 590c6d9903e..e4e6f6fabed 100644 --- a/etc/themes/modus-operandi-theme.el +++ b/etc/themes/modus-operandi-theme.el @@ -1,9 +1,9 @@ ;;; modus-operandi-theme.el --- Elegant, highly legible theme with a white background -*- lexical-binding:t -*- -;; Copyright (C) 2019-2026 Free Software Foundation, Inc. +;; Copyright (C) 2019-2026 Free Software Foundation, Inc. -;; Author: Protesilaos Stavrou <[email protected]> -;; Maintainer: Protesilaos Stavrou <[email protected]> +;; Author: Protesilaos <[email protected]> +;; Maintainer: Protesilaos <[email protected]> ;; URL: https://github.com/protesilaos/modus-themes ;; Keywords: faces, theme, accessibility @@ -87,4 +87,6 @@ which corresponds to a minimum contrast in relative luminance of 'modus-operandi-palette-user 'modus-operandi-palette-overrides) +(provide 'modus-operandi-theme) + ;;; modus-operandi-theme.el ends here diff --git a/etc/themes/modus-operandi-tinted-theme.el b/etc/themes/modus-operandi-tinted-theme.el index 17fc6be8d4d..92e14a4c1df 100644 --- a/etc/themes/modus-operandi-tinted-theme.el +++ b/etc/themes/modus-operandi-tinted-theme.el @@ -1,9 +1,9 @@ ;;; modus-operandi-tinted-theme.el --- Elegant, highly legible theme with a light ochre background -*- lexical-binding:t -*- -;; Copyright (C) 2019-2026 Free Software Foundation, Inc. +;; Copyright (C) 2019-2026 Free Software Foundation, Inc. -;; Author: Protesilaos Stavrou <[email protected]> -;; Maintainer: Protesilaos Stavrou <[email protected]> +;; Author: Protesilaos <[email protected]> +;; Maintainer: Protesilaos <[email protected]> ;; URL: https://github.com/protesilaos/modus-themes ;; Keywords: faces, theme, accessibility @@ -87,4 +87,6 @@ which corresponds to a minimum contrast in relative luminance of 'modus-operandi-tinted-palette-user 'modus-operandi-tinted-palette-overrides) +(provide 'modus-operandi-tinted-theme) + ;;; modus-operandi-tinted-theme.el ends here diff --git a/etc/themes/modus-operandi-tritanopia-theme.el b/etc/themes/modus-operandi-tritanopia-theme.el index 9e4211512ef..f8a2e62dacc 100644 --- a/etc/themes/modus-operandi-tritanopia-theme.el +++ b/etc/themes/modus-operandi-tritanopia-theme.el @@ -1,9 +1,9 @@ ;;; modus-operandi-tritanopia-theme.el --- Tritanopia-optimized theme with a white background -*- lexical-binding:t -*- -;; Copyright (C) 2019-2026 Free Software Foundation, Inc. +;; Copyright (C) 2019-2026 Free Software Foundation, Inc. -;; Author: Protesilaos Stavrou <[email protected]> -;; Maintainer: Protesilaos Stavrou <[email protected]> +;; Author: Protesilaos <[email protected]> +;; Maintainer: Protesilaos <[email protected]> ;; URL: https://github.com/protesilaos/modus-themes ;; Keywords: faces, theme, accessibility @@ -90,4 +90,6 @@ standard)." 'modus-operandi-tritanopia-palette-overrides 'modus-themes-faces-tritanopia) +(provide 'modus-operandi-tritanopia-theme) + ;;; modus-operandi-tritanopia-theme.el ends here diff --git a/etc/themes/modus-themes.el b/etc/themes/modus-themes.el index 8994dc68985..ff9bf48e553 100644 --- a/etc/themes/modus-themes.el +++ b/etc/themes/modus-themes.el @@ -1,11 +1,11 @@ ;;; modus-themes.el --- Elegant, highly legible and customizable themes -*- lexical-binding:t -*- -;; Copyright (C) 2019-2026 Free Software Foundation, Inc. +;; Copyright (C) 2019-2026 Free Software Foundation, Inc. -;; Author: Protesilaos Stavrou <[email protected]> -;; Maintainer: Protesilaos Stavrou <[email protected]> +;; Author: Protesilaos <[email protected]> +;; Maintainer: Protesilaos <[email protected]> ;; URL: https://github.com/protesilaos/modus-themes -;; Version: 5.2.0 +;; Version: 5.3.0 ;; Package-Requires: ((emacs "28.1")) ;; Keywords: faces, theme, accessibility @@ -188,25 +188,17 @@ properties from their context (e.g. an overlay over an underlined 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." - :group 'modus-themes-faces) +(define-obsolete-face-alias 'modus-themes-prompt nil "5.3.0") (defface modus-themes-button nil "Face for graphical buttons." :group 'modus-themes-faces) -(defface modus-themes-completion-selected nil - "Face for current selection in completion UIs." - :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)) +(define-obsolete-face-alias 'modus-themes-completion-selected nil "5.3.0") +(define-obsolete-face-alias 'modus-themes-completion-match-0 nil "5.3.0") +(define-obsolete-face-alias 'modus-themes-completion-match-1 nil "5.3.0") +(define-obsolete-face-alias 'modus-themes-completion-match-2 nil "5.3.0") +(define-obsolete-face-alias 'modus-themes-completion-match-3 nil "5.3.0") @@ -479,123 +471,15 @@ and related user options." :value-type ,modus-themes--headings-widget) :link '(info-link "(modus-themes) Heading styles")) -(defcustom modus-themes-completions nil - "Control the style of completion user interfaces. - -This affects Company, Corfu, Flx, Icomplete/Fido, Ido, Ivy, -Orderless, Vertico, and the standard *Completions* buffer. 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 underline)) - (selection . (semibold italic))))) - -The `matches' key refers to the highlighted characters that -correspond 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: - -- `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 - 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, a bold weight, and the base foreground -value for the text. The list of properties it accepts is as -follows (order is not significant): - -- `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 - variable `modus-themes-weights'. The absence of a weight means - that bold will be used. - -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 underline))))) - -Is the same as: - - (setq modus-themes-completions - (quote ((matches . (extrabold underline)) - (selection . (extrabold underline)))))" - :group 'modus-themes - :package-version '(modus-themes . "4.0.0") - :version "30.1" - :type `(set - (cons :tag "Matches" - (const matches) - (set :tag "Style of matches" :greedy t - ,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 - ,modus-themes--weight-widget - (const :tag "Italic font (oblique or slanted forms)" italic) - (const :tag "Underline" underline))) - (cons :tag "Fallback for both matches and selection" - (const t) - (set :tag "Style of both matches and selection" :greedy t - ,modus-themes--weight-widget - (const :tag "Italic font (oblique or slanted forms)" italic) - (const :tag "Underline" underline)))) - :link '(info-link "(modus-themes) Completion UIs")) - -(defcustom modus-themes-prompts nil - "Use subtle or intense styles for minibuffer and REPL prompts. - -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 colored foreground color. - -The `italic' property adds a slant to the font's forms (italic or -oblique forms, depending on the typeface). - -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 italic) - (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-prompts (quote (extrabold italic)))" - :group 'modus-themes - :package-version '(modus-themes . "4.0.0") - :version "30.1" - :type `(set :tag "Properties" :greedy t - (const :tag "Italic font slant" italic) - ,modus-themes--weight-widget) - :link '(info-link "(modus-themes) Command prompts")) +(make-obsolete-variable + 'modus-themes-completions + "Completion matches are bold when `modus-themes-bold-constructs' is non-nil" + "5.3.0") +(make-obsolete-variable + 'modus-themes-prompts + "Prompts are now bold if `modus-themes-bold-constructs' is non-nil" + "5.3.0") (defcustom modus-themes-common-palette-user nil "Common user-defined colors to extend all the themes' palettes. @@ -649,6 +533,8 @@ represents." (defconst modus-themes-common-palette-mappings '((fringe bg-dim) + (fg-region fg-main) + (fg-mode-line-active fg-main) ;; Button mappings @@ -909,14 +795,13 @@ represents." ;; Special purpose (bg-completion "#c0deff") + (bg-popup "#f3f3f3") (bg-hover "#b2e4dc") (bg-hover-secondary "#f5d0a0") (bg-hl-line "#dae5ec") (bg-region "#bdbdbd") - (fg-region "#000000") (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") @@ -1069,7 +954,6 @@ represents." ;; Prose mappings - (fg-prose-code cyan-cooler) (fg-prose-macro magenta-cooler) (fg-prose-verbatim magenta-warmer) @@ -1238,14 +1122,13 @@ exists in the palette and is associated with a HEX-VALUE.") ;; Special purpose (bg-completion "#f0c1cf") + (bg-popup "#f6eddd") (bg-hover "#b2e4dc") (bg-hover-secondary "#dfe09f") (bg-hl-line "#f1d5d0") (bg-region "#c2bcb5") - (fg-region "#000000") (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") @@ -1565,14 +1448,13 @@ exists in the palette and is associated with a HEX-VALUE.") ;; Special purpose (bg-completion "#c0deff") + (bg-popup "#f3f3f3") (bg-hover "#b2e4dc") (bg-hover-secondary "#e5d7a0") (bg-hl-line "#dae5ec") (bg-region "#bdbdbd") - (fg-region "#000000") (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") @@ -1894,14 +1776,13 @@ exists in the palette and is associated with a HEX-VALUE.") ;; Special purpose (bg-completion "#afdfef") + (bg-popup "#f3f3f3") (bg-hover "#ffafbc") (bg-hover-secondary "#abdfdd") (bg-hl-line "#dfeaec") (bg-region "#bdbdbd") - (fg-region "#000000") (bg-mode-line-active "#afe0f2") - (fg-mode-line-active "#0f0f0f") (border-mode-line-active "#2f4f44") (bg-mode-line-inactive "#e6e6e6") (fg-mode-line-inactive "#585858") @@ -2221,14 +2102,13 @@ exists in the palette and is associated with a HEX-VALUE.") ;; Special purpose (bg-completion "#2f447f") + (bg-popup "#0c0c0c") (bg-hover "#45605e") (bg-hover-secondary "#654a39") (bg-hl-line "#2f3849") (bg-region "#5a5a5a") - (fg-region "#ffffff") (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") @@ -2548,14 +2428,13 @@ exists in the palette and is associated with a HEX-VALUE.") ;; Special purpose (bg-completion "#483d8a") + (bg-popup "#14162c") (bg-hover "#45605e") (bg-hover-secondary "#64404f") (bg-hl-line "#303a6f") (bg-region "#555a66") - (fg-region "#ffffff") (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") @@ -2875,14 +2754,13 @@ exists in the palette and is associated with a HEX-VALUE.") ;; Special purpose (bg-completion "#2f447f") + (bg-popup "#0c0c0c") (bg-hover "#45605e") (bg-hover-secondary "#604c30") (bg-hl-line "#2f3849") (bg-region "#5a5a5a") - (fg-region "#ffffff") (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") @@ -3202,14 +3080,13 @@ exists in the palette and is associated with a HEX-VALUE.") ;; Special purpose (bg-completion "#004253") + (bg-popup "#0c0c0c") (bg-hover "#8e3e3b") (bg-hover-secondary "#204853") (bg-hl-line "#2f3849") (bg-region "#5a5a5a") - (fg-region "#ffffff") (bg-mode-line-active "#003c52") - (fg-mode-line-active "#f0f0f0") (border-mode-line-active "#5f8fb4") (bg-mode-line-inactive "#2d2d2d") (fg-mode-line-inactive "#969696") @@ -3748,6 +3625,31 @@ Info node `(modus-themes) Option for palette overrides'.") ;;;; Helper functions for theme setup +(defvar modus-themes--hex-regexp + (concat + "\\`#" + "\\(?:[[:xdigit:]]\\{3\\}" + "\\|" + "[[:xdigit:]]\\{6\\}\\)" + "\\'") + "Regular expression to match a color in hexadecimal RGB notation.") + +(defun modus-themes--color-hex-p (color) + "Return non-nil if COLOR is hexadecimal RGB." + (and (stringp color) (string-match-p modus-themes--hex-regexp color))) + +(defun modus-themes--hex-or-name-to-rgb (color) + "Convert COLOR to a list of normalized RGB values. +COLOR can be a hexadecimal RGB value like #123456 or a named color +like those produced by `list-colors-display'." + (cond + ((modus-themes--color-hex-p color) + (when-let* ((spec (color-values-from-color-spec color))) + (mapcar (lambda (x) (/ x 65535.0)) spec))) + ((color-name-to-rgb color)) + (t + (error "The color `%s' cannot be resolved" color)))) + ;; This is the WCAG formula: https://www.w3.org/TR/WCAG20-TECHS/G18.html (defun modus-themes--wcag-contribution (channel weight) "Return the CHANNEL contribution to overall luminance given WEIGHT." @@ -3756,23 +3658,50 @@ Info node `(modus-themes) Option for palette overrides'.") (/ channel 12.92) (expt (/ (+ channel 0.055) 1.055) 2.4)))) -(defun modus-themes-wcag-formula (hex) - "Get WCAG value of color value HEX. -The value is defined in hexadecimal RGB notation, such #123456." - (let ((channels (color-name-to-rgb hex)) - (weights '(0.2126 0.7152 0.0722)) - contribution) - (while channels - (push (modus-themes--wcag-contribution (pop channels) (pop weights)) contribution)) - (apply #'+ contribution))) +(defun modus-themes-wcag-formula (color) + "Get WCAG value of color value COLOR. +The value is defined in hexadecimal RGB notation, such #123456, or +as a named color like those of `list-colors-display'." + (when-let* ((channels (modus-themes--hex-or-name-to-rgb color))) + (let ((weights '(0.2126 0.7152 0.0722)) + (contribution nil)) + (while channels + (push (modus-themes--wcag-contribution (pop channels) (pop weights)) contribution)) + (apply #'+ contribution)))) ;;;###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)))) +(defun modus-themes-contrast (color-1 color-2) + "Measure WCAG contrast ratio between COLOR-1 and COLOR-2. +Color values are of the form accepted by `modus-themes-wcag-formula'." + (if-let* ((hex1-weight (modus-themes-wcag-formula color-1)) + (hex2-weight (modus-themes-wcag-formula color-2))) + (let ((contrast (/ (+ hex1-weight 0.05) (+ hex2-weight 0.05)))) + (max contrast (/ contrast))) + (error "Both `%s' and `%s' must be valid hexadecimal RGB or named colors" color-1 color-2))) + +(defun modus-themes--color-eight-to-six-digits (hex-color) + "Reduce representation of hexadecimal RGB HEX-COLOR from eight to six digits. +If HEX-COLOR is three or six digits, then return it as is." + (if (modus-themes--color-hex-p hex-color) + hex-color + (let* ((color-no-hash (substring hex-color 1)) + (triplets (seq-split color-no-hash 4)) + (triplets-shortened (mapcar + (lambda (string) + (substring string 0 2)) + triplets))) + (concat "#" (string-join triplets-shortened))))) + +(defun modus-themes-adjust-value (color percentage) + "Adjust value of COLOR by PERCENTAGE. +COLOR is either a hexadecimal RGB string or a named color." + (when-let* ((rgb (modus-themes--hex-or-name-to-rgb color))) + (pcase-let* ((`(,r ,g ,b) rgb) + (`(,h ,s ,l) (color-rgb-to-hsl r g b)) + (adjusted (color-lighten-hsl h s l percentage)) + (adjusted-rgb (apply #'color-hsl-to-rgb adjusted)) + (value (apply #'color-rgb-to-hex adjusted-rgb))) + (modus-themes--color-eight-to-six-digits value)))) (defvar modus-themes-registered-items nil "List of defined themes. @@ -3917,10 +3846,18 @@ If THEME is unknown, return nil. Else return (append OVERRIDES USER CORE)." (defun modus-themes--disable-themes (themes) "Disable THEMES per `modus-themes-disable-other-themes'." - (mapc #'disable-theme - (if modus-themes-disable-other-themes - themes - (seq-filter #'modus-themes--modus-theme-p themes)))) + (mapc + #'disable-theme + (if modus-themes-disable-other-themes + themes + (seq-filter #'modus-themes--modus-theme-p themes)))) + +(defun modus-themes--get-color-schemes () + "Return `custom-enabled-themes' of :kind `color-scheme'." + (seq-filter + (lambda (theme) + (eq (plist-get (get theme 'theme-properties) :kind) 'color-scheme)) + custom-enabled-themes)) (defun modus-themes-load-theme (theme &optional hook) "Load THEME while disabling other themes. @@ -3933,11 +3870,16 @@ after loading the THEME. If HOOK, then call that instead. Return THEME." (load-theme theme :no-confirm) - (modus-themes--disable-themes (remq theme custom-enabled-themes)) + (modus-themes--disable-themes (remq theme (modus-themes--get-color-schemes))) (run-hooks (or hook 'modus-themes-after-load-theme-hook)) theme) -(defun modus-themes--retrieve-palette-value (color palette) +(define-obsolete-function-alias + 'modus-themes--retrieve-palette-value + 'modus-themes-retrieve-palette-value + "5.3.0") + +(defun modus-themes-retrieve-palette-value (color palette) "Return COLOR from PALETTE. Use recursion until COLOR is retrieved as a string. Refrain from doing so if the value of COLOR is not a key in the PALETTE. @@ -3945,8 +3887,7 @@ doing so if the value of COLOR is not a key in the PALETTE. Return `unspecified' if the value of COLOR cannot be determined. This symbol is accepted by faces and is thus harmless. -This function is used in the macros `modus-themes-theme', -`modus-themes-with-colors'." +This function is used in the macro `modus-themes-theme'" (let ((value (car (alist-get color palette)))) (cond ((or (stringp value) @@ -3954,7 +3895,7 @@ This function is used in the macros `modus-themes-theme', value) ((and (symbolp value) value) - (modus-themes--retrieve-palette-value value palette)) + (modus-themes-retrieve-palette-value value palette)) (t 'unspecified)))) @@ -3980,7 +3921,7 @@ symbol, which is safe when used as a face attribute's value." (when theme (modus-themes-activate theme)) (if-let* ((palette (modus-themes-get-theme-palette theme with-overrides :with-user-palette)) - (value (modus-themes--retrieve-palette-value color palette))) + (value (modus-themes-retrieve-palette-value color palette))) value 'unspecified)) @@ -4094,10 +4035,9 @@ Disable other themes per `modus-themes-disable-other-themes'." (interactive) (if-let* ((themes (modus-themes-known-p modus-themes-to-toggle)) (one (car themes)) - (two (cadr themes)) - (current (modus-themes-get-current-theme))) - (modus-themes-load-theme (if (eq current one) two one)) - (modus-themes-load-theme (modus-themes-select-prompt "No valid theme to toggle; select other")))) + (two (cadr themes))) + (modus-themes-load-theme (if (eq (modus-themes-get-current-theme) one) two one)) + (modus-themes-load-theme (modus-themes-select-prompt "No two valid themes to toggle; select other")))) ;;;;; Rotate through a list of themes @@ -4206,6 +4146,18 @@ Run `modus-themes-after-load-theme-hook' after loading a theme." ;;;;; Preview a theme palette +(defun modus-themes-color-dark-p (color) + "Return non-nil if hexadecimal RGB COLOR is dark. +Test that COLOR has more contrast against white than black." + (> (modus-themes-contrast color "#ffffff") + (modus-themes-contrast color "#000000"))) + +(defun modus-themes-get-readable-foreground (color) + "Get readable foreground for background hexadecimal RGB COLOR." + (if (modus-themes-color-dark-p color) + "#ffffff" + "#000000")) + (defun modus-themes--list-colors-get-mappings (palette) "Get the semantic palette entries in PALETTE. PALETTE is the value of a variable like `modus-operandi-palette'." @@ -4238,8 +4190,8 @@ PALETTE is the value of a variable like `modus-operandi-palette'." (propertize value-string 'face `( :foreground ,color)) (propertize value-string-padded 'face `( :background ,color :foreground ,(if (string= color "unspecified") - (readable-foreground-color (modus-themes-get-color-value 'bg-main nil theme)) - (readable-foreground-color color)))))))) + (modus-themes-get-readable-foreground (modus-themes-get-color-value 'bg-main nil theme)) + (modus-themes-get-readable-foreground color)))))))) palette))) (defvar modus-themes-current-preview nil) @@ -4444,32 +4396,6 @@ list given LIST-PRED, using DEFAULT as a fallback." (when modus-themes-variable-pitch-ui (list :inherit 'variable-pitch))) -(defun modus-themes--prompt (fg bg) - "Conditional use of colors for text prompt faces. -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)) - 'bold-italic) - ((memq 'italic properties) - 'italic) - ((memq 'bold properties) - 'bold) - ('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 semibold bold heavy extrabold ultrabold) @@ -4510,53 +4436,6 @@ Optional OL is the color of an overline." 'unspecified) :weight (or weight '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 'selection var) (alist-get t var))) - (italic (memq 'italic properties)) - (weight (modus-themes--weight properties)) - (bold (when (and weight (eq weight 'bold)) 'bold))) - (list - :inherit - (cond - ((and italic weight (not (eq weight 'bold))) - 'italic) - ((and weight (not (eq weight 'bold))) - 'unspecified) - (italic 'bold-italic) - ('bold)) - :background bg - :foreground 'unspecified - :underline - (if (memq 'underline properties) t 'unspecified) - :weight - (if (and weight (null bold)) weight 'unspecified)))) - -(defun modus-themes--completion-match (fg bg) - "Styles for `modus-themes-completions'. -FG and BG are the main colors." - (let* ((var (modus-themes--list-or-warn 'modus-themes-completions)) - (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))) - (list - :inherit - (cond - ((and italic weight (not (eq weight 'bold))) - 'italic) - ((and weight (not (eq weight 'bold))) - 'unspecified) - (italic 'bold-italic) - ('bold)) - :background bg - :foreground fg - :underline - (if (memq 'underline properties) t 'unspecified) - :weight - (if (and weight (null bold)) weight 'unspecified)))) - ;; NOTE 2025-11-23: In theory we need the `modus-themes--box' ;; equivalent for this: @@ -4564,7 +4443,7 @@ FG and BG are the main colors." ;; :underline (:style wave :color unspecified) ;; ;; I checked all the relevant faces and feel that users will not be -;; benefiting form such a style anyway. What would be the point of a +;; benefitting form such a style anyway. What would be the point of a ;; spell checker that cannot highlight its errors, for example? ;; Granted, we could have another kind of highlight, but I am here ;; focusing on the use of this: @@ -4604,12 +4483,6 @@ If COLOR is unspecified, then return :box unspecified." `(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)))) -;;;;; completion frameworks - `(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 ((,c ,@(modus-themes--bold-weight)))) `(modus-themes-fixed-pitch ((,c ,@(modus-themes--fixed-pitch)))) @@ -4621,7 +4494,6 @@ If COLOR is unspecified, then return :box unspecified." (((supports :box t)) ,@(modus-themes--box border 1 'released-button)) (t :underline ,border))) - `(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))) @@ -4634,17 +4506,18 @@ If COLOR is unspecified, then return :box unspecified." `(italic ((,c :slant italic))) `(cursor ((,c :background ,cursor))) `(fringe ((,c :background ,fringe :foreground ,fg-main))) - `(scroll-bar ((,c :background ,fringe :foreground ,border))) + `(margin ((,c :background ,fringe :foreground ,fg-main))) + `(scroll-bar ((,c :background ,bg-main :foreground ,border))) `(tool-bar ((,c :background ,bg-dim :foreground ,fg-main))) `(vertical-border ((,c :foreground ,border))) ;;;;; basic and/or ungrouped styles `(abbrev-table-name ((,c :inherit modus-themes-heading-1))) `(appt-notification ((,c :inherit modus-themes-bold :foreground ,modeline-err))) - `(blink-matching-paren-offscreen ((,c :background ,bg-paren-match))) + `(blink-matching-paren-offscreen ((,c :background ,bg-paren-match :foreground ,fg-paren-match :underline ,underline-paren-match))) `(buffer-menu-buffer ((,c :foreground ,name))) `(child-frame-border ((,c :background ,border))) `(comint-highlight-input ((,c :inherit modus-themes-bold))) - `(comint-highlight-prompt ((,c :inherit modus-themes-prompt))) + `(comint-highlight-prompt ((,c :inherit bold :background ,bg-prompt :foreground ,fg-prompt))) `(confusingly-reordered ((,c :underline (:style wave :color ,underline-err)))) `(edmacro-label ((,c :inherit modus-themes-bold :foreground ,accent-0))) `(error ((,c :inherit modus-themes-bold :foreground ,err))) @@ -4662,13 +4535,13 @@ If COLOR is unspecified, then return :box unspecified." `(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))) + `(minibuffer-prompt ((,c :inherit bold :background ,bg-prompt :foreground ,fg-prompt))) `(minibuffer-nonselected ((,c :inverse-video t))) `(mm-command-output ((,c :foreground ,mail-part))) `(mm-uu-extract ((,c :foreground ,mail-part))) `(next-error ((,c :background ,bg-prominent-err :foreground ,fg-prominent-err))) `(pgtk-im-0 ((,c :background ,bg-prominent-note :foreground ,fg-prominent-note))) - `(read-multiple-choice-face ((,c :inherit bold :background ,bg-mark-select :foreground ,fg-mark-select))) + `(read-multiple-choice-face ((,c :inverse-video t))) `(rectangle-preview ((,c :background ,bg-active :foreground ,fg-main))) `(region ((,c :background ,bg-region :foreground ,fg-region))) `(secondary-selection ((,c :background ,bg-hover-secondary :foreground ,fg-main))) @@ -4785,7 +4658,7 @@ If COLOR is unspecified, then return :box unspecified." `(font-latex-doctex-preprocessor-face ((,c :foreground ,preprocessor))) `(font-latex-italic-face ((,c :inherit italic))) `(font-latex-math-face ((,c :foreground ,constant))) - `(font-latex-script-char-face ((,c :inherit modus-themes-bold :foreground ,builtin))) + `(font-latex-script-char-face ((,c :inherit modus-themes-bold :foreground ,keybind))) `(font-latex-sectioning-5-face ((,c :inherit modus-themes-bold :foreground ,fg-alt))) `(font-latex-sedate-face ((,c :inherit modus-themes-bold :foreground ,keyword))) `(font-latex-slide-title-face ((,c :inherit modus-themes-heading-1))) @@ -4824,8 +4697,8 @@ If COLOR is unspecified, then return :box unspecified." `(binder-sidebar-tags ((,c :foreground ,variable))) ;;;;; breadcrumb `(breadcrumb-face ((,c :foreground ,fg-alt))) - `(breadcrumb-imenu-leaf-face ((,c :inherit modus-themes-bold :foreground ,modeline-info))) ; same as `which-func' - `(breadcrumb-project-leaf-face ((,c :inherit modus-themes-bold))) + `(breadcrumb-imenu-leaf-face ((,c :inherit (modus-themes-bold breadcrumb-face) :foreground ,modeline-info))) ; same as `which-func' + `(breadcrumb-project-leaf-face ((,c :inherit (modus-themes-bold breadcrumb-face)))) ;;;;; bongo `(bongo-album-title (( ))) `(bongo-artist ((,c :foreground ,accent-0))) @@ -4906,7 +4779,7 @@ If COLOR is unspecified, then return :box unspecified." `(change-log-name ((,c :foreground ,name))) `(log-edit-header ((,c :inherit modus-themes-bold))) `(log-edit-headers-separator ((,c :height 1 :background ,border :extend t))) - `(log-edit-summary ((,c :inherit modus-themes-bold :foreground ,fg-alt))) + `(log-edit-summary ((,c :inherit modus-themes-bold :foreground ,info))) `(log-edit-unknown-header ((,c :foreground ,fg-dim))) `(log-view-commit-body (( ))) `(log-view-file ((,c :inherit modus-themes-bold))) @@ -4919,14 +4792,14 @@ If COLOR is unspecified, then return :box unspecified." `(cider-fringe-good-face ((,c :foreground ,info))) `(cider-instrumented-face ((,c :box ,err))) `(cider-reader-conditional-face ((,c :inherit modus-themes-bold :foreground ,type))) - `(cider-repl-prompt-face ((,c :inherit modus-themes-prompt))) + `(cider-repl-prompt-face ((,c :inherit bold :background ,bg-prompt :foreground ,fg-prompt))) `(cider-repl-stderr-face ((,c :foreground ,err))) `(cider-repl-stdout-face (( ))) `(cider-warning-highlight-face ((,c :underline (:style wave :color ,underline-warning)))) ;;;;; circe (and lui) `(circe-fool-face ((,c :foreground ,fg-dim))) `(circe-highlight-nick-face ((,c :foreground ,err))) - `(circe-prompt-face ((,c :inherit modus-themes-prompt))) + `(circe-prompt-face ((,c :inherit bold :background ,bg-prompt :foreground ,fg-prompt))) `(circe-server-face ((,c :foreground ,fg-dim))) `(lui-button-face ((,c :background ,bg-link :foreground ,fg-link :underline ,underline-link))) `(lui-highlight-face ((,c :foreground ,err))) @@ -4939,23 +4812,23 @@ If COLOR is unspecified, then return :box unspecified." ;;;;; column-enforce-mode `(column-enforce-face ((,c :background ,bg-prominent-err :foreground ,fg-prominent-err))) ;;;;; company-mode - `(company-echo-common ((,c :inherit modus-themes-completion-match-0))) - `(company-preview ((,c :background ,bg-dim :foreground ,fg-dim))) - `(company-preview-common ((,c :inherit modus-themes-completion-match-0))) + `(company-echo-common ((,c :inherit modus-themes-bold :background ,bg-completion-match-0 :foreground ,fg-completion-match-0))) + `(company-preview ((,c :foreground ,fg-dim))) + `(company-preview-common ((,c :inherit modus-themes-bold :background ,bg-completion-match-0 :foreground ,fg-completion-match-0))) `(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 :inherit modus-themes-fixed-pitch :background ,bg-dim))) + `(company-tooltip ((,c :inherit modus-themes-fixed-pitch :background ,bg-popup))) `(company-tooltip-annotation ((,c :inherit modus-themes-slant :foreground ,docstring))) - `(company-tooltip-common ((,c :inherit modus-themes-completion-match-0))) + `(company-tooltip-common ((,c :inherit modus-themes-bold :background ,bg-completion-match-0 :foreground ,fg-completion-match-0))) `(company-tooltip-deprecated ((,c :inherit modus-themes-fixed-pitch :background ,bg-dim :strike-through t))) `(company-tooltip-mouse ((,c :background ,bg-hover :foreground ,fg-main))) `(company-tooltip-scrollbar-thumb ((,c :background ,fg-alt))) `(company-tooltip-scrollbar-track ((,c :background ,bg-inactive))) `(company-tooltip-search ((,c :background ,bg-hover-secondary :foreground ,fg-main))) `(company-tooltip-search-selection ((,c :background ,bg-hover-secondary :foreground ,fg-main :underline t))) - `(company-tooltip-selection ((,c :inherit modus-themes-completion-selected))) + `(company-tooltip-selection ((,c :background ,bg-completion))) ;;;;; compilation `(compilation-column-number ((,c :foreground ,fg-dim))) `(compilation-error ((,c :inherit modus-themes-bold :foreground ,err))) @@ -4972,12 +4845,14 @@ If COLOR is unspecified, then return :box unspecified." ;; `completion-preview', then we should remember to customize ;; `completion-preview-adapt-background-color' accordingly. `(completion-preview-common ((,c :inherit completion-preview :underline t))) - `(completion-preview-exact ((,c :inherit (modus-themes-completion-match-0 completion-preview)))) + `(completion-preview-exact ((,c :inherit (modus-themes-bold completion-preview) :background ,bg-completion-match-0 :foreground ,fg-completion-match-0))) ;;;;; completions `(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))) - `(completions-highlight ((,c :inherit modus-themes-completion-selected))) + `(completions-common-part ((,c :inherit modus-themes-bold :background ,bg-completion-match-0 :foreground ,fg-completion-match-0))) + `(completions-group-title ((,c :inherit modus-themes-slant :foreground ,name :height 0.9))) + `(completions-group-separator ((,c :strike-through t :foreground ,border))) + `(completions-first-difference ((,c :inherit modus-themes-bold :background ,bg-completion-match-1 :foreground ,fg-completion-match-1))) + `(completions-highlight ((,c :background ,bg-completion))) ;;;;; consult `(consult-async-split ((,c :foreground ,err))) `(consult-file ((,c :inherit modus-themes-bold :foreground ,info))) @@ -4989,10 +4864,10 @@ If COLOR is unspecified, then return :box unspecified." `(consult-line-number-prefix ((,c :foreground ,fg-dim))) `(consult-preview-insertion ((,c :background ,bg-dim))) ;;;;; corfu - `(corfu-current ((,c :inherit modus-themes-completion-selected))) + `(corfu-current ((,c :background ,bg-completion))) `(corfu-bar ((,c :background ,fg-dim))) `(corfu-border ((,c :background ,bg-active))) - `(corfu-default ((,c :inherit modus-themes-fixed-pitch :background ,bg-dim))) + `(corfu-default ((,c :inherit modus-themes-fixed-pitch :background ,bg-popup))) ;;;;; corfu-candidate-overlay `(corfu-candidate-overlay-face ((,c :foreground ,fg-dim))) ;;;;; corfu-quick @@ -5192,7 +5067,11 @@ If COLOR is unspecified, then return :box unspecified." `(disk-usage-symlink ((,c :background ,bg-link-symbolic :foreground ,fg-link-symbolic :underline ,underline-link-symbolic))) `(disk-usage-symlink-directory ((,c :background ,bg-link-symbolic :foreground ,fg-link-symbolic :underline ,underline-link-symbolic))) ;;;;; display-fill-column-indicator-mode - `(fill-column-indicator ((,c :height 1 :background ,bg-active :foreground ,bg-active))) + `(fill-column-indicator + ((((type tty)) + :height 1.0 :background unspecified :foreground ,bg-active) + (,c + :height 1 :background ,bg-active :foreground ,bg-active))) ;;;;; doom-modeline `(doom-modeline-bar ((,c :background ,blue))) ; special case like `centaur-tabs-active-bar-face' `(doom-modeline-bar-inactive ((,c :background ,border))) @@ -5281,6 +5160,12 @@ If COLOR is unspecified, then return :box unspecified." `(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-show-header-face ((,c :inherit modus-themes-bold))) + `(elfeed-show-title-face ((,c :inherit modus-themes-bold :foreground ,mail-subject))) + `(elfeed-show-author-face ((,c :inherit modus-themes-bold :foreground ,mail-recipient))) + `(elfeed-show-date-face ((,c :foreground ,date-common))) + `(elfeed-show-feed-face ((,c :foreground ,accent-1))) + `(elfeed-show-tags-face ((,c :foreground ,accent-0))) ;;;;; elfeed-score `(elfeed-score-date-face ((,c :foreground ,date-common))) `(elfeed-score-debug-level-face ((,c :inherit modus-themes-bold))) @@ -5398,7 +5283,7 @@ If COLOR is unspecified, then return :box unspecified." `(erc-nick-prefix-face ((,c :inherit erc-nick-default-face))) `(erc-notice-face ((,c :inherit modus-themes-slant :foreground ,comment))) `(erc-pal-face ((,c :inherit modus-themes-bold :foreground ,accent-1))) - `(erc-prompt-face ((,c :inherit modus-themes-prompt))) + `(erc-prompt-face ((,c :inherit bold :background ,bg-prompt :foreground ,fg-prompt))) `(erc-timestamp-face ((,c :foreground ,date-common))) `(erc-underline-face ((,c :inherit underline))) ;;;;; ert @@ -5421,7 +5306,7 @@ If COLOR is unspecified, then return :box unspecified." `(eshell-ls-special ((,c :foreground ,accent-3))) `(eshell-ls-symlink ((,c :background ,bg-link :foreground ,fg-link :underline ,underline-link))) `(eshell-ls-unreadable ((,c :foreground ,fg-dim))) - `(eshell-prompt ((,c :inherit modus-themes-prompt))) + `(eshell-prompt ((,c :inherit bold :background ,bg-prompt :foreground ,fg-prompt))) ;;;;; eshell-fringe-status `(eshell-fringe-status-failure ((,c :foreground ,err))) `(eshell-fringe-status-success ((,c :foreground ,info))) @@ -5480,7 +5365,7 @@ If COLOR is unspecified, then return :box unspecified." `(flyspell-duplicate ((,c :underline (:style wave :color ,underline-warning)))) `(flyspell-incorrect ((,c :underline (:style wave :color ,underline-err)))) ;;;;; flx - `(flx-highlight-face ((,c :inherit modus-themes-completion-match-0))) + `(flx-highlight-face ((,c :inherit modus-themes-bold :background ,bg-completion-match-0 :foreground ,fg-completion-match-0))) ;;;;; focus `(focus-unfocused ((,c :foreground "gray50"))) ;;;;; fold-this @@ -5536,7 +5421,7 @@ If COLOR is unspecified, then return :box unspecified." `(geiser-font-lock-image-button ((,c :foreground ,info :underline t))) `(geiser-font-lock-repl-input ((,c :inherit modus-themes-bold))) `(geiser-font-lock-repl-output ((,c :inherit modus-themes-bold :foreground ,keyword))) - `(geiser-font-lock-repl-prompt ((,c :inherit modus-themes-prompt))) + `(geiser-font-lock-repl-prompt ((,c :inherit bold :background ,bg-prompt :foreground ,fg-prompt))) `(geiser-font-lock-xref-header ((,c :inherit modus-themes-bold))) `(geiser-font-lock-xref-link ((,c :background ,bg-link :foreground ,fg-link :underline ,underline-link))) ;;;;; git-commit @@ -5548,7 +5433,7 @@ If COLOR is unspecified, then return :box unspecified." `(git-commit-keyword ((,c :foreground ,keyword))) `(git-commit-nonempty-second-line ((,c :foreground ,err))) `(git-commit-overlong-summary ((,c :foreground ,warning))) - `(git-commit-summary ((,c :inherit modus-themes-bold :foreground ,fg-alt))) + `(git-commit-summary ((,c :inherit modus-themes-bold :foreground ,info))) ;;;;; git-gutter `(git-gutter:added ((,c :background ,bg-added-fringe))) `(git-gutter:deleted ((,c :background ,bg-removed-fringe))) @@ -5719,15 +5604,15 @@ If COLOR is unspecified, then return :box unspecified." `(ibuffer-marked ((,c :inherit bold :background ,bg-mark-select :foreground ,fg-mark-select))) `(ibuffer-title ((,c :inherit bold))) ;;;;; icomplete - `(icomplete-first-match ((,c :inherit modus-themes-completion-match-0))) + `(icomplete-first-match ((,c :inherit modus-themes-bold :background ,bg-completion-match-0 :foreground ,fg-completion-match-0))) `(icomplete-vertical-selected-prefix-indicator-face ((,c :inherit modus-themes-bold :foreground ,keybind))) `(icomplete-vertical-unselected-prefix-indicator-face ((,c :foreground ,fg-dim))) - `(icomplete-selected-match ((,c :inherit modus-themes-completion-selected))) + `(icomplete-selected-match ((,c :background ,bg-completion))) ;;;;; ido-mode - `(ido-first-match ((,c :inherit modus-themes-completion-match-0))) + `(ido-first-match ((,c :inherit modus-themes-bold :background ,bg-completion-match-0 :foreground ,fg-completion-match-0))) `(ido-incomplete-regexp ((,c :foreground ,err))) `(ido-indicator ((,c :inherit modus-themes-bold))) - `(ido-only-match ((,c :inherit modus-themes-completion-match-0))) + `(ido-only-match ((,c :inherit modus-themes-bold :background ,bg-completion-match-0 :foreground ,fg-completion-match-0))) `(ido-subdir ((,c :foreground ,keyword))) `(ido-virtual ((,c :foreground ,warning))) ;;;;; iedit @@ -5794,6 +5679,9 @@ If COLOR is unspecified, then return :box unspecified." `(info-colors-ref-item-type ((,c :inherit modus-themes-bold :foreground ,type))) `(info-colors-ref-item-user-option ((,c :foreground ,variable))) `(info-colors-ref-item-variable ((,c :foreground ,variable))) +;;;;; institution-calendar + `(institution-calendar-term-indicator-regular-week ((,c :background ,bg-dim :foreground ,fg-alt))) + `(institution-calendar-term-indicator-extra-week ((,c :foreground ,fg-dim))) ;;;;; ioccur `(ioccur-cursor ((,c :foreground ,fg-main))) `(ioccur-invalid-regexp ((,c :foreground ,err))) @@ -5814,12 +5702,12 @@ If COLOR is unspecified, then return :box unspecified." ;;;;; ivy `(ivy-action ((,c :inherit (bold modus-themes-fixed-pitch) :foreground ,keybind))) `(ivy-confirm-face ((,c :foreground ,info))) - `(ivy-current-match ((,c :inherit modus-themes-completion-selected))) + `(ivy-current-match ((,c :background ,bg-completion))) `(ivy-match-required-face ((,c :foreground ,err))) `(ivy-minibuffer-match-face-1 (( ))) - `(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-minibuffer-match-face-2 ((,c :inherit modus-themes-bold :background ,bg-completion-match-0 :foreground ,fg-completion-match-0))) + `(ivy-minibuffer-match-face-3 ((,c :inherit modus-themes-bold :background ,bg-completion-match-1 :foreground ,fg-completion-match-1))) + `(ivy-minibuffer-match-face-4 ((,c :inherit modus-themes-bold :background ,bg-completion-match-2 :foreground ,fg-completion-match-2))) `(ivy-remote ((,c :inherit modus-themes-slant))) `(ivy-separator ((,c :foreground ,fg-dim))) `(ivy-subdir ((,c :foreground ,keyword))) @@ -5912,6 +5800,25 @@ If COLOR is unspecified, then return :box unspecified." `(ledger-font-xact-highlight-face ((,c :background ,bg-hl-line :extend t))) ;;;;; leerzeichen `(leerzeichen ((,c :background ,bg-inactive))) +;;;;; lin + `(lin-blue ((,c :background ,bg-blue-subtle))) + `(lin-cyan ((,c :background ,bg-cyan-subtle))) + `(lin-green ((,c :background ,bg-green-subtle))) + `(lin-magenta ((,c :background ,bg-magenta-subtle))) + `(lin-purple ((,c :background ,bg-lavender))) + `(lin-red ((,c :background ,bg-red-subtle))) + `(lin-orange ((,c :background ,bg-ochre))) + `(lin-yellow ((,c :background ,bg-yellow-subtle))) + `(lin-slate ((,c :background ,bg-inactive))) + `(lin-blue-override-fg ((,c :background ,bg-blue-subtle :foreground ,fg-main))) + `(lin-cyan-override-fg ((,c :background ,bg-cyan-subtle :foreground ,fg-main))) + `(lin-green-override-fg ((,c :background ,bg-green-subtle :foreground ,fg-main))) + `(lin-magenta-override-fg ((,c :background ,bg-magenta-subtle :foreground ,fg-main))) + `(lin-purple-override-fg ((,c :background ,bg-lavender :foreground ,fg-main))) + `(lin-red-override-fg ((,c :background ,bg-red-subtle :foreground ,fg-main))) + `(lin-orange-override-fg ((,c :background ,bg-ochre :foreground ,fg-main))) + `(lin-yellow-override-fg ((,c :background ,bg-yellow-subtle :foreground ,fg-main))) + `(lin-slate-override-fg ((,c :background ,bg-inactive :foreground ,fg-main))) ;;;;; 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 @@ -6021,7 +5928,6 @@ If COLOR is unspecified, then return :box unspecified." `(magit-refname-pullreq ((,c :foreground ,fg-dim))) `(magit-refname-stash ((,c :foreground ,fg-dim))) `(magit-refname-wip ((,c :foreground ,fg-dim))) - `(magit-section ((,c :background ,bg-dim :foreground ,fg-main))) `(magit-section-heading ((,c :inherit modus-themes-bold :foreground ,fg-alt))) `(magit-section-heading-selection ((,c :inherit modus-themes-bold :background ,bg-hover-secondary))) `(magit-section-highlight ((,c :background ,bg-dim))) @@ -6102,7 +6008,36 @@ If COLOR is unspecified, then return :box unspecified." `(markdown-missing-link-face ((,c :foreground ,warning))) `(markdown-pre-face ((,c :inherit modus-themes-fixed-pitch :background ,bg-prose-block-contents :extend t))) `(markdown-table-face ((,c :inherit modus-themes-fixed-pitch :foreground ,prose-table))) - `(markdown-url-face ((,c :foreground ,fg-alt))) + `(markdown-url-face ((,c :background ,bg-link :foreground ,fg-link))) +;;;;; markdown-ts-mode + `(markdown-ts-block-quote ((,c :inherit modus-themes-slant :foreground ,docstring))) + `(markdown-ts-bold ((,c :inherit bold))) + `(markdown-ts-code-block ((,c :inherit modus-themes-fixed-pitch :background ,bg-prose-block-contents :extend t))) + `(markdown-ts-code-block-markup-hidden ((,c :inherit modus-themes-fixed-pitch :background ,bg-prose-block-contents :extend t))) + `(markdown-ts-code-span ((,c :inherit modus-themes-fixed-pitch :background ,bg-prose-code :foreground ,fg-prose-code))) + `(markdown-ts-delimiter ((,c :foreground ,fg-dim))) + `(markdown-ts-emphasis ((,c :inherit italic))) + `(markdown-ts-entity-reference ((,c :inherit modus-themes-fixed-pitch :background ,bg-prose-verbatim :foreground ,fg-prose-verbatim))) + `(markdown-ts-hard-line-break-backslash ((,c :foreground ,rx-backslash))) + `(markdown-ts-hard-line-break-backslash-hidden ((,c :foreground ,rx-backslash))) + `(markdown-ts-hard-line-break-space ((,c :foreground ,err :underline t))) + `(markdown-ts-hard-line-break-space-hidden ((,c :foreground ,err :underline t))) + `(markdown-ts-heading-1 ((,c :inherit modus-themes-heading-1))) + `(markdown-ts-heading-2 ((,c :inherit modus-themes-heading-2))) + `(markdown-ts-heading-3 ((,c :inherit modus-themes-heading-3))) + `(markdown-ts-heading-4 ((,c :inherit modus-themes-heading-4))) + `(markdown-ts-heading-5 ((,c :inherit modus-themes-heading-5))) + `(markdown-ts-heading-6 ((,c :inherit modus-themes-heading-6))) + `(markdown-ts-html-block ((,c :inherit modus-themes-fixed-pitch :background ,bg-prose-block-contents :extend t))) + `(markdown-ts-html-tag ((,c :foreground ,fg-dim))) + `(markdown-ts-indented-code-block ((,c :inherit modus-themes-fixed-pitch :background ,bg-prose-block-contents :extend t))) + `(markdown-ts-language-keyword ((,c :inherit modus-themes-fixed-pitch :background ,bg-prose-block-delimiter :foreground ,fg-prose-block-delimiter))) + `(markdown-ts-latex ((,c :foreground ,type))) + `(markdown-ts-numeric-character-reference ((,c :foreground ,number))) + `(markdown-ts-table ((,c :inherit modus-themes-fixed-pitch :foreground ,prose-table))) + `(markdown-ts-table-cell ((,c :inherit modus-themes-fixed-pitch :foreground ,prose-table))) + `(markdown-ts-table-delimiter-cell ((,c :inherit modus-themes-fixed-pitch :foreground ,prose-table))) + `(markdown-ts-table-header ((,c :inherit (modus-themes-bold modus-themes-fixed-pitch) :foreground ,prose-table))) ;;;;; markup-faces (`adoc-mode') `(markup-attribute-face ((,c :inherit modus-themes-fixed-pitch :foreground ,fg-dim))) `(markup-bold-face ((,c :inherit bold))) @@ -6137,7 +6072,7 @@ If COLOR is unspecified, then return :box unspecified." ;;;;; mbdepth `(minibuffer-depth-indicator ((,c :inverse-video t))) ;;;;; mct - `(mct-highlight-candidate ((,c :inherit modus-themes-completion-selected))) + `(mct-highlight-candidate ((,c :background ,bg-completion))) ;;;;; messages `(message-cited-text-1 ((,c :foreground ,mail-cite-0))) `(message-cited-text-2 ((,c :foreground ,mail-cite-1))) @@ -6236,7 +6171,7 @@ If COLOR is unspecified, then return :box unspecified." `(mu4e-view-body-face (( ))) `(mu4e-warning-face ((,c :foreground ,warning))) ;;;;; multiple-cursors - `(mc/cursor-bar-face ((,c :height 1 :foreground ,fg-main :background ,bg-main))) + `(mc/cursor-bar-face ((,c :height 1 :background ,cursor))) `(mc/cursor-face ((,c :inverse-video t))) `(mc/region-face ((,c :background ,bg-region :foreground ,fg-region))) ;;;;; nerd-icons @@ -6367,10 +6302,10 @@ If COLOR is unspecified, then return :box unspecified." ;;;;; olivetti `(olivetti-fringe ((,c :background ,fringe))) ;;;;; orderless - `(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))) + `(orderless-match-face-0 ((,c :inherit modus-themes-bold :background ,bg-completion-match-0 :foreground ,fg-completion-match-0))) + `(orderless-match-face-1 ((,c :inherit modus-themes-bold :background ,bg-completion-match-1 :foreground ,fg-completion-match-1))) + `(orderless-match-face-2 ((,c :inherit modus-themes-bold :background ,bg-completion-match-2 :foreground ,fg-completion-match-2))) + `(orderless-match-face-3 ((,c :inherit modus-themes-bold :background ,bg-completion-match-3 :foreground ,fg-completion-match-3))) ;;;;; org `(org-agenda-calendar-daterange ((,c :foreground ,date-range))) `(org-agenda-calendar-event ((,c :foreground ,date-event))) @@ -6441,7 +6376,7 @@ If COLOR is unspecified, then return :box unspecified." `(org-level-7 ((,c :inherit modus-themes-heading-7))) `(org-level-8 ((,c :inherit modus-themes-heading-8))) `(org-link ((,c :background ,bg-link :foreground ,fg-link :underline ,underline-link))) - `(org-list-dt ((,c :inherit modus-themes-bold :foreground ,fg-alt))) + `(org-list-dt ((,c :inherit bold))) `(org-macro ((,c :inherit modus-themes-fixed-pitch :background ,bg-prose-macro :foreground ,fg-prose-macro))) `(org-meta-line ((,c :inherit modus-themes-fixed-pitch :foreground ,prose-metadata))) `(org-mode-line-clock (( ))) @@ -6467,19 +6402,14 @@ If COLOR is unspecified, then return :box unspecified." `(org-verse ((,c :inherit modus-themes-fixed-pitch :background ,bg-prose-block-contents :extend t))) `(org-warning ((,c :foreground ,warning))) ;;;;; org-habit - ;; NOTE 2025-11-12: We used to have `readable-foreground-color' - ;; for the foreground values of these faces, but that function - ;; breaks the theme if it is loaded in the early-init.el. Maybe - ;; we can find a better solution. I do not want to introduce new - ;; palette entries or a new function just for these faces though. - `(org-habit-alert-face ((,c :background ,bg-graph-yellow-0))) - `(org-habit-alert-future-face ((,c :background ,bg-graph-yellow-1))) - `(org-habit-clear-face ((,c :background ,bg-graph-blue-0))) - `(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-green-0))) - `(org-habit-ready-future-face ((,c :background ,bg-graph-green-1))) + `(org-habit-alert-face ((,c :background ,bg-graph-yellow-0 :foreground ,(modus-themes-get-readable-foreground bg-graph-yellow-0)))) + `(org-habit-alert-future-face ((,c :background ,bg-graph-yellow-1 :foreground ,(modus-themes-get-readable-foreground bg-graph-yellow-1)))) + `(org-habit-clear-face ((,c :background ,bg-graph-blue-0 :foreground ,(modus-themes-get-readable-foreground bg-graph-blue-0)))) + `(org-habit-clear-future-face ((,c :background ,bg-graph-blue-1 :foreground ,(modus-themes-get-readable-foreground bg-graph-blue-1)))) + `(org-habit-overdue-face ((,c :background ,bg-graph-red-0 :foreground ,(modus-themes-get-readable-foreground bg-graph-red-0)))) + `(org-habit-overdue-future-face ((,c :background ,bg-graph-red-1 :foreground ,(modus-themes-get-readable-foreground bg-graph-red-1)))) + `(org-habit-ready-face ((,c :background ,bg-graph-green-0 :foreground ,(modus-themes-get-readable-foreground bg-graph-green-0)))) + `(org-habit-ready-future-face ((,c :background ,bg-graph-green-1 :foreground ,(modus-themes-get-readable-foreground bg-graph-green-1)))) ;;;;; org-journal `(org-journal-calendar-entry-face ((,c :inherit modus-themes-slant :foreground ,date-common))) `(org-journal-calendar-scheduled-face ((,c :inherit modus-themes-slant :foreground ,date-scheduled-subtle))) @@ -6578,10 +6508,10 @@ If COLOR is unspecified, then return :box unspecified." `(proced-uninterruptible-sleep-status-code ((,c :foreground ,err))) `(proced-user (( ))) ;;;;; popup - `(popup-face ((,c :background ,bg-inactive :foreground ,fg-main))) + `(popup-face ((,c :background ,bg-popup :foreground ,fg-main))) `(popup-isearch-match ((,c :background ,bg-search-current :foreground ,fg-search-current))) `(popup-menu-mouse-face ((,c :background ,bg-hover :foreground ,fg-main))) - `(popup-menu-selection-face ((,c :inherit modus-themes-completion-selected))) + `(popup-menu-selection-face ((,c :background ,bg-completion))) `(popup-scroll-bar-background-face ((,c :background ,bg-active))) `(popup-scroll-bar-foreground-face (( ))) `(popup-summary-face ((,c :background ,bg-active :foreground ,fg-dim))) @@ -6621,8 +6551,8 @@ If COLOR is unspecified, then return :box unspecified." `(powerline-evil-replace-face ((,c :background ,bg-main :foreground ,err))) `(powerline-evil-visual-face ((,c :inherit modus-themes-bold :background ,bg-main))) ;;;;; prescient - `(prescient-primary-highlight ((,c :inherit modus-themes-completion-match-0))) - `(prescient-secondary-highlight ((,c :inherit modus-themes-completion-match-1))) + `(prescient-primary-highlight ((,c :inherit modus-themes-bold :background ,bg-completion-match-0 :foreground ,fg-completion-match-0))) + `(prescient-secondary-highlight ((,c :inherit modus-themes-bold :background ,bg-completion-match-1 :foreground ,fg-completion-match-1))) ;;;;; proced `(proced-mark ((,c :inherit modus-themes-bold))) `(proced-marked ((,c :inherit bold :background ,bg-mark-other :foreground ,fg-mark-other))) @@ -6631,6 +6561,13 @@ If COLOR is unspecified, then return :box unspecified." `(prodigy-green-face ((,c :foreground ,info))) `(prodigy-red-face ((,c :foreground ,err))) `(prodigy-yellow-face ((,c :foreground ,warning))) +;;;;; pulsar + `(pulsar-blue ((,c :background ,bg-blue-subtle))) + `(pulsar-cyan ((,c :background ,bg-cyan-subtle))) + `(pulsar-green ((,c :background ,bg-green-subtle))) + `(pulsar-magenta ((,c :background ,bg-magenta-subtle))) + `(pulsar-red ((,c :background ,bg-red-subtle))) + `(pulsar-yellow ((,c :background ,bg-yellow-subtle))) ;;;;; pulse `(pulse-highlight-start-face ((,c :background ,bg-blue-intense :extend t))) ;;;;; pyim @@ -6663,7 +6600,7 @@ If COLOR is unspecified, then return :box unspecified." `(rcirc-nick-in-message ((,c :inherit modus-themes-bold :foreground ,accent-1))) `(rcirc-nick-in-message-full-line ((,c :inherit modus-themes-bold :foreground ,accent-1))) `(rcirc-other-nick ((,c :inherit modus-themes-bold :foreground ,accent-0))) - `(rcirc-prompt ((,c :inherit modus-themes-prompt))) + `(rcirc-prompt ((,c :inherit bold :background ,bg-prompt :foreground ,fg-prompt))) `(rcirc-server ((,c :inherit modus-themes-slant :foreground ,comment))) `(rcirc-timestamp ((,c :foreground ,date-common))) `(rcirc-track-keyword ((,c :inherit modus-themes-bold :foreground ,modeline-warning))) @@ -6770,7 +6707,7 @@ If COLOR is unspecified, then return :box unspecified." `(slime-repl-input-face ((,c :inherit modus-themes-bold))) `(slime-repl-inputed-output-face ((,c :foreground ,string))) `(slime-repl-output-mouseover-face ((,c :background ,bg-hover :foreground ,fg-main))) - `(slime-repl-prompt-face ((,c :inherit modus-themes-prompt))) + `(slime-repl-prompt-face ((,c :inherit bold :background ,bg-prompt :foreground ,fg-prompt))) `(slime-style-warning-face ((,c :underline (:style wave :color ,underline-note)))) `(slime-warning-face ((,c :underline (:style wave :color ,underline-warning)))) ;;;;; sly @@ -6780,7 +6717,7 @@ If COLOR is unspecified, then return :box unspecified." `(sly-error-face ((,c :underline (:style wave :color ,underline-err)))) `(sly-mode-line ((,c :inherit italic :foreground ,modeline-info))) `(sly-mrepl-output-face ((,c :foreground ,string))) - `(sly-mrepl-prompt-face ((,c :inherit modus-themes-prompt))) + `(sly-mrepl-prompt-face ((,c :inherit bold :background ,bg-prompt :foreground ,fg-prompt))) `(sly-note-face ((,c :underline (:style wave :color ,underline-note)))) `(sly-stickers-placed-face ((,c :background ,bg-inactive))) `(sly-style-warning-face ((,c :underline (:style wave :color ,underline-note)))) @@ -6843,14 +6780,14 @@ If COLOR is unspecified, then return :box unspecified." `(switch-window-label ((,c :inherit (bold modus-themes-reset-soft) :height 1.5 :foreground ,err))) ; same as `aw-leading-char-face' ;;;;; swiper `(swiper-background-match-face-1 (( ))) - `(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-background-match-face-2 ((,c :inherit modus-themes-bold :background ,bg-completion-match-0 :foreground ,fg-completion-match-0))) + `(swiper-background-match-face-3 ((,c :inherit modus-themes-bold :background ,bg-completion-match-1 :foreground ,fg-completion-match-1))) + `(swiper-background-match-face-4 ((,c :inherit modus-themes-bold :background ,bg-completion-match-2 :foreground ,fg-completion-match-2))) `(swiper-line-face ((,c :background ,bg-hl-line :extend t))) `(swiper-match-face-1 (( ))) - `(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))) + `(swiper-match-face-2 ((,c :inherit modus-themes-bold :background ,bg-completion-match-0 :foreground ,fg-completion-match-0))) + `(swiper-match-face-3 ((,c :inherit modus-themes-bold :background ,bg-completion-match-1 :foreground ,fg-completion-match-1))) + `(swiper-match-face-4 ((,c :inherit modus-themes-bold :background ,bg-completion-match-2 :foreground ,fg-completion-match-2))) ;;;;; symbol-overlay `(symbol-overlay-default-face ((,c :background ,bg-inactive))) `(symbol-overlay-face-1 ((,c :background ,bg-blue-intense :foreground ,fg-main))) @@ -6881,6 +6818,8 @@ If COLOR is unspecified, then return :box unspecified." `(tab-bar-tab-ungrouped ((,c :background ,bg-tab-other ,@(modus-themes--box bg-tab-other -2 nil)))) ;;;;; tab-line-mode `(tab-line ((,c :inherit modus-themes-ui-variable-pitch :background ,bg-tab-bar :height 0.95))) + `(tab-line-active ((,c :inherit modus-themes-ui-variable-pitch :background ,bg-tab-bar))) + `(tab-line-inactive ((,c :inherit modus-themes-ui-variable-pitch :background ,bg-dim))) `(tab-line-close-highlight ((,c :foreground ,err))) `(tab-line-highlight ((,c :background ,bg-hover :foreground ,fg-main))) `(tab-line-tab (( ))) @@ -6894,7 +6833,7 @@ If COLOR is unspecified, then return :box unspecified." `(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 :background ,bg-hover :foreground ,fg-main))) - `(telega-chat-prompt ((,c :inherit modus-themes-prompt))) + `(telega-chat-prompt ((,c :inherit bold :background ,bg-prompt :foreground ,fg-prompt))) `(telega-entity-type-code ((,c :inherit modus-themes-fixed-pitch :background ,bg-prose-verbatim :foreground ,fg-prose-verbatim))) `(telega-entity-type-mention ((,c :foreground ,type))) `(telega-entity-type-pre ((,c :inherit modus-themes-fixed-pitch :background ,bg-prose-code :foreground ,fg-prose-code))) @@ -7011,6 +6950,8 @@ If COLOR is unspecified, then return :box unspecified." `(treemacs-window-background-face ((,c :background ,bg-main))) `(treemacs-nerd-icons-root-face ((,c :foreground ,accent-0))) `(treemacs-nerd-icons-file-face ((,c :foreground ,accent-0))) +;;;;; trust-manager + `(trust-manager-untrusted-indicator ((,c :inherit modus-themes-bold :foreground ,modeline-err))) ;;;;; tty-menu `(tty-menu-disabled-face ((,c :background ,bg-inactive :foreground ,fg-dim))) `(tty-menu-enabled-face ((,c :inherit bold :background ,bg-inactive :foreground ,fg-main))) @@ -7042,6 +6983,12 @@ If COLOR is unspecified, then return :box unspecified." `(typescript-jsdoc-tag ((,c :inherit modus-themes-slant :foreground ,builtin))) `(typescript-jsdoc-type ((,c :inherit modus-themes-slant :foreground ,type))) `(typescript-jsdoc-value ((,c :inherit modus-themes-slant :foreground ,string))) +;;;;; typst-ts-mode + `(typst-ts-error-face ((,c :foreground ,err))) + `(typst-ts-markup-label-face ((,c :inherit ,(if modus-themes-mixed-fonts '(fixed-pitch default) 'default) :foreground ,builtin))) + `(typst-ts-markup-linebreak-face ((,c :foreground ,warning))) + `(typst-ts-markup-reference-face ((,c :background ,bg-link-symbolic :foreground ,fg-link-symbolic :underline ,underline-link-symbolic))) + `(typst-ts-script-char-face ((,c :inherit modus-themes-bold :foreground ,keybind))) ;;;;; undo-tree `(undo-tree-visualizer-active-branch-face ((,c :inherit modus-themes-bold :foreground ,fg-main))) `(undo-tree-visualizer-current-face ((,c :foreground ,err))) @@ -7070,7 +7017,9 @@ If COLOR is unspecified, then return :box unspecified." `(vc-state-base (( ))) `(vc-up-to-date-state (( ))) ;;;;; vertico - `(vertico-current ((,c :inherit modus-themes-completion-selected))) + `(vertico-current ((,c :background ,bg-completion))) + `(vertico-group-title ((,c :inherit modus-themes-slant :foreground ,name :height 0.9))) + `(vertico-group-separator ((,c :strike-through t :foreground ,border))) ;;;;; vertico-quick `(vertico-quick1 ((,c :inherit bold :background ,bg-search-current :foreground ,fg-search-current))) `(vertico-quick2 ((,c :inherit bold :background ,bg-search-current :foreground ,fg-search-current))) @@ -7233,9 +7182,9 @@ If COLOR is unspecified, then return :box unspecified." `(widget-button ((,c :inherit modus-themes-bold :foreground ,fg-link))) `(widget-button-pressed ((,c :inherit modus-themes-bold :foreground ,fg-link-visited))) `(widget-documentation ((,c :inherit modus-themes-slant :foreground ,docstring))) - `(widget-field ((,c :background ,bg-button-inactive :foreground ,fg-button-active :extend nil :underline (:position t)))) + `(widget-field ((,c :background ,bg-button-inactive :foreground ,fg-button-active :extend nil :underline (:position t :color ,border)))) `(widget-inactive ((,c :background ,bg-button-inactive :foreground ,fg-button-inactive))) - `(widget-single-line-field ((,c :background ,bg-button-inactive :foreground ,fg-button-active :extend nil :underline (:position t)))) + `(widget-single-line-field ((,c :background ,bg-button-inactive :foreground ,fg-button-active :extend nil :underline (:position t :color ,border)))) ;;;;; writegood-mode `(writegood-duplicates-face ((,c :underline (:style wave :color ,underline-err)))) `(writegood-passive-voice-face ((,c :underline (:style wave :color ,underline-warning)))) @@ -7405,7 +7354,7 @@ the Modus themes have by default. Consult the manual for details on how to build a theme on top of the `modus-themes': Info node `(modus-themes) Build on top of the Modus themes'." - (let ((theme-exists-p (custom-theme-p name)) + (let ((theme-exists-p (get name 'theme-feature)) (faces (append (symbol-value custom-faces) modus-themes-faces)) @@ -7427,7 +7376,7 @@ Consult the manual for details on how to build a theme on top of the ,@(mapcar (lambda (entry) (let ((name (car entry))) - (list name `(modus-themes--retrieve-palette-value ',name palette)))) + (list name `(modus-themes-retrieve-palette-value ',name palette)))) palette)) (custom-theme-set-faces ',name @@ -7436,7 +7385,7 @@ Consult the manual for details on how to build a theme on top of the ',name ,@variables)) :lexical)) - (unless theme-exists-p + (unless (featurep theme-exists-p) (provide-theme name)))) ;;;; Use theme colors @@ -7472,23 +7421,18 @@ whose value is another symbol, which ultimately resolves to a string or (semantic-unique (funcall unique-fn semantic))) (nreverse (nconc semantic-unique named-unique))))) -(defun modus-themes-with-colors-subr (body) - "Do the work of `modus-themes-with-colors' for BODY." - (condition-case data - (when-let* ((modus-themes-with-colors--current (modus-themes-get-current-theme)) - (palette (modus-themes--with-colors-get-palette modus-themes-with-colors--current)) - (sorted (modus-themes--with-colors-resolve-palette-sort palette))) - (eval - `(let* ((c '((class color) (min-colors 256))) - (unspecified 'unspecified) - ,@sorted) - (funcall ',body)))) - (error (message "Error in `modus-themes-with-colors': %s" data)))) - (defmacro modus-themes-with-colors (&rest body) "Evaluate BODY with colors from current palette bound." (declare (indent 0)) - `(modus-themes-with-colors-subr (lambda () ,@body))) + `(condition-case data + (when-let* ((theme (modus-themes-get-current-theme)) + (palette (modus-themes--with-colors-get-palette theme))) + (let ((bindings + (append + '((c '((class color) (min-colors 256))) (unspecified 'unspecified)) + (cl-remove-duplicates (apply #'append palette) :key #'car)))) + (eval (nconc `(cl-symbol-macrolet ,bindings) ',body)))) + (error (message "Error in modus-themes-with-colors: %s" data)))) ;;;; Declare all the Modus themes @@ -7577,25 +7521,18 @@ For instance: (push (+ (* (nth i a) alpha) (* (nth i b) (- 1 alpha))) blend)) (nreverse blend))) -(defun modus-themes--color-six-digits (color) - "Reduce representation of hexadecimal RGB COLOR to six digits." - (let ((color-no-hash (substring color 1))) - (if (= (length color-no-hash) 6) - color - (let* ((triplets (seq-split color-no-hash 4)) - (triplets-shortened (mapcar - (lambda (string) - (substring string 0 2)) - triplets))) - (concat "#" (string-join triplets-shortened)))))) - -(defun modus-themes-generate-color-blend (color blended-with alpha) - "Return hexadecimal RGB of COLOR with BLENDED-WITH given ALPHA. -BLENDED-WITH is commensurate with COLOR. ALPHA is between 0.0 and 1.0, -inclusive." - (let* ((blend-rgb (modus-themes-blend (color-name-to-rgb color) (color-name-to-rgb blended-with) alpha)) +(defun modus-themes-generate-color-blend (color blended-with-hex alpha) + "Return hexadecimal RGB of COLOR with BLENDED-WITH-HEX given ALPHA. +BLENDED-WITH-HEX is commensurate with COLOR. ALPHA is between 0.0 and 1.0, +inclusive. + +Color values are of the form accepted by `modus-themes-wcag-formula'." + (let* ((blend-rgb (modus-themes-blend + (modus-themes--hex-or-name-to-rgb color) + (modus-themes--hex-or-name-to-rgb blended-with-hex) + alpha)) (blend-hex (apply #'color-rgb-to-hex blend-rgb))) - (modus-themes--color-six-digits blend-hex))) + (modus-themes--color-eight-to-six-digits blend-hex))) (defun modus-themes-generate-color-warmer (color alpha) "Return warmer COLOR by ALPHA, per `modus-themes-generate-color-blend'." @@ -7605,30 +7542,16 @@ inclusive." "Return cooler COLOR by ALPHA, per `modus-themes-generate-color-blend'." (modus-themes-generate-color-blend color "#0000ff" alpha)) -;; NOTE 2025-11-24: I originally wrote a variation of this for my Doric themes. -(defun modus-themes-generate-gradient (color percent) - "Adjust value of COLOR by PERCENT." - (pcase-let* ((`(,r ,g ,b) (color-name-to-rgb color)) - (color-luminance-dark-limit 0.5) - (gradient (funcall (if (color-dark-p (list r g b)) - #'color-lighten-name - #'color-darken-name) - color - percent))) - (modus-themes--color-six-digits gradient))) - -;; NOTE 2025-11-25: I used to rely on `color-distance', thinking that -;; it would do the right thing here: -;; -;; (> (color-distance color "#ff0000") (color-distance color "#0000ff")) -;; -;; But my understanding of "warm" versus "cool" is simple, so better -;; do it my way. +(define-obsolete-function-alias + 'modus-themes-generate-gradient + 'modus-themes-adjust-value + "5.3.0") + (defun modus-themes-color-warm-p (color) "Return non-nil if COLOR is warm. A warm color has more contribution from the red channel of light than the blue one." - (pcase-let ((`(,r ,_ ,b) (color-name-to-rgb color))) + (pcase-let ((`(,r ,_ ,b) (modus-themes--hex-or-name-to-rgb color))) (> r b))) (defun modus-themes-color-is-warm-or-cool-p (color) @@ -7705,7 +7628,7 @@ rest come from CORE-PALETTE." (unless (and bg-main fg-main) (error "The palette must define at least a bg-main and fg-main entry with their values")) (let* ((bg-main (car bg-main)) - (bg-main-dark-p (color-dark-p (color-name-to-rgb bg-main))) + (bg-main-dark-p (modus-themes-color-dark-p bg-main)) (fg-main (car fg-main)) (six-colors (seq-filter (lambda (color) @@ -7723,24 +7646,24 @@ rest come from CORE-PALETTE." (unless (assq name mappings) (push (list name value) derived-mappings))))) ;; Base entries - (funcall push-derived-value-fn 'bg-dim (modus-themes-generate-gradient bg-main 5)) - (funcall push-derived-value-fn 'bg-active (modus-themes-generate-gradient bg-main 10)) - (funcall push-derived-value-fn 'bg-inactive (modus-themes-generate-gradient bg-main 8)) - (funcall push-derived-value-fn 'border (modus-themes-generate-gradient bg-main 20)) - (funcall push-derived-value-fn 'fg-dim (modus-themes-generate-gradient fg-main 20)) - (funcall push-derived-value-fn 'fg-alt (modus-themes-generate-color-warmer-or-cooler (modus-themes-generate-gradient fg-main 10) 0.8 prefers-cool-p)) + (funcall push-derived-value-fn 'bg-dim (modus-themes-adjust-value bg-main (if bg-main-dark-p 5 -5))) + (funcall push-derived-value-fn 'bg-active (modus-themes-adjust-value bg-main (if bg-main-dark-p 10 -10))) + (funcall push-derived-value-fn 'bg-inactive (modus-themes-adjust-value bg-main (if bg-main-dark-p 8 -8))) + (funcall push-derived-value-fn 'border (modus-themes-adjust-value bg-main (if bg-main-dark-p 20 -20))) + (funcall push-derived-value-fn 'fg-dim (modus-themes-adjust-value fg-main (if bg-main-dark-p -20 20))) + (funcall push-derived-value-fn 'fg-alt (modus-themes-generate-color-warmer-or-cooler (modus-themes-adjust-value fg-main (if bg-main-dark-p -10 10)) 0.8 prefers-cool-p)) ;; Primary and secondary colors (pcase-dolist (`(,name ,value) six-colors) - (funcall push-derived-value-fn (intern (format "%s-warmer" name)) (modus-themes-generate-gradient (modus-themes-generate-color-warmer value 0.9) (if bg-main-dark-p 20 -20))) - (funcall push-derived-value-fn (intern (format "%s-cooler" name)) (modus-themes-generate-gradient (modus-themes-generate-color-cooler value 0.9) (if bg-main-dark-p 20 -20))) - (funcall push-derived-value-fn (intern (format "%s-faint" name)) (modus-themes-generate-gradient value (if bg-main-dark-p 10 -10))) - (funcall push-derived-value-fn (intern (format "%s-intense" name)) (modus-themes-generate-gradient value (if bg-main-dark-p -5 5))) + (funcall push-derived-value-fn (intern (format "%s-warmer" name)) (modus-themes-adjust-value (modus-themes-generate-color-warmer value 0.9) (if bg-main-dark-p 20 -20))) + (funcall push-derived-value-fn (intern (format "%s-cooler" name)) (modus-themes-adjust-value (modus-themes-generate-color-cooler value 0.9) (if bg-main-dark-p 20 -20))) + (funcall push-derived-value-fn (intern (format "%s-faint" name)) (modus-themes-adjust-value value (if bg-main-dark-p 10 -10))) + (funcall push-derived-value-fn (intern (format "%s-intense" name)) (modus-themes-adjust-value value (if bg-main-dark-p -5 5))) ;; TODO 2025-12-06: We should have a function here that adjusts the value also up to a ;; maximum distance from bg-main. Basically, we want to avoid the scenario where a given ;; base value produces something that is virtually indistinguishable from bg-main. - (funcall push-derived-value-fn (intern (format "bg-%s-intense" name)) (modus-themes-generate-gradient value (if bg-main-dark-p -40 40))) - (funcall push-derived-value-fn (intern (format "bg-%s-subtle" name)) (modus-themes-generate-gradient value (if bg-main-dark-p -60 60))) - (funcall push-derived-value-fn (intern (format "bg-%s-nuanced" name)) (modus-themes-generate-gradient value (if bg-main-dark-p -80 80)))) + (funcall push-derived-value-fn (intern (format "bg-%s-intense" name)) (modus-themes-adjust-value value (if bg-main-dark-p -40 40))) + (funcall push-derived-value-fn (intern (format "bg-%s-subtle" name)) (modus-themes-adjust-value value (if bg-main-dark-p -60 60))) + (funcall push-derived-value-fn (intern (format "bg-%s-nuanced" name)) (modus-themes-adjust-value value (if bg-main-dark-p -80 80)))) ;; Mappings (funcall push-mapping-fn 'bg-completion (if prefers-cool-p 'bg-cyan-subtle 'bg-yellow-subtle)) (funcall push-mapping-fn 'bg-hover (if prefers-cool-p 'bg-green-intense 'bg-magenta-intense)) diff --git a/etc/themes/modus-vivendi-deuteranopia-theme.el b/etc/themes/modus-vivendi-deuteranopia-theme.el index 5b8c2395d1f..9f339aee436 100644 --- a/etc/themes/modus-vivendi-deuteranopia-theme.el +++ b/etc/themes/modus-vivendi-deuteranopia-theme.el @@ -1,9 +1,9 @@ ;;; modus-vivendi-deuteranopia-theme.el --- Deuteranopia-optimized theme with a black background -*- lexical-binding:t -*- -;; Copyright (C) 2019-2026 Free Software Foundation, Inc. +;; Copyright (C) 2019-2026 Free Software Foundation, Inc. -;; Author: Protesilaos Stavrou <[email protected]> -;; Maintainer: Protesilaos Stavrou <[email protected]> +;; Author: Protesilaos <[email protected]> +;; Maintainer: Protesilaos <[email protected]> ;; URL: https://github.com/protesilaos/modus-themes ;; Keywords: faces, theme, accessibility @@ -90,4 +90,6 @@ standard)." 'modus-vivendi-deuteranopia-palette-overrides 'modus-themes-faces-deuteranopia) +(provide 'modus-vivendi-deuteranopia-theme) + ;;; modus-vivendi-deuteranopia-theme.el ends here diff --git a/etc/themes/modus-vivendi-theme.el b/etc/themes/modus-vivendi-theme.el index 155f699d56f..8ce0d69d464 100644 --- a/etc/themes/modus-vivendi-theme.el +++ b/etc/themes/modus-vivendi-theme.el @@ -1,9 +1,9 @@ ;;; modus-vivendi-theme.el --- Elegant, highly legible theme with a black background -*- lexical-binding:t -*- -;; Copyright (C) 2019-2026 Free Software Foundation, Inc. +;; Copyright (C) 2019-2026 Free Software Foundation, Inc. -;; Author: Protesilaos Stavrou <[email protected]> -;; Maintainer: Protesilaos Stavrou <[email protected]> +;; Author: Protesilaos <[email protected]> +;; Maintainer: Protesilaos <[email protected]> ;; URL: https://github.com/protesilaos/modus-themes ;; Keywords: faces, theme, accessibility @@ -87,4 +87,6 @@ which corresponds to a minimum contrast in relative luminance of 'modus-vivendi-palette-user 'modus-vivendi-palette-overrides) +(provide 'modus-vivendi-theme) + ;;; modus-vivendi-theme.el ends here diff --git a/etc/themes/modus-vivendi-tinted-theme.el b/etc/themes/modus-vivendi-tinted-theme.el index df744485476..588d34e4ba8 100644 --- a/etc/themes/modus-vivendi-tinted-theme.el +++ b/etc/themes/modus-vivendi-tinted-theme.el @@ -1,9 +1,9 @@ ;;; modus-vivendi-tinted-theme.el --- Elegant, highly legible theme with a night sky background -*- lexical-binding:t -*- -;; Copyright (C) 2019-2026 Free Software Foundation, Inc. +;; Copyright (C) 2019-2026 Free Software Foundation, Inc. -;; Author: Protesilaos Stavrou <[email protected]> -;; Maintainer: Protesilaos Stavrou <[email protected]> +;; Author: Protesilaos <[email protected]> +;; Maintainer: Protesilaos <[email protected]> ;; URL: https://github.com/protesilaos/modus-themes ;; Keywords: faces, theme, accessibility @@ -87,4 +87,6 @@ which corresponds to a minimum contrast in relative luminance of 'modus-vivendi-tinted-palette-user 'modus-vivendi-tinted-palette-overrides) +(provide 'modus-vivendi-tinted-theme) + ;;; modus-vivendi-tinted-theme.el ends here diff --git a/etc/themes/modus-vivendi-tritanopia-theme.el b/etc/themes/modus-vivendi-tritanopia-theme.el index e4fb11cfff5..81a0b58d442 100644 --- a/etc/themes/modus-vivendi-tritanopia-theme.el +++ b/etc/themes/modus-vivendi-tritanopia-theme.el @@ -1,9 +1,9 @@ ;;; modus-vivendi-tritanopia-theme.el --- Tritanopia-optimized theme with a black background -*- lexical-binding:t -*- -;; Copyright (C) 2019-2026 Free Software Foundation, Inc. +;; Copyright (C) 2019-2026 Free Software Foundation, Inc. -;; Author: Protesilaos Stavrou <[email protected]> -;; Maintainer: Protesilaos Stavrou <[email protected]> +;; Author: Protesilaos <[email protected]> +;; Maintainer: Protesilaos <[email protected]> ;; URL: https://github.com/protesilaos/modus-themes ;; Keywords: faces, theme, accessibility @@ -90,4 +90,6 @@ standard)." 'modus-vivendi-tritanopia-palette-overrides 'modus-themes-faces-tritanopia) +(provide 'modus-vivendi-tritanopia-theme) + ;;; modus-vivendi-tritanopia-theme.el ends here diff --git a/java/AndroidManifest.xml.in b/java/AndroidManifest.xml.in index 10e121134e4..9ec1f181811 100644 --- a/java/AndroidManifest.xml.in +++ b/java/AndroidManifest.xml.in @@ -206,8 +206,12 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/> + <!-- Under Android 17 or later to access local network devices. --> + + <uses-permission android:name="android.permission.ACCESS_LOCAL_NETWORK"/> + <uses-sdk android:minSdkVersion="@ANDROID_MIN_SDK@" - android:targetSdkVersion="36"/> + android:targetSdkVersion="37"/> <application android:name="org.gnu.emacs.EmacsApplication" android:label="Emacs" diff --git a/java/INSTALL b/java/INSTALL index f0263037d22..4ad0ffb226c 100644 --- a/java/INSTALL +++ b/java/INSTALL @@ -39,7 +39,7 @@ script like so: Replacing the paths in the command line above with: - the path to the `android.jar' headers which come with the Android - SDK. They must correspond to Android version 16 (API level 36). + SDK. They must correspond to Android version 17 (API level 37). - the path to the C compiler in the Android NDK, for the kind of CPU you are building Emacs to run on. @@ -85,15 +85,10 @@ whose headers have been installed. Each of these directories in turn includes the android.jar archive for that version of Android, also necessary for compiling Emacs. -It is imperative that Emacs is compiled using the headers for the -exact API level that it is written for. This is currently API level -35, so the correct android.jar archive is located within a directory -whose name begins with `android-35'. Minor revisions to the headers -are inconsequential towards the Emacs compilation process; if there is -a directory named `android-35-extN' (where N represents a revision to -the Android SDK), whether you provide `configure' with that -directory's android.jar or the android.jar contained within the -directory named `android-35' is of no special importance. +It is imperative that Emacs is compiled using the headers for the exact +API level that it is written for. This is currently API level 37, so +the correct android.jar archive is located within a directory whose name +begins with `android-37.0' or `android-37.1'. The ndk directory contains one subdirectory for each version of the Android NDK installed. This directory in turn contains the C and C++ @@ -116,7 +111,8 @@ DEX format employed by Android. There is one subdirectory for each version of the build tools, but the version you opt for is not of paramount significance: if your version does not work, configure will protest, so install a newer one. We anticipate that most recent -releases will work, such as those from the 35.0.x and 36.0.x series. +releases will work, such as those from the 35.0.x, 36.0.x, and 37.0.x +series. BUILDING WITH OLD NDK VERSIONS diff --git a/java/org/gnu/emacs/EmacsFillPolygon.java b/java/org/gnu/emacs/EmacsFillPolygon.java index f960e309eec..f2afcb62197 100644 --- a/java/org/gnu/emacs/EmacsFillPolygon.java +++ b/java/org/gnu/emacs/EmacsFillPolygon.java @@ -30,7 +30,6 @@ import android.os.Build; public final class EmacsFillPolygon { - @SuppressWarnings ("deprecation") /* computeBounds (IZ) */ public static void perform (EmacsDrawable drawable, EmacsGC gc, Point points[]) { @@ -64,14 +63,10 @@ public final class EmacsFillPolygon /* Compute the damage rectangle. */ rectF = new RectF (0, 0, 0, 0); - /* computeBounds (IZ) is deprecated but the incompetence of - Android's release management has caused its replacement to be - omitted from published header files. */ - - /* if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) */ + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.BAKLAVA) path.computeBounds (rectF, true); - /* else - path.computeBounds (rectF); */ + else + path.computeBounds (rectF); rect = new Rect ((int) Math.floor (rectF.left), (int) Math.floor (rectF.top), diff --git a/lib/af_alg.h b/lib/af_alg.h deleted file mode 100644 index 6272d1ecbbb..00000000000 --- a/lib/af_alg.h +++ /dev/null @@ -1,115 +0,0 @@ -/* af_alg.h - Compute message digests from file streams and buffers. - Copyright (C) 2018-2026 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/>. */ - -/* Written by Matteo Croce <[email protected]>, 2018. - Documentation by Bruno Haible <[email protected]>, 2018. */ - -/* Declare specific functions for computing message digests - using the Linux kernel crypto API, if available. This kernel API gives - access to specialized crypto instructions (that would also be available - in user space) or to crypto devices (not directly available in user space). - - For a more complete set of facilities that use the Linux kernel crypto API, - look at libkcapi. */ - -#ifndef AF_ALG_H -# define AF_ALG_H 1 - -# include <stdio.h> -# include <errno.h> - -# ifdef __cplusplus -extern "C" { -# endif - -# if USE_LINUX_CRYPTO_API - -/* Compute a message digest of a memory region. - - The memory region starts at BUFFER and is LEN bytes long. - - ALG is the message digest algorithm; see the file /proc/crypto. - - RESBLOCK points to a block of HASHLEN bytes, for the result. - HASHLEN must be the length of the message digest, in bytes, in particular: - - alg | hashlen - -------+-------- - md5 | 16 - sha1 | 20 - sha224 | 28 - sha256 | 32 - sha384 | 48 - sha512 | 64 - - If successful, fill RESBLOCK and return 0. - Upon failure, return a negated error number. */ -int -afalg_buffer (char const *restrict buffer, size_t len, char const *restrict alg, - void *restrict resblock, ssize_t hashlen); - -/* Compute a message digest of data read from STREAM. - - STREAM is an open file stream. The last operation on STREAM should - not be 'ungetc', and if STREAM is also open for writing it should - have been fflushed since its last write. Read from the current - position to the end of STREAM. Handle regular files efficiently. - - ALG is the message digest algorithm; see the file /proc/crypto. - - RESBLOCK points to a block of HASHLEN bytes, for the result. - HASHLEN must be the length of the message digest, in bytes, in particular: - - alg | hashlen - -------+-------- - md5 | 16 - sha1 | 20 - sha224 | 28 - sha256 | 32 - sha384 | 48 - sha512 | 64 - - If successful, fill RESBLOCK and return 0. - Upon failure, return a negated error number. - Unless returning 0 or -EIO, restore STREAM's file position so that - the caller can fall back on some other method. */ -int -afalg_stream (FILE *restrict stream, char const *restrict alg, - void *restrict resblock, ssize_t hashlen); - -# else - -static inline int -afalg_buffer (char const *restrict buffer, size_t len, char const *restrict alg, - void *restrict resblock, ssize_t hashlen) -{ - return -EAFNOSUPPORT; -} - -static inline int -afalg_stream (FILE *restrict stream, char const *restrict alg, - void *restrict resblock, ssize_t hashlen) -{ - return -EAFNOSUPPORT; -} - -# endif - -# ifdef __cplusplus -} -# endif - -#endif /* AF_ALG_H */ diff --git a/lib/faccessat.c b/lib/faccessat.c index ee0205e3972..c1463aa70ea 100644 --- a/lib/faccessat.c +++ b/lib/faccessat.c @@ -53,21 +53,25 @@ orig_faccessat (int fd, char const *name, int mode, int flag) #if HAVE_FACCESSAT int -rpl_faccessat (int fd, char const *file, int mode, int flag) +rpl_faccessat (int fd, char const *file, int mode, int flags) { - int result = orig_faccessat (fd, file, mode, flag); + int result = orig_faccessat (fd, file, mode, flags); - if (file[strlen (file) - 1] == '/') + if (file) { - struct stat st; - int ret = fstatat (fd, file, &st, 0); - if (ret == 0 && !S_ISDIR (st.st_mode)) + size_t len = strlen (file); + if (len && file[len - 1] == '/') { - errno = ENOTDIR; - return -1; + struct stat st; + int ret = fstatat (fd, file, &st, 0); + if (ret == 0 && !S_ISDIR (st.st_mode)) + { + errno = ENOTDIR; + return -1; + } + if (result == 0) + result = ret; } - if (result == 0) - result = ret; } return result; diff --git a/lib/fchmodat.c b/lib/fchmodat.c index 9ac951ce68d..fa225901533 100644 --- a/lib/fchmodat.c +++ b/lib/fchmodat.c @@ -48,18 +48,32 @@ orig_fchmodat (int dir, char const *file, mode_t mode, int flags) #include "issymlinkat.h" +#ifndef AT_EMPTY_PATH +# define AT_EMPTY_PATH 0 +#endif + /* Invoke chmod or lchmod on FILE, using mode MODE, in the directory open on descriptor FD. If possible, do it without changing the working directory. Otherwise, resort to using save_cwd/fchdir, then (chmod|lchmod)/restore_cwd. If either the save_cwd or the restore_cwd fails, then give a diagnostic and exit nonzero. - Note that an attempt to use a FLAG value of AT_SYMLINK_NOFOLLOW - on a system without lchmod support causes this function to fail. */ + Fail if FLAGS contains AT_SYMLINK_NOFOLLOW on a system lacking + lchmod support. */ #if HAVE_FCHMODAT int fchmodat (int dir, char const *file, mode_t mode, int flags) { + if (file && *file) + flags &= ~AT_EMPTY_PATH; + else if (! (flags & AT_EMPTY_PATH)) + { + errno = ENOENT; + return -1; + } + else if (! (flags & AT_SYMLINK_NOFOLLOW) && 0 <= dir) + return fchmod (dir, mode); + # if HAVE_NEARLY_WORKING_FCHMODAT /* Correct the trailing slash handling. */ size_t len = strlen (file); @@ -77,17 +91,21 @@ fchmodat (int dir, char const *file, mode_t mode, int flags) # endif # if NEED_FCHMODAT_NONSYMLINK_FIX - if (flags == AT_SYMLINK_NOFOLLOW) + if ((flags & ~AT_EMPTY_PATH) == AT_SYMLINK_NOFOLLOW) { # if HAVE_READLINKAT # ifdef O_PATH - /* Open a file descriptor with O_NOFOLLOW, to make sure we don't - follow symbolic links, if /proc is mounted. O_PATH is used to - avoid a failure if the file is not readable. - Cf. <https://sourceware.org/PR14578> */ - int fd = openat (dir, file, O_PATH | O_NOFOLLOW | O_CLOEXEC); - if (fd < 0) - return fd; + int fd; + if (flags & AT_EMPTY_PATH) + fd = dir; + else + { + /* Open with O_NOFOLLOW, so we don't follow symlinks. + See <https://sourceware.org/PR14578>. */ + fd = openat (dir, file, O_PATH | O_NOFOLLOW | O_CLOEXEC); + if (fd < 0) + return fd; + } int err; { @@ -105,7 +123,8 @@ fchmodat (int dir, char const *file, mode_t mode, int flags) err = errno == ENOENT ? -1 : errno; } - close (fd); + if (! (flags & AT_EMPTY_PATH)) + close (fd); errno = err; if (0 <= err) @@ -114,15 +133,16 @@ fchmodat (int dir, char const *file, mode_t mode, int flags) /* O_PATH + /proc is not supported. */ - if (issymlinkat (dir, file) > 0) + if (issymlinkat (dir, file ? file : "") > 0) { errno = EOPNOTSUPP; return -1; } # endif - /* Fall back on orig_fchmodat with no flags, despite a possible race. */ - flags = 0; + /* Fall back on orig_fchmodat without AT_SYMLINK_NOFOLLOW, + despite a possible race. */ + flags &= ~AT_SYMLINK_NOFOLLOW; } # endif diff --git a/lib/fstatat.c b/lib/fstatat.c index 8d26e44501a..6b0c564a210 100644 --- a/lib/fstatat.c +++ b/lib/fstatat.c @@ -46,6 +46,10 @@ orig_fstatat (int fd, char const *filename, struct stat *buf, int flags) #include <stdlib.h> #include <string.h> +#ifndef AT_EMPTY_PATH +# define AT_EMPTY_PATH 0 +#endif + #if HAVE_FSTATAT && HAVE_WORKING_FSTATAT_ZERO_FLAG # ifndef LSTAT_FOLLOWS_SLASHED_SYMLINK @@ -68,14 +72,19 @@ normal_fstatat (int fd, char const *file, struct stat *st, int flag) Work around this bug if FSTATAT_AT_FDCWD_0_BROKEN is nonzero. */ int -rpl_fstatat (int fd, char const *file, struct stat *st, int flag) +rpl_fstatat (int fd, char const *file, struct stat *st, int flags) { - int result = normal_fstatat (fd, file, st, flag); + /* Implement Linux kernel 6.11+ behavior on platforms that have + AT_EMPTY_PATH but do not support it on null pointers. */ + if (flags & AT_EMPTY_PATH && !file) + file = ""; + + int result = normal_fstatat (fd, file, st, flags); if (LSTAT_FOLLOWS_SLASHED_SYMLINK || result != 0) return result; size_t len = strlen (file); - if (flag & AT_SYMLINK_NOFOLLOW) + if (flags & AT_SYMLINK_NOFOLLOW) { /* Fix lstat behavior. */ if (file[len - 1] != '/' || S_ISDIR (st->st_mode)) @@ -85,7 +94,7 @@ rpl_fstatat (int fd, char const *file, struct stat *st, int flag) errno = ENOTDIR; return -1; } - result = normal_fstatat (fd, file, st, flag & ~AT_SYMLINK_NOFOLLOW); + result = normal_fstatat (fd, file, st, flags & ~AT_SYMLINK_NOFOLLOW); } /* Fix stat behavior. */ if (result == 0 && !S_ISDIR (st->st_mode) && file[len - 1] == '/') diff --git a/lib/getopt-pfx-ext.h b/lib/getopt-pfx-ext.h index db2e27f36c3..189598a125b 100644 --- a/lib/getopt-pfx-ext.h +++ b/lib/getopt-pfx-ext.h @@ -58,6 +58,7 @@ #ifndef __getopt_argv_const # if defined __GETOPT_PREFIX # define __getopt_argv_const /* empty */ +# define __getopt_argv_const_is_empty 1 # else # define __getopt_argv_const const # endif diff --git a/lib/getopt1.c b/lib/getopt1.c index a5f9988828b..7a5ae1cad07 100644 --- a/lib/getopt1.c +++ b/lib/getopt1.c @@ -24,11 +24,19 @@ #include <getopt.h> #include "getopt_int.h" +/* Convert char *__getopt_argv_const * to char ** without provoking + gcc -Wuseless-cast when __getopt_argv_gconst is empty. */ +#ifdef __getopt_argv_const_is_empty +# define ARGV_CAST(argv) (argv) +#else +# define ARGV_CAST(argv) ((char **) (argv)) +#endif + int getopt_long (int argc, char *__getopt_argv_const *argv, const char *options, const struct option *long_options, int *opt_index) { - return _getopt_internal (argc, (char **) argv, options, long_options, + return _getopt_internal (argc, ARGV_CAST (argv), options, long_options, opt_index, 0, 0); } @@ -51,7 +59,7 @@ getopt_long_only (int argc, char *__getopt_argv_const *argv, const char *options, const struct option *long_options, int *opt_index) { - return _getopt_internal (argc, (char **) argv, options, long_options, + return _getopt_internal (argc, ARGV_CAST (argv), options, long_options, opt_index, 1, 0); } diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index 0605164636d..b21d470cd0b 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -44,7 +44,6 @@ # --avoid=c32toupper \ # --avoid=chmod \ # --avoid=close \ -# --avoid=crypto/af_alg \ # --avoid=dup \ # --avoid=fchdir \ # --avoid=fstat \ @@ -265,6 +264,7 @@ DBUS_OBJ = @DBUS_OBJ@ DEFS = @DEFS@ DESLIB = @DESLIB@ DIR_HAS_FD_MEMBER = @DIR_HAS_FD_MEMBER@ +DOCLANGS = @DOCLANGS@ DOCMISC_W32 = @DOCMISC_W32@ DUMPING = @DUMPING@ DYNAMIC_LIB_SECONDARY_SUFFIX = @DYNAMIC_LIB_SECONDARY_SUFFIX@ diff --git a/lib/intprops-internal.h b/lib/intprops-internal.h index 1fb3b799011..4055173dc84 100644 --- a/lib/intprops-internal.h +++ b/lib/intprops-internal.h @@ -106,7 +106,7 @@ || (defined __clang_major__ && 4 <= __clang_major__) \ || (defined __IBMC__ && 1210 <= __IBMC__ && defined __IBM__TYPEOF__) \ || (defined __SUNPRO_C && 0x5110 <= __SUNPRO_C && !__STDC__) \ - || (defined _MSC_VER && 1939 <= _MSC_VER)) + || (defined _MSC_VER && 1939 <= _MSC_VER && !defined __cplusplus)) # define _GL_HAVE___TYPEOF__ 1 #else # define _GL_HAVE___TYPEOF__ 0 diff --git a/lib/md5-stream.c b/lib/md5-stream.c index ffe077f52ab..a406d17b53c 100644 --- a/lib/md5-stream.c +++ b/lib/md5-stream.c @@ -30,7 +30,9 @@ # include "unlocked-io.h" #endif -#include "af_alg.h" +#if GNULIB_AF_ALG +# include "af_alg.h" +#endif #ifdef _LIBC # include <endian.h> @@ -57,11 +59,13 @@ int md5_stream (FILE *stream, void *resblock) { +#if GNULIB_AF_ALG switch (afalg_stream (stream, "md5", resblock, MD5_DIGEST_SIZE)) { case 0: return 0; case -EIO: return 1; } +#endif char *buffer = malloc (BLOCKSIZE); if (!buffer) diff --git a/lib/mini-gmp.c b/lib/mini-gmp.c index 9f3812b31bd..87cc12aa0fd 100644 --- a/lib/mini-gmp.c +++ b/lib/mini-gmp.c @@ -3,7 +3,7 @@ Contributed to the GNU project by Niels Möller Additional functionalities and improvements by Marco Bodrato. -Copyright 1991-1997, 1999-2022 Free Software Foundation, Inc. +Copyright 1991-1997, 1999-2026 Free Software Foundation, Inc. This file is part of the GNU MP Library. @@ -2832,10 +2832,10 @@ mpz_gcd (mpz_t g, const mpz_t u, const mpz_t v) mpz_swap (tu, tv); tu->_mp_size = mpn_gcd (tu->_mp_d, tu->_mp_d, tu->_mp_size, tv->_mp_d, tv->_mp_size); - mpz_mul_2exp (g, tu, gz); + mpz_clear (tv); + mpz_mul_2exp (g, tu, gz); mpz_clear (tu); - mpz_clear (tv); } void @@ -2969,6 +2969,7 @@ mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v) else mpz_setbit (t0, uz); + mpz_clear (tu); /* Now tv = odd part of gcd, and -s0 and t0 are corresponding cofactors. */ @@ -3005,13 +3006,19 @@ mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v) the one with smallest corresponding t (this asymmetric condition is needed to prefer s = 0, |t| = 1 when g = |a| = |b|). */ mpz_add (s1, s0, s1); - mpz_sub (t1, t0, t1); cmp = mpz_cmpabs (s0, s1); - if (cmp > 0 || (cmp == 0 && mpz_cmpabs (t0, t1) > 0)) + if (cmp >= 0) { + mpz_sub (t1, t0, t1); + if (cmp > 0 || mpz_cmpabs (t0, t1) > 0) + { mpz_swap (s0, s1); mpz_swap (t0, t1); + } } + mpz_clear (s1); + mpz_clear (t1); + if (u->_mp_size < 0) mpz_neg (s0, s0); if (v->_mp_size < 0) @@ -3023,12 +3030,9 @@ mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v) if (t) mpz_swap (t, t0); - mpz_clear (tu); mpz_clear (tv); mpz_clear (s0); - mpz_clear (s1); mpz_clear (t0); - mpz_clear (t1); } void @@ -3081,6 +3085,7 @@ mpz_invert (mpz_t r, const mpz_t u, const mpz_t m) mpz_gcdext (g, tr, NULL, u, m); invertible = (mpz_cmp_ui (g, 1) == 0); + mpz_clear (g); if (invertible) { @@ -3094,7 +3099,6 @@ mpz_invert (mpz_t r, const mpz_t u, const mpz_t m) mpz_swap (r, tr); } - mpz_clear (g); mpz_clear (tr); return invertible; } @@ -3222,6 +3226,7 @@ mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m) } while (bit > 0); } + mpz_clear (base); /* Final reduction */ if (tr->_mp_size >= mn) @@ -3235,7 +3240,6 @@ mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m) mpz_swap (r, tr); mpz_clear (tr); - mpz_clear (base); } void @@ -3271,9 +3275,8 @@ mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z) } mpz_init (u); - mpz_init (t); bc = (mpz_sizeinbase (y, 2) - 1) / z + 1; - mpz_setbit (t, bc); + mpz_init_setbit (t, bc); if (z == 2) /* simplify sqrt loop: z-1 == 1 */ do { @@ -3339,12 +3342,23 @@ mpz_sqrt (mpz_t s, const mpz_t u) } int -mpz_perfect_square_p (const mpz_t u) +mpz_perfect_square_root (mpz_t r, const mpz_t u) { if (u->_mp_size <= 0) - return (u->_mp_size == 0); + { + int ret = u->_mp_size == 0; + if (r != NULL) + r->_mp_size = 0; + return ret; + } else - return mpz_root (NULL, u, 2); + return mpz_root (r, u, 2); +} + +int +mpz_perfect_square_p (const mpz_t u) +{ + return mpz_perfect_square_root (NULL, u); } int @@ -3844,6 +3858,14 @@ mpz_combit (mpz_t d, mp_bitcnt_t bit_index) mpz_abs_add_bit (d, bit_index); } +void +mpz_init_setbit (mpz_t r, mp_bitcnt_t b) +{ + mpz_init (r); + /* mpz_setbit (r, b); */ + mpz_abs_add_bit (r, b); +} + void mpz_com (mpz_t r, const mpz_t u) { diff --git a/lib/mini-gmp.h b/lib/mini-gmp.h index f28cb360ce1..eb7c3e86271 100644 --- a/lib/mini-gmp.h +++ b/lib/mini-gmp.h @@ -1,6 +1,7 @@ /* mini-gmp, a minimalistic implementation of a GNU GMP subset. -Copyright 2011-2015, 2017, 2019-2021 Free Software Foundation, Inc. +Copyright 2011-2015, 2017, 2019-2021, 2024, 2026 Free Software +Foundation, Inc. This file is part of the GNU MP Library. @@ -211,6 +212,7 @@ int mpz_invert (mpz_t, const mpz_t, const mpz_t); void mpz_sqrtrem (mpz_t, mpz_t, const mpz_t); void mpz_sqrt (mpz_t, const mpz_t); +int mpz_perfect_square_root (mpz_t, const mpz_t); int mpz_perfect_square_p (const mpz_t); void mpz_pow_ui (mpz_t, const mpz_t, unsigned long); @@ -272,6 +274,7 @@ void mpz_set_d (mpz_t, double); void mpz_init_set_si (mpz_t, signed long int); void mpz_init_set_ui (mpz_t, unsigned long int); void mpz_init_set (mpz_t, const mpz_t); +void mpz_init_setbit (mpz_t, mp_bitcnt_t); void mpz_init_set_d (mpz_t, double); size_t mpz_sizeinbase (const mpz_t, int); diff --git a/lib/signal.in.h b/lib/signal.in.h index 9e140ca5e83..236ec7a83c9 100644 --- a/lib/signal.in.h +++ b/lib/signal.in.h @@ -200,7 +200,7 @@ _GL_CXXALIAS_RPL (pthread_sigmask, int, const sigset_t *restrict new_mask, sigset_t *restrict old_mask)); # else -# if !(@HAVE_PTHREAD_SIGMASK@ || defined pthread_sigmask) +# if !@HAVE_PTHREAD_SIGMASK@ _GL_FUNCDECL_SYS (pthread_sigmask, int, (int how, const sigset_t *restrict new_mask, diff --git a/lib/stat-time.h b/lib/stat-time.h index 461a0c88b93..37b7ec4ee8d 100644 --- a/lib/stat-time.h +++ b/lib/stat-time.h @@ -221,7 +221,7 @@ get_stat_birthtime (_GL_UNUSED struct stat const *st) in *ST, if this platform suffers from a macOS and Solaris bug where tv_nsec might be negative. Return the adjusted RESULT, setting errno to EOVERFLOW if normalization overflowed. This function - is intended to be private to this .h file. */ + is intended to be private to Gnulib. */ _GL_STAT_TIME_INLINE int stat_time_normalize (int result, _GL_UNUSED struct stat *st) { diff --git a/lib/stdbit.in.h b/lib/stdbit.in.h index 92749487fa8..d9a873a43aa 100644 --- a/lib/stdbit.in.h +++ b/lib/stdbit.in.h @@ -26,6 +26,10 @@ /* The include_next requires a split double-inclusion guard. */ #if @HAVE_STDBIT_H@ +/* The FreeBSD 15.1 <stdbit.h> uses the _Bool type. */ +# if defined __FreeBSD__ && defined __cplusplus +# define _Bool bool +# endif # @INCLUDE_NEXT@ @NEXT_STDBIT_H@ #endif @@ -175,7 +179,7 @@ _GL_INLINE_HEADER_BEGIN || (defined __clang_major__ && 4 <= __clang_major__) \ || (defined __IBMC__ && 1210 <= __IBMC__ && defined __IBM__TYPEOF__) \ || (defined __SUNPRO_C && 0x5110 <= __SUNPRO_C && !__STDC__) \ - || (defined _MSC_VER && 1939 <= _MSC_VER)) + || (defined _MSC_VER && 1939 <= _MSC_VER && !defined __cplusplus)) # define _GL_STDBIT_TYPEOF_CAST(a, b) ((__typeof__ (a)) (b)) #elif 202311 <= __STDC_VERSION__ # define _GL_STDBIT_TYPEOF_CAST(a, b) ((typeof (a)) (b)) diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h index 3c2004611fe..6f63c879698 100644 --- a/lib/stdlib.in.h +++ b/lib/stdlib.in.h @@ -103,7 +103,8 @@ struct random_data # endif #endif -#if (@GNULIB_MKSTEMP@ || @GNULIB_MKSTEMPS@ || @GNULIB_MKOSTEMP@ || @GNULIB_MKOSTEMPS@ || @GNULIB_GETSUBOPT@ || defined GNULIB_POSIXCHECK) && ! defined __GLIBC__ && !(defined _WIN32 && ! defined __CYGWIN__) +#if (@GNULIB_MKDTEMP@ || @GNULIB_MKSTEMP@ || @GNULIB_MKSTEMPS@ || @GNULIB_MKOSTEMP@ || @GNULIB_MKOSTEMPS@ || @GNULIB_GETSUBOPT@ || defined GNULIB_POSIXCHECK) && ! defined __GLIBC__ && !(defined _WIN32 && ! defined __CYGWIN__) +/* On macOS 26, only <unistd.h> declares mkdtemp. */ /* On Mac OS X 10.3, only <unistd.h> declares mkstemp. */ /* On Mac OS X 10.5, only <unistd.h> declares mkstemps. */ /* On Mac OS X 10.13, only <unistd.h> declares mkostemp and mkostemps. */ diff --git a/lib/string.in.h b/lib/string.in.h index 1c46c65f60d..eb22a912c34 100644 --- a/lib/string.in.h +++ b/lib/string.in.h @@ -1647,15 +1647,21 @@ _GL_EXTERN_C bool mbs_endswith (const char *string, const char *suffix) /* Map any int, typically from errno, into an error message. */ #if @GNULIB_STRERROR@ +/* The return type 'const char *' serves the purpose of producing warnings + for invalid uses of the value returned from this function. */ # if @REPLACE_STRERROR@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # undef strerror # define strerror rpl_strerror +# define GNULIB_defined_strerror 1 # endif -_GL_FUNCDECL_RPL (strerror, char *, (int), ); -_GL_CXXALIAS_RPL (strerror, char *, (int)); +_GL_FUNCDECL_RPL (strerror, const char *, (int), ); +_GL_CXXALIAS_RPL (strerror, const char *, (int)); # else -_GL_CXXALIAS_SYS (strerror, char *, (int)); +_GL_CXXALIAS_SYS_CAST (strerror, const char *, (int)); +# if !defined strerror && !defined __cplusplus +# define strerror(...) ((const char *) strerror (__VA_ARGS__)) +# endif # endif # if __GLIBC__ >= 2 _GL_CXXALIASWARN (strerror); diff --git a/lib/sys_stat.in.h b/lib/sys_stat.in.h index deed21cdf39..567dffa6209 100644 --- a/lib/sys_stat.in.h +++ b/lib/sys_stat.in.h @@ -480,18 +480,18 @@ _GL_CXXALIASWARN (chmod); # define fchmodat rpl_fchmodat # endif _GL_FUNCDECL_RPL (fchmodat, int, - (int fd, char const *file, mode_t mode, int flag), - _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD); + (int fd, char const *file, mode_t mode, int flags), + _GL_ATTRIBUTE_NODISCARD); _GL_CXXALIAS_RPL (fchmodat, int, - (int fd, char const *file, mode_t mode, int flag)); + (int fd, char const *file, mode_t mode, int flags)); # else # if !@HAVE_FCHMODAT@ _GL_FUNCDECL_SYS (fchmodat, int, - (int fd, char const *file, mode_t mode, int flag), - _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD); + (int fd, char const *file, mode_t mode, int flags), + _GL_ATTRIBUTE_NODISCARD); # endif _GL_CXXALIAS_SYS (fchmodat, int, - (int fd, char const *file, mode_t mode, int flag)); + (int fd, char const *file, mode_t mode, int flags)); # endif _GL_CXXALIASWARN (fchmodat); #elif defined GNULIB_POSIXCHECK @@ -542,7 +542,7 @@ _GL_WARN_ON_USE (fstat, "fstat has portability problems - " _GL_FUNCDECL_RPL (fstatat, int, (int fd, char const *restrict name, struct stat *restrict st, int flags), - _GL_ARG_NONNULL ((2, 3))); + _GL_ARG_NONNULL ((3))); _GL_CXXALIAS_RPL (fstatat, int, (int fd, char const *restrict name, struct stat *restrict st, int flags)); @@ -551,7 +551,7 @@ _GL_CXXALIAS_RPL (fstatat, int, _GL_FUNCDECL_SYS (fstatat, int, (int fd, char const *restrict name, struct stat *restrict st, int flags), - _GL_ARG_NONNULL ((2, 3))); + _GL_ARG_NONNULL ((3))); # endif _GL_CXXALIAS_SYS (fstatat, int, (int fd, char const *restrict name, struct stat *restrict st, @@ -966,18 +966,18 @@ _GL_CXXALIASWARN (umask); # define utimensat rpl_utimensat # endif _GL_FUNCDECL_RPL (utimensat, int, (int fd, char const *name, - struct timespec const times[2], int flag), - _GL_ARG_NONNULL ((2))); + struct timespec const times[2], int flags), + ); _GL_CXXALIAS_RPL (utimensat, int, (int fd, char const *name, - struct timespec const times[2], int flag)); + struct timespec const times[2], int flags)); # else # if !@HAVE_UTIMENSAT@ _GL_FUNCDECL_SYS (utimensat, int, (int fd, char const *name, - struct timespec const times[2], int flag), - _GL_ARG_NONNULL ((2))); + struct timespec const times[2], int flags), + ); # endif _GL_CXXALIAS_SYS (utimensat, int, (int fd, char const *name, - struct timespec const times[2], int flag)); + struct timespec const times[2], int flags)); # endif # if __GLIBC__ >= 2 && @HAVE_UTIMENSAT@ _GL_CXXALIASWARN (utimensat); diff --git a/lib/unistd.in.h b/lib/unistd.in.h index f7e4450cede..8f40c19e2a1 100644 --- a/lib/unistd.in.h +++ b/lib/unistd.in.h @@ -930,18 +930,18 @@ _GL_CXXALIASWARN (execvpe); # define faccessat rpl_faccessat # endif _GL_FUNCDECL_RPL (faccessat, int, - (int fd, char const *name, int mode, int flag), - _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD); + (int fd, char const *name, int mode, int flags), + _GL_ATTRIBUTE_NODISCARD); _GL_CXXALIAS_RPL (faccessat, int, - (int fd, char const *name, int mode, int flag)); + (int fd, char const *name, int mode, int flags)); # else # if !@HAVE_FACCESSAT@ _GL_FUNCDECL_SYS (faccessat, int, - (int fd, char const *file, int mode, int flag), - _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD); + (int fd, char const *file, int mode, int flags), + _GL_ATTRIBUTE_NODISCARD); # endif _GL_CXXALIAS_SYS (faccessat, int, - (int fd, char const *file, int mode, int flag)); + (int fd, char const *file, int mode, int flags)); # endif # if __GLIBC__ >= 2 _GL_CXXALIASWARN (faccessat); @@ -997,18 +997,18 @@ _GL_WARN_ON_USE (fchdir, "fchdir is unportable - " # define fchownat rpl_fchownat # endif _GL_FUNCDECL_RPL (fchownat, int, (int fd, char const *file, - uid_t owner, gid_t group, int flag), - _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD); + uid_t owner, gid_t group, int flags), + _GL_ATTRIBUTE_NODISCARD); _GL_CXXALIAS_RPL (fchownat, int, (int fd, char const *file, - uid_t owner, gid_t group, int flag)); + uid_t owner, gid_t group, int flags)); # else # if !@HAVE_FCHOWNAT@ _GL_FUNCDECL_SYS (fchownat, int, (int fd, char const *file, - uid_t owner, gid_t group, int flag), - _GL_ARG_NONNULL ((2)) _GL_ATTRIBUTE_NODISCARD); + uid_t owner, gid_t group, int flags), + _GL_ATTRIBUTE_NODISCARD); # endif _GL_CXXALIAS_SYS (fchownat, int, (int fd, char const *file, - uid_t owner, gid_t group, int flag)); + uid_t owner, gid_t group, int flags)); # endif _GL_CXXALIASWARN (fchownat); #elif defined GNULIB_POSIXCHECK @@ -1728,21 +1728,21 @@ _GL_WARN_ON_USE (link, "link is unportable - " # endif _GL_FUNCDECL_RPL (linkat, int, (int fd1, const char *path1, int fd2, const char *path2, - int flag), + int flags), _GL_ARG_NONNULL ((2, 4)) _GL_ATTRIBUTE_NODISCARD); _GL_CXXALIAS_RPL (linkat, int, (int fd1, const char *path1, int fd2, const char *path2, - int flag)); + int flags)); # else # if !@HAVE_LINKAT@ _GL_FUNCDECL_SYS (linkat, int, (int fd1, const char *path1, int fd2, const char *path2, - int flag), + int flags), _GL_ARG_NONNULL ((2, 4)) _GL_ATTRIBUTE_NODISCARD); # endif _GL_CXXALIAS_SYS (linkat, int, (int fd1, const char *path1, int fd2, const char *path2, - int flag)); + int flags)); # endif # if __GLIBC__ >= 2 _GL_CXXALIASWARN (linkat); diff --git a/lisp/bindings.el b/lisp/bindings.el index b13dc0a705c..123f6615e65 100644 --- a/lisp/bindings.el +++ b/lisp/bindings.el @@ -726,7 +726,6 @@ mouse-1: Display Line and Column Mode Menu")) `((:propertize ("" mode-line-percent-position) local-map ,mode-line-column-line-number-mode-map - display (min-width (5.0)) mouse-face mode-line-highlight ;; XXX needs better description help-echo "Window Scroll Percentage @@ -745,31 +744,26 @@ mouse-1: Display Line and Column Mode Menu"))) (10 (:propertize mode-line-position-column-line-format - display (min-width (10.0)) ,@mode-line-position--column-line-properties)) (10 (:propertize (:eval (string-replace "%c" "%C" (car mode-line-position-column-line-format))) - display (min-width (10.0)) ,@mode-line-position--column-line-properties))) (6 (:propertize mode-line-position-line-format - display (min-width (6.0)) ,@mode-line-position--column-line-properties))) (column-number-mode (column-number-indicator-zero-based (6 (:propertize mode-line-position-column-format - display (min-width (6.0)) ,@mode-line-position--column-line-properties)) (6 (:propertize (:eval (string-replace "%c" "%C" (car mode-line-position-column-format))) - display (min-width (6.0)) ,@mode-line-position--column-line-properties)))))) "Mode line construct for displaying the position in the buffer. Normally displays the buffer percentage and, optionally, the @@ -824,15 +818,11 @@ By default, this shows the information specified by `global-mode-string'.") (let ((standard-mode-line-format (list "%e" 'mode-line-front-space - (list - :propertize - (list "" - 'mode-line-mule-info - 'mode-line-client - 'mode-line-modified - 'mode-line-remote - 'mode-line-window-dedicated) - 'display '(min-width (6.0))) + 'mode-line-mule-info + 'mode-line-client + 'mode-line-modified + 'mode-line-remote + 'mode-line-window-dedicated 'mode-line-frame-identification 'mode-line-buffer-identification " " @@ -889,6 +879,18 @@ or not." (with-selected-window (minibuffer-window) (eq window (minibuffer-selected-window))))))) +(defun mode-line-window-select (&optional _ignored-arg) + "Select the window on whose mode-line the mouse was clicked." + (when-let* ((_ (mouse-event-p last-input-event)) + (event (event-start last-input-event)) + (_ (eq (posn-area event) 'mode-line)) + (window (posn-window event)) + (_ (not (eq (selected-window) window)))) + (mouse-select-window last-input-event))) + +(add-hook 'x-pre-popup-menu-hook #'mode-line-window-select) + + (defmacro bound-and-true-p (var) "Return the value of symbol VAR if it is bound, else nil. Note that if `lexical-binding' is in effect, this function isn't diff --git a/lisp/bookmark.el b/lisp/bookmark.el index 1113144f87a..77136308573 100644 --- a/lisp/bookmark.el +++ b/lisp/bookmark.el @@ -286,7 +286,7 @@ described below. An entry with a key but null value means the entry is not used. (filename . FILENAME) - (buf . BUFFER-OR-NAME) + (buffer . BUFFER-OR-NAME) (position . POS) (front-context-string . STR-AFTER-POS) (rear-context-string . STR-BEFORE-POS) diff --git a/lisp/calc/calc-forms.el b/lisp/calc/calc-forms.el index adb2d932a9a..d6ff7e953f5 100644 --- a/lisp/calc/calc-forms.el +++ b/lisp/calc/calc-forms.el @@ -1474,7 +1474,10 @@ This is measured in the integer number of days from December 31, ( "PGT" 8 "PST" "PDT" ) ( "PST" 8 0 ) ( "PDT" 8 -1 ) ; Pacific ( "YGT" 9 "YST" "YDT" ) ( "YST" 9 0 ) ( "YDT" 9 -1 ) ; Yukon ) - "No doc yet. See calc manual for now.") + "No doc yet. See calc manual for now. +This variable is obsolete and new software should not rely on its +contents. Its abbreviations like \"PST\" have their circa 1970 meanings +even if timekeeping has changed since then.") (defvar var-TimeZone nil) diff --git a/lisp/calendar/cal-dst.el b/lisp/calendar/cal-dst.el index 7681059f592..8285bbb09fb 100644 --- a/lisp/calendar/cal-dst.el +++ b/lisp/calendar/cal-dst.el @@ -356,7 +356,7 @@ If the locale never uses daylight saving time, set this to 0." "-0000") (or (nth 2 calendar-current-time-zone-cache) "UTC")) "Abbreviated name of standard time zone at `calendar-location-name'. -For example, \"-0500\" or \"EST\" in New York City." +For example, \"+1200\" or \"NZST\" in New Zealand." :type 'string :version "28.1" :set-after '(calendar-time-zone-style)) @@ -369,7 +369,7 @@ For example, \"-0500\" or \"EST\" in New York City." "-0000") (or (nth 3 calendar-current-time-zone-cache) "UTC")) "Abbreviated name of daylight saving time zone at `calendar-location-name'. -For example, \"-0400\" or \"EDT\" in New York City." +For example, \"+1300\" or \"NZDT\" in New Zealand." :type 'string :version "28.1" :set-after '(calendar-time-zone-style)) diff --git a/lisp/calendar/calendar.el b/lisp/calendar/calendar.el index b4390fd2191..e20c8ae95ec 100644 --- a/lisp/calendar/calendar.el +++ b/lisp/calendar/calendar.el @@ -918,7 +918,9 @@ including those inserted into the diary from the calendar with (defconst diary-european-date-insertion-form '(day "/" month "/" year) "Pseudo-pattern for European dates in `diary-date-insertion-form'") -(defconst diary-iso-date-insertion-form '(year "/" month "/" day) +(defconst diary-iso-date-insertion-form '((format "%s-%.2d-%.2d" year + (string-to-number month) + (string-to-number day))) "Pseudo-pattern for ISO dates in `diary-date-insertion-form'") (defcustom diary-date-insertion-form diff --git a/lisp/calendar/icalendar-macs.el b/lisp/calendar/icalendar-macs.el index b216d8dc141..43903ddd1d0 100644 --- a/lisp/calendar/icalendar-macs.el +++ b/lisp/calendar/icalendar-macs.el @@ -989,7 +989,7 @@ Each binding in BINDINGS should be a list of one of the following forms: "Execute BODY with bindings in BINDINGS taken from NODE and its children. NODE should be an iCalendar syntax node representing a property or -parameter. If NODE is not a syntax node, this form evalutes to nil +parameter. If NODE is not a syntax node, this form evaluates to nil without binding the variables in BINDINGS and without executing BODY. Within BODY, if NODE's value is itself a syntax node, the symbol @@ -1044,7 +1044,7 @@ available in BODY; see its docstring for their form." "Execute BODY with BINDINGS taken from the value and parameters in NODE. NODE should be an iCalendar syntax node representing a property. If NODE -is not a syntax node, this form evalutes to nil without binding the +is not a syntax node, this form evaluates to nil without binding the variables in BINDINGS and without executing BODY. Within BODY, if NODE's value is itself a syntax node, the symbol @@ -1067,7 +1067,7 @@ available in BODY; see its docstring for their form.") "Bind the value in PARAMETER and execute BODY. PARAMETER should be an iCalendar syntax node representing a -parameter. If PARAMETER is nil, this form evalutes to nil without +parameter. If PARAMETER is nil, this form evaluates to nil without executing BODY. Within BODY, if PARAMETER's value is a syntax node, the symbol @@ -1087,7 +1087,7 @@ bound to nil." Find the first child node of type TYPE in NODE, bind that child node's value and any of its children in BINDINGS and execute BODY -with these bindings. If there is no such node, this form evalutes to +with these bindings. If there is no such node, this form evaluates to nil without executing BODY. Within BODY, the symbols `value-node', `value-type', and `value' will be diff --git a/lisp/calendar/icalendar-recur.el b/lisp/calendar/icalendar-recur.el index b6c766962c9..9bf55d4ba8b 100644 --- a/lisp/calendar/icalendar-recur.el +++ b/lisp/calendar/icalendar-recur.el @@ -1543,12 +1543,15 @@ UTC offsets local to that time zone." ;; time described occurs more than once (when changing from daylight to ;; standard time), the DATE-TIME value refers to the first occurrence of ;; the referenced time. Thus, TZID=America/New_York:20071104T013000 -;; indicates November 4, 2007 at 1:30 A.M. EDT (UTC-04:00). If the +;; indicates November 4, 2007 at 1:30 A.M. EDT (UTC-04:00). If the ;; local time described does not occur (when changing from standard to ;; daylight time), the DATE-TIME value is interpreted using the UTC ;; offset before the gap in local times. Thus, ;; TZID=America/New_York:20070311T023000 indicates March 11, 2007 at -;; 3:30 A.M. EDT (UTC-04:00), one hour after 1:30 A.M. EST (UTC-05:00)." +;; 3:30 A.M. EDT (UTC-04:00), one hour after 1:30 A.M. EST (UTC-05:00)." +;; This quote from RFC 5545 is based on New York's 2007 timekeeping practice; +;; although that practice may change in the future, the example is still +;; valid for 2007. ;; TODO: verify that these functions are correct for time zones other ;; than US Eastern. @@ -1641,10 +1644,10 @@ OBS-ONSET, or a range of local times that occur twice (see `icalendar-recur-nonexistent-date-time-p' and `icalendar-recur-date-time-occurs-twice-p'), it needs to be interpreted with the UTC offset in effect prior to the OBS-ONSET of OBSERVANCE (see -RFC5545 Section 3.3.5). So e.g. at the switch from Standard to Daylight -in US Eastern, 2:30AM EST (a nonexistent time) becomes 3:30AM EDT, and -at the switch from Daylight to Standard, 1:30AM (which occurs twice) -becomes 1:30AM EDT, the first occurence." +RFC5545 Section 3.3.5). So, for example, at the switch from standard to +daylight in New Zealand, 2:30AM NZST (a nonexistent time) becomes 3:30AM NZDT, +and at the switch from daylight to standard, 2:30AM (which occurs twice) +becomes 1:30AM NZDT, the first occurrence." (ical:with-component observance ((ical:tzoffsetfrom :value offset-from) (ical:tzoffsetto :value offset-to)) diff --git a/lisp/calendar/parse-time.el b/lisp/calendar/parse-time.el index 21e0e2d569d..16eab83433d 100644 --- a/lisp/calendar/parse-time.el +++ b/lisp/calendar/parse-time.el @@ -95,7 +95,11 @@ letters, digits, plus or minus signs or colons." ("mst" ,(* -7 3600)) ("mdt" ,(* -6 3600) t) ("cst" ,(* -6 3600)) ("cdt" ,(* -5 3600) t) ("est" ,(* -5 3600)) ("edt" ,(* -4 3600) t)) - "(zoneinfo seconds-off daylight-savings-time-p)") + "List of some RFC 822 (or later) alphabetic time zones. + +Each entry is in the form (ABBR UTC-OFFSET DAYLIGHT-SAVING-TIME-P). +As specified in the RFCs, a time zone abbreviation like \"PST\" retains +its circa 1970 meaning even if legislation changes Pacific time.") (defvar parse-time-rules `(((6) parse-time-weekdays) @@ -163,6 +167,8 @@ affect the returned value of date and time, they only affect the last two members of the returned value. This function simply parses the textual representation of date and time into separate numerical values, and doesn't care whether the time is local or UTC. +Also, alphabetic time zone abbreviations like \"PST\" have their +circa 1970 meanings, even if current usage differs. See `decode-time' for the meaning of FORM." (condition-case () diff --git a/lisp/calendar/timeclock.el b/lisp/calendar/timeclock.el index acdf99f77ae..5ff938c3925 100644 --- a/lisp/calendar/timeclock.el +++ b/lisp/calendar/timeclock.el @@ -136,6 +136,11 @@ This variable only has effect if set with \\[customize]." (set symbol value)) :type 'boolean) +(defcustom timeclock-use-24hr-format nil + "If non-nil, use 24-hour clock when displaying times. +Otherwise use 12-hour clock with AM/PM suffix." + :type 'boolean) + (defvar timeclock-update-timer nil "The timer used to update `timeclock-mode-string'.") @@ -411,11 +416,8 @@ worked today, ignoring the time worked on previous days." (status (format "Currently %s since %s (%s), %s %s, leave at %s" (if last-in "IN" "OUT") - (if show-seconds - (format-time-string "%-I:%M:%S %p" - (nth 1 timeclock-last-event)) - (format-time-string "%-I:%M %p" - (nth 1 timeclock-last-event))) + (format-time-string (timeclock-time-format show-seconds) + (nth 1 timeclock-last-event)) (or (nth 2 timeclock-last-event) (if last-in "**UNKNOWN**" "workday over")) (timeclock-seconds-to-string remainder show-seconds t) @@ -539,10 +541,8 @@ relative only to the time worked today, and not to past time." ;; Should today-only be removed in favor of timeclock-relative? - gm (interactive) (let* ((then (timeclock-when-to-leave today-only)) - (string - (if show-seconds - (format-time-string "%-I:%M:%S %p" then) - (format-time-string "%-I:%M %p" then)))) + (string (format-time-string (timeclock-time-format show-seconds) + then))) (if (called-interactively-p 'interactive) (message "%s" string) string))) @@ -1171,7 +1171,9 @@ HTML-P is non-nil, HTML markup is added." (setq done t)) (insert "OUT"))) (unless done - (insert " since " (format-time-string "%Y/%m/%d %-I:%M %p" begin)) + (insert " since " (format-time-string + (concat "%Y/%m/%d " (timeclock-time-format)) + begin)) (if html-p (insert "<br>\n<b>") (insert "\n*")) @@ -1322,6 +1324,14 @@ HTML-P is non-nil, HTML markup is added." (interactive) (find-file-other-window timeclock-file)) +(defun timeclock-time-format (&optional seconds) + "Return a time format string suitable for format-time-string. +Use 24-hour clock if `timeclock-use-24hr-format' is non-nil, otherwise +use 12-hour clock. Include seconds field if SECONDS is non-nil." + (if timeclock-use-24hr-format + (if seconds "%-H:%M:%S" "%-H:%M") + (if seconds "%-I:%M:%S %p" "%-I:%M %p"))) + (provide 'timeclock) (run-hooks 'timeclock-load-hook) diff --git a/lisp/cedet/ede.el b/lisp/cedet/ede.el index 36864e6f3e9..478d8911c1f 100644 --- a/lisp/cedet/ede.el +++ b/lisp/cedet/ede.el @@ -469,7 +469,7 @@ To be used in hook functions." ;; Emacs 21 has no buffer file name for directory edits. ;; so we need to add these hacks in. (eq major-mode 'dired-mode) - (eq major-mode 'vc-dir-mode)) + (derived-mode-p 'vc-dir-mode)) (ede-minor-mode 1))) (define-minor-mode ede-minor-mode diff --git a/lisp/comint.el b/lisp/comint.el index 95e117d999a..e5418f4ee67 100644 --- a/lisp/comint.el +++ b/lisp/comint.el @@ -4234,7 +4234,9 @@ function called, or nil, if no function was called (if BEG = END)." (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 the whole field surrounding the region. + ;; `syntax-propertize' can't widen so avoid the need to (bug#81243). + (syntax-propertize beg2) (narrow-to-region beg2 end2)) (setq return-end (list (funcall fun beg1 (marker-position end1))))) diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el index 3687f231f94..18e649987f2 100644 --- a/lisp/cus-edit.el +++ b/lisp/cus-edit.el @@ -1104,6 +1104,22 @@ even if it doesn't match the type.) (put variable 'custom-check-value (list value)) (funcall (or (get variable 'custom-set) #'set-default) variable value)) +;;;###autoload +(defcustom setopt-local-type-mismatch nil + "Behavior of `setopt-local’ if value's type doesn't match its definition. +If nil, emit a warning, but accept the mismatched value. +If the symbol `accept', ignore type mismatch warning and assign the value. +If the symbol `discard', ignore warning and discard the mismatched value. +If any other non-nil value, prompt whether to accept or discard the value. +Note: Accepting mismatched values may result in unexpected behavior." + :type '(choice (const :tag "Emit a warning and accept the type value" nil) + (const :tag "Prompt to accept or discard the value" t) + (const :tag "Ignore the warning and accept the value" accept) + (const :tag "Ignore the warning and discard the value" discard)) + :version "32.1" + :safe #'symbolp + :group 'customize) + ;;;###autoload (defmacro setopt-local (&rest pairs) "Set buffer local VARIABLE/VALUE pairs, and return the final VALUE. @@ -1135,17 +1151,38 @@ Signal an error if a `custom-set' form does not support the ;;;###autoload (defun setopt--set-local (variable value) + "Set a buffer local VARIABLE to VALUE. +Consult `setopt-local-type-mismatch'." (custom-load-symbol variable) - ;; Check that the type is correct. - (when-let* ((type (get variable 'custom-type))) - (unless (widget-apply (widget-convert type) :match value) - (warn "Value does not match %S's type `%S': %S" variable type value))) - (condition-case _ - (funcall (or (get variable 'custom-set) - (lambda (x v &optional _) (set-local x v))) - variable value 'buffer-local) - (wrong-number-of-arguments - (error "The setter of %S does not support setopt-local" variable)))) + (let ((accept t)) + ;; Check that the type is correct. + (when-let* ((type (get variable 'custom-type))) + (unless (widget-apply (widget-convert type) :match value) + (let ((msg (format-message + "Value does not match %S's type `%S': %S" + variable type value))) + (cond + ;; Fall through and try anyway. + ((eq setopt-local-type-mismatch 'accept)) + ;; Silently discard the mismatched value. + ((eq setopt-local-type-mismatch 'discard) + (setq accept nil)) + ;; Prompt to accept or discard the value. + (setopt-local-type-mismatch + (setq accept (eq ?a (car + (read-multiple-choice msg + '((?a "accept" "Accept") + (?d "discard" "Discard"))))))) + (t + (warn msg)))))) + (when accept + (condition-case _ + (funcall (or (get variable 'custom-set) + (lambda (x v &optional _) (set-local x v))) + variable value 'buffer-local) + (wrong-number-of-arguments + (warn "The setter of %S lacks support for setopt-local" variable) + (set-local variable value)))))) ;;;###autoload (defun customize-save-variable (variable value &optional comment) diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 0ba77b197cc..bf5b331a30f 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -378,7 +378,11 @@ Leaving \"Default\" unchecked is equivalent with specifying a default of "26.1") (tooltip-reuse-hidden-frame tooltip boolean "26.1") (use-system-tooltips tooltip boolean "29.1") - (after-delete-frame-select-mru-frame frames boolean "31.1") + (delete-frame-choose-selected + frames + (choice (const :tag "Most recently used" mru) + (const :tag "Oldest visible " nil)) + "31.1") ;; fringe.c (overflow-newline-into-fringe fringe boolean) ;; image.c diff --git a/lisp/dabbrev.el b/lisp/dabbrev.el index 9fe2904c415..be4fbae9434 100644 --- a/lisp/dabbrev.el +++ b/lisp/dabbrev.el @@ -601,7 +601,7 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]." (message nil)) ;; To get correct further expansions we have to be sure to use the ;; buffer containing the already found expansions. - (when dabbrev--last-buffer-found + (when (buffer-live-p dabbrev--last-buffer-found) (setq buf dabbrev--last-buffer-found)) ;; If the buffer where we called dabbrev-expand differs from the ;; buffer containing the expansion, make sure copy-marker is diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el index a870f610094..50287a67129 100644 --- a/lisp/dired-aux.el +++ b/lisp/dired-aux.el @@ -361,12 +361,16 @@ only in the active region if `dired-mark-region' is non-nil." dir1 nil (lambda () (dired-mark-if - (member (dired-get-filename nil t) file-list1) nil))) + (and (not (dired--hidden-p)) + (member (dired-get-filename nil t) file-list1)) + nil))) (dired-fun-in-all-buffers dir2 nil (lambda () (dired-mark-if - (member (dired-get-filename nil t) file-list2) nil))) + (and (not (dired--hidden-p)) + (member (dired-get-filename nil t) file-list2)) + nil))) (message "Marked in dir1: %s, in dir2: %s" (format-message (ngettext "%d file" "%d files" (length file-list1)) (length file-list1)) diff --git a/lisp/dired-x.el b/lisp/dired-x.el index ecd7c83e42a..128332bb0cf 100644 --- a/lisp/dired-x.el +++ b/lisp/dired-x.el @@ -552,6 +552,7 @@ files in the active region if `dired-mark-region' is non-nil." (let ((dired-marker-char (if unflag-p ?\s dired-marker-char))) (dired-mark-if (and + (not (dired--hidden-p)) (if unflag-p ;; Already marked. (not (= (following-char) ?\s)) diff --git a/lisp/dired.el b/lisp/dired.el index 9ce3f042f6b..53ec6779061 100644 --- a/lisp/dired.el +++ b/lisp/dired.el @@ -1459,10 +1459,20 @@ The return value is the target column for the file names." ;; (buffer-local), so we can call dired-readin: (let ((failed t)) (unwind-protect - (progn (dired-readin) - (unless (and dired--ls-error-buffer - (get-buffer "*ls error*")) - (setq failed nil))) + (progn + ;; `dired--ls-error-buffer' should only be set in + ;; `insert-directory', and if `ls' errors and the buffer + ;; displaying the error message pops ups, + ;; `dired--ls-error-buffer' is then unset. But if for + ;; some reason it gets set before the next Dired + ;; buffer-display command is invoked, this can raise an + ;; error, so ensure the variable is unset before reading + ;; the directory contents into a Dired buffer. + (setq dired--ls-error-buffer nil) + (dired-readin) + (unless (and dired--ls-error-buffer + (get-buffer "*ls error*")) + (setq failed nil))) ;; If either `dired-readin' failed (e.g. if parent directories ;; are inaccessible) or `ls' errored, don't leave the Dired ;; buffer around. @@ -4756,6 +4766,7 @@ object files--just `.o' will mark more than you might think." (dired-mark-if (and (not (looking-at-p dired-re-dot)) (not (eolp)) ; empty line + (not (dired--hidden-p)) (let ((fn (dired-get-filename t t))) (and fn (string-match-p regexp fn)))) "matching file"))) @@ -4807,6 +4818,7 @@ since it was last visited." (dired-mark-if (and (not (looking-at-p dired-re-dot)) (not (eolp)) ; empty line + (not (dired--hidden-p)) (let ((fn (dired-get-filename nil t))) (when (and fn (file-readable-p fn) (not (file-directory-p fn))) diff --git a/lisp/electric.el b/lisp/electric.el index 3e5b81c86a7..e2deb7aa63d 100644 --- a/lisp/electric.el +++ b/lisp/electric.el @@ -193,7 +193,7 @@ Returns nil when we can't find this char." ;;; Electric indentation. (defcustom electric-indent-actions nil - "List of actions to indent. + "List of `electric-indent-mode' actions that can reindent. The valid elements of this list can be: - `yank': Indent the yanked text only if point is not in a string or @@ -219,17 +219,19 @@ significant." ;; value, which only works well if the variable is preloaded. ;;;###autoload (defvar electric-indent-chars '(?\n) - "Characters that should cause automatic reindentation.") + "Characters that can cause `electric-indent-mode' to reindent.") (defvar electric-indent-functions nil "Special hook run to decide whether to auto-indent. -Each function is called with one argument (the inserted char), with -point right after that char, and it should return t to cause indentation, -`no-indent' to prevent indentation or nil to let other functions decide.") +This hook is used by `electric-indent-mode'. Each function is called +with one argument (the inserted char), with point right after that char, +and it should return t to cause indentation, `no-indent' to prevent +indentation or nil to let other functions decide.") (defvar-local electric-indent-inhibit nil - "If non-nil, reindentation is not appropriate for this buffer. -This should be set by major modes such as `python-mode' since + "If non-nil, inhibit reindentation by `electric-indent-mode'. +This should be non-nil if reindentation is not appropriate for this +buffer. This should be set by major modes such as `python-mode' since Python does not lend itself to fully automatic indentation.") (defvar electric-indent-functions-without-reindent @@ -241,7 +243,7 @@ not try to reindent lines. It is normally better to make the major mode set `electric-indent-inhibit', but this can be used as a workaround.") (defun electric-indent-can-reindent-p () - "Return t if `electric-indent-mode' can performs reindentation." + "Return t if `electric-indent-mode' can perform reindentation." (not (or (memq indent-line-function electric-indent-functions-without-reindent) electric-indent-inhibit))) @@ -273,7 +275,8 @@ mode set `electric-indent-inhibit', but this can be used as a workaround.") (indent-region (point-min) (point-max)))))) (defun electric-indent--activate-indent-actions (enable) - "Enable the actions specified in `electric-indent-actions'." + "If ENABLE is non-nil, enable the actions in `electric-indent-actions'. +If ENABLE is nil, disable them." (advice-remove 'yank #'electric-indent--yank-advice) (remove-hook 'before-save-hook #'electric-indent-save-hook) (when enable @@ -419,6 +422,8 @@ use `electric-indent-local-mode'." (defvar electric-layout-rules nil "List of rules saying where to automatically insert newlines. +These rules control the behavior of `electric-layout-mode'. + Each rule has the form (CHAR . WHERE), the rule matching if the character just inserted was CHAR. WHERE specifies where to insert newlines, and can be: @@ -442,14 +447,16 @@ function of a single argument, the character just inserted. It is called at that position, and should return a value compatible with WHERE if the rule matches, or nil if it doesn't match. -If multiple rules match, only first one is executed.") +If multiple rules match, only the first one is executed.") ;; TODO: Make this a defcustom? (defvar electric-layout-allow-duplicate-newlines nil - "If non-nil, allow duplication of `before' newlines.") + "If non-nil, allow `electric-layout-mode' to duplicate `before' newlines. +See `electric-layout-rules' for the meaning of `before' in this context.") (defvar electric-layout-allow-in-comment-or-string nil - "If non-nil, allow inserting newlines inside a comment or string.") + "If non-nil, `electric-layout-mode' works inside comments and strings. +Otherwise the mode leaves comments and strings alone.") (defun electric-layout-post-self-insert-function () (when electric-layout-mode @@ -566,12 +573,14 @@ The variable `electric-layout-rules' says when and how to insert newlines." ;;; Electric quoting. (defcustom electric-quote-comment t - "Non-nil means to use electric quoting in program comments." + "Non-nil means `electric-quote-mode' acts in program comments. +Otherwise, the mode leaves program comments alone." :version "25.1" :type 'boolean :safe 'booleanp :group 'electricity) (defcustom electric-quote-string nil - "Non-nil means to use electric quoting in program strings." + "Non-nil means `electric-quote-mode' acts in program strings. +Otherwise, the mode leaves program strings alone." :version "25.1" :type 'boolean :safe 'booleanp :group 'electricity) @@ -621,6 +630,13 @@ The variable `electric-layout-rules' says when and how to insert newlines." This list's members correspond to left single quote, right single quote, left double quote, and right double quote, respectively. +When `electric-quote-mode' is enabled, as you type it replaces \\=` with +the first element of this list, \\=' with the second element, \\=`\\=` +with the third, and \\='\\=' with the fourth. This occurs only in +comments, strings, and text paragraphs, and these are selectively +controlled with `electric-quote-comment', `electric-quote-string', and +`electric-quote-paragraph'. + Commonly used pairs are predefined, or you can define your own completely custom style." :version "26.1" @@ -642,31 +658,47 @@ completely custom style." :group 'electricity) (defcustom electric-quote-paragraph t - "Non-nil means to use electric quoting in text paragraphs." + "Non-nil means `electric-quote-mode' acts in text paragraphs. +Otherwise, the mode leaves text paragraphs alone." :version "25.1" :type 'boolean :safe 'booleanp :group 'electricity) (defcustom electric-quote-context-sensitive nil "Non-nil means to replace \\=' with an electric quote depending on context. -If `electric-quote-context-sensitive' is non-nil, Emacs replaces -\\=' and \\='\\=' with an opening quote after a line break, -whitespace, opening parenthesis, or quote and leaves \\=` alone." +If `electric-quote-context-sensitive' is non-nil and `electric-quote-mode' +is enabled, as you type Emacs replaces \\=' and \\='\\=' with an opening +quote after a line break, whitespace, opening parenthesis, or quote and +leaves \\=` alone. + +The replacing quote character is defined by `electric-quote-chars'." :version "26.1" :type 'boolean :safe #'booleanp :group 'electricity) (defcustom electric-quote-replace-double nil "Non-nil means to replace \" with an electric double quote. -Emacs replaces \" with an opening double quote after a line -break, whitespace, opening parenthesis, or quote, and with a -closing double quote otherwise." +If `electric-quote-replace-double' is non-nil and `electric-quote-mode' +is enabled, as you type Emacs replaces \" with an opening double quote +after a line break, whitespace, opening parenthesis, or quote, and with +a closing double quote otherwise. + +The replacing double quote characters are defined by +`electric-quote-chars'." :version "26.1" :type 'boolean :safe #'booleanp :group 'electricity) (defcustom electric-quote-replace-consecutive t "Non-nil means to replace a pair of single quotes with a double quote. -Two single quotes are replaced by the corresponding double quote -when the second quote of the pair is entered (i.e. by typing ` or -') by default. If nil, the single quotes are not altered." +If `electric-quote-replace-consecutive' is non-nil and +`electric-quote-mode' is enabled, as you type Emacs replaces two single +quotes with the corresponding double quote when the second quote of the +pair is entered (i.e. by typing \\=` or \\=') by default. For example, +with the default setting of `electric-quote-chars', if you type +\\=`\\=`, Emacs replaces both characters with a single “. + +If this option is nil, the single quotes are not altered. + +The replacing double quote characters are defined by +`electric-quote-chars'." :version "29.1" :type 'boolean :safe #'booleanp @@ -674,13 +706,13 @@ when the second quote of the pair is entered (i.e. by typing ` or (defvar electric-quote-inhibit-functions () "List of functions that should inhibit electric quoting. -When the variable `electric-quote-mode' is non-nil, Emacs will -call these functions in order after the user has typed an \\=` or -\\=' character. If one of them returns non-nil, electric quote -substitution is inhibited. The functions are called after the -\\=` or \\=' character has been inserted with point directly -after the inserted character. The functions in this hook should -not move point or change the current buffer.") +When `electric-quote-mode' is enabled, Emacs will call these functions +in order after the user has typed an \\=` or \\=' character (or a \" +character if `electric-quote-replace-double' is non-nil). If one of +them returns non-nil, electric quote substitution is inhibited. The +functions are called after the \\=` or \\=' character has been inserted +with point directly after the inserted character. The functions in this +hook should not move point or change the current buffer.") (defvar electric-pair-text-pairs) @@ -761,8 +793,10 @@ and text paragraphs, and these are selectively controlled with `electric-quote-comment', `electric-quote-string', and `electric-quote-paragraph'. -Customize `electric-quote-chars' to use characters other than the -ones listed here. Also see `electric-quote-replace-consecutive'. +Customize `electric-quote-chars' to use characters other than the ones +listed here. To also replace \" with “ or ” depending on the context, +see `electric-quote-replace-double'. Also see +`electric-quote-replace-consecutive'. This is a global minor mode. To toggle the mode in a single buffer, use `electric-quote-local-mode'." diff --git a/lisp/emacs-lisp/backtrace.el b/lisp/emacs-lisp/backtrace.el index 440061e6e29..dfdd026dd4f 100644 --- a/lisp/emacs-lisp/backtrace.el +++ b/lisp/emacs-lisp/backtrace.el @@ -813,7 +813,11 @@ Fall back to `prin1' if there is an error." (defun backtrace--filter-visible (beg end &optional _delete) "Return the visible text between BEG and END." - (let ((result "")) + (let ((result "") + (b (min beg end)) + (e (max beg end))) + ;; Make sure BEG and END are in the correct order. + (setq beg b end e) (while (< beg end) (let ((next (next-single-char-property-change beg 'invisible))) (unless (get-char-property beg 'invisible) diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 7ed71346451..a596dee6844 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el @@ -1771,7 +1771,7 @@ See Info node `(elisp) Integer Basics'." ;; json.c json-serialize json-parse-string ;; keyboard.c - posn-at-point posn-at-x-y + posn-at-point posn-at-x-y posn-point ;; keymap.c copy-keymap keymap-parent keymap-prompt make-keymap make-sparse-keymap ;; lread.c diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 669f26f3647..5e37606223b 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el @@ -358,7 +358,11 @@ A value of `all' really means all." (const :tag "All" all) (set :menu-tag "Some" ,@(mapcar (lambda (x) `(const ,x)) - byte-compile-warning-types)))) + byte-compile-warning-types)) + (cons :tag "All Except" + (const :tag "Not" not) + (set ,@(mapcar (lambda (x) `(const ,x)) + byte-compile-warning-types))))) (defconst byte-compile--emacs-build-warning-types '(docstrings-non-ascii-quotes) diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index 9fa2a2b7cf0..2cc9b169314 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el @@ -694,8 +694,10 @@ its argument list allows full Common Lisp conventions." (setq ,var nil)) (t (error - ,(format "Keyword argument %%S not one of %S" - keys) + ,(format "Keyword argument %%S not one of %s" + ;; Escape % in slot names. + (string-replace "%" "%%" + (format "%S" keys))) (car ,var))))))) (push `(let ((,var ,restarg)) ,check) cl--bind-forms))))) (cl--do-&aux args) @@ -3293,8 +3295,9 @@ To see the documentation for a defined struct type, use ;; the parent's accessor? (push `(define-inline ,accessor (x) ,(let ((long-docstring - (format "Access slot \"%s\" of `%s' struct X." - slot name))) + (internal--format-docstring-line + "Access slot \"%s\" of `%s' struct X." + slot name))) (concat ;; NB. This will produce incorrect results ;; in some cases, as our coding conventions @@ -3315,7 +3318,7 @@ To see the documentation for a defined struct type, use "\n" (internal--format-docstring-line "Struct X is a `%s'." name)) - (internal--format-docstring-line long-docstring)) + long-docstring) (if doc (concat "\n" doc) "") "\n" (format "\n\n(fn %s X)" accessor))) diff --git a/lisp/emacs-lisp/debug-early.el b/lisp/emacs-lisp/debug-early.el index 02dc275c02f..9786b267bf5 100644 --- a/lisp/emacs-lisp/debug-early.el +++ b/lisp/emacs-lisp/debug-early.el @@ -115,8 +115,12 @@ available before `debug' was usable.)" (defalias 'debug-early--handler ;Called from C. #'(lambda (err) - (if backtrace-on-error-noninteractive - (debug--early err #'debug-early--handler)))) + ;; Do the same `inhibit-debugger' dance as we do in + ;; `(maybe_)call_debugger' to avoid nested debugging (bug#80916). + (if (and backtrace-on-error-noninteractive + (not inhibit-debugger)) + (let ((inhibit-debugger t)) + (debug--early err #'debug-early--handler))))) (defalias 'debug-early--muted ;Called from C. #'(lambda (err) diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el index 3bb12e18842..29cb0350415 100644 --- a/lisp/emacs-lisp/edebug.el +++ b/lisp/emacs-lisp/edebug.el @@ -1318,7 +1318,7 @@ infinite loops when the code/environment contains a circular object.") (aref sexp 0) (mapcar #'edebug-unwrap* (aref sexp 1)) (mapcar (lambda (x) (if (consp x) (cons (car x) (edebug-unwrap* (cdr x))) x)) (aref sexp 2)) - (documentation sexp 'raw) (interactive-form sexp))) + (documentation sexp 'raw) (edebug-unwrap* (interactive-form sexp)))) (t sexp))) @@ -2721,6 +2721,11 @@ when edebug becomes active." edebug-function) )) + ;; Margin setup for overlay arrow when there is no left + ;; fringe. + (when (zerop (car (window-fringes))) + (edebug-prepare-margin)) + ;; Make sure we bind those in the right buffer (bug#16410). (let ((overlay-arrow-position overlay-arrow-position) (overlay-arrow-string overlay-arrow-string)) @@ -3001,6 +3006,17 @@ when edebug becomes active." ) "Association list of arrows for each edebug mode.") +(defun edebug-prepare-margin () + "Increase (or set) left margin with the size of the longest arrow string." + (let ((arrow-len (apply #'max (mapcar (lambda (x) + (string-width (cdr x))) + edebug-arrow-alist))) + (margins (window-margins))) + ;; Set or increase left margin. + (if (numberp (car margins)) + (set-window-margins nil (+ (car margins) arrow-len)) + (set-window-margins nil arrow-len)))) + (defun edebug-overlay-arrow () ;; Set up the overlay arrow at beginning-of-line in current buffer. ;; The arrow string is derived from edebug-arrow-alist and @@ -3011,7 +3027,6 @@ when edebug becomes active." (setq overlay-arrow-position (make-marker)) (set-marker overlay-arrow-position pos (current-buffer)))) - (defun edebug-toggle-save-all-windows () "Toggle the saving and restoring of all windows. Also, each time you toggle it on, the inside and outside window diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el index 55f9fb1988b..7b12024cba6 100644 --- a/lisp/emacs-lisp/eldoc.el +++ b/lisp/emacs-lisp/eldoc.el @@ -140,10 +140,15 @@ is only skipped if the documentation needs to be truncated there." (defcustom eldoc-help-at-pt nil "If non-nil, show `help-at-pt-kbd-string' at point via Eldoc. -This setting is an alternative to `help-at-pt-display-when-idle'. If -the value is non-nil, `eldoc-show-help-at-pt' will show help-at-point -via Eldoc." +This setting is an alternative to `help-at-pt-display-when-idle'. In +order to enable help at point only in certain buffers add +`eldoc-show-help-at-pt' locally to `eldoc-documentation-functions'." :type 'boolean + :set (lambda (sym val) + (custom-set-default sym val) + (if val + (add-hook 'eldoc-documentation-functions #'eldoc-show-help-at-pt 90) + (remove-hook 'eldoc-documentation-functions #'eldoc-show-help-at-pt))) :version "31.1") (defface eldoc-highlight-function-argument @@ -417,7 +422,7 @@ Also store it in `eldoc-last-message' and return that value." (overlay-end show-paren--overlay))))))) -(defvar eldoc-documentation-functions (list #'eldoc-show-help-at-pt) +(defvar eldoc-documentation-functions nil "Hook of functions that produce doc strings. A doc string is typically relevant if point is on a function-like @@ -813,7 +818,9 @@ all." (defun eldoc--supported-p () "Non-nil if an ElDoc function is set for this buffer." - (and (not (memq eldoc-documentation-strategy '(nil ignore))) + ;; Exclude ephemeral *eldoc* buffers, to avoid blinking (bug#81356). + (and (not (string-prefix-p " *eldoc" (buffer-name))) + (not (memq eldoc-documentation-strategy '(nil ignore))) (or eldoc-documentation-functions ;; The old API had major modes set `eldoc-documentation-function' ;; to provide eldoc support. It's impossible now to determine @@ -973,9 +980,11 @@ the docstrings eventually produced, using (eldoc--invoke-strategy nil)))))) (defun eldoc-show-help-at-pt (&rest _) - "Show help at point via Eldoc if `eldoc-help-at-pt' is non-nil. -Intended for `eldoc-documentation-functions' (which see)." - (when-let* ((help (and eldoc-help-at-pt (help-at-pt-kbd-string)))) + "Show help at point via Eldoc taken from `help-at-pt-kbd-string'. +This function is intended to be added buffer-locally by major modes to +`eldoc-documentation-functions'. In order to enable help at point +globally, users can set `eldoc-help-at-pt' to t." + (when-let* ((help (help-at-pt-kbd-string))) (format "Help: %s" (substitute-command-keys help)))) diff --git a/lisp/emacs-lisp/elisp-scope.el b/lisp/emacs-lisp/elisp-scope.el index f95ea41e496..a81a7dfacaf 100644 --- a/lisp/emacs-lisp/elisp-scope.el +++ b/lisp/emacs-lisp/elisp-scope.el @@ -108,7 +108,7 @@ ;; ;; When analyzer functions invoke `elisp-scope-1/n' to analyze some ;; sub-forms, they specify the OUTSPEC argument to convey information -;; but the expected value of the evaluated sub-form(s), so +;; about the expected value of the evaluated sub-form(s), so ;; `elisp-scope-1/n' will know what to do with a sub-form that is just ;; (quoted) data. For example, the analyzer function for ;; `face-attribute' calls `elisp-scope-1' to analyze its first argument @@ -130,6 +130,10 @@ ;; ;; See also the docstring of `elisp-scope-1' for details about the ;; format of the `outspec' argument. +;; +;; To define custom analyzers, you can use the macros +;; `elisp-scope-define-function-spec' and +;; `elisp-scope-define-macro-analyzer', which see. ;;; Code: @@ -1576,16 +1580,23 @@ property, or if the current buffer is trusted (see `trusted-content-p')." (defmacro elisp-scope-define-analyzer (fsym args &rest body) "Define an analyzer function for function/macro FSYM. +FSYM is a symbol, or a list of symbols that all share the same analyzer. ARGS is the arguments list of the analyzer function, and BODY is its body." (declare (indent defun)) - (let ((analyzer (intern (concat "elisp-scope--analyze-" (symbol-name fsym))))) + (let* ((syms (ensure-list fsym)) + (fsym (car syms)) + (analyzer (intern (concat "elisp-scope--analyze-" (symbol-name fsym))))) `(progn (defun ,analyzer ,args ,@body) - (put ',fsym 'elisp-scope-analyzer #',analyzer)))) + . ,(mapcar (lambda (sym) + `(put ',sym 'elisp-scope-analyzer #',analyzer)) + syms)))) (defmacro elisp-scope--define-function-analyzer (fsym args role &rest body) (declare (indent defun)) - (let ((helper (intern (concat "elisp-scope--analyze-" (symbol-name fsym) "-1")))) + (let ((helper (intern (concat "elisp-scope--analyze-" + (symbol-name (car (ensure-list fsym))) + "-1")))) `(progn (defun ,helper ,args ,@body) (elisp-scope-define-analyzer ,fsym (f &rest args) @@ -1594,19 +1605,48 @@ ARGS is the arguments list of the analyzer function, and BODY is its body." (defmacro elisp-scope-define-function-analyzer (fsym args &rest body) "Define an analyzer function for function FSYM. +FSYM is a symbol, or a list of symbols that all share the same analyzer. The analyzer function analyzes occurrences of FSYM as a function call, and it analyzes the arguments in calls to FSYM by executing BODY with ARGS bound to the analyzed arguments." (declare (indent defun)) `(elisp-scope--define-function-analyzer ,fsym ,args function ,@body)) +(defun elisp-scope--analyze-function-args (args specs &optional rest-spec) + (while (and args specs) (elisp-scope-1 (pop args) (pop specs))) + (dolist (arg args) (elisp-scope-1 arg rest-spec))) + +(defmacro elisp-scope-define-function-spec (fsym arg-specs &optional rest-spec) + "Specify how to analyze arguments of FSYM. +FSYM is a function symbol or a list of function symbols, and ARG-SPECS +is a list of output specs corresponding to the arguments of FSYM. +Optional argument REST-SPEC is the output spec of any remaining +arguments after those specified by ARG-SPECS. + +For example, the following form says that the functions `foo' and `bar' +take a face name as their second argument, and that all arguments after +the second are macro names. The first argument remains unspecified. + + (elisp-scope-define-function-spec (foo bar) + (nil (symbol . face)) + (symbol . macro))" + (declare (indent 1)) + `(elisp-scope-define-function-analyzer ,fsym (&rest args) + (elisp-scope--analyze-function-args args ',arg-specs ',rest-spec))) + +(elisp-scope-define-function-spec elisp-scope--analyze-function-args + (nil (repeat . spec) spec)) + (defmacro elisp-scope-define-macro-analyzer (fsym args &rest body) "Define an analyzer function for macro FSYM. +FSYM is a symbol, or a list of symbols that all share the same analyzer. The analyzer function analyzes occurrences of FSYM as a macro call, and it analyzes the arguments in calls to FSYM by executing BODY with ARGS bound to the analyzed arguments." (declare (indent defun)) - (let ((helper (intern (concat "elisp-scope--analyze-" (symbol-name fsym) "-1")))) + (let ((helper (intern (concat "elisp-scope--analyze-" + (symbol-name (car (ensure-list fsym))) + "-1")))) `(progn (defun ,helper ,args ,@body) (elisp-scope-define-analyzer ,fsym (f &rest args) @@ -1615,11 +1655,14 @@ bound to the analyzed arguments." (defmacro elisp-scope-define-special-form-analyzer (fsym args &rest body) "Define an analyzer function for special form FSYM. +FSYM is a symbol, or a list of symbols that all share the same analyzer. The analyzer function analyzes occurrences of FSYM as a special form, and it analyzes the arguments in calls to FSYM by executing BODY with ARGS bound to the analyzed arguments." (declare (indent defun)) - (let ((helper (intern (concat "elisp-scope--analyze-" (symbol-name fsym) "-1")))) + (let ((helper (intern (concat "elisp-scope--analyze-" + (symbol-name (car (ensure-list fsym))) + "-1")))) `(progn (defun ,helper ,args ,@body) (elisp-scope-define-analyzer ,fsym (f &rest args) @@ -1647,16 +1690,10 @@ ARGS bound to the analyzed arguments." (elisp-scope-1 (or (elisp-scope--unquote form) form)) (elisp-scope-1 lexical)) -(elisp-scope-define-function-analyzer funcall (&optional f &rest args) - (elisp-scope-1 f '(symbol . function)) - (elisp-scope-n args)) +(elisp-scope-define-function-spec (funcall apply) ((symbol . function))) -(put 'apply 'elisp-scope-analyzer #'elisp-scope--analyze-funcall) - -(elisp-scope-define-function-analyzer defalias (&optional sym def docstring) - (elisp-scope-1 sym '(symbol . defun)) - (elisp-scope-1 def '(symbol . defun)) - (elisp-scope-1 docstring)) +(elisp-scope-define-function-spec defalias + ((symbol . defun) (symbol . defun))) (elisp-scope-define-function-analyzer oclosure--define (&optional name docstring parent-names slots &rest props) @@ -1676,120 +1713,81 @@ ARGS bound to the analyzed arguments." (setq props (cddr props))) (when props (elisp-scope-n props))) -(elisp-scope-define-function-analyzer define-charset - (&optional name docstring &rest props) - (elisp-scope-1 name '(symbol . defcharset)) - (elisp-scope-1 docstring) - (elisp-scope-n props)) - -(elisp-scope-define-function-analyzer define-charset-alias - (&optional alias charset) - (elisp-scope-1 alias '(symbol . defcharset)) - (elisp-scope-1 charset '(symbol . charset))) - -(elisp-scope-define-function-analyzer charset-chars - (&optional charset &rest rest) - (elisp-scope-1 charset '(symbol . charset)) - (elisp-scope-n rest)) - -(dolist (sym '(charset-description charset-info charset-iso-final-char - charset-long-name charset-plist - charset-short-name - get-charset-property put-charset-property - list-charset-chars - set-charset-plist - set-charset-priority - unify-charset - locale-charset-to-coding-system)) - (put sym 'elisp-scope-analyzer #'elisp-scope--analyze-charset-chars)) - -(elisp-scope-define-function-analyzer define-coding-system - (&optional name &rest rest) - (elisp-scope-1 name '(symbol . defcoding)) - (mapc #'elisp-scope-1 rest)) - -(elisp-scope-define-function-analyzer define-coding-system-alias - (&optional alias coding-system) - (elisp-scope-1 alias '(symbol . defcoding)) - (elisp-scope-1 coding-system '(symbol . coding))) - -(elisp-scope-define-function-analyzer decode-coding-region - (&optional start end coding-system &rest rest) - (elisp-scope-1 start) - (elisp-scope-1 end) - (elisp-scope-1 coding-system '(symbol . coding)) - (elisp-scope-n rest)) - -(put 'encode-coding-region 'elisp-scope-analyzer #'elisp-scope--analyze-decode-coding-region) - -(elisp-scope-define-function-analyzer decode-coding-string - (&optional string coding-system &rest rest) - (elisp-scope-1 string) - (elisp-scope-1 coding-system '(symbol . coding)) - (elisp-scope-n rest)) - -(dolist (sym '(encode-coding-char encode-coding-string)) - (put sym 'elisp-scope-analyzer #'elisp-scope--analyze-decode-coding-string)) - -(elisp-scope-define-function-analyzer coding-system-mnemonic - (&optional coding-system &rest rest) - (elisp-scope-1 coding-system '(symbol . coding)) - (elisp-scope-n rest)) - -(dolist (sym '(add-to-coding-system-list - check-coding-system - coding-system-aliases - coding-system-base - coding-system-category - coding-system-change-eol-conversion - coding-system-change-text-conversion - coding-system-charset-list - coding-system-doc-string - coding-system-eol-type - coding-system-eol-type-mnemonic - coding-system-get - coding-system-plist - coding-system-post-read-conversion - coding-system-pre-write-conversion - coding-system-put - coding-system-translation-table-for-decode - coding-system-translation-table-for-encode - coding-system-type - describe-coding-system - prefer-coding-system - print-coding-system - print-coding-system-briefly - revert-buffer-with-coding-system - set-buffer-file-coding-system - set-clipboard-coding-system - set-coding-system-priority - set-default-coding-systems - set-file-name-coding-system - set-keyboard-coding-system - set-next-selection-coding-system - set-selection-coding-system - set-terminal-coding-system - universal-coding-system-argument)) - (put sym 'elisp-scope-analyzer #'elisp-scope--analyze-coding-system-mnemonic)) - -(elisp-scope-define-function-analyzer thing-at-point (&optional thing no-props) - (elisp-scope-1 thing '(symbol . thing)) - (elisp-scope-1 no-props)) - -(dolist (sym '( forward-thing - beginning-of-thing - end-of-thing - bounds-of-thing-at-point)) - (put sym 'elisp-scope-analyzer #'elisp-scope--analyze-thing-at-point)) - -(elisp-scope-define-function-analyzer bounds-of-thing-at-mouse (&optional event thing) - (elisp-scope-1 event) - (elisp-scope-1 thing '(symbol . thing))) - -(elisp-scope-define-function-analyzer thing-at-mouse (&optional event thing no-props) - (elisp-scope-1 event) - (elisp-scope-1 thing '(symbol . thing)) - (elisp-scope-1 no-props)) +(elisp-scope-define-function-spec define-charset ((symbol . defcharset))) + +(elisp-scope-define-function-spec define-charset-alias + ((symbol . defcharset) (symbol . charset))) + +(elisp-scope-define-function-spec + (charset-chars + charset-description charset-info charset-iso-final-char + charset-long-name charset-plist charset-short-name + get-charset-property put-charset-property list-charset-chars + set-charset-plist set-charset-priority unify-charset + locale-charset-to-coding-system) + ((symbol . charset))) + +(elisp-scope-define-function-spec define-coding-system ((symbol . defcoding))) + +(elisp-scope-define-function-spec define-coding-system-alias + ((symbol . defcoding) (symbol . coding))) + +(elisp-scope-define-function-spec + (decode-coding-region encode-coding-region) + (nil nil (symbol . coding))) + +(elisp-scope-define-function-spec + (decode-coding-string encode-coding-char encode-coding-string) + (nil (symbol . coding))) + +(elisp-scope-define-function-spec + (coding-system-mnemonic + add-to-coding-system-list + check-coding-system + coding-system-aliases + coding-system-base + coding-system-category + coding-system-change-eol-conversion + coding-system-change-text-conversion + coding-system-charset-list + coding-system-doc-string + coding-system-eol-type + coding-system-eol-type-mnemonic + coding-system-get + coding-system-plist + coding-system-post-read-conversion + coding-system-pre-write-conversion + coding-system-put + coding-system-translation-table-for-decode + coding-system-translation-table-for-encode + coding-system-type + describe-coding-system + prefer-coding-system + print-coding-system + print-coding-system-briefly + revert-buffer-with-coding-system + set-buffer-file-coding-system + set-clipboard-coding-system + set-coding-system-priority + set-default-coding-systems + set-file-name-coding-system + set-keyboard-coding-system + set-next-selection-coding-system + set-selection-coding-system + set-terminal-coding-system + universal-coding-system-argument) + ((symbol . coding))) + +(elisp-scope-define-function-spec + (thing-at-point + forward-thing beginning-of-thing end-of-thing bounds-of-thing-at-point) + ((symbol . thing))) + +(elisp-scope-define-function-spec bounds-of-thing-at-mouse + (nil (symbol . thing))) + +(elisp-scope-define-function-spec thing-at-mouse + (nil (symbol . thing))) (elisp-scope-define-function-analyzer custom-declare-variable (sym default doc &rest args) (elisp-scope-1 sym '(symbol . defvar)) @@ -1830,14 +1828,10 @@ ARGS bound to the analyzed arguments." (setq args (cddr args))) (when args (elisp-scope-n args))) -(elisp-scope-define-function-analyzer cl-typep (val type) - (elisp-scope-1 val) - (elisp-scope-1 type 'cl-type)) +(elisp-scope-define-function-spec cl-typep (nil cl-type)) -(elisp-scope-define-function-analyzer pulse-momentary-highlight-region (start end &optional face) - (elisp-scope-1 start) - (elisp-scope-1 end) - (elisp-scope-1 face '(symbol . face))) +(elisp-scope-define-function-spec pulse-momentary-highlight-region + (nil nil (symbol . face))) (elisp-scope--define-function-analyzer throw (&optional tag val) non-local-exit (elisp-scope-1 tag '(symbol . throw-tag)) @@ -1847,19 +1841,17 @@ ARGS bound to the analyzed arguments." (elisp-scope-1 error-symbol '(symbol . condition)) (elisp-scope-1 data)) -(elisp-scope--define-function-analyzer kill-emacs (&rest rest) non-local-exit +(elisp-scope--define-function-analyzer + (kill-emacs + abort-recursive-edit top-level exit-recursive-edit + tty-frame-restack error user-error + minibuffer-quit-recursive-edit exit-minibuffer) + (&rest rest) non-local-exit (elisp-scope-n rest)) -(dolist (sym '( abort-recursive-edit top-level exit-recursive-edit - tty-frame-restack error user-error - minibuffer-quit-recursive-edit exit-minibuffer)) - (put sym 'elisp-scope-analyzer #'elisp-scope--analyze-kill-emacs)) +(elisp-scope-define-function-spec run-hooks () (symbol . free-variable)) -(elisp-scope-define-function-analyzer run-hooks (&rest hooks) - (dolist (hook hooks) (elisp-scope-1 hook '(symbol . free-variable)))) - -(elisp-scope-define-function-analyzer fboundp (&optional symbol) - (elisp-scope-1 symbol '(symbol . function))) +(elisp-scope-define-function-spec fboundp ((symbol . function))) (elisp-scope-define-function-analyzer overlay-put (&optional ov prop val) (elisp-scope-1 ov) @@ -1870,63 +1862,47 @@ ARGS bound to the analyzed arguments." (when (memq (elisp-scope--sym-bare q) '(face mouse-face)) 'face)))) -(elisp-scope-define-function-analyzer add-face-text-property (&optional start end face &rest rest) - (elisp-scope-1 start) - (elisp-scope-1 end) - (elisp-scope-1 face 'face) - (elisp-scope-n rest)) - -(elisp-scope-define-function-analyzer facep (&optional face &rest rest) - (elisp-scope-1 face '(symbol . face)) - (elisp-scope-n rest)) - -(dolist (sym '( check-face face-id face-differs-from-default-p - face-name face-all-attributes face-attribute - face-foreground face-background face-stipple - face-underline-p face-inverse-video-p face-bold-p - face-italic-p face-extend-p face-documentation - set-face-documentation set-face-attribute - set-face-font set-face-background set-face-foreground - set-face-stipple set-face-underline set-face-inverse-video - set-face-bold set-face-italic set-face-extend)) - (put sym 'elisp-scope-analyzer #'elisp-scope--analyze-facep)) - -(elisp-scope-define-function-analyzer boundp (&optional var &rest rest) - (elisp-scope-1 var '(symbol . free-variable)) - (elisp-scope-n rest)) - -(dolist (sym '( set symbol-value define-abbrev-table - special-variable-p local-variable-p - local-variable-if-set-p add-variable-watcher - get-variable-watchers remove-variable-watcher - default-value set-default make-local-variable - buffer-local-value add-to-list add-to-history find-buffer - customize-set-variable set-variable - add-hook remove-hook run-hook-with-args run-hook-wrapped)) - (put sym 'elisp-scope-analyzer #'elisp-scope--analyze-boundp)) - -(elisp-scope-define-function-analyzer defvaralias (new base &optional docstring) - (elisp-scope-1 new '(symbol . defvar)) - (elisp-scope-1 base '(symbol . free-variable)) - (elisp-scope-1 docstring)) - -(elisp-scope-define-function-analyzer define-error (&optional name message parent) - (elisp-scope-1 name '(symbol . defcondition)) - (elisp-scope-1 message) - (elisp-scope-1 parent '(or (symbol . condition) - (repeat . (symbol . condition))))) - -(elisp-scope-define-function-analyzer featurep (feature &rest rest) - (elisp-scope-1 feature '(symbol . feature)) - (elisp-scope-n rest)) - -(put 'require 'elisp-scope-analyzer #'elisp-scope--analyze-featurep) - -(elisp-scope-define-function-analyzer provide (feature &rest rest) - (elisp-scope-1 feature '(symbol . deffeature)) - (elisp-scope-n rest)) - -(elisp-scope-define-function-analyzer put-text-property (&optional beg end prop val obj) +(elisp-scope-define-function-spec add-face-text-property (nil nil face)) + +(elisp-scope-define-function-spec + (facep + check-face face-id face-differs-from-default-p + face-name face-all-attributes face-attribute + face-foreground face-background face-stipple + face-underline-p face-inverse-video-p face-bold-p + face-italic-p face-extend-p face-documentation + set-face-documentation set-face-attribute + set-face-font set-face-background set-face-foreground + set-face-stipple set-face-underline set-face-inverse-video + set-face-bold set-face-italic set-face-extend) + ((symbol . face))) + +(elisp-scope-define-function-spec + (boundp + set symbol-value define-abbrev-table + special-variable-p local-variable-p + local-variable-if-set-p add-variable-watcher + get-variable-watchers remove-variable-watcher + default-value set-default make-local-variable + buffer-local-value add-to-list add-to-history find-buffer + customize-set-variable set-variable + add-hook remove-hook run-hook-with-args run-hook-wrapped) + ((symbol . free-variable))) + +(elisp-scope-define-function-spec defvaralias + ((symbol . defvar) (symbol . free-variable))) + +(elisp-scope-define-function-spec define-error + ((symbol . defcondition) nil + (or (symbol . condition) + (repeat . (symbol . condition))))) + +(elisp-scope-define-function-spec (featurep require) ((symbol . feature))) + +(elisp-scope-define-function-spec provide ((symbol . deffeature))) + +(elisp-scope-define-function-analyzer (put-text-property remove-overlays) + (&optional beg end prop val obj) (elisp-scope-1 beg) (elisp-scope-1 end) (elisp-scope-1 prop) @@ -1937,8 +1913,6 @@ ARGS bound to the analyzed arguments." 'face))) (elisp-scope-1 obj)) -(put 'remove-overlays 'elisp-scope-analyzer #'elisp-scope--analyze-put-text-property) - (elisp-scope-define-function-analyzer propertize (string &rest props) (elisp-scope-1 string) (while props @@ -1951,37 +1925,26 @@ ARGS bound to the analyzed arguments." (setq props (cddr props))) (when props (elisp-scope-n props))) -(elisp-scope-define-function-analyzer eieio-defclass-internal - (&optional name superclasses slots options) - (elisp-scope-1 name '(symbol . deftype)) - (elisp-scope-1 superclasses '(repeat . (symbol . type))) - (elisp-scope-1 slots - '(repeat - cons - (symbol . slot) - plist - (:initform . code) - (:initarg . (symbol . constant)) - (:accessor . (symbol . defun)) - (:allocation . code) - (:writer . (symbol . function)) - (:reader . (symbol . function)) - (:type . cl-type) - ;; TODO: add (:custom . custom-type) - )) - (elisp-scope-1 options)) - -(elisp-scope-define-function-analyzer cl-struct-define - (&optional name doc parent type named slots children tag print) - (elisp-scope-1 name '(symbol . deftype)) - (elisp-scope-1 doc) - (elisp-scope-1 parent '(symbol . type)) - (elisp-scope-1 type) - (elisp-scope-1 named) - (elisp-scope-1 slots) ;TODO: Specify type of `slots'. - (elisp-scope-1 children) - (elisp-scope-1 tag) - (elisp-scope-1 print)) +(elisp-scope-define-function-spec eieio-defclass-internal + ((symbol . deftype) + (repeat . (symbol . type)) + (repeat + cons + (symbol . slot) + plist + (:initform . code) + (:initarg . (symbol . constant)) + (:accessor . (symbol . defun)) + (:allocation . code) + (:writer . (symbol . function)) + (:reader . (symbol . function)) + (:type . cl-type) + ;; TODO: add (:custom . custom-type) + ))) + +;; TODO: Specify spec of the `slots' argument. +(elisp-scope-define-function-spec cl-struct-define + ((symbol . deftype) nil (symbol . type))) (elisp-scope-define-function-analyzer define-widget (name class doc &rest args) (elisp-scope-1 name '(symbol . widget-type-definition)) @@ -1998,63 +1961,43 @@ ARGS bound to the analyzed arguments." (setq args (cddr args))) (when args (elisp-scope-n args))) -(elisp-scope-define-function-analyzer provide-theme (name &rest rest) - (elisp-scope-1 name '(symbol . theme)) - (elisp-scope-n rest)) - -(dolist (sym '(enable-theme disable-theme load-theme custom-theme-p)) - (put sym 'elisp-scope-analyzer #'elisp-scope--analyze-provide-theme)) - -(elisp-scope-define-function-analyzer custom-theme-set-variables (theme &rest args) - (elisp-scope-1 theme '(symbol . theme)) - (dolist (arg args) - (elisp-scope-1 - arg - '(cons (symbol . free-variable) . - (cons code . - (or (cons t . - (cons (repeat . (symbol . feature)) . - t)) - t)))))) - -(elisp-scope-define-function-analyzer custom-declare-theme (name &rest rest) - (elisp-scope-1 name '(symbol . deftheme)) - (elisp-scope-n rest)) +(elisp-scope-define-function-spec + (provide-theme enable-theme disable-theme load-theme custom-theme-p) + ((symbol . theme))) -(elisp-scope-define-function-analyzer eieio-oref (obj slot) - (elisp-scope-1 obj) - (elisp-scope-1 slot '(symbol . slot))) +(elisp-scope-define-function-spec custom-theme-set-variables + ((symbol . theme)) + (cons (symbol . free-variable) . + (cons code . + (or (cons t . + (cons (repeat . (symbol . feature)) . + t)) + t)))) -(dolist (fun '(slot-boundp slot-makeunbound slot-exists-p eieio-oref-default)) - (put fun 'elisp-scope-analyzer #'elisp-scope--analyze-eieio-oref)) +(elisp-scope-define-function-spec custom-declare-theme ((symbol . deftheme))) -(elisp-scope-define-function-analyzer eieio-oset (obj slot value) - (elisp-scope-1 obj) - (elisp-scope-1 slot '(symbol . slot)) - (elisp-scope-1 value)) +(elisp-scope-define-function-spec + (eieio-oref slot-boundp slot-makeunbound slot-exists-p eieio-oref-default) + (nil (symbol . slot))) -(put 'eieio-oset-default 'elisp-scope-analyzer #'elisp-scope--analyze-eieio-oset) +(elisp-scope-define-function-spec (eieio-oset eieio-oset-default) + (nil (symbol . slot))) -(elisp-scope-define-function-analyzer derived-mode-p (modes &rest rest) - (elisp-scope-1 modes '(or (repeat . (symbol . major-mode)) - (symbol . major-mode))) - (dolist (mode rest) (elisp-scope-1 mode '(symbol . major-mode)))) +(elisp-scope-define-function-spec derived-mode-p + ((or (repeat . (symbol . major-mode)) + (symbol . major-mode))) + (symbol . major-mode)) -(elisp-scope-define-function-analyzer derived-mode-set-parent (&optional mode parent) - (elisp-scope-1 mode '(symbol . major-mode)) - (elisp-scope-1 parent '(symbol . major-mode))) +(elisp-scope-define-function-spec derived-mode-set-parent + ((symbol . major-mode) (symbol . major-mode))) -(elisp-scope-define-function-analyzer elisp-scope-report (role &rest args) - (elisp-scope-1 role '(symbol . symbol-role)) - (mapc #'elisp-scope-1 args)) +(elisp-scope-define-function-spec elisp-scope-report + ((symbol . symbol-role))) -(elisp-scope-define-function-analyzer elisp-scope-report-s (&optional sym role) - (elisp-scope-1 sym) - (elisp-scope-1 role '(symbol . symbol-role))) +(elisp-scope-define-function-spec elisp-scope-report-s + (nil (symbol . symbol-role))) -(elisp-scope-define-function-analyzer elisp-scope-1 (&optional form outspec) - (elisp-scope-1 form) - (elisp-scope-1 outspec 'spec)) +(elisp-scope-define-function-spec elisp-scope-1 (nil spec)) (elisp-scope-define-function-analyzer icons--register (&optional name parent spec doc kws) (elisp-scope-1 name '(symbol . deficon)) @@ -2076,21 +2019,15 @@ ARGS bound to the analyzed arguments." (elisp-scope-1 var '(symbol . free-variable)) (elisp-scope-1 val elisp-scope-output-spec)) -(elisp-scope-define-function-analyzer autoload (&optional func file doc int type) - (elisp-scope-1 func '(symbol . function)) - (elisp-scope-1 file) - (elisp-scope-1 doc) - (elisp-scope-1 int '(repeat . (symbol . major-mode))) - (elisp-scope-1 type)) +(elisp-scope-define-function-spec autoload + ((symbol . function) nil nil (repeat . (symbol . major-mode)))) -(elisp-scope-define-function-analyzer define-completion-category (&optional name parents &rest rest) - (elisp-scope-1 name '(symbol . completion-category-definition)) - (elisp-scope-1 parents '(repeat . (symbol . completion-category))) - (elisp-scope-n rest)) +(elisp-scope-define-function-spec define-completion-category + ((symbol . completion-category-definition) + (repeat . (symbol . completion-category)))) -(elisp-scope-define-function-analyzer completion-table-with-category (&optional category table) - (elisp-scope-1 category '(symbol . completion-category)) - (elisp-scope-1 table)) +(elisp-scope-define-function-spec completion-table-with-category + ((symbol . completion-category))) (defun elisp-scope--easy-menu-do-define-menu (menu) (let ((items (cdr menu))) @@ -2149,9 +2086,8 @@ ARGS bound to the analyzed arguments." (elisp-scope-1 def)) (elisp-scope-1 remove)) -(elisp-scope-define-function-analyzer eval-after-load (&optional file form) - (elisp-scope-1 file '(symbol . feature)) - (elisp-scope-1 form 'code)) +(elisp-scope-define-function-spec eval-after-load + ((symbol . feature) code)) ;; We use a bespoke analyzer for `if-let*' instead of letting ;; `elisp-scope-1' expand it because `if-let*' expands to a form that @@ -2332,25 +2268,19 @@ ARGS bound to the analyzed arguments." (elisp-scope-define-macro-analyzer define-minor-mode (&optional mode doc &rest body) (when mode (elisp-scope-define-minor-mode mode doc body))) -(elisp-scope-define-macro-analyzer setq-local (&rest args) +(elisp-scope-define-macro-analyzer (setq-local setq-default) (&rest args) (elisp-scope-setq args)) -(put 'setq-default 'elisp-scope-analyzer #'elisp-scope--analyze-setq-local) - -(elisp-scope-define-macro-analyzer cl-defun (name arglist &rest body) +(elisp-scope-define-macro-analyzer (cl-defun cl-defmacro) (name arglist &rest body) (elisp-scope-cl-defun name arglist body)) -(put 'cl-defmacro 'elisp-scope-analyzer #'elisp-scope--analyze-cl-defun) - -(elisp-scope-define-macro-analyzer defun (&optional name arglist &rest body) +(elisp-scope-define-macro-analyzer (defun ert-deftest) (&optional name arglist &rest body) (when name (elisp-scope-defun name arglist body))) (elisp-scope-define-macro-analyzer defmacro (&optional name arglist &rest body) (elisp-scope-report-s name 'defmacro) (elisp-scope-lambda arglist body)) -(put 'ert-deftest 'elisp-scope-analyzer #'elisp-scope--analyze-defun) - (elisp-scope-define-macro-analyzer elisp-scope-define-symbol-role (&optional name parents &rest props) (elisp-scope-report-s name 'symbol-role-definition) (dolist (parent parents) (elisp-scope-report-s parent 'symbol-role)) @@ -2386,34 +2316,25 @@ ARGS bound to the analyzed arguments." (elisp-scope-1 place) (elisp-scope-n body elisp-scope-output-spec)) -(elisp-scope-define-macro-analyzer cl-pushnew (&rest args) +(elisp-scope-define-macro-analyzer (cl-pushnew incf decf) (&rest args) (mapc #'elisp-scope-1 args)) -(dolist (sym '(incf decf)) - (put sym 'elisp-scope-analyzer #'elisp-scope--analyze-cl-pushnew)) - (elisp-scope-define-macro-analyzer static-if (&optional test then &rest else) (elisp-scope-1 test) (elisp-scope-1 then elisp-scope-output-spec) (elisp-scope-n else elisp-scope-output-spec)) -(elisp-scope-define-macro-analyzer static-when (&optional test &rest body) +(elisp-scope-define-macro-analyzer (static-when static-unless) (&optional test &rest body) (elisp-scope-1 test) (elisp-scope-n body elisp-scope-output-spec)) -(put 'static-unless 'elisp-scope-analyzer #'elisp-scope--analyze-static-when) - -(elisp-scope-define-macro-analyzer eval-when-compile (&rest body) +(elisp-scope-define-macro-analyzer (eval-when-compile eval-and-compile) (&rest body) (elisp-scope-n body elisp-scope-output-spec)) -(put 'eval-and-compile 'elisp-scope-analyzer #'elisp-scope--analyze-eval-when-compile) - -(elisp-scope-define-macro-analyzer cl-callf (&rest args) +(elisp-scope-define-macro-analyzer (cl-callf cl-callf2) (&rest args) (elisp-scope-sharpquote (car args)) (elisp-scope-n (cdr args))) -(put 'cl-callf2 'elisp-scope-analyzer #'elisp-scope--analyze-cl-callf) - (elisp-scope-define-macro-analyzer seq-let (args sequence &rest body) (elisp-scope-1 sequence) (let ((l elisp-scope-local-bindings)) @@ -2696,23 +2617,18 @@ ARGS bound to the analyzed arguments." (elisp-scope-1 tag '(symbol . throw-tag)) (elisp-scope-n body elisp-scope-output-spec)) -(elisp-scope-define-special-form-analyzer progn (&rest body) +(elisp-scope-define-special-form-analyzer + (progn inline save-current-buffer save-excursion save-restriction) + (&rest body) (elisp-scope-n body elisp-scope-output-spec)) -(put 'inline 'elisp-scope-analyzer #'elisp-scope--analyze-progn) -(put 'save-current-buffer 'elisp-scope-analyzer #'elisp-scope--analyze-progn) -(put 'save-excursion 'elisp-scope-analyzer #'elisp-scope--analyze-progn) -(put 'save-restriction 'elisp-scope-analyzer #'elisp-scope--analyze-progn) - (elisp-scope-define-special-form-analyzer while (&rest rest) (mapc #'elisp-scope-1 rest)) -(elisp-scope-define-special-form-analyzer prog1 (&rest body) +(elisp-scope-define-special-form-analyzer (prog1 unwind-protect) (&rest body) (when (consp body) (elisp-scope-1 (pop body) elisp-scope-output-spec)) (elisp-scope-n body)) -(put 'unwind-protect 'elisp-scope-analyzer #'elisp-scope--analyze-prog1) - ;;; Specifications for some common variables: (put 'coding-system-for-read 'elisp-scope-variable-spec '(symbol . coding)) (put 'coding-system-for-write 'elisp-scope-variable-spec '(symbol . coding)) @@ -2794,6 +2710,7 @@ are analyzed." (symbols-with-pos-enabled t) (message-log-max nil) (inhibit-message t) + (macroexp-enable-preserve-posification nil) (macroexpand-all-environment (append (mapcar #'list elisp-scope-unsafe-macros) macroexpand-all-environment))) (ignore-errors (macroexpand-1 form macroexpand-all-environment))) diff --git a/lisp/emacs-lisp/ewoc.el b/lisp/emacs-lisp/ewoc.el index 387e5d3be5e..118b66eb15f 100644 --- a/lisp/emacs-lisp/ewoc.el +++ b/lisp/emacs-lisp/ewoc.el @@ -152,6 +152,7 @@ and (ewoc--node-nth dll -1) returns the last node." `dll' will be bound when VARLIST is initialized, but the current buffer will *not* have been changed. Return value of last form in FORMS." + (declare (debug (form let))) (let ((hnd (make-symbol "ewoc"))) `(let* ((,hnd ,ewoc) (dll (ewoc--dll ,hnd)) @@ -568,15 +569,21 @@ Return nil if the buffer has been deleted." (ewoc--node-data (ewoc--footer ewoc)))) (defun ewoc-set-hf (ewoc header footer) - "Set the HEADER and FOOTER of EWOC." + "Set the HEADER and/or FOOTER of EWOC. +To change only the header (respectively footer), pass nil for +FOOTER (respectively HEADER). +To clear the header (respectively footer), pass an empty string for +HEADER (respectively FOOTER)." (ewoc--set-buffer-bind-dll-let* ewoc ((head (ewoc--header ewoc)) (foot (ewoc--footer ewoc)) (hf-pp (ewoc--hf-pp ewoc))) - (setf (ewoc--node-data head) header - (ewoc--node-data foot) footer) - (ewoc--refresh-node hf-pp head dll) - (ewoc--refresh-node hf-pp foot dll))) + (when header + (setf (ewoc--node-data head) header) + (ewoc--refresh-node hf-pp head dll)) + (when footer + (setf (ewoc--node-data foot) footer) + (ewoc--refresh-node hf-pp foot dll)))) (provide 'ewoc) diff --git a/lisp/emacs-lisp/gv.el b/lisp/emacs-lisp/gv.el index 625eaedf844..4633461a5dc 100644 --- a/lisp/emacs-lisp/gv.el +++ b/lisp/emacs-lisp/gv.el @@ -532,42 +532,49 @@ See also `incf'." (put 'cond 'gv-expander (lambda (do &rest branches) - (if (or (not lexical-binding) ;The other code requires lexical-binding. - (macroexp-small-p (funcall do 'dummy (lambda (_) 'dummy)))) - ;; This duplicates the `do' code, which is a problem if that - ;; code is large, but otherwise results in more efficient code. - `(cond - ,@(mapcar (lambda (branch) - (if (cdr branch) - (cons (car branch) - (macroexp-unprogn - (gv-get (macroexp-progn (cdr branch)) do))) - (gv-get (car branch) do))) - branches)) - (let ((v (gensym "v"))) - (macroexp-let2 nil - gv `(cond - ,@(mapcar - (lambda (branch) - (if (cdr branch) - `(,(car branch) - ,@(macroexp-unprogn - (gv-letplace (getter setter) - (macroexp-progn (cdr branch)) - `(cons (lambda () ,getter) - (lambda (,v) ,(funcall setter v)))))) - (gv-letplace (getter setter) - (car branch) - `(cons (lambda () ,getter) - (lambda (,v) ,(funcall setter v)))))) - branches)) - (funcall do `(funcall (car ,gv)) - (lambda (v) `(funcall (cdr ,gv) ,v)))))))) - -(put 'error 'gv-expander - (lambda (do &rest args) - (funcall do `(error . ,args) - (lambda (v) `(progn ,v (error . ,args)))))) + (let ((res (apply #'gv--cond-expander do branches)) + (last-test (caar (last branches)))) + (if (and (macroexp-const-p last-test) + (if (consp last-test) (cadr last-test) last-test)) + res + ;; There is no setter for the nil expression, so a missing default + ;; branch is a bug (bug#81217). Let's not signal an error, tho, + ;; for backward compatibility reasons. + (macroexp-warn-and-return "Missing default branch in cond" + res '(suspicious cond)))))) + +(defun gv--cond-expander (do &rest branches) + (if (or (not lexical-binding) ;The other code requires lexical-binding. + (macroexp-small-p (funcall do 'dummy (lambda (_) 'dummy)))) + ;; This duplicates the `do' code, which is a problem if that + ;; code is large, but otherwise results in more efficient code. + `(cond + ,@(mapcar (lambda (branch) + (if (cdr branch) + (cons (car branch) + (macroexp-unprogn + (gv-get (macroexp-progn (cdr branch)) do))) + (gv-get (car branch) do))) + branches)) + (let ((v (gensym "v"))) + (macroexp-let2 nil + gv `(cond + ,@(mapcar + (lambda (branch) + (if (cdr branch) + `(,(car branch) + ,@(macroexp-unprogn + (gv-letplace (getter setter) + (macroexp-progn (cdr branch)) + `(cons (lambda () ,getter) + (lambda (,v) ,(funcall setter v)))))) + (gv-letplace (getter setter) + (car branch) + `(cons (lambda () ,getter) + (lambda (,v) ,(funcall setter v)))))) + branches)) + (funcall do `(funcall (car ,gv)) + (lambda (v) `(funcall (cdr ,gv) ,v))))))) (defun gv-synthetic-place (getter setter) "Special place described by its setter and getter. @@ -671,11 +678,9 @@ REF must have been previously obtained with `gv-ref'." ;;; Generalized variables. -;; You'd think no one would write `(setf (error ...) ..)' but it -;; appears naturally as the result of macroexpansion of things like -;; (setf (pcase-exhaustive ...)). -;; We could generalize this to `throw' and `signal', but it seems -;; preferable to wait until there's a concrete need. +;; `error' and `ignore' places come in handy in the default branch +;; of `cond/pcase' places. +(gv-define-setter ignore (store &rest _args) store) ;; A kind of >/dev/null (gv-define-expander error (lambda (_do &rest args) `(error . ,args))) ;; Some Emacs-related place types. diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el index a28123088ce..d9e11761657 100644 --- a/lisp/emacs-lisp/lisp-mode.el +++ b/lisp/emacs-lisp/lisp-mode.el @@ -730,7 +730,6 @@ font-lock keywords will not be case sensitive." "Major mode for buffers holding data written in Lisp syntax." :group 'lisp (lisp-mode-variables nil t nil) - (setq-local electric-quote-string t) (setq imenu-case-fold-search nil) (setq-local hs-block-start-regexp "\\s(\\|\"") (setq-local hs-block-end-regexp "\\s)\\|\"")) diff --git a/lisp/emacs-lisp/lisp.el b/lisp/emacs-lisp/lisp.el index 936d5f91a06..e0111af1a1d 100644 --- a/lisp/emacs-lisp/lisp.el +++ b/lisp/emacs-lisp/lisp.el @@ -31,8 +31,11 @@ ;; Note that this variable is used by non-lisp modes too. (defcustom defun-prompt-regexp nil - "If non-nil, a regexp to ignore before a defun. -This is only necessary if the opening paren or brace is not in column 0. + "If non-nil, matches a prefix on the line of a defun's opening paren. +This regexp should begin with \"^\". It is used to recognize a function's +opening paren or brace when it is not in column 0. +The prefix typically names the defun, and possibly gives its type and +arguments. See function `beginning-of-defun'." :type '(choice (const nil) regexp) @@ -634,13 +637,12 @@ report errors as appropriate for this kind of usage." (funcall end-of-defun-function)))) ((< arg 0) ;; Moving backward. - (if (< (point) pos) - ;; We already moved backward because we started from between - ;; two functions. - (setq arg (1+ arg)) - ;; We started from inside a function. - (goto-char beg)) + (when (< (point) pos) + ;; We already moved backward because we started from between + ;; two functions. + (setq arg (1+ arg))) (unless (zerop arg) + (goto-char beg) (when (setq success (beginning-of-defun-raw (- arg))) (setq beg (point)) (funcall end-of-defun-function))))) @@ -756,15 +758,10 @@ Interactively, the behavior depends on `narrow-to-defun-include-comments'." ;; the function might go to the previous function. ;; ;; Therefore we first move one character forward and then call - ;; `beginning-of-defun'. However now we must check that we did - ;; not move into the next function. - (let ((here (point))) - (unless (eolp) - (forward-char)) - (beginning-of-defun) - (when (< (point) here) - (goto-char here) - (beginning-of-defun))) + ;; `beginning-of-defun'. + (unless (eolp) + (forward-char)) + (beginning-of-defun) (setq beg (point)) (end-of-defun) (setq end (point)) diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el index 6a16ebb0fd2..1d40e30bb08 100644 --- a/lisp/emacs-lisp/macroexp.el +++ b/lisp/emacs-lisp/macroexp.el @@ -304,6 +304,9 @@ modified FORM." (let ((new-form (macroexp--posify-form-1 form call-pos 10))) (or new-form form))) +(defvar macroexp-enable-preserve-posification t + "Whether to attach position of a macro call to the expanded form.") + (defmacro macroexp-preserve-posification (pos-form &rest body) "Evaluate BODY..., posifying the result with POS-FORM's position, if any. If the result of body happens to have a position already, we do not @@ -316,7 +319,7 @@ change this." ((symbol-with-pos-p ,pos-form) (symbol-with-pos-pos ,pos-form)))) (new-value (progn ,@body))) - (if (and call-pos + (if (and macroexp-enable-preserve-posification call-pos (not (or (and (consp new-value) (symbol-with-pos-p (car new-value))) (and (symbol-with-pos-p new-value))))) diff --git a/lisp/emacs-lisp/map-ynp.el b/lisp/emacs-lisp/map-ynp.el index 7522d465d61..d4191e3c8cb 100644 --- a/lisp/emacs-lisp/map-ynp.el +++ b/lisp/emacs-lisp/map-ynp.el @@ -105,7 +105,7 @@ function is used instead. The function's value is the number of actions taken." (let* ((actions 0) (msg (current-message)) - user-keys mouse-event map prompt char elt def + user-keys mouse-event map prompt chars elt def ;; Non-nil means we should use mouse menus to ask. use-menus delayed-switch-frame @@ -174,14 +174,15 @@ The function's value is the number of actions taken." 'quit))) (y-or-n-p-use-read-key ;; Prompt in the echo area using `read-key'. - (let ((cursor-in-echo-area (not no-cursor-in-echo-area))) - (message "%s" (substitute-command-keys - (format - (apply #'propertize - "%s(\\`y', \\`n', \\`!', \\`.', \\`q', %sor \\`%s') " - minibuffer-prompt-properties) - prompt user-keys - (help-key)))) + (let ((cursor-in-echo-area (not no-cursor-in-echo-area)) + (full-prompt + (substitute-command-keys + (format + (apply #'propertize + "%s(\\`y', \\`n', \\`!', \\`.', \\`q', %sor \\`%s') " + minibuffer-prompt-properties) + prompt user-keys + (help-key))))) (if minibuffer-auto-raise (raise-frame (window-frame (minibuffer-window)))) (unwind-protect @@ -196,8 +197,8 @@ The function's value is the number of actions taken." ;; Do NOT use read-event here. That ;; function does not consult ;; input-decode-map (bug#75886). - (setq char (read-key)) - (when (eq char ?\C-g) + (setq chars (read-key-sequence-vector full-prompt)) + (when (member chars '([?\C-g] [?\C-\[ ?\C-\[ ?\C-\[])) (signal 'quit nil))) (when (fboundp 'set-text-conversion-style) (set-text-conversion-style text-conversion-style))) @@ -207,10 +208,10 @@ The function's value is the number of actions taken." "%s(\\`y', \\`n', \\`!', \\`.', \\`q', %sor \\`%s') %s" prompt user-keys (help-key) - (if (equal char -1) + (if (equal chars [-1]) "[end-of-keyboard-macro]" - (single-key-description char)))))) - (setq def (lookup-key map (vector char)))) + (key-description chars)))))) + (setq def (and chars (lookup-key map chars)))) (t ;; Read from the minibuffer. (let* ((full-prompt @@ -224,7 +225,7 @@ The function's value is the number of actions taken." (cmd-char (lambda () (interactive) - (setq char last-command-event) + (setq chars (this-command-keys-vector)) (exit-minibuffer))) (cmd-help (lambda () @@ -250,8 +251,8 @@ The function's value is the number of actions taken." (read-from-minibuffer full-prompt nil remap nil (or y-or-n-p-history-variable t)) - (message "%s%s" full-prompt (single-key-description char))) - (setq def (lookup-key map (vector char))))) + (message "%s%s" full-prompt (key-description chars))) + (setq def (and chars (lookup-key map chars))))) (cond ((eq def 'exit) (setq next (lambda () nil))) ((eq def 'act) @@ -318,12 +319,16 @@ Type \\`SPC' or \\`y' to %s the current %s; (setq actions (1+ actions)) ;; Regurgitated; try again. (funcall try-again))) - ((and (consp char) - (eq (car char) 'switch-frame)) + ((eq chars '[switch-frame]) ;; switch-frame event. Put it off until we're done. - (setq delayed-switch-frame char) + (setq delayed-switch-frame chars) (funcall try-again)) - ((eq def nil) ;; Special case for bug#67836 + ((and noninteractive (member chars '(nil []))) + ;; Special case for kmacro in batch mode (bug#67836). + ;; When 'y-or-n-p-use-read-key' is non-nil, + ;; 'read-key-sequence-vector' returns []. + ;; When 'y-or-n-p-use-read-key' is nil, + ;; 'chars' is nil. (error "Can't use in a kmacro in batch mode")) (t ;; Random char. diff --git a/lisp/emacs-lisp/multisession.el b/lisp/emacs-lisp/multisession.el index 8df3d9e4b22..fbd5452a71f 100644 --- a/lisp/emacs-lisp/multisession.el +++ b/lisp/emacs-lisp/multisession.el @@ -54,7 +54,6 @@ Valid methods are `sqlite' and `files'." :version "29.1" :group 'files) -;;;###autoload (defmacro define-multisession-variable (name initial-value &optional doc &rest args) "Make NAME into a multisession variable initialized from INITIAL-VALUE. diff --git a/lisp/emacs-lisp/package-activate.el b/lisp/emacs-lisp/package-activate.el index 53a3fa30836..5e2623c57f1 100644 --- a/lisp/emacs-lisp/package-activate.el +++ b/lisp/emacs-lisp/package-activate.el @@ -208,8 +208,6 @@ called via `package-activate-all'. To change which packages are loaded and/or activated, customize `package-load-list'.") (put 'package-alist 'risky-local-variable t) -;;;; Public interfaces for accessing built-in package info - ;;;###autoload (defvar package-activated-list nil ;; FIXME: This should implicitly include all builtin packages. diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index 9ff761f0157..062659fc912 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -535,6 +535,22 @@ package." summary) +;;; Public interfaces for accessing built-in package info + +(defun package-versioned-builtin-packages () + "Return a list of all the versioned built-in packages. +The return value is a list of names of built-in packages represented as +symbols." + (mapcar #'car package--builtin-versions)) + +(defun package-builtin-package-version (package) + "Return the version of a built-in PACKAGE given by its symbol. +The return value is a list of integers representing the version of +PACKAGE, in the format returned by `version-to-list', or nil if the +package is built-in but has no version or is not a built-in package." + (alist-get package package--builtin-versions)) + + ;;; Installed packages ;; The following functions are called on each installed package by @@ -2170,8 +2186,8 @@ NAME should be a symbol." (package-desc-version (cadr elt)) (package-desc-version available))) (not (package-vc-p (cadr elt)))))) - (nconc (and include-builtins (package--builtin-alist)) - (package--alist))))) + (append (and include-builtins (package--builtin-alist)) + (package--alist))))) ;;;###autoload (defun package-upgrade-all (&optional query) @@ -2379,6 +2395,15 @@ installed), maybe you need to \\[package-refresh-contents]") (equal (cadr (assq (package-desc-name pkg) package-alist)) pkg)) +(defun package--dependency-p (pkg) + "Return non-nil if PKG is a dependency." + (let ((name (package-desc-name pkg))) + (catch 'is-dependency + (dolist (ent (package--alist) nil) + (dolist (desc (cdr ent)) + (when (assq name (package-desc-reqs desc)) + (throw 'is-dependency t))))))) + (declare-function comp-el-to-eln-filename "comp.c") (defvar package-vc-repository-store) (defun package--delete-directory (dir) @@ -2433,15 +2458,20 @@ If NOSAVE is non-nil, the package is not removed from (if (null (remove pkg-desc (cdr pkgs))) (remq pkgs package-alist) package-alist))) - pkg-used-elsewhere-by) + pkg-used-elsewhere-by) ;; If the user is trying to delete this package, they definitely ;; don't want it marked as selected, so we remove it from ;; `package-selected-packages' even if it can't be deleted. (when (and (null nosave) (package--user-selected-p name) - ;; Don't deselect if this is an older version of an - ;; upgraded package. - (package--newest-p pkg-desc)) + (or + ;; Don't deselect if this is an older version of an + ;; upgraded package. + (package--newest-p pkg-desc) + ;; Don't deselect if the package is a dependency and + ;; there are multiple installations (bug#81082). + (and (length< (alist-get name package-alist) 1) + (package--dependency-p pkg-desc)))) (package--save-selected-packages (remove name package-selected-packages))) (cond ((not (string-prefix-p (file-name-as-directory (expand-file-name package-user-dir)) @@ -2452,7 +2482,16 @@ If NOSAVE is non-nil, the package is not removed from ((and (null force) (setq pkg-used-elsewhere-by (let ((package-alist new-package-alist)) - (package--used-elsewhere-p pkg-desc)))) ;See bug#65475 + (package--used-elsewhere-p pkg-desc))) ;See bug#65475 + (and-let* ((other (package-get-descriptor + name 'installed + (lambda (pkg-other) + (not (equal pkg-desc pkg-other)))))) + (not (yes-or-no-p + (format "Package `%s' is used by `%s' as dependency, but `%s' is also available. Use that instead?" + (package-desc-full-name pkg-desc) + (package-desc-name pkg-used-elsewhere-by) + (package-desc-full-name other)))))) ;; Don't delete packages used as dependency elsewhere. (error "Package `%s' is used by `%s' as dependency, not deleting" (package-desc-full-name pkg-desc) diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el index 166b346fbbe..6f9312a50d3 100644 --- a/lisp/emacs-lisp/pcase.el +++ b/lisp/emacs-lisp/pcase.el @@ -268,22 +268,28 @@ nil." `(lambda ,args ,@(car parsed-body) (pcase-let* ,(nreverse bindings) ,@(cdr parsed-body))))) -(defun pcase--let* (bindings body) +(defun pcase--let* (bindings body &optional strict) (cond ((null bindings) (macroexp-progn body)) ((pcase--trivial-upat-p (caar bindings)) (macroexp-let* `(,(car bindings)) (pcase--let* (cdr bindings) body))) (t - (let ((binding (pop bindings))) + (let* ((binding (pop bindings)) + (x (gensym "x")) + (pcase--dontwarn-upats (cons x pcase--dontwarn-upats))) (pcase--expand (cadr binding) - `((,(car binding) ,(pcase--let* bindings body)) - ;; We can either signal an error here, or just use `pcase--dontcare' - ;; which generates more efficient code. In practice, if we use - ;; `pcase--dontcare' we will still often get an error and the few - ;; cases where we don't do not matter that much, so - ;; it's a better choice. - (pcase--dontcare nil))))))) + `((,(car binding) ,(pcase--let* bindings body strict)) + ,(if strict + `(,x (error "`pcase' pattern does not match value: %S %S" + (quote ,(car binding)) + ,x)) + ;; We can either signal an error here, or just use `pcase--dontcare' + ;; which generates more efficient code. In practice, if we use + ;; `pcase--dontcare' we will still often get an error and the few + ;; cases where we don't do not matter that much, so + ;; it's a better choice. + '(pcase--dontcare nil)))))))) ;;;###autoload (defmacro pcase-let* (bindings &rest body) @@ -305,6 +311,27 @@ undetected, binding variables to arbitrary values, such as nil." (puthash bindings (cons body expansion) pcase--memoize) expansion)))) +;;;###autoload +(defmacro pcase-let*-strict (bindings &rest body) + "Like `pcase-let*', but signal an error when a pattern does not match. +As with `pcase-let*', BINDINGS are of the form (PATTERN EXP), but the +EXP in each binding in BINDINGS can use the results of the destructuring +bindings that precede it in BINDINGS' order. + +Each EXP should match its respective PATTERN (i.e. be of structure +compatible to PATTERN); a mismatch may signal an error or may go +undetected, binding variables to arbitrary values, such as nil." + (declare (indent 1) + (debug ((&rest (pcase-PAT &optional form)) body))) + (let ((cached (gethash bindings pcase--memoize))) + ;; cached = (BODY . EXPANSION) + (if (equal (car cached) body) + (cdr cached) + (let ((expansion (pcase--let* bindings body t))) + (puthash bindings (cons body expansion) pcase--memoize) + expansion)))) + + ;;;###autoload (defmacro pcase-let (bindings &rest body) "Like `let', but supports destructuring BINDINGS using `pcase' patterns. diff --git a/lisp/emacs-lisp/smie.el b/lisp/emacs-lisp/smie.el index 33821b8be28..b7de55c580e 100644 --- a/lisp/emacs-lisp/smie.el +++ b/lisp/emacs-lisp/smie.el @@ -1452,7 +1452,14 @@ This is used when we're not trying to indent point but just need to compute the column at which point should be indented in order to figure out the indentation of some other (further down) point." ;; Trust pre-existing indentation on other lines. - (if (smie-indent--bolp) (current-column) (smie-indent-calculate))) + (let ((col (if (smie-indent--bolp) + (current-column) + (smie-indent-calculate)))) + (if (numberp col) + col + (message "Warning: smie-indent-virtual at pos %s got: %S" + (point) col) + (current-column)))) (defun smie-indent-fixindent () ;; Obey the `fixindent' special comment. @@ -1865,11 +1872,12 @@ to which that point should be aligned, if we were to reindent it.") ;; here may not be accurate, but in practice it seems ;; to work well enough. (skip-chars-forward " \t") - (let* ((newcol (smie-indent-calculate)) - (newgain (- (current-column) newcol))) - (when (> newgain gain) - (setq gain newgain) - (setq bsf (point))))) + (let* ((newcol (smie-indent-calculate))) + (when (numberp newcol) + (let ((newgain (- (current-column) newcol))) + (when (> newgain gain) + (setq gain newgain) + (setq bsf (point))))))) (when (> gain 0) (goto-char bsf) (newline-and-indent) @@ -2091,7 +2099,8 @@ position corresponding to each rule." (goal (current-indentation)) (cur (smie-indent-calculate))) (cond - ((and (eq goal + ((and (numberp cur) + (eq goal (progn (setf (car rule) (- goal cur)) (smie-indent-calculate)))) (- goal cur))))) diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el index d5a39b77c2e..8780a07a69d 100644 --- a/lisp/emacs-lisp/subr-x.el +++ b/lisp/emacs-lisp/subr-x.el @@ -334,10 +334,10 @@ automatically killed, which means that in a such case (erase-buffer) (delete-all-overlays)) (let (change-major-mode-hook) - ;; `kill-all-local-variables' does not kill permanent locals - ;; like `buffer-read-only'. - (setq buffer-read-only nil) - (kill-all-local-variables t)) + ;; Ensure `kill-all-local-variables' kills *all* permanent locals + ;; rather than exempting any, and resets the buffer to pristine + ;; state. + (kill-all-local-variables 'reset)) ;; Make the buffer available again. (push buffer work-buffer--list))) ;; If the maximum number of reusable work buffers is exceeded, kill @@ -426,42 +426,51 @@ this function using the same ELLIPSIS." string ;; Keeping a work buffer around is more efficient than creating a ;; new temporary buffer. - (let ((original-buffer (or buffer (current-buffer)))) + (let* ((window (selected-window)) + (original-buffer (window-buffer window)) + (window-dedication (window-dedicated-p window)) + (buffer-list-update-hook) + (window-scroll-functions) + (window-configuration-change-hook)) (with-work-buffer - (work-buffer--prepare-pixelwise string buffer) - (set-window-buffer nil (current-buffer) 'keep-margins) - ;; Use a binary search to prune the number of calls to - ;; `window-text-pixel-size'. - ;; These are 1-based buffer indexes. - (let* ((low 1) - (high (1+ (length string))) - mid) - (when (> (car (window-text-pixel-size nil 1 high)) max-pixels) - (when (and ellipsis (not (stringp ellipsis))) - (setq ellipsis (truncate-string-ellipsis))) - (setq ellipsis-pixels (if ellipsis - (if ellipsis-pixels - ellipsis-pixels - (string-pixel-width ellipsis buffer)) - 0)) - (let ((adjusted-pixels - (if (> max-pixels ellipsis-pixels) - (- max-pixels ellipsis-pixels) - max-pixels))) - (while (<= low high) - (setq mid (floor (+ low high) 2)) - (if (<= (car (window-text-pixel-size nil 1 mid)) - adjusted-pixels) - (setq low (1+ mid)) - (setq high (1- mid)))))) - (set-window-buffer nil original-buffer 'keep-margins) - (if mid - ;; Binary search ran. - (if (and ellipsis (> max-pixels ellipsis-pixels)) - (concat (substring string 0 (1- high)) ellipsis) - (substring string 0 (1- high))) - ;; Fast path. - string)))))) + ;; Use a binary search to prune the number of calls to + ;; `window-text-pixel-size'. + ;; These are 1-based buffer indexes. + (unwind-protect + (let* ((low 1) + (high (1+ (length string))) + mid) + (work-buffer--prepare-pixelwise string buffer) + (set-window-dedicated-p window nil) + (set-window-buffer window (current-buffer) 'keep-margins) + (when (> (car (window-text-pixel-size nil 1 high)) max-pixels) + (when (and ellipsis (not (stringp ellipsis))) + (setq ellipsis (truncate-string-ellipsis))) + (setq ellipsis-pixels (if ellipsis + (if ellipsis-pixels + ellipsis-pixels + (string-pixel-width ellipsis buffer)) + 0)) + (let ((adjusted-pixels + (if (> max-pixels ellipsis-pixels) + (- max-pixels ellipsis-pixels) + max-pixels))) + (while (<= low high) + (setq mid (floor (+ low high) 2)) + (if (<= (car (window-text-pixel-size nil 1 mid)) + adjusted-pixels) + (setq low (1+ mid)) + (setq high (1- mid)))))) + (if mid + ;; Binary search ran. + (if (and ellipsis (> max-pixels ellipsis-pixels)) + (concat (substring string 0 (1- high)) ellipsis) + (substring string 0 (1- high))) + ;; Fast path. + string)) + (set-window-buffer window original-buffer 'keep-margins) + (set-window-dedicated-p window window-dedication) + (unrecord-window-buffer window (current-buffer) t)))))) ;;;###autoload (defun string-glyph-split (string) diff --git a/lisp/emacs-lisp/uuid.el b/lisp/emacs-lisp/uuid.el new file mode 100644 index 00000000000..592751a427e --- /dev/null +++ b/lisp/emacs-lisp/uuid.el @@ -0,0 +1,245 @@ +;;; uuid.el --- UUID creation and handling -*- lexical-binding: t; -*- + +;; Copyright (C) 2026 Free Software Foundation, Inc. + +;; Author: Andrew Hyatt <[email protected]> +;; Keywords: tools + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + + +;;; Commentary: +;; This library provides useful code for handling UUIDs. It provides +;; methods for generating UUIDs, parsing them, and outputting them as +;; a string, a unibyte binary string, or as a number. +;; +;;; Code: + +(require 'cl-lib) +(require 'bindat) +(require 'seq) + +(define-error + 'uuid-invalid-string + "Invalid UUID string not conforming to expected UUID shape.") + +(define-error + 'uuid-invalid-bytes + "Invalid UUID bytes not conforming to expected 16-byte length.") + +(define-error + 'uuid-invalid-namespace + "Namespace not found in `uuid-namespace-alist'.") + +(defconst uuid--bindat-type + (bindat-type (:high uint 48) + ;; We can't separate out ver and mid due to bindat + ;; limitations on byte alignment. + (:ver-mid uint 16) + ;; Same issue with var and low. + (:var-low uint 64)) + "The bindat type for UUIDs, as defined in RFC 9562.") + +(cl-defstruct (uuid + (:constructor nil) + (:conc-name uuid--) + (:constructor + uuid--from-parts + (high mid low ver var))) + "The base type for all UUIDs. + +This will represent versions where we don't have a more specific version +defined, so all versions except for v4, v5, and v7." + high mid low ver var) + +(defun uuid--upper-bits (num n bitsize) + "Return the upper N bits of NUM of BITSIZE. + +BITSIZE is the total size of the num." + (ash num (- n bitsize))) + +(defun uuid--lower-bits (num n) + "Return the lower N bits of NUM." + (logand num (- (ash 1 n) 1))) + +(defun uuid--concat-bits (&rest num-and-sizes) + "Return number doing bitwise concatenating NUM-AND-SIZES. + +NUM-AND-SIZES is a list of alternating numbers and their sizes in bits." + (cl-loop for num-and-size in (reverse + (seq-partition num-and-sizes 2)) + with shift = 0 + sum (ash (car num-and-size) shift) + do (incf shift (cadr num-and-size)))) + +(defun uuid-to-string (id) + "Convert the uuid object ID to a string." + (let ((low (uuid--low id)) + (high (uuid--high id))) + (format "%08x-%04x-%04x-%04x-%012x" + (uuid--upper-bits high 32 48) + (uuid--lower-bits high 16) + (uuid--concat-bits + (uuid--ver id) 4 + (uuid--mid id) 12) + (uuid--concat-bits + (uuid--var id) 2 + (uuid--upper-bits low 14 62) 14) + (uuid--lower-bits low 48)))) + +(defun uuid-to-bytes (id) + "Convert the uuid object ID to a 16-byte unibyte string." + (bindat-pack uuid--bindat-type + `((:high . ,(uuid--high id)) + (:ver-mid . ,(uuid--concat-bits + (uuid--ver id) 4 + (uuid--mid id) 12)) + (:var-low . ,(uuid--concat-bits + (uuid--var id) 2 + (uuid--low id) 62))))) + +(defun uuid-to-number (id) + "Convert ID, a `uuid' lisp object, to a numerical representation." + (uuid--concat-bits + (uuid--high id) 48 + (uuid--ver id) 4 + (uuid--mid id) 12 + (uuid--var id) 2 + (uuid--low id) 62)) + +(defconst uuid-nil + (uuid--from-parts 0 0 0 0 0) + "A UUID representing `nil', as defined in RFC 9562.") + +(defconst uuid-max + (uuid--from-parts (1- (ash 1 48)) (1- (ash 1 12)) (1- (ash 1 62)) 15 3) + "A UUID representing the maximum UUID, per RFC 9562.") + +(cl-deftype uuid-v (var) + `(and uuid (satisfies + ,(lambda (id) (and (= (uuid--ver id) var) + (= (uuid--var id) 2)))))) + +(defun uuid--random-bits (n &optional rng) + "Return a random number with N bits." + (funcall (or rng #'random) + (expt 2 n))) + +(defun uuid-from-string (uuid-str) + "Parse UUID-STR and return the appropriate UUID object." + (let* ((parts (split-string uuid-str "-")) + (_ (unless (and (= (length parts) 5) + (= (length (nth 0 parts)) 8) + (= (length (nth 1 parts)) 4) + (= (length (nth 2 parts)) 4) + (= (length (nth 3 parts)) 4) + (= (length (nth 4 parts)) 12) + (string-match "^[0-9a-fA-F-]+$" uuid-str)) + (signal 'uuid-invalid-string (list uuid-str)))) + (hex-parts (mapcar (lambda (part) (string-to-number part 16)) parts)) + (version (uuid--upper-bits (nth 2 hex-parts) 4 16)) + (variant (uuid--upper-bits (nth 3 hex-parts) 2 16)) + (high (uuid--concat-bits + (nth 0 hex-parts) 32 + (nth 1 hex-parts) 16)) + (mid (uuid--lower-bits (nth 2 hex-parts) 12)) + (low + (uuid--concat-bits + (uuid--lower-bits (nth 3 hex-parts) 14) 14 + (nth 4 hex-parts) 48))) + (uuid--from-parts high mid low version variant))) + +(defun uuid-from-bytes (uuid-bytes) + "Parse unibyte string UUID-BYTES and return a UUID object. + +If UUID-BYTES are not unibyte, or not 16 bytes, a `uuid-invalid-bytes' +error is signaled." + (unless (and + (not (multibyte-string-p uuid-bytes)) + (= 16 (string-bytes uuid-bytes))) + (signal 'uuid-invalid-bytes (list uuid-bytes))) + (let* ((parts (bindat-unpack uuid--bindat-type uuid-bytes)) + (version (uuid--upper-bits (assoc-default :ver-mid parts) 4 16)) + (variant (uuid--upper-bits (assoc-default :var-low parts) 2 64)) + (high (assoc-default :high parts)) + (mid (uuid--lower-bits (assoc-default :ver-mid parts) 12)) + (low (uuid--lower-bits (assoc-default :var-low parts) 62))) + (uuid--from-parts high mid low version variant))) + +(defconst uuid-namespace-alist + (mapcar (lambda (x) (cons (car x) (uuid-from-string (cdr x)))) + '((dns . "6ba7b810-9dad-11d1-80b4-00c04fd430c8") + (url . "6ba7b811-9dad-11d1-80b4-00c04fd430c8") + (oid . "6ba7b812-9dad-11d1-80b4-00c04fd430c8") + (x500 . "6ba7b814-9dad-11d1-80b4-00c04fd430c8"))) + "An alist of namespaces and their canonical UUIDs. + This is defined at https://www.rfc-editor.org/info/rfc9562/#namespaces.") + +(cl-defun uuid-v4 (&key rng) + "Return a new UUIDv4 ID. + +RNG is an alternate random number function which should take a single +argument, the limit (exclusive) for the random number, and return an +integer between 0 and that number. To be valid according to RFC 9562, +the random numbers should be cryptographically secure, which the default +random number generator typically is not, so if these UUIDs are +important, it's advised to use a better random number function, which +typically requires getting random numbers from outside of Emacs." + (uuid--from-parts (uuid--random-bits 48 rng) + (uuid--random-bits 12 rng) + (uuid--random-bits 62 rng) + 4 2)) + +(defun uuid-v5 (namespace name) + "Return a new UUIDv5 ID from the given NAMESPACE and NAME. + +NAMESPACE should be a symbol corresponding to a namespace in +`uuid-namespace-alist'. If this is not recognized it will signal an +`uuid-invalid-namespace' signal. + +NAME is the name from which to generate the UUID, and should be a +string." + (let* ((namespace-uuid (or + (alist-get namespace uuid-namespace-alist) + (signal 'uuid-invalid-namespace (list namespace)))) + (hash-bytes (sha1 + (concat + (uuid-to-bytes namespace-uuid) + (encode-coding-string name 'utf-8)) + nil nil t)) + (hash-vals (bindat-unpack uuid--bindat-type hash-bytes))) + (uuid--from-parts (assoc-default :high hash-vals) + (uuid--lower-bits (assoc-default :ver-mid hash-vals) 12) + (uuid--lower-bits (assoc-default :var-low hash-vals) 62) + 5 2))) + +(cl-defun uuid-v7 (&key rng) + "Return a new UUIDv7 ID. + +The UUIDv7 uses a timestamp instead of being purely random, which makes +it more suitable for use cases such as database keys. + +RNG is an alternate random number function which should take a single +argument, the limit (exclusive) for the random number, and return an +integer between 0 and that number. See `uuid-v4' for more details on +the expected behavior of this function." + (uuid--from-parts (floor (* (float-time) 1000)) + (uuid--random-bits 12 rng) + (uuid--random-bits 62 rng) + 7 2)) + +(provide 'uuid) +;;; uuid.el ends here diff --git a/lisp/emacs-lock.el b/lisp/emacs-lock.el index ec71fa2c713..0bc1678979f 100644 --- a/lisp/emacs-lock.el +++ b/lisp/emacs-lock.el @@ -62,13 +62,13 @@ Possible values are: ;; the old emacs-lock.el. (defcustom emacs-lock-unlockable-modes '((shell-mode . all) (telnet-mode . all)) - "Alist of auto-unlockable modes. + "Alist of major modes whose buffers can be automatically unlocked. Each element is a pair (MAJOR-MODE . ACTION), where ACTION is one of `kill', `exit' or `all'. Buffers with matching major -modes are auto-unlocked for the specific action if their -inferior processes are not alive. If this variable is t, all -buffers associated to inferior processes are auto-unlockable -for both actions (NOT RECOMMENDED)." +modes that have `emacs-lock-mode' turned on can be auto-unlocked +for the specific action if their inferior processes are not alive. +If this variable is t, all buffers associated with inferior processes +are auto-unlockable for all actions (NOT RECOMMENDED)." :type '(choice (const :tag "All buffers with inferior processes" t) (repeat :tag "Selected modes" @@ -82,15 +82,20 @@ for both actions (NOT RECOMMENDED)." :version "24.1") (defcustom emacs-lock-locked-buffer-functions nil - "Abnormal hook run when Emacs Lock prevents exiting Emacs, or killing a buffer. -The functions get one argument, the first locked buffer found." + "Abnormal hook run when exiting Emacs or killing a buffer. +When exiting Emacs, the hook is run from `kill-emacs-query-functions' +and from `kill-emacs-hook' if any buffer has `emacs-lock-mode' turned on. +When killing a buffer, the hook is run if the buffer has `emacs-lock-mode' +turned on. +The functions on this hook are called with one argument, the first (or +only) locked buffer that is found." :type 'hook :group 'emacs-lock :version "24.3") (defvar-local emacs-lock-mode nil "If non-nil, the current buffer is locked. -It can be one of the following values: +The value can be one of the following: exit -- Emacs cannot exit while the buffer is locked kill -- the buffer cannot be killed, but Emacs can exit as usual all -- the buffer is locked against both actions @@ -116,7 +121,7 @@ Internal use only.") (defun emacs-lock--can-auto-unlock (action) "Return t if the current buffer can auto-unlock for ACTION. -ACTION must be one of `kill' or `exit'. +ACTION must be one of `kill', `exit' or `all'. See `emacs-lock-unlockable-modes'." (and emacs-lock--try-unlocking (not (emacs-lock-live-process-p (current-buffer))) @@ -136,16 +141,16 @@ See `emacs-lock-unlockable-modes'." nil))) (defun emacs-lock--kill-emacs-hook () - "Signal an error if any buffer is exit-locked. + "Signal an error if any buffer is exit-locked to prevent Emacs from exiting. Used from `kill-emacs-hook' (which see)." (let ((locked (emacs-lock--exit-locked-buffer))) (when locked (run-hook-with-args 'emacs-lock-locked-buffer-functions locked) - (error "Emacs cannot exit because buffer %S is locked" + (user-error "Emacs cannot exit because buffer %S is locked" (buffer-name locked))))) (defun emacs-lock--kill-emacs-query-functions () - "Display a message if any buffer is exit-locked. + "Display a message if any buffer is exit-locked and prevent Emacs exiting. Return a value appropriate for `kill-emacs-query-functions' (which see)." (let ((locked (emacs-lock--exit-locked-buffer))) (if (not locked) @@ -156,7 +161,7 @@ Return a value appropriate for `kill-emacs-query-functions' (which see)." nil))) (defun emacs-lock--kill-buffer-query-functions () - "Display a message if the current buffer is kill-locked. + "Display a message if the current buffer is kill-locked and prevent killing it. Return a value appropriate for `kill-buffer-query-functions' (which see)." (if (or (emacs-lock--can-auto-unlock 'kill) (memq emacs-lock-mode '(nil exit))) @@ -190,13 +195,17 @@ Return a value appropriate for `kill-buffer-query-functions' (which see)." ;;;###autoload (define-minor-mode emacs-lock-mode "Toggle Emacs Lock mode in the current buffer. +When a buffer is locked, it cannot be killed and/or Emacs cannot exit +unless the buffer is unlocked first. This protects buffers from +being accidentally killed or lost. + If called with a plain prefix argument, ask for the locking mode -to be used. +to be used in the buffer. Initially, if the user does not pass an explicit locking mode, it defaults to `emacs-lock-default-locking-mode' (which see); afterwards, the locking mode most recently set on the buffer is -used instead. +used as the default instead. When called from Elisp code, ARG can be any locking mode: @@ -204,7 +213,7 @@ When called from Elisp code, ARG can be any locking mode: kill -- the buffer cannot be killed, but Emacs can exit as usual all -- the buffer is locked against both actions -Other values are interpreted as usual. +Other values are interpreted as usual for turning modes on/off. See also `emacs-lock-unlockable-modes', which exempts buffers under some major modes from being locked under some circumstances." @@ -233,7 +242,8 @@ some major modes from being locked under some circumstances." (add-hook 'kill-emacs-query-functions 'emacs-lock--kill-emacs-query-functions)) (defun emacs-lock-unload-function () - "Unload the Emacs Lock library." + "Unload the Emacs Lock library. +This is called from `unload-feature', which see." (catch :continue (dolist (buffer (buffer-list)) (set-buffer buffer) diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index 819b8ae5033..85475a4c52f 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -2381,8 +2381,8 @@ A server may send more than one 005 message." value negated) (when (string-match - (rx bot (| (: (group (+ (any "A-Z"))) "=" (group (* nonl))) - (: (? (group "-")) (group (+ (any "A-Z"))))) + (rx bot (| (: (group (+ (any "A-Z./"))) "=" (group (* nonl))) + (: (? (group "-")) (group (+ (any "A-Z./"))))) eot) section) (setq key (or (match-string 1 section) (match-string 4 section)) diff --git a/lisp/erc/erc-button.el b/lisp/erc/erc-button.el index 3cb2d527cd4..0fbd43ad22f 100644 --- a/lisp/erc/erc-button.el +++ b/lisp/erc/erc-button.el @@ -54,13 +54,11 @@ "This mode buttonizes all messages according to `erc-button-alist'." ((add-hook 'erc-insert-modify-hook #'erc-button-add-buttons 30) (add-hook 'erc-send-modify-hook #'erc-button-add-buttons 30) - (add-hook 'erc-mode-hook #'erc-button-setup 91) - (unless erc--updating-modules-p (erc-buffer-do #'erc-button-setup)) + (erc-with-initialized-session (erc-button-setup)) (add-hook 'erc--tab-functions #'erc-button-next) (erc--modify-local-map t "<backtab>" #'erc-button-previous)) ((remove-hook 'erc-insert-modify-hook #'erc-button-add-buttons) (remove-hook 'erc-send-modify-hook #'erc-button-add-buttons) - (remove-hook 'erc-mode-hook #'erc-button-setup) (remove-hook 'erc--tab-functions #'erc-button-next) (erc--modify-local-map nil "<backtab>" #'erc-button-previous))) @@ -873,9 +871,7 @@ non-strings, concatenate leading string members before applying (with-temp-buffer (insert string) (goto-char (point-min)) - (with-syntax-table lisp-mode-syntax-table - (skip-syntax-forward "^-")) - (forward-char) + (erc--pfx-skip-word-fwd) (erc--lwarn 'erc :warning (buffer-substring-no-properties (point) (point-max)))))) diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el index 1a0b9c323d1..481b6084a6a 100644 --- a/lisp/erc/erc-common.el +++ b/lisp/erc/erc-common.el @@ -434,6 +434,22 @@ if ARG is omitted or nil. (put ',enable 'definition-name ',name) (put ',disable 'definition-name ',name)))) +(defmacro erc-with-initialized-session (&rest body) + "Run BODY in all ERC buffers if outside `erc-open' and soon otherwise. +When inside `erc-open', run BODY after session variables have been +initialzied and after all `erc-mode-hook' members but before any +`after-change-major-mode-hook' members. Expect caller to know this is +only useful in global-module setup and that they're still responsible +for teardown, which is often done with `erc-buffer-do' or similar." + (let ((fn (make-symbol "fn")) + (hook-var (make-symbol "hook-var"))) + `(let ((,fn (lambda () ,@body))) + (if erc--updating-modules-p + (let ((,hook-var (gensym "erc--oneoff-major-mode-hook-"))) + (set ,hook-var ,fn) + (push ,hook-var delayed-mode-hooks)) + (erc-buffer-do ,fn))))) + (defmacro erc-with-buffer (spec &rest body) "Execute BODY in the buffer associated with SPEC. @@ -572,7 +588,12 @@ Use the CASEMAPPING ISUPPORT parameter to determine the style." (when erc-channel-members-changed-hook (run-hooks 'erc-channel-members-changed-hook)))))))) -(defmacro erc--with-dependent-type-match (type &rest features) +;; The default values of some ERC's options contain items defined in +;; other libraries that may not be loaded when `setopt' is invoked on +;; the option, which results in an unfriendly warning. User configs can +;; simply `require' such dependencies beforehand, but that's often +;; undesirable in ERC's own library code. +(defmacro erc--custom-with-type-match-features (type &rest features) "Massage Custom :type TYPE with :match function that pre-loads FEATURES." `(backquote-list* ',(car type) :match (lambda (w v) diff --git a/lisp/erc/erc-desktop-notifications.el b/lisp/erc/erc-desktop-notifications.el index e4a62c614a4..a3b728a5e53 100644 --- a/lisp/erc/erc-desktop-notifications.el +++ b/lisp/erc/erc-desktop-notifications.el @@ -47,6 +47,28 @@ "Icon to use for notification." :type '(choice (const :tag "No icon" nil) file)) +(defcustom erc-desktop-notifications-ignored-when-focused () + "Contexts in which to suppress notification in the selected window. +Assumes `erc-desktop-notifications-focused-p' is a member of +`erc-desktop-notifications-skip-predicates'. If the option's value +contains the symbol `query', ERC skips all notifications in focused +query buffers. And if it contains `mention', ERC skips notifications +upon mention of the user's nick in a focused channel buffer." + :package-version '(ERC . "5.7") + :type '(set (const query) (const mention))) + +(defcustom erc-desktop-notifications-skip-predicates + '(erc-desktop-notifications-focused-p + erc-desktop-notifications-untracked-p + erc-desktop-notifications-fool-p) + "Abnormal hook whose members return non-nil to suppress notification. +Called in match buffer with a matching `erc-match-user' object." + :options '(erc-desktop-notifications-focused-p + erc-desktop-notifications-untracked-p + erc-desktop-notifications-fool-p) + :package-version '(ERC . "5.7") + :type 'hook) + (defcustom erc-notifications-bus :session "D-Bus bus to use for notification." :version "25.1" @@ -60,16 +82,18 @@ (defun erc-notifications-notify (nick msg &optional privp) "Notify that NICK send some MSG, where PRIVP should be non-nil for PRIVMSGs. This will replace the last notification sent with this function." - ;; TODO: can we do this without PRIVP? (by "fixing" ERC's not - ;; setting the current buffer to the existing query buffer) (dbus-ignore-errors (setq erc-notifications-last-notification - (let* ((channel (if privp (erc-get-buffer nick) (current-buffer))) - (title (format "%s in %s" - (erc-compat--xml-escape-string nick t) - channel)) - (body (erc-compat--xml-escape-string (erc-controls-strip msg) - t))) + (let* ((channel (or (and privp (not (equal nick (erc-target))) + (erc-get-buffer nick)) + (current-buffer))) + (title (if (or privp (equal nick (erc-target))) + (erc-compat--xml-escape-string nick t) + (format "%s in %s" + (erc-compat--xml-escape-string nick t) + channel))) + (body (erc-compat--xml-escape-string + (erc-controls-strip msg) t))) (funcall (cond ((featurep 'android) #'android-notifications-notify) ((featurep 'haiku) @@ -85,6 +109,7 @@ This will replace the last notification sent with this function." (pop-to-buffer channel))))))) (defun erc-notifications-PRIVMSG (_proc parsed) + (declare (obsolete "switched to `erc-match-type' API" "31.1")) (let ((nick (car (erc-parse-user (erc-response.sender parsed)))) (target (car (erc-response.command-args parsed))) (msg (erc-response.contents parsed))) @@ -96,23 +121,96 @@ This will replace the last notification sent with this function." ;; Return nil to continue processing by ERC nil) -(defun erc-notifications-notify-on-match (match-type nickuserhost msg) +(defun erc-desktop-notifications-untracked-p (&rest _) + "Return non-nil if current buffer's target appears in `erc-track-exclude'." + (and (boundp 'erc-track-exclude) (member (erc-target) erc-track-exclude))) + +(defun erc-desktop-notifications-fool-p (&rest _) + "Return non-nil if the current message has a \"match type\" of `fool'." + (erc-match-get-match 'erc-match-opt-fool)) + +(defun erc-desktop-notifications-focused-p (match) + "Return non-nil if the frame is focused and suppressed by context. +See `erc-desktop-notifications-ignored-when-focused' for contexts." + (and (eq (current-buffer) (window-buffer)) + (cond + ((erc-query-buffer-p) + (memq 'query erc-desktop-notifications-ignored-when-focused)) + ((erc-match-opt-current-nick-p match) + (memq 'mention erc-desktop-notifications-ignored-when-focused))) + (frame-focus-state))) + +(defun erc-notifications-notify-on-match (match-type _ msg) + "Emit MSG if MATCH-TYPE is `current-nick' and other conditions allow." (when (eq match-type 'current-nick) - (let ((nick (nth 0 (erc-parse-user nickuserhost)))) - (unless (or (string-match-p "^Server:" nick) - (when (boundp 'erc-track-exclude) - (member nick erc-track-exclude))) - (erc-notifications-notify nick msg))))) + (let ((match erc-match-highlight-matched)) + (cl-assert (erc-match-opt-current-nick-p match)) + (when-let* ((nick (erc-match-nick match))) + (unless (run-hook-with-args-until-success + 'erc-desktop-notifications-skip-predicates + match) + (erc-notifications-notify nick msg)))))) ;;;###autoload(autoload 'erc-notifications-mode "erc-desktop-notifications" "" t) (define-erc-module notifications nil "Send notifications on private message reception and mentions." ;; Enable - ((add-hook 'erc-server-PRIVMSG-functions #'erc-notifications-PRIVMSG) - (add-hook 'erc-text-matched-hook #'erc-notifications-notify-on-match)) + ((unless erc--updating-modules-p + (erc-buffer-do #'erc-desktop-notifications--setup)) + (add-hook 'erc-mode-hook #'erc-desktop-notifications--setup)) ;; Disable - ((remove-hook 'erc-server-PRIVMSG-functions #'erc-notifications-PRIVMSG) - (remove-hook 'erc-text-matched-hook #'erc-notifications-notify-on-match))) + ((erc-buffer-do #'erc-desktop-notifications--setup) + (remove-hook 'erc-mode-hook #'erc-desktop-notifications--setup))) + +(defun erc-desktop-notifications--setup () + (if erc-notifications-mode + (progn + (add-hook 'erc-match-functions + ;; Run after default value to detect fools. + #'erc-desktop-notifications-match-query 20 t) + (add-hook 'erc-text-matched-hook #'erc-notifications-notify-on-match + 20 t)) + (remove-hook 'erc-match-functions + #'erc-desktop-notifications-match-query t) + (remove-hook 'erc-text-matched-hook + #'erc-notifications-notify-on-match t))) + +;; This flag is most likely only temporary and exists as a hedge against +;; a likely thinko involving NOTICEs sent to query buffers. At the time +;; of writing, it's unclear whether the current behavior of suppressing +;; query NOTICEs outright is TRT. For example, a user might want +;; NOTICEs from a particular bot to trigger notifications because it's +;; monitoring critical updates to some library they use. When the +;; picture becomes clearer, the introduction of a new option/predicate +;; pair resembling `erc-desktop-notifications-ignored-when-focused' and +;; `erc-desktop-notifications-focused-p' may be warranted. +(defvar erc-desktop-notifications--query-NOTICE-p nil + "Whether to notify on receiving a \"NOTICE\" in a query. +Bots and services typically send these.") + +(cl-defstruct (erc-desktop-notifications-match-query + (:constructor erc-desktop-notifications-match-query) + (:include erc-match-user + (category nil) + (predicate #'erc-desktop-notifications--query-p) + (handler #'erc-desktop-notifications--query-notify))) + "Desktop notification match type for queries.") + +(defun erc-desktop-notifications--query-p (match) + "Return non-nil if MATCH object describes a \"PRIVMSG\" query." + (and (erc-query-buffer-p) + (or erc-desktop-notifications--query-NOTICE-p + (eq (erc-match-command match) 'PRIVMSG)) + (progn + (cl-assert (erc-match-nick match)) + (not (run-hook-with-args-until-success + 'erc-desktop-notifications-skip-predicates match))))) + +(defun erc-desktop-notifications--query-notify (match) + ;; No need for PRIVP arg because current buffer is correct. + (erc-notifications-notify (erc-target) + (erc-match-get-message-body match))) + (provide 'erc-desktop-notifications) diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el index 7ca29f16e03..0d72bde5309 100644 --- a/lisp/erc/erc-fill.el +++ b/lisp/erc/erc-fill.el @@ -706,15 +706,17 @@ See `erc-fill-wrap-mode' for details." (let ((len (or (and erc-fill--wrap-length-function (funcall erc-fill--wrap-length-function)) (and-let* ((msg-prop (erc--check-msg-prop 'erc--msg)) - ((not (eq msg-prop 'unknown)))) - (when-let* ((e (erc--get-speaker-bounds)) - (b (pop e)) - ((or erc-fill--wrap-action-dedent-p - (not (erc--check-msg-prop 'erc--ctcp - 'ACTION))))) - (goto-char e)) - (skip-syntax-forward "^-") - (forward-char) + (_ (not (eq msg-prop 'unknown)))) + (if-let* ((fn (erc--check-msg-prop 'erc--pfx))) + (let ((erc--ctcp-action-speaker-in-prefix-p + erc-fill--wrap-action-dedent-p)) + (funcall fn)) + ;; FIXME remove this before releasing ERC 5.7. + (unless (eq msg-prop 'datestamp) + (erc--lwarn 'erc-fill :error + "Missing `erc--pfx' skip-fwd function: %S" + (list :msg-prop msg-prop + :buffer-string (buffer-string))))) (cond ((eq msg-prop 'datestamp) (when erc-fill--wrap-rejigger-last-message (set-marker erc-fill--wrap-last-msg (point-min))) diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el index e99d5f68175..ddb5a24bd0d 100644 --- a/lisp/erc/erc-goodies.el +++ b/lisp/erc/erc-goodies.el @@ -79,12 +79,11 @@ be experimental. It currently only works with Emacs 28+." ;;;###autoload(autoload 'erc-scrolltobottom-mode "erc-goodies" nil t) (define-erc-module scrolltobottom nil "This mode causes the prompt to stay at the end of the window." - ((add-hook 'erc-mode-hook #'erc--scrolltobottom-setup) - (when (and erc-scrolltobottom-all (< emacs-major-version 28)) + ((when (and erc-scrolltobottom-all (< emacs-major-version 28)) (erc-button--display-error-notice-with-keys "Option `erc-scrolltobottom-all' requires Emacs 28+. Disabling.") (setq erc-scrolltobottom-all nil)) - (unless erc--updating-modules-p (erc-buffer-do #'erc--scrolltobottom-setup)) + (erc-with-initialized-session (erc--scrolltobottom-setup)) (if erc-scrolltobottom-all (progn (remove-hook 'erc-insert-done-hook #'erc-possibly-scroll-to-bottom) @@ -97,8 +96,7 @@ be experimental. It currently only works with Emacs 28+." (remove-hook 'erc-insert-done-hook #'erc--scrolltobottom-all) (remove-hook 'erc-send-completed-hook #'erc--scrolltobottom-all) (add-hook 'erc-insert-done-hook #'erc-possibly-scroll-to-bottom))) - ((remove-hook 'erc-mode-hook #'erc--scrolltobottom-setup) - (erc-buffer-do #'erc--scrolltobottom-setup) + ((erc-buffer-do #'erc--scrolltobottom-setup) (remove-hook 'erc-insert-pre-hook #'erc--scrolltobottom-on-pre-insert) (remove-hook 'erc-send-completed-hook #'erc--scrolltobottom-all) (remove-hook 'erc-insert-done-hook #'erc--scrolltobottom-all) @@ -258,10 +256,8 @@ Put this function on `erc-insert-post-hook' and/or `erc-send-post-hook'." ;;;###autoload(autoload 'erc-move-to-prompt-mode "erc-goodies" nil t) (define-erc-module move-to-prompt nil "This mode causes the point to be moved to the prompt when typing text." - ((add-hook 'erc-mode-hook #'erc-move-to-prompt-setup) - (unless erc--updating-modules-p (erc-buffer-do #'erc-move-to-prompt-setup))) - ((remove-hook 'erc-mode-hook #'erc-move-to-prompt-setup) - (dolist (buffer (erc-buffer-list)) + ((erc-with-initialized-session (erc-move-to-prompt-setup))) + ((dolist (buffer (erc-buffer-list)) (with-current-buffer buffer (remove-hook 'pre-command-hook #'erc-move-to-prompt t))))) @@ -633,6 +629,9 @@ Do nothing if the variable `erc-command-indicator' is nil." (erc--input-split-substxt state) #'erc--command-indicator-display) (erc-send-distinguish-noncommands state))) +(defun erc--command-indicator-body-find () + (search-forward (erc--check-msg-prop 'erc--command-indicator) (pos-eol) t)) + ;; This function used to be called `erc-display-command'. It was ;; neutered in ERC 5.3.x (Emacs 24.5), commented out in 5.4, removed ;; in 5.5, and restored in 5.6. @@ -651,6 +650,9 @@ Do nothing if the variable `erc-command-indicator' is nil." 'hash-table))))) (when-let* ((string (erc-command-indicator)) (erc-input-marker (copy-marker erc-input-marker))) + (puthash 'erc--command-indicator string erc--msg-props) + (puthash 'erc--pfx #'erc--command-indicator-body-find + erc--msg-props) (erc-display-prompt nil nil string 'erc-command-indicator-face) (remove-text-properties insert-position (point) '(field nil erc-prompt nil)) diff --git a/lisp/erc/erc-imenu.el b/lisp/erc/erc-imenu.el index 965e8ead14c..669d8bf42b1 100644 --- a/lisp/erc/erc-imenu.el +++ b/lisp/erc/erc-imenu.el @@ -135,11 +135,9 @@ Don't rely on this function, read it first!" ;;;###autoload(autoload 'erc-imenu-mode "erc-imenu" nil t) (define-erc-module imenu nil "Simple Imenu integration for ERC." - ((add-hook 'erc-mode-hook #'erc-imenu-setup) - (add-hook 'which-function-mode-hook #'erc-imenu--disable-which-func) - (unless erc--updating-modules-p (erc-buffer-do #'erc-imenu-setup))) - ((remove-hook 'erc-mode-hook #'erc-imenu-setup) - (remove-hook 'which-function-mode-hook #'erc-imenu--disable-which-func) + ((add-hook 'which-function-mode-hook #'erc-imenu--disable-which-func) + (erc-with-initialized-session (erc-imenu-setup))) + ((remove-hook 'which-function-mode-hook #'erc-imenu--disable-which-func) (erc-buffer-do #'erc-imenu-setup))) (defun erc-imenu-setup () diff --git a/lisp/erc/erc-match.el b/lisp/erc/erc-match.el index b003cb1f49e..c6675053e55 100644 --- a/lisp/erc/erc-match.el +++ b/lisp/erc/erc-match.el @@ -63,14 +63,28 @@ highlighted." (erc-buffer-do #'erc-match--setup) (erc--modify-local-map nil "C-c C-k" #'erc-go-to-log-matches-buffer))) +;; This caches the result of applying `regexp-opt' analogs to the +;; regexp-based user options, mainly for history playback bursts. +(defvar erc-match--opt-pat-cache nil + "Alist of (COMPUTE-FN . PAIRS) where PAIRS is an alist of (IN . OUT).") + +(defun erc-match--opt-pat-custom-set (sym val &optional _) + "Assign VAL to SYM via `set'." + (when erc-match--opt-pat-cache + (setq erc-match--opt-pat-cache nil)) + (set sym val)) + + ;; Remaining customizations (defcustom erc-pals nil "List of pals on IRC." + :set #'erc-match--opt-pat-custom-set :type '(repeat regexp)) (defcustom erc-fools nil "List of fools on IRC." + :set #'erc-match--opt-pat-custom-set :type '(repeat regexp)) (defcustom erc-keywords nil @@ -78,12 +92,14 @@ highlighted." Each entry in the list is either a regexp, or a cons cell with the regexp in the car and the face to use in the cdr. If no face is specified, `erc-keyword-face' is used." + :set #'erc-match--opt-pat-custom-set :type '(repeat (choice regexp (list regexp face)))) (defcustom erc-dangerous-hosts nil "List of regexps for hosts to highlight. Useful to mark nicks from dangerous hosts." + :set #'erc-match--opt-pat-custom-set :type '(repeat regexp)) (defcustom erc-current-nick-highlight-type 'keyword @@ -122,10 +138,15 @@ The following values are allowed: `all' - highlight the entire message (including the nick) from pal + `nick-or-mention' - highlight a matching speaker or all matching + mentions as quasi keywords + A value of `nick' only highlights a matching sender's nick in the bracketed speaker portion of the message. A value of \\+`message' basically highlights its complement: the message-body alone, after the -speaker tag. All values for this option require a matching sender to be +speaker tag. A value of `nick-or-mention' works like `nick' but also +matches \"mentions,\" which `erc-fool-highlight-type' explains in its +doc string. All values for this option require a matching sender to be an actual user on the network \(or a bot/service) as opposed to a host name, such as that of the server itself \(e.g. \"irc.gnu.org\"). When patterns from other user-based categories \(namely, \\+`fool' and @@ -135,6 +156,7 @@ which in turn clobbers `erc-pal-face'. \(Other effects, such as \\+`fool'-related invisibility may not survive such collisions.)" :type '(choice (const nil) (const nick) + (const nick-or-mention) (const message) (const all))) @@ -148,12 +170,12 @@ IRC-style \"mentions\" in which a speaker addresses a USER directly: <speaker> USER: hi. <speaker> USER, hi. -However, at present, this option doesn't offer a means of highlighting -matched mentions alone. See `erc-pal-highlight-type' for a summary of -possible values and additional details common to categories like -\\+`fool' that normally match against a message's sender." +See `erc-pal-highlight-type' for a summary of possible values and +additional details common to categories like \\+`fool' that normally +match against a message's sender." :type '(choice (const nil) (const nick) + (const nick-or-mention) (const message) (const all))) @@ -182,6 +204,7 @@ additional details common to categories like \\+`dangerous-host' that normally match against a message's sender." :type '(choice (const nil) (const nick) + (const nick-or-mention) (const message) (const all))) @@ -241,12 +264,12 @@ for beeping to work." (defcustom erc-text-matched-hook '(erc-log-matches) "Abnormal hook for visiting text matching a predefined \"type\". ERC calls members with the arguments (MATCH-TYPE NUH MESSAGE), where -MATCH-TYPE is a symbol among `current-nick', `keyword', `pal', -`dangerous-host', and `fool'; and NUH is an `erc-response' sender, like -\"[email protected]\" or an IRC command prefixed with the string -\"Server:\", as in \"Server:353\". MESSAGE is the current incarnation -of the just-inserted message minus a leading speaker, like \"<bob> \". -For traditional reasons, MESSAGE always includes a leading +MATCH-TYPE is a \"category\" symbol, one of `current-nick', `keyword', +`pal', `dangerous-host', and `fool'; and NUH is an `erc-response' +sender, like \"[email protected]\" or an IRC command prefixed with +the string \"Server:\", as in \"Server:353\". MESSAGE is the current +incarnation of the just-inserted message minus a leading speaker, like +\"<bob> \". For traditional reasons, MESSAGE always includes a leading `erc-notice-prefix' and a trailing newline." :options '(erc-log-matches erc-hide-fools erc-beep-on-match) :type 'hook) @@ -267,6 +290,22 @@ available via universal argument." (const t) (const nil))) +(defcustom erc-match-functions '(erc-match-opt-pal + erc-match-opt-fool + erc-match-opt-dangerous-host + erc-match-opt-keyword + erc-match-opt-current-nick) + "Type constructors for \\+`match' processing. +See the struct `erc-match' as well as Info node `(erc) Match API' for +details." + :package-version '(ERC . "5.7") + :type '(hook :options (erc-match-opt-pal + erc-match-opt-fool + erc-match-opt-dangerous-host + erc-match-opt-keyword + erc-match-opt-current-nick))) + + ;; Internal variables: ;; This is exactly the same as erc-button-syntax-table. Should we @@ -322,6 +361,8 @@ Note that this is the default face to use if LIST must be passed as a symbol The query happens using PROMPT. Completion is performed on the optional alist COMPLETIONS." + (when erc-match--opt-pat-cache + (setq erc-match--opt-pat-cache nil)) (let ((entry (completing-read prompt completions @@ -345,6 +386,8 @@ Completion is performed on the optional alist COMPLETIONS." LIST must be passed as a symbol. The elements of LIST can be strings, or cons cells where the car is the string." + (when erc-match--opt-pat-cache + (setq erc-match--opt-pat-cache nil)) (let* ((alist (mapcar (lambda (x) (if (listp x) x @@ -468,7 +511,310 @@ In any of the following situations, MSG is directed at an entry FOOL: (or (erc-list-match fools-beg msg) (erc-list-match fools-end msg)))) +(cl-defstruct (erc-match (:constructor erc-match)) + "Base type for text and user matching performed by the \\+`match' module. +Users wishing to perform custom matching should add a constructor that +returns an instance of this type to the hook `erc-match-functions'. If +the `:predicate' slot's predicate returns non-nil after being called +with its own instance in the narrowed single-message buffer, ERC calls +the `:handler' slot's function with the same instance and with the match +data still intact. More details in Info node `(erc) Match API'." + ( predicate (error "Keyword `:predicate' missing") :type function + :documentation "Called in narrowed buffer with own instance.") + ( spkr-beg nil :type (or null natnum) + :documentation "Position of the beginning of speaker's nick, if known.") + ( spkr-end nil :type (or null natnum) + :documentation "Position of the end of speaker's nick, if known.") + ( body-beg (error "Keyword `:body-beg' missing") :type marker + :documentation "Marker residing at the beginning of the message body.") + ( sender (error "Keyword `:sender' missing") :type string + :documentation "The sender's n!u@h.") + ( nick nil :type (or null string) + :documentation "The sender's nick if they're a user and not the server.") + ( command (error "Keyword `:command' missing") :type (or symbol natnum) + :documentation "Protocol command or numeric, like `PRIVMSG' or 353.") + ( handler #'ignore :type function + :documentation "Called on `:predicate' match with own instance.") + ( newlinep nil :type boolean + :documentation "Whether narrowed buffer includes trailing newline.")) + +(cl-defstruct (erc-match-traditional + (:constructor erc-match-traditional) + (:include erc-match + (handler #'erc-match-highlight) + (newlinep t))) + "Match type for user-option based on \"categories\" and \"parts\". +The `:category' slot exists for the benefit of `erc-text-matched-hook', +which receives its value as a second parameter (the hook only runs when +the slot is non-nil). For compatibility, the narrowed buffer includes a +trailing newline." + ( category (error "Keyword `:category' missing") :type symbol + :documentation "Traditional \\+`match' \"category\", like `pal'.") + ( face 'erc-default-face :type face + :documentation "Face to highlight the matched portion with.") + ( part nil :type symbol + :documentation "Symbol for the portion of the message to highlight.") + ( data nil :type list + :documentation "User-specified patterns or other type-specific data.")) + +(cl-defstruct (erc-match-opt-current-nick + (:include erc-match-traditional + (category 'current-nick) + (predicate #'erc-match--current-nick-p) + (part erc-current-nick-highlight-type) + (face 'erc-current-nick-face) + (data (list (concat "\\b" + (regexp-quote (erc-current-nick)) + "\\b")))) + (:constructor erc-match-opt-current-nick)) + "An options-based type for the `current-nick' category.") + +(cl-defstruct (erc-match-opt-keyword + (:include erc-match-traditional + (category 'keyword) + (predicate #'erc-match--keyword-p) + (part erc-keyword-highlight-type) + (face 'erc-keyword-face) + (data erc-keywords)) + (:constructor erc-match-opt-keyword)) + "An options-based type for the `keyword' category.") + +(cl-defstruct (erc-match-user (:include erc-match-traditional) + (:constructor erc-match-user)) + "An `erc-match' that's only processed when `:nick' is non-nil.") + +(cl-defstruct (erc-match-opt-fool + (:include erc-match-user + (category 'fool) + (predicate #'erc-match--user-nuh-or-mention-p) + (part erc-fool-highlight-type) + (face 'erc-fool-face) + (data erc-fools)) + (:constructor erc-match-opt-fool)) + "An options-based type for the `fool' category.") + +(cl-defstruct (erc-match-opt-pal + (:include erc-match-user + (category 'pal) + (predicate #'erc-match--user-nuh-or-mention-p) + (part erc-pal-highlight-type) + (face 'erc-pal-face) + (data erc-pals)) + (:constructor erc-match-opt-pal)) + "An options-based type for the `pal' category.") + +(cl-defstruct (erc-match-opt-dangerous-host + (:include erc-match-user + (category 'dangerous-host) + (predicate #'erc-match--user-nuh-or-mention-p) + (part erc-dangerous-host-highlight-type) + (face 'erc-dangerous-host-face) + (data erc-dangerous-hosts)) + (:constructor erc-match-opt-dangerous-host)) + "An options-based type for the `dangerous-host' category.") + +(defun erc-match--opt-pat-get (compute-fn input) + "Retrieve cached results for computing INPUT with COMPUTE-FN." + (with-memoization (alist-get input (alist-get compute-fn + erc-match--opt-pat-cache nil t) + nil t) + (funcall compute-fn input))) + +(defun erc-match--opt-pat-make (patterns) + "Act like `regexp-opt' but for regexp PATTERNS, not fixed strings." + (string-join patterns "\\|")) + +(defun erc-match--opt-pat-make-kw (patterns) + (mapconcat (lambda (w) (or (car-safe w) w)) patterns "\\|")) + +(defun erc-match--opt-pat-make-addr-beg (patterns) + (concat "\\<\\(" (erc-match--opt-pat-make patterns) "\\)[:,] ")) + +(defun erc-match--opt-pat-make-addr-end (patterns) + (concat "\\s. \\(" (erc-match--opt-pat-make patterns) "\\)\\s.")) + +(defun erc-match--current-nick-p (match) + (re-search-forward (car (erc-match-traditional-data match)) nil t)) + +(defun erc-match--keyword-p (match) + "Return non-nil if the pattern given for MATCH's user option matches." + (and-let* ((patterns (erc-match-traditional-data match))) + (goto-char (erc-match-body-beg match)) + (re-search-forward (erc-match--opt-pat-get #'erc-match--opt-pat-make-kw + patterns) + nil t))) + +(defun erc-match--user-nuh-or-mention-p (match) + "Return non-nil on matching \"NUH\" for MATCH object. +Also do so on mentions if the category is `fool' or the corresponding +\"part\" option is `nick-or-mention'." + (and-let* ((patterns (erc-match-traditional-data match))) + (or (string-match (erc-match--opt-pat-get #'erc-match--opt-pat-make + patterns) + (erc-match-sender match)) + (and (or (eq (erc-match-traditional-category match) 'fool) + (eq (erc-match-traditional-part match) 'nick-or-mention)) + ;; Mimic `erc-match-directed-at-fool-p', but search + ;; the narrowed buffer instead of a string argument. + (goto-char (erc-match-body-beg match)) + (or (looking-at (erc-match--opt-pat-get + #'erc-match--opt-pat-make-addr-beg + patterns)) + (search-forward-regexp + (erc-match--opt-pat-get #'erc-match--opt-pat-make-addr-end + patterns) + nil t)))))) + +(cl-defgeneric erc-match-highlight-by-part (match part) + "Highlight PART of narrowed buffer for `erc-match' object MATCH.") + +(cl-defmethod erc-match-highlight-by-part ((match erc-match-traditional) + (_ (eql nick))) + "Highlight MATCH's nick in the bracketed speaker portion of the message." + (when (erc-match-spkr-beg match) + (erc-put-text-property (erc-match-spkr-beg match) + (erc-match-spkr-end match) + 'font-lock-face + (erc-match-traditional-face match)))) + +(cl-defmethod erc-match-highlight-by-part ((match erc-match-traditional) + (_ (eql message))) + "Highlight MATCH's message body, not including the leading speaker tag." + (erc-put-text-property (erc-match-body-beg match) (point-max) + 'font-lock-face (erc-match-traditional-face match))) + +(cl-defmethod erc-match-highlight-by-part ((match erc-match-traditional) + (_ (eql all))) + "Highlight MATCH's whole message, including the speaker tag." + (erc-put-text-property (point-min) (point-max) + 'font-lock-face (erc-match-traditional-face match))) + +(cl-defmethod erc-match-highlight-by-part ((match erc-match-traditional) + (_ (eql keyword))) + "Highlight all occurrences of all keyword patterns for MATCH." + (dolist (pat (erc-match-traditional-data match)) + (let ((regex (if (consp pat) (car pat) pat)) + (face (if (consp pat) (cdr pat) (erc-match-traditional-face match)))) + (goto-char (erc-match-body-beg match)) + (while (re-search-forward regex nil t) + (erc-put-text-property (match-beginning 0) (match-end 0) + 'font-lock-face face))))) + +(cl-defmethod erc-match-highlight-by-part ((match erc-match-traditional) + (_ (eql nick-or-keyword))) + "Highlight MATCH's speaker-tag nick if applicable, otherwise all mentions." + (if (erc-match-spkr-end match) + (erc-put-text-property (erc-match-spkr-beg match) + (erc-match-spkr-end match) + 'font-lock-face + (erc-match-traditional-face match)) + (erc-match-highlight-by-part match 'keyword))) + +(cl-defmethod erc-match-highlight-by-part ((match erc-match-traditional) + (_ (eql nick-or-mention))) + "Highlight MATCH's speaker tag nick of matching users or all mentions." + (cl-letf (((erc-match-body-beg match) + (or (erc-match-spkr-beg match) (point-min)))) + (erc-match-highlight-by-part match 'keyword))) + +(defvar erc-match-highlight-matched nil + "Matched `erc-match' instance in `erc-text-matched-hook'.") + +(defvar erc-match--instances nil + "Alist mapping constructors to successful `erc-match' instances.") + +(defun erc-match-highlight (match) + "Dispatch `erc-match-highlight-by-part' on MATCH's `:part' slot. +Run `erc-text-matched-hook' when MATCH's `category' slot is non-nil." + (unless (erc-match-traditional-p match) + (signal 'wrong-type-argument (list 'erc-match-traditional match))) + (cl-assert (erc-match-newlinep match)) + (erc-match-highlight-by-part match (erc-match-traditional-part match)) + (when (erc-match-traditional-category match) + (let ((user-nuh (and (erc-match-nick match) (erc-match-sender match))) + (erc-match-highlight-matched match)) + (run-hook-with-args 'erc-text-matched-hook + (erc-match-traditional-category match) + (or user-nuh (format "Server:%s" + (erc-match-command match))) + ;; For compatibility, include a leading "*** ". + (buffer-substring (if user-nuh + (erc-match-body-beg match) + (point-min)) + (point-max)))))) + +(defun erc-match-get-message-body (match) + "Return the message body for MATCH in the current narrowed buffer." + (with-restriction (point-min) + (if (erc-match-newlinep match) (point-max) (1+ (point-max))) + (buffer-substring (erc-match-body-beg match) (1- (point-max))))) + +(defun erc-match-get-match (constructor) + "Return successful `erc-match' instance for CONSTRUCTOR, if any. +Expect to be called only from `erc-match' :predicate and :handler +functions as well as `erc-text-matched-hook' members." + (alist-get constructor erc-match--instances)) + +(defun erc-match--run-match (constructor spkr-beg spkr-end body-beg + nick sender command) + "Run `erc-match' handler if its predicate returns non-nil. +Call CONSTRUCTOR with SPKR-BEG, SPKR-END, BODY-BEG, NICK SENDER, and +COMMAND to create the `erc-match' instance." + (when-let* ((instance (funcall constructor + :spkr-beg spkr-beg + :spkr-end spkr-end + :body-beg body-beg + :nick nick + :sender sender + :command command)) + (_ (or nick (not (erc-match-user-p instance)))) + (_ (goto-char (point-min))) + (_ (funcall (erc-match-predicate instance) instance))) + (if (erc-match-newlinep instance) + (funcall (erc-match-handler instance) instance) + (with-restriction (point-min) (1- (point-max)) + (funcall (erc-match-handler instance) instance))) + (push (cons constructor instance) erc-match--instances) + nil)) + +(defun erc-match--message () + "Run `erc-match-functions' against contents of narrowed buffer." + (goto-char (point-min)) + (let* ((response erc--parsed-response) + (user-nuh (and response (erc-get-parsed-vector-nick response))) + ;; Nick of sender's NUH if they are not the server itself. + (nick (and user-nuh (or (erc--check-msg-prop 'erc--spkr) + (erc-extract-nick user-nuh)))) + (unknownp (erc--check-msg-prop 'erc--msg 'unknown)) + (spkr-end (and (not unknownp) (erc--get-speaker-bounds))) + (spkr-beg (and spkr-end (pop spkr-end))) + (body-beg (save-excursion + (unless unknownp + (when-let* ((fn (erc--check-msg-prop 'erc--pfx))) + (funcall fn))) + (point-marker))) + (command (erc--check-msg-prop 'erc--cmd)) + (erc-match--instances ())) + (with-syntax-table erc-match-syntax-table + (run-hook-wrapped 'erc-match-functions #'erc-match--run-match + spkr-beg spkr-end body-beg nick + (erc-response.sender response) command)))) + +(defvar erc-match-use-legacy-logic-p nil + "When non-nil, use the non-`erc-match' variant of `erc-match-message'.") +(make-obsolete 'erc-match-use-legacy-logic-p + "non-nil behavior mostly replicated bug for bug" "32.1") + (defun erc-match-message () + "Run handlers for matched patterns in the narrowed buffer." + (if (or erc-match-use-legacy-logic-p (null erc--parsed-response)) + (erc-match--message-legacy) + (unless (or (and erc-match-exclude-server-buffer (erc--server-buffer-p)) + (null (erc--check-msg-prop 'erc--cmd)) + (erc--memq-msg-prop 'erc--skip 'match)) + (erc-match--message)))) + +(defun erc-match--message-legacy () "Mark certain keywords in a region. Use this defun with `erc-insert-modify-hook'." ;; This needs some refactoring. @@ -591,27 +937,25 @@ The behavior of this function is controlled by the variables Specify the match types which should be logged in the former, and deactivate/activate match logging in the latter. See `erc-log-match-format'." - (let ((match-buffer-name (cdr (assq match-type - erc-log-matches-types-alist))) - (nick (nth 0 (erc-parse-user nickuserhost)))) - (when (and - (or (eq erc-log-matches-flag t) - (and (eq erc-log-matches-flag 'away) - (erc-away-time))) - match-buffer-name) - (let ((line (format-spec - erc-log-match-format - `((?n . ,nick) - (?t . ,(format-time-string - (or (bound-and-true-p erc-timestamp-format) - "[%Y-%m-%d %H:%M] "))) - (?c . ,(or (erc-default-target) "")) - (?m . ,message) - (?u . ,nickuserhost))))) - (with-current-buffer (erc-log-matches-make-buffer match-buffer-name) - (let ((inhibit-read-only t)) - (goto-char (point-max)) - (insert line))))))) + (when-let* + ((erc-log-matches-flag) + (_ (or (eq erc-log-matches-flag t) (erc-away-time))) + (match-buffer-name (cdr (assq match-type erc-log-matches-types-alist))) + (line (format-spec + erc-log-match-format + (erc-compat--defer-format-spec-in-buffer + (?n . (or (erc--check-msg-prop 'erc--spkr) + (erc-extract-nick nickuserhost))) + (?t . (format-time-string + (or (bound-and-true-p erc-timestamp-format) + "[%Y-%m-%d %H:%M] "))) + (?c erc-default-target) + (?m . message) + (?u . nickuserhost))))) + (with-current-buffer (erc-log-matches-make-buffer match-buffer-name) + (with-silent-modifications + (goto-char (point-max)) + (insert line))))) (defun erc-log-matches-make-buffer (name) "Create or get a log-matches buffer named NAME and return it." diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el index 3e924d0b0f1..20188b323df 100644 --- a/lisp/erc/erc-networks.el +++ b/lisp/erc/erc-networks.el @@ -1609,28 +1609,12 @@ return the host alone sans URL formatting (for compatibility)." (scheme (if (cdr pspec) "ircs" "irc"))) (if ports (format "%s://%s:%d" scheme host (seq-random-elt ports)) host))) -;;; The following experimental -;; It does not work yet, help me with it if you -;; think it is worth the effort. - -(defvar erc-settings - '((pals Libera.Chat ("kensanata" "shapr" "anti\\(fuchs\\|gone\\)")) - (format-nick-function (Libera.Chat "#emacs") erc-format-@nick)) - "Experimental: Alist of configuration options. - -WARNING: this variable is a vestige from a long-abandoned -experiment. ERC may redefine it using the same name for any -purpose at any time. - -The format is (VARNAME SCOPE VALUE) where -VARNAME is a symbol identifying the configuration option, -SCOPE is either a symbol which identifies an entry from - `erc-networks-alist' or a list (NET TARGET) where NET is a network symbol and - TARGET is a string identifying the channel/query target. -VALUE is the options value.") -(make-obsolete-variable 'erc-settings - "temporarily deprecated for later repurposing" "30.1") +;; Longtime occupant of this file `erc-settings' was repurposed in ERC +;; 5.7 and moved to erc-settings.el. +;; Attempting to provide a "working" version of this function would be +;; nonsensical because `erc-settings' now has a completely different +;; layout than the unfinished version from `erc-networks' (circa 2002). (defun erc-get (var &optional net target) "Retrieve configuration values from `erc-settings'. @@ -1639,27 +1623,9 @@ long-abandoned experiment. ERC may redefine it using the same name for any purpose at any time. \(fn &rest UNKNOWN)" - (declare (obsolete "temporarily deprecated for later repurposing" "30.1")) - (let ((items erc-settings) - elt val) - (while items - (setq elt (car items) - items (cdr items)) - (when (eq (car elt) var) - (cond ((and net target (listp (nth 1 elt)) - (eq net (car (nth 1 elt))) - (string-equal target (nth 1 (nth 1 elt)))) - (setq val (nth 2 elt) - items nil)) - ((and net (eq net (nth 1 elt))) - (setq val (nth 2 elt) - items nil)) - ((and (not net) (not target) (not (nth 1 elt))) - (setq val (nth 2 elt) - items nil))))) - val)) - -;; (erc-get 'pals 'Libera.Chat) + (declare (obsolete "`erc-settings' schema incompatible with PoC from 2002" + "31.1")) + (ignore var net target)) (provide 'erc-networks) diff --git a/lisp/erc/erc-settings.el b/lisp/erc/erc-settings.el new file mode 100644 index 00000000000..570a86a9039 --- /dev/null +++ b/lisp/erc/erc-settings.el @@ -0,0 +1,296 @@ +;;; erc-settings.el -- Buffer-local options -*- lexical-binding: t; -*- + +;; Copyright (C) 2026 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: + +;; This module is based on an ancient proof-of-concept by Mario Lang, +;; with contributions from Diane Murray and possibly others. It lived +;; in erc-networks.el for over two decades before becoming its own +;; module in 2026. + +;; Usage: add `settings' to `erc-modules', and customize the option +;; `erc-settings'. + +;;; Code: +(require 'erc) + +(defgroup erc-settings nil + "Buffer-local values for arbitrary user options." + :group 'erc) + +(define-widget 'erc--buffer-match 'lazy + "Condition for `erc-settings--buffer-match-p'." + :tag "Valid `erc-settings' match condition" + :type `(choice (boolean :tag "Always/never") + (regexp :tag "Buffer-name regexp") + (function :tag "Predicate") + (cons :tag "Network" (const network) symbol) + (cons :tag "ID" (const id) symbol) + (cons :tag "Target" (const target) (choice string + (const nil))) + (cons :tag "Buffer name" (const name) string) + (list :tag "Negation" + (const not) + (erc--buffer-match :tag "Match condition")) + (cons :tag "All/any" + (choice :tag "Operator" (const or) (const and)) + (repeat :tag "Match condition" erc--buffer-match)))) + +(defcustom erc-settings () + "A match-condition alist for setting ERC's user options locally. + +This \"meta option\" provides a means of specifying buffer-local values +for other user options. It does this by setting an option's variable +locally in server and target buffers. If a local binding already exists +for a variable, ERC leaves it alone. Alist members should be of the +form (MATCHCOND . BINDINGS), where BINDINGS is a list of assignments +like (VAR VAL . FLAGS). + +MATCHCOND works like a `buffer-match-p' condition, only tailored +slightly to meet ERC's unique requirements. The boolean operators +`and', `or', and `not' remain unchanged, as do strings, which ERC treats +as regexps to be matched against a buffer's name. For servers, this +name is usually a dialed TCP address while connecting and a network (ID) +once connected. Query and channel buffers normally share their target's +name, possibly suffixed by a disambiguating \"@\" + identifier. If +MATCHCOND is a function, ERC assumes it's a predicate that takes no +arguments and runs in the candidate ERC buffer. As for key-value +cons-cell conditions, ERC ignores all traditional ones defined by +`buffer-match-p', like `derived-mode' and `major-mode', instead +preferring to define its own: (network . NETWORK), where NETWORK is a +symbol returned by the function `erc-network'; (id . ID), where ID is a +user-provided symbol as described by the Info node `(erc) Network +Identifier'; (target . TARGET), where TARGET, if non-nil, is the channel +name or query nick; and (name . NAME), which matches a buffer's NAME, as +a string. + +In BINDINGS, each member's VAR is the symbol of a user option or +variable to which ERC assigns the sexp VAL locally in the current +buffer. When FLAGS contains the keyword :eval, ERC evaluates VAL as a +Lisp form and assigns the result to VAR. Each entry in BINDINGS should +appear in order of decreasing match specificity and increasing +generality because even though ERC applies all matching entries, it +skips subsequent ones for which a local binding already exists. + +See Info node `(erc) Settings' for a friendlier description of the DSL +and Info node `(erc) Settings Examples' for example usage." + :package-version '(ERC . "5.7") + :type (let* ((flags '(set :tag "Flags" + (const :tag "Prefer custom-set (advanced)" :custom) + (const :tag "Evaluate form" :eval))) + (setting `(cons :tag "Binding assignment" + (variable :tag "Option/variable") + (cons :tag "Value" sexp ,flags)))) + `(alist :key-type erc--buffer-match :value-type (repeat ,setting)))) + +;;;###autoload(autoload 'erc-settings-mode "erc-settings" nil t) +(define-erc-module settings nil + "Global module to set ERC options locally per-buffer. +Like many modules, this cannot reasonably be toggled via mode command +mid-session. To see the result of updates to the option `erc-settings' +immediately, destroy and reopen all affected sessions." + ((when (and erc--updating-modules-p + (not (memq #'erc-settings--set-modules + (default-value 'erc--set-modules-functions)))) + (erc--warn-once-before-connect 'erc-settings-mode + "Module `settings' did not load properly. Add it to `erc-modules'" + " and run `erc-update-modules' before connecting, or use a" + " Custom-aware configuration method, like `setopt'.")) + ;; Set non-`erc-module' entries in target buffers after all default + ;; non-connection related local session variables have been set. + (if erc--updating-modules-p + (add-hook 'change-major-mode-after-body-hook + #'erc-settings--setup -90 t) + (erc-buffer-do #'erc-settings--setup)) + ;; Set any remaining entries in server buffers once the network is + ;; known and all local session variables have been populated. + (add-hook 'erc-after-connect #'erc-settings-bind -30) + (add-hook 'erc--set-modules-functions #'erc-settings--set-modules 30)) + ((erc-buffer-do #'erc-settings--setup) + (remove-hook 'erc-after-connect #'erc-settings-bind) + (remove-hook 'erc--set-modules-functions #'erc-settings--set-modules))) + +(defun erc-settings--setup () + (if erc-settings-mode + (when erc-server-connected + (erc-settings--set (erc-settings--gather-bindings (current-buffer)))) + (remove-hook 'change-major-mode-after-body-hook #'erc-settings--setup t) + (dolist (entry erc-settings) + (pcase-dolist (`(,var . ,_) (cdr entry)) + (when (local-variable-p var) + (kill-local-variable var)))))) + +(defun erc-settings--buffer-match-p (condition) + "Return non-nil if CONDITION matches current buffer. +Act almost like `buffer-match-p', except recognize an alternate set of +property-based cons-cell conditions. Additionally, don't pass any +arguments to predicate-type conditions, and interpret CONDITION in the +current buffer, where CONDITION should be among the following: + +- the symbol t, which always matches, +- the symbol nil, which never matches, +- a regular expression matched against current buffer's name, +- a predicate taking no arguments and run in the candidate buffer +- a symbol-keyed cons cell described by one the following: + + `id' `eq' to current buffer's network context ID + `network' `eq' to current buffer's `erc-network' + `target' `equal' to current buffer's `erc-target' + `name' `equal' to current buffer's name + `and' a list of matching conditions + `or' a list containing at least one matching condition + `not' a list of a single condition that matches when negated" + (pcase condition + ('t t) + ((pred stringp) (string-match-p condition (buffer-name))) + ((pred functionp) (funcall condition)) + (`(id . ,id) (and erc-networks--id + (eq (erc-networks--id-symbol erc-networks--id) id))) + (`(network . ,network) (and erc-network (eq erc-network network))) + (`(target . ,target) (equal target (erc-target))) + (`(name . ,name) (equal name (buffer-name))) + (`(not . ,cond) (not (erc-settings--buffer-match-p cond))) + (`(or . ,args) (seq-some #'erc-settings--buffer-match-p args)) + (`(and . ,args) (seq-every-p #'erc-settings--buffer-match-p args)))) + +(defun erc-settings-bind (&rest _) + "Set all settings in option `erc-settings' from current network's ID." + (erc-settings--set (erc-settings--gather-bindings (current-buffer)))) + +;;;###autoload +(defun erc-settings--set-modules (id target target-server-buffer) + "Set `erc-modules' locally if an entry exists for the current buffer. +In server buffers, bind all matching entries, not just `erc-modules'. +Expect TARGET to be a string or nil and ID to be a symbol. When TARGET +is non-nil, borrow local values from TARGET-SERVER-BUFFER to temporarily +bind identifying variables sought by match conditions." + (when (and erc-settings (or erc-settings-mode (memq 'settings erc-modules))) + ;; Shadow `erc-networks--id' for (id . <id>), `erc--target' for + ;; (target . <target>), etc. Although predicates of interest, like + ;; `erc-query-buffer-p', may call on `buffer-local-value', its + ;; `buffer' argument will be the current buffer, which doesn't yet + ;; have any buffer-local bindings. + (cl-assert (not (local-variable-p 'erc-networks--id))) + (cl-assert (not (local-variable-p 'erc-network))) + (cl-assert (not (local-variable-p 'erc--target))) + (let ((erc-networks--id + (or (and id (erc-networks--id-create id)) + (and target (buffer-local-value 'erc-networks--id + target-server-buffer))))) + (if target + (if-let* + ((erc-network (buffer-local-value 'erc-network + target-server-buffer)) + (erc--target (erc--target-from-string target)) + (bindings (erc-settings--gather-bindings (current-buffer))) + (entry (assq 'erc-modules bindings))) + (erc-settings--set-value 'erc-modules (nth 1 entry) (cddr entry)) + (when-let* ((old-value (with-current-buffer target-server-buffer + (and (local-variable-p 'erc-modules) + erc-modules)))) + (setq-local erc-modules old-value))) + (erc-settings-bind))))) + +(defun erc-settings--gather-bindings (buffer) + "Return a list of matching bindings for server BUFFER's session." + (with-current-buffer buffer + (mapcan (lambda (entry) + (and (erc-settings--buffer-match-p (car entry)) + (copy-sequence (cdr entry)))) + erc-settings))) + +;; Currently, when a binding contains the experimental flag :custom, ERC +;; tries to use VAR's `custom-set' function, if defined, for setting its +;; value. ERC doesn't do so by default because many such functions use +;; `set-default', which defeats the purpose. +(defun erc-settings--set-value (var value flags) + "Set VAR to VALUE locally and interpret FLAGS. +Do nothing if VAR already has a local binding. If VAR has the symbol +property `erc-settings--wrap', assume it's a function that takes the +arguments (SETTER VAR VALUE), and defer to it to perform the actual +setting." + (unless (local-variable-p var) + (let ((setter #'set) + (evalp nil) + (customp nil)) + (dolist (flag flags) + (pcase-exhaustive flag + (:eval (setq evalp t)) + (:custom (setq customp t)))) + (make-local-variable var) + (when evalp + (setq value (eval value t))) + (when customp + (custom-load-symbol var) + (setq setter (or (get var 'custom-set) #'set))) + (if-let* ((xsetter (get var 'erc-settings--wrap))) + (funcall xsetter setter var value) + (funcall setter var value))))) + +(defun erc-settings--set (bindings) + "Set all matching bindings locally in current buffer. +Expect BINDINGS to be a list of (KEY VALUE . FLAGS)." + (pcase-dolist (`(,var ,value . ,flags) bindings) + (erc-settings--set-value var value flags))) + +(defun erc-settings--ensure-prompt-reset (setter var value) + (cl-assert (eq var 'erc-prompt)) + (when (and erc-input-marker (stringp value)) + (let ((erc-prompt (lambda () value))) + (with-silent-modifications + (erc--refresh-prompt)))) + (funcall setter var value)) + +(put 'erc-prompt 'erc-settings--wrap #'erc-settings--ensure-prompt-reset) + +(defun erc-settings--find-condition (predicate settings) + "Return all conditions in SETTINGS for which PREDICATE returns non-nil." + (letrec ((found ()) + (find (lambda (condition) + (pcase condition + (`(and . ,rest) (mapc find rest)) + (`(or . ,rest) (mapc find rest)) + (`(not ,cond) (funcall find cond)) + ((pred (funcall predicate)) (push condition found)))))) + (dolist (setting settings) + (funcall find (car setting))) + (nreverse found))) + +(defun erc-settings--extract-ids () + "Return all arguments to an `id' property condition in `erc-settings'." + (mapcar #'cdr (erc-settings--find-condition + (lambda (condition) (eq (car-safe condition) 'id)) + erc-settings))) + +;;;###autoload +(defun erc-settings-connect-by-id (network-id) + "Connect via some preconfigured network ID specified in `erc-settings'. +See Info node `(erc) ID-based Settings Example'." + (interactive (list (completing-read "Network ID: " + (erc-settings--extract-ids)))) + (erc-tls :server nil :port nil :nick nil :user nil + :password nil :full-name nil :id network-id)) + +(provide 'erc-settings) + +;;; erc-settings.el ends here +;; +;; Local Variables: +;; generated-autoload-file: "erc-loaddefs.el" +;; End: diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index fa4b829b4cf..00644c2c997 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -150,7 +150,7 @@ This string specifies the format of the timestamp being echoed in the minibuffer." :type '(choice (const :tag "Timestamped Monday, 15:04:05" "Timestamped %A, %H:%M:%S") - (const :tag "2006-01-02 15:04:05 MST" "%F %T %Z") + (const :tag "2026-07-21 15:04:05 JST" "%F %T %Z") string)) (defcustom erc-echo-timestamp-zone nil @@ -178,13 +178,11 @@ from entering them and instead jump over them." ;;;###autoload(autoload 'erc-timestamp-mode "erc-stamp" nil t) (define-erc-module stamp timestamp "This mode timestamps messages in the channel buffers." - ((add-hook 'erc-mode-hook #'erc-stamp--setup) - (add-hook 'erc-insert-modify-hook #'erc-add-timestamp 70) + ((add-hook 'erc-insert-modify-hook #'erc-add-timestamp 70) (add-hook 'erc-send-modify-hook #'erc-add-timestamp 70) (add-hook 'erc-mode-hook #'erc-stamp--recover-on-reconnect) - (unless erc--updating-modules-p (erc-buffer-do #'erc-stamp--setup))) - ((remove-hook 'erc-mode-hook #'erc-stamp--setup) - (remove-hook 'erc-insert-modify-hook #'erc-add-timestamp) + (erc-with-initialized-session (erc-stamp--setup))) + ((remove-hook 'erc-insert-modify-hook #'erc-add-timestamp) (remove-hook 'erc-send-modify-hook #'erc-add-timestamp) (remove-hook 'erc-mode-hook #'erc-stamp--recover-on-reconnect) (erc-buffer-do #'erc-stamp--setup))) diff --git a/lisp/erc/erc-track.el b/lisp/erc/erc-track.el index 6306df3fa2a..53213217f7c 100644 --- a/lisp/erc/erc-track.el +++ b/lisp/erc/erc-track.el @@ -215,7 +215,7 @@ Note that ERC prioritizes certain faces reserved for critical messages regardless of this option's value." :package-version '(ERC . "5.6.1") :set #'erc-track--massage-nick-button-faces - :type (erc--with-dependent-type-match + :type (erc--custom-with-type-match-features (repeat (choice face (repeat :tag "Combination" face))) erc-button)) @@ -259,7 +259,7 @@ module. To see your changes reflected mid-session, cycle The effect may be disabled by setting this variable to nil." :package-version '(ERC . "5.6.1") :set #'erc-track--massage-nick-button-faces - :type (erc--with-dependent-type-match + :type (erc--custom-with-type-match-features (repeat (choice face (repeat :tag "Combination" face))) erc-button)) @@ -607,8 +607,7 @@ keybindings will not do anything useful." ;; enable the tracking keybindings (add-hook 'erc-connect-pre-hook #'erc-track-minor-mode-maybe) (erc-track-minor-mode-maybe)) - (add-hook 'erc-mode-hook #'erc-track--setup) - (unless erc--updating-modules-p (erc-buffer-do #'erc-track--setup)) + (erc-with-initialized-session (erc-track--setup)) (add-hook 'erc-networks--copy-server-buffer-functions #'erc-track--replace-killed-buffer)) ;; Disable: @@ -630,7 +629,6 @@ keybindings will not do anything useful." (remove-hook 'erc-connect-pre-hook #'erc-track-minor-mode-maybe) (when erc-track-minor-mode (erc-track-minor-mode -1))) - (remove-hook 'erc-mode-hook #'erc-track--setup) (erc-buffer-do #'erc-track--setup) (remove-hook 'erc-networks--copy-server-buffer-functions #'erc-track--replace-killed-buffer))) diff --git a/lisp/erc/erc-truncate.el b/lisp/erc/erc-truncate.el index 340584e26db..d651d87d412 100644 --- a/lisp/erc/erc-truncate.el +++ b/lisp/erc/erc-truncate.el @@ -67,12 +67,10 @@ for other purposes should customize either `erc-enable-logging' or ;;enable ((add-hook 'erc-insert-done-hook #'erc-truncate-buffer) (add-hook 'erc-connect-pre-hook #'erc-truncate--warn-about-logging) - (add-hook 'erc-mode-hook #'erc-truncate--setup) - (unless erc--updating-modules-p (erc-buffer-do #'erc-truncate--setup))) + (erc-with-initialized-session (erc-truncate--setup))) ;; disable ((remove-hook 'erc-insert-done-hook #'erc-truncate-buffer) (remove-hook 'erc-connect-pre-hook #'erc-truncate--warn-about-logging) - (remove-hook 'erc-mode-hook #'erc-truncate--setup) (erc-buffer-do #'erc-truncate--setup))) (defvar-local erc-truncate--buffer-size nil diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 591ca1f5fbe..f87d13eb559 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -188,6 +188,9 @@ as of ERC 5.6: - `erc--skip': list of symbols known to modules that indicate an intent to skip or simplify module-specific processing + - `erc--pfx': function taking no args that advances point to the + start of the semantic body + - `erc--ephemeral': a symbol prefixed by or matching a module name; indicates to other modules and members of modification hooks that the current message should not affect stateful @@ -2013,6 +2016,10 @@ buries those." (target (buffer-local-value 'erc--target target)) ((erc--target-channel-p target))))))) +(defun erc-channel-buffer-p (&optional buffer) + "Call `erc-channel-p' with BUFFER or the current buffer." + (erc-channel-p (or buffer (current-buffer)))) + ;; For the sake of compatibility, a historical quirk concerning this ;; option, when nil, has been preserved: all buffers are suffixed with ;; the original dialed host name, which is usually something like @@ -2407,6 +2414,7 @@ removed modules. It also gives packages access to the hook scrolltobottom) (const :tag "services: Identify to Nickserv (IRC Services) automatically" services) + (const :tag "settings: Set ERC user options buffer locally" settings) (const :tag "smiley: Convert smileys to pretty icons" smiley) (const :tag "sound: Play sounds when you receive CTCP SOUND requests" sound) @@ -2494,6 +2502,11 @@ realizes it's missing some required module \"foo\", it can confidently call (erc-foo-mode 1) without having to learn anything about the dependency's implementation.") +(defvar erc--set-modules-functions nil + "Abnormal hook run before updating modules on major-mode init. +Calls members with ID and TARGET parameters of `erc-open', both possibly +nil, along with a non-nil TARGET's server buffer when applicable.") + (defvar erc--setup-buffer-hook '(erc--warn-about-aberrant-modules) "Internal hook for module setup involving windows and frames.") @@ -2649,6 +2662,9 @@ side effect of setting the current buffer to the one it returns. Use (when connect (run-hook-with-args 'erc-before-connect server port nick)) (set-buffer buffer) (setq old-point (point)) + (delay-mode-hooks (erc-mode)) + (run-hook-with-args 'erc--set-modules-functions id channel + (and channel old-buffer)) (setq delayed-modules (erc--merge-local-modes (let ((erc--updating-modules-p t)) (erc--update-modules @@ -2656,8 +2672,6 @@ side effect of setting the current buffer to the one it returns. Use (or erc--server-reconnecting erc--target-priors))) - (delay-mode-hooks (erc-mode)) - (setq erc-server-reconnect-count old-recon-count) (when (setq erc-server-connected (not connect)) @@ -3269,11 +3283,13 @@ when present. Assume NICK itself to be free of any text props, and return it." (cond (erc--msg-props (puthash 'erc--spkr nick erc--msg-props) + (puthash 'erc--pfx #'erc--pfx-skip-spkr-fwd erc--msg-props) (dolist (entry overrides) (puthash (car entry) (cdr entry) erc--msg-props))) (erc--msg-prop-overrides (setq erc--msg-prop-overrides - `((erc--spkr . ,nick) ,@overrides ,@erc--msg-prop-overrides)))) + `((erc--spkr . ,nick) (erc--pfx . ,#'erc--pfx-skip-spkr-fwd) + ,@overrides ,@erc--msg-prop-overrides)))) nick) (defun erc-string-invisible-p (string) @@ -3868,8 +3884,14 @@ retrieval by `text-properties-at' and friends." See also `erc-make-notice'." (cond ((eq type 'notice) + (when erc--msg-props + (puthash 'erc--pfx #'erc--pfx-skip-notice-fwd erc--msg-props)) (erc-make-notice string)) (t + (when (and erc--msg-props ; prefer notice if combined + (not (erc--check-msg-prop 'erc--pfx + #'erc--pfx-skip-notice-fwd))) + (puthash 'erc--pfx #'erc--pfx-skip-template-fwd erc--msg-props)) (erc-put-text-property 0 (length string) 'font-lock-face @@ -6283,6 +6305,35 @@ Assume buffer is narrowed to the confines of an inserted message." 'erc--speaker nil))) (cons beg (next-single-property-change beg 'erc--speaker)))) +(defvar erc--ctcp-action-speaker-in-prefix-p nil + ;; This variable replaces `erc-fill--wrap-action-dedent-p' in ERC 5.6. + "Whether the speaker of a /ME is part of the prefix rather than the body.") + +;; Insertion hook members defer to the function value of the `erc--pfx' +;; msg prop to find the "body" portion of a message after a prefix, such +;; as a "<speaker> " tag, assuming the `erc--msg' prop isn't `unknown'. +(defun erc--pfx-skip-word-fwd () + "Go to a space following an initial run of non-space chars." + (unless (and (bobp) (eq ?\s (char-after (point)))) + (search-forward " " (pos-eol) t))) + +(defun erc--pfx-skip-spkr-fwd () + "Move point after the first space following the speaker tag. +That's one char beyond the last with a `erc--speaker' text property." + (let ((bounds (erc--get-speaker-bounds))) + (when (or erc--ctcp-action-speaker-in-prefix-p + (not (erc--check-msg-prop 'erc--ctcp 'ACTION))) + (goto-char (cdr bounds))) + (search-forward " " (pos-eol) t))) + +(defun erc--pfx-skip-notice-fwd () + "Move point past `erc-notice-prefix'." + (search-forward erc-notice-prefix (+ (point) (length erc-notice-prefix)) t)) + +(defun erc--pfx-skip-template-fwd () + "Skip common prefixes from the English format-template catalog." + (search-forward-regexp (rx bol (| "\n\n*** " "==> ")) (+ (point) 6) t)) + (defvar erc--cmem-from-nick-function #'erc--cmem-get-existing "Function maybe returning a \"channel member\" cons from a nick. Must return either nil or a cons of an `erc-server-user' and an diff --git a/lisp/files.el b/lisp/files.el index 22313b71635..27a69b3fc81 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -1331,7 +1331,7 @@ remote, otherwise search locally." ;; Use 1 rather than file-executable-p to better match the ;; behavior of call-process. (let ((default-directory (file-name-quote default-directory 'top))) - (locate-file command exec-path exec-suffixes 1)))) + (locate-file command exec-path (default-value 'exec-suffixes) 1)))) (declare-function read-library-name "find-func" nil) @@ -3155,6 +3155,7 @@ since only a single case-insensitive search through the alist is made." ("\\.srt\\'" . srecode-template-mode) ("\\.prolog\\'" . prolog-mode) ("\\.tar\\'" . tar-mode) + ("\\(?:\\.rmail\\|\\(?:\\`\\|[/\\]\\)RMAIL\\)\\'" . rmail-mode) ;; The list of archive file extensions should be in sync with ;; `auto-coding-alist' with `no-conversion' coding system. ("\\.\\(\ @@ -3990,6 +3991,18 @@ variable `enable-remote-dir-locals' is non-nil." :risky t :group 'find-file) +(defmacro without-local-variable-queries (&rest body) + "Execute BODY without querying user about local variable values. +In some uses, this is a workaround for the problem that a command +disables displaying new windows for its own reasons but this also breaks +`hack-local-variables-confirm'. See Emacs bug#80528 and bug#81233." + (declare (indent 0) (debug t)) + `(let ((enable-local-variables + (if (memq enable-local-variables '(:safe :all nil)) + enable-local-variables + :safe))) + ,@body)) + (defun hack-local-variables-confirm (all-vars unsafe-vars risky-vars dir-name) "Get confirmation before setting up local variable values. ALL-VARS is the list of all variables to be set up. @@ -4054,6 +4067,9 @@ i -- to ignore the local variables list, and permanently mark these ;; Display the buffer and read a choice. (save-window-excursion (pop-to-buffer buf '(display-buffer--maybe-at-bottom)) + (unless (get-buffer-window buf) + (error "Failed to display local variables buffer; this is a bug +Possibly caller should use `without-local-variable-queries', which see.")) (let* ((exit-chars '(?y ?n ?\s)) (prompt (format "Please type %s%s: " (if offer-save @@ -4623,7 +4639,9 @@ already the major mode." ;; so it is risky to put them on with a local variable list. (if (stringp val) (set-text-properties 0 (length val) nil val)) - (set (make-local-variable var) val)))) + (if (custom-variable-p var) + (setopt--set-local var val) + (set (make-local-variable var) val))))) ;;; Handling directory-local variables, aka project settings. @@ -8486,8 +8504,10 @@ normally equivalent short `-D' option is just passed on to (defvar dired--ls-error-buffer) ; Pacify byte-compiler. (let ((errbuf (get-buffer-create "*ls error*"))) (with-current-buffer errbuf - (erase-buffer) - (insert-file-contents errfile)) + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (erase-buffer) + (insert-file-contents errfile))) (setq dired--ls-error-buffer errbuf))) (defvar dired--ls-error-file) ; Pacify byte-compiler. (setq dired--ls-error-file errfile) diff --git a/lisp/frame.el b/lisp/frame.el index 85b58cee070..36c14304ec7 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -1782,11 +1782,7 @@ resize and move FRAME." (when negative (setq gravity 3) (setq left (- parent-or-display-width (- left) - (+ text-width - (frame-scroll-bar-width frame) - (frame-fringe-width frame) - (* 2 (frame-internal-border-width frame)) - outer-minus-text-width)))) + text-width outer-minus-text-width))) (setq negative nil) (cond @@ -1813,9 +1809,7 @@ resize and move FRAME." ;; This should get us 7 or 9. (setq gravity (+ gravity 6)) (setq top (- parent-or-display-height (- top) - (+ text-height - (* 2 (frame-internal-border-width frame))) - outer-minus-text-height))) + text-height outer-minus-text-height))) (set-frame-size-and-position-pixelwise frame text-width text-height left top gravity))) diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el index 88217b15398..75430ba2e6e 100644 --- a/lisp/gnus/mml.el +++ b/lisp/gnus/mml.el @@ -556,12 +556,19 @@ type detected." (libxml-parse-html-region (point) (progn (forward-sexp) (point)))))) (end (point)) - (parsed (url-generic-parse-url (cdr (assq 'src (cadr img)))))) - (when (and (null (url-type parsed)) + (url (cdr (assq 'src (cadr img)))) + (parsed (url-generic-parse-url url))) + (when (and (let ((type (url-type parsed))) + (or + ;; No scheme. + (null type) + ;; A file scheme with an empty host part. + (and (string-equal type "file") + (string-empty-p (url-host parsed))))) (not (zerop (length (url-filename parsed)))) (file-exists-p (url-filename parsed))) (goto-char start) - (when (search-forward (url-filename parsed) end t) + (when (search-forward url end t) (let ((cid (format "fsf.%d" cid))) (replace-match (concat "cid:" cid) t t) (push (list cid (url-filename parsed) diff --git a/lisp/gnus/nndiary.el b/lisp/gnus/nndiary.el index eef00938453..8c7f815652f 100644 --- a/lisp/gnus/nndiary.el +++ b/lisp/gnus/nndiary.el @@ -345,7 +345,8 @@ all. This may very well take some time.") ;; 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 + ;; been wrong since Internet RFC 2822 (2001), and abbreviations like "PST" + ;; do not match current practice in some locations. However, the ;; abbreviations have not been changed due to backward compatibility ;; concerns. ) diff --git a/lisp/help-fns.el b/lisp/help-fns.el index b7292eafb8a..af5a64f9e9c 100644 --- a/lisp/help-fns.el +++ b/lisp/help-fns.el @@ -1184,7 +1184,8 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED REAL-DEF)." ;; FIXME: If someday Emacs has a function type symbol ;; like `unicode-function' or `hour-function', this ;; will produce an ungrammatical string (bug#79469). - (concat (if (string-match-p "\\`[aeiou]" (symbol-name type)) + (concat (if (and (equal beg "a ") + (string-match-p "\\`[aeiou]" typ-str)) "an " beg) typ-str)))))) diff --git a/lisp/help.el b/lisp/help.el index f5fe34435bb..be6e56ab646 100644 --- a/lisp/help.el +++ b/lisp/help.el @@ -1998,18 +1998,20 @@ function is called, the window to be resized is selected." (define-minor-mode temp-buffer-resize-mode "Toggle auto-resizing temporary buffer windows (Temp Buffer Resize Mode). -When Temp Buffer Resize mode is enabled, the windows in which we -show a temporary buffer are automatically resized in height to +When Temp Buffer Resize mode is enabled, the windows in which Emacs +shows a temporary buffer are automatically resized in height to fit the buffer's contents, but never more than `temp-buffer-max-height' nor less than `window-min-height'. -A window is resized only if it has been specially created for the -buffer. Windows that have shown another buffer before are not -resized. A frame is resized only if `fit-frame-to-buffer' is -non-nil. +When this mode is enabled, a window is resized only if it has been +specially created for a temporary buffer. Windows that have shown +another buffer before being reused for displaying a temporary buffer +are not resized (but note that if `even-window-sizes' is non-nil, they +might be resized in some situations anyway). A frame is resized only +if `fit-frame-to-buffer' is non-nil. This mode is used by `help', `apropos' and `completion' buffers, -and some others." +and some others, when they display their pop-up buffers." :global t :group 'help (if temp-buffer-resize-mode ;; `help-make-xrefs' may add a `back' button and thus increase the @@ -2050,7 +2052,10 @@ provided `fit-frame-to-buffer' is non-nil." (quit-cadr (cadr (window-parameter window 'quit-restore)))) ;; Resize WINDOW only if it was made by `display-buffer'. (when (or (and (eq quit-cadr 'window) - (or (and (window-combined-p window) + ;; When WINDOW was reused, its buffer must be the one + ;; initially shown in it (Bug#81207). + (eq buffer (nth 3 (window-parameter window 'quit-restore))) + (or (and (window-combined-p window) (not (eq fit-window-to-buffer-horizontally 'only)) (pos-visible-in-window-p diff --git a/lisp/image/image-dired.el b/lisp/image/image-dired.el index cba090e7c85..1a8fb1007f4 100644 --- a/lisp/image/image-dired.el +++ b/lisp/image/image-dired.el @@ -1296,10 +1296,10 @@ which is based on `image-mode'." (when buf (pop-to-buffer buf)) (select-window cur-win))) -(defun image-dired-display-this (&optional arg) +(defun image-dired-display-this (&optional _ignore) "Display current thumbnail's original image in display buffer. -See documentation for `image-dired-display-image' for more information. -With prefix argument ARG, display image in its original size." +See documentation for `image-dired-display-image' for more information." + (declare (advertised-calling-convention () "29.1")) (interactive "P" image-dired-thumbnail-mode) (unless (string-equal major-mode "image-dired-thumbnail-mode") (user-error "Not in `image-dired-thumbnail-mode'")) @@ -1309,7 +1309,7 @@ With prefix argument ARG, display image in its original size." ((not file) (message "No original file name found")) (t - (image-dired-display-image file arg))))) + (image-dired-display-image file))))) (defun image-dired-display-next (&optional arg) "Move to the next image in the thumbnail buffer and display it. diff --git a/lisp/international/mule-conf.el b/lisp/international/mule-conf.el index 818ae9728ce..f6347d3765c 100644 --- a/lisp/international/mule-conf.el +++ b/lisp/international/mule-conf.el @@ -1644,6 +1644,8 @@ for decoding and encoding files, process I/O, etc." ;; the beginning of a doc string, work. ("\\(\\`\\|/\\)loaddefs.el\\'" . (raw-text . raw-text-unix)) ("\\.tar\\'" . (no-conversion . no-conversion)) + ("\\(?:\\.rmail\\|\\(?:\\`\\|[/\\]\\)RMAIL\\)\\'" + . (no-conversion . no-conversion)) ( "\\.po[tx]?\\'\\|\\.po\\." . po-find-file-coding-system) ("\\.\\(tex\\|ltx\\|dtx\\|drv\\)\\'" . latexenc-find-file-coding-system) ("" . (undecided . nil)))) diff --git a/lisp/isearch.el b/lisp/isearch.el index 92bd9af6643..3d594c72780 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -2204,8 +2204,8 @@ nil and a non-nil value of the option `search-invisible' (if (setq isearch-invisible (if isearch-invisible nil (or search-invisible 'open))) - "match invisible text" - "match visible text"))) + "match also invisible text" + "match only visible text"))) ;; Word search diff --git a/lisp/jsonrpc.el b/lisp/jsonrpc.el index 174c99afc86..55d0dea81bb 100644 --- a/lisp/jsonrpc.el +++ b/lisp/jsonrpc.el @@ -4,7 +4,7 @@ ;; Author: João Távora <[email protected]> ;; Keywords: processes, languages, extensions -;; Version: 1.0.28 +;; Version: 1.0.29 ;; Package-Requires: ((emacs "25.2")) ;; This is a GNU ELPA :core package. Avoid functionality that is not @@ -678,14 +678,16 @@ If CONN is not shutdown within a reasonable amount of time, warn and delete the network process." (unwind-protect (cl-loop - with proc = (jsonrpc--process conn) for i from 0 + with proc = (jsonrpc--process conn) + with grace = 0.3 with start = (float-time) + for i from 0 while (not (process-get proc 'jsonrpc-sentinel-cleanup-started)) - unless (zerop i) do + unless (or (zerop i) (< (- (float-time) start) grace)) do (jsonrpc--warn "Sentinel for %s still hasn't run, deleting it!" proc) (delete-process proc) do ;; Let sentinel have a chance to run - (accept-process-output nil 0.1)) + (accept-process-output nil grace)) (when cleanup (kill-buffer (process-buffer (jsonrpc--process conn))) (kill-buffer (jsonrpc-stderr-buffer conn))))) diff --git a/lisp/ldefs-boot.el b/lisp/ldefs-boot.el index b8664c9693d..2f58a8ebc68 100644 --- a/lisp/ldefs-boot.el +++ b/lisp/ldefs-boot.el @@ -2561,8 +2561,9 @@ used instead of `browse-url-new-window-flag'. (make-obsolete 'browse-url-mozilla 'nil "29.1") (autoload 'browse-url-firefox "browse-url" "Ask the Firefox WWW browser to load URL. -Defaults to the URL around or before point. Passes the strings -in the variable `browse-url-firefox-arguments' to Firefox. +Defaults to the URL around or before point. Invokes the program +specified by `browse-url-firefox-program'. Passes the strings +in the variable `browse-url-firefox-arguments' to that program. Interactively, if the variable `browse-url-new-window-flag' is non-nil, loads the document in a new Firefox window. A non-nil prefix argument @@ -2578,9 +2579,9 @@ instead of `browse-url-new-window-flag'. (fn URL &optional NEW-WINDOW)" t) (autoload 'browse-url-chromium "browse-url" "Ask the Chromium WWW browser to load URL. -Default to the URL around or before point. The strings in -variable `browse-url-chromium-arguments' are also passed to -Chromium. +Default to the URL around or before point. Invokes the program +specified by `browse-url-chromium-program'. Passes the strings in +variable `browse-url-chromium-arguments' to that program. The optional argument NEW-WINDOW is not used. (fn URL &optional NEW-WINDOW)" t) @@ -6384,6 +6385,15 @@ even if it doesn't match the type.) " (fn VARIABLE VALUE)") +(defvar setopt-local-type-mismatch nil +"Behavior of `setopt-local’ if value's type doesn't match its definition. +If nil, emit a warning, but accept the mismatched value. +If the symbol `accept', ignore type mismatch warning and assign the value. +If the symbol `discard', ignore warning and discard the mismatched value. +If any other non-nil value, prompt whether to accept or discard the value. +Note: Accepting mismatched values may result in unexpected behavior.") +(custom-autoload 'setopt-local-type-mismatch "cus-edit" t) +(put 'setopt-local-type-mismatch 'safe-local-variable #'symbolp) (autoload 'setopt-local "cus-edit" "Set buffer local VARIABLE/VALUE pairs, and return the final VALUE. This is like `setq-local', but is meant for user options instead of @@ -6401,7 +6411,8 @@ Signal an error if a `custom-set' form does not support the (fn [VARIABLE VALUE]...)" nil t) (autoload 'setopt--set-local "cus-edit" -" +"Set a buffer local VARIABLE to VALUE. +Consult `setopt-local-type-mismatch'. (fn VARIABLE VALUE)") (autoload 'customize-save-variable "cus-edit" @@ -8407,6 +8418,38 @@ Linux console, for which Emacs has a reliable way of determining which characters can be displayed and which cannot. (fn &optional REPL FROM TO)" t) +(defvar prettify-special-glyphs-mode nil +"Non-nil if Prettify-Special-Glyphs mode is enabled. +See the `prettify-special-glyphs-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `prettify-special-glyphs-mode'.") +(custom-autoload 'prettify-special-glyphs-mode "disp-table" nil) +(autoload 'prettify-special-glyphs-mode "disp-table" +"Mode to display pretty special character glyphs. + +If you have already customized your special character glyphs, only the +`special-glyphs' face is applied to them. This mode only applies to the +`standard-display-table'. Window or buffer display table, if defined, +still take precedence. + +This is a global minor mode. If called interactively, toggle the +`Prettify-Special-Glyphs mode' mode. If the prefix argument is +positive, enable the mode, and if it is zero or negative, disable the +mode. + +If called from Lisp, toggle the mode if ARG is `toggle'. Enable the +mode if ARG is nil, omitted, or is a positive number. Disable the mode +if ARG is a negative number. + +To check whether the minor mode is enabled in the current buffer, +evaluate `(default-value \\='prettify-special-glyphs-mode)'. + +The mode's hook is called both when the mode is enabled and when it is +disabled. + +(fn &optional ARG)" t) (register-definition-prefixes "disp-table" '("display-table-print-array")) @@ -9962,7 +10005,7 @@ Argument BOTTOM is the bottom margin in number of lines or percent of window. ;;; Generated autoloads from progmodes/eglot.el -(push '(eglot 1 23) package--builtin-versions) +(push '(eglot 1 24) package--builtin-versions) (define-obsolete-function-alias 'eglot-update #'eglot-upgrade-eglot "29.1") (autoload 'eglot "eglot" "Start LSP server for PROJECT's buffers under MANAGED-MAJOR-MODES. @@ -10332,10 +10375,50 @@ Interactively, prompt for ROLE. Call CALLBACK for each analyzed symbol SYM with arguments ROLE, POS, SYM, ID and DEF, where ROLE is a symbol that specifies the semantics of SYM; POS is the position of SYM in STREAM; ID is an object that uniquely -identifies (co-)occurrences of SYM in the current defun; and DEF is the -position in which SYM is locally defined, or nil. If SYM is itself a -binding occurrence, then POS and DEF are equal. If SYM is not lexically -bound, then DEF is nil. +identifies the local reference of SYM in the current defun, so different +occurrences of SYM get the same ID (up to `equal') if and only if they +refer to the same object; and lastly, DEF is the position in which SYM +is locally defined, or nil. For the occurrence of SYM at the position +where it is locally defined (a.k.a. \"bound\"), the values of POS and +DEF are equal. If SYM is not lexically bound, then DEF is nil and so +is ID. + +CALLBACK should use ID by checking if it is nil or `equal' to other ID +values produced in the same call to this function. The specific value +of a given ID is otherwise meaningless. + +As an example, when this function analyzes the following form + + (lambda (mode) (let ((mode (or mode major-mode))) (symbol-name mode))) + +the CALLBACK function is invoked four times with SYM `mode': + +- Once for the `mode' in the `lambda' arguments list, with ROLE + `binding-variable', some non-nil ID value MODE-ID1, and with POS and + DEF both being the same position POS1 where this `mode' occurs. + +- Another time for the binder in the let form, with ROLE + `binding-variable' some non-nil ID value MODE-ID2 that is not `equal' + to MODE-ID1, and with POS and DEF both being the same position POS2. + +- Another for the first argument of `or', with ROLE `bound-variable' and + ID of MODE-ID1, since this occurrence of `mode' is bound by the + `lambda' argument `mode'. Similarly, DEF is POS1, and POS is now a + different position, POS3. + +- Finally, CALLBACK is also invoked for the `mode' that appears in the + body of `let' as the argument of `symbol-name', with ROLE set to + `bound-variable', ID set to MODE-ID2, and DEF set to POS3. + +In the above example, CALLBACK is also invoked for `lambda', `let', +`or', `major-mode' and `symbol-name'. Since those symbols do not have +local references (they refer to global functions/macros/variables), +CALLBACK gets nil ID and nil DEF. + +Note that if SYM is locally-bound, but has no specific binding position, +then DEF is nil while ID is non-nil. This is the case when SYM is bound +by a binder that is only introduced during macro expansion and does not +appear literally in the analyzed code. If STREAM is nil, it defaults to the current buffer. When reading from the current buffer, this function leaves point at the end of the form. @@ -10565,13 +10648,17 @@ or penultimate step during initialization. (autoload 'emacs-lock-mode "emacs-lock" "Toggle Emacs Lock mode in the current buffer. +When a buffer is locked, it cannot be killed and/or Emacs cannot exit +unless the buffer is unlocked first. This protects buffers from +being accidentally killed or lost. + If called with a plain prefix argument, ask for the locking mode -to be used. +to be used in the buffer. Initially, if the user does not pass an explicit locking mode, it defaults to `emacs-lock-default-locking-mode' (which see); afterwards, the locking mode most recently set on the buffer is -used instead. +used as the default instead. When called from Elisp code, ARG can be any locking mode: @@ -10579,7 +10666,7 @@ When called from Elisp code, ARG can be any locking mode: kill -- the buffer cannot be killed, but Emacs can exit as usual all -- the buffer is locked against both actions -Other values are interpreted as usual. +Other values are interpreted as usual for turning modes on/off. See also `emacs-lock-unlockable-modes', which exempts buffers under some major modes from being locked under some circumstances. @@ -10678,9 +10765,12 @@ Message buffer where you can explain more about the patch. ;;; Generated autoloads from international/emoji.el -(autoload 'emoji-insert "emoji") -(autoload 'emoji-recent "emoji") -(autoload 'emoji-search "emoji") +(autoload 'emoji-insert "emoji" nil t) +(autoload 'emoji-recent "emoji" nil t) +(autoload 'emoji-search "emoji" +" + +(fn GLYPH DERIVED)" t) (autoload 'emoji-list "emoji" "List Emoji and allow selecting and inserting one of them. If you are displaying Emoji on a text-only terminal, and some @@ -10700,7 +10790,10 @@ If called from Lisp, return the name as a string; return nil if the name is not known. (fn GLYPH &optional INTERACTIVE)" t) -(autoload 'emoji-list-select "emoji") +(autoload 'emoji-list-select "emoji" +" + +(fn EVENT)" '(emoji-list-mode)) (autoload 'emoji--init "emoji" " @@ -11093,7 +11186,7 @@ a single minimum version string. ;;; Generated autoloads from erc/erc.el -(push '(erc 5 6 2 -4) package--builtin-versions) +(push '(erc 5 7 -4) package--builtin-versions) (dolist (symbol '( erc-sasl erc-spelling ; 29 erc-imenu erc-nicks)) ; 30 (custom-add-load symbol symbol)) @@ -11310,7 +11403,7 @@ server name and search for a match in `erc-networks-alist'.") ;;; Generated autoloads from erc/erc-pcomplete.el -(register-definition-prefixes "erc-pcomplete" '("erc-pcomplet" "pcomplete")) +(register-definition-prefixes "erc-pcomplete" '("erc-" "pcomplete")) ;;; Generated autoloads from erc/erc-replace.el @@ -13851,8 +13944,6 @@ evaluate the variable `flymake-mode'. The mode's hook is called both when the mode is enabled and when it is disabled. -\\{flymake-mode-map} - (fn &optional ARG)" t) (autoload 'flymake-mode-on "flymake" "Turn Flymake mode on.") @@ -15032,11 +15123,6 @@ supported. (register-definition-prefixes "gnus-cus" '("category-fields" "gnus-")) -;;; Generated autoloads from gnus/gnus-dbus.el - -(register-definition-prefixes "gnus-dbus" '("gnus-dbus-")) - - ;;; Generated autoloads from gnus/gnus-delay.el (autoload 'gnus-delay-article "gnus-delay" @@ -20052,7 +20138,7 @@ penultimate step during initialization. ;;; Generated autoloads from jsonrpc.el -(push '(jsonrpc 1 0 28) package--builtin-versions) +(push '(jsonrpc 1 0 29) package--builtin-versions) (register-definition-prefixes "jsonrpc" '("jsonrpc-")) @@ -20427,7 +20513,7 @@ penultimate step during initialization." t) Dotted symbol is any symbol starting with a `.'. This macro creates let-bindings for dotted symbols that appear literally in BODY (whether or not they are actually used). It does not create bindings for dotted -symbols that are introdcued by macro-expansion in BODY. +symbols that are introduced by macro-expansion in BODY. A symbol of the form `.foo.N' where N is a natural number refers to the Nth element of the value that ALIST associates to key `foo'. @@ -20442,7 +20528,7 @@ For instance, the following code essentially expands to - (let ((.title.0 (nth 0 (cdr (assq \\='title alist)))) + (let ((.title.0 (elt (cdr (assq \\='title alist)) 0)) (.body (cdr (assq \\='body alist))) (.site (cdr (assq \\='site alist))) (.site.contents (cdr (assq \\='contents (cdr (assq \\='site alist)))))) @@ -21429,22 +21515,273 @@ for the current invocation. ;;; Generated autoloads from textmodes/markdown-ts-mode.el +(push '(markdown-ts-mode 1 0) package--builtin-versions) (autoload 'markdown-ts-mode "markdown-ts-mode" "Major mode for editing Markdown using tree-sitter grammar. +NOTE: See `markdown-ts--set-up-inline'. In addition to any hooks its parent mode `text-mode' might have run, this mode runs the hook `markdown-ts-mode-hook', as the final or penultimate step during initialization. \\{markdown-ts-mode-map}" t) +(autoload 'markdown-ts-view-mode "markdown-ts-mode" +"Major mode for read-only viewing Markdown using tree-sitter grammar. + +This mode runs the hook `markdown-ts-view-mode-hook', as the final or +penultimate step during initialization. + +\\{markdown-ts-view-mode-map}" t) +(autoload 'markdown-ts-buffer-string "markdown-ts-mode" +"Like `buffer-string', and convert overlay properties to text properties.") (autoload 'markdown-ts-mode-maybe "markdown-ts-mode" -"Enable `markdown-ts-mode' when its grammar is available. -Also propose to install the grammar when `treesit-enabled-modes' +"Enable `markdown-ts-mode' when its grammars are available. +Also propose to install the grammars when `treesit-enabled-modes' is t or contains the mode name.") -(when (boundp 'treesit-major-mode-remap-alist) (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-ts-mode-maybe)) (add-to-list 'treesit-major-mode-remap-alist '(markdown-mode . markdown-ts-mode))) +(when (boundp 'treesit-major-mode-remap-alist) (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-ts-mode-maybe)) (add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-ts-mode-maybe)) (add-to-list 'auto-mode-alist '("\\.mdx\\'" . markdown-ts-mode-maybe)) (add-to-list 'treesit-major-mode-remap-alist '(markdown-mode . markdown-ts-mode))) (register-definition-prefixes "markdown-ts-mode" '("markdown-ts-")) +;;; Generated autoloads from textmodes/markdown-ts-mode-x.el + +(push '(markdown-ts-mode-x 1 0) package--builtin-versions) +(autoload 'markdown-ts-convert-file "markdown-ts-mode-x" +"Convert Markdown INPUT-FILE to FORMAT. +If optional DISPLAY is non-nil, show the output file in a buffer, if +possible, using the function `markdown-ts-convert-display-function'. + +With a prefix argument, DISPLAY will be non-nil. + +Optional FORMAT is a format/converter pair specified as a cons +\\='(format . converter) for example \\='(html . pandoc). See +`markdown-ts-converters'. If nil, prompt for the format and converter. + +If optional OVERWRITE is non-nil, silently overwrite OUTPUT-FILE if it +exists. + +If QUIET is non-nil, inhibit showing conversion warnings or errors. + +The external executable specified by a converter must be installed and +found; see the variable `exec-path'. + +(fn INPUT-FILE &optional FORMAT OUTPUT-FILE DISPLAY OVERWRITE QUIET)" t) +(autoload 'markdown-ts-convert "markdown-ts-mode-x" +"Convert a `markdown-ts-mode' buffer or file to FORMAT. +Convert INPUT-FILE to OUTPUT-FILE. + +If INPUT-FILE is nil, use the current buffer. + +If OUTPUT-FILE is nil, prompt for an output file. + +Optional FORMAT is a format/converter pair specified as a cons +\\='(format . converter) for example \\='(html . pandoc). See +`markdown-ts-converters'. If nil, prompt for the format and converter. + +If optional DISPLAY is non-nil, show the output file in a buffer, if +possible, using the function `markdown-ts-convert-display-function'. + +With a prefix argument, DISPLAY will be non-nil. + +If optional OVERWRITE is non-nil, silently overwrite OUTPUT-FILE if it +exists. + +If QUIET is non-nil, inhibit showing conversion warnings or errors. + +The external executable specified by a converter must be installed and +found; see the variable `exec-path'. + +(fn &optional INPUT-FILE OUTPUT-FILE FORMAT DISPLAY OVERWRITE QUIET)" t) +(autoload 'markdown-ts-toc-update-before-save-mode "markdown-ts-mode-x" +"If enabled, update `markdown-ts-mode' tables of contents before saving. + +This is a minor mode. If called interactively, toggle the +`Markdown-Ts-Toc-Update-Before-Save mode' mode. If the prefix argument +is positive, enable the mode, and if it is zero or negative, disable the +mode. + +If called from Lisp, toggle the mode if ARG is `toggle'. Enable the +mode if ARG is nil, omitted, or is a positive number. Disable the mode +if ARG is a negative number. + +To check whether the minor mode is enabled in the current buffer, +evaluate the variable `markdown-ts-toc-update-before-save-mode'. + +The mode's hook is called both when the mode is enabled and when it is +disabled. + +(fn &optional ARG)" t) +(autoload 'markdown-ts-toc-clear-and-remove "markdown-ts-mode-x" +"Remove `markdown-ts-mode' table of contents bodies and templates. +Operate on the active region BEG to END, otherwise operate on the +buffer, which may be narrowed. + +(fn &optional BEG END)" t) +(autoload 'markdown-ts-toc-clear "markdown-ts-mode-x" +"Clear `markdown-ts-mode' table of contents bodies. +Operate on the active region BEG to END, otherwise operate on the +buffer, which may be narrowed. +If optional REMOVE is non-nil, remove tables including their templates. + +(fn &optional BEG END REMOVE)" t) +(autoload 'markdown-ts-toc-insert-template "markdown-ts-mode-x" +"Insert a `markdown-ts-mode` table of contents template at point. + +CHAR is the template type \"b\" for basic, \"c\" for complete. If CHAR +is nil and the command is run interactively, prompt for a template. + +The basic template uses all defaults and is likely the best choice for +most uses. The complete template illustrates all parameters set to +their defaults and is useful as a starting point to customize a table. + +(fn &optional CHAR)" t) +(autoload 'markdown-ts-toc-generate "markdown-ts-mode-x" +"Generate tables of contents in the current buffer. +`markdown-ts-mode' uses Markdown HTML comment elements to identify table +of contents (aka toc) insertion boundaries and the parameters for each +table. Derive table content from the Markdown elements in the current +buffer which are usually headings but can also be list items, setext +headers, named code blocks. + +Operate on the active region BEG to END, otherwise operate on the +buffer, which may be narrowed. + +Each time you run this command, existing tables of contents are cleared +and refreshed with new content. So don't place toc elements around +important text. + +The buffer can have one or more tocs. By default, populate each toc +with elements that appear in the buffer below the toc. Therefore, the +easiest way to insert a complete table of contents, is to put the toc +template near the top of your buffer. + +A basic empty toc template looks like this: + +Header text you want here. + +<!-- markdown-ts-toc: --> +Contents inserted between these elements. +<!-- markdown-ts-toc-end: --> + +Footer text you want here. + +Use the command `markdown-ts-toc-insert-template' to insert a table of +contents template. + +Use the command `markdown-ts-toc-clear' to clear table content, and the +command `markdown-ts-toc-clear-and-remove' to both clear and remove +table content and templates. + +By default, a toc includes headers at all levels below the toc which are +presented as list items with links. + +To ignore a Markdown element that would otherwise be included in the +toc, add a toc ignore element: + +## Ignore Me <!-- markdown-ts-toc-ignore: --> + +The starting toc element accepts parameters in the syntax of Emacs file +variables. + +For example, if you want to generate a table of contents limited to +headings two levels deep: + +<!-- markdown-ts-toc: -*- max-depth: 2; -*- --> +<!-- markdown-ts-toc-end: --> + +Or use only headings two and three levels deep. + +<!-- markdown-ts-toc: -*- min-depth: 2; max-depth: 3; -*- --> +<!-- markdown-ts-toc-end: --> + +These are the supported parameters which are optional. They each list +their defaults. + + min-depth: 1 ; an integer + max-depth: nil ; an integer + candidates: (heading) ; a list + from: below ; a symbol + style: item ; a symbol + indent: 1 ; a number + no-link: nil ; a boolean + relative-depth: nil ; a boolean + ignore: nil ; a boolean + +`min-depth' and `max-depth' both default to using all candidates at +every level. Use `min-depth' to ignore level 1 headings like \"# +Heading\", by using 2. Use `max-depth' to control how deep into the +heading hierarchy you need your toc to go. Use 3 to stop at level three +headings. + +Headings dictate the level of their children even if headings are +excluded from candidates. Other element types inherit the level of +their preceding heading. + +`candidates' is a list and can contain any of the following Markdown +element shortcut names. You can mix higher-level grouping symbols and +lower level symbols. + + all (includes everything) + heading (includes the below) + h1 h2 h3 h4 h5 h6 + setext (includes the below) + sh1 sh2 + item (includes the below) + minus plus star + numbered-item (includes the below) + dot paren + code (named code blocks) + +`from' controls the direction and scope from which candidates are +selected. Typically, a toc is placed at the beginning of a buffer and +`from' is `below' to capture entry candidates after the toc. If you set +`from' to `above', candidates are selected from above the toc. Use +`all' to capture every entry candidate. This is useful to create a +complete toc at the end of your buffer. + +The `style' parameter can be nil, `item', `number' or `number.'. Under +nil, entries have no decorations. If `item', entries are prefixed with +\"-\". If `bullet', prefix with \"*\". If `number', numeric prefixes +are generated, for example 1, 1.1, 2, 2.1, 2.1.1, 2.1.2. Use `number.' +to add a period to each entry's number. + +`indent' is an integer between 0 and 10. 0 means nothing should be +indented. Otherwise, each entry is indented by the number of spaces of +its Markdown level multiplied by this value. Candidates that have no +native level such as list items inherit the base indentation level of +its preceding header. List item hierarchies and code blocks indent +under that base. + +Set `no-link' to t if you do not want your entries to have header links. +By default, each entry derived from a heading is presented as a link to +its source heading. NOTE: The elements represented by `setext', `item', +`numbered-item', `code' do not support links. + +Use `relative-depth' to create a toc underneath a heading, limiting the +toc to heading depths underneath the preceding header and specify the +levels relative to that header. More concretely, if the preceding +header is a level 1 \"#\" header, `min-depth' 1 and `max-depth' 2 will +be interpreted to be 2 and 3. If you demote the header to level 2 +\"##\" they will be interpreted as 3 and 4. This is useful to avoid +fussing with toc configurations under headers when you change their +levels. + +For example: + +<!-- markdown-ts-toc: -*- relative-depth: t; min-depth: 1; max-depth: 2; -*- --> +<!-- markdown-ts-toc-end: --> + +Finally, if `ignore' is t, you can keep a toc element in place and skip +it. + +INTERACTIVE will be non-nil if this command was invoked interactively. + +See `markdown-ts-toc-generate-warn-if-none' to configure warnings about +tables not being processed when this function is called. + +(fn &optional INTERACTIVE BEG END)" t) +(register-definition-prefixes "markdown-ts-mode-x" '("markdown-ts-")) + + ;;; Generated autoloads from master.el (autoload 'master-mode "master" @@ -23940,7 +24277,7 @@ penultimate step during initialization." t) ;;; Generated autoloads from org/org.el -(push '(org 9 8 3) package--builtin-versions) +(push '(org 9 8 6) package--builtin-versions) (autoload 'org-babel-do-load-languages "org" "Load the languages defined in `org-babel-load-languages'. @@ -24701,6 +25038,17 @@ The arguments are the same as in `outline-search-text-property', except the hard-coded property name `outline-level'. This function is intended to be used in `outline-search-function'. +(fn &optional BOUND MOVE BACKWARD LOOKING-AT)") +(autoload 'outline-search-from-regexp "outline" +"Search for the next heading matching `outline-regexp'. +The arguments BOUND, MOVE, BACKWARD, and LOOKING-AT are described +in `outline-search-function'. This function is intended to be +used in `outline-search-function' by modes and minor modes that +customize `outline-regexp' but do not need a custom search strategy. +Install it with + + (setq-local outline-search-function #\\='outline-search-from-regexp) + (fn &optional BOUND MOVE BACKWARD LOOKING-AT)") (register-definition-prefixes "outline" '("outline-")) @@ -25081,9 +25429,9 @@ DESC must be a `package-desc' object. "List of the names of currently activated packages.") (defvar package--activated nil "Non-nil if `package-activate-all' has been run.") -(defun package-activate-all nil +(autoload 'package-activate-all "package-activate" "Activate all installed packages. -The variable `package-load-list' controls which packages to load." (setq package--activated t) (let* ((elc (concat package-quickstart-file "c")) (qs (if (file-readable-p elc) elc (if (file-readable-p package-quickstart-file) package-quickstart-file)))) (or (and qs (not (bound-and-true-p package-activated-list)) (with-demoted-errors "Error during quickstart: %S" (let ((load-source-file-function nil)) (unless (boundp 'package-activated-list) (setq package-activated-list nil)) (load qs nil [...] +The variable `package-load-list' controls which packages to load.") (autoload 'package-installed-p "package-activate" "Return non-nil if PACKAGE, of MIN-VERSION or newer, is installed. If PACKAGE is a symbol, it is the package name and MIN-VERSION @@ -25396,10 +25744,9 @@ Emacs Lisp manual for more information and examples. (autoload 'pcase--make-docstring "pcase") (autoload 'pcase-exhaustive "pcase" "The exhaustive version of `pcase' (which see). -If EXP fails to match any of the patterns in CASES, an error is -signaled. +If EXP fails to match any of the patterns in CASES, signal an error. -In contrast, `pcase' will return nil if there is no match, but +In contrast, `pcase' will return nil if there is no match, but will not signal an error. (fn EXP &rest CASES)" nil t) @@ -28077,8 +28424,6 @@ evaluate the variable `rectangle-mark-mode'. The mode's hook is called both when the mode is enabled and when it is disabled. -\\{rectangle-mark-mode-map} - (fn &optional ARG)" t) (register-definition-prefixes "rect" '("apply-on-rectangle" "clear-rectangle-line" "delete-" "extract-rectangle-" "killed-rectangle" "ope" "rectangle-" "spaces-string" "string-rectangle-")) @@ -29905,6 +30250,8 @@ ITEMS list is also populated by the resolved handler, but can be explicitly overridden. (fn &optional ITEMS)" t) +(autoload 'send-to--resolve-handler "send-to" +"Return first supported handler from `send-to-handlers'.") (register-definition-prefixes "send-to" '("send-to-")) @@ -32326,6 +32673,10 @@ as the new values of the bound variables in the recursive invocation. This construct can only be used with lexical binding. (fn NAME BINDINGS &rest BODY)" nil t) +(autoload 'work-buffer--release "subr-x" +"Release work BUFFER. + +(fn BUFFER)") (autoload 'with-work-buffer "subr-x" "Create a work buffer, and evaluate BODY there like `progn'. Like `with-temp-buffer', but reuse an already created temporary @@ -33565,6 +33916,7 @@ if it matches the first line of the file, The command `tex-file' runs TeX on the file specified by `tex-main-file' if the variable is non-nil.") (custom-autoload 'tex-main-file "tex-mode" t) +(put 'tex-main-file 'safe-local-variable (lambda (x) (or (stringp x) (null x)))) (defvar tex-offer-save t "If non-nil, ask about saving modified buffers before \\[tex-file] is run.") (custom-autoload 'tex-offer-save "tex-mode" t) @@ -34358,7 +34710,7 @@ If DATE is malformed, return a time value of zero. (fn DATE)") (autoload 'format-seconds "time-date" -"Use format control STRING to format the number SECONDS. +"Use format control STRING to format the time value SECONDS. The valid format specifiers are: %y is the number of (365-day) years. %d is the number of days. @@ -34560,7 +34912,7 @@ relative only to the time worked today, and not to past time. ;;; Generated autoloads from emacs-lisp/timeout.el -(push '(timeout 2 1) package--builtin-versions) +(push '(timeout 2 1 6) package--builtin-versions) (autoload 'timeout-debounce "timeout" "Debounce FUNC by making it run DELAY seconds after it is called. @@ -35192,13 +35544,13 @@ Interactively, with a prefix argument, prompt for a different method." t) ;;; Generated autoloads from net/trampver.el -(push '(tramp 2 8 2 -1) package--builtin-versions) +(push '(tramp 2 8 2) package--builtin-versions) (register-definition-prefixes "trampver" '("tramp-")) ;;; Generated autoloads from transient.el -(push '(transient 0 13 0) package--builtin-versions) +(push '(transient 0 13 3) package--builtin-versions) (autoload 'transient-insert-suffix "transient" "Insert a SUFFIX into PREFIX before LOC. PREFIX is a prefix command, a symbol. @@ -36663,6 +37015,11 @@ If FILE-NAME is non-nil, save the result to FILE-NAME. (register-definition-prefixes "uudecode" '("uudecode-")) +;;; Generated autoloads from emacs-lisp/uuid.el + +(register-definition-prefixes "uuid" '("uuid-")) + + ;;; Generated autoloads from vc/vc.el (defvar vc-checkout-hook nil @@ -37899,7 +38256,7 @@ step during initialization." t) ;;; Generated autoloads from progmodes/verilog-mode.el -(push '(verilog-mode 2026 1 18 88738971) package--builtin-versions) +(push '(verilog-mode 2026 4 14 10117132) package--builtin-versions) (autoload 'verilog-mode "verilog-mode" "Major mode for editing Verilog code. \\<verilog-mode-map> @@ -40211,8 +40568,10 @@ selected window. (autoload 'merge-frames "window-x" "Merge the main window of FRAME2 into FRAME1. Split the main window of FRAME1 and make the new window display the main -window of FRAME2. Both FRAME1 and FRAME2 must be live frames. If -VERTICAL is non-nil, make the new window below the old main window of +window of FRAME2. Both FRAME1 and FRAME2 must be live frames. FRAME1 +defaults to the selected frame and FRAME2 to the frame that follows FRAME1 +in the frame list. +If VERTICAL is non-nil, make the new window below the old main window of FRAME1. Otherwise, make the new window on the right of FRAME1's main window. Interactively, VERTICAL is the prefix argument, FRAME1 is the selected frame and FRAME2 is the frame following FRAME1 in the frame diff --git a/lisp/mail/emacsbug.el b/lisp/mail/emacsbug.el index d69fd106e5c..e43e982c04b 100644 --- a/lisp/mail/emacsbug.el +++ b/lisp/mail/emacsbug.el @@ -127,7 +127,9 @@ This requires either the macOS \"open\" command, or the freedesktop (goto-char (point-min)) (if (re-search-forward (format "^%s\\s-*:\\s-+\\(.*\\)$" s) nil t) - (setq os (concat os " " (match-string 1))))))) + (setq os (concat os + (if os " ") + (match-string 1))))))) os)) ((eq system-type 'windows-nt) (or report-emacs-bug--os-description diff --git a/lisp/mail/rmail.el b/lisp/mail/rmail.el index d51a90d1e63..f7770b047b9 100644 --- a/lisp/mail/rmail.el +++ b/lisp/mail/rmail.el @@ -903,6 +903,9 @@ If `rmail-display-summary' is non-nil, make a summary for this RMAIL file." ;; The mail file is either unchanged or not visited. Visit it. (switch-to-buffer (let ((enable-local-variables nil) + ;; Avoid entering 'rmail-mode' via 'auto-mode-alist'; + ;; 'rmail' does its own setup after visiting the file. + (auto-mode-alist nil) ;; Force no-conversion by default, since that's what ;; pre-mbox Rmail did with BABYL files (via ;; auto-coding-regexp-alist). @@ -1259,8 +1262,6 @@ The buffer is expected to be narrowed to just the header of the message." (defun rmail-mode-kill-summary () (if rmail-summary-buffer (kill-buffer rmail-summary-buffer))) -(defvar rmail-enable-multibyte) ; dynamically bound - ;;;###autoload (defun rmail-mode () "Rmail Mode is used by \\<rmail-mode-map>\\[rmail] for editing Rmail files. @@ -1317,11 +1318,9 @@ Instead, these commands are available: (rmail-mode-2) (when (and finding-rmail-file (null coding-system-for-read)) - (let ((rmail-enable-multibyte t)) - (rmail-require-mime-maybe) - (rmail-convert-file-maybe) - (goto-char (point-max)) - (set-buffer-multibyte t))) + (rmail-require-mime-maybe) + (rmail-convert-file-maybe) + (goto-char (point-max))) (rmail-set-message-counters) (rmail-show-message rmail-total-messages) (when finding-rmail-file @@ -1504,10 +1503,8 @@ If so restore the actual mbox message collection." (defun rmail-revert (arg noconfirm) (set-buffer rmail-buffer) (let* ((revert-buffer-function (default-value 'revert-buffer-function)) - (rmail-enable-multibyte enable-multibyte-characters) - ;; See similar code in `rmail'. - ;; FIXME needs updating? - (coding-system-for-read (and rmail-enable-multibyte 'raw-text)) + (coding-system-for-read + (or coding-system-for-read 'no-conversion)) (before-revert-hook 'rmail-swap-buffers-maybe)) ;; Call our caller again, but this time it does the default thing. (when (revert-buffer arg noconfirm) @@ -1515,13 +1512,7 @@ If so restore the actual mbox message collection." ;; reparse the messages. (set-buffer rmail-buffer) (rmail-mode-2) - ;; Convert all or part to Babyl file if possible. (rmail-convert-file-maybe) - ;; We have read the file as raw-text, so the buffer is set to - ;; unibyte. Make it multibyte if necessary. - (if (and rmail-enable-multibyte - (not enable-multibyte-characters)) - (set-buffer-multibyte t)) (goto-char (point-max)) (rmail-set-message-counters) (rmail-show-message rmail-total-messages) @@ -1728,7 +1719,6 @@ not be a new one). It returns non-nil if it got any new messages." (or (eq buffer-undo-list t) (setq buffer-undo-list nil)) (let ((all-files (if file-name (list file-name) rmail-inbox-list)) - (rmail-enable-multibyte t) found) (unwind-protect (progn diff --git a/lisp/man.el b/lisp/man.el index 3b59efa0a44..c49c4da8f04 100644 --- a/lisp/man.el +++ b/lisp/man.el @@ -88,6 +88,7 @@ ;;; Code: (require 'ansi-color) +(require 'ansi-osc) (require 'cl-lib) (defgroup man nil @@ -155,6 +156,9 @@ set `Man-ansi-color-basic-faces-vector'.") (make-obsolete-variable 'Man-ansi-color-map 'Man-ansi-color-basic-faces-vector "28.1") +(defvar Man-ansi-osc-handlers '(("8" . ansi-osc-hyperlink-handler)) + "The value used here for `ansi-osc-handlers'.") + (defcustom Man-notify-method 'friendly "Selects the behavior when manpage is ready. This variable may have one of the following values, where (sf) means @@ -1377,6 +1381,8 @@ Same for the ANSI bold and normal escape sequences." (let ((ansi-color-apply-face-function #'ansi-color-apply-text-property-face) (ansi-color-basic-faces-vector Man-ansi-color-basic-faces-vector)) (ansi-color-apply-on-region (point-min) (point-max))) + (let ((ansi-osc-handlers Man-ansi-osc-handlers)) + (ansi-osc-apply-on-region (point-min) (point-max))) ;; Other highlighting. (let ((buffer-undo-list t)) (if (< (buffer-size) (position-bytes (point-max))) diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 00ce306ba67..74c7cd9baa2 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -2769,22 +2769,24 @@ is always true." (defvar completions--background-update-timer nil) -(defun completions--background-update (force-eager-update) +(defun completions--background-update (force-eager-update buffer) "Try to update *Completions* without blocking input. This function uses `while-no-input' and sets `non-essential' to t so that the update is less likely to interfere with user typing." (setq completions--background-update-timer nil) - (when (while-no-input - (let ((non-essential t)) - (redisplay) - (cond - (completion-in-region-mode (completion-help-at-point t)) - ((completions--should-show-p - (completion--field-metadata (minibuffer-prompt-end)) - force-eager-update) - (minibuffer-completion-help)))) - nil) + (when (and + (eq buffer (current-buffer)) + (while-no-input + (let ((non-essential t)) + (redisplay) + (cond + (completion-in-region-mode (completion-help-at-point t)) + ((completions--should-show-p + (completion--field-metadata (minibuffer-prompt-end)) + force-eager-update) + (minibuffer-completion-help)))) + nil)) ;; If we got interrupted, try again the next time the user is idle. (completions--start-background-update force-eager-update))) @@ -2802,7 +2804,8 @@ If FORCE-EAGER-UPDATE is non-nil, we only check eager-display." (unless completions--background-update-timer (setq completions--background-update-timer (run-with-idle-timer - 0 nil #'completions--background-update force-eager-update)))) + 0 nil #'completions--background-update + force-eager-update (current-buffer))))) (defun completions--start-eager-display () "Maybe display the *Completions* buffer when the user is next idle. @@ -4631,6 +4634,11 @@ filter out additional entries (because TABLE might not obey PRED)." ;; Text that goes between the new submatches and the ;; completion substring. (between nil)) + ;; SUBPAT was computed with point=(length substring); remove + ;; the trailing `point' since that's not the real location of + ;; point (bug#80914). + (cl-assert (eq (car (last subpat)) 'point)) + (setq subpat (butlast subpat)) ;; Eliminate submatches that don't end with the separator. (dolist (submatch (prog1 suball (setq suball ()))) (when (eq sep (aref submatch (1- (length submatch)))) @@ -5088,12 +5096,14 @@ usual. Returns (ALL PAT PREFIX SUFFIX)." ;; to /usr/share/a/e just because we mistyped "ae" for "ar", ;; so we probably don't want initials to touch anything that ;; looks like /usr/share/foo. As a heuristic, we just check that - ;; the text before the boundary char is at most 1 char. - ;; This allows both ~/eee and /eee and not much more. + ;; the previous completion field is empty. + ;; This allows ~/eee and /eee and /usr//eee and not much more. ;; FIXME: It sadly also disallows the use of ~/eee when that's ;; embedded within something else (e.g. "(~/eee" in Info node ;; completion or "ancestor:/eee" in bzr-revision completion). - (when (< (car bounds) 3) + (when (let ((str-without-last-field (substring str 0 (1- (car bounds))))) + (= (car (completion-boundaries str-without-last-field table pred "")) + (length str-without-last-field))) (let ((sep (substring str (1- (car bounds)) (car bounds)))) ;; FIXME: the above string-match checks the whole string, whereas ;; we end up only caring about the after-boundary part. diff --git a/lisp/mouse.el b/lisp/mouse.el index 1ff79e3833e..dea7b190a1f 100644 --- a/lisp/mouse.el +++ b/lisp/mouse.el @@ -1864,18 +1864,26 @@ click is the local or global binding of that event. - Otherwise, the mouse-1 event is translated into a mouse-2 event at the same position." - (let ((action - (and (or (not (consp pos)) - mouse-1-click-in-non-selected-windows - (eq (selected-window) (posn-window pos))) - (or (mouse-posn-property pos 'follow-link) - (let ((area (posn-area pos))) - (when area - (key-binding (vector area 'follow-link) nil t pos))) - (key-binding [follow-link] nil t pos))))) + (let* ((area (and (consp pos) (posn-area pos))) + (action + (and (or (not (consp pos)) + mouse-1-click-in-non-selected-windows + (eq (selected-window) (posn-window pos))) + (or (mouse-posn-property pos 'follow-link) + (when area + (key-binding (vector area 'follow-link) nil t pos)) + (key-binding [follow-link] nil t pos))))) (cond ((eq action 'mouse-face) - (and (mouse-posn-property pos 'mouse-face) t)) + ;; Inhibit follow-link when `mouse-1' is clicked on the tab-bar to + ;; prevent misdirected clicks in `dired-mode'. This does not prevent + ;; remapping `mouse-1' to `mouse-2' on the tab-bar. See bug#49247 + ;; bug#81036. + ;; FIXME: The tab-bar is not associated with a buffer so a better fix + ;; might be not to honor the current buffer's keymap when considering + ;; tab-bar mouse clicks, + (and (not (eq area 'tab-bar)) + (mouse-posn-property pos 'mouse-face) t)) ((functionp action) ;; FIXME: This seems questionable if the click is not in a buffer. ;; Should we instead decide that `action' takes a `posn'? @@ -2380,8 +2388,8 @@ if `mouse-drag-copy-region' is non-nil)." (exchange-point-and-mark) (mouse-set-region-1) (when (and mouse-drag-copy-region - (or (not (eq mouse-drag-copy-region 'non-empty)) - (not (/= (mark t) (point))))) + (not (and (eq mouse-drag-copy-region 'non-empty) + (= (mark t) (point))))) (kill-new (filter-buffer-substring (mark t) (point)))) (setq mouse-save-then-kill-posn click-pt))))) diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el index b75c4f119a0..6700211cda3 100644 --- a/lisp/net/browse-url.el +++ b/lisp/net/browse-url.el @@ -988,8 +988,8 @@ opposite of the browser kind of `browse-url-browser-function'." (default (if (eq (browse-url--browser-kind browse-url-browser-function (car url-arg)) 'internal) - 'external - 'internal)) + "external" + "internal")) (k (intern (completing-read (format-prompt "Browser kind" default) '(internal external) diff --git a/lisp/net/eww.el b/lisp/net/eww.el index 542afa41180..631440706e9 100644 --- a/lisp/net/eww.el +++ b/lisp/net/eww.el @@ -686,6 +686,12 @@ The renaming scheme is performed in accordance with (when rename-string (rename-buffer rename-string t)))) +(defun eww-parse-target (target) + "Separate TARGET from its optional text fragments." + (when (stringp target) + (string-match "\\([^:]*\\)\\(:~:\\)?\\(.*\\)" target) + (cons (match-string 1 target) (match-string 3 target)))) + (defun eww-render (status url &optional point buffer encode) (let* ((headers (eww-parse-headers)) (content-type @@ -699,7 +705,8 @@ The renaming scheme is performed in accordance with (eww-detect-charset (eww-html-p (car content-type))) "utf-8")))) (data-buffer (current-buffer)) - (shr-target-id (url-target (url-generic-parse-url url))) + (full-target (eww-parse-target (url-target (url-generic-parse-url url)))) + (shr-target-id (car full-target)) last-coding-system-used) (let ((redirect (plist-get status :redirect))) (when redirect @@ -3056,28 +3063,57 @@ Otherwise, the restored buffer will contain a prompt to do so by using (put 'eww-bookmark-jump 'bookmark-handler-type "EWW") -(provide 'eww) - ;;; Alternate links (RSS and Atom feeds, etc.) (defun eww--alternate-urls (dom &optional base) - "Return an alist of alternate links in DOM. - -Each element is a list of the form (URL TYPE TITLE) where URL is -the href attribute of the link expanded relative to BASE, TYPE is -its type attribute, and TITLE is its title attribute. If any of -these attributes is absent, the corresponding element is nil." - (let ((alternates - (seq-filter - (lambda (attrs) (string= (alist-get 'rel attrs) - "alternate")) - (mapcar #'dom-attributes (dom-by-tag dom 'link))))) - (mapcar (lambda (alternate) - (list (url-expand-file-name (alist-get 'href alternate) - base) - (alist-get 'type alternate) - (alist-get 'title alternate))) - alternates))) + "Return a list of alternate links in DOM. + +Each element is a string URL, which is the href attribute of the link, +expanded relative to BASE. Each URL string has text properties \\+`type' +which is the link's type attribute, and \\+`title', its title attribute." + (seq-keep + (lambda (link) + (let ((attrs (dom-attributes link))) + (when (equal (alist-get 'rel attrs) "alternate") + (propertize + (url-expand-file-name (alist-get 'href attrs) base) + 'type (alist-get 'type attrs) + 'title (or (alist-get 'title attrs) ""))))) + (dom-by-tag dom 'link))) + +(defun eww--alternate-urls-affixation (urls) + (let ((url-max-width + (seq-max (cons 0 (mapcar #'string-pixel-width urls)))) + (title-max-width + (seq-max + (cons 0 (mapcar + (lambda (url) + (string-pixel-width (get-text-property 0 'title url))) + urls)))) + (sep-width (string-pixel-width " "))) + (mapcar + (lambda (url) + (let ((title (get-text-property 0 'title url))) + (list + url "" + (propertize + (concat + (propertize + " " 'display + `( space :width + (,(+ sep-width + (- url-max-width (string-pixel-width url)))))) + title + (when-let* ((type (get-text-property 0 'type url))) + (concat + (propertize + " " 'display + `( space :width + (,(+ sep-width + (- title-max-width (string-pixel-width title)))))) + "[" type "]"))) + 'face 'completions-annotations)))) + urls))) (defun eww-read-alternate-url () "Get the URL of an alternate link of this page. @@ -3085,46 +3121,17 @@ these attributes is absent, the corresponding element is nil." If there is just one alternate link, return its URL. If there are multiple alternate links, prompt for one in the minibuffer with completion. If there are none, return nil." - (when-let* ((alternates (eww--alternate-urls - (plist-get eww-data :dom) - (plist-get eww-data :url)))) - (let ((url-max-width - (seq-max (mapcar #'string-pixel-width - (mapcar #'car alternates)))) - (title-max-width - (seq-max (mapcar #'string-pixel-width - (mapcar #'caddr alternates)))) - (sep-width (string-pixel-width " "))) - (if (cdr alternates) - (completing-read - "Alternate URL: " - (completion-table-with-metadata - alternates - `((annotation-function - . ,(lambda (feed) - (let* ((attrs (alist-get feed - alternates - nil - nil - #'string=)) - (type (car attrs)) - (title (cadr attrs))) - (concat - (propertize " " 'display - `(space :align-to - (,(+ sep-width - url-max-width)))) - title - (when type - (concat - (propertize " " 'display - `(space :align-to - (,(+ (* 2 sep-width) - url-max-width - title-max-width)))) - "[" type "]")))))))) - nil t) - (caar alternates))))) + (when-let* ((alts (eww--alternate-urls (plist-get eww-data :dom) + (plist-get eww-data :url)))) + (if (cdr alts) + ;; Multiple alternate links, prompt the user to select one. + (completing-read + "Alternate URL: " + (completion-table-with-metadata + alts `((affixation-function . eww--alternate-urls-affixation))) + nil t) + ;; Just one alternate link, return it without prompting. + (caar alts)))) (defun eww-copy-alternate-url () "Copy the alternate URL of the current page into the kill ring. @@ -3140,4 +3147,5 @@ version or an RSS feed." (message "Copied %s to kill ring" url)) (user-error "No alternate links found on this page!"))) +(provide 'eww) ;;; eww.el ends here diff --git a/lisp/net/gnutls.el b/lisp/net/gnutls.el index dbb7d19e9e6..aa0eb7e08de 100644 --- a/lisp/net/gnutls.el +++ b/lisp/net/gnutls.el @@ -255,7 +255,7 @@ For the meaning of the rest of the parameters, see `gnutls-boot-parameters'." (setq ret (gnutls-boot process type (append (list :complete-negotiation t) params))) - "boot: %s" params) + "boot: %S" params) (when (gnutls-errorp ret) ;; This is an error from the underlying C code. diff --git a/lisp/net/goto-addr.el b/lisp/net/goto-addr.el index 09166fe1d5b..fccfa4b7438 100644 --- a/lisp/net/goto-addr.el +++ b/lisp/net/goto-addr.el @@ -191,6 +191,7 @@ and `goto-address-fontify-p'." (overlay-put this-overlay 'keymap goto-address-highlight-keymap) (overlay-put this-overlay 'button this-overlay) + (overlay-put this-overlay 'action #'goto-address--button-action) (overlay-put this-overlay 'category 'goto-address) (overlay-put this-overlay 'goto-address t)))) (goto-char (or start (point-min))) @@ -250,6 +251,12 @@ using `browse-url-secondary-browser-function' instead." (browse-url-button-open-url url) (error "No e-mail address or URL found")))))) +(defun goto-address--button-action (button) + "Open the URL represented by BUTTON." + (save-excursion + (goto-char (overlay-start button)) + (goto-address-at-point))) + (defun goto-address-find-address-at-point () "Find e-mail address around or before point. Then search backwards to beginning of line for the start of an e-mail diff --git a/lisp/net/newst-backend.el b/lisp/net/newst-backend.el index 58bbb1b7fcb..e680224f069 100644 --- a/lisp/net/newst-backend.el +++ b/lisp/net/newst-backend.el @@ -1598,7 +1598,7 @@ is present, this function defaults to universal time." RFC822-STRING should use RFC 822 (or later) format. Examples: Sat, 07 September 2002 00:00:01 +0100 -Sat, 07 September 2002 00:00:01 MET +Sat, 07 September 2002 00:00:01 MDT Sat, 07 Sep 2002 00:00:01 GMT 07 Sep 2002 00:00:01 GMT 07 Sep 2002" diff --git a/lisp/net/newst-treeview.el b/lisp/net/newst-treeview.el index 8b5f8a8528f..dd7659d5bc7 100644 --- a/lisp/net/newst-treeview.el +++ b/lisp/net/newst-treeview.el @@ -1191,6 +1191,15 @@ Arguments are ignored." (if newsticker-automatically-mark-visited-items-as-old (newsticker-treeview-mark-item-old)))))) +(defun newsticker-treeview-copy-url () + "Copy the url for the current item." + (interactive) + (let ((url (url-encode-url + (newsticker--link + (newsticker--treeview-get-selected-item))))) + (kill-new url) + (message "Copied %s" url))) + (defun newsticker--treeview-buffer-init () "Initialize all treeview buffers." (setq newsticker--treeview-buffers nil) @@ -2040,6 +2049,7 @@ Return t if groups have changed, nil otherwise." "s" #'newsticker-treeview-save "u" #'newsticker-treeview-update "v" #'newsticker-treeview-browse-url + "w" #'newsticker-treeview-copy-url ;;"C-j" #'newsticker-treeview-scroll-item ;;"RET" #'newsticker-treeview-scroll-item "M-m" #'newsticker-group-move-feed diff --git a/lisp/net/tramp-archive.el b/lisp/net/tramp-archive.el index e970fd1cd56..2c7a65b375f 100644 --- a/lisp/net/tramp-archive.el +++ b/lisp/net/tramp-archive.el @@ -710,11 +710,12 @@ offered." (defun tramp-archive-handle-insert-file-contents (filename &optional visit beg end replace) "Like `insert-file-contents' for file archives." + (setq filename (expand-file-name filename)) (let ((result (insert-file-contents (tramp-archive-gvfs-file-name filename) visit beg end replace))) (when visit (setq buffer-file-name filename)) - (cons (expand-file-name filename) (cdr result)))) + (cons filename (cdr result)))) (defun tramp-archive-handle-load (file &optional noerror nomessage nosuffix must-suffix) diff --git a/lisp/net/tramp-cmds.el b/lisp/net/tramp-cmds.el index 1fc77f0e80d..e6ab0630d7a 100644 --- a/lisp/net/tramp-cmds.el +++ b/lisp/net/tramp-cmds.el @@ -794,9 +794,8 @@ This is needed if there are compatibility problems." (interactive) ;; We expect just one Tramp package is installed. (when-let* - ((dir (tramp-compat-funcall - 'package-desc-dir - (car (alist-get 'tramp (bound-and-true-p package-alist)))))) + ((dir (tramp-compat-funcall 'package-desc-dir + (car (alist-get 'tramp (bound-and-true-p package-alist)))))) (dolist (elc (directory-files dir 'full (rx ".elc" eos))) (delete-file elc)) (with-current-buffer (get-buffer-create byte-compile-log-buffer) diff --git a/lisp/net/tramp-compat.el b/lisp/net/tramp-compat.el index 3f947ef1b2c..cd6cfdfe949 100644 --- a/lisp/net/tramp-compat.el +++ b/lisp/net/tramp-compat.el @@ -103,7 +103,7 @@ Add the extension of F, if existing." dir-flag (file-name-extension f t))) (defalias 'tramp-compat-error-type-p - (if (fboundp 'error-type-p) ;Emacs-31 + (if (fboundp 'error-type-p) ; Emacs-31 #'error-type-p (lambda (symbol) (get symbol 'error-conditions)))) @@ -264,10 +264,20 @@ value is the default binding of the variable." ;; kept, for example when the HANDLER propagates the error with ;; `(signal (car err) (cdr err)'. ;; -;; * Starting with Emacs 31.1, use `(signal err)' instead of `(signal -;; (car err) (cdr err)'. -;; ;; * Starting with Emacs 30.1, use '(_ VALUEFORM)' instead of ;; '(VALUEFORM)' in 'if-let*/when-let*/and-let*'. +;; +;; * Starting with Emacs 30, use `static-if'. Starting with Emacs 31, +;; use `static-when' and `static-unless'. +;; +;; * Starting with Emacs 31.1, use `(signal err)' instead of `(signal +;; (car err) (cdr err)'. Use also the functions `error-type-p', `error-type', +;; `error-has-type-p', and `error-slot-value'. +;; +;; * Starting with Emacs 31.1, use `set-local' and `setopt-local'. +;; +;; * Starting with Emacs 31.1, use `plusp', `minusp', `oddp' and `evenp'. +;; +;; * Starting with Emacs 31.1, use `hash-table-contains-p'. ;;; tramp-compat.el ends here diff --git a/lisp/net/tramp-container.el b/lisp/net/tramp-container.el index fec2e16a624..dabc03f990b 100644 --- a/lisp/net/tramp-container.el +++ b/lisp/net/tramp-container.el @@ -290,14 +290,14 @@ see its function help for a description of the format." (tramp-skeleton-completion-function method (when-let* ((raw-list (shell-command-to-string - (concat program " ps --format '{{.ID}}\t{{.Names}}'"))) + (concat program " ps --format '{{.ID}}<>{{.Names}}'"))) (lines (split-string raw-list "\n" 'omit)) (names (tramp-compat-seq-keep (lambda (line) (when (string-match (rx bol (group (1+ nonl)) - "\t" (? (group (1+ nonl))) eol) + "<>" (? (group (1+ nonl))) eol) line) (or (match-string 2 line) (match-string 1 line)))) lines))) diff --git a/lisp/net/tramp-fuse.el b/lisp/net/tramp-fuse.el index f7abddab1a1..8cf2b939f4f 100644 --- a/lisp/net/tramp-fuse.el +++ b/lisp/net/tramp-fuse.el @@ -108,11 +108,16 @@ (defun tramp-fuse-handle-insert-directory (filename switches &optional wildcard full-directory-p) "Like `insert-directory' for Tramp files." - (insert-directory - (tramp-fuse-local-file-name filename) switches wildcard full-directory-p) - (goto-char (point-min)) - (while (search-forward (tramp-fuse-local-file-name filename) nil 'noerror) - (replace-match filename))) + (with-tramp-progress-reporter + (tramp-dissect-file-name filename) + 0 (format "Opening directory %s" filename) + (insert-directory + (tramp-fuse-local-file-name filename) + switches wildcard full-directory-p) + (goto-char (point-min)) + (while + (search-forward (tramp-fuse-local-file-name filename) nil 'noerror) + (replace-match filename)))) (defun tramp-fuse-handle-make-directory (dir &optional parents) "Like `make-directory' for Tramp files." diff --git a/lisp/net/tramp-message.el b/lisp/net/tramp-message.el index 37628e2f001..7ae7408b745 100644 --- a/lisp/net/tramp-message.el +++ b/lisp/net/tramp-message.el @@ -211,6 +211,13 @@ They are completed by `M-x TAB' only in Tramp debug buffers." (defvar tramp-trace-functions nil "A list of non-Tramp functions to be traced with `tramp-verbose' > 10.") +(defun tramp-trace-add-package (package) + "Add all functions of PACKAGE to `tramp-trace-functions'." + (when (and (symbolp package) (require package nil 'noerror)) + (dolist (elt (apropos-internal + (rx bos (literal (symbol-name package))) #'functionp)) + (add-to-list 'tramp-trace-functions elt)))) + (defun tramp-debug-message (vec fmt-string &rest arguments) "Append message to debug buffer of VEC. Message is formatted with FMT-STRING as control string and the remaining diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index f939635cfb5..f567a221342 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -2775,174 +2775,183 @@ The method used must be an out-of-band method." (unless wildcard (access-file filename "Reading directory")) (with-parsed-tramp-file-name (expand-file-name filename) nil - (let ((dired (tramp-get-ls-command-with v "--dired"))) - (when (stringp switches) - (setq switches (split-string switches))) - ;; Newer coreutils versions of ls (9.5 and up) imply long format - ;; output when "--dired" is given. Suppress this implicit rule. - (when dired - (let ((tem switches) - case-fold-search) - (catch 'long - (while tem - (when (and (not (string-match-p "--" (car tem))) - (string-match-p "l" (car tem))) - (throw 'long nil)) - (setq tem (cdr tem))) - (setq dired nil)))) - (setq switches - (append switches (split-string (tramp-sh--quoting-style-options v)) - (when dired `(,dired)))) - (unless dired - (setq switches (seq-difference switches '("-N" "--dired"))))) - (when wildcard - (setq wildcard (tramp-run-real-handler - #'file-name-nondirectory (list localname))) - (setq localname (tramp-run-real-handler - #'file-name-directory (list localname)))) - (unless (or full-directory-p (member "-d" switches)) - (setq switches (append switches '("-d")))) - (setq switches (seq-uniq switches) - switches (mapconcat #'tramp-shell-quote-argument switches " ")) - (when wildcard - (setq switches (concat switches " " wildcard))) - (tramp-message - v 4 "Inserting directory `ls %s %s', wildcard %s, fulldir %s" - switches filename (if wildcard "yes" "no") - (if full-directory-p "yes" "no")) - ;; If `full-directory-p', we just say `ls -l FILENAME'. Else we - ;; chdir to the parent directory, then say `ls -ld BASENAME'. - (if full-directory-p + (with-tramp-progress-reporter + v 0 (format "Opening directory %s" filename) + (let ((dired (tramp-get-ls-command-with v "--dired"))) + (when (stringp switches) + (setq switches (split-string switches))) + ;; Newer coreutils versions of ls (9.5 and up) imply long + ;; format output when "--dired" is given. Suppress this + ;; implicit rule. + (when dired + (let ((tem switches) + case-fold-search) + (catch 'long + (while tem + (when (and (not (string-match-p "--" (car tem))) + (string-match-p "l" (car tem))) + (throw 'long nil)) + (setq tem (cdr tem))) + (setq dired nil)))) + (setq switches + (append switches + (split-string (tramp-sh--quoting-style-options v)) + (when dired `(,dired)))) + (unless dired + (setq switches (seq-difference switches '("-N" "--dired"))))) + (when wildcard + (setq wildcard (tramp-run-real-handler + #'file-name-nondirectory (list localname))) + (setq localname (tramp-run-real-handler + #'file-name-directory (list localname)))) + (unless (or full-directory-p (member "-d" switches)) + (setq switches (append switches '("-d")))) + (setq switches (seq-uniq switches) + switches (mapconcat #'tramp-shell-quote-argument switches " ")) + (when wildcard + (setq switches (concat switches " " wildcard))) + (tramp-message + v 4 "Inserting directory `ls %s %s', wildcard %s, fulldir %s" + switches filename (if wildcard "yes" "no") + (if full-directory-p "yes" "no")) + ;; If `full-directory-p', we just say `ls -l FILENAME'. Else + ;; we chdir to the parent directory, then say `ls -ld + ;; BASENAME'. + (if full-directory-p + (tramp-send-command + v (format "%s %s %s 2>%s" + (tramp-get-ls-command v) + switches + (if wildcard + localname + (tramp-shell-quote-argument (concat localname "."))) + (tramp-get-remote-null-device v))) + (tramp-barf-unless-okay + v (format "cd %s" (tramp-shell-quote-argument + (tramp-run-real-handler + #'file-name-directory (list localname)))) + "Couldn't `cd %s'" + (tramp-shell-quote-argument + (tramp-run-real-handler #'file-name-directory (list localname)))) (tramp-send-command v (format "%s %s %s 2>%s" (tramp-get-ls-command v) switches - (if wildcard - localname - (tramp-shell-quote-argument (concat localname "."))) - (tramp-get-remote-null-device v))) - (tramp-barf-unless-okay - v (format "cd %s" (tramp-shell-quote-argument - (tramp-run-real-handler - #'file-name-directory (list localname)))) - "Couldn't `cd %s'" - (tramp-shell-quote-argument - (tramp-run-real-handler #'file-name-directory (list localname)))) - (tramp-send-command - v (format "%s %s %s 2>%s" - (tramp-get-ls-command v) - switches - (if (or wildcard - (tramp-string-empty-or-nil-p - (tramp-run-real-handler - #'file-name-nondirectory (list localname)))) - "" - (tramp-shell-quote-argument - (tramp-run-real-handler - #'file-name-nondirectory (list localname)))) - (tramp-get-remote-null-device v)))) - - (let ((beg-marker (copy-marker (point) nil)) - (end-marker (copy-marker (point) t)) - (emc enable-multibyte-characters)) - ;; We cannot use `insert-buffer-substring' because the Tramp - ;; buffer changes its contents before insertion due to calling - ;; `expand-file-name' and alike. - (insert (tramp-get-buffer-string (tramp-get-buffer v))) - - ;; We must enable unibyte strings, because the "--dired" - ;; output counts in bytes. - (set-buffer-multibyte nil) - (save-restriction - (narrow-to-region beg-marker end-marker) - ;; Check for "--dired" output. - (when (search-backward-regexp - (rx bol "//DIRED//" (+ blank) (group (+ nonl)) eol) - nil 'noerror) - (let ((beg (match-beginning 1)) - (end (match-end 0))) - ;; Now read the numeric positions of file names. - (goto-char beg) - (while (< (point) end) - (let ((start (+ (point-min) (read (current-buffer)))) - (end (+ (point-min) (read (current-buffer))))) - (if (memq (char-after end) '(?\n ?\ )) - ;; End is followed by \n or by " -> ". - (put-text-property start end 'dired-filename t)))))) - ;; Remove trailing lines. - (goto-char (point-max)) - (while (search-backward-regexp (rx bol "//") nil 'noerror) - (forward-line 1) - (delete-region (match-beginning 0) (point)))) - ;; Reset multibyte if needed. - (set-buffer-multibyte emc) - - (save-restriction - (narrow-to-region beg-marker end-marker) - ;; Some busyboxes are reluctant to discard colors. - (unless (string-search - "color" (tramp-get-connection-property v "ls" "")) - (goto-char (point-min)) - (while (search-forward-regexp ansi-color-control-seq-regexp nil t) - (replace-match ""))) - - ;; Now decode what read if necessary. Stolen from `insert-directory'. - (let ((coding (or coding-system-for-read - file-name-coding-system - default-file-name-coding-system - 'undecided)) - coding-no-eol - val pos) - (when (and enable-multibyte-characters - (not (memq (coding-system-base coding) - '(raw-text no-conversion)))) - ;; If no coding system is specified or detection is - ;; requested, detect the coding. - (if (eq (coding-system-base coding) 'undecided) - (setq coding (detect-coding-region (point-min) (point) t))) - (unless (eq (coding-system-base coding) 'undecided) - (setq coding-no-eol - (coding-system-change-eol-conversion coding 'unix)) - (goto-char (point-min)) - (while (not (eobp)) - (setq pos (point) - val (get-text-property (point) 'dired-filename)) - (goto-char (next-single-property-change - (point) 'dired-filename nil (point-max))) - ;; Force no eol conversion on a file name, so that - ;; CR is preserved. - (decode-coding-region - pos (point) (if val coding-no-eol coding)) - (if val (put-text-property pos (point) 'dired-filename t)))))) - - ;; The inserted file could be from somewhere else. - (when (and (not wildcard) (not full-directory-p)) + (if (or wildcard + (tramp-string-empty-or-nil-p + (tramp-run-real-handler + #'file-name-nondirectory (list localname)))) + "" + (tramp-shell-quote-argument + (tramp-run-real-handler + #'file-name-nondirectory (list localname)))) + (tramp-get-remote-null-device v)))) + + (let ((beg-marker (copy-marker (point) nil)) + (end-marker (copy-marker (point) t)) + (emc enable-multibyte-characters)) + ;; We cannot use `insert-buffer-substring' because the Tramp + ;; buffer changes its contents before insertion due to + ;; calling `expand-file-name' and alike. + (insert (tramp-get-buffer-string (tramp-get-buffer v))) + + ;; We must enable unibyte strings, because the "--dired" + ;; output counts in bytes. + (set-buffer-multibyte nil) + (save-restriction + (narrow-to-region beg-marker end-marker) + ;; Check for "--dired" output. + (when (search-backward-regexp + (rx bol "//DIRED//" (+ blank) (group (+ nonl)) eol) + nil 'noerror) + (let ((beg (match-beginning 1)) + (end (match-end 0))) + ;; Now read the numeric positions of file names. + (goto-char beg) + (while (< (point) end) + (let ((start (+ (point-min) (read (current-buffer)))) + (end (+ (point-min) (read (current-buffer))))) + (if (memq (char-after end) '(?\n ?\ )) + ;; End is followed by \n or by " -> ". + (put-text-property start end 'dired-filename t)))))) + ;; Remove trailing lines. (goto-char (point-max)) - (when (file-symlink-p filename) - (goto-char (search-backward "->" (point-min) 'noerror))) - (search-backward - (if (directory-name-p filename) - "." - (file-name-nondirectory filename)) - (point-min) 'noerror) - (replace-match (file-relative-name filename) t)) - - ;; Try to insert the amount of free space. - (goto-char (point-min)) - ;; First find the line to put it on. - (when-let* (((search-forward-regexp - (rx bol (group (* blank) "total")) nil t)) - ;; Emacs 29.1 or later. - ((not (fboundp 'dired--insert-disk-space))) - (available (get-free-disk-space "."))) - ;; Replace "total" with "total used", to avoid confusion. - (replace-match "\\1 used in directory") - (end-of-line) - (insert " available " available))) - - (prog1 (goto-char end-marker) - (set-marker beg-marker nil) - (set-marker end-marker nil)))))) + (while (search-backward-regexp (rx bol "//") nil 'noerror) + (forward-line 1) + (delete-region (match-beginning 0) (point)))) + ;; Reset multibyte if needed. + (set-buffer-multibyte emc) + + (save-restriction + (narrow-to-region beg-marker end-marker) + ;; Some busyboxes are reluctant to discard colors. + (unless (string-search + "color" (tramp-get-connection-property v "ls" "")) + (goto-char (point-min)) + (while + (search-forward-regexp ansi-color-control-seq-regexp nil t) + (replace-match ""))) + + ;; Now decode what read if necessary. Stolen from + ;; `insert-directory'. + (let ((coding (or coding-system-for-read + file-name-coding-system + default-file-name-coding-system + 'undecided)) + coding-no-eol + val pos) + (when (and enable-multibyte-characters + (not (memq (coding-system-base coding) + '(raw-text no-conversion)))) + ;; If no coding system is specified or detection is + ;; requested, detect the coding. + (if (eq (coding-system-base coding) 'undecided) + (setq coding + (detect-coding-region (point-min) (point) t))) + (unless (eq (coding-system-base coding) 'undecided) + (setq coding-no-eol + (coding-system-change-eol-conversion coding 'unix)) + (goto-char (point-min)) + (while (not (eobp)) + (setq pos (point) + val (get-text-property (point) 'dired-filename)) + (goto-char (next-single-property-change + (point) 'dired-filename nil (point-max))) + ;; Force no eol conversion on a file name, so that + ;; CR is preserved. + (decode-coding-region + pos (point) (if val coding-no-eol coding)) + (when val + (put-text-property pos (point) 'dired-filename t)))))) + + ;; The inserted file could be from somewhere else. + (when (and (not wildcard) (not full-directory-p)) + (goto-char (point-max)) + (when (file-symlink-p filename) + (goto-char (search-backward "->" (point-min) 'noerror))) + (search-backward + (if (directory-name-p filename) + "." + (file-name-nondirectory filename)) + (point-min) 'noerror) + (replace-match (file-relative-name filename) t)) + + ;; Try to insert the amount of free space. + (goto-char (point-min)) + ;; First find the line to put it on. + (when-let* (((search-forward-regexp + (rx bol (group (* blank) "total")) nil t)) + ;; Emacs 29.1 or later. + ((not (fboundp 'dired--insert-disk-space))) + (available (get-free-disk-space "."))) + ;; Replace "total" with "total used", to avoid confusion. + (replace-match "\\1 used in directory") + (end-of-line) + (insert " available " available))) + + (prog1 (goto-char end-marker) + (set-marker beg-marker nil) + (set-marker end-marker nil))))))) ;; Canonicalization of file names. diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el index 8eec0e1bd08..6f88c7dedba 100644 --- a/lisp/net/tramp-smb.el +++ b/lisp/net/tramp-smb.el @@ -651,36 +651,35 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored." (defun tramp-smb-handle-delete-directory (directory &optional recursive trash) "Like `delete-directory' for Tramp files." (tramp-skeleton-delete-directory directory recursive trash - (when (file-exists-p directory) - (when recursive - (mapc - (lambda (file) - (if (file-directory-p file) - (delete-directory file recursive) - (delete-file file))) - ;; We do not want to delete "." and "..". - (directory-files directory 'full directory-files-no-dot-files-regexp))) - - ;; We must also flush the cache of the directory, because - ;; `file-attributes' reads the values from there. - (tramp-flush-directory-properties v localname) - (unless (tramp-smb-send-command - v (format - "%s %s" - (if (tramp-smb-get-cifs-capabilities v) - "posix_rmdir" "rmdir") - (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) directory))) + (when recursive + (mapc + (lambda (file) + (if (file-directory-p file) + (delete-directory file recursive) + (delete-file file))) + ;; We do not want to delete "." and "..". + (directory-files directory 'full directory-files-no-dot-files-regexp))) + + ;; We must also flush the cache of the directory, because + ;; `file-attributes' reads the values from there. + (tramp-flush-directory-properties v localname) + (unless (tramp-smb-send-command + v (format + "%s %s" + (if (tramp-smb-get-cifs-capabilities v) + "posix_rmdir" "rmdir") + (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) directory))) - ;; "rmdir" does not report an error. So we check ourselves. - ;; Deletion of a watched directory could be pending. - (when (and (not (tramp-directory-watched directory)) - (file-exists-p directory)) - (tramp-error v 'file-error "`%s' not removed" directory))))) + ;; "rmdir" does not report an error. So we check ourselves. + ;; Deletion of a watched directory could be pending. + (when (and (not (tramp-directory-watched directory)) + (file-exists-p directory)) + (tramp-error v 'file-error "`%s' not removed" directory)))) (defun tramp-smb-handle-delete-file (filename &optional trash) "Like `delete-file' for Tramp files." @@ -2053,11 +2052,6 @@ If ARGUMENT is non-nil, use it as argument for (let* (coding-system-for-read (process-connection-type tramp-process-connection-type) - ;; There might be some unfortunate values of - ;; `tramp-smb-connection-local-default-system-variables'. - ;(path-separator (default-value 'path-separator)) - ;(null-device (default-value 'null-device)) - ;(exec-suffixes (default-value 'exec-suffixes)) (p (apply #'tramp-start-process vec (tramp-get-connection-name vec) (tramp-get-connection-buffer vec) diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 044580bac07..eb0bc649d69 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -571,7 +571,9 @@ interpreted as a regular expression which always matches." ;; <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=38079#20>. (defcustom tramp-restricted-shell-hosts-alist (when (and (eq system-type 'windows-nt) - (not (string-match-p (rx "sh" eol) tramp-encoding-shell))) + (not (string-match-p + (rx "sh" eol) + (file-name-sans-extension tramp-encoding-shell)))) (list (rx bos (| (literal (downcase tramp-system-name)) (literal (upcase tramp-system-name))) @@ -2213,12 +2215,12 @@ If VAR is nil, then we bind `v' to the structure and `method', `user', (ignore ,@(mapcar #'car bindings)) ,@body))) -(defun tramp-progress-reporter-update (reporter &optional value suffix) +(defun tramp-progress-reporter-update (reporter &optional value update-text) "Report progress of an operation for Tramp." (let* ((parameters (cdr reporter)) (message (aref parameters 3))) (when (string-search message (or (current-message) "")) - (progress-reporter-update reporter value suffix)))) + (progress-reporter-update reporter value update-text)))) ;;;###tramp-autoload (defvar tramp-inhibit-progress-reporter nil @@ -2233,15 +2235,17 @@ without a visible progress reporter." `(if (or noninteractive inhibit-message) (progn ,@body) (tramp-message ,vec ,level "%s..." ,message) - (let ((cookie "failed") - (tm - ;; We start a pulsing progress reporter after 3 seconds. - ;; Start only when there is no other progress reporter - ;; running, and when there is a minimum level. - (when-let* ((pr (and (null tramp-inhibit-progress-reporter) - (<= ,level (min tramp-verbose 3)) - (make-progress-reporter ,message)))) - (run-at-time 3 0.1 #'tramp-progress-reporter-update pr)))) + (let* ((cookie "failed") + ;; We create a pulsing progress reporter when there is no + ;; other progress reporter running, and when there is a + ;; minimum level. + (pr (and (null tramp-inhibit-progress-reporter) + (<= ,level (min tramp-verbose 3)) + (make-progress-reporter ,message))) + ;; We start it after 3 seconds. + (tm + (when pr + (run-at-time 3 0.1 #'tramp-progress-reporter-update pr)))) (unwind-protect ;; Execute the body. (prog1 @@ -2251,7 +2255,10 @@ without a visible progress reporter." ,@body) (setq cookie "done")) ;; Stop progress reporter. - (if tm (cancel-timer tm)) + (when (and tm pr) + (cancel-timer tm) + (let (message-log-max) + (progress-reporter-done pr))) (tramp-message ,vec ,level "%s...%s" ,message cookie))))) (defmacro with-tramp-timeout (list &rest body) @@ -2447,6 +2454,8 @@ symbol checked. - `process': `default-directory' of the process buffer of the first argument of OPERATION is the remote file name to be checked. +- `tramp-file-name': the first argument of OPERATION, a + `tramp-file-name' structure, is the remote file name to be checked. If the first argument of OPERATION is nil, `default-directory' is the remote file name to be checked in case of `file' and `process'. @@ -2500,8 +2509,10 @@ Must be handled by the callers." (if (and (stringp (nth 0 args)) (file-name-absolute-p (nth 0 args))) (nth 0 args) default-directory)) + ;; STRING FILE. ((eq operation 'make-symbolic-link) (nth 1 args)) + ;; FILE DIRECTORY resp FILE1 FILE2. ((memq operation '(add-name-to-file copy-directory copy-file @@ -2512,23 +2523,27 @@ Must be handled by the callers." ((tramp-tramp-file-p (nth 0 args)) (nth 0 args)) ((file-name-absolute-p (nth 1 args)) (nth 1 args)) (t default-directory))) + ;; FILE DIRECTORY resp FILE1 FILE2. ((eq operation 'expand-file-name) (cond ((file-name-absolute-p (nth 0 args)) (nth 0 args)) ((tramp-tramp-file-p (nth 1 args)) (nth 1 args)) (t default-directory))) + ;; START END FILE. ((eq operation 'write-region) (if (file-name-absolute-p (nth 2 args)) (nth 2 args) default-directory)) + ;; BUFFER. ((memq operation '(make-auto-save-file-name set-visited-file-modtime verify-visited-file-modtime)) (buffer-file-name (if (bufferp (nth 0 args)) (nth 0 args) (current-buffer)))) + ;; COMMAND. ((or (memq operation @@ -2541,6 +2556,7 @@ Must be handled by the callers." (eq (alist-get operation tramp-file-name-for-operation-external) 'default-directory)) default-directory) + ;; PROC or BUFFER. ((or (memq operation '(file-notify-rm-watch file-notify-valid-p)) @@ -2557,16 +2573,25 @@ Must be handled by the callers." (or (get-process (nth 0 args)) (get-buffer (nth 0 args))))))) (tramp-get-default-directory buf)) "")) + ;; VEC. - ((memq operation - '(tramp-get-home-directory tramp-get-remote-gid - tramp-get-remote-groups tramp-get-remote-uid)) - (tramp-make-tramp-file-name (nth 0 args))) + ((or + (memq operation + '(tramp-get-home-directory tramp-get-remote-gid + tramp-get-remote-groups tramp-get-remote-uid)) + (eq (alist-get operation tramp-file-name-for-operation-external) + 'tramp-file-name)) + (or + (and (tramp-file-name-p (nth 0 args)) + (tramp-make-tramp-file-name (nth 0 args))) + "")) + ;; A function. ((functionp (alist-get operation tramp-file-name-for-operation-external)) (apply (alist-get operation tramp-file-name-for-operation-external) operation args)) + ;; Unknown file primitive. (t (unless (memq 'remote-file-error debug-ignored-errors) (tramp-error @@ -2601,17 +2626,17 @@ OPERATION must not be one of the magic operations listed in Info node `(elisp) Magic File Names'. FUNCTION must have the same argument list as OPERATION. BACKEND, a symbol, must be one of the Tramp backend packages like `tramp-sh' (except `tramp-ftp'). ARG-TYPE is either -`file' (the default), `default-directory', `process' or a function -symbol. It describes the type of the OPERATION argument to be checked. -See the docstring of `tramp-file-name-for-operation-external' for its -meaning." +`file' (the default), `default-directory', `process', `tramp-file-name', +or a function symbol. It describes the type of the OPERATION argument +to be checked. See the docstring of +`tramp-file-name-for-operation-external' for its meaning." (require backend) (when-let* ((fnha (intern-soft (concat (symbol-name backend) "-file-name-handler-alist"))) ((boundp fnha)) (arg-type (or arg-type 'file))) - (unless (or (memq arg-type '(file default-directory process)) + (unless (or (memq arg-type '(file default-directory process tramp-file-name)) (functionp arg-type)) (tramp-error nil 'remote-file-error "Unknown arg type: %s" arg-type)) ;; Make BACKEND aware of the new operation. @@ -2635,6 +2660,15 @@ meaning." (apply orig-fun args))) `((name . ,(concat "tramp-advice-" (symbol-name operation)))))))) +(defun tramp-external-operation-p (operation backend) + "Check, whether Tramp BACKEND supports external OPERATION. +It returns the function registered as handler, or nil." + (and-let* ((fnha + (intern-soft + (concat (symbol-name backend) "-file-name-handler-alist"))) + ((boundp fnha)) + ((alist-get operation (symbol-value fnha)))))) + (defun tramp-remove-external-operation (operation backend) "Remove OPERATION from Tramp BACKEND as handler for OPERATION. OPERATION must not be one of the magic operations listed in Info @@ -2979,24 +3013,26 @@ not in completion mode." "Like `expand-file-name' for partial Tramp files." ;; We need special handling only when a method is needed. Then we ;; check, whether DIRECTORY is "/method:" or "/[method/". - (let ((dir (or directory default-directory "/"))) - (cond - ((file-name-absolute-p filename) - ;; FILENAME could be like "~/". We must expand this. - (tramp-run-real-handler #'expand-file-name (list filename directory))) - ((and (eq tramp-syntax 'simplified) - (string-match-p (rx (regexp tramp-postfix-host-regexp) eos) dir)) - (concat dir filename)) - ((string-match-p - (rx (regexp tramp-prefix-regexp) - (* (regexp tramp-remote-file-name-spec-regexp) - (regexp tramp-postfix-hop-regexp)) - (? (regexp tramp-method-regexp) (regexp tramp-postfix-method-regexp) - (? (regexp tramp-user-regexp) (regexp tramp-postfix-user-regexp))) - eos) - dir) - (concat dir filename)) - (t (tramp-run-real-handler #'expand-file-name (list filename directory)))))) + (tramp-drop-volume-letter + (let ((dir (or directory default-directory "/"))) + (cond + ((file-name-absolute-p filename) + ;; FILENAME could be like "~/". We must expand this. + (tramp-run-real-handler #'expand-file-name (list filename directory))) + ((and (eq tramp-syntax 'simplified) + (string-match-p (rx (regexp tramp-postfix-host-regexp) eos) dir)) + (concat dir filename)) + ((string-match-p + (rx (regexp tramp-prefix-regexp) + (* (regexp tramp-remote-file-name-spec-regexp) + (regexp tramp-postfix-hop-regexp)) + (? (regexp tramp-method-regexp) (regexp tramp-postfix-method-regexp) + (? (regexp tramp-user-regexp) (regexp tramp-postfix-user-regexp))) + eos) + dir) + (concat dir filename)) + (t (tramp-run-real-handler + #'expand-file-name (list filename directory))))))) ;; This is needed in pcomplete.el. (defun tramp-completion-handle-file-directory-p (filename) @@ -3703,14 +3739,15 @@ BODY is the backend specific code." ;; 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 (directory-empty-p ,directory))) - (tramp-error - v 'file-error "Directory is not empty, not moving to trash") - (move-file-to-trash ,directory)) - ,@body) + (tramp-barf-if-file-missing v ,directory + (if (and delete-by-moving-to-trash ,trash) + ;; Move non-empty dir to trash only if recursive deletion was + ;; requested. + (if (not (or ,recursive (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) @@ -3723,9 +3760,10 @@ BODY is the backend specific code." ;; 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) + (ignore-errors + (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 @@ -4264,9 +4302,8 @@ Let-bind it when necessary.") (tramp-get-connection-property vec "~")))) (when home-dir (setq home-dir - (tramp-compat-funcall - 'directory-abbrev-apply - (tramp-make-tramp-file-name vec home-dir)))) + (tramp-compat-funcall 'directory-abbrev-apply + (tramp-make-tramp-file-name vec home-dir)))) ;; If any elt of `directory-abbrev-alist' matches this name, ;; abbreviate accordingly. (setq filename (tramp-compat-funcall 'directory-abbrev-apply filename)) @@ -4864,22 +4901,21 @@ existing) are returned." (setq remote-copy (tramp-make-tramp-temp-file v)) ;; This is defined in tramp-sh.el. Let's assume ;; this is loaded already. - (tramp-compat-funcall - 'tramp-send-command - v - (cond - ((and beg end) - (format "dd bs=1 skip=%d if=%s count=%d of=%s" - beg (tramp-shell-quote-argument localname) - (- end beg) remote-copy)) - (beg - (format "dd bs=1 skip=%d if=%s of=%s" - beg (tramp-shell-quote-argument localname) - remote-copy)) - (end - (format "dd bs=1 count=%d if=%s of=%s" - end (tramp-shell-quote-argument localname) - remote-copy)))) + (tramp-compat-funcall 'tramp-send-command + v + (cond + ((and beg end) + (format "dd bs=1 skip=%d if=%s count=%d of=%s" + beg (tramp-shell-quote-argument localname) + (- end beg) remote-copy)) + (beg + (format "dd bs=1 skip=%d if=%s of=%s" + beg (tramp-shell-quote-argument localname) + remote-copy)) + (end + (format "dd bs=1 count=%d if=%s of=%s" + end (tramp-shell-quote-argument localname) + remote-copy)))) (setq tramp-temp-buffer-file-name nil beg nil end nil)) ;; `insert-file-contents-literally' takes care to @@ -5478,8 +5514,10 @@ should be set connection-local.") "Return non-nil if ARG exists in default `process-environment'. Tramp does not propagate local environment variables in remote processes." - (or (ignore-error void-variable - (member arg (buffer-local-toplevel-value 'process-environment))) + (or ;; `buffer-local-toplevel-value' has been defined in Emacs 31.1. + (ignore-error (void-variable void-function) + (member arg (tramp-compat-funcall 'buffer-local-toplevel-value + 'process-environment))) (member arg (default-toplevel-value 'process-environment)))) (defun tramp-handle-make-process (&rest args) @@ -5563,12 +5601,10 @@ processes." (tramp-compat-make-temp-name)))) (options (when sh-file-name-handler-p - (tramp-compat-funcall - 'tramp-ssh-controlmaster-options v))) + (tramp-compat-funcall 'tramp-ssh-controlmaster-options v))) (device (when adb-file-name-handler-p - (tramp-compat-funcall - 'tramp-adb-get-device v))) + (tramp-compat-funcall 'tramp-adb-get-device v))) (pta (unless (eq connection-type 'pipe) "-t")) login-args p) @@ -7197,6 +7233,7 @@ might have improper values." (mapcar #'car tramp-connection-local-default-system-variables)))) `(let* ((default-directory tramp-compat-temporary-file-directory) (temporary-file-directory tramp-compat-temporary-file-directory) + (process-environment (copy-sequence process-environment)) ,@bindings) (setenv "TERM" tramp-terminal-type) (setenv "PROMPT_COMMAND") @@ -7473,13 +7510,12 @@ name of a process or buffer, or nil to default to the current buffer." ;; This is for tramp-sh.el. Other backends do not support this (yet). ;; Not all "kill" implementations support process groups by ;; negative pid, so we try both variants. - (tramp-compat-funcall - 'tramp-send-command - (process-get proc 'tramp-vector) - (format "(\\kill -2 -%d || \\kill -2 %d) 2>%s" - pid pid - (tramp-get-remote-null-device - (process-get proc 'tramp-vector)))) + (tramp-compat-funcall 'tramp-send-command + (process-get proc 'tramp-vector) + (format "(\\kill -2 -%d || \\kill -2 %d) 2>%s" + pid pid + (tramp-get-remote-null-device + (process-get proc 'tramp-vector)))) ;; Wait, until the process has disappeared. If it doesn't, ;; fall back to the default implementation. (while (tramp-accept-process-output proc)) @@ -7529,9 +7565,8 @@ SIGCODE may be an integer, or a symbol whose name is a signal name." (tramp-message vec 5 "Send signal %s to process %s with pid %s" sigcode process pid) ;; This is for tramp-sh.el. Other backends do not support this (yet). - (if (tramp-compat-funcall - 'tramp-send-command-and-check - vec (format "\\kill -%s %d" sigcode pid)) + (if (tramp-compat-funcall 'tramp-send-command-and-check + vec (format "\\kill -%s %d" sigcode pid)) 0 -1)))) ;; `signal-process-functions' exists since Emacs 29.1. diff --git a/lisp/net/trampver.el b/lisp/net/trampver.el index 00d5ffb2afa..d65cffbabec 100644 --- a/lisp/net/trampver.el +++ b/lisp/net/trampver.el @@ -7,7 +7,7 @@ ;; Maintainer: Michael Albinus <[email protected]> ;; Keywords: comm, processes ;; Package: tramp -;; Version: 2.8.2 +;; Version: 2.8.3-pre ;; Package-Requires: ((emacs "28.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.8.2" +(defconst tramp-version "2.8.3-pre" "This version of Tramp.") ;;;###tramp-autoload @@ -76,7 +76,7 @@ ;; Check for Emacs version. (let ((x (if (not (string-version-lessp emacs-version "28.1")) "ok" - (format "Tramp 2.8.2 is not fit for %s" + (format "Tramp 2.8.3-pre is not fit for %s" (replace-regexp-in-string "\n" "" (emacs-version)))))) (unless (string-equal "ok" x) (error "%s" x))) @@ -110,7 +110,7 @@ ("2.6.0.29.1" . "29.1") ("2.6.2.29.2" . "29.2") ("2.6.3-pre" . "29.3") ("2.6.3" . "29.4") ("2.7.1.30.1" . "30.1") ("2.7.3.30.2" . "30.2") - ("2.8.2" . "31.1"))) + ("2.8.2.31.1" . "31.1"))) (add-hook 'tramp-unload-hook (lambda () diff --git a/lisp/obsolete/cl-compat.el b/lisp/obsolete/cl-compat.el index 5b46e1ff187..46cf17923b2 100644 --- a/lisp/obsolete/cl-compat.el +++ b/lisp/obsolete/cl-compat.el @@ -177,8 +177,4 @@ (provide 'cl-compat) -;; Local variables: -;; byte-compile-warnings: (not cl-functions) -;; End: - ;;; cl-compat.el ends here diff --git a/lisp/org/ob-core.el b/lisp/org/ob-core.el index a8ca1ccd080..13fa3a2c236 100644 --- a/lisp/org/ob-core.el +++ b/lisp/org/ob-core.el @@ -2976,6 +2976,7 @@ used as a string to be appended to #+begin_example line." (forward-line 0) (insert ": ") (forward-line 1))) (t (goto-char beg) + (unless (bolp) (insert "\n")) (insert (if results-switches (format "%s%s\n" (funcall maybe-cap "#+begin_example") @@ -2984,7 +2985,9 @@ used as a string to be appended to #+begin_example line." (let ((p (point))) (if (markerp end) (goto-char end) (forward-char (- end beg))) (org-escape-code-in-region p (point))) - (insert (funcall maybe-cap "#+end_example\n"))))))))) + (unless (bolp) (insert "\n")) + (insert (funcall maybe-cap "#+end_example")) + (unless (eolp) (insert "\n"))))))))) (defun org-babel-update-block-body (new-body) "Update the body of the current code block to NEW-BODY." diff --git a/lisp/org/org-agenda.el b/lisp/org/org-agenda.el index 481eba50313..d727ab4cef0 100644 --- a/lisp/org/org-agenda.el +++ b/lisp/org/org-agenda.el @@ -9723,8 +9723,10 @@ the dedicated frame." (pos (marker-position marker))) (with-current-buffer buffer (save-excursion - (goto-char pos) - (org-tree-to-indirect-buffer arg)))) + (save-restriction + (widen) + (goto-char pos) + (org-tree-to-indirect-buffer arg))))) (setq org-agenda-last-indirect-buffer org-last-indirect-buffer)) (defvar org-last-heading-marker (make-marker) diff --git a/lisp/org/org-feed.el b/lisp/org/org-feed.el index 139c7f729ef..8ed79121711 100644 --- a/lisp/org/org-feed.el +++ b/lisp/org/org-feed.el @@ -112,7 +112,7 @@ (defcustom org-feed-alist nil "Alist specifying RSS feeds that should create inputs for Org. -Each entry in this list specified an RSS feed tat should be queried +Each entry in this list specified an RSS feed that should be queried to create inbox items in Org. Each entry is a list with the following items: name a custom name for this feed diff --git a/lisp/org/org-version.el b/lisp/org/org-version.el index f0a212f2ef0..9a46c453c2f 100644 --- a/lisp/org/org-version.el +++ b/lisp/org/org-version.el @@ -5,13 +5,13 @@ (defun org-release () "The release version of Org. Inserted by installing Org mode or when a release is made." - (let ((org-release "9.8.5")) + (let ((org-release "9.8.7")) org-release)) ;;;###autoload (defun org-git-version () "The Git version of Org mode. Inserted by installing Org or when a release is made." - (let ((org-git-version "release_9.8.5")) + (let ((org-git-version "release_9.8.7")) org-git-version)) (provide 'org-version) diff --git a/lisp/org/org.el b/lisp/org/org.el index ba31ad67bd1..a20ecc3c38f 100644 --- a/lisp/org/org.el +++ b/lisp/org/org.el @@ -9,7 +9,7 @@ ;; URL: https://orgmode.org ;; Package-Requires: ((emacs "28.2")) -;; Version: 9.8.5 +;; Version: 9.8.7 ;; This file is part of GNU Emacs. ;; @@ -9551,6 +9551,7 @@ When foo is written as FOO, upcase the #+BEGIN/END as well." (goto-char region-end) ;; Ignore empty lines at the end of the region. (skip-chars-backward " \r\t\n") + (unless (eolp) (insert "\n") (forward-line -1)) (end-of-line)) (unless (bolp) (insert "\n")) (indent-to column) @@ -9877,7 +9878,8 @@ When called through Elisp, arg is also interpreted in the following way: (org-update-parent-todo-statistics)) (when (bound-and-true-p org-clock-out-when-done) (org-clock-out-if-current)) - (run-hooks 'org-after-todo-state-change-hook) + (save-excursion + (run-hooks 'org-after-todo-state-change-hook)) (when (and arg (not (member org-state org-done-keywords))) (setq head (org-get-todo-sequence-head org-state))) (put-text-property (line-beginning-position) @@ -10583,7 +10585,8 @@ enough to shift date past today. Continue? " (org-timestamp-change n (cdr (assoc what whata)) nil t)) (setq msg (concat msg type " " org-last-changed-timestamp " "))))))) - (run-hooks 'org-todo-repeat-hook) + (save-excursion + (run-hooks 'org-todo-repeat-hook)) (setq org-log-post-message msg) (message msg)))) diff --git a/lisp/org/ox-beamer.el b/lisp/org/ox-beamer.el index 72fe18acdb8..302ebdc6a40 100644 --- a/lisp/org/ox-beamer.el +++ b/lisp/org/ox-beamer.el @@ -4,6 +4,7 @@ ;; Author: Carsten Dominik <carsten.dominik AT gmail DOT com> ;; Nicolas Goaziou <n.goaziou AT gmail DOT com> +;; Maintainer: Pedro A. Aranda <paaguti aT gmail d.T com> ;; Keywords: org, text, tex ;; This file is part of GNU Emacs. diff --git a/lisp/org/ox-latex.el b/lisp/org/ox-latex.el index 1feddac37cd..d07af9e63ad 100644 --- a/lisp/org/ox-latex.el +++ b/lisp/org/ox-latex.el @@ -1712,7 +1712,7 @@ Return the new header." ;; exclusively through ini files, return HEADER as-is. (header (if (or language-ini-only (not (stringp language-code)) - (not (string-match "\\\\usepackage\\[\\(.*\\)\\]{babel}" header))) + (not (string-match "\\\\usepackage\\[\\([^]]*\\)\\]{babel}" header))) header (let ((options (save-match-data (org-split-string (match-string 1 header) ",[ \t]*")))) diff --git a/lisp/outline.el b/lisp/outline.el index ea66ee5c8e9..4b4f3c2d520 100644 --- a/lisp/outline.el +++ b/lisp/outline.el @@ -61,8 +61,10 @@ The recommended way to set this is with a `Local Variables:' list in the file it applies to.") ;;;###autoload(put 'outline-heading-end-regexp 'safe-local-variable 'stringp) -(defvar outline-search-function nil - "Function to search the next outline heading. +(defcustom outline-search-function nil + "If non-nil, the function to search the next outline heading. +When nil, headings are found by searching for `outline-regexp'. + The function is called with four optional arguments: BOUND, MOVE, BACKWARD, LOOKING-AT. The first two arguments BOUND and MOVE are almost the same as the BOUND and NOERROR arguments of `re-search-forward', with the difference @@ -71,7 +73,15 @@ BACKWARD is non-nil, the search should search backward like `re-search-backward' does. In case of a successful search, the function should return non-nil, move point, and set match-data appropriately. When the argument LOOKING-AT is non-nil, it should -imitate the function `looking-at'.") +imitate the function `looking-at'." + :type '(choice (const :tag "Use `outline-regexp'" nil) + (function-item :tag "Search by `outline-regexp' (regexp-based)" + outline-search-from-regexp) + (function-item :tag "Search by `outline-level' text property" + outline-search-level) + (function :tag "Other function")) + :group 'outlines + :version "32.1") (defvar-keymap outline-mode-prefix-map "@" #'outline-mark-subtree @@ -86,7 +96,7 @@ imitate the function `looking-at'.") "C-t" #'outline-hide-body "C-a" #'outline-show-all "C-c" #'outline-hide-entry - "C-e" #'outline-show-entry + "C-e" #'outline-show-entry-and-parents "C-l" #'outline-hide-leaves "C-k" #'outline-show-branches "C-q" #'outline-hide-sublevels @@ -130,8 +140,8 @@ imitate the function `looking-at'.") (define-key map [show outline-show-branches] '(menu-item "Show Branches" outline-show-branches :help "Show all subheadings of this heading, but not their bodies")) - (define-key map [show outline-show-entry] - '(menu-item "Show Entry" outline-show-entry + (define-key map [show outline-show-entry-and-parents] + '(menu-item "Show Entry" outline-show-entry-and-parents :help "Show the body directly following this heading")) (define-key map [show outline-show-all] '(menu-item "Show All" outline-show-all @@ -1095,7 +1105,7 @@ If FLAG is nil then text is shown, while if FLAG is t the text is hidden." ;; `outline-flag-region'). (defun outline-isearch-open-invisible (_overlay) ;; We rely on the fact that isearch places point on the matched text. - (outline-show-entry)) + (outline-show-entry-and-parents)) (defun outline-hide-entry () "Hide the body directly following this heading." @@ -1123,6 +1133,67 @@ Show the heading too, if it is currently invisible." (define-obsolete-function-alias 'show-entry #'outline-show-entry "25.1") +(defun outline-show-entry-and-parents () + "Reveal the current entry and its parent hierarchy. +This command ensures that the current entry, all of its ancestor +headings, and their immediate sibling headings are visible. + +The function iteratively unfolds the children and body of the target +entry until it is fully revealed. If invoked when the point is inside +a completely hidden subtree, it manages the visibility state to avoid +leaving the buffer in an inconsistent layout. This guarantees a safe +and predictable visual expansion." + (interactive) + ;; Wrap in `save-match-data' because outline functions use regular + ;; expressions. Without this, calling `outline-show-entry-and-parents' + ;; programmatically would clobber the caller's match data, leading to + ;; subtle, hard-to-trace bugs. + (save-match-data + ;; Repeatedly expand the outline structure at point from the outside + ;; in until the target text is fully visible. + ;; + ;; Think of this block as manually opening nested folds: + ;; - It checks whether the heading at point is folded. + ;; - If it is folded, it moves backward to that parent heading. + ;; - It opens the heading to reveal its text and subheadings. + ;; - It repeats this process layer by layer down to the target. + (let (heading-point + prior-heading-point) + (while (condition-case nil + (save-excursion + ;; Workaround: `outline-back-to-heading' throws an + ;; `outline-before-first-heading' error if the + ;; heading is on the first line (e.g., in + ;; `markdown-ts-mode') and point is deep within the + ;; hidden body of that folded first heading. + (vertical-motion 0) + ;; Navigate backward to the nearest visible heading + (outline-back-to-heading) + (setq heading-point (point)) + ;; Break the loop if we stop making progress, + ;; preventing infinite recursion + (if (eq heading-point prior-heading-point) + ;; Break out of the loop + nil + (setq prior-heading-point heading-point) + ;; Check if the heading is folded by inspecting the + ;; end of the line + (when (invisible-p (pos-eol)) + ;; Ignore errors to guarantee the target entry is + ;; still revealed via `outline-show-entry' even + ;; if a buggy third-party `outline-level' + ;; function fails during child expansion. + (ignore-errors (outline-show-children)) + + ;; Show the body directly following this heading + (outline-show-entry) + + ;; Return t to continue drilling down to the next + ;; layer of the outline hierarchy + t))) + (outline-before-first-heading + nil)))))) + (defun outline-hide-body () "Hide all body lines in buffer, leaving all headings visible. Note that this does not hide the lines preceding the first heading line." @@ -1313,7 +1384,7 @@ This also unhides the top heading-less body, if any." (or first (> (funcall outline-level) level))) (setq first nil) (outline-next-heading)) - (if (and (bolp) (not (eolp))) + (if (or (eobp) (and (bolp) (not (eolp)))) ;; We stopped at a nonempty line (the next heading). (outline--end-of-previous)))) @@ -1490,6 +1561,26 @@ The rest of arguments are described in `outline-search-function'." nil)))) +;;; Search regexp for outline headings + +;;;###autoload +(defun outline-search-from-regexp (&optional bound move backward looking-at) + "Search for the next heading matching `outline-regexp'. +The arguments BOUND, MOVE, BACKWARD, and LOOKING-AT are described +in `outline-search-function'. This function is intended to be +used in `outline-search-function' by modes and minor modes that +customize `outline-regexp' but do not need a custom search strategy. +Install it with + + (setq-local outline-search-function #\\='outline-search-from-regexp)" + (if looking-at + (looking-at outline-regexp) + (funcall (if backward #'re-search-backward #'re-search-forward) + (concat "^\\(?:" outline-regexp "\\)") + bound + (if move 'move t)))) + + (defun outline-headers-as-kill (beg end) "Save the visible outline headers between BEG and END to the kill ring. diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index d08615446a1..5f064716a89 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -501,6 +501,7 @@ MODE can be `c' or `cpp'. STYLE can be `gnu', `k&r', `linux', `bsd'." ((parent-is ,(rx (or "function_definition" "struct_specifier" "enum_specifier" + "union_specifier" "function_declarator" "template_declaration"))) standalone-parent 0) diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el index 6eed5b53c19..c00fef8a471 100644 --- a/lisp/progmodes/cc-mode.el +++ b/lisp/progmodes/cc-mode.el @@ -675,24 +675,16 @@ that requires a literal mode spec at compile time." (setq c-min-syn-tab-mkr nil) (setq c-max-syn-tab-mkr nil) - (when (or c-recognize-<>-arglists - (c-major-mode-is 'awk-mode) - (c-major-mode-is '(java-mode c-mode c++-mode objc-mode pike-mode))) - ;; We'll use the syntax-table text property to change the syntax - ;; of some chars for this language, so do the necessary setup for - ;; that. - ;; - ;; Note to other package developers: It's ok to turn this on in CC - ;; Mode buffers when CC Mode doesn't, but it's not ok to turn it - ;; off if CC Mode has turned it on. - - ;; Emacs. - (when (boundp 'parse-sexp-lookup-properties) - (set (make-local-variable 'parse-sexp-lookup-properties) t)) - - ;; Same as above for XEmacs. - (when (boundp 'lookup-syntax-properties) - (set (make-local-variable 'lookup-syntax-properties) t))) + ;; We use the syntax-table text property to change the syntax of some + ;; chars, potentially in every language, so set this up. + ;; Emacs. + (when (boundp 'parse-sexp-lookup-properties) + (make-local-variable 'parse-sexp-lookup-properties) + (setq parse-sexp-lookup-properties t)) + ;; Same as above for XEmacs. + (when (boundp 'lookup-syntax-properties) + (make-local-variable 'lookup-syntax-properties) + (setq lookup-syntax-properties t)) ;; Use this in Emacs 21+ to avoid meddling with the rear-nonsticky ;; property on each character. @@ -3402,22 +3394,6 @@ Key bindings: style c-features))))))) -;; Make entries in `major-mode-remap-defaults' to ensure that when CC -;; Mode has been loaded, the symbols `c-mode' etc., will call CC Mode's -;; modes rather than c-ts-mode etc.. -(when (boundp 'major-mode-remap-defaults) - (add-to-list 'major-mode-remap-defaults '(c++-mode . c++-ts-mode)) - (add-to-list 'major-mode-remap-defaults '(c-mode . c-ts-mode)) - (add-to-list 'major-mode-remap-defaults '(c-or-c++-mode . c-or-c++-ts-mode)) - (let (entry) - (dolist (mode '(c-mode c++-mode c-or-c++-mode)) - (if (and (setq entry (assq mode major-mode-remap-defaults)) - (null (cdr entry))) - (setq major-mode-remap-defaults - (delq entry major-mode-remap-defaults))) - (push (cons mode nil) major-mode-remap-defaults)))) - - (cc-provide 'cc-mode) ;; Local Variables: diff --git a/lisp/progmodes/cc-vars.el b/lisp/progmodes/cc-vars.el index 4ac18869400..cfdbd73f20a 100644 --- a/lisp/progmodes/cc-vars.el +++ b/lisp/progmodes/cc-vars.el @@ -1737,7 +1737,9 @@ If you change this variable's value, call the function `c-make-noise-macro-regexps' to set the necessary internal variables (or do this implicitly by reinitializing C/C++/Objc Mode on any buffer)." :version "26.1" - :type '(repeat :tag "List of names" string) + :type '(choice + (repeat :tag "List of names (possibly empty)" string) + (regexp :tag "Names regexp")) :group 'c) (put 'c-noise-macro-names 'safe-local-variable #'c-string-list-p) (make-variable-buffer-local 'c-noise-macro-names) @@ -1754,7 +1756,9 @@ If you change this variable's value, call the function `c-make-noise-macro-regexps' to set the necessary internal variables (or do this implicitly by reinitializing C/C++/Objc Mode on any buffer)." :version "26.1" - :type '(repeat :tag "List of names (possibly empty)" string) + :type '(choice + (repeat :tag "List of names (possibly empty)" string) + (regexp :tag "Names regexp")) :group 'c) (put 'c-noise-macro-with-parens-names 'safe-local-variable #'c-string-list-p) (make-variable-buffer-local 'c-noise-macro-with-parens-names) diff --git a/lisp/progmodes/cperl-mode.el b/lisp/progmodes/cperl-mode.el index 91e2e46fdba..22d312d6be1 100644 --- a/lisp/progmodes/cperl-mode.el +++ b/lisp/progmodes/cperl-mode.el @@ -959,7 +959,6 @@ Unless KEEP, removes the old indentation." ("foreachmy" cperl-electric-keyword) ("do" cperl-electric-keyword) ("=pod" cperl-electric-pod) - ("=begin" cperl-electric-pod t) ("=over" cperl-electric-pod) ("=head1" cperl-electric-pod) ("=head2" cperl-electric-pod) @@ -2302,7 +2301,6 @@ to nil." (save-excursion (or (not (re-search-backward "^=" nil t)) (or (looking-at "=cut") - (looking-at "=end") (and cperl-use-syntax-table-text-property (not (eq (get-text-property (point) 'syntax-type) @@ -2378,7 +2376,7 @@ Go to POS which defaults to the current point after processing." (get-text-property (point) 'in-pod) (cperl-after-expr-p nil "{;:") (and (re-search-backward "\\(\\`\n?\\|^\n\\)=\\sw+" (point-min) t) - (not (or (looking-at "\n*=cut") (looking-at "\n*=end"))) + (not (looking-at "\n*=cut")) (or (not cperl-use-syntax-table-text-property) (eq (get-text-property (point) 'syntax-type) 'pod)))))) (progn @@ -2436,7 +2434,6 @@ to nil." beg t))) (save-excursion (or (not (re-search-backward "^=" nil t)) (looking-at "=cut") - (looking-at "=end") (and cperl-use-syntax-table-text-property (not (eq (get-text-property (point) 'syntax-type) @@ -2536,7 +2533,7 @@ If in POD, insert appropriate lines." ;; We are after \n now, so look for the rest (if (looking-at "\\(\\`\n?\\|\n\\)=\\sw+") (progn - (setq cut (looking-at "\\(\\`\n?\\|\n\\)=\\(cut\\|end\\)\\>")) + (setq cut (looking-at "\\(\\`\n?\\|\n\\)=cut\\>")) (setq over (looking-at "\\(\\`\n?\\|\n\\)=over\\>")) t))) (if (and over @@ -4496,7 +4493,7 @@ recursive calls in starting lines of here-documents." state-point b nil nil state) state-point b) (if (or (nth 3 state) (nth 4 state) - (looking-at "\\(cut\\|end\\)\\>")) + (looking-at "cut\\>")) (if (or (nth 3 state) (nth 4 state) ignore-max) nil ; Doing a chunk only (setq warning-message "=cut is not preceded by a POD section") @@ -4509,10 +4506,10 @@ recursive calls in starting lines of here-documents." b1 nil) ; error condition ;; We do not search to max, since we may be called from ;; some hook of fontification, and max is random - (or (re-search-forward "^\n=\\(cut\\|end\\)\\>" stop-point 'toend) + (or (re-search-forward "^\n=cut\\>" stop-point 'toend) (progn (goto-char b) - (if (re-search-forward "\n=\\(cut\\|end\\)\\>" stop-point 'toend) + (if (re-search-forward "\n=cut\\>" stop-point 'toend) (progn (setq warning-message "=cut is not preceded by an empty line") (setq b1 t) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 8d5d7cafc3c..f701a38ab8b 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -2,12 +2,12 @@ ;; Copyright (C) 2018-2026 Free Software Foundation, Inc. -;; Version: 1.23 +;; Version: 1.24 ;; Author: João Távora <[email protected]> ;; Maintainer: João Távora <[email protected]> ;; URL: https://github.com/joaotavora/eglot ;; Keywords: convenience, languages -;; Package-Requires: ((emacs "26.3") (eldoc "1.16.0") (external-completion "0.1") (flymake "1.4.5") (jsonrpc "1.0.28") (project "0.11.2") (seq "2.23") (xref "1.7.0")) +;; Package-Requires: ((emacs "26.3") (eldoc "1.16.0") (external-completion "0.1") (flymake "1.4.5") (jsonrpc "1.0.29") (project "0.11.2") (seq "2.23") (xref "1.7.0")) ;; This is a GNU ELPA :core package. Avoid adding functionality ;; that is not available in the version of Emacs recorded above or any @@ -317,7 +317,7 @@ automatically)." ((toml-ts-mode conf-toml-mode) . ("tombi" "lsp")) (nix-mode . ,(eglot-alternatives '("nil" "rnix-lsp" "nixd"))) (nickel-mode . ("nls")) - ((nushell-mode nushell-ts-mode) . ("nu" "--lsp")) + ((nushell-mode nushell-ts-mode nu-ts-mode) . ("nu" "--lsp")) (gdscript-mode . ("localhost" 6008)) (fennel-mode . ("fennel-ls")) (move-mode . ("move-analyzer")) @@ -1264,7 +1264,8 @@ object." ;; `file-name-handler-alist' should know how to handle them ;; (bug#58790). (if (string= "file" (url-type url)) - (let* ((unhexed (url-unhex-string (url-filename url))) + (let* ((unhexed (decode-coding-string + (url-unhex-string (url-filename url)) 'utf-8-unix)) ;; Remove the leading "/" for local MS Windows-style paths. (norm (if (and (not remote-prefix) (eq system-type 'windows-nt) @@ -2117,7 +2118,7 @@ and also used as a hint of the request cancellation mechanism (see :timeout-fn (wrapfn timeout-fn) moreargs))) (when (and hint eglot-advertise-cancellation) - (push id (plist-get inflight hint))) + (push id (cl-getf inflight hint))) id)) (cl-defun eglot--delete-overlays (&optional (prop 'eglot--overlays)) diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index 5a550b33016..c293789cee3 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el @@ -694,7 +694,7 @@ happens in interactive invocations. When calling from Lisp, use nil or a positive number as the value of INTERACTIVE to enable `lexical-binding', a negative number to disable it." - (interactive "p") + (interactive "@p") (let* ((disable-lexbind (or (and (numberp interactive) (< interactive 0)) (if current-prefix-arg t))) @@ -2618,11 +2618,12 @@ Calls REPORT-FN directly." (generate-new-buffer " *checkdoc-temp*"))) (unwind-protect (save-excursion - ;; checkdoc-current-buffer can error if there are - ;; unbalanced parens, for example, but this shouldn't - ;; disable the backend (bug#29176). - (ignore-errors - (checkdoc-current-buffer t))) + (without-restriction + ;; checkdoc-current-buffer can error if there are + ;; unbalanced parens, for example, but this shouldn't + ;; disable the backend (bug#29176). + (ignore-errors + (checkdoc-current-buffer t)))) (kill-buffer checkdoc-diagnostic-buffer))) (funcall report-fn (cl-loop for (text start end _unfixable) in diff --git a/lisp/progmodes/etags-regen.el b/lisp/progmodes/etags-regen.el index b9cb75358c0..9be4be9f92d 100644 --- a/lisp/progmodes/etags-regen.el +++ b/lisp/progmodes/etags-regen.el @@ -236,8 +236,9 @@ is used in buffers that have no alternative completion configured." ;; this mode, skip all functionality. (not (or tags-file-name tags-table-list)) - (file-exists-p (etags-regen--choose-tags-file - (setq proj (project-current))))) + (prog1 (setq proj (project-current)) + (unless proj (message "No project found"))) + (file-exists-p (etags-regen--choose-tags-file proj))) (message "Found existing tags table, refreshing...") (etags-regen--refresh proj)) (when (and (not (or tags-file-name diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el index 823aa4fe673..3b017a56d01 100644 --- a/lisp/progmodes/flymake.el +++ b/lisp/progmodes/flymake.el @@ -2238,9 +2238,9 @@ some of this variable's contents the diagnostic listings.") (defun flymake-show-project-diagnostics () "Show a list of Flymake diagnostics for the current project." (interactive) - (let* ((prj (project-current)) - (root (project-root prj)) - (buffer (flymake--project-diagnostics-buffer root))) + (let* ((prj (project-current t)) + (default-directory (project-root prj)) + (buffer (flymake--project-diagnostics-buffer default-directory))) (with-current-buffer buffer (flymake-project-diagnostics-mode) (setq-local flymake--project-diagnostic-list-project prj) diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index 3f2deca317c..bd58b16d342 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -289,7 +289,7 @@ Match group 1 is the name of the macro.") "instanceof" "interface" "native" "new" "of" "package" "private" "protected" "public" "return" "static" "super" "switch" "synchronized" "throw" - "throws" "transient" "try" "typeof" "var" "void" "let" + "throws" "transient" "try" "typeof" "using" "var" "void" "let" "yield" "volatile" "while" "with")) "Regexp matching any JavaScript keyword.") @@ -1740,7 +1740,7 @@ point of view of font-lock. It applies highlighting directly with ;; variable declarations ,(list - (concat "\\_<\\(const\\|var\\|let\\)\\_>\\|" js--basic-type-re) + (concat "\\_<\\(const\\|var\\|let\\|using\\)\\_>\\|" js--basic-type-re) (list #'js--variable-decl-matcher nil nil nil)) ;; class instantiation @@ -2352,7 +2352,7 @@ testing for syntax only valid as JSX." "Regexp matching keywords optionally followed by an opening brace.") (defconst js--declaration-keyword-re - (regexp-opt '("var" "let" "const") 'words) + (regexp-opt '("var" "let" "const" "using") 'words) "Regular expression matching variable declaration keywords.") (defconst js--indent-operator-re @@ -3581,6 +3581,14 @@ characters of the current line." "typeof" "var" "void" "while" "with" "yield") "JavaScript keywords for tree-sitter font-locking.") + +;; "using" support was only added in tree-sitter-javascript 0.25.0, in +;; https://github.com/tree-sitter/tree-sitter-javascript/commit/ebdb4f17a4da79a70344a41ae76bb95b2415a653 +;; So make it optional +(defvar js--treesit-optional-keywords + '("using") + "JavaScript optional keywords for tree-sitter font-locking.") + (defvar js--treesit-operators '("=" "+=" "-=" "*=" "/=" "%=" "**=" "<<=" ">>=" ">>>=" "&=" "^=" "|=" "&&=" "||=" "??=" "==" "!=" "===" "!==" ">" ">=" "<" "<=" "+" @@ -3605,8 +3613,10 @@ characters of the current line." :language 'javascript :feature 'keyword - `([,@js--treesit-keywords] @font-lock-keyword-face - [(this) (super)] @font-lock-keyword-face) + (treesit-query-with-optional 'javascript + `([,@js--treesit-keywords] @font-lock-keyword-face + [(this) (super)] @font-lock-keyword-face) + `([,@js--treesit-optional-keywords] @font-lock-keyword-face)) :language 'javascript :feature 'string @@ -3789,7 +3799,7 @@ Return nil if there is no name or if NODE is not a defun node." (treesit-node-text (treesit-node-child-by-field-name (pcase (treesit-node-type node) - ((or "lexical_declaration" "variable_declaration") + ((or "lexical_declaration" "variable_declaration" "using_declaration") (treesit-search-subtree node "variable_declarator" nil nil 1)) ((or "function_declaration" "method_definition" "class_declaration") node)) @@ -3799,7 +3809,7 @@ Return nil if there is no name or if NODE is not a defun node." (defun js--treesit-valid-imenu-entry (node) "Return nil if NODE is a non-top-level lexical/variable declaration." (pcase (treesit-node-type node) - ((or "lexical_declaration" "variable_declaration") + ((or "lexical_declaration" "variable_declaration" "using_declaration") (not (treesit-node-top-level node (rx bos (or "class_declaration" "method_definition" @@ -3930,6 +3940,7 @@ Currently there are `js-mode' and `js-ts-mode'." "labeled_statement" "variable_declaration" "lexical_declaration" + "using_declaration" "jsx_opening_element" "jsx_attribute" "jsx_closing_element") @@ -3997,7 +4008,8 @@ See `treesit-thing-settings' for more information.") ("Method" "\\`method_definition\\'" nil nil) ("Function" "\\`function_declaration\\'" nil nil) ("Variable" ,(rx bos (or "lexical_declaration" - "variable_declaration") + "variable_declaration" + "using_declaration") eos) ,#'js--treesit-valid-imenu-entry nil)) "Settings for `treesit-simple-imenu'.") @@ -4015,7 +4027,8 @@ See `treesit-thing-settings' for more information.") "method_definition" "function_declaration" "lexical_declaration" - "variable_declaration") + "variable_declaration" + "using_declaration") eos) "Settings for `treesit-defun-type-regexp'.") diff --git a/lisp/progmodes/perl-mode.el b/lisp/progmodes/perl-mode.el index 61988d85027..26dfc9e97c8 100644 --- a/lisp/progmodes/perl-mode.el +++ b/lisp/progmodes/perl-mode.el @@ -1021,7 +1021,7 @@ Returns (parse-state) if line starts inside a string." (containing-sexp (nth 1 state)) ;; Don't auto-indent in a quoted string or a here-document. (unindentable (or (nth 3 state) (eq 2 (nth 7 state)))) - (format (and (nth 3 state) + (format (and (characterp (nth 3 state)) (char-equal (nth 3 state) ?\n)))) (when (and (eq t (nth 3 state)) (save-excursion diff --git a/lisp/progmodes/prog-mode.el b/lisp/progmodes/prog-mode.el index afa18d9958b..a1cc32d3601 100644 --- a/lisp/progmodes/prog-mode.el +++ b/lisp/progmodes/prog-mode.el @@ -166,6 +166,14 @@ instead." (and (re-search-forward "\\s-*\\s<" (line-end-position) t) (nth 8 (syntax-ppss)))))) +(defun prog--text-at-point-or-region-p () + "Return non-nil if point or region's other end are in text." + (or (prog--text-at-point-p) + (and (use-region-p) + (save-excursion + (goto-char (mark)) + (prog--text-at-point-p))))) + (defvar prog-fill-reindent-defun-function #'prog-fill-reindent-defun-default "Function called by `prog-fill-reindent-defun' to do the actual work. @@ -176,7 +184,7 @@ It should take the same argument as `prog-fill-reindent-defun'.") JUSTIFY is the same as in `fill-paragraph'." (interactive "P") (save-excursion - (if (prog--text-at-point-p) + (if (prog--text-at-point-or-region-p) (fill-paragraph justify (region-active-p)) (beginning-of-defun) (let ((start (point))) diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 7e794330b1f..4ddfe7a48c4 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1,7 +1,7 @@ ;;; project.el --- Operations on the current project -*- lexical-binding: t; -*- ;; Copyright (C) 2015-2026 Free Software Foundation, Inc. -;; Version: 0.11.2 +;; Version: 0.12.0 ;; Package-Requires: ((emacs "26.1") (xref "1.7.0")) ;; This is a GNU ELPA :core package. Avoid functionality that is not @@ -84,11 +84,11 @@ ;; This project type can also be used for non-VCS controlled ;; directories, see the variable `project-vc-extra-root-markers'. ;; -;; Some of the methods on this backend cache their computations for time -;; determined either by variable `project-vc-cache-timeout' or +;; Some of the methods on this backend cache their computations. +;; Cache invalidation is done inside the `project-current' call, with +;; duration determined either by variable `project-vc-cache-timeout' or ;; `project-vc-non-essential-cache-timeout', depending on whether the -;; MAYBE-PROMPT argument to `project-current' is non-nil, or the value -;; of `non-essential' when project methods are called. +;; argument MAYBE-PROMPT is non-nil. ;; ;; Utils: ;; @@ -157,11 +157,9 @@ ;; force every project backend to be aware of the build tool(s) the ;; project is using. ;; -;; * Command to (re)build the tag files in all project roots. To that -;; end, we might need to add a way to provide file whitelist -;; wildcards for each root to limit etags to certain files (in -;; addition to the blacklist provided by ignores), and/or allow -;; specifying additional tag regexps. +;; * Minor mode to (re)build the tags across the current project: +;; `etags-regen-mode'. It would be straightforward to add support for +;; multiple roots, if someone works with a project organized this way. ;; ;; * UI for the user to be able to pick the current project for the ;; whole Emacs session, independent of the current directory. Or, @@ -406,7 +404,7 @@ to find the list of ignores for each directory." ;; expanded and not left for the shell command ;; to interpret. (localdir (file-name-unquote (file-local-name (expand-file-name dir)))) - (command (format "%s -H . %s -type f %s -print0" + (command (format "%s -L . %s -type f %s -print0" find-program (xref--find-ignores-arguments ignores "./") (if files @@ -613,27 +611,21 @@ higher numbers, intended for \"background\" things like `project-mode-line' indicators and `project-uniquify-dirname-transform'. It is used when `non-essential' is non-nil.") -(defun project--get-cached (dir key) +(defun project--get-cached (dir key timeout) (let ((cached (vc-file-getprop dir key)) (current-time (float-time))) (when (and (numberp (cdr cached)) ;; Support package upgrade mid-session. - (let* ((project-vc-cache-timeout - (if non-essential - project-vc-non-essential-cache-timeout - project-vc-cache-timeout)) - (timeout + (let* ((timeout (cond - ((numberp project-vc-cache-timeout) - project-vc-cache-timeout) - ((null project-vc-cache-timeout) - nil) - ((listp project-vc-cache-timeout) + ((numberp timeout) + timeout) + ((listp timeout) (cdr (seq-find (lambda (pair) (and (functionp (car pair)) (funcall (car pair) dir))) - project-vc-cache-timeout))) + timeout))) (t nil)))) (or (null timeout) (< (- current-time (cdr cached)) timeout)))) @@ -647,7 +639,9 @@ It is used when `non-essential' is non-nil.") (obarray-map (lambda (sym) (if (get sym 'project-vc) - (put sym 'project-vc nil))) + (put sym 'project-vc nil)) + (if (get sym 'project-vc-dir-locals) + (put sym 'project-vc-dir-locals nil))) vc-file-prop-obarray)) (defun project-try-vc (dir) @@ -656,15 +650,18 @@ It is used when `non-essential' is non-nil.") The value is cached, and depending on whether MAYBE-PROMPT was non-nil in the `project-current' call, the timeout is determined by `project-vc-cache-timeout' or `project-vc-non-essential-cache-timeout'." - (let ((cached (project--get-cached dir 'project-vc))) + (let* ((timeout (if non-essential + project-vc-non-essential-cache-timeout + project-vc-cache-timeout)) + (cached (project--get-cached dir 'project-vc timeout))) (if (eq cached 'none) nil (or cached - (let ((res (project-try-vc--search dir))) + (let ((res (project-try-vc--search dir timeout))) (project--set-cached dir 'project-vc (or res 'none)) res))))) -(defun project-try-vc--search (dir) +(defun project-try-vc--search (dir timeout) (let* ((backend-markers (delete nil @@ -677,7 +674,7 @@ in the `project-current' call, the timeout is determined by (mapconcat (lambda (m) (format "\\(%s\\)" (wildcard-to-regexp m))) (append backend-markers - (project--value-in-dir 'project-vc-extra-root-markers dir)) + (project--value-in-dir 'project-vc-extra-root-markers dir timeout)) "\\|") "\\'")) (locate-dominating-stop-dir-regexp @@ -702,7 +699,7 @@ in the `project-current' call, the timeout is determined by (while (and root (eq backend 'Git) - (project--vc-merge-submodules-p root) + (project--vc-merge-submodules-p root timeout) (project--submodule-p root)) (let* ((parent (file-name-directory (directory-file-name root)))) (setq root (vc-call-backend 'Git 'root parent)))) @@ -713,7 +710,7 @@ in the `project-current' call, the timeout is determined by (let* ((project-vc-extra-root-markers nil) ;; Avoid submodules scan. (enable-dir-local-variables nil) - (parent (project-try-vc--search root))) + (parent (project-try-vc--search root timeout))) (and parent (setq backend (nth 1 parent))))) (setq project (list 'vc backend root)) project))) @@ -762,7 +759,7 @@ in the `project-current' call, the timeout is determined by (cl-defmethod project-files ((project (head vc)) &optional dirs) (mapcan (lambda (dir) - (let ((ignores (project--value-in-dir 'project-vc-ignores dir)) + (let ((ignores (project--value-in-dir 'project-vc-ignores dir nil)) (backend (project-vc--backend project dir))) (if backend (vc-call-backend backend 'project-list-files dir ignores) @@ -790,7 +787,8 @@ in the `project-current' call, the timeout is determined by (vc-git-use-literal-pathspecs nil) (include-untracked (project--value-in-dir 'project-vc-include-untracked - dir)) + dir + nil)) (submodules (project--git-submodules)) (gitver (vc-git--program-version)) (dedup (and (version<= "2.31" gitver) '("--deduplicate"))) @@ -842,7 +840,7 @@ in the `project-current' call, the timeout is determined by (with-output-to-string (apply #'vc-git-command standard-output 0 nil "ls-files" args)) "\0" t)))) - (when (project--vc-merge-submodules-p default-directory) + (when (project--vc-merge-submodules-p default-directory nil) ;; Unfortunately, 'ls-files --recurse-submodules' conflicts with '-o'. (let ((sub-files (mapcar @@ -867,7 +865,8 @@ in the `project-current' call, the timeout is determined by (let* ((default-directory (expand-file-name (file-name-as-directory dir))) (include-untracked (project--value-in-dir 'project-vc-include-untracked - dir)) + dir + nil)) (args (list (concat "-mcard" (and include-untracked "u")) "--no-status" "-0")) @@ -887,10 +886,11 @@ in the `project-current' call, the timeout is determined by files))) files))) -(defun project--vc-merge-submodules-p (dir) +(defun project--vc-merge-submodules-p (dir timeout) (project--value-in-dir 'project-vc-merge-submodules - dir)) + dir + timeout)) (defun project--git-submodules () ;; 'git submodule foreach' is much slower. @@ -907,7 +907,7 @@ in the `project-current' call, the timeout is determined by (cl-defmethod project-ignores ((project (head vc)) dir) (project--vc-ignores dir (project-vc--backend project dir) - (project--value-in-dir 'project-vc-ignores dir))) + (project--value-in-dir 'project-vc-ignores dir nil))) (defun project--vc-ignores (dir backend extra-ignores) (require 'vc) ; Can be removed when we require Emacs 31.1. @@ -964,17 +964,21 @@ DIRS must contain directory names." ;; Sidestep the issue of expanded/abbreviated file names here. (cl-set-difference files dirs :test #'file-in-directory-p)) -(defun project--value-in-dir (var dir) +(defun project--value-in-dir (var dir timeout) + "Look up variable VAR's value in DIR, with cache duration TIMEOUT. +If TIMEOUT is nil, the cache is not invalidated." (alist-get var - (let ((cached (project--get-cached dir 'project-vc-dir-locals))) - (if (eq cached 'none) - nil - (or cached - (let ((res (project--read-dir-locals dir))) - (project--set-cached dir 'project-vc-dir-locals (or res 'none)) - res)))) - (symbol-value var))) + (and + enable-dir-local-variables + (let ((cached (project--get-cached dir 'project-vc-dir-locals timeout))) + (if (eq cached 'none) + nil + (or cached + (let ((res (project--read-dir-locals dir))) + (project--set-cached dir 'project-vc-dir-locals (or res 'none)) + res))))) + (default-value var))) (defun project--read-dir-locals (dir) (with-temp-buffer @@ -986,7 +990,7 @@ DIRS must contain directory names." (cl-defmethod project-buffers ((project (head vc))) (let* ((root (expand-file-name (file-name-as-directory (project-root project)))) - (modules (unless (or (project--vc-merge-submodules-p root) + (modules (unless (or (project--vc-merge-submodules-p root nil) (condition-case nil (project--submodule-p root) (file-missing nil))) @@ -1004,12 +1008,8 @@ DIRS must contain directory names." (nreverse bufs))) (cl-defmethod project-name ((project (head vc))) - "Returns the name of this VC-aware type PROJECT. - -The value is cached, and depending on whether `non-essential' is nil, -the timeout is determined by `project-vc-cache-timeout' or -`project-vc-non-essential-cache-timeout'." - (or (project--value-in-dir 'project-vc-name (project-root project)) + "Returns the name of this VC-aware type PROJECT." + (or (project--value-in-dir 'project-vc-name (project-root project) nil) (cl-call-next-method))) @@ -1610,6 +1610,10 @@ The current buffer's `default-directory' is available as part of ;;;###autoload (defun project-vc-dir () "Run VC-Dir in the current project's root." + ;; This is unfortunately inconsistent with `vc-dir' which calls + ;; `file-truename' on the directory. But following symlink results in + ;; "mismatched" project for that buffer and any visited from it. See + ;; <https://lists.gnu.org/archive/html/emacs-devel/2026-06/msg00196.html>. (interactive) (vc-dir (project-root (project-current t)))) @@ -2731,8 +2735,7 @@ slash-separated components from `project-name' will be appended to the buffer's directory name when buffers from two different projects would otherwise have the same name." (if-let* ((proj (project-current nil dirname))) - (let ((root (project-root proj)) - (non-essential t)) + (let ((root (project-root proj))) (expand-file-name (file-name-concat (file-name-directory root) @@ -2778,7 +2781,6 @@ value is `non-remote', show the project name only for local files." ;; 'last-coding-system-used' when reading the project name ;; from .dir-locals.el also enables flyspell-mode (bug#66825). (when-let* ((last-coding-system-used last-coding-system-used) - (non-essential t) (project (project-current)) (project-name (project-name project))) (concat diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 86336979067..962f9c5a031 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -7056,6 +7056,10 @@ REPORT-FN is Flymake's callback function." ;;; Import management (defconst python--list-imports "\ +import sys + +sys.path = [p for p in sys.path if p] + from sys import argv, exit, stdin try: @@ -7164,6 +7168,17 @@ PROMPT string, is made unless there is a single candidate." (unless (string-empty-p statement) statement))) +(defconst python--run-module "\ +import runpy, sys + +sys.path = [p for p in sys.path if p] + +runpy.run_module(sys.argv.pop(1), run_name='__main__', alter_sys=True) +" + "Script to run a Python module. +It removes the leading empty string from `sys.path' before executing the +module.") + (defun python--do-isort (&rest args) "Edit the current buffer using isort called with ARGS. Return non-nil if the buffer was actually modified." @@ -7178,7 +7193,7 @@ Return non-nil if the buffer was actually modified." (append (split-string-shell-command python-interpreter-args) - '("-m" "isort" "-") + `("-c" ,python--run-module "isort" "-") args))) (tick (buffer-chars-modified-tick))) (unless (eq 0 status) @@ -7272,7 +7287,7 @@ and may appear to hang." (append (split-string-shell-command python-interpreter-args) - '("-m" "pyflakes")))) + `("-c" ,python--run-module "pyflakes")))) (goto-char (point-min)) (when (looking-at-p ".* No module named pyflakes$") (error "%s couldn't find pyflakes" python-interpreter)) diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el index 4d025eeb18d..f9d4310f367 100644 --- a/lisp/progmodes/sh-script.el +++ b/lisp/progmodes/sh-script.el @@ -1492,12 +1492,19 @@ implementations. Currently there are two: `sh-mode' and (setq-local skeleton-filter-function #'sh-feature) (setq-local skeleton-newline-indent-rigidly t) (setq-local defun-prompt-regexp - (concat - "^\\(" - "\\(function[ \t]\\)?[ \t]*[[:alnum:]_]+[ \t]*([ \t]*)" - "\\|" - "function[ \t]+[[:alnum:]_]+[ \t]*\\(([ \t]*)\\)?" - "\\)[ \t]*")) + (let* ((fname-char "^ \t\n\r\v\f\\\"'`$|&;()<>") + (fname-char0 (concat fname-char "#")) + (fname-re + (concat "[" fname-char0 "]" + "[" fname-char "]*"))) + (concat + "^\\([ \t]*" + "\\(" + "\\(function[ \t]+\\)?" fname-re "[ \t]*([ \t]*)" + "\\|" + "function[ \t]+" fname-re "[ \t]*\\(([ \t]*)\\)?" + "\\)" + "\\)[ \t]*"))) (setq-local add-log-current-defun-function #'sh-current-defun-name) (add-hook 'completion-at-point-functions #'sh-completion-at-point-function nil t) diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index 61e281310aa..dc951811bb3 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -225,7 +225,7 @@ Argument LANGUAGE is either `typescript' or `tsx'." "get" "if" "implements" "import" "in" "instanceof" "interface" "is" "infer" "keyof" "let" "namespace" "new" "of" "private" "protected" "public" "readonly" "return" "satisfies" "set" "static" "switch" - "target" "throw" "try" "type" "typeof" "var" "void" + "target" "throw" "try" "type" "typeof" "using" "var" "void" "while" "with" "yield") "TypeScript keywords for tree-sitter font-locking.") @@ -860,8 +860,8 @@ at least 3 (which is the default value)." (match-beginning 0) (match-end 0) 'syntax-table (string-to-syntax (cond - ((equal (match-string 0) "<") "(<") - ((equal (match-string 0) ">") ")>") + ((equal (match-string 0) "<") "(>") + ((equal (match-string 0) ">") ")<") (t "."))))))))))) ;;;###autoload diff --git a/lisp/progmodes/verilog-mode.el b/lisp/progmodes/verilog-mode.el index 961d7b57fa4..999f6cda732 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: 2026.01.18.088738971 +;; Version: 2026.04.14.010117132 ;; Yoni Rabkin <[email protected]> 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 "2026-01-18-54a0c9b-vpo-GNU" +(defconst verilog-mode-version "2026-04-14-09a600c-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.") @@ -2790,9 +2790,9 @@ find the errors." "\\|\\(\\<table\\>\\)" ;7 "\\|\\(\\<specify\\>\\)" ;8 "\\|\\(\\<function\\>\\)" ;9 - "\\|\\(\\(?:\\<\\(?:virtual\\|protected\\|static\\)\\>\\s-+\\)*\\<function\\>\\)" ;10 + "\\|\\(\\(?:\\<\\(?:virtual\\|protected\\|local\\|static\\)\\>\\s-+\\)*\\<function\\>\\)" ;10 "\\|\\(\\<task\\>\\)" ;11 - "\\|\\(\\(?:\\<\\(?:virtual\\|protected\\|static\\)\\>\\s-+\\)*\\<task\\>\\)" ;12 + "\\|\\(\\(?:\\<\\(?:virtual\\|protected\\|local\\|static\\)\\>\\s-+\\)*\\<task\\>\\)" ;12 "\\|\\(\\<generate\\>\\)" ;13 "\\|\\(\\<covergroup\\>\\)" ;14 "\\|\\(\\(?:\\(?:\\<cover\\>\\s-+\\)\\|\\(?:\\<assert\\>\\s-+\\)\\)*\\<property\\>\\)" ;15 @@ -6406,7 +6406,7 @@ Jump from end to matching begin, from endcase to matching case, and so on." "\\(\\<endcase\\>\\)\\|\\(\\<join\\(_any\\|_none\\)?\\>\\)" ))) ((looking-at "\\<endtask\\>") ;; 2: Search back for matching task - (setq reg "\\(\\<task\\>\\)\\|\\(\\(\\<\\(virtual\\|protected\\|static\\)\\>\\s-+\\)+\\<task\\>\\)") + (setq reg "\\(\\<task\\>\\)\\|\\(\\(\\<\\(virtual\\|protected\\|local\\|static\\)\\>\\s-+\\)+\\<task\\>\\)") (setq nesting 'no)) ((looking-at "\\<endcase\\>") (catch 'nesting @@ -6430,7 +6430,7 @@ Jump from end to matching begin, from endcase to matching case, and so on." (setq reg "\\(\\<specify\\>\\)\\|\\(\\<endspecify\\>\\)" )) ((looking-at "\\<endfunction\\>") ;; 8: Search back for matching function - (setq reg "\\(\\<function\\>\\)\\|\\(\\(\\<\\(virtual\\|protected\\|static\\)\\>\\s-+\\)+\\<function\\>\\)") + (setq reg "\\(\\<function\\>\\)\\|\\(\\(\\<\\(virtual\\|protected\\|local\\|static\\)\\>\\s-+\\)+\\<function\\>\\)") (setq nesting 'no)) ;;(setq reg "\\(\\<function\\>\\)\\|\\(\\<endfunction\\>\\)" )) ((looking-at "\\<endgenerate\\>") @@ -7396,7 +7396,7 @@ Do not count named blocks or case-statements." (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\\>\\)")) + (looking-at "\\(\\<\\(virtual\\|protected\\|local\\|static\\)\\>\\s-+\\)?\\(\\<task\\>\\|\\<function\\>\\)")) (setq pos-arg-paren (save-excursion (goto-char start-pos) (verilog-backward-up-list 1) diff --git a/lisp/replace.el b/lisp/replace.el index 4bb91fbd6a0..e7407869ca2 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -1982,12 +1982,12 @@ See also `multi-occur'." (source-buffer-default-directory default-directory)) ;; Handle the case where one of the buffers we're searching is the ;; output buffer. Just rename it. - (when (member buf-name - ;; FIXME: Use cl-exists. - (mapcar - (lambda (boo) - (buffer-name (if (overlayp boo) (overlay-buffer boo) boo))) - active-bufs)) + (when (seq-some (lambda (boo) + (equal buf-name + (buffer-name (if (overlayp boo) + (overlay-buffer boo) + boo)))) + active-bufs) (with-current-buffer buf-name (rename-uniquely))) diff --git a/lisp/simple.el b/lisp/simple.el index fd9ba28c762..1f7d57f299a 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -5579,12 +5579,14 @@ These commands include \\[set-mark-command] and \\[start-kbd-macro]." "Function to perform the filtering in `filter-buffer-substring'. The function is called with the same 3 arguments (BEG END DELETE) that `filter-buffer-substring' received. It should return the -buffer substring between BEG and END, after filtering. If DELETE is -non-nil, it should delete the text between BEG and END from the buffer.") +buffer substring between BEG and END, regardless of the order of +BEG and END, after filtering. If DELETE is non-nil, it should +delete the text between BEG and END from the buffer.") (defun filter-buffer-substring (beg end &optional delete) "Return the buffer substring between BEG and END, after filtering. If DELETE is non-nil, delete the text between BEG and END from the buffer. +The order of BEG and END does not matter. This calls the function that `filter-buffer-substring-function' specifies \(passing the same three arguments that it received) to do the work, @@ -10025,10 +10027,12 @@ makes it easier to edit it." (call-interactively `(lambda (arg) (interactive ,prop) arg)) - (read-from-minibuffer prompt nil - read-expression-map t - 'set-variable-value-history - (format "%S" (symbol-value var))))))) + (read-from-minibuffer + prompt nil + read-expression-map t + 'set-variable-value-history + (when (boundp var) + (format "%S" (symbol-value var)))))))) (list var val current-prefix-arg))) (and (custom-variable-p variable) diff --git a/lisp/startup.el b/lisp/startup.el index e6f2087604f..24cb3fc2582 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -1263,22 +1263,23 @@ unconditionally." (not (string-match-p ignored (file-name-nondirectory dir))))) (dir (expand-file-name user-lisp-directory)) (backup-inhibited t) - (dirs (list dir))) + (dirs (list dir)) (files '())) (add-to-list 'load-path (directory-file-name dir)) (dolist (file (directory-files-recursively dir "" t pred t)) (cond ((and (file-regular-p file) (string-suffix-p ".el" file)) - (unless just-activate - (with-demoted-errors "Error while compiling: %S" - (byte-recompile-file file force 0) - (when (native-comp-available-p) - (native-compile-async file))))) + (push file files)) ((and (file-directory-p file) (not (string-match-p ignored (file-name-nondirectory file)))) (add-to-list 'load-path (directory-file-name file)) (push file dirs)))) (unless just-activate - (loaddefs-generate dirs autoload-file nil nil nil force)) + (loaddefs-generate dirs autoload-file nil nil nil force) + (dolist (file files) + (with-demoted-errors "Error while compiling: %S" + (byte-recompile-file file force 0) + (when (native-comp-available-p) + (native-compile-async file))))) (when (file-exists-p autoload-file) (load autoload-file nil t)))) diff --git a/lisp/subr.el b/lisp/subr.el index cea786ae64d..60a57688f73 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -2013,19 +2013,6 @@ and `event-end' functions." (nth 1 position)))) (and (symbolp area) area))) -(defun posn-point (position) - "Return the buffer location in POSITION. -POSITION should be a list of the form returned by the `event-start' -and `event-end' functions. -Returns nil if POSITION does not correspond to any buffer location (e.g. -a click on a scroll bar)." - (declare (side-effect-free t)) - (or (nth 5 position) - (let ((pt (nth 1 position))) - (or (car-safe pt) - ;; Apparently this can also be `vertical-scroll-bar' (bug#13979). - (if (integerp pt) pt))))) - (defun posn-set-point (position) "Move point to POSITION. Select the corresponding window as well." @@ -5415,7 +5402,7 @@ See the related form `with-temp-buffer-window'." (with-current-buffer (get-buffer-create ,bufname) (prog1 (current-buffer) (kill-all-local-variables) - ;; FIXME: delete_all_overlays + (delete-all-overlays) (setq default-directory ,old-dir) (setq buffer-read-only nil) (setq buffer-file-name nil) @@ -7108,7 +7095,8 @@ to deactivate this transient map, regardless of KEEP-PRED." ;; MESSAGE ;; MIN-CHANGE ;; MIN-TIME -;; MESSAGE-SUFFIX]) +;; UNUSED (formerly SUFFIX) +;; CONTEXT]) ;; ;; This weirdness is for optimization reasons: we want ;; `progress-reporter-update' to be as fast as possible, so @@ -7120,15 +7108,18 @@ to deactivate this transient map, regardless of KEEP-PRED." (defvar progress-reporter-update-functions (list #'progress-reporter-echo-area) "Special hook run on progress-reporter updates. -Each function is called with two arguments: +Each function is called with three arguments: REPORTER is the result of a call to `make-progress-reporter'. STATE can be one of: - A float representing the percentage complete in the range 0.0-1.0 for a numeric reporter. - A monotonically increasing integer for a pulsing reporter. -- The symbol `done' to indicate that the progress reporter is complete.") +- The symbol `done' to indicate that the progress reporter is complete. +UPDATE-TEXT is a string that a progress-reporter back-end might display +as a result of this update. A typical use is as the \"step\" of the +progress reporting process.") -(defsubst progress-reporter-update (reporter &optional value suffix) +(defsubst progress-reporter-update (reporter &optional value update-text) "Report progress of an operation, by default, in the echo area. REPORTER should be the result of a call to `make-progress-reporter'. @@ -7137,10 +7128,11 @@ made using non-nil MIN-VALUE and MAX-VALUE arguments to `make-progress-reporter'---then VALUE should be a number between MIN-VALUE and MAX-VALUE. -Optional argument SUFFIX is a string to be displayed after REPORTER's -main message and progress text. If REPORTER is a non-numerical -reporter, then VALUE should be nil, or a string to use instead of -SUFFIX. +Optional argument UPDATE-TEXT is a string that a progress-reporter +back-end might display as a result of this update. A typical use is as +the \"step\" of the progress reporting process. If REPORTER is a +non-numerical reporter, then VALUE should be nil, or a string to use +instead of UPDATE-TEXT. See `progress-reporter-update-functions' for the list of functions called on each update. @@ -7150,7 +7142,7 @@ last update is too small or insufficient time has passed, it does nothing." (when (or (not (numberp value)) ; For pulsing reporter (>= value (car reporter))) ; For numerical reporter - (progress-reporter-do-update reporter value suffix))) + (progress-reporter-do-update reporter value update-text))) (defun make-progress-reporter (message &optional min-value max-value current-value min-change min-time @@ -7200,7 +7192,7 @@ the echo area progress reports may be muted if the echo area is busy." message (if min-change (max (min min-change 50) 1) 1) min-time - ;; SUFFIX + ;; Unused (formerly SUFFIX). nil ;; context)))) @@ -7218,24 +7210,26 @@ the echo area progress reports may be muted if the echo area is busy." "Return REPORTER's context." (aref (cdr reporter) 7)) -(defun progress-reporter-force-update (reporter &optional value new-message suffix) +(defun progress-reporter-force-update (reporter &optional + value new-message update-text) "Report progress of an operation in the echo area unconditionally. -REPORTER, VALUE, and SUFFIX are the same as in `progress-reporter-update'. +REPORTER, VALUE, and UPDATE-TEXT are the same as in +`progress-reporter-update'. NEW-MESSAGE, if non-nil, sets a new message for the reporter." (let ((parameters (cdr reporter))) (when new-message (aset parameters 3 new-message)) (when (aref parameters 0) (aset parameters 0 (float-time))) - (progress-reporter-do-update reporter value suffix))) + (progress-reporter-do-update reporter value update-text))) (defvar progress-reporter--pulse-characters ["-" "\\" "|" "/"] "Characters to use for pulsing progress reporters.") -(defun progress-reporter-echo-area (reporter state) +(defun progress-reporter-echo-area (reporter state update-text) "Progress reporter echo area update function. -REPORTER and STATE are the same as in +REPORTER, STATE, and UPDATE-TEXT are the same as in `progress-reporter-update-functions'. Do not emit a message if the reporter context is `async' and the echo @@ -7244,21 +7238,22 @@ area is busy with something else." (unless (and (eq (progress-reporter-context reporter) 'async) (current-message) (not (string-prefix-p text (current-message)))) + (setq update-text (concat (if update-text " " "") update-text)) (pcase state ((pred floatp) (if (plusp state) - (message "%s%d%%" text (* state 100.0)) - (message "%s" text))) + (message "%s%d%%%s" text (* state 100.0) update-text) + (message "%s%s" text update-text))) ((pred integerp) (let ((message-log-max nil) (pulse-char (aref progress-reporter--pulse-characters (mod state (length progress-reporter--pulse-characters))))) - (message "%s %s" text pulse-char))) + (message "%s %s%s" text pulse-char update-text))) ('done (message "%sdone" text)))))) -(defun progress-reporter-do-update (reporter value &optional suffix) +(defun progress-reporter-do-update (reporter value &optional update-text) (let* ((parameters (cdr reporter)) (update-time (aref parameters 0)) (min-value (aref parameters 1)) @@ -7292,31 +7287,26 @@ area is busy with something else." (setcar reporter (ceiling (car reporter)))) ;; Print message only if enough time has passed (when enough-time-passed - (if suffix - (aset parameters 6 suffix) - (setq suffix (or (aref parameters 6) ""))) (run-hook-with-args 'progress-reporter-update-functions reporter - (/ percentage 100.0))))) + (/ percentage 100.0) + update-text)))) ;; Pulsing indicator (enough-time-passed - (when (and value (not suffix)) - (setq suffix value)) - (if suffix - (aset parameters 6 suffix) - (setq suffix (or (aref parameters 6) ""))) (let ((index (1+ (car reporter)))) (setcar reporter index) (run-hook-with-args 'progress-reporter-update-functions reporter - index)))))) + index + (or update-text value))))))) (defun progress-reporter-done (reporter) "Print reporter's message followed by word \"done\" in echo area. Call the functions on `progress-reporter-update-functions`." (run-hook-with-args 'progress-reporter-update-functions reporter - 'done)) + 'done + nil)) (defmacro dotimes-with-progress-reporter (spec reporter-or-message &rest body) "Loop a certain number of times and report progress in the echo area. @@ -7807,7 +7797,7 @@ seconds." (unless (y-or-n-p-with-timeout (format "Error %s; continue?" (error-message-string err)) 5 t) - (error err)))) + (signal err)))) ;; Continue running. nil))) diff --git a/lisp/system-taskbar.el b/lisp/system-taskbar.el index 973b426e026..d1fe276844d 100644 --- a/lisp/system-taskbar.el +++ b/lisp/system-taskbar.el @@ -273,9 +273,9 @@ If PROGRESS is nil, remove the progress indicator.") ;; `progress-reporter' support. -(defun system-taskbar--progress-reporter-update (_reporter state) +(defun system-taskbar--progress-reporter-update (_reporter state _update-text) "Progress reporter system taskbar update function. -REPORTER and STATE are the same as in +REPORTER, STATE, and UPDATE-TEXT are the same as in `progress-reporter-update-functions'." (when system-taskbar-mode (pcase state diff --git a/lisp/textmodes/markdown-ts-mode.el b/lisp/textmodes/markdown-ts-mode.el index fb895c9231f..6b0b0424095 100644 --- a/lisp/textmodes/markdown-ts-mode.el +++ b/lisp/textmodes/markdown-ts-mode.el @@ -1600,19 +1600,14 @@ properties `markdown-ts-code-block-language' and (markdown-ts--code-block-language-mode lang))) (existing (seq-find (lambda (ov) (overlay-get ov 'markdown-ts-code-block)) - (overlays-at node-start)))) + (overlays-in node-start node-end)))) (if existing (progn (move-overlay existing node-start node-end) (overlay-put existing 'face face) (overlay-put existing 'markdown-ts-code-block-language lang) (overlay-put existing 'markdown-ts-code-block-mode mode)) - (let ((ov (make-overlay node-start node-end nil t nil))) - ;; Markers need to be set only once. - (overlay-put ov 'markdown-ts-code-beg-marker (set-marker (make-marker) - node-start)) - (overlay-put ov 'markdown-ts-code-end-marker (set-marker (make-marker) - node-end)) + (let ((ov (make-overlay node-start node-end nil nil t))) (overlay-put ov 'markdown-ts-code-block t) (overlay-put ov 'face face) (overlay-put ov 'priority '(nil . 10)) @@ -1623,7 +1618,8 @@ properties `markdown-ts-code-block-language' and (defun markdown-ts-at-code-block-p (&optional pos) "Return non nil if point is in a code block. If POS is nil, use point." - (get-char-property (or pos (point)) 'markdown-ts-code-block)) + (cl-some (lambda (ov) (overlay-get ov 'markdown-ts-code-block)) + (overlays-at (or pos (point))))) (defun markdown-ts-code-block-language-at (&optional pos) "Return the language symbol of the code block at POS. @@ -1631,14 +1627,18 @@ If POS is nil, use point. Returns nil if POS is not inside a fenced code block. This works regardless of whether a guest tree-sitter parser is active, since the language is stored on the code block overlay by the host parser's fontification." - (get-char-property (or pos (point)) 'markdown-ts-code-block-language)) + (cl-some (lambda (ov) (overlay-get ov 'markdown-ts-code-block-language)) + (overlays-at (or pos (point))))) (defun markdown-ts-code-block-mode-at (&optional pos) "Return the major mode for the code block at POS. If POS is nil, use point. Returns nil if POS is not inside a fenced -code block or if the language has no recognized mode." +code block, or `markdown-ts-default-code-block-mode' if the language has +no recognized mode." + (setq pos (or pos (point))) (when (markdown-ts-at-code-block-p pos) - (or (get-char-property (or pos (point)) 'markdown-ts-code-block-mode) + (or (cl-some (lambda (ov) (overlay-get ov 'markdown-ts-code-block-mode)) + (overlays-at pos)) markdown-ts-default-code-block-mode))) (defun markdown-ts--host-ranges-notifier (ranges _parser) @@ -2901,8 +2901,8 @@ node as a non-ts mode." (mode (alist-get lang markdown-ts--code-block-non-ts-modes)) (tick (buffer-chars-modified-tick)) (block-start (treesit-node-start node)) - ;; Cannot use markers 'markdown-ts-code-beg-marker - ;; 'markdown-ts-code-end-marker they are set after this + ;; Cannot rely on anything set in + ;; `markdown-ts--fontify-code-block' that runs after this ;; function runs. (node-start (save-excursion (goto-char (treesit-node-start node)) @@ -2987,7 +2987,7 @@ content as a standalone markdown document, which is what we want." 'markdown-ts-inhibit-code-block-mode-warnings (delay-mode-hooks (funcall mode))) (narrow-to-region beg end) - (font-lock-ensure) + (let ((font-lock-dont-widen t)) (font-lock-ensure)) (let ((pos (point-min))) (while (< pos (point-max)) (let ((next (next-single-property-change @@ -3198,8 +3198,12 @@ command will run in the context of the `markdown-ts-mode' buffer." (defun markdown-ts--run-command-in-code-block (block-mode command &rest args) "Run COMMAND in BLOCK-MODE. ARGS are captured by `markdown-ts--maybe-run-command-in-code-block'." - (when-let* ((beg (get-char-property (point) 'markdown-ts-code-beg-marker)) - (end (get-char-property (point) 'markdown-ts-code-end-marker)) + (when-let* ((ov (cl-some + (lambda (ov) + (when (overlay-get ov 'markdown-ts-code-block) ov)) + (overlays-at (point)))) + (beg (overlay-start ov)) + (end (overlay-end ov)) (str (buffer-substring-no-properties beg end))) ;; Use a temp (or work) buffer because treesit currently confuses ;; nodes in an indirect buffer even if the indirect buffer is not @@ -3212,8 +3216,8 @@ ARGS are captured by `markdown-ts--maybe-run-command-in-code-block'." (region-end (use-region-end)) (adj-point (1+ (- orig-point beg))) (adj-mark (when orig-mark (1+ (- orig-mark beg)))) - (adj-region-beg (when region-beg (1+ (- orig-point region-beg)))) - (adj-region-end (when region-end (1+ (- orig-point region-end)))) + (adj-region-beg (when region-beg (1+ (- region-beg beg)))) + (adj-region-end (when region-end (1+ (- region-end beg)))) (point-delta 0) (ignore-output (memq command markdown-ts-code-block-ignore-output-commands)) @@ -3348,18 +3352,22 @@ With the prefix argument ARG, remain within the current code block." (defun markdown-ts--table-abutting-pos (pos) "Adjust POS to abut its closest text. -Return pos adjusted to the position of the nearest non-blank character. -Otherwise, return nil, for example, if the line is empty." +If POS is already in a table, return POS. If not, adjust POS to the +nearest non-blank character, looking first forward and then backward +adjusting, if it is in a table, return the adjusted POS. Otherwise +return nil, for example, if the line is empty." (save-excursion (goto-char pos) - (skip-chars-forward "[[:blank:]]" (pos-eol)) - (if (eq pos (pos-eol)) - (progn - (goto-char pos) - (skip-chars-backward "[[:blank:]]" (pos-bol)) - (unless (eq pos (pos-bol)) - (max (point-min) (1- (point))))) - (min (point-max) (1+ (point)))))) + (if (markdown-ts--table-node-row nil pos) + pos + (skip-chars-forward "[[:blank:]]" (pos-eol)) + (if (markdown-ts--table-node-row) + (point) + (goto-char pos) + (skip-chars-backward "[[:blank:]]" (pos-bol)) + (unless (eq (point) (pos-bol)) + (if (markdown-ts--table-node-row nil (1- (point))) + (1- (point)))))))) (defun markdown-ts--table-node-cell (&optional node pos abutting) "Compute table cell from named NODE at POS. @@ -5116,7 +5124,6 @@ On a heading, call `outline-cycle'. Otherwise do nothing." :doc "Keymap for `markdown-ts-code-block-in-context-mode'. These override keys in `markdown-ts-mode-map' to support executing their commands in a code-block context." - :parent markdown-ts-mode-map :menu nil "M-." #'markdown-ts--code-block-xref-find-definitions "TAB" #'indent-for-tab-command @@ -5129,10 +5136,10 @@ commands in a code-block context." :doc "Keymap for `markdown-ts-in-table-mode'. These override keys in `markdown-ts-mode-map' to support executing their commands in a table context." - :parent markdown-ts-mode-map :menu nil "<return>" #'markdown-ts-table-next-row "S-<return>" #'markdown-ts-table-previous-row + "M-RET" #'markdown-ts-table-insert-row-below "<tab>" #'markdown-ts-table-next-cell "<backtab>" #'markdown-ts-table-previous-cell "M-<up>" #'markdown-ts-table-move-row-up @@ -5492,20 +5499,24 @@ This enables the keymap `markdown-ts-code-block-in-context-mode-map'." (defun markdown-ts--code-block-in-context-mode-update-ov () "Manage `markdown-ts--code-block-in-context-mode-ov'." (cond (markdown-ts-code-block-in-context-mode - (let ((beg (get-char-property (point) 'markdown-ts-code-beg-marker)) - (end (get-char-property (point) 'markdown-ts-code-end-marker))) + (when-let* ((ov (cl-some + (lambda (ov) + (when (overlay-get ov 'markdown-ts-code-block) ov)) + (overlays-at (point)))) + (beg (overlay-start ov)) + (end (overlay-end ov))) (if markdown-ts--code-block-in-context-mode-ov (move-overlay markdown-ts--code-block-in-context-mode-ov beg end) (setq markdown-ts--code-block-in-context-mode-ov - (make-overlay beg end nil t nil))) - (overlay-put markdown-ts--code-block-in-context-mode-ov - 'markdown-ts-in-code-block t) - (overlay-put markdown-ts--code-block-in-context-mode-ov - 'evaporate t) - (overlay-put markdown-ts--code-block-in-context-mode-ov - 'priority '(nil . 20)) - (overlay-put markdown-ts--code-block-in-context-mode-ov - 'face 'markdown-ts-in-code-block))) + (make-overlay beg end nil nil t)) + (overlay-put markdown-ts--code-block-in-context-mode-ov + 'markdown-ts-in-code-block t) + (overlay-put markdown-ts--code-block-in-context-mode-ov + 'evaporate t) + (overlay-put markdown-ts--code-block-in-context-mode-ov + 'priority '(nil . 20)) + (overlay-put markdown-ts--code-block-in-context-mode-ov + 'face 'markdown-ts-in-code-block)))) (t (when markdown-ts--code-block-in-context-mode-ov (delete-overlay markdown-ts--code-block-in-context-mode-ov))))) @@ -5587,22 +5598,21 @@ It is up to this function's callers to call (end (treesit-node-end table))) (if markdown-ts--in-table-mode-ov ;; Move the overlay, if needed, and reset the tick if so. - (when (not (eq (overlay-start markdown-ts--in-table-mode-ov) - beg)) + (unless (and (eq (overlay-start markdown-ts--in-table-mode-ov) beg) + (eq (overlay-end markdown-ts--in-table-mode-ov) end)) (move-overlay markdown-ts--in-table-mode-ov beg end) (overlay-put markdown-ts--in-table-mode-ov 'markdown-ts-in-table-tick nil)) (setq markdown-ts--in-table-mode-ov - (make-overlay beg end nil t nil))) - (overlay-put markdown-ts--in-table-mode-ov - 'markdown-ts-in-table t) - (overlay-put markdown-ts--in-table-mode-ov - 'evaporate t) - (overlay-put markdown-ts--in-table-mode-ov - 'priority '(nil . 20)) - (overlay-put markdown-ts--in-table-mode-ov - 'face 'markdown-ts-in-table) - )) + (make-overlay beg end nil t t)) + (overlay-put markdown-ts--in-table-mode-ov + 'markdown-ts-in-table t) + (overlay-put markdown-ts--in-table-mode-ov + 'evaporate t) + (overlay-put markdown-ts--in-table-mode-ov + 'priority '(nil . 20)) + (overlay-put markdown-ts--in-table-mode-ov + 'face 'markdown-ts-in-table)))) (t (when markdown-ts--in-table-mode-ov (delete-overlay markdown-ts--in-table-mode-ov))))) diff --git a/lisp/textmodes/yaml-ts-mode.el b/lisp/textmodes/yaml-ts-mode.el index 5afd4d2d111..37925f69782 100644 --- a/lisp/textmodes/yaml-ts-mode.el +++ b/lisp/textmodes/yaml-ts-mode.el @@ -274,6 +274,7 @@ Calls REPORT-FN directly." ;; Indentation. (setq-local indent-tabs-mode nil) + (setq-local tab-width 2) ;; Font-lock. (setq-local treesit-font-lock-settings yaml-ts-mode--font-lock-settings) diff --git a/lisp/time-stamp.el b/lisp/time-stamp.el index df5acfa629a..d2bb7acc470 100644 --- a/lisp/time-stamp.el +++ b/lisp/time-stamp.el @@ -57,7 +57,7 @@ with %, which are converted as follows: %S seconds %w day number of week, Sunday is 0 %Y 4-digit year %y 2-digit year -%Z time zone name: `EST' +%Z time zone name: `JST' %-z zone offset with hour: `-08' %:::z adds colons as needed: `+05:30' %5z zone offset with mins: `-0800' %:z adds colon: `-08:00' diff --git a/lisp/timezone.el b/lisp/timezone.el index 63f58a477b0..643e974ece0 100644 --- a/lisp/timezone.el +++ b/lisp/timezone.el @@ -52,8 +52,8 @@ ("GMT-10" . -1000) ("GMT-11" . -1100) ("GMT-12" . -1200)) "Time differentials of timezone from GMT in +-HHMM form. This list is obsolescent, and is present only for backwards compatibility, -because time zone names are ambiguous in practice. -Use `current-time-zone' instead.") +because time zone names are ambiguous in practice; for example, abbreviations +like \"PST\" can change meaning with time. Use `current-time-zone' instead.") (defvar timezone-months-assoc '(("JAN" . 1)("FEB" . 2)("MAR" . 3) diff --git a/lisp/treesit.el b/lisp/treesit.el index e2e62bb71a2..107b41abef6 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -58,7 +58,7 @@ (require 'cl-lib) (require 'font-lock) (require 'seq) -(require 'prog-mode) ; For `prog--text-at-point-p'. +(require 'prog-mode) ; For `prog--text-at-point-or-region-p'. ;;; Function declarations @@ -680,6 +680,11 @@ If none are valid, return nil." ;;; Range API supplement +;; See bug#81019. +(defvar treesit--embed-languages-need-full-parse '(markdown-inline) + "Languages that requires a full parse when used as embedded languages. +This variable is not intended for general use.") + (defvar treesit--range-verbose nil "If non-nil, print verbose debugging info for setting ranges. Useful when your multi-parser setup doesn't seem to work.") @@ -1094,6 +1099,14 @@ RANGES is a list of (START . END) or just (START . END)." (when (and (null new-ranges) treesit--range-verbose) (message "Setting empty ranges to %s\nRanges for embedded parser :%s\nRanges for host parser: %s\nIntersection is empty" new-ranges-1 embed-parser host-parser)) + ;; Due to some tree-sitter bug[1], we need to force a full reparse for + ;; some languages to get a correct parse tree. + ;; [1] https://github.com/tree-sitter/tree-sitter/issues/5636 + (when (memq (treesit-parser-language embed-parser) + treesit--embed-languages-need-full-parse) + (treesit-parser-set-included-ranges + embed-parser `((,(point-min) . ,(point-min)))) + (treesit-parser-root-node embed-parser)) ;; When there's no range for the embedded language, set it's range ;; to a dummy (1 . 1), otherwise it would be set to the whole ;; buffer, which is not what we want. @@ -1585,7 +1598,7 @@ variable `treesit-font-lock-feature-list'. Setting this variable directly with `setq' or `let' doesn't work; use `setopt' or \\[customize-option] instead." - :type 'integer + :type '(choice integer (alist :key-type symbol :value-type integer)) :set #'treesit--font-lock-level-setter :version "29.1") @@ -3797,7 +3810,7 @@ the current line if the beginning of the defun is indented." Return the first non-nil evaluation of BODY. \(fn (SYM VAL) &rest BODY)" - (declare (indent 1)) + (declare (indent 1) (debug ((symbolp form) body))) (let ((result-sym (gensym)) (val-sym (gensym)) (sym (car sym-val)) @@ -4152,7 +4165,7 @@ This is a tree-sitter implementation of `prog-fill-reindent-defun'. JUSTIFY is the same as in `fill-paragraph'." (interactive "P") (save-excursion - (if (prog--text-at-point-p) + (if (prog--text-at-point-or-region-p) (fill-paragraph justify (region-active-p)) (let* ((treesit-defun-tactic 'parent-first) (node (treesit-defun-at-point))) diff --git a/lisp/url/url-util.el b/lisp/url/url-util.el index d091092783c..fb70d553768 100644 --- a/lisp/url/url-util.el +++ b/lisp/url/url-util.el @@ -230,10 +230,12 @@ Will not do anything if `url-show-status' is nil." (setq cur (concat cur "="))) (when (string-match "=" cur) - (setq key (url-unhex-string (substring cur 0 (match-beginning 0)) - allow-newlines)) - (setq val (url-unhex-string (substring cur (match-end 0) nil) - allow-newlines)) + (let ((beg (match-beginning 0)) + (end (match-end 0))) + (setq key (url-unhex-string (substring cur 0 beg) + allow-newlines)) + (setq val (url-unhex-string (substring cur end nil) + allow-newlines))) (if downcase (setq key (downcase key))) (setq cur (assoc key retval)) diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el index 32f34ebaa10..c27abda1af9 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el @@ -1176,6 +1176,10 @@ PREFIX is only used internally: don't use it." (or (ignore-errors (diff-beginning-of-file)) (re-search-forward diff-file-header-re nil t))) (let ((fs (diff-hunk-file-names old))) + (when (memq diff-buffer-type '(git hg)) + (setq fs + (mapcar (lambda (f) (replace-regexp-in-string "\\`[icoawib]/" "" f)) + fs))) (if prefix (setq fs (mapcar (lambda (f) (concat prefix f)) fs))) (or ;; use any previously used preference @@ -1186,7 +1190,10 @@ PREFIX is only used internally: don't use it." (if (and newfile (file-exists-p newfile)) (cl-return newfile)))) ;; look for each file in turn. If none found, try again but ;; ignoring the first level of directory, ... - (cl-do* ((files fs (delq nil (mapcar #'diff-filename-drop-dir files))) + (cl-do* ((files fs (and (not (and (memq diff-buffer-type '(git hg)) + (not old) + (equal null-device (cadr files)))) + (delq nil (mapcar #'diff-filename-drop-dir files)))) (file nil nil)) ((or (null files) (setq file (cl-do* ((files files (cdr files)) @@ -1212,10 +1219,6 @@ PREFIX is only used internally: don't use it." (let ((file (or (car fs) "")) (creation (equal null-device (car (diff-hunk-file-names (not old)))))) - (when (and (memq diff-buffer-type '(git hg)) - (string-match "/" file)) - ;; Strip the dst prefix (like b/) if diff is from Git/Hg. - (setq file (substring file (match-end 0)))) (setq file (expand-file-name file)) (setq file (read-file-name (format "Use file %s: " file) @@ -1290,7 +1293,7 @@ else cover the whole buffer." (goto-char start) (while (and (re-search-forward (concat "^\\(\\(---\\) .+\n\\(\\+\\+\\+\\) .+\\|" - diff-hunk-header-re-unified ".*\\)$") + diff-hunk-header-re-unified "\\( .*\\)?\\)$") nil t) (< (point) end)) (combine-after-change-calls @@ -1305,13 +1308,14 @@ else cover the whole buffer." (lines1 (or (match-string 5) "1")) (line2 (match-string 6)) (lines2 (or (match-string 7) "1")) + (comment (match-string 8)) ;; Variables to use the special undo function. (old-undo buffer-undo-list) (old-end (marker-position end)) (start (match-beginning 0)) (reversible t)) (replace-match - (concat "***************\n*** " line1 "," + (concat "***************" comment "\n*** " line1 "," (number-to-string (+ (string-to-number line1) (string-to-number lines1) -1)) @@ -1414,7 +1418,7 @@ With a prefix argument, convert unified format to context format." (inhibit-read-only t)) (save-excursion (goto-char start) - (while (and (re-search-forward "^\\(\\(\\*\\*\\*\\) .+\n\\(---\\) .+\\|\\*\\{15\\}.*\n\\*\\*\\* \\([0-9]+\\),\\(-?[0-9]+\\) \\*\\*\\*\\*\\)\\(?: \\(.*\\)\\|$\\)" nil t) + (while (and (re-search-forward "^\\(\\(\\*\\*\\*\\) .+\n\\(---\\) .+\\|\\*\\{15\\}\\( .*\\)?\n\\*\\*\\* \\([0-9]+\\),\\(-?[0-9]+\\) \\*\\*\\*\\*\\)$" nil t) (< (point) end)) (combine-after-change-calls (if (match-beginning 2) @@ -1424,15 +1428,14 @@ With a prefix argument, convert unified format to context format." (replace-match "+++" t t nil 3) (replace-match "---" t t nil 2)) ;; we matched a hunk header - (let ((line1s (match-string 4)) - (line1e (match-string 5)) + (let ((comment (match-string 4)) + (line1s (match-string 5)) + (line1e (match-string 6)) (pt1 (match-beginning 0)) ;; Variables to use the special undo function. (old-undo buffer-undo-list) (old-end (marker-position end)) - ;; We currently throw away the comment that can follow - ;; the hunk header. FIXME: Preserve it instead! - (reversible (not (match-end 6)))) + (reversible t)) (replace-match "") (unless (re-search-forward diff-context-mid-hunk-header-re nil t) @@ -1487,7 +1490,8 @@ With a prefix argument, convert unified format to context format." " +" line2s "," (number-to-string (- (string-to-number line2e) (string-to-number line2s) - -1)) " @@")) + -1)) + " @@" (or comment ""))) (set-marker pt2 nil) ;; The whole procedure succeeded, let's replace the myriad ;; of undo elements with just a single special one. @@ -1822,7 +1826,7 @@ modified lines of the diff." (setq-local diff-buffer-type (if (re-search-forward "^diff --git" nil t) 'git - (if (re-search-forward "^diff -r.*-r" nil t) + (if (re-search-forward "^diff -r " nil t) 'hg nil)))) (when (eq diff-buffer-type 'git) @@ -3501,25 +3505,25 @@ hunk text is not found in the source file." ;; When initialization is requested, we should be in a brand new ;; temp buffer. (cl-assert (null buffer-file-name)) - ;; Use `:safe' to find `mode:'. In case of hunk-only, use nil because - ;; Local Variables list might be incomplete when context is truncated. - (let ((enable-local-variables - (unless hunk-only - (if (memq enable-local-variables '(:safe :all nil)) - enable-local-variables - ;; Ignore other values that query. - :safe))) - (buffer-file-name file)) - ;; Don't run hooks that might assume buffer-file-name - ;; really associates buffer with a file (bug#39190). - (delay-mode-hooks (set-auto-mode)) - ;; FIXME: Is this really worth the trouble? - (when (and (fboundp 'generic-mode-find-file-hook) - (memq #'generic-mode-find-file-hook - ;; There's no point checking the buffer-local value, - ;; we're in a fresh new buffer. - (default-value 'find-file-hook))) - (generic-mode-find-file-hook)))) + (cl-flet + ((set-mode () + ;; Don't run hooks that might assume buffer-file-name + ;; really associates buffer with a file (bug#39190). + (delay-mode-hooks (set-auto-mode)) + ;; FIXME: Is this really worth the trouble? + (when (and (fboundp 'generic-mode-find-file-hook) + (memq #'generic-mode-find-file-hook + ;; There's no point checking the + ;; buffer-local value because we're in a + ;; fresh new buffer. + (default-value 'find-file-hook))) + (generic-mode-find-file-hook)))) + ;; Use `:safe' to find `mode:'. In case of hunk-only, use nil because + ;; Local Variables list might be incomplete when context is truncated. + (let ((buffer-file-name file)) + (if hunk-only + (let (enable-local-variables) (set-mode)) + (without-local-variable-queries (set-mode)))))) (let ((font-lock-defaults (or font-lock-defaults '(nil t))) props beg end) diff --git a/lisp/vc/log-edit.el b/lisp/vc/log-edit.el index e3c92bd4d28..b7b9c32ad99 100644 --- a/lisp/vc/log-edit.el +++ b/lisp/vc/log-edit.el @@ -1367,16 +1367,74 @@ entry." (if (setq entry (assoc key log-entries)) (setcdr entry (append (cdr entry) (list file))) (push (list key file) log-entries))))) - ;; Now map over log-entries, and extract the strings. - (dolist (log-entry (nreverse log-entries)) - (apply 'log-edit-changelog-insert-entries - (append (car log-entry) (cdr log-entry))) - (insert "\n")) + ;; Check whether all log entries come from the same ChangeLog file. + (if (length= (seq-uniq (mapcar #'caar log-entries)) 1) + ;; If so, extract the commit message in toto from that file. + (log-edit-insert-changelog-entry (caaar log-entries)) + ;; Otherwise, map over the entries constructed from each ChangeLog + ;; file used, and extract the strings. + (dolist (log-entry (nreverse log-entries)) + (apply 'log-edit-changelog-insert-entries + (append (car log-entry) (cdr log-entry))) + (insert "\n"))) ;; No newline after the last entry. (when log-entries (delete-char -1)) log-edit-author)) +(declare-function vc-deduce-fileset "vc") + +(defun log-edit-insert-changelog-entry (buffer) + "Use body of ChangeLog entry in BUFFER as commit message. +Insert the body of the latest entry in the ChangeLog file that BUFFER is +visiting into the \"*vc-log*\" buffer. If the first line of the body +does not begin with \"* \", move it to the Summary header in the +\"*vc-log*\" buffer, thus making is the summary line of the commit +message. + +If the set of files listed in the ChangeLog entry differs from the set +of files with changes to commit according to VC, display a warning +urging the user to correct this discrepancy before committing the +changes." + (let (summary beg end files-in-changelog) + (with-current-buffer buffer + (save-restriction + (log-edit-narrow-changelog) + (setq summary (let ((s (buffer-substring-no-properties + (pos-bol) (pos-eol)))) + (and (string-match "^\t\\([^*].+\\)$" s) + (match-string 1 s))) + beg (or (and summary (forward-line) + (skip-syntax-forward "\s-") + (goto-char (pos-bol))) + (point)) + end (point-max)) + ;; List of changed files according to the ChangeLog entry. + (save-excursion + (let* ((bfn (buffer-file-name buffer)) + (bn (buffer-name)) + (fnd (or (and bfn (file-name-directory bfn)) + ;; If ChangeLog buffer is not visiting a file, + ;; extract the directory from the buffer name. + (and + (string-match "\\`\\*changes to \\(.+\\)\\*\\'" bn) + (match-string 1 bn))))) + (while (re-search-forward "\t\\* \\([^ :\n]+\\)[ :\n]" nil t) + (let ((fn (concat fnd (match-string-no-properties 1)))) + (when (file-exists-p fn) + (push fn files-in-changelog)))))))) + (log-edit-changelog-insert-entries buffer beg end) + (when summary (log-edit-set-header "Summary" summary)) + (unless (seq-set-equal-p + (save-current-buffer + (nth 2 (vc-deduce-fileset nil nil 'state-model-only-files))) + files-in-changelog) + (display-warning + 'log-edit + "Files in ChangeLog entry differ from files with changes to commit! +Remove this discrepancy before committing the changes by adjusting as +appropriate either the ChangeLog entry or the selection of files to commit.")))) + (defun log-edit-toggle-header (header value) "Toggle a boolean-type header in the current buffer. See `log-edit-set-header' for details." diff --git a/lisp/vc/vc-annotate.el b/lisp/vc/vc-annotate.el index 83b5185a4b4..42dbbbbe9d2 100644 --- a/lisp/vc/vc-annotate.el +++ b/lisp/vc/vc-annotate.el @@ -277,22 +277,25 @@ cover the range from the oldest annotation to the newest." (- current newest)) (format "Spanned to %.1f days old" (- current oldest)))))) -;; Menu -- Using easymenu.el